aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp2303
1 files changed, 2303 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp
new file mode 100644
index 0000000..b94d566
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CIrrDeviceLinux.cpp
@@ -0,0 +1,2303 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CIrrDeviceLinux.h"
6
7#ifdef _IRR_COMPILE_WITH_X11_DEVICE_
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/utsname.h>
12#include <time.h>
13#include "IEventReceiver.h"
14#include "ISceneManager.h"
15#include "IGUIEnvironment.h"
16#include "os.h"
17#include "CTimer.h"
18#include "irrString.h"
19#include "Keycodes.h"
20#include "COSOperator.h"
21#include "CColorConverter.h"
22#include "SIrrCreationParameters.h"
23#include "IGUISpriteBank.h"
24#include <X11/XKBlib.h>
25#include <X11/Xatom.h>
26
27#ifdef _IRR_LINUX_XCURSOR_
28#include <X11/Xcursor/Xcursor.h>
29#endif
30
31#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
32#include <fcntl.h>
33#include <unistd.h>
34
35#ifdef __FREE_BSD_
36#include <sys/joystick.h>
37#else
38
39// linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys.
40// These override the irr::KEY_FOO equivalents, which stops key handling from working.
41// As a workaround, defining _INPUT_H stops linux/input.h from being included; it
42// doesn't actually seem to be necessary except to pull in sys/ioctl.h.
43#define _INPUT_H
44#include <sys/ioctl.h> // Would normally be included in linux/input.h
45#include <linux/joystick.h>
46#undef _INPUT_H
47#endif
48
49#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
50
51namespace irr
52{
53 namespace video
54 {
55 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
56 io::IFileSystem* io, CIrrDeviceLinux* device);
57 }
58} // end namespace irr
59
60namespace
61{
62 Atom X_ATOM_CLIPBOARD;
63 Atom X_ATOM_TARGETS;
64 Atom X_ATOM_UTF8_STRING;
65 Atom X_ATOM_TEXT;
66};
67
68namespace irr
69{
70
71const char* wmDeleteWindow = "WM_DELETE_WINDOW";
72
73//! constructor
74CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
75 : CIrrDeviceStub(param),
76#ifdef _IRR_COMPILE_WITH_X11_
77 display(0), visual(0), screennr(0), window(0), StdHints(0), SoftwareImage(0),
78#ifdef _IRR_COMPILE_WITH_OPENGL_
79 glxWin(0),
80 Context(0),
81#endif
82#endif
83 Width(param.WindowSize.Width), Height(param.WindowSize.Height),
84 WindowHasFocus(false), WindowMinimized(false),
85 UseXVidMode(false), UseXRandR(false), UseGLXWindow(false),
86 ExternalWindow(false), AutorepeatSupport(0)
87{
88 #ifdef _DEBUG
89 setDebugName("CIrrDeviceLinux");
90 #endif
91
92 // print version, distribution etc.
93 // thx to LynxLuna for pointing me to the uname function
94 core::stringc linuxversion;
95 struct utsname LinuxInfo;
96 uname(&LinuxInfo);
97
98 linuxversion += LinuxInfo.sysname;
99 linuxversion += " ";
100 linuxversion += LinuxInfo.release;
101 linuxversion += " ";
102 linuxversion += LinuxInfo.version;
103 linuxversion += " ";
104 linuxversion += LinuxInfo.machine;
105
106 Operator = new COSOperator(linuxversion, this);
107 os::Printer::log(linuxversion.c_str(), ELL_INFORMATION);
108
109 // create keymap
110 createKeyMap();
111
112 // create window
113 if (CreationParams.DriverType != video::EDT_NULL)
114 {
115 // create the window, only if we do not use the null device
116 if (!createWindow())
117 return;
118 }
119
120 // create cursor control
121 CursorControl = new CCursorControl(this, CreationParams.DriverType == video::EDT_NULL);
122
123 // create driver
124 createDriver();
125
126 if (!VideoDriver)
127 return;
128
129 createGUIAndScene();
130}
131
132
133//! destructor
134CIrrDeviceLinux::~CIrrDeviceLinux()
135{
136#ifdef _IRR_COMPILE_WITH_X11_
137 if (StdHints)
138 XFree(StdHints);
139 // Disable cursor (it is drop'ed in stub)
140 if (CursorControl)
141 {
142 CursorControl->setVisible(false);
143 static_cast<CCursorControl*>(CursorControl)->clearCursors();
144 }
145
146 // Must free OpenGL textures etc before destroying context, so can't wait for stub destructor
147 if ( GUIEnvironment )
148 {
149 GUIEnvironment->drop();
150 GUIEnvironment = NULL;
151 }
152 if ( SceneManager )
153 {
154 SceneManager->drop();
155 SceneManager = NULL;
156 }
157 if ( VideoDriver )
158 {
159 VideoDriver->drop();
160 VideoDriver = NULL;
161 }
162
163 if (display)
164 {
165 #ifdef _IRR_COMPILE_WITH_OPENGL_
166 if (Context)
167 {
168 if (glxWin)
169 {
170 if (!glXMakeContextCurrent(display, None, None, NULL))
171 os::Printer::log("Could not release glx context.", ELL_WARNING);
172 }
173 else
174 {
175 if (!glXMakeCurrent(display, None, NULL))
176 os::Printer::log("Could not release glx context.", ELL_WARNING);
177 }
178 glXDestroyContext(display, Context);
179 if (glxWin)
180 glXDestroyWindow(display, glxWin);
181 }
182 #endif // #ifdef _IRR_COMPILE_WITH_OPENGL_
183
184 // Reset fullscreen resolution change
185 switchToFullscreen(true);
186
187 if (SoftwareImage)
188 XDestroyImage(SoftwareImage);
189
190 if (!ExternalWindow)
191 {
192 XDestroyWindow(display,window);
193 XCloseDisplay(display);
194 }
195 }
196 if (visual)
197 XFree(visual);
198
199#endif // #ifdef _IRR_COMPILE_WITH_X11_
200
201#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
202 for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
203 {
204 if (ActiveJoysticks[joystick].fd >= 0)
205 {
206 close(ActiveJoysticks[joystick].fd);
207 }
208 }
209#endif
210}
211
212
213#if defined(_IRR_COMPILE_WITH_X11_) && defined(_DEBUG)
214int IrrPrintXError(Display *display, XErrorEvent *event)
215{
216 char msg[256];
217 char msg2[256];
218
219 snprintf(msg, 256, "%d", event->request_code);
220 XGetErrorDatabaseText(display, "XRequest", msg, "unknown", msg2, 256);
221 XGetErrorText(display, event->error_code, msg, 256);
222 os::Printer::log("X Error", msg, ELL_WARNING);
223 os::Printer::log("From call ", msg2, ELL_WARNING);
224 return 0;
225}
226#endif
227
228
229bool CIrrDeviceLinux::switchToFullscreen(bool reset)
230{
231 if (!CreationParams.Fullscreen)
232 return true;
233 if (reset)
234 {
235#ifdef _IRR_LINUX_X11_VIDMODE_
236 if (UseXVidMode && CreationParams.Fullscreen)
237 {
238 XF86VidModeSwitchToMode(display, screennr, &oldVideoMode);
239 XF86VidModeSetViewPort(display, screennr, 0, 0);
240 }
241 #endif
242 #ifdef _IRR_LINUX_X11_RANDR_
243 if (UseXRandR && CreationParams.Fullscreen)
244 {
245 XRRScreenConfiguration *config=XRRGetScreenInfo(display,DefaultRootWindow(display));
246 XRRSetScreenConfig(display,config,DefaultRootWindow(display),oldRandrMode,oldRandrRotation,CurrentTime);
247 XRRFreeScreenConfigInfo(config);
248 }
249 #endif
250 return true;
251 }
252
253 getVideoModeList();
254 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
255 s32 eventbase, errorbase;
256 s32 bestMode = -1;
257 #endif
258
259 #ifdef _IRR_LINUX_X11_VIDMODE_
260 if (XF86VidModeQueryExtension(display, &eventbase, &errorbase))
261 {
262 // enumerate video modes
263 s32 modeCount;
264 XF86VidModeModeInfo** modes;
265
266 XF86VidModeGetAllModeLines(display, screennr, &modeCount, &modes);
267
268 // find fitting mode
269 for (s32 i = 0; i<modeCount; ++i)
270 {
271 if (bestMode==-1 && modes[i]->hdisplay >= Width && modes[i]->vdisplay >= Height)
272 bestMode = i;
273 else if (bestMode!=-1 &&
274 modes[i]->hdisplay >= Width &&
275 modes[i]->vdisplay >= Height &&
276 modes[i]->hdisplay <= modes[bestMode]->hdisplay &&
277 modes[i]->vdisplay <= modes[bestMode]->vdisplay)
278 bestMode = i;
279 }
280 if (bestMode != -1)
281 {
282 os::Printer::log("Starting vidmode fullscreen mode...", ELL_INFORMATION);
283 os::Printer::log("hdisplay: ", core::stringc(modes[bestMode]->hdisplay).c_str(), ELL_INFORMATION);
284 os::Printer::log("vdisplay: ", core::stringc(modes[bestMode]->vdisplay).c_str(), ELL_INFORMATION);
285
286 XF86VidModeSwitchToMode(display, screennr, modes[bestMode]);
287 XF86VidModeSetViewPort(display, screennr, 0, 0);
288 UseXVidMode=true;
289 }
290 else
291 {
292 os::Printer::log("Could not find specified video mode, running windowed.", ELL_WARNING);
293 CreationParams.Fullscreen = false;
294 }
295
296 XFree(modes);
297 }
298 else
299 #endif
300 #ifdef _IRR_LINUX_X11_RANDR_
301 if (XRRQueryExtension(display, &eventbase, &errorbase))
302 {
303 s32 modeCount;
304 XRRScreenConfiguration *config=XRRGetScreenInfo(display,DefaultRootWindow(display));
305 XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);
306 for (s32 i = 0; i<modeCount; ++i)
307 {
308 if (bestMode==-1 && (u32)modes[i].width >= Width && (u32)modes[i].height >= Height)
309 bestMode = i;
310 else if (bestMode!=-1 &&
311 (u32)modes[i].width >= Width &&
312 (u32)modes[i].height >= Height &&
313 modes[i].width <= modes[bestMode].width &&
314 modes[i].height <= modes[bestMode].height)
315 bestMode = i;
316 }
317 if (bestMode != -1)
318 {
319 os::Printer::log("Starting randr fullscreen mode...", ELL_INFORMATION);
320 os::Printer::log("width: ", core::stringc(modes[bestMode].width).c_str(), ELL_INFORMATION);
321 os::Printer::log("height: ", core::stringc(modes[bestMode].height).c_str(), ELL_INFORMATION);
322
323 XRRSetScreenConfig(display,config,DefaultRootWindow(display),bestMode,oldRandrRotation,CurrentTime);
324 UseXRandR=true;
325 }
326 XRRFreeScreenConfigInfo(config);
327 }
328 else
329 #endif
330 {
331 os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht "
332 "to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING);
333 CreationParams.Fullscreen = false;
334 }
335 return CreationParams.Fullscreen;
336}
337
338
339#if defined(_IRR_COMPILE_WITH_X11_)
340void IrrPrintXGrabError(int grabResult, const c8 * grabCommand )
341{
342 if ( grabResult == GrabSuccess )
343 {
344// os::Printer::log(grabCommand, ": GrabSuccess", ELL_INFORMATION);
345 return;
346 }
347
348 switch ( grabResult )
349 {
350 case AlreadyGrabbed:
351 os::Printer::log(grabCommand, ": AlreadyGrabbed", ELL_WARNING);
352 break;
353 case GrabNotViewable:
354 os::Printer::log(grabCommand, ": GrabNotViewable", ELL_WARNING);
355 break;
356 case GrabFrozen:
357 os::Printer::log(grabCommand, ": GrabFrozen", ELL_WARNING);
358 break;
359 case GrabInvalidTime:
360 os::Printer::log(grabCommand, ": GrabInvalidTime", ELL_WARNING);
361 break;
362 default:
363 os::Printer::log(grabCommand, ": grab failed with unknown problem", ELL_WARNING);
364 break;
365 }
366}
367#endif
368
369
370bool CIrrDeviceLinux::createWindow()
371{
372#ifdef _IRR_COMPILE_WITH_X11_
373#ifdef _DEBUG
374 os::Printer::log("Creating X window...", ELL_INFORMATION);
375 XSetErrorHandler(IrrPrintXError);
376#endif
377
378// onefang changes start
379 if (CreationParams.VideoData)
380 display = (Display *) CreationParams.VideoData->OpenGLLinux.X11Display;
381 if (!display)
382// onefang changes end
383 display = XOpenDisplay(0);
384 if (!display)
385 {
386 os::Printer::log("Error: Need running XServer to start Irrlicht Engine.", ELL_ERROR);
387 if (XDisplayName(0)[0])
388 os::Printer::log("Could not open display", XDisplayName(0), ELL_ERROR);
389 else
390 os::Printer::log("Could not open display, set DISPLAY variable", ELL_ERROR);
391 return false;
392 }
393
394 screennr = DefaultScreen(display);
395
396 switchToFullscreen();
397
398#ifdef _IRR_COMPILE_WITH_OPENGL_
399
400 GLXFBConfig glxFBConfig;
401 int major, minor;
402 bool isAvailableGLX=false;
403 if (CreationParams.DriverType==video::EDT_OPENGL)
404 {
405 isAvailableGLX=glXQueryExtension(display,&major,&minor);
406 if (isAvailableGLX && glXQueryVersion(display, &major, &minor))
407 {
408#ifdef GLX_VERSION_1_3
409 typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
410
411#ifdef _IRR_OPENGL_USE_EXTPOINTER_
412 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXChooseFBConfig"));
413#else
414 PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig=glXChooseFBConfig;
415#endif
416 if (major==1 && minor>2 && glxChooseFBConfig)
417 {
418 // attribute array for the draw buffer
419 int visualAttrBuffer[] =
420 {
421 GLX_RENDER_TYPE, GLX_RGBA_BIT,
422 GLX_RED_SIZE, 4,
423 GLX_GREEN_SIZE, 4,
424 GLX_BLUE_SIZE, 4,
425 GLX_ALPHA_SIZE, CreationParams.WithAlphaChannel?1:0,
426 GLX_DEPTH_SIZE, CreationParams.ZBufferBits, //10,11
427 GLX_DOUBLEBUFFER, CreationParams.Doublebuffer?True:False,
428 GLX_STENCIL_SIZE, CreationParams.Stencilbuffer?1:0,
429#if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string!
430 GLX_SAMPLE_BUFFERS, 1,
431 GLX_SAMPLES, CreationParams.AntiAlias, // 18,19
432#elif defined(GLX_ARB_multisample)
433 GLX_SAMPLE_BUFFERS_ARB, 1,
434 GLX_SAMPLES_ARB, CreationParams.AntiAlias, // 18,19
435#elif defined(GLX_SGIS_multisample)
436 GLX_SAMPLE_BUFFERS_SGIS, 1,
437 GLX_SAMPLES_SGIS, CreationParams.AntiAlias, // 18,19
438#endif
439//#ifdef GL_ARB_framebuffer_sRGB
440// GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, CreationParams.HandleSRGB,
441//#elif defined(GL_EXT_framebuffer_sRGB)
442// GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, CreationParams.HandleSRGB,
443//#endif
444 GLX_STEREO, CreationParams.Stereobuffer?True:False,
445 None
446 };
447
448 GLXFBConfig *configList=0;
449 int nitems=0;
450 if (CreationParams.AntiAlias<2)
451 {
452 visualAttrBuffer[17] = 0;
453 visualAttrBuffer[19] = 0;
454 }
455 // first round with unchanged values
456 {
457 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
458 if (!configList && CreationParams.AntiAlias)
459 {
460 while (!configList && (visualAttrBuffer[19]>1))
461 {
462 visualAttrBuffer[19] -= 1;
463 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
464 }
465 if (!configList)
466 {
467 visualAttrBuffer[17] = 0;
468 visualAttrBuffer[19] = 0;
469 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
470 if (configList)
471 {
472 os::Printer::log("No FSAA available.", ELL_WARNING);
473 CreationParams.AntiAlias=0;
474 }
475 else
476 {
477 //reenable multisampling
478 visualAttrBuffer[17] = 1;
479 visualAttrBuffer[19] = CreationParams.AntiAlias;
480 }
481 }
482 }
483 }
484 // Next try with flipped stencil buffer value
485 // If the first round was with stencil flag it's now without
486 // Other way round also makes sense because some configs
487 // only have depth buffer combined with stencil buffer
488 if (!configList)
489 {
490 if (CreationParams.Stencilbuffer)
491 os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING);
492 CreationParams.Stencilbuffer = !CreationParams.Stencilbuffer;
493 visualAttrBuffer[15]=CreationParams.Stencilbuffer?1:0;
494
495 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
496 if (!configList && CreationParams.AntiAlias)
497 {
498 while (!configList && (visualAttrBuffer[19]>1))
499 {
500 visualAttrBuffer[19] -= 1;
501 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
502 }
503 if (!configList)
504 {
505 visualAttrBuffer[17] = 0;
506 visualAttrBuffer[19] = 0;
507 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
508 if (configList)
509 {
510 os::Printer::log("No FSAA available.", ELL_WARNING);
511 CreationParams.AntiAlias=0;
512 }
513 else
514 {
515 //reenable multisampling
516 visualAttrBuffer[17] = 1;
517 visualAttrBuffer[19] = CreationParams.AntiAlias;
518 }
519 }
520 }
521 }
522 // Next try without double buffer
523 if (!configList && CreationParams.Doublebuffer)
524 {
525 os::Printer::log("No doublebuffering available.", ELL_WARNING);
526 CreationParams.Doublebuffer=false;
527 visualAttrBuffer[13] = GLX_DONT_CARE;
528 CreationParams.Stencilbuffer = false;
529 visualAttrBuffer[15]=0;
530 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
531 if (!configList && CreationParams.AntiAlias)
532 {
533 while (!configList && (visualAttrBuffer[19]>1))
534 {
535 visualAttrBuffer[19] -= 1;
536 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
537 }
538 if (!configList)
539 {
540 visualAttrBuffer[17] = 0;
541 visualAttrBuffer[19] = 0;
542 configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
543 if (configList)
544 {
545 os::Printer::log("No FSAA available.", ELL_WARNING);
546 CreationParams.AntiAlias=0;
547 }
548 else
549 {
550 //reenable multisampling
551 visualAttrBuffer[17] = 1;
552 visualAttrBuffer[19] = CreationParams.AntiAlias;
553 }
554 }
555 }
556 }
557 if (configList)
558 {
559 glxFBConfig=configList[0];
560 XFree(configList);
561 UseGLXWindow=true;
562#ifdef _IRR_OPENGL_USE_EXTPOINTER_
563 typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
564 PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig= (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXGetVisualFromFBConfig"));
565 if (glxGetVisualFromFBConfig)
566 visual = glxGetVisualFromFBConfig(display,glxFBConfig);
567#else
568 visual = glXGetVisualFromFBConfig(display,glxFBConfig);
569#endif
570 }
571 }
572 else
573#endif
574 {
575 // attribute array for the draw buffer
576 int visualAttrBuffer[] =
577 {
578 GLX_RGBA, GLX_USE_GL,
579 GLX_RED_SIZE, 4,
580 GLX_GREEN_SIZE, 4,
581 GLX_BLUE_SIZE, 4,
582 GLX_ALPHA_SIZE, CreationParams.WithAlphaChannel?1:0,
583 GLX_DEPTH_SIZE, CreationParams.ZBufferBits,
584 GLX_STENCIL_SIZE, CreationParams.Stencilbuffer?1:0, // 12,13
585 // The following attributes have no flags, but are
586 // either present or not. As a no-op we use
587 // GLX_USE_GL, which is silently ignored by glXChooseVisual
588 CreationParams.Doublebuffer?GLX_DOUBLEBUFFER:GLX_USE_GL, // 14
589 CreationParams.Stereobuffer?GLX_STEREO:GLX_USE_GL, // 15
590//#ifdef GL_ARB_framebuffer_sRGB
591// CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL,
592//#elif defined(GL_EXT_framebuffer_sRGB)
593// CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL,
594//#endif
595 None
596 };
597
598 visual=glXChooseVisual(display, screennr, visualAttrBuffer);
599 if (!visual)
600 {
601 if (CreationParams.Stencilbuffer)
602 os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING);
603 CreationParams.Stencilbuffer = !CreationParams.Stencilbuffer;
604 visualAttrBuffer[13]=CreationParams.Stencilbuffer?1:0;
605
606 visual=glXChooseVisual(display, screennr, visualAttrBuffer);
607 if (!visual && CreationParams.Doublebuffer)
608 {
609 os::Printer::log("No doublebuffering available.", ELL_WARNING);
610 CreationParams.Doublebuffer=false;
611 visualAttrBuffer[14] = GLX_USE_GL;
612 visual=glXChooseVisual(display, screennr, visualAttrBuffer);
613 }
614 }
615 }
616 }
617 else
618 os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING);
619 }
620 // don't use the XVisual with OpenGL, because it ignores all requested
621 // properties of the CreationParams
622 else if (!visual)
623#endif // _IRR_COMPILE_WITH_OPENGL_
624
625 // create visual with standard X methods
626 {
627 os::Printer::log("Using plain X visual");
628 XVisualInfo visTempl; //Template to hold requested values
629 int visNumber; // Return value of available visuals
630
631 visTempl.screen = screennr;
632 // ARGB visuals should be avoided for usual applications
633 visTempl.depth = CreationParams.WithAlphaChannel?32:24;
634 while ((!visual) && (visTempl.depth>=16))
635 {
636 visual = XGetVisualInfo(display, VisualScreenMask|VisualDepthMask,
637 &visTempl, &visNumber);
638 visTempl.depth -= 8;
639 }
640 }
641
642 if (!visual)
643 {
644 os::Printer::log("Fatal error, could not get visual.", ELL_ERROR);
645 XCloseDisplay(display);
646 display=0;
647 return false;
648 }
649#ifdef _DEBUG
650 else
651 os::Printer::log("Visual chosen: ", core::stringc(static_cast<u32>(visual->visualid)).c_str(), ELL_DEBUG);
652#endif
653
654 // create color map
655 Colormap colormap;
656 colormap = XCreateColormap(display,
657 RootWindow(display, visual->screen),
658 visual->visual, AllocNone);
659
660 attributes.colormap = colormap;
661 attributes.border_pixel = 0;
662 attributes.event_mask = StructureNotifyMask | FocusChangeMask | ExposureMask;
663 if (!CreationParams.IgnoreInput)
664 attributes.event_mask |= PointerMotionMask |
665 ButtonPressMask | KeyPressMask |
666 ButtonReleaseMask | KeyReleaseMask;
667
668 if (!CreationParams.WindowId)
669 {
670 // create new Window
671 // Remove window manager decoration in fullscreen
672 attributes.override_redirect = CreationParams.Fullscreen;
673 window = XCreateWindow(display,
674 RootWindow(display, visual->screen),
675 0, 0, Width, Height, 0, visual->depth,
676 InputOutput, visual->visual,
677 CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
678 &attributes);
679 XMapRaised(display, window);
680 CreationParams.WindowId = (void*)window;
681 Atom wmDelete;
682 wmDelete = XInternAtom(display, wmDeleteWindow, True);
683 XSetWMProtocols(display, window, &wmDelete, 1);
684 if (CreationParams.Fullscreen)
685 {
686 XSetInputFocus(display, window, RevertToParent, CurrentTime);
687 int grabKb = XGrabKeyboard(display, window, True, GrabModeAsync,
688 GrabModeAsync, CurrentTime);
689 IrrPrintXGrabError(grabKb, "XGrabKeyboard");
690 int grabPointer = XGrabPointer(display, window, True, ButtonPressMask,
691 GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
692 IrrPrintXGrabError(grabPointer, "XGrabPointer");
693 XWarpPointer(display, None, window, 0, 0, 0, 0, 0, 0);
694 }
695 }
696 else
697 {
698 // attach external window
699 window = (Window)CreationParams.WindowId;
700 if (!CreationParams.IgnoreInput)
701 {
702 XCreateWindow(display,
703 window,
704 0, 0, Width, Height, 0, visual->depth,
705 InputOutput, visual->visual,
706 CWBorderPixel | CWColormap | CWEventMask,
707 &attributes);
708 }
709 XWindowAttributes wa;
710 XGetWindowAttributes(display, window, &wa);
711 CreationParams.WindowSize.Width = wa.width;
712 CreationParams.WindowSize.Height = wa.height;
713 CreationParams.Fullscreen = false;
714 ExternalWindow = true;
715 }
716
717 WindowMinimized=false;
718 // Currently broken in X, see Bug ID 2795321
719 // XkbSetDetectableAutoRepeat(display, True, &AutorepeatSupport);
720
721#ifdef _IRR_COMPILE_WITH_OPENGL_
722
723 // connect glx context to window
724 Context=0;
725 if (isAvailableGLX && CreationParams.DriverType==video::EDT_OPENGL)
726 {
727// onefang changes start
728// if (UseGLXWindow)
729 if (CreationParams.VideoData)
730 Context = (GLXContext) CreationParams.VideoData->OpenGLLinux.X11Context;
731 if (Context)
732 {
733 if (!glXMakeCurrent(display, window, Context))
734 {
735 os::Printer::log("Could not make context current.", ELL_WARNING);
736 glXDestroyContext(display, Context);
737 }
738 }
739 else if (UseGLXWindow)
740// onefang changes end
741 {
742 glxWin=glXCreateWindow(display,glxFBConfig,window,NULL);
743 if (glxWin)
744 {
745 // create glx context
746 Context = glXCreateNewContext(display, glxFBConfig, GLX_RGBA_TYPE, NULL, True);
747 if (Context)
748 {
749 if (!glXMakeContextCurrent(display, glxWin, glxWin, Context))
750 {
751 os::Printer::log("Could not make context current.", ELL_WARNING);
752 glXDestroyContext(display, Context);
753 }
754 }
755 else
756 {
757 os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
758 }
759 }
760 else
761 {
762 os::Printer::log("Could not create GLX window.", ELL_WARNING);
763 }
764 }
765 else
766 {
767 Context = glXCreateContext(display, visual, NULL, True);
768 if (Context)
769 {
770 if (!glXMakeCurrent(display, window, Context))
771 {
772 os::Printer::log("Could not make context current.", ELL_WARNING);
773 glXDestroyContext(display, Context);
774 }
775 }
776 else
777 {
778 os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
779 }
780 }
781 }
782#endif // _IRR_COMPILE_WITH_OPENGL_
783
784 Window tmp;
785 u32 borderWidth;
786 int x,y;
787 unsigned int bits;
788
789 XGetGeometry(display, window, &tmp, &x, &y, &Width, &Height, &borderWidth, &bits);
790 CreationParams.Bits = bits;
791 CreationParams.WindowSize.Width = Width;
792 CreationParams.WindowSize.Height = Height;
793
794 StdHints = XAllocSizeHints();
795 long num;
796 XGetWMNormalHints(display, window, StdHints, &num);
797
798 // create an XImage for the software renderer
799 //(thx to Nadav for some clues on how to do that!)
800
801 if (CreationParams.DriverType == video::EDT_SOFTWARE || CreationParams.DriverType == video::EDT_BURNINGSVIDEO)
802 {
803 SoftwareImage = XCreateImage(display,
804 visual->visual, visual->depth,
805 ZPixmap, 0, 0, Width, Height,
806 BitmapPad(display), 0);
807
808 // use malloc because X will free it later on
809 if (SoftwareImage)
810 SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));
811 }
812
813 initXAtoms();
814
815#endif // #ifdef _IRR_COMPILE_WITH_X11_
816 return true;
817}
818
819
820//! create the driver
821void CIrrDeviceLinux::createDriver()
822{
823 switch(CreationParams.DriverType)
824 {
825#ifdef _IRR_COMPILE_WITH_X11_
826
827 case video::EDT_SOFTWARE:
828 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
829 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
830 #else
831 os::Printer::log("No Software driver support compiled in.", ELL_ERROR);
832 #endif
833 break;
834
835 case video::EDT_BURNINGSVIDEO:
836 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
837 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
838 #else
839 os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR);
840 #endif
841 break;
842
843 case video::EDT_OPENGL:
844 #ifdef _IRR_COMPILE_WITH_OPENGL_
845 if (Context)
846 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this);
847 #else
848 os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
849 #endif
850 break;
851
852 case video::EDT_DIRECT3D8:
853 case video::EDT_DIRECT3D9:
854 os::Printer::log("This driver is not available in Linux. Try OpenGL or Software renderer.",
855 ELL_ERROR);
856 break;
857
858 case video::EDT_NULL:
859 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
860 break;
861
862 default:
863 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
864 break;
865#else
866 case video::EDT_NULL:
867 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
868 break;
869 default:
870 os::Printer::log("No X11 support compiled in. Only Null driver available.", ELL_ERROR);
871 break;
872#endif
873 }
874}
875
876
877//! runs the device. Returns false if device wants to be deleted
878bool CIrrDeviceLinux::run()
879{
880 os::Timer::tick();
881
882#ifdef _IRR_COMPILE_WITH_X11_
883
884 if ( CursorControl )
885 static_cast<CCursorControl*>(CursorControl)->update();
886
887 if ((CreationParams.DriverType != video::EDT_NULL) && display)
888 {
889 SEvent irrevent;
890 irrevent.MouseInput.ButtonStates = 0xffffffff;
891
892 while (XPending(display) > 0 && !Close)
893 {
894 XEvent event;
895 XNextEvent(display, &event);
896
897 switch (event.type)
898 {
899 case ConfigureNotify:
900 // check for changed window size
901 if ((event.xconfigure.width != (int) Width) ||
902 (event.xconfigure.height != (int) Height))
903 {
904 Width = event.xconfigure.width;
905 Height = event.xconfigure.height;
906
907 // resize image data
908 if (SoftwareImage)
909 {
910 XDestroyImage(SoftwareImage);
911
912 SoftwareImage = XCreateImage(display,
913 visual->visual, visual->depth,
914 ZPixmap, 0, 0, Width, Height,
915 BitmapPad(display), 0);
916
917 // use malloc because X will free it later on
918 if (SoftwareImage)
919 SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));
920 }
921
922 if (VideoDriver)
923 VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));
924 }
925 break;
926
927 case MapNotify:
928 WindowMinimized=false;
929 break;
930
931 case UnmapNotify:
932 WindowMinimized=true;
933 break;
934
935 case FocusIn:
936 WindowHasFocus=true;
937 break;
938
939 case FocusOut:
940 WindowHasFocus=false;
941 break;
942
943 case MotionNotify:
944 irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
945 irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
946 irrevent.MouseInput.X = event.xbutton.x;
947 irrevent.MouseInput.Y = event.xbutton.y;
948 irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0;
949 irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0;
950
951 // mouse button states
952 irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0;
953 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0;
954 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0;
955
956 postEventFromUser(irrevent);
957 break;
958
959 case ButtonPress:
960 case ButtonRelease:
961
962 irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
963 irrevent.MouseInput.X = event.xbutton.x;
964 irrevent.MouseInput.Y = event.xbutton.y;
965 irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0;
966 irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0;
967
968 // mouse button states
969 // This sets the state which the buttons had _prior_ to the event.
970 // So unlike on Windows the button which just got changed has still the old state here.
971 // We handle that below by flipping the corresponding bit later.
972 irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0;
973 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0;
974 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0;
975
976 irrevent.MouseInput.Event = irr::EMIE_COUNT;
977
978 switch(event.xbutton.button)
979 {
980 case Button1:
981 irrevent.MouseInput.Event =
982 (event.type == ButtonPress) ? irr::EMIE_LMOUSE_PRESSED_DOWN : irr::EMIE_LMOUSE_LEFT_UP;
983 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_LEFT;
984 break;
985
986 case Button3:
987 irrevent.MouseInput.Event =
988 (event.type == ButtonPress) ? irr::EMIE_RMOUSE_PRESSED_DOWN : irr::EMIE_RMOUSE_LEFT_UP;
989 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_RIGHT;
990 break;
991
992 case Button2:
993 irrevent.MouseInput.Event =
994 (event.type == ButtonPress) ? irr::EMIE_MMOUSE_PRESSED_DOWN : irr::EMIE_MMOUSE_LEFT_UP;
995 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_MIDDLE;
996 break;
997
998 case Button4:
999 if (event.type == ButtonPress)
1000 {
1001 irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL;
1002 irrevent.MouseInput.Wheel = 1.0f;
1003 }
1004 break;
1005
1006 case Button5:
1007 if (event.type == ButtonPress)
1008 {
1009 irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL;
1010 irrevent.MouseInput.Wheel = -1.0f;
1011 }
1012 break;
1013 }
1014
1015 if (irrevent.MouseInput.Event != irr::EMIE_COUNT)
1016 {
1017 postEventFromUser(irrevent);
1018
1019 if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN )
1020 {
1021 u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event);
1022 if ( clicks == 2 )
1023 {
1024 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
1025 postEventFromUser(irrevent);
1026 }
1027 else if ( clicks == 3 )
1028 {
1029 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
1030 postEventFromUser(irrevent);
1031 }
1032 }
1033 }
1034 break;
1035
1036 case MappingNotify:
1037 XRefreshKeyboardMapping (&event.xmapping) ;
1038 break;
1039
1040 case KeyRelease:
1041 if (0 == AutorepeatSupport && (XPending( display ) > 0) )
1042 {
1043 // check for Autorepeat manually
1044 // We'll do the same as Windows does: Only send KeyPressed
1045 // So every KeyRelease is a real release
1046 XEvent next_event;
1047 XPeekEvent (event.xkey.display, &next_event);
1048 if ((next_event.type == KeyPress) &&
1049 (next_event.xkey.keycode == event.xkey.keycode) &&
1050 (next_event.xkey.time - event.xkey.time) < 2) // usually same time, but on some systems a difference of 1 is possible
1051 {
1052 /* Ignore the key release event */
1053 break;
1054 }
1055 }
1056 // fall-through in case the release should be handled
1057 case KeyPress:
1058 {
1059 SKeyMap mp;
1060 char buf[8]={0};
1061 XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
1062
1063 irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
1064 irrevent.KeyInput.PressedDown = (event.type == KeyPress);
1065// mbtowc(&irrevent.KeyInput.Char, buf, sizeof(buf));
1066 irrevent.KeyInput.Char = ((wchar_t*)(buf))[0];
1067 irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
1068 irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
1069
1070 event.xkey.state = 0; // ignore shift-ctrl states for figuring out the key
1071 XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
1072 const s32 idx = KeyMap.binary_search(mp);
1073 if (idx != -1)
1074 {
1075 irrevent.KeyInput.Key = (EKEY_CODE)KeyMap[idx].Win32Key;
1076 }
1077 else
1078 {
1079 irrevent.KeyInput.Key = (EKEY_CODE)0;
1080 }
1081 if (irrevent.KeyInput.Key == 0)
1082 {
1083 // 1:1 mapping to windows-keys would require testing for keyboard type (us, ger, ...)
1084 // So unless we do that we will have some unknown keys here.
1085 if (idx == -1)
1086 {
1087 os::Printer::log("Could not find EKEY_CODE, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
1088 }
1089 else
1090 {
1091 os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
1092 }
1093 // Any value is better than none, that allows at least using the keys.
1094 // Worst case is that some keys will be identical, still better than _all_
1095 // unknown keys being identical.
1096 irrevent.KeyInput.Key = (EKEY_CODE)event.xkey.keycode;
1097 }
1098
1099 postEventFromUser(irrevent);
1100 }
1101 break;
1102
1103 case ClientMessage:
1104 {
1105 char *atom = XGetAtomName(display, event.xclient.message_type);
1106 if (*atom == *wmDeleteWindow)
1107 {
1108 os::Printer::log("Quit message received.", ELL_INFORMATION);
1109 Close = true;
1110 }
1111 else
1112 {
1113 // we assume it's a user message
1114 irrevent.EventType = irr::EET_USER_EVENT;
1115 irrevent.UserEvent.UserData1 = (s32)event.xclient.data.l[0];
1116 irrevent.UserEvent.UserData2 = (s32)event.xclient.data.l[1];
1117 postEventFromUser(irrevent);
1118 }
1119 XFree(atom);
1120 }
1121 break;
1122
1123 case SelectionRequest:
1124 {
1125 XEvent respond;
1126 XSelectionRequestEvent *req = &(event.xselectionrequest);
1127 if ( req->target == XA_STRING)
1128 {
1129 XChangeProperty (display,
1130 req->requestor,
1131 req->property, req->target,
1132 8, // format
1133 PropModeReplace,
1134 (unsigned char*) Clipboard.c_str(),
1135 Clipboard.size());
1136 respond.xselection.property = req->property;
1137 }
1138 else if ( req->target == X_ATOM_TARGETS )
1139 {
1140 long data[2];
1141
1142 data[0] = X_ATOM_TEXT;
1143 data[1] = XA_STRING;
1144
1145 XChangeProperty (display, req->requestor,
1146 req->property, req->target,
1147 8, PropModeReplace,
1148 (unsigned char *) &data,
1149 sizeof (data));
1150 respond.xselection.property = req->property;
1151 }
1152 else
1153 {
1154 respond.xselection.property= None;
1155 }
1156 respond.xselection.type= SelectionNotify;
1157 respond.xselection.display= req->display;
1158 respond.xselection.requestor= req->requestor;
1159 respond.xselection.selection=req->selection;
1160 respond.xselection.target= req->target;
1161 respond.xselection.time = req->time;
1162 XSendEvent (display, req->requestor,0,0,&respond);
1163 XFlush (display);
1164 }
1165 break;
1166
1167 default:
1168 break;
1169 } // end switch
1170
1171 } // end while
1172 }
1173#endif //_IRR_COMPILE_WITH_X11_
1174
1175 if (!Close)
1176 pollJoysticks();
1177
1178 return !Close;
1179}
1180
1181
1182//! Pause the current process for the minimum time allowed only to allow other processes to execute
1183void CIrrDeviceLinux::yield()
1184{
1185 struct timespec ts = {0,1};
1186 nanosleep(&ts, NULL);
1187}
1188
1189
1190//! Pause execution and let other processes to run for a specified amount of time.
1191void CIrrDeviceLinux::sleep(u32 timeMs, bool pauseTimer=false)
1192{
1193 const bool wasStopped = Timer ? Timer->isStopped() : true;
1194
1195 struct timespec ts;
1196 ts.tv_sec = (time_t) (timeMs / 1000);
1197 ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
1198
1199 if (pauseTimer && !wasStopped)
1200 Timer->stop();
1201
1202 nanosleep(&ts, NULL);
1203
1204 if (pauseTimer && !wasStopped)
1205 Timer->start();
1206}
1207
1208
1209//! sets the caption of the window
1210void CIrrDeviceLinux::setWindowCaption(const wchar_t* text)
1211{
1212#ifdef _IRR_COMPILE_WITH_X11_
1213 if (CreationParams.DriverType == video::EDT_NULL)
1214 return;
1215
1216 XTextProperty txt;
1217 if (Success==XwcTextListToTextProperty(display, const_cast<wchar_t**>(&text),
1218 1, XStdICCTextStyle, &txt))
1219 {
1220 XSetWMName(display, window, &txt);
1221 XSetWMIconName(display, window, &txt);
1222 XFree(txt.value);
1223 }
1224#endif
1225}
1226
1227
1228//! presents a surface in the client area
1229bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rect<s32>* srcRect)
1230{
1231#ifdef _IRR_COMPILE_WITH_X11_
1232 // this is only necessary for software drivers.
1233 if (!SoftwareImage)
1234 return true;
1235
1236 // thx to Nadav, who send me some clues of how to display the image
1237 // to the X Server.
1238
1239 const u32 destwidth = SoftwareImage->width;
1240 const u32 minWidth = core::min_(image->getDimension().Width, destwidth);
1241 const u32 destPitch = SoftwareImage->bytes_per_line;
1242
1243 video::ECOLOR_FORMAT destColor;
1244 switch (SoftwareImage->bits_per_pixel)
1245 {
1246 case 16:
1247 if (SoftwareImage->depth==16)
1248 destColor = video::ECF_R5G6B5;
1249 else
1250 destColor = video::ECF_A1R5G5B5;
1251 break;
1252 case 24: destColor = video::ECF_R8G8B8; break;
1253 case 32: destColor = video::ECF_A8R8G8B8; break;
1254 default:
1255 os::Printer::log("Unsupported screen depth.");
1256 return false;
1257 }
1258
1259 u8* srcdata = reinterpret_cast<u8*>(image->lock());
1260 u8* destData = reinterpret_cast<u8*>(SoftwareImage->data);
1261
1262 const u32 destheight = SoftwareImage->height;
1263 const u32 srcheight = core::min_(image->getDimension().Height, destheight);
1264 const u32 srcPitch = image->getPitch();
1265 for (u32 y=0; y!=srcheight; ++y)
1266 {
1267 video::CColorConverter::convert_viaFormat(srcdata,image->getColorFormat(), minWidth, destData, destColor);
1268 srcdata+=srcPitch;
1269 destData+=destPitch;
1270 }
1271 image->unlock();
1272
1273 GC gc = DefaultGC(display, DefaultScreen(display));
1274 Window myWindow=window;
1275 if (windowId)
1276 myWindow = reinterpret_cast<Window>(windowId);
1277 XPutImage(display, myWindow, gc, SoftwareImage, 0, 0, 0, 0, destwidth, destheight);
1278#endif
1279 return true;
1280}
1281
1282
1283//! notifies the device that it should close itself
1284void CIrrDeviceLinux::closeDevice()
1285{
1286 Close = true;
1287}
1288
1289
1290//! returns if window is active. if not, nothing need to be drawn
1291bool CIrrDeviceLinux::isWindowActive() const
1292{
1293 return (WindowHasFocus && !WindowMinimized);
1294}
1295
1296
1297//! returns if window has focus.
1298bool CIrrDeviceLinux::isWindowFocused() const
1299{
1300 return WindowHasFocus;
1301}
1302
1303
1304//! returns if window is minimized.
1305bool CIrrDeviceLinux::isWindowMinimized() const
1306{
1307 return WindowMinimized;
1308}
1309
1310
1311//! returns color format of the window.
1312video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const
1313{
1314#ifdef _IRR_COMPILE_WITH_X11_
1315 if (visual && (visual->depth != 16))
1316 return video::ECF_R8G8B8;
1317 else
1318#endif
1319 return video::ECF_R5G6B5;
1320}
1321
1322
1323//! Sets if the window should be resizable in windowed mode.
1324void CIrrDeviceLinux::setResizable(bool resize)
1325{
1326#ifdef _IRR_COMPILE_WITH_X11_
1327 if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen )
1328 return;
1329
1330 XUnmapWindow(display, window);
1331 if ( !resize )
1332 {
1333 // Must be heap memory because data size depends on X Server
1334 XSizeHints *hints = XAllocSizeHints();
1335 hints->flags=PSize|PMinSize|PMaxSize;
1336 hints->min_width=hints->max_width=hints->base_width=Width;
1337 hints->min_height=hints->max_height=hints->base_height=Height;
1338 XSetWMNormalHints(display, window, hints);
1339 XFree(hints);
1340 }
1341 else
1342 {
1343 XSetWMNormalHints(display, window, StdHints);
1344 }
1345 XMapWindow(display, window);
1346 XFlush(display);
1347#endif // #ifdef _IRR_COMPILE_WITH_X11_
1348}
1349
1350
1351//! Return pointer to a list with all video modes supported by the gfx adapter.
1352video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
1353{
1354#ifdef _IRR_COMPILE_WITH_X11_
1355 if (!VideoModeList->getVideoModeCount())
1356 {
1357 bool temporaryDisplay = false;
1358
1359 if (!display)
1360 {
1361 display = XOpenDisplay(0);
1362 temporaryDisplay=true;
1363 }
1364 if (display)
1365 {
1366 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
1367 s32 eventbase, errorbase;
1368 s32 defaultDepth=DefaultDepth(display,screennr);
1369 #endif
1370
1371 #ifdef _IRR_LINUX_X11_VIDMODE_
1372 if (XF86VidModeQueryExtension(display, &eventbase, &errorbase))
1373 {
1374 // enumerate video modes
1375 int modeCount;
1376 XF86VidModeModeInfo** modes;
1377
1378 XF86VidModeGetAllModeLines(display, screennr, &modeCount, &modes);
1379
1380 // save current video mode
1381 oldVideoMode = *modes[0];
1382
1383 // find fitting mode
1384
1385 VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(
1386 modes[0]->hdisplay, modes[0]->vdisplay));
1387 for (int i = 0; i<modeCount; ++i)
1388 {
1389 VideoModeList->addMode(core::dimension2d<u32>(
1390 modes[i]->hdisplay, modes[i]->vdisplay), defaultDepth);
1391 }
1392 XFree(modes);
1393 }
1394 else
1395 #endif
1396 #ifdef _IRR_LINUX_X11_RANDR_
1397 if (XRRQueryExtension(display, &eventbase, &errorbase))
1398 {
1399 int modeCount;
1400 XRRScreenConfiguration *config=XRRGetScreenInfo(display,DefaultRootWindow(display));
1401 oldRandrMode=XRRConfigCurrentConfiguration(config,&oldRandrRotation);
1402 XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);
1403 VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(
1404 modes[oldRandrMode].width, modes[oldRandrMode].height));
1405 for (int i = 0; i<modeCount; ++i)
1406 {
1407 VideoModeList->addMode(core::dimension2d<u32>(
1408 modes[i].width, modes[i].height), defaultDepth);
1409 }
1410 XRRFreeScreenConfigInfo(config);
1411 }
1412 else
1413 #endif
1414 {
1415 os::Printer::log("VidMode or RandR X11 extension requireed for VideoModeList." , ELL_WARNING);
1416 }
1417 }
1418 if (display && temporaryDisplay)
1419 {
1420 XCloseDisplay(display);
1421 display=0;
1422 }
1423 }
1424#endif
1425
1426 return VideoModeList;
1427}
1428
1429
1430//! Minimize window
1431void CIrrDeviceLinux::minimizeWindow()
1432{
1433#ifdef _IRR_COMPILE_WITH_X11_
1434 XIconifyWindow(display, window, screennr);
1435#endif
1436}
1437
1438
1439//! Maximize window
1440void CIrrDeviceLinux::maximizeWindow()
1441{
1442#ifdef _IRR_COMPILE_WITH_X11_
1443 XMapWindow(display, window);
1444#endif
1445}
1446
1447
1448//! Restore original window size
1449void CIrrDeviceLinux::restoreWindow()
1450{
1451#ifdef _IRR_COMPILE_WITH_X11_
1452 XMapWindow(display, window);
1453#endif
1454}
1455
1456
1457void CIrrDeviceLinux::createKeyMap()
1458{
1459 // I don't know if this is the best method to create
1460 // the lookuptable, but I'll leave it like that until
1461 // I find a better version.
1462
1463#ifdef _IRR_COMPILE_WITH_X11_
1464 KeyMap.reallocate(84);
1465 KeyMap.push_back(SKeyMap(XK_BackSpace, KEY_BACK));
1466 KeyMap.push_back(SKeyMap(XK_Tab, KEY_TAB));
1467 KeyMap.push_back(SKeyMap(XK_ISO_Left_Tab, KEY_TAB));
1468 KeyMap.push_back(SKeyMap(XK_Linefeed, 0)); // ???
1469 KeyMap.push_back(SKeyMap(XK_Clear, KEY_CLEAR));
1470 KeyMap.push_back(SKeyMap(XK_Return, KEY_RETURN));
1471 KeyMap.push_back(SKeyMap(XK_Pause, KEY_PAUSE));
1472 KeyMap.push_back(SKeyMap(XK_Scroll_Lock, KEY_SCROLL));
1473 KeyMap.push_back(SKeyMap(XK_Sys_Req, 0)); // ???
1474 KeyMap.push_back(SKeyMap(XK_Escape, KEY_ESCAPE));
1475 KeyMap.push_back(SKeyMap(XK_Insert, KEY_INSERT));
1476 KeyMap.push_back(SKeyMap(XK_Delete, KEY_DELETE));
1477 KeyMap.push_back(SKeyMap(XK_Home, KEY_HOME));
1478 KeyMap.push_back(SKeyMap(XK_Left, KEY_LEFT));
1479 KeyMap.push_back(SKeyMap(XK_Up, KEY_UP));
1480 KeyMap.push_back(SKeyMap(XK_Right, KEY_RIGHT));
1481 KeyMap.push_back(SKeyMap(XK_Down, KEY_DOWN));
1482 KeyMap.push_back(SKeyMap(XK_Prior, KEY_PRIOR));
1483 KeyMap.push_back(SKeyMap(XK_Page_Up, KEY_PRIOR));
1484 KeyMap.push_back(SKeyMap(XK_Next, KEY_NEXT));
1485 KeyMap.push_back(SKeyMap(XK_Page_Down, KEY_NEXT));
1486 KeyMap.push_back(SKeyMap(XK_End, KEY_END));
1487 KeyMap.push_back(SKeyMap(XK_Begin, KEY_HOME));
1488 KeyMap.push_back(SKeyMap(XK_Num_Lock, KEY_NUMLOCK));
1489 KeyMap.push_back(SKeyMap(XK_KP_Space, KEY_SPACE));
1490 KeyMap.push_back(SKeyMap(XK_KP_Tab, KEY_TAB));
1491 KeyMap.push_back(SKeyMap(XK_KP_Enter, KEY_RETURN));
1492 KeyMap.push_back(SKeyMap(XK_KP_F1, KEY_F1));
1493 KeyMap.push_back(SKeyMap(XK_KP_F2, KEY_F2));
1494 KeyMap.push_back(SKeyMap(XK_KP_F3, KEY_F3));
1495 KeyMap.push_back(SKeyMap(XK_KP_F4, KEY_F4));
1496 KeyMap.push_back(SKeyMap(XK_KP_Home, KEY_HOME));
1497 KeyMap.push_back(SKeyMap(XK_KP_Left, KEY_LEFT));
1498 KeyMap.push_back(SKeyMap(XK_KP_Up, KEY_UP));
1499 KeyMap.push_back(SKeyMap(XK_KP_Right, KEY_RIGHT));
1500 KeyMap.push_back(SKeyMap(XK_KP_Down, KEY_DOWN));
1501 KeyMap.push_back(SKeyMap(XK_Print, KEY_PRINT));
1502 KeyMap.push_back(SKeyMap(XK_KP_Prior, KEY_PRIOR));
1503 KeyMap.push_back(SKeyMap(XK_KP_Page_Up, KEY_PRIOR));
1504 KeyMap.push_back(SKeyMap(XK_KP_Next, KEY_NEXT));
1505 KeyMap.push_back(SKeyMap(XK_KP_Page_Down, KEY_NEXT));
1506 KeyMap.push_back(SKeyMap(XK_KP_End, KEY_END));
1507 KeyMap.push_back(SKeyMap(XK_KP_Begin, KEY_HOME));
1508 KeyMap.push_back(SKeyMap(XK_KP_Insert, KEY_INSERT));
1509 KeyMap.push_back(SKeyMap(XK_KP_Delete, KEY_DELETE));
1510 KeyMap.push_back(SKeyMap(XK_KP_Equal, 0)); // ???
1511 KeyMap.push_back(SKeyMap(XK_KP_Multiply, KEY_MULTIPLY));
1512 KeyMap.push_back(SKeyMap(XK_KP_Add, KEY_ADD));
1513 KeyMap.push_back(SKeyMap(XK_KP_Separator, KEY_SEPARATOR));
1514 KeyMap.push_back(SKeyMap(XK_KP_Subtract, KEY_SUBTRACT));
1515 KeyMap.push_back(SKeyMap(XK_KP_Decimal, KEY_DECIMAL));
1516 KeyMap.push_back(SKeyMap(XK_KP_Divide, KEY_DIVIDE));
1517 KeyMap.push_back(SKeyMap(XK_KP_0, KEY_KEY_0));
1518 KeyMap.push_back(SKeyMap(XK_KP_1, KEY_KEY_1));
1519 KeyMap.push_back(SKeyMap(XK_KP_2, KEY_KEY_2));
1520 KeyMap.push_back(SKeyMap(XK_KP_3, KEY_KEY_3));
1521 KeyMap.push_back(SKeyMap(XK_KP_4, KEY_KEY_4));
1522 KeyMap.push_back(SKeyMap(XK_KP_5, KEY_KEY_5));
1523 KeyMap.push_back(SKeyMap(XK_KP_6, KEY_KEY_6));
1524 KeyMap.push_back(SKeyMap(XK_KP_7, KEY_KEY_7));
1525 KeyMap.push_back(SKeyMap(XK_KP_8, KEY_KEY_8));
1526 KeyMap.push_back(SKeyMap(XK_KP_9, KEY_KEY_9));
1527 KeyMap.push_back(SKeyMap(XK_F1, KEY_F1));
1528 KeyMap.push_back(SKeyMap(XK_F2, KEY_F2));
1529 KeyMap.push_back(SKeyMap(XK_F3, KEY_F3));
1530 KeyMap.push_back(SKeyMap(XK_F4, KEY_F4));
1531 KeyMap.push_back(SKeyMap(XK_F5, KEY_F5));
1532 KeyMap.push_back(SKeyMap(XK_F6, KEY_F6));
1533 KeyMap.push_back(SKeyMap(XK_F7, KEY_F7));
1534 KeyMap.push_back(SKeyMap(XK_F8, KEY_F8));
1535 KeyMap.push_back(SKeyMap(XK_F9, KEY_F9));
1536 KeyMap.push_back(SKeyMap(XK_F10, KEY_F10));
1537 KeyMap.push_back(SKeyMap(XK_F11, KEY_F11));
1538 KeyMap.push_back(SKeyMap(XK_F12, KEY_F12));
1539 KeyMap.push_back(SKeyMap(XK_Shift_L, KEY_LSHIFT));
1540 KeyMap.push_back(SKeyMap(XK_Shift_R, KEY_RSHIFT));
1541 KeyMap.push_back(SKeyMap(XK_Control_L, KEY_LCONTROL));
1542 KeyMap.push_back(SKeyMap(XK_Control_R, KEY_RCONTROL));
1543 KeyMap.push_back(SKeyMap(XK_Caps_Lock, KEY_CAPITAL));
1544 KeyMap.push_back(SKeyMap(XK_Shift_Lock, KEY_CAPITAL));
1545 KeyMap.push_back(SKeyMap(XK_Meta_L, KEY_LWIN));
1546 KeyMap.push_back(SKeyMap(XK_Meta_R, KEY_RWIN));
1547 KeyMap.push_back(SKeyMap(XK_Alt_L, KEY_LMENU));
1548 KeyMap.push_back(SKeyMap(XK_Alt_R, KEY_RMENU));
1549 KeyMap.push_back(SKeyMap(XK_ISO_Level3_Shift, KEY_RMENU));
1550 KeyMap.push_back(SKeyMap(XK_Menu, KEY_MENU));
1551 KeyMap.push_back(SKeyMap(XK_space, KEY_SPACE));
1552 KeyMap.push_back(SKeyMap(XK_exclam, 0)); //?
1553 KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //?
1554 KeyMap.push_back(SKeyMap(XK_section, 0)); //?
1555 KeyMap.push_back(SKeyMap(XK_numbersign, KEY_OEM_2));
1556 KeyMap.push_back(SKeyMap(XK_dollar, 0)); //?
1557 KeyMap.push_back(SKeyMap(XK_percent, 0)); //?
1558 KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //?
1559 KeyMap.push_back(SKeyMap(XK_apostrophe, KEY_OEM_7));
1560 KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //?
1561 KeyMap.push_back(SKeyMap(XK_parenright, 0)); //?
1562 KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //?
1563 KeyMap.push_back(SKeyMap(XK_plus, KEY_PLUS)); //?
1564 KeyMap.push_back(SKeyMap(XK_comma, KEY_COMMA)); //?
1565 KeyMap.push_back(SKeyMap(XK_minus, KEY_MINUS)); //?
1566 KeyMap.push_back(SKeyMap(XK_period, KEY_PERIOD)); //?
1567 KeyMap.push_back(SKeyMap(XK_slash, KEY_OEM_2)); //?
1568 KeyMap.push_back(SKeyMap(XK_0, KEY_KEY_0));
1569 KeyMap.push_back(SKeyMap(XK_1, KEY_KEY_1));
1570 KeyMap.push_back(SKeyMap(XK_2, KEY_KEY_2));
1571 KeyMap.push_back(SKeyMap(XK_3, KEY_KEY_3));
1572 KeyMap.push_back(SKeyMap(XK_4, KEY_KEY_4));
1573 KeyMap.push_back(SKeyMap(XK_5, KEY_KEY_5));
1574 KeyMap.push_back(SKeyMap(XK_6, KEY_KEY_6));
1575 KeyMap.push_back(SKeyMap(XK_7, KEY_KEY_7));
1576 KeyMap.push_back(SKeyMap(XK_8, KEY_KEY_8));
1577 KeyMap.push_back(SKeyMap(XK_9, KEY_KEY_9));
1578 KeyMap.push_back(SKeyMap(XK_colon, 0)); //?
1579 KeyMap.push_back(SKeyMap(XK_semicolon, KEY_OEM_1));
1580 KeyMap.push_back(SKeyMap(XK_less, KEY_OEM_102));
1581 KeyMap.push_back(SKeyMap(XK_equal, KEY_PLUS));
1582 KeyMap.push_back(SKeyMap(XK_greater, 0)); //?
1583 KeyMap.push_back(SKeyMap(XK_question, 0)); //?
1584 KeyMap.push_back(SKeyMap(XK_at, KEY_KEY_2)); //?
1585 KeyMap.push_back(SKeyMap(XK_mu, 0)); //?
1586 KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //?
1587 KeyMap.push_back(SKeyMap(XK_A, KEY_KEY_A));
1588 KeyMap.push_back(SKeyMap(XK_B, KEY_KEY_B));
1589 KeyMap.push_back(SKeyMap(XK_C, KEY_KEY_C));
1590 KeyMap.push_back(SKeyMap(XK_D, KEY_KEY_D));
1591 KeyMap.push_back(SKeyMap(XK_E, KEY_KEY_E));
1592 KeyMap.push_back(SKeyMap(XK_F, KEY_KEY_F));
1593 KeyMap.push_back(SKeyMap(XK_G, KEY_KEY_G));
1594 KeyMap.push_back(SKeyMap(XK_H, KEY_KEY_H));
1595 KeyMap.push_back(SKeyMap(XK_I, KEY_KEY_I));
1596 KeyMap.push_back(SKeyMap(XK_J, KEY_KEY_J));
1597 KeyMap.push_back(SKeyMap(XK_K, KEY_KEY_K));
1598 KeyMap.push_back(SKeyMap(XK_L, KEY_KEY_L));
1599 KeyMap.push_back(SKeyMap(XK_M, KEY_KEY_M));
1600 KeyMap.push_back(SKeyMap(XK_N, KEY_KEY_N));
1601 KeyMap.push_back(SKeyMap(XK_O, KEY_KEY_O));
1602 KeyMap.push_back(SKeyMap(XK_P, KEY_KEY_P));
1603 KeyMap.push_back(SKeyMap(XK_Q, KEY_KEY_Q));
1604 KeyMap.push_back(SKeyMap(XK_R, KEY_KEY_R));
1605 KeyMap.push_back(SKeyMap(XK_S, KEY_KEY_S));
1606 KeyMap.push_back(SKeyMap(XK_T, KEY_KEY_T));
1607 KeyMap.push_back(SKeyMap(XK_U, KEY_KEY_U));
1608 KeyMap.push_back(SKeyMap(XK_V, KEY_KEY_V));
1609 KeyMap.push_back(SKeyMap(XK_W, KEY_KEY_W));
1610 KeyMap.push_back(SKeyMap(XK_X, KEY_KEY_X));
1611 KeyMap.push_back(SKeyMap(XK_Y, KEY_KEY_Y));
1612 KeyMap.push_back(SKeyMap(XK_Z, KEY_KEY_Z));
1613 KeyMap.push_back(SKeyMap(XK_bracketleft, KEY_OEM_4));
1614 KeyMap.push_back(SKeyMap(XK_backslash, KEY_OEM_5));
1615 KeyMap.push_back(SKeyMap(XK_bracketright, KEY_OEM_6));
1616 KeyMap.push_back(SKeyMap(XK_asciicircum, KEY_OEM_5));
1617 KeyMap.push_back(SKeyMap(XK_degree, 0)); //?
1618 KeyMap.push_back(SKeyMap(XK_underscore, KEY_MINUS)); //?
1619 KeyMap.push_back(SKeyMap(XK_grave, KEY_OEM_3));
1620 KeyMap.push_back(SKeyMap(XK_acute, KEY_OEM_6));
1621 KeyMap.push_back(SKeyMap(XK_a, KEY_KEY_A));
1622 KeyMap.push_back(SKeyMap(XK_b, KEY_KEY_B));
1623 KeyMap.push_back(SKeyMap(XK_c, KEY_KEY_C));
1624 KeyMap.push_back(SKeyMap(XK_d, KEY_KEY_D));
1625 KeyMap.push_back(SKeyMap(XK_e, KEY_KEY_E));
1626 KeyMap.push_back(SKeyMap(XK_f, KEY_KEY_F));
1627 KeyMap.push_back(SKeyMap(XK_g, KEY_KEY_G));
1628 KeyMap.push_back(SKeyMap(XK_h, KEY_KEY_H));
1629 KeyMap.push_back(SKeyMap(XK_i, KEY_KEY_I));
1630 KeyMap.push_back(SKeyMap(XK_j, KEY_KEY_J));
1631 KeyMap.push_back(SKeyMap(XK_k, KEY_KEY_K));
1632 KeyMap.push_back(SKeyMap(XK_l, KEY_KEY_L));
1633 KeyMap.push_back(SKeyMap(XK_m, KEY_KEY_M));
1634 KeyMap.push_back(SKeyMap(XK_n, KEY_KEY_N));
1635 KeyMap.push_back(SKeyMap(XK_o, KEY_KEY_O));
1636 KeyMap.push_back(SKeyMap(XK_p, KEY_KEY_P));
1637 KeyMap.push_back(SKeyMap(XK_q, KEY_KEY_Q));
1638 KeyMap.push_back(SKeyMap(XK_r, KEY_KEY_R));
1639 KeyMap.push_back(SKeyMap(XK_s, KEY_KEY_S));
1640 KeyMap.push_back(SKeyMap(XK_t, KEY_KEY_T));
1641 KeyMap.push_back(SKeyMap(XK_u, KEY_KEY_U));
1642 KeyMap.push_back(SKeyMap(XK_v, KEY_KEY_V));
1643 KeyMap.push_back(SKeyMap(XK_w, KEY_KEY_W));
1644 KeyMap.push_back(SKeyMap(XK_x, KEY_KEY_X));
1645 KeyMap.push_back(SKeyMap(XK_y, KEY_KEY_Y));
1646 KeyMap.push_back(SKeyMap(XK_z, KEY_KEY_Z));
1647 KeyMap.push_back(SKeyMap(XK_ssharp, KEY_OEM_4));
1648 KeyMap.push_back(SKeyMap(XK_adiaeresis, KEY_OEM_7));
1649 KeyMap.push_back(SKeyMap(XK_odiaeresis, KEY_OEM_3));
1650 KeyMap.push_back(SKeyMap(XK_udiaeresis, KEY_OEM_1));
1651 KeyMap.push_back(SKeyMap(XK_Super_L, KEY_LWIN));
1652 KeyMap.push_back(SKeyMap(XK_Super_R, KEY_RWIN));
1653
1654 KeyMap.sort();
1655#endif
1656}
1657
1658bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
1659{
1660#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1661
1662 joystickInfo.clear();
1663
1664 u32 joystick;
1665 for (joystick = 0; joystick < 32; ++joystick)
1666 {
1667 // The joystick device could be here...
1668 core::stringc devName = "/dev/js";
1669 devName += joystick;
1670
1671 SJoystickInfo returnInfo;
1672 JoystickInfo info;
1673
1674 info.fd = open(devName.c_str(), O_RDONLY);
1675 if (-1 == info.fd)
1676 {
1677 // ...but Ubuntu and possibly other distros
1678 // create the devices in /dev/input
1679 devName = "/dev/input/js";
1680 devName += joystick;
1681 info.fd = open(devName.c_str(), O_RDONLY);
1682 if (-1 == info.fd)
1683 {
1684 // and BSD here
1685 devName = "/dev/joy";
1686 devName += joystick;
1687 info.fd = open(devName.c_str(), O_RDONLY);
1688 }
1689 }
1690
1691 if (-1 == info.fd)
1692 continue;
1693
1694#ifdef __FREE_BSD_
1695 info.axes=2;
1696 info.buttons=2;
1697#else
1698 ioctl( info.fd, JSIOCGAXES, &(info.axes) );
1699 ioctl( info.fd, JSIOCGBUTTONS, &(info.buttons) );
1700 fcntl( info.fd, F_SETFL, O_NONBLOCK );
1701#endif
1702
1703 (void)memset(&info.persistentData, 0, sizeof(info.persistentData));
1704 info.persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
1705 info.persistentData.JoystickEvent.Joystick = ActiveJoysticks.size();
1706
1707 // There's no obvious way to determine which (if any) axes represent a POV
1708 // hat, so we'll just set it to "not used" and forget about it.
1709 info.persistentData.JoystickEvent.POV = 65535;
1710
1711 ActiveJoysticks.push_back(info);
1712
1713 returnInfo.Joystick = joystick;
1714 returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN;
1715 returnInfo.Axes = info.axes;
1716 returnInfo.Buttons = info.buttons;
1717
1718#ifndef __FREE_BSD_
1719 char name[80];
1720 ioctl( info.fd, JSIOCGNAME(80), name);
1721 returnInfo.Name = name;
1722#endif
1723
1724 joystickInfo.push_back(returnInfo);
1725 }
1726
1727 for (joystick = 0; joystick < joystickInfo.size(); ++joystick)
1728 {
1729 char logString[256];
1730 (void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'",
1731 joystick, joystickInfo[joystick].Axes,
1732 joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
1733 os::Printer::log(logString, ELL_INFORMATION);
1734 }
1735
1736 return true;
1737#else
1738 return false;
1739#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1740}
1741
1742
1743void CIrrDeviceLinux::pollJoysticks()
1744{
1745#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1746 if (0 == ActiveJoysticks.size())
1747 return;
1748
1749 for (u32 j= 0; j< ActiveJoysticks.size(); ++j)
1750 {
1751 JoystickInfo & info = ActiveJoysticks[j];
1752
1753#ifdef __FREE_BSD_
1754 struct joystick js;
1755 if (read(info.fd, &js, JS_RETURN) == JS_RETURN)
1756 {
1757 info.persistentData.JoystickEvent.ButtonStates = js.buttons; /* should be a two-bit field */
1758 info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
1759 info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
1760#else
1761 struct js_event event;
1762 while (sizeof(event) == read(info.fd, &event, sizeof(event)))
1763 {
1764 switch(event.type & ~JS_EVENT_INIT)
1765 {
1766 case JS_EVENT_BUTTON:
1767 if (event.value)
1768 info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number);
1769 else
1770 info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number);
1771 break;
1772
1773 case JS_EVENT_AXIS:
1774 if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES)
1775 info.persistentData.JoystickEvent.Axis[event.number] = event.value;
1776 break;
1777
1778 default:
1779 break;
1780 }
1781 }
1782#endif
1783
1784 // Send an irrlicht joystick event once per ::run() even if no new data were received.
1785 (void)postEventFromUser(info.persistentData);
1786 }
1787#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1788}
1789
1790
1791//! Set the current Gamma Value for the Display
1792bool CIrrDeviceLinux::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
1793{
1794 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
1795 s32 eventbase, errorbase;
1796 #ifdef _IRR_LINUX_X11_VIDMODE_
1797 if (XF86VidModeQueryExtension(display, &eventbase, &errorbase))
1798 {
1799 XF86VidModeGamma gamma;
1800 gamma.red=red;
1801 gamma.green=green;
1802 gamma.blue=blue;
1803 XF86VidModeSetGamma(display, screennr, &gamma);
1804 return true;
1805 }
1806 #endif
1807 #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)
1808 else
1809 #endif
1810 #ifdef _IRR_LINUX_X11_RANDR_
1811 if (XRRQueryExtension(display, &eventbase, &errorbase))
1812 {
1813 XRRQueryVersion(display, &eventbase, &errorbase); // major, minor
1814 if (eventbase>=1 && errorbase>1)
1815 {
1816 #if (RANDR_MAJOR>1 || RANDR_MINOR>1)
1817 XRRCrtcGamma *gamma = XRRGetCrtcGamma(display, screennr);
1818 if (gamma)
1819 {
1820 *gamma->red=(u16)red;
1821 *gamma->green=(u16)green;
1822 *gamma->blue=(u16)blue;
1823 XRRSetCrtcGamma(display, screennr, gamma);
1824 XRRFreeGamma(gamma);
1825 return true;
1826 }
1827 #endif
1828 }
1829 }
1830 #endif
1831 #endif
1832 return false;
1833}
1834
1835
1836//! Get the current Gamma Value for the Display
1837bool CIrrDeviceLinux::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
1838{
1839 brightness = 0.f;
1840 contrast = 0.f;
1841 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
1842 s32 eventbase, errorbase;
1843 #ifdef _IRR_LINUX_X11_VIDMODE_
1844 if (XF86VidModeQueryExtension(display, &eventbase, &errorbase))
1845 {
1846 XF86VidModeGamma gamma;
1847 XF86VidModeGetGamma(display, screennr, &gamma);
1848 red = gamma.red;
1849 green = gamma.green;
1850 blue = gamma.blue;
1851 return true;
1852 }
1853 #endif
1854 #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)
1855 else
1856 #endif
1857 #ifdef _IRR_LINUX_X11_RANDR_
1858 if (XRRQueryExtension(display, &eventbase, &errorbase))
1859 {
1860 XRRQueryVersion(display, &eventbase, &errorbase); // major, minor
1861 if (eventbase>=1 && errorbase>1)
1862 {
1863 #if (RANDR_MAJOR>1 || RANDR_MINOR>1)
1864 XRRCrtcGamma *gamma = XRRGetCrtcGamma(display, screennr);
1865 if (gamma)
1866 {
1867 red = *gamma->red;
1868 green = *gamma->green;
1869 blue= *gamma->blue;
1870 XRRFreeGamma(gamma);
1871 return true;
1872 }
1873 #endif
1874 }
1875 }
1876 #endif
1877 #endif
1878 return false;
1879}
1880
1881
1882//! gets text from the clipboard
1883//! \return Returns 0 if no string is in there.
1884const c8* CIrrDeviceLinux::getTextFromClipboard() const
1885{
1886#if defined(_IRR_COMPILE_WITH_X11_)
1887 Window ownerWindow = XGetSelectionOwner (display, X_ATOM_CLIPBOARD);
1888 if ( ownerWindow == window )
1889 {
1890 return Clipboard.c_str();
1891 }
1892 Clipboard = "";
1893 if (ownerWindow != None )
1894 {
1895 XConvertSelection (display, X_ATOM_CLIPBOARD, XA_STRING, None, ownerWindow, CurrentTime);
1896 XFlush (display);
1897
1898 // check for data
1899 Atom type;
1900 int format;
1901 unsigned long numItems, bytesLeft, dummy;
1902 unsigned char *data;
1903 XGetWindowProperty (display, ownerWindow,
1904 XA_STRING, // property name
1905 0, // offset
1906 0, // length (we only check for data, so 0)
1907 0, // Delete 0==false
1908 AnyPropertyType, // AnyPropertyType or property identifier
1909 &type, // return type
1910 &format, // return format
1911 &numItems, // number items
1912 &bytesLeft, // remaining bytes for partial reads
1913 &data); // data
1914 if ( bytesLeft > 0 )
1915 {
1916 // there is some data to get
1917 int result = XGetWindowProperty (display, ownerWindow, XA_STRING, 0,
1918 bytesLeft, 0, AnyPropertyType, &type, &format,
1919 &numItems, &dummy, &data);
1920 if (result == Success)
1921 Clipboard = (irr::c8*)data;
1922 XFree (data);
1923 }
1924 }
1925
1926 return Clipboard.c_str();
1927
1928#else
1929 return 0;
1930#endif
1931}
1932
1933//! copies text to the clipboard
1934void CIrrDeviceLinux::copyToClipboard(const c8* text) const
1935{
1936#if defined(_IRR_COMPILE_WITH_X11_)
1937 // Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked.
1938 // Which btw. also means that on X you lose clipboard content when closing applications.
1939 Clipboard = text;
1940 XSetSelectionOwner (display, X_ATOM_CLIPBOARD, window, CurrentTime);
1941 XFlush (display);
1942#endif
1943}
1944
1945#ifdef _IRR_COMPILE_WITH_X11_
1946// return true if the passed event has the type passed in parameter arg
1947Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg)
1948{
1949 if ( event && event->type == *(int*)arg )
1950 {
1951// os::Printer::log("remove event:", core::stringc((int)arg).c_str(), ELL_INFORMATION);
1952 return True;
1953 }
1954 return False;
1955}
1956#endif //_IRR_COMPILE_WITH_X11_
1957
1958//! Remove all messages pending in the system message loop
1959void CIrrDeviceLinux::clearSystemMessages()
1960{
1961#ifdef _IRR_COMPILE_WITH_X11_
1962 if (CreationParams.DriverType != video::EDT_NULL)
1963 {
1964 XEvent event;
1965 int usrArg = ButtonPress;
1966 while ( XCheckIfEvent(display, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
1967 usrArg = ButtonRelease;
1968 while ( XCheckIfEvent(display, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
1969 usrArg = MotionNotify;
1970 while ( XCheckIfEvent(display, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
1971 usrArg = KeyRelease;
1972 while ( XCheckIfEvent(display, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
1973 usrArg = KeyPress;
1974 while ( XCheckIfEvent(display, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
1975 }
1976#endif //_IRR_COMPILE_WITH_X11_
1977}
1978
1979void CIrrDeviceLinux::initXAtoms()
1980{
1981#ifdef _IRR_COMPILE_WITH_X11_
1982 X_ATOM_CLIPBOARD = XInternAtom(display, "CLIPBOARD", False);
1983 X_ATOM_TARGETS = XInternAtom(display, "TARGETS", False);
1984 X_ATOM_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
1985 X_ATOM_TEXT = XInternAtom (display, "TEXT", False);
1986#endif
1987}
1988
1989
1990#ifdef _IRR_COMPILE_WITH_X11_
1991
1992Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
1993{
1994 XImage * sourceImage = XCreateImage(display, visual->visual,
1995 1, // depth,
1996 ZPixmap, // XYBitmap (depth=1), ZPixmap(depth=x)
1997 0, 0, sourceRect.getWidth(), sourceRect.getHeight(),
1998 32, // bitmap_pad,
1999 0// bytes_per_line (0 means continuos in memory)
2000 );
2001 sourceImage->data = new char[sourceImage->height * sourceImage->bytes_per_line];
2002 XImage * maskImage = XCreateImage(display, visual->visual,
2003 1, // depth,
2004 ZPixmap,
2005 0, 0, sourceRect.getWidth(), sourceRect.getHeight(),
2006 32, // bitmap_pad,
2007 0 // bytes_per_line
2008 );
2009 maskImage->data = new char[maskImage->height * maskImage->bytes_per_line];
2010
2011 // write texture into XImage
2012 video::ECOLOR_FORMAT format = tex->getColorFormat();
2013 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
2014 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
2015 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
2016 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
2017 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
2018 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
2019 {
2020 data += bytesLeftGap;
2021 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
2022 {
2023 video::SColor pixelCol;
2024 pixelCol.setData((const void*)data, format);
2025 data += bytesPerPixel;
2026
2027 if ( pixelCol.getAlpha() == 0 ) // transparent
2028 {
2029 XPutPixel(maskImage, x, y, 0);
2030 XPutPixel(sourceImage, x, y, 0);
2031 }
2032 else // color
2033 {
2034 if ( pixelCol.getAverage() >= 127 )
2035 XPutPixel(sourceImage, x, y, 1);
2036 else
2037 XPutPixel(sourceImage, x, y, 0);
2038 XPutPixel(maskImage, x, y, 1);
2039 }
2040 }
2041 data += bytesRightGap;
2042 }
2043 tex->unlock();
2044
2045 Pixmap sourcePixmap = XCreatePixmap(display, window, sourceImage->width, sourceImage->height, sourceImage->depth);
2046 Pixmap maskPixmap = XCreatePixmap(display, window, maskImage->width, maskImage->height, maskImage->depth);
2047
2048 XGCValues values;
2049 values.foreground = 1;
2050 values.background = 1;
2051 GC gc = XCreateGC( display, sourcePixmap, GCForeground | GCBackground, &values );
2052
2053 XPutImage(display, sourcePixmap, gc, sourceImage, 0, 0, 0, 0, sourceImage->width, sourceImage->height);
2054 XPutImage(display, maskPixmap, gc, maskImage, 0, 0, 0, 0, maskImage->width, maskImage->height);
2055
2056 XFreeGC(display, gc);
2057 XDestroyImage(sourceImage);
2058 XDestroyImage(maskImage);
2059
2060 Cursor cursorResult = 0;
2061 XColor foreground, background;
2062 foreground.red = 65535;
2063 foreground.green = 65535;
2064 foreground.blue = 65535;
2065 foreground.flags = DoRed | DoGreen | DoBlue;
2066 background.red = 0;
2067 background.green = 0;
2068 background.blue = 0;
2069 background.flags = DoRed | DoGreen | DoBlue;
2070
2071 cursorResult = XCreatePixmapCursor(display, sourcePixmap, maskPixmap, &foreground, &background, hotspot.X, hotspot.Y);
2072
2073 XFreePixmap(display, sourcePixmap);
2074 XFreePixmap(display, maskPixmap);
2075
2076 return cursorResult;
2077}
2078
2079#ifdef _IRR_LINUX_XCURSOR_
2080Cursor CIrrDeviceLinux::TextureToARGBCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
2081{
2082 XcursorImage * image = XcursorImageCreate (sourceRect.getWidth(), sourceRect.getHeight());
2083 image->xhot = hotspot.X;
2084 image->yhot = hotspot.Y;
2085
2086 // write texture into XcursorImage
2087 video::ECOLOR_FORMAT format = tex->getColorFormat();
2088 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
2089 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
2090 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
2091 XcursorPixel* target = image->pixels;
2092 const u8* data = (const u8*)tex->lock(ETLM_READ_ONLY, 0);
2093 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
2094 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
2095 {
2096 data += bytesLeftGap;
2097 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
2098 {
2099 video::SColor pixelCol;
2100 pixelCol.setData((const void*)data, format);
2101 data += bytesPerPixel;
2102
2103 *target = (XcursorPixel)pixelCol.color;
2104 ++target;
2105 }
2106 data += bytesRightGap;
2107 }
2108 tex->unlock();
2109
2110 Cursor cursorResult=XcursorImageLoadCursor(display, image);
2111
2112 XcursorImageDestroy(image);
2113
2114
2115 return cursorResult;
2116}
2117#endif // #ifdef _IRR_LINUX_XCURSOR_
2118
2119Cursor CIrrDeviceLinux::TextureToCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
2120{
2121#ifdef _IRR_LINUX_XCURSOR_
2122 return TextureToARGBCursor( tex, sourceRect, hotspot );
2123#else
2124 return TextureToMonochromeCursor( tex, sourceRect, hotspot );
2125#endif
2126}
2127#endif // _IRR_COMPILE_WITH_X11_
2128
2129
2130CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux* dev, bool null)
2131 : Device(dev)
2132#ifdef _IRR_COMPILE_WITH_X11_
2133 , PlatformBehavior(gui::ECPB_NONE), lastQuery(0)
2134#endif
2135 , IsVisible(true), Null(null), UseReferenceRect(false)
2136 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
2137{
2138#ifdef _IRR_COMPILE_WITH_X11_
2139 if (!Null)
2140 {
2141 XGCValues values;
2142 unsigned long valuemask = 0;
2143
2144 XColor fg, bg;
2145
2146 // this code, for making the cursor invisible was sent in by
2147 // Sirshane, thank your very much!
2148
2149
2150 Pixmap invisBitmap = XCreatePixmap(Device->display, Device->window, 32, 32, 1);
2151 Pixmap maskBitmap = XCreatePixmap(Device->display, Device->window, 32, 32, 1);
2152 Colormap screen_colormap = DefaultColormap( Device->display, DefaultScreen( Device->display ) );
2153 XAllocNamedColor( Device->display, screen_colormap, "black", &fg, &fg );
2154 XAllocNamedColor( Device->display, screen_colormap, "white", &bg, &bg );
2155
2156 GC gc = XCreateGC( Device->display, invisBitmap, valuemask, &values );
2157
2158 XSetForeground( Device->display, gc, BlackPixel( Device->display, DefaultScreen( Device->display ) ) );
2159 XFillRectangle( Device->display, invisBitmap, gc, 0, 0, 32, 32 );
2160 XFillRectangle( Device->display, maskBitmap, gc, 0, 0, 32, 32 );
2161
2162 invisCursor = XCreatePixmapCursor( Device->display, invisBitmap, maskBitmap, &fg, &bg, 1, 1 );
2163 XFreeGC(Device->display, gc);
2164 XFreePixmap(Device->display, invisBitmap);
2165 XFreePixmap(Device->display, maskBitmap);
2166
2167 initCursors();
2168 }
2169#endif
2170}
2171
2172CIrrDeviceLinux::CCursorControl::~CCursorControl()
2173{
2174 // Do not clearCursors here as the display is already closed
2175 // TODO (cutealien): droping cursorcontrol earlier might work, not sure about reason why that's done in stub currently.
2176}
2177
2178#ifdef _IRR_COMPILE_WITH_X11_
2179void CIrrDeviceLinux::CCursorControl::clearCursors()
2180{
2181 if (!Null)
2182 XFreeCursor(Device->display, invisCursor);
2183 for ( u32 i=0; i < Cursors.size(); ++i )
2184 {
2185 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
2186 {
2187 XFreeCursor(Device->display, Cursors[i].Frames[f].IconHW);
2188 }
2189 }
2190}
2191
2192void CIrrDeviceLinux::CCursorControl::initCursors()
2193{
2194 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_top_left_arrow)) ); // (or XC_arrow?)
2195 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_crosshair)) );
2196 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_hand2)) ); // (or XC_hand1? )
2197 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_question_arrow)) );
2198 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_xterm)) );
2199 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_X_cursor)) ); // (or XC_pirate?)
2200 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_watch)) ); // (or XC_clock?)
2201 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_fleur)) );
2202 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_top_right_corner)) ); // NESW not available in X11
2203 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_top_left_corner)) ); // NWSE not available in X11
2204 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_sb_v_double_arrow)) );
2205 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_sb_h_double_arrow)) );
2206 Cursors.push_back( CursorX11(XCreateFontCursor(Device->display, XC_sb_up_arrow)) ); // (or XC_center_ptr?)
2207}
2208
2209void CIrrDeviceLinux::CCursorControl::update()
2210{
2211 if ( (u32)ActiveIcon < Cursors.size() && !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
2212 {
2213 // 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)
2214 u32 now = Device->getTimer()->getRealTime();
2215 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
2216 XDefineCursor(Device->display, Device->window, Cursors[ActiveIcon].Frames[frame].IconHW);
2217 }
2218}
2219#endif
2220
2221//! Sets the active cursor icon
2222void CIrrDeviceLinux::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
2223{
2224#ifdef _IRR_COMPILE_WITH_X11_
2225 if ( iconId >= (s32)Cursors.size() )
2226 return;
2227
2228 if ( Cursors[iconId].Frames.size() )
2229 XDefineCursor(Device->display, Device->window, Cursors[iconId].Frames[0].IconHW);
2230
2231 ActiveIconStartTime = Device->getTimer()->getRealTime();
2232 ActiveIcon = iconId;
2233#endif
2234}
2235
2236
2237//! Add a custom sprite as cursor icon.
2238gui::ECURSOR_ICON CIrrDeviceLinux::CCursorControl::addIcon(const gui::SCursorSprite& icon)
2239{
2240#ifdef _IRR_COMPILE_WITH_X11_
2241 if ( icon.SpriteId >= 0 )
2242 {
2243 CursorX11 cX11;
2244 cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
2245 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
2246 {
2247 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
2248 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
2249 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
2250 Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
2251 cX11.Frames.push_back( CursorFrameX11(cursor) );
2252 }
2253
2254 Cursors.push_back( cX11 );
2255
2256 return (gui::ECURSOR_ICON)(Cursors.size() - 1);
2257 }
2258#endif
2259 return gui::ECI_NORMAL;
2260}
2261
2262//! replace the given cursor icon.
2263void CIrrDeviceLinux::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
2264{
2265#ifdef _IRR_COMPILE_WITH_X11_
2266 if ( iconId >= (s32)Cursors.size() )
2267 return;
2268
2269 for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
2270 XFreeCursor(Device->display, Cursors[iconId].Frames[i].IconHW);
2271
2272 if ( icon.SpriteId >= 0 )
2273 {
2274 CursorX11 cX11;
2275 cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
2276 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
2277 {
2278 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
2279 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
2280 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
2281 Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
2282 cX11.Frames.push_back( CursorFrameX11(cursor) );
2283 }
2284
2285 Cursors[iconId] = cX11;
2286 }
2287#endif
2288}
2289
2290irr::core::dimension2di CIrrDeviceLinux::CCursorControl::getSupportedIconSize() const
2291{
2292 // this returns the closest match that is smaller or same size, so we just pass a value which should be large enough for cursors
2293 unsigned int width=0, height=0;
2294#ifdef _IRR_COMPILE_WITH_X11_
2295 XQueryBestCursor(Device->display, Device->window, 64, 64, &width, &height);
2296#endif
2297 return core::dimension2di(width, height);
2298}
2299
2300} // end namespace
2301
2302#endif // _IRR_COMPILE_WITH_X11_DEVICE_
2303