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