]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceLinux.h
Implement X11 primary selection
[irrlicht.git] / source / Irrlicht / CIrrDeviceLinux.h
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 #ifndef __C_IRR_DEVICE_LINUX_H_INCLUDED__\r
6 #define __C_IRR_DEVICE_LINUX_H_INCLUDED__\r
7 \r
8 \r
9 #ifdef _IRR_COMPILE_WITH_X11_DEVICE_\r
10 \r
11 #include "CIrrDeviceStub.h"\r
12 #include "IrrlichtDevice.h"\r
13 #include "ICursorControl.h"\r
14 #include "os.h"\r
15 \r
16 #ifdef _IRR_COMPILE_WITH_X11_\r
17 \r
18 #include <X11/Xlib.h>\r
19 #include <X11/Xutil.h>\r
20 #include <X11/cursorfont.h>\r
21 #include <X11/keysym.h>\r
22 \r
23 #ifdef _IRR_LINUX_X11_XINPUT2_\r
24 #include <X11/extensions/XInput2.h>\r
25 #endif\r
26 \r
27 #else\r
28 #define KeySym s32\r
29 #endif\r
30 \r
31 namespace irr\r
32 {\r
33 \r
34         class CIrrDeviceLinux : public CIrrDeviceStub\r
35         {\r
36         public:\r
37 \r
38                 //! constructor\r
39                 CIrrDeviceLinux(const SIrrlichtCreationParameters& param);\r
40 \r
41                 //! destructor\r
42                 virtual ~CIrrDeviceLinux();\r
43 \r
44                 //! runs the device. Returns false if device wants to be deleted\r
45                 bool run() override;\r
46 \r
47                 //! Cause the device to temporarily pause execution and let other processes to run\r
48                 // This should bring down processor usage without major performance loss for Irrlicht\r
49                 void yield() override;\r
50 \r
51                 //! Pause execution and let other processes to run for a specified amount of time.\r
52                 void sleep(u32 timeMs, bool pauseTimer) override;\r
53 \r
54                 //! sets the caption of the window\r
55                 void setWindowCaption(const wchar_t* text) override;\r
56 \r
57                 //! returns if window is active. if not, nothing need to be drawn\r
58                 bool isWindowActive() const override;\r
59 \r
60                 //! returns if window has focus.\r
61                 bool isWindowFocused() const override;\r
62 \r
63                 //! returns if window is minimized.\r
64                 bool isWindowMinimized() const override;\r
65 \r
66                 //! returns last state from maximizeWindow() and restoreWindow()\r
67                 bool isWindowMaximized() const override;\r
68 \r
69                 //! returns color format of the window.\r
70                 video::ECOLOR_FORMAT getColorFormat() const override;\r
71 \r
72                 //! notifies the device that it should close itself\r
73                 void closeDevice() override;\r
74 \r
75                 //! Sets if the window should be resizable in windowed mode.\r
76                 void setResizable(bool resize=false) override;\r
77 \r
78                 //! Resize the render window.\r
79                 void setWindowSize(const irr::core::dimension2d<u32>& size) override;\r
80 \r
81                 //! Minimizes the window.\r
82                 void minimizeWindow() override;\r
83 \r
84                 //! Maximizes the window.\r
85                 void maximizeWindow() override;\r
86 \r
87                 //! Restores the window size.\r
88                 void restoreWindow() override;\r
89 \r
90                 //! Get the position of this window on screen\r
91                 core::position2di getWindowPosition() override;\r
92 \r
93                 //! Activate any joysticks, and generate events for them.\r
94                 bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo) override;\r
95 \r
96                 //! gets text from the clipboard\r
97                 //! \return Returns 0 if no string is in there, otherwise utf-8 text.\r
98                 virtual const c8 *getTextFromClipboard() const;\r
99 \r
100                 //! gets text from the primary selection\r
101                 //! \return Returns 0 if no string is in there, otherwise utf-8 text.\r
102                 virtual const c8 *getTextFromPrimarySelection() const;\r
103 \r
104                 //! copies text to the clipboard\r
105                 //! This sets the clipboard selection and _not_ the primary selection.\r
106                 //! @param text The text in utf-8\r
107                 virtual void copyToClipboard(const c8 *text) const;\r
108 \r
109                 //! copies text to the primary selection\r
110                 //! This sets the primary selection which you have on X on the middle mouse button.\r
111                 //! @param text The text in utf-8\r
112                 virtual void copyToPrimarySelection(const c8 *text) const;\r
113 \r
114                 //! Remove all messages pending in the system message loop\r
115                 void clearSystemMessages() override;\r
116 \r
117                 //! Get the device type\r
118                 E_DEVICE_TYPE getType() const override\r
119                 {\r
120                         return EIDT_X11;\r
121                 }\r
122 \r
123 #ifdef _IRR_COMPILE_WITH_X11_\r
124                 // convert an Irrlicht texture to a X11 cursor\r
125                 Cursor TextureToCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);\r
126                 Cursor TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);\r
127 #ifdef _IRR_LINUX_XCURSOR_\r
128                 Cursor TextureToARGBCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);\r
129 #endif\r
130 #endif\r
131 \r
132         private:\r
133 \r
134                 //! create the driver\r
135                 void createDriver();\r
136 \r
137                 bool createWindow();\r
138 \r
139                 void createKeyMap();\r
140 \r
141                 void pollJoysticks();\r
142 \r
143                 void initXAtoms();\r
144 \r
145                 void initXInput2();\r
146 \r
147                 bool switchToFullscreen();\r
148 \r
149 #ifdef _IRR_COMPILE_WITH_X11_\r
150                 bool createInputContext();\r
151                 void destroyInputContext();\r
152                 EKEY_CODE getKeyCode(XEvent &event);\r
153 \r
154                 const c8 *getTextFromSelection(Atom selection, core::stringc &text_buffer) const;\r
155                 bool becomeSelectionOwner(Atom selection) const;\r
156 #endif\r
157 \r
158                 //! Implementation of the linux cursor control\r
159                 class CCursorControl : public gui::ICursorControl\r
160                 {\r
161                 public:\r
162 \r
163                         CCursorControl(CIrrDeviceLinux* dev, bool null);\r
164 \r
165                         ~CCursorControl();\r
166 \r
167                         //! Changes the visible state of the mouse cursor.\r
168                         void setVisible(bool visible) override\r
169                         {\r
170                                 if (visible==IsVisible)\r
171                                         return;\r
172                                 IsVisible = visible;\r
173 #ifdef _IRR_COMPILE_WITH_X11_\r
174                                 if (!Null)\r
175                                 {\r
176                                         if ( !IsVisible )\r
177                                                 XDefineCursor( Device->XDisplay, Device->XWindow, InvisCursor );\r
178                                         else\r
179                                                 XUndefineCursor( Device->XDisplay, Device->XWindow );\r
180                                 }\r
181 #endif\r
182                         }\r
183 \r
184                         //! Returns if the cursor is currently visible.\r
185                         bool isVisible() const override\r
186                         {\r
187                                 return IsVisible;\r
188                         }\r
189 \r
190                         //! Sets the new position of the cursor.\r
191                         void setPosition(const core::position2d<f32> &pos) override\r
192                         {\r
193                                 setPosition(pos.X, pos.Y);\r
194                         }\r
195 \r
196                         //! Sets the new position of the cursor.\r
197                         void setPosition(f32 x, f32 y) override\r
198                         {\r
199                                 setPosition((s32)(x*Device->Width), (s32)(y*Device->Height));\r
200                         }\r
201 \r
202                         //! Sets the new position of the cursor.\r
203                         void setPosition(const core::position2d<s32> &pos) override\r
204                         {\r
205                                 setPosition(pos.X, pos.Y);\r
206                         }\r
207 \r
208                         //! Sets the new position of the cursor.\r
209                         void setPosition(s32 x, s32 y) override\r
210                         {\r
211 #ifdef _IRR_COMPILE_WITH_X11_\r
212 \r
213                                 if (!Null)\r
214                                 {\r
215                                         if (UseReferenceRect)\r
216                                         {\r
217 // NOTE: XIWarpPointer works when X11 has set a coordinate transformation matrix for the mouse unlike XWarpPointer\r
218 // which runs into a bug mentioned here: https://gitlab.freedesktop.org/xorg/xserver/-/issues/600\r
219 // So also workaround for Irrlicht bug #450\r
220 #ifdef _IRR_LINUX_X11_XINPUT2_\r
221                                                 if ( DeviceId != 0)\r
222                                                 {\r
223                                                         XIWarpPointer(Device->XDisplay,\r
224                                                                 DeviceId,\r
225                                                                 None,\r
226                                                                 Device->XWindow, 0, 0,\r
227                                                                 Device->Width,\r
228                                                                 Device->Height,\r
229                                                                 ReferenceRect.UpperLeftCorner.X + x,\r
230                                                                 ReferenceRect.UpperLeftCorner.Y + y);\r
231                                                 }\r
232                                                 else\r
233 #endif\r
234                                                 {\r
235                                                         XWarpPointer(Device->XDisplay,\r
236                                                                 None,\r
237                                                                 Device->XWindow, 0, 0,\r
238                                                                 Device->Width,\r
239                                                                 Device->Height,\r
240                                                                 ReferenceRect.UpperLeftCorner.X + x,\r
241                                                                 ReferenceRect.UpperLeftCorner.Y + y);\r
242                                                 }\r
243                                         }\r
244                                         else\r
245                                         {\r
246 #ifdef _IRR_LINUX_X11_XINPUT2_\r
247                                                 if ( DeviceId != 0)\r
248                                                 {\r
249                                                         XIWarpPointer(Device->XDisplay,\r
250                                                                 DeviceId,\r
251                                                                 None,\r
252                                                                 Device->XWindow, 0, 0,\r
253                                                                 Device->Width,\r
254                                                                 Device->Height, x, y);\r
255                                                 }\r
256                                                 else\r
257 #endif\r
258                                                 {\r
259                                                         XWarpPointer(Device->XDisplay,\r
260                                                                 None,\r
261                                                                 Device->XWindow, 0, 0,\r
262                                                                 Device->Width,\r
263                                                                 Device->Height, x, y);\r
264                                                 }\r
265                                         }\r
266                                         XFlush(Device->XDisplay);\r
267                                 }\r
268 #endif\r
269                                 CursorPos.X = x;\r
270                                 CursorPos.Y = y;\r
271                         }\r
272 \r
273                         //! Returns the current position of the mouse cursor.\r
274                         const core::position2d<s32>& getPosition(bool updateCursor) override\r
275                         {\r
276                                 if ( updateCursor )\r
277                                         updateCursorPos();\r
278                                 return CursorPos;\r
279                         }\r
280 \r
281                         //! Returns the current position of the mouse cursor.\r
282                         core::position2d<f32> getRelativePosition(bool updateCursor) override\r
283                         {\r
284                                 if ( updateCursor )\r
285                                         updateCursorPos();\r
286 \r
287                                 if (!UseReferenceRect)\r
288                                 {\r
289                                         return core::position2d<f32>(CursorPos.X / (f32)Device->Width,\r
290                                                 CursorPos.Y / (f32)Device->Height);\r
291                                 }\r
292 \r
293                                 return core::position2d<f32>(CursorPos.X / (f32)ReferenceRect.getWidth(),\r
294                                                 CursorPos.Y / (f32)ReferenceRect.getHeight());\r
295                         }\r
296 \r
297                         void setReferenceRect(core::rect<s32>* rect=0) override\r
298                         {\r
299                                 if (rect)\r
300                                 {\r
301                                         ReferenceRect = *rect;\r
302                                         UseReferenceRect = true;\r
303 \r
304                                         // prevent division through zero and uneven sizes\r
305 \r
306                                         if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2)\r
307                                                 ReferenceRect.LowerRightCorner.Y += 1;\r
308 \r
309                                         if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2)\r
310                                                 ReferenceRect.LowerRightCorner.X += 1;\r
311                                 }\r
312                                 else\r
313                                         UseReferenceRect = false;\r
314                         }\r
315 \r
316                         //! Sets the active cursor icon\r
317                         void setActiveIcon(gui::ECURSOR_ICON iconId) override;\r
318 \r
319                         //! Gets the currently active icon\r
320                         gui::ECURSOR_ICON getActiveIcon() const override\r
321                         {\r
322                                 return ActiveIcon;\r
323                         }\r
324 \r
325                         //! Add a custom sprite as cursor icon.\r
326                         gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) override;\r
327 \r
328                         //! replace the given cursor icon.\r
329                         void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) override;\r
330 \r
331                         //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.\r
332                         core::dimension2di getSupportedIconSize() const override;\r
333 \r
334 #ifdef _IRR_COMPILE_WITH_X11_\r
335                         //! Set platform specific behavior flags.\r
336                         void setPlatformBehavior(gui::ECURSOR_PLATFORM_BEHAVIOR behavior) override {PlatformBehavior = behavior; }\r
337 \r
338                         //! Return platform specific behavior.\r
339                         gui::ECURSOR_PLATFORM_BEHAVIOR getPlatformBehavior() const override { return PlatformBehavior; }\r
340 \r
341                         void update();\r
342                         void clearCursors();\r
343 #endif\r
344                 private:\r
345 \r
346                         void updateCursorPos()\r
347                         {\r
348 #ifdef _IRR_COMPILE_WITH_X11_\r
349                                 if (Null)\r
350                                         return;\r
351 \r
352                                 if ( PlatformBehavior&gui::ECPB_X11_CACHE_UPDATES && !os::Timer::isStopped() )\r
353                                 {\r
354                                         u32 now = os::Timer::getTime();\r
355                                         if (now <= LastQuery)\r
356                                                 return;\r
357                                         LastQuery = now;\r
358                                 }\r
359 \r
360                                 Window tmp;\r
361                                 int itmp1, itmp2;\r
362                                 unsigned  int maskreturn;\r
363                                 XQueryPointer(Device->XDisplay, Device->XWindow,\r
364                                         &tmp, &tmp,\r
365                                         &itmp1, &itmp2,\r
366                                         &CursorPos.X, &CursorPos.Y, &maskreturn);\r
367 #endif\r
368                         }\r
369 \r
370                         CIrrDeviceLinux* Device;\r
371                         core::position2d<s32> CursorPos;\r
372                         core::rect<s32> ReferenceRect;\r
373 #ifdef _IRR_COMPILE_WITH_X11_\r
374                         gui::ECURSOR_PLATFORM_BEHAVIOR PlatformBehavior;\r
375                         u32 LastQuery;\r
376                         Cursor InvisCursor;\r
377 \r
378 #ifdef _IRR_LINUX_X11_XINPUT2_\r
379                         int DeviceId;\r
380 #endif\r
381 \r
382                         struct CursorFrameX11\r
383                         {\r
384                                 CursorFrameX11() : IconHW(0) {}\r
385                                 CursorFrameX11(Cursor icon) : IconHW(icon) {}\r
386 \r
387                                 Cursor IconHW;  // hardware cursor\r
388                         };\r
389 \r
390                         struct CursorX11\r
391                         {\r
392                                 CursorX11() {}\r
393                                 explicit CursorX11(Cursor iconHw, u32 frameTime=0) : FrameTime(frameTime)\r
394                                 {\r
395                                         Frames.push_back( CursorFrameX11(iconHw) );\r
396                                 }\r
397                                 core::array<CursorFrameX11> Frames;\r
398                                 u32 FrameTime;\r
399                         };\r
400 \r
401                         core::array<CursorX11> Cursors;\r
402 \r
403                         void initCursors();\r
404 #endif\r
405                         bool IsVisible;\r
406                         bool Null;\r
407                         bool UseReferenceRect;\r
408                         gui::ECURSOR_ICON ActiveIcon;\r
409                         u32 ActiveIconStartTime;\r
410                 };\r
411 \r
412                 friend class CCursorControl;\r
413 \r
414 #ifdef _IRR_COMPILE_WITH_X11_\r
415                 friend class COpenGLDriver;\r
416 \r
417                 Display *XDisplay;\r
418                 XVisualInfo* VisualInfo;\r
419                 int Screennr;\r
420                 Window XWindow;\r
421                 XSetWindowAttributes WndAttributes;\r
422                 XSizeHints* StdHints;\r
423                 XIM XInputMethod;\r
424                 XIC XInputContext;\r
425                 bool HasNetWM;\r
426                 // text is utf-8\r
427                 mutable core::stringc Clipboard;\r
428                 mutable core::stringc PrimarySelection;\r
429 #endif\r
430 #if defined(_IRR_LINUX_X11_XINPUT2_)\r
431                 int currentTouchedCount;\r
432 #endif\r
433                 u32 Width, Height;\r
434                 bool WindowHasFocus;\r
435                 bool WindowMinimized;\r
436                 bool WindowMaximized;\r
437                 bool ExternalWindow;\r
438                 int AutorepeatSupport;\r
439 \r
440                 struct SKeyMap\r
441                 {\r
442                         SKeyMap() {}\r
443                         SKeyMap(s32 x11, s32 win32)\r
444                                 : X11Key(x11), Win32Key(win32)\r
445                         {\r
446                         }\r
447 \r
448                         KeySym X11Key;\r
449                         s32 Win32Key;\r
450 \r
451                         bool operator<(const SKeyMap& o) const\r
452                         {\r
453                                 return X11Key<o.X11Key;\r
454                         }\r
455                 };\r
456 \r
457                 core::array<SKeyMap> KeyMap;\r
458 \r
459 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
460                 struct JoystickInfo\r
461                 {\r
462                         int     fd;\r
463                         int     axes;\r
464                         int     buttons;\r
465 \r
466                         SEvent persistentData;\r
467 \r
468                         JoystickInfo() : fd(-1), axes(0), buttons(0) { }\r
469                 };\r
470                 core::array<JoystickInfo> ActiveJoysticks;\r
471 #endif\r
472         };\r
473 \r
474 \r
475 } // end namespace irr\r
476 \r
477 #endif // _IRR_COMPILE_WITH_X11_DEVICE_\r
478 #endif // __C_IRR_DEVICE_LINUX_H_INCLUDED__\r
479 \r