1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __C_IRR_DEVICE_LINUX_H_INCLUDED__
6 #define __C_IRR_DEVICE_LINUX_H_INCLUDED__
7 
8 #include "IrrCompileConfig.h"
9 
10 #ifdef _IRR_COMPILE_WITH_X11_DEVICE_
11 
12 #include "CIrrDeviceStub.h"
13 #include "IrrlichtDevice.h"
14 #include "IImagePresenter.h"
15 #include "ICursorControl.h"
16 #include "os.h"
17 
18 #ifdef _IRR_COMPILE_WITH_X11_
19 
20 #ifdef _IRR_COMPILE_WITH_OPENGL_
21 #include <GL/gl.h>
22 #define GLX_GLXEXT_LEGACY 1
23 #include <GL/glx.h>
24 #ifdef _IRR_OPENGL_USE_EXTPOINTER_
25 #include "glxext.h"
26 #endif
27 #endif
28 
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/cursorfont.h>
32 #ifdef _IRR_LINUX_X11_VIDMODE_
33 #include <X11/extensions/xf86vmode.h>
34 #endif
35 #ifdef _IRR_LINUX_X11_RANDR_
36 #include <X11/extensions/Xrandr.h>
37 #endif
38 #include <X11/keysym.h>
39 
40 #else
41 #define KeySym s32
42 #endif
43 
44 namespace irr
45 {
46 
47 	class CIrrDeviceLinux : public CIrrDeviceStub, public video::IImagePresenter
48 	{
49 	public:
50 
51 		//! constructor
52 		CIrrDeviceLinux(const SIrrlichtCreationParameters& param);
53 
54 		//! destructor
55 		virtual ~CIrrDeviceLinux();
56 
57 		//! runs the device. Returns false if device wants to be deleted
58 		virtual bool run();
59 
60 		//! Cause the device to temporarily pause execution and let other processes to run
61 		// This should bring down processor usage without major performance loss for Irrlicht
62 		virtual void yield();
63 
64 		//! Pause execution and let other processes to run for a specified amount of time.
65 		virtual void sleep(u32 timeMs, bool pauseTimer);
66 
67 		//! sets the caption of the window
68 		virtual void setWindowCaption(const wchar_t* text);
69 
70 		//! returns if window is active. if not, nothing need to be drawn
71 		virtual bool isWindowActive() const;
72 
73 		//! returns if window has focus.
74 		virtual bool isWindowFocused() const;
75 
76 		//! returns if window is minimized.
77 		virtual bool isWindowMinimized() const;
78 
79 		//! returns color format of the window.
80 		virtual video::ECOLOR_FORMAT getColorFormat() const;
81 
82 		//! presents a surface in the client area
83 		virtual bool present(video::IImage* surface, void* windowId=0, core::rect<s32>* src=0 );
84 
85 		//! notifies the device that it should close itself
86 		virtual void closeDevice();
87 
88 		//! \return Returns a pointer to a list with all video modes
89 		//! supported by the gfx adapter.
90 		video::IVideoModeList* getVideoModeList();
91 
92 		//! Sets if the window should be resizable in windowed mode.
93 		virtual void setResizable(bool resize=false);
94 
95 		//! Minimizes the window.
96 		virtual void minimizeWindow();
97 
98 		//! Maximizes the window.
99 		virtual void maximizeWindow();
100 
101 		//! Restores the window size.
102 		virtual void restoreWindow();
103 
104 		//! Activate any joysticks, and generate events for them.
105 		virtual bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo);
106 
107 		//! Set the current Gamma Value for the Display
108 		virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast );
109 
110 		//! Get the current Gamma Value for the Display
111 		virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast );
112 
113 		//! gets text from the clipboard
114 		//! \return Returns 0 if no string is in there.
115 		virtual const c8* getTextFromClipboard() const;
116 
117 		//! copies text to the clipboard
118 		//! This sets the clipboard selection and _not_ the primary selection which you have on X on the middle mouse button.
119 		virtual void copyToClipboard(const c8* text) const;
120 
121 		//! Remove all messages pending in the system message loop
122 		virtual void clearSystemMessages();
123 
124 		//! Get the device type
getType()125 		virtual E_DEVICE_TYPE getType() const
126 		{
127 				return EIDT_X11;
128 		}
129 
130 #ifdef _IRR_COMPILE_WITH_X11_
131 		// convert an Irrlicht texture to a X11 cursor
132 		Cursor TextureToCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);
133 		Cursor TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);
134 #ifdef _IRR_LINUX_XCURSOR_
135 		Cursor TextureToARGBCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);
136 #endif
137 #endif
138 
139 	private:
140 
141 		//! create the driver
142 		void createDriver();
143 
144 		bool createWindow();
145 
146 		void createKeyMap();
147 
148 		void pollJoysticks();
149 
150 		void initXAtoms();
151 
152 		bool switchToFullscreen(bool reset=false);
153 
154 		//! Implementation of the linux cursor control
155 		class CCursorControl : public gui::ICursorControl
156 		{
157 		public:
158 
159 			CCursorControl(CIrrDeviceLinux* dev, bool null);
160 
161 			~CCursorControl();
162 
163 			//! Changes the visible state of the mouse cursor.
setVisible(bool visible)164 			virtual void setVisible(bool visible)
165 			{
166 				if (visible==IsVisible)
167 					return;
168 				IsVisible = visible;
169 #ifdef _IRR_COMPILE_WITH_X11_
170 				if (!Null)
171 				{
172 					if ( !IsVisible )
173 						XDefineCursor( Device->display, Device->window, invisCursor );
174 					else
175 						XUndefineCursor( Device->display, Device->window );
176 				}
177 #endif
178 			}
179 
180 			//! Returns if the cursor is currently visible.
isVisible()181 			virtual bool isVisible() const
182 			{
183 				return IsVisible;
184 			}
185 
186 			//! Sets the new position of the cursor.
setPosition(const core::position2d<f32> & pos)187 			virtual void setPosition(const core::position2d<f32> &pos)
188 			{
189 				setPosition(pos.X, pos.Y);
190 			}
191 
192 			//! Sets the new position of the cursor.
setPosition(f32 x,f32 y)193 			virtual void setPosition(f32 x, f32 y)
194 			{
195 				setPosition((s32)(x*Device->Width), (s32)(y*Device->Height));
196 			}
197 
198 			//! Sets the new position of the cursor.
setPosition(const core::position2d<s32> & pos)199 			virtual void setPosition(const core::position2d<s32> &pos)
200 			{
201 				setPosition(pos.X, pos.Y);
202 			}
203 
204 			//! Sets the new position of the cursor.
setPosition(s32 x,s32 y)205 			virtual void setPosition(s32 x, s32 y)
206 			{
207 #ifdef _IRR_COMPILE_WITH_X11_
208 
209 				if (!Null)
210 				{
211 					if (UseReferenceRect)
212 					{
213 						XWarpPointer(Device->display,
214 							None,
215 							Device->window, 0, 0,
216 							Device->Width,
217 							Device->Height,
218 							ReferenceRect.UpperLeftCorner.X + x,
219 							ReferenceRect.UpperLeftCorner.Y + y);
220 
221 					}
222 					else
223 					{
224 						XWarpPointer(Device->display,
225 							None,
226 							Device->window, 0, 0,
227 							Device->Width,
228 							Device->Height, x, y);
229 					}
230 					XFlush(Device->display);
231 				}
232 #endif
233 				CursorPos.X = x;
234 				CursorPos.Y = y;
235 			}
236 
237 			//! Returns the current position of the mouse cursor.
getPosition()238 			virtual const core::position2d<s32>& getPosition()
239 			{
240 				updateCursorPos();
241 				return CursorPos;
242 			}
243 
244 			//! Returns the current position of the mouse cursor.
getRelativePosition()245 			virtual core::position2d<f32> getRelativePosition()
246 			{
247 				updateCursorPos();
248 
249 				if (!UseReferenceRect)
250 				{
251 					return core::position2d<f32>(CursorPos.X / (f32)Device->Width,
252 						CursorPos.Y / (f32)Device->Height);
253 				}
254 
255 				return core::position2d<f32>(CursorPos.X / (f32)ReferenceRect.getWidth(),
256 						CursorPos.Y / (f32)ReferenceRect.getHeight());
257 			}
258 
259 			virtual void setReferenceRect(core::rect<s32>* rect=0)
260 			{
261 				if (rect)
262 				{
263 					ReferenceRect = *rect;
264 					UseReferenceRect = true;
265 
266 					// prevent division through zero and uneven sizes
267 
268 					if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2)
269 						ReferenceRect.LowerRightCorner.Y += 1;
270 
271 					if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2)
272 						ReferenceRect.LowerRightCorner.X += 1;
273 				}
274 				else
275 					UseReferenceRect = false;
276 			}
277 
278 			//! Sets the active cursor icon
279 			virtual void setActiveIcon(gui::ECURSOR_ICON iconId);
280 
281 			//! Gets the currently active icon
getActiveIcon()282 			virtual gui::ECURSOR_ICON getActiveIcon() const
283 			{
284 				return ActiveIcon;
285 			}
286 
287 			//! Add a custom sprite as cursor icon.
288 			virtual gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon);
289 
290 			//! replace the given cursor icon.
291 			virtual void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon);
292 
293 			//! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
294 			virtual core::dimension2di getSupportedIconSize() const;
295 
296 #ifdef _IRR_COMPILE_WITH_X11_
297 			//! Set platform specific behavior flags.
setPlatformBehavior(gui::ECURSOR_PLATFORM_BEHAVIOR behavior)298 			virtual void setPlatformBehavior(gui::ECURSOR_PLATFORM_BEHAVIOR behavior) {PlatformBehavior = behavior; }
299 
300 			//! Return platform specific behavior.
getPlatformBehavior()301 			virtual gui::ECURSOR_PLATFORM_BEHAVIOR getPlatformBehavior() const { return PlatformBehavior; }
302 
303 			void update();
304 			void clearCursors();
305 #endif
306 		private:
307 
updateCursorPos()308 			void updateCursorPos()
309 			{
310 #ifdef _IRR_COMPILE_WITH_X11_
311 				if (Null)
312 					return;
313 
314 				if ( PlatformBehavior&gui::ECPB_X11_CACHE_UPDATES && !os::Timer::isStopped() )
315 				{
316 					u32 now = os::Timer::getTime();
317 					if (now <= lastQuery)
318 						return;
319 					lastQuery = now;
320 				}
321 
322 				Window tmp;
323 				int itmp1, itmp2;
324 				unsigned  int maskreturn;
325 				XQueryPointer(Device->display, Device->window,
326 					&tmp, &tmp,
327 					&itmp1, &itmp2,
328 					&CursorPos.X, &CursorPos.Y, &maskreturn);
329 
330 				if (CursorPos.X < 0)
331 					CursorPos.X = 0;
332 				if (CursorPos.X > (s32) Device->Width)
333 					CursorPos.X = Device->Width;
334 				if (CursorPos.Y < 0)
335 					CursorPos.Y = 0;
336 				if (CursorPos.Y > (s32) Device->Height)
337 					CursorPos.Y = Device->Height;
338 #endif
339 			}
340 
341 			CIrrDeviceLinux* Device;
342 			core::position2d<s32> CursorPos;
343 			core::rect<s32> ReferenceRect;
344 #ifdef _IRR_COMPILE_WITH_X11_
345 			gui::ECURSOR_PLATFORM_BEHAVIOR PlatformBehavior;
346 			u32 lastQuery;
347 			Cursor invisCursor;
348 
349 			struct CursorFrameX11
350 			{
CursorFrameX11CursorFrameX11351 				CursorFrameX11() : IconHW(0) {}
CursorFrameX11CursorFrameX11352 				CursorFrameX11(Cursor icon) : IconHW(icon) {}
353 
354 				Cursor IconHW;	// hardware cursor
355 			};
356 
357 			struct CursorX11
358 			{
CursorX11CursorX11359 				CursorX11() {}
FrameTimeCursorX11360 				explicit CursorX11(Cursor iconHw, u32 frameTime=0) : FrameTime(frameTime)
361 				{
362 					Frames.push_back( CursorFrameX11(iconHw) );
363 				}
364 				core::array<CursorFrameX11> Frames;
365 				u32 FrameTime;
366 			};
367 
368 			core::array<CursorX11> Cursors;
369 
370 			void initCursors();
371 #endif
372 			bool IsVisible;
373 			bool Null;
374 			bool UseReferenceRect;
375 			gui::ECURSOR_ICON ActiveIcon;
376 			u32 ActiveIconStartTime;
377 		};
378 
379 		friend class CCursorControl;
380 
381 #ifdef _IRR_COMPILE_WITH_X11_
382 		friend class COpenGLDriver;
383 
384 		Display *display;
385 		XVisualInfo* visual;
386 		int screennr;
387 		Window window;
388 		XSetWindowAttributes attributes;
389 		XSizeHints* StdHints;
390 		XImage* SoftwareImage;
391 		mutable core::stringc Clipboard;
392 		#ifdef _IRR_LINUX_X11_VIDMODE_
393 		XF86VidModeModeInfo oldVideoMode;
394 		#endif
395 		#ifdef _IRR_LINUX_X11_RANDR_
396 		SizeID oldRandrMode;
397 		Rotation oldRandrRotation;
398 		#endif
399 		#ifdef _IRR_COMPILE_WITH_OPENGL_
400 		GLXWindow glxWin;
401 		GLXContext Context;
402 		#endif
403 #endif
404 		u32 Width, Height;
405 		bool WindowHasFocus;
406 		bool WindowMinimized;
407 		bool UseXVidMode;
408 		bool UseXRandR;
409 		bool UseGLXWindow;
410 		bool ExternalWindow;
411 		int AutorepeatSupport;
412 
413 		struct SKeyMap
414 		{
SKeyMapSKeyMap415 			SKeyMap() {}
SKeyMapSKeyMap416 			SKeyMap(s32 x11, s32 win32)
417 				: X11Key(x11), Win32Key(win32)
418 			{
419 			}
420 
421 			KeySym X11Key;
422 			s32 Win32Key;
423 
424 			bool operator<(const SKeyMap& o) const
425 			{
426 				return X11Key<o.X11Key;
427 			}
428 		};
429 
430 		core::array<SKeyMap> KeyMap;
431 
432 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
433 		struct JoystickInfo
434 		{
435 			int	fd;
436 			int	axes;
437 			int	buttons;
438 
439 			SEvent persistentData;
440 
JoystickInfoJoystickInfo441 			JoystickInfo() : fd(-1), axes(0), buttons(0) { }
442 		};
443 		core::array<JoystickInfo> ActiveJoysticks;
444 #endif
445 	};
446 
447 
448 } // end namespace irr
449 
450 #endif // _IRR_COMPILE_WITH_X11_DEVICE_
451 #endif // __C_IRR_DEVICE_LINUX_H_INCLUDED__
452 
453