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