2
0

os_x11.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  1. /*************************************************************************/
  2. /* os_x11.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "servers/visual/visual_server_raster.h"
  30. #include "drivers/gles2/rasterizer_gles2.h"
  31. #include "drivers/gles1/rasterizer_gles1.h"
  32. #include "os_x11.h"
  33. #include "key_mapping_x11.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include "print_string.h"
  37. #include "servers/physics/physics_server_sw.h"
  38. #include "X11/Xutil.h"
  39. #include "main/main.h"
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #include <fcntl.h>
  43. #include <unistd.h>
  44. #include <linux/joystick.h>
  45. //stupid linux.h
  46. #ifdef KEY_TAB
  47. #undef KEY_TAB
  48. #endif
  49. #include <X11/Xatom.h>
  50. #include "os/pc_joystick_map.h"
  51. #undef CursorShape
  52. int OS_X11::get_video_driver_count() const {
  53. return 2;
  54. }
  55. const char * OS_X11::get_video_driver_name(int p_driver) const {
  56. return p_driver==0?"GLES2":"GLES1";
  57. }
  58. OS::VideoMode OS_X11::get_default_video_mode() const {
  59. return OS::VideoMode(800,600,false);
  60. }
  61. void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
  62. last_button_state=0;
  63. dpad_last[0]=0;
  64. dpad_last[1]=0;
  65. xmbstring=NULL;
  66. event_id=0;
  67. x11_window=0;
  68. last_click_ms=0;
  69. args=OS::get_singleton()->get_cmdline_args();
  70. current_videomode=p_desired;
  71. main_loop=NULL;
  72. last_timestamp=0;
  73. last_mouse_pos_valid=false;
  74. last_keyrelease_time=0;
  75. if (get_render_thread_mode()==RENDER_SEPARATE_THREAD) {
  76. XInitThreads();
  77. }
  78. /** XLIB INITIALIZATION **/
  79. x11_display = XOpenDisplay(NULL);
  80. char * modifiers = XSetLocaleModifiers ("@im=none");
  81. ERR_FAIL_COND( modifiers == NULL );
  82. xim = XOpenIM (x11_display, NULL, NULL, NULL);
  83. if (xim == NULL) {
  84. WARN_PRINT("XOpenIM failed");
  85. xim_style=NULL;
  86. } else {
  87. ::XIMStyles *xim_styles=NULL;
  88. xim_style=0;
  89. char *imvalret=NULL;
  90. imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
  91. if (imvalret != NULL || xim_styles == NULL) {
  92. fprintf (stderr, "Input method doesn't support any styles\n");
  93. }
  94. if (xim_styles) {
  95. xim_style = 0;
  96. for (int i=0;i<xim_styles->count_styles;i++) {
  97. if (xim_styles->supported_styles[i] ==
  98. (XIMPreeditNothing | XIMStatusNothing)) {
  99. xim_style = xim_styles->supported_styles[i];
  100. break;
  101. }
  102. }
  103. XFree (xim_styles);
  104. }
  105. }
  106. /*
  107. char* windowid = getenv("GODOT_WINDOWID");
  108. if (windowid) {
  109. //freopen("/home/punto/stdout", "w", stdout);
  110. //reopen("/home/punto/stderr", "w", stderr);
  111. x11_window = atol(windowid);
  112. XWindowAttributes xwa;
  113. XGetWindowAttributes(x11_display,x11_window,&xwa);
  114. current_videomode.width = xwa.width;
  115. current_videomode.height = xwa.height;
  116. };
  117. */
  118. // maybe contextgl wants to be in charge of creating the window
  119. //print_line("def videomode "+itos(current_videomode.width)+","+itos(current_videomode.height));
  120. #if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
  121. context_gl = memnew( ContextGL_X11( x11_display, x11_window,current_videomode, false ) );
  122. context_gl->initialize();
  123. if (p_video_driver == 0) {
  124. rasterizer = memnew( RasterizerGLES2 );
  125. } else {
  126. rasterizer = memnew( RasterizerGLES1 );
  127. };
  128. #endif
  129. visual_server = memnew( VisualServerRaster(rasterizer) );
  130. if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
  131. visual_server =memnew(VisualServerWrapMT(visual_server,get_render_thread_mode()==RENDER_SEPARATE_THREAD));
  132. }
  133. AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
  134. if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
  135. ERR_PRINT("Initializing audio failed.");
  136. }
  137. sample_manager = memnew( SampleManagerMallocSW );
  138. audio_server = memnew( AudioServerSW(sample_manager) );
  139. audio_server->init();
  140. spatial_sound_server = memnew( SpatialSoundServerSW );
  141. spatial_sound_server->init();
  142. spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
  143. spatial_sound_2d_server->init();
  144. ERR_FAIL_COND(!visual_server);
  145. ERR_FAIL_COND(x11_window==0);
  146. XSetWindowAttributes new_attr;
  147. new_attr.event_mask=KeyPressMask | KeyReleaseMask | ButtonPressMask |
  148. ButtonReleaseMask | EnterWindowMask |
  149. LeaveWindowMask | PointerMotionMask |
  150. Button1MotionMask |
  151. Button2MotionMask | Button3MotionMask |
  152. Button4MotionMask | Button5MotionMask |
  153. ButtonMotionMask | KeymapStateMask |
  154. ExposureMask | VisibilityChangeMask |
  155. StructureNotifyMask |
  156. SubstructureNotifyMask | SubstructureRedirectMask |
  157. FocusChangeMask | PropertyChangeMask |
  158. ColormapChangeMask | OwnerGrabButtonMask;
  159. XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr);
  160. wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
  161. XSetWMProtocols(x11_display, x11_window, &wm_delete, 1);
  162. if (xim && xim_style) {
  163. xic = XCreateIC (xim,XNInputStyle, xim_style,XNClientWindow,x11_window,XNFocusWindow, x11_window, (char*)NULL);
  164. } else {
  165. xic=NULL;
  166. WARN_PRINT("XCreateIC couldn't create xic");
  167. }
  168. XcursorSetTheme(x11_display,"default");
  169. cursor_size = XcursorGetDefaultSize(x11_display);
  170. cursor_theme = XcursorGetTheme(x11_display);
  171. if (!cursor_theme) {
  172. print_line("not found theme");
  173. cursor_theme="default";
  174. }
  175. for(int i=0;i<CURSOR_MAX;i++) {
  176. cursors[i]=None;
  177. }
  178. current_cursor=CURSOR_ARROW;
  179. if (cursor_theme) {
  180. //print_line("cursor theme: "+String(cursor_theme));
  181. for(int i=0;i<CURSOR_MAX;i++) {
  182. static const char *cursor_file[]={
  183. "left_ptr",
  184. "xterm",
  185. "hand2",
  186. "cross",
  187. "watch",
  188. "left_ptr_watch",
  189. "fleur",
  190. "hand1",
  191. "X_cursor",
  192. "sb_v_double_arrow",
  193. "sb_h_double_arrow",
  194. "size_bdiag",
  195. "size_fdiag",
  196. "hand1",
  197. "sb_v_double_arrow",
  198. "sb_h_double_arrow",
  199. "question_arrow"
  200. };
  201. XcursorImage *img = XcursorLibraryLoadImage(cursor_file[i],cursor_theme,cursor_size);
  202. if (img) {
  203. cursors[i]=XcursorImageLoadCursor(x11_display,img);
  204. //print_line("found cursor: "+String(cursor_file[i])+" id "+itos(cursors[i]));
  205. } else {
  206. if (OS::is_stdout_verbose())
  207. print_line("failed cursor: "+String(cursor_file[i]));
  208. }
  209. }
  210. }
  211. {
  212. Pixmap cursormask;
  213. XGCValues xgc;
  214. GC gc;
  215. XColor col;
  216. Cursor cursor;
  217. cursormask = XCreatePixmap(x11_display, RootWindow(x11_display,DefaultScreen(x11_display)), 1, 1, 1);
  218. xgc.function = GXclear;
  219. gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
  220. XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
  221. col.pixel = 0;
  222. col.red = 0;
  223. col.flags = 4;
  224. cursor = XCreatePixmapCursor(x11_display,
  225. cursormask, cursormask,
  226. &col, &col, 0, 0);
  227. XFreePixmap(x11_display, cursormask);
  228. XFreeGC(x11_display, gc);
  229. if (cursor == None)
  230. {
  231. ERR_PRINT("FAILED CREATING CURSOR");
  232. }
  233. null_cursor=cursor;
  234. }
  235. set_cursor_shape(CURSOR_BUSY);
  236. visual_server->init();
  237. //
  238. physics_server = memnew( PhysicsServerSW );
  239. physics_server->init();
  240. physics_2d_server = memnew( Physics2DServerSW );
  241. physics_2d_server->init();
  242. input = memnew( InputDefault );
  243. probe_joystick();
  244. _ensure_data_dir();
  245. net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
  246. //printf("got map notify\n");
  247. }
  248. void OS_X11::finalize() {
  249. if(main_loop)
  250. memdelete(main_loop);
  251. main_loop=NULL;
  252. spatial_sound_server->finish();
  253. memdelete(spatial_sound_server);
  254. spatial_sound_2d_server->finish();
  255. memdelete(spatial_sound_2d_server);
  256. //if (debugger_connection_console) {
  257. // memdelete(debugger_connection_console);
  258. //}
  259. audio_server->finish();
  260. memdelete(audio_server);
  261. memdelete(sample_manager);
  262. visual_server->finish();
  263. memdelete(visual_server);
  264. memdelete(rasterizer);
  265. physics_server->finish();
  266. memdelete(physics_server);
  267. physics_2d_server->finish();
  268. memdelete(physics_2d_server);
  269. memdelete(input);
  270. #if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
  271. memdelete(context_gl);
  272. #endif
  273. XCloseDisplay(x11_display);
  274. if (xmbstring)
  275. memfree(xmbstring);
  276. args.clear();
  277. }
  278. void OS_X11::set_mouse_mode(MouseMode p_mode) {
  279. print_line("WUTF "+itos(p_mode)+" old "+itos(mouse_mode));
  280. if (p_mode==mouse_mode)
  281. return;
  282. if (mouse_mode==MOUSE_MODE_CAPTURED)
  283. XUngrabPointer(x11_display, CurrentTime);
  284. if (mouse_mode!=MOUSE_MODE_VISIBLE && p_mode==MOUSE_MODE_VISIBLE)
  285. XUndefineCursor(x11_display,x11_window);
  286. if (p_mode!=MOUSE_MODE_VISIBLE && mouse_mode==MOUSE_MODE_VISIBLE) {
  287. XDefineCursor(x11_display,x11_window,null_cursor);
  288. }
  289. mouse_mode=p_mode;
  290. if (mouse_mode==MOUSE_MODE_CAPTURED) {
  291. if (XGrabPointer(x11_display, x11_window, True,
  292. ButtonPressMask | ButtonReleaseMask |
  293. PointerMotionMask, GrabModeAsync, GrabModeAsync,
  294. x11_window, None, CurrentTime) !=
  295. GrabSuccess) {
  296. ERR_PRINT("NO GRAB");
  297. }
  298. center.x = current_videomode.width/2;
  299. center.y = current_videomode.height/2;
  300. XWarpPointer(x11_display, None, x11_window,
  301. 0,0,0,0, (int)center.x, (int)center.y);
  302. }
  303. }
  304. OS::MouseMode OS_X11::get_mouse_mode() const {
  305. return mouse_mode;
  306. }
  307. int OS_X11::get_mouse_button_state() const {
  308. return last_button_state;
  309. }
  310. Point2 OS_X11::get_mouse_pos() const {
  311. return last_mouse_pos;
  312. }
  313. void OS_X11::set_window_title(const String& p_title) {
  314. XStoreName(x11_display,x11_window,p_title.utf8().get_data());
  315. }
  316. void OS_X11::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
  317. }
  318. OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
  319. return current_videomode;
  320. }
  321. void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
  322. }
  323. InputModifierState OS_X11::get_key_modifier_state(unsigned int p_x11_state) {
  324. InputModifierState state;
  325. state.shift = (p_x11_state&ShiftMask);
  326. state.control = (p_x11_state&ControlMask);
  327. state.alt = (p_x11_state&Mod1Mask /*|| p_x11_state&Mod5Mask*/); //altgr should not count as alt
  328. state.meta = (p_x11_state&Mod4Mask);
  329. return state;
  330. }
  331. unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
  332. unsigned int state=0;
  333. if (p_x11_state&Button1Mask) {
  334. state|=1<<0;
  335. }
  336. if (p_x11_state&Button3Mask) {
  337. state|=1<<1;
  338. }
  339. if (p_x11_state&Button2Mask) {
  340. state|=1<<2;
  341. }
  342. if (p_x11_state&Button4Mask) {
  343. state|=1<<3;
  344. }
  345. if (p_x11_state&Button5Mask) {
  346. state|=1<<4;
  347. }
  348. last_button_state=state;
  349. return state;
  350. }
  351. void OS_X11::handle_key_event(XKeyEvent *p_event) {
  352. // X11 functions don't know what const is
  353. XKeyEvent *xkeyevent = p_event;
  354. // This code was pretty difficult to write.
  355. // The docs stink and every toolkit seems to
  356. // do it in a different way.
  357. /* Phase 1, obtain a proper keysym */
  358. // This was also very difficult to figure out.
  359. // You'd expect you could just use Keysym provided by
  360. // XKeycodeToKeysym to obtain internationalized
  361. // input.. WRONG!!
  362. // you must use XLookupString (???) which not only wastes
  363. // cycles generating an unnecesary string, but also
  364. // still works in half the cases. (won't handle deadkeys)
  365. // For more complex input methods (deadkeys and more advanced)
  366. // you have to use XmbLookupString (??).
  367. // So.. then you have to chosse which of both results
  368. // you want to keep.
  369. // This is a real bizarreness and cpu waster.
  370. KeySym keysym_keycode=0; // keysym used to find a keycode
  371. KeySym keysym_unicode=0; // keysym used to find unicode
  372. int nbytes=0; // bytes the string takes
  373. // XLookupString returns keysyms usable as nice scancodes/
  374. char str[256+1];
  375. nbytes=XLookupString(xkeyevent, str, 256, &keysym_keycode, NULL);
  376. // Meanwhile, XLookupString returns keysyms useful for unicode.
  377. if (!xmbstring) {
  378. // keep a temporary buffer for the string
  379. xmbstring=(char*)memalloc(sizeof(char)*8);
  380. xmblen=8;
  381. }
  382. if (xkeyevent->type == KeyPress && xic) {
  383. Status status;
  384. do {
  385. int mnbytes = XmbLookupString (xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
  386. xmbstring[mnbytes] = '\0';
  387. if (status == XBufferOverflow) {
  388. xmblen = mnbytes + 1;
  389. xmbstring = (char*)memrealloc (xmbstring, xmblen);
  390. }
  391. } while (status == XBufferOverflow);
  392. }
  393. /* Phase 2, obtain a pigui keycode from the keysym */
  394. // KeyMappingX11 just translated the X11 keysym to a PIGUI
  395. // keysym, so it works in all platforms the same.
  396. unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
  397. /* Phase 3, obtain an unicode character from the keysym */
  398. // KeyMappingX11 also translates keysym to unicode.
  399. // It does a binary search on a table to translate
  400. // most properly.
  401. //print_line("keysym_unicode: "+rtos(keysym_unicode));
  402. unsigned int unicode = keysym_unicode>0? KeyMappingX11::get_unicode_from_keysym(keysym_unicode):0;
  403. /* Phase 4, determine if event must be filtered */
  404. // This seems to be a side-effect of using XIM.
  405. // XEventFilter looks like a core X11 funciton,
  406. // but it's actually just used to see if we must
  407. // ignore a deadkey, or events XIM determines
  408. // must not reach the actual gui.
  409. // Guess it was a design problem of the extension
  410. bool keypress = xkeyevent->type == KeyPress;
  411. if (xkeyevent->type == KeyPress && xic) {
  412. if (XFilterEvent((XEvent*)xkeyevent, x11_window))
  413. return;
  414. }
  415. if (keycode==0 && unicode==0)
  416. return;
  417. /* Phase 5, determine modifier mask */
  418. // No problems here, except I had no way to
  419. // know Mod1 was ALT and Mod4 was META (applekey/winkey)
  420. // just tried Mods until i found them.
  421. //print_line("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
  422. InputModifierState state = get_key_modifier_state(xkeyevent->state);
  423. /* Phase 6, determine echo character */
  424. // Echo characters in X11 are a keyrelease and a keypress
  425. // one after the other with the (almot) same timestamp.
  426. // To detect them, i use XPeekEvent and check that their
  427. // difference in time is below a treshold.
  428. bool echo=false;
  429. if (xkeyevent->type == KeyPress) {
  430. // saved the time of the last keyrelease to see
  431. // if it's the same as this keypress.
  432. if (xkeyevent->time==last_keyrelease_time)
  433. echo=true;
  434. } else {
  435. // make sure there are events pending,
  436. // so this call won't block.
  437. if (XPending(x11_display)>0) {
  438. XEvent peek_event;
  439. XPeekEvent(x11_display, &peek_event);
  440. // I'm using a treshold of 5 msecs,
  441. // since sometimes there seems to be a little
  442. // jitter. I'm still not convinced that all this approach
  443. // is correct, but the xorg developers are
  444. // not very helpful today.
  445. ::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
  446. if (peek_event.type == KeyPress && tresh<5 )
  447. echo=true;
  448. // use the time from peek_event so it always works
  449. last_keyrelease_time=peek_event.xkey.time;
  450. } else {
  451. last_keyrelease_time=xkeyevent->time;
  452. }
  453. // save the time to check for echo when keypress happens
  454. }
  455. /* Phase 7, send event to Window */
  456. InputEvent event;
  457. event.ID=++event_id;
  458. event.type = InputEvent::KEY;
  459. event.device=0;
  460. event.key.mod=state;
  461. event.key.pressed=keypress;
  462. if (keycode>='a' && keycode<='z')
  463. keycode-='a'-'A';
  464. event.key.scancode=keycode;
  465. event.key.unicode=unicode;
  466. event.key.echo=echo;
  467. if (event.key.scancode==KEY_BACKTAB) {
  468. //make it consistent accross platforms.
  469. event.key.scancode=KEY_TAB;
  470. event.key.mod.shift=true;
  471. }
  472. //printf("key: %x\n",event.key.scancode);
  473. input->parse_input_event( event);
  474. }
  475. void OS_X11::process_xevents() {
  476. //printf("checking events %i\n", XPending(x11_display));
  477. bool do_mouse_warp=false;
  478. while (XPending(x11_display) > 0) {
  479. XEvent event;
  480. XNextEvent(x11_display, &event);
  481. switch (event.type) {
  482. case Expose:
  483. Main::force_redraw();
  484. break;
  485. case NoExpose:
  486. minimized = true;
  487. break;
  488. case VisibilityNotify: {
  489. XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
  490. minimized = (visibility->state == VisibilityFullyObscured);
  491. } break;
  492. case FocusIn:
  493. main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
  494. if (mouse_mode==MOUSE_MODE_CAPTURED) {
  495. XGrabPointer(x11_display, x11_window, True,
  496. ButtonPressMask | ButtonReleaseMask |
  497. PointerMotionMask, GrabModeAsync, GrabModeAsync,
  498. x11_window, None, CurrentTime);
  499. }
  500. break;
  501. case FocusOut:
  502. main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
  503. if (mouse_mode==MOUSE_MODE_CAPTURED) {
  504. //dear X11, I try, I really try, but you never work, you do whathever you want.
  505. XUngrabPointer(x11_display, CurrentTime);
  506. }
  507. break;
  508. case ConfigureNotify:
  509. /* call resizeGLScene only if our window-size changed */
  510. if ((event.xconfigure.width == current_videomode.width) &&
  511. (event.xconfigure.height == current_videomode.height))
  512. break;
  513. current_videomode.width=event.xconfigure.width;
  514. current_videomode.height=event.xconfigure.height;
  515. break;
  516. case ButtonPress:
  517. case ButtonRelease: {
  518. /* exit in case of a mouse button press */
  519. last_timestamp=event.xbutton.time;
  520. if (mouse_mode==MOUSE_MODE_CAPTURED) {
  521. event.xbutton.x=last_mouse_pos.x;
  522. event.xbutton.y=last_mouse_pos.y;
  523. }
  524. InputEvent mouse_event;
  525. mouse_event.ID=++event_id;
  526. mouse_event.type = InputEvent::MOUSE_BUTTON;
  527. mouse_event.device=0;
  528. mouse_event.mouse_button.mod = get_key_modifier_state(event.xbutton.state);
  529. mouse_event.mouse_button.button_mask = get_mouse_button_state(event.xbutton.state);
  530. mouse_event.mouse_button.x=event.xbutton.x;
  531. mouse_event.mouse_button.y=event.xbutton.y;
  532. mouse_event.mouse_button.global_x=event.xbutton.x;
  533. mouse_event.mouse_button.global_y=event.xbutton.y;
  534. mouse_event.mouse_button.button_index=event.xbutton.button;
  535. if (mouse_event.mouse_button.button_index==2)
  536. mouse_event.mouse_button.button_index=3;
  537. else if (mouse_event.mouse_button.button_index==3)
  538. mouse_event.mouse_button.button_index=2;
  539. mouse_event.mouse_button.pressed=(event.type==ButtonPress);
  540. if (event.type==ButtonPress && event.xbutton.button==1) {
  541. uint64_t diff = get_ticks_usec()/1000 - last_click_ms;
  542. if (diff<400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x,event.xbutton.y))<5) {
  543. last_click_ms=0;
  544. last_click_pos = Point2(-100,-100);
  545. mouse_event.mouse_button.doubleclick=true;
  546. mouse_event.ID=++event_id;
  547. } else {
  548. last_click_ms+=diff;
  549. last_click_pos = Point2(event.xbutton.x,event.xbutton.y);
  550. }
  551. }
  552. input->parse_input_event( mouse_event);
  553. } break;
  554. case MotionNotify: {
  555. last_timestamp=event.xmotion.time;
  556. // Motion is also simple.
  557. // A little hack is in order
  558. // to be able to send relative motion events.
  559. Point2i pos( event.xmotion.x, event.xmotion.y );
  560. if (mouse_mode==MOUSE_MODE_CAPTURED) {
  561. #if 1
  562. Vector2 c = Point2i(current_videomode.width/2,current_videomode.height/2);
  563. if (pos==Point2i(current_videomode.width/2,current_videomode.height/2)) {
  564. //this sucks, it's a hack, etc and is a little inaccurate, etc.
  565. //but nothing I can do, X11 sucks.
  566. center=pos;
  567. break;
  568. }
  569. Point2i ncenter = pos;
  570. pos = last_mouse_pos + ( pos-center );
  571. center=ncenter;
  572. do_mouse_warp=true;
  573. #else
  574. //Dear X11, thanks for making my life miserable
  575. center.x = current_videomode.width/2;
  576. center.y = current_videomode.height/2;
  577. pos = last_mouse_pos + ( pos-center );
  578. if (pos==last_mouse_pos)
  579. break;
  580. XWarpPointer(x11_display, None, x11_window,
  581. 0,0,0,0, (int)center.x, (int)center.y);
  582. #endif
  583. }
  584. if (!last_mouse_pos_valid) {
  585. last_mouse_pos=pos;
  586. last_mouse_pos_valid=true;
  587. }
  588. Point2i rel = pos - last_mouse_pos;
  589. InputEvent motion_event;
  590. motion_event.ID=++event_id;
  591. motion_event.type=InputEvent::MOUSE_MOTION;
  592. motion_event.device=0;
  593. motion_event.mouse_motion.mod = get_key_modifier_state(event.xmotion.state);
  594. motion_event.mouse_motion.button_mask = get_mouse_button_state(event.xmotion.state);
  595. motion_event.mouse_motion.x=pos.x;
  596. motion_event.mouse_motion.y=pos.y;
  597. input->set_mouse_pos(pos);
  598. motion_event.mouse_motion.global_x=pos.x;
  599. motion_event.mouse_motion.global_y=pos.y;
  600. motion_event.mouse_motion.speed_x=input->get_mouse_speed().x;
  601. motion_event.mouse_motion.speed_y=input->get_mouse_speed().y;
  602. motion_event.mouse_motion.relative_x=rel.x;
  603. motion_event.mouse_motion.relative_y=rel.y;
  604. last_mouse_pos=pos;
  605. input->parse_input_event( motion_event);
  606. } break;
  607. case KeyPress:
  608. case KeyRelease: {
  609. last_timestamp=event.xkey.time;
  610. // key event is a little complex, so
  611. // it will be handled in it's own function.
  612. handle_key_event( (XKeyEvent*)&event );
  613. } break;
  614. case SelectionRequest: {
  615. XSelectionRequestEvent *req;
  616. XEvent e, respond;
  617. e = event;
  618. req=&(e.xselectionrequest);
  619. if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
  620. req->target == XInternAtom(x11_display, "UTF8_STRING", 0))
  621. {
  622. CharString clip = OS::get_clipboard().utf8();
  623. XChangeProperty (x11_display,
  624. req->requestor,
  625. req->property,
  626. req->target,
  627. 8,
  628. PropModeReplace,
  629. (unsigned char*)clip.get_data(),
  630. clip.length());
  631. respond.xselection.property=req->property;
  632. } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
  633. Atom data[2];
  634. data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
  635. data[1] = XA_STRING;
  636. XChangeProperty (x11_display, req->requestor, req->property, req->target,
  637. 8, PropModeReplace, (unsigned char *) &data,
  638. sizeof (data));
  639. respond.xselection.property=req->property;
  640. } else {
  641. printf ("No String %x\n",
  642. (int)req->target);
  643. respond.xselection.property= None;
  644. }
  645. respond.xselection.type= SelectionNotify;
  646. respond.xselection.display= req->display;
  647. respond.xselection.requestor= req->requestor;
  648. respond.xselection.selection=req->selection;
  649. respond.xselection.target= req->target;
  650. respond.xselection.time = req->time;
  651. XSendEvent (x11_display, req->requestor,0,0,&respond);
  652. XFlush (x11_display);
  653. } break;
  654. case ClientMessage:
  655. if ((unsigned int)event.xclient.data.l[0]==(unsigned int)wm_delete)
  656. main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
  657. break;
  658. default:
  659. break;
  660. }
  661. }
  662. XFlush(x11_display);
  663. if (do_mouse_warp) {
  664. XWarpPointer(x11_display, None, x11_window,
  665. 0,0,0,0, (int)current_videomode.width/2, (int)current_videomode.height/2);
  666. }
  667. }
  668. MainLoop *OS_X11::get_main_loop() const {
  669. return main_loop;
  670. }
  671. void OS_X11::delete_main_loop() {
  672. if (main_loop)
  673. memdelete(main_loop);
  674. main_loop=NULL;
  675. }
  676. void OS_X11::set_main_loop( MainLoop * p_main_loop ) {
  677. main_loop=p_main_loop;
  678. input->set_main_loop(p_main_loop);
  679. }
  680. bool OS_X11::can_draw() const {
  681. return !minimized;
  682. };
  683. void OS_X11::set_clipboard(const String& p_text) {
  684. OS::set_clipboard(p_text);
  685. XSetSelectionOwner(x11_display, XA_PRIMARY, x11_window, CurrentTime);
  686. XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
  687. };
  688. static String _get_clipboard(Atom p_source, Window x11_window, ::Display* x11_display, String p_internal_clipboard) {
  689. String ret;
  690. Atom type;
  691. Atom selection = XA_PRIMARY;
  692. int format, result;
  693. unsigned long len, bytes_left, dummy;
  694. unsigned char *data;
  695. Window Sown = XGetSelectionOwner (x11_display, p_source);
  696. if (Sown == x11_window) {
  697. printf("returning internal clipboard\n");
  698. return p_internal_clipboard;
  699. };
  700. if (Sown != None) {
  701. XConvertSelection (x11_display, p_source, XA_STRING, selection,
  702. x11_window, CurrentTime);
  703. XFlush (x11_display);
  704. while (true) {
  705. XEvent event;
  706. XNextEvent(x11_display, &event);
  707. if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
  708. break;
  709. };
  710. };
  711. //
  712. // Do not get any data, see how much data is there
  713. //
  714. XGetWindowProperty (x11_display, x11_window,
  715. selection, // Tricky..
  716. 0, 0, // offset - len
  717. 0, // Delete 0==FALSE
  718. AnyPropertyType, //flag
  719. &type, // return type
  720. &format, // return format
  721. &len, &bytes_left, //that
  722. &data);
  723. // DATA is There
  724. if (bytes_left > 0)
  725. {
  726. result = XGetWindowProperty (x11_display, x11_window,
  727. selection, 0,bytes_left,0,
  728. AnyPropertyType, &type,&format,
  729. &len, &dummy, &data);
  730. if (result == Success) {
  731. ret.parse_utf8((const char*)data);
  732. } else printf ("FAIL\n");
  733. XFree (data);
  734. }
  735. }
  736. return ret;
  737. };
  738. String OS_X11::get_clipboard() const {
  739. String ret;
  740. ret = _get_clipboard(XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, x11_display, OS::get_clipboard());
  741. if (ret == "") {
  742. ret = _get_clipboard(XA_PRIMARY, x11_window, x11_display, OS::get_clipboard());
  743. };
  744. return ret;
  745. };
  746. String OS_X11::get_name() {
  747. return "X11";
  748. }
  749. void OS_X11::close_joystick(int p_id) {
  750. if (p_id == -1) {
  751. for (int i=0; i<JOYSTICKS_MAX; i++) {
  752. close_joystick(i);
  753. };
  754. return;
  755. };
  756. if (joysticks[p_id].fd != -1) {
  757. close(joysticks[p_id].fd);
  758. joysticks[p_id].fd = -1;
  759. };
  760. };
  761. void OS_X11::probe_joystick(int p_id) {
  762. if (p_id == -1) {
  763. for (int i=0; i<JOYSTICKS_MAX; i++) {
  764. probe_joystick(i);
  765. };
  766. return;
  767. };
  768. close_joystick(p_id);
  769. const char *joy_names[] = {
  770. "/dev/input/js%d",
  771. "/dev/js%d",
  772. NULL
  773. };
  774. int i=0;
  775. while(joy_names[i]) {
  776. char fname[64];
  777. sprintf(fname, joy_names[i], p_id);
  778. int fd = open(fname, O_RDONLY);
  779. if (fd != -1) {
  780. fcntl( fd, F_SETFL, O_NONBLOCK );
  781. joysticks[p_id] = Joystick(); // this will reset the axis array
  782. joysticks[p_id].fd = fd;
  783. break; // don't try the next name
  784. };
  785. ++i;
  786. };
  787. };
  788. void OS_X11::move_window_to_foreground() {
  789. XRaiseWindow(x11_display,x11_window);
  790. }
  791. void OS_X11::process_joysticks() {
  792. int bytes;
  793. js_event events[32];
  794. InputEvent ievent;
  795. for (int i=0; i<JOYSTICKS_MAX; i++) {
  796. if (joysticks[i].fd == -1)
  797. continue;
  798. ievent.device = i;
  799. while ( (bytes = read(joysticks[i].fd, &events, sizeof(events))) > 0) {
  800. int ev_count = bytes / sizeof(js_event);
  801. for (int j=0; j<ev_count; j++) {
  802. js_event& event = events[j];
  803. //printf("got event on joystick %i, %i, %i, %i, %i\n", i, joysticks[i].fd, event.type, event.number, event.value);
  804. if (event.type & JS_EVENT_INIT)
  805. continue;
  806. switch (event.type & ~JS_EVENT_INIT) {
  807. case JS_EVENT_AXIS:
  808. if (joysticks[i].last_axis[event.number] != event.value) {
  809. if (event.number==5 || event.number==6) {
  810. int axis=event.number-5;
  811. int val = event.value;
  812. if (val<0)
  813. val=-1;
  814. if (val>0)
  815. val=+1;
  816. InputEvent ev;
  817. ev.type = InputEvent::JOYSTICK_BUTTON;
  818. ev.ID = ++event_id;
  819. if (val!=dpad_last[axis]) {
  820. int prev_val = dpad_last[axis];
  821. if (prev_val!=0) {
  822. ev.joy_button.pressed=false;
  823. ev.joy_button.pressure=0.0;
  824. if (event.number==5)
  825. ev.joy_button.button_index=JOY_DPAD_LEFT+(prev_val+1)/2;
  826. if (event.number==6)
  827. ev.joy_button.button_index=JOY_DPAD_UP+(prev_val+1)/2;
  828. input->parse_input_event( ev );
  829. }
  830. }
  831. if (val!=0) {
  832. ev.joy_button.pressed=true;
  833. ev.joy_button.pressure=1.0;
  834. if (event.number==5)
  835. ev.joy_button.button_index=JOY_DPAD_LEFT+(val+1)/2;
  836. if (event.number==6)
  837. ev.joy_button.button_index=JOY_DPAD_UP+(val+1)/2;
  838. input->parse_input_event( ev );
  839. }
  840. dpad_last[axis]=val;
  841. }
  842. //print_line("ev: "+itos(event.number)+" val: "+ rtos((float)event.value / (float)MAX_JOY_AXIS));
  843. if (event.number >= JOY_AXIS_MAX)
  844. break;
  845. //ERR_FAIL_COND(event.number >= JOY_AXIS_MAX);
  846. ievent.type = InputEvent::JOYSTICK_MOTION;
  847. ievent.ID = ++event_id;
  848. ievent.joy_motion.axis = _pc_joystick_get_native_axis(event.number);
  849. ievent.joy_motion.axis_value = (float)event.value / (float)MAX_JOY_AXIS;
  850. joysticks[i].last_axis[event.number] = event.value;
  851. input->parse_input_event( ievent );
  852. };
  853. break;
  854. case JS_EVENT_BUTTON:
  855. ievent.type = InputEvent::JOYSTICK_BUTTON;
  856. ievent.ID = ++event_id;
  857. ievent.joy_button.button_index = _pc_joystick_get_native_button(event.number);
  858. ievent.joy_button.pressed = event.value;
  859. input->parse_input_event( ievent );
  860. break;
  861. };
  862. };
  863. };
  864. };
  865. };
  866. void OS_X11::set_cursor_shape(CursorShape p_shape) {
  867. ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
  868. if (p_shape==current_cursor)
  869. return;
  870. if (mouse_mode==MOUSE_MODE_VISIBLE) {
  871. if (cursors[p_shape]!=None)
  872. XDefineCursor(x11_display,x11_window,cursors[p_shape]);
  873. else if (cursors[CURSOR_ARROW]!=None)
  874. XDefineCursor(x11_display,x11_window,cursors[CURSOR_ARROW]);
  875. }
  876. current_cursor=p_shape;
  877. }
  878. void OS_X11::release_rendering_thread() {
  879. context_gl->release_current();
  880. }
  881. void OS_X11::make_rendering_thread() {
  882. context_gl->make_current();
  883. }
  884. void OS_X11::swap_buffers() {
  885. context_gl->swap_buffers();
  886. }
  887. void OS_X11::set_icon(const Image& p_icon) {
  888. if (!p_icon.empty()) {
  889. Image img=p_icon;
  890. img.convert(Image::FORMAT_RGBA);
  891. int w = img.get_width();
  892. int h = img.get_height();
  893. // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
  894. Vector<long> pd;
  895. pd.resize(2+w*h);
  896. print_line("***** SET ICON ***** "+itos(w)+" "+itos(h));
  897. pd[0]=w;
  898. pd[1]=h;
  899. DVector<uint8_t>::Read r = img.get_data().read();
  900. long * wr = &pd[2];
  901. uint8_t const * pr = r.ptr();
  902. for(int i=0;i<w*h;i++) {
  903. long v=0;
  904. // A R G B
  905. v|=pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
  906. *wr++=v;
  907. pr += 4;
  908. }
  909. XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) pd.ptr(), pd.size());
  910. } else {
  911. XDeleteProperty(x11_display, x11_window, net_wm_icon);
  912. }
  913. XFlush(x11_display);
  914. }
  915. void OS_X11::run() {
  916. force_quit = false;
  917. if (!main_loop)
  918. return;
  919. main_loop->init();
  920. // uint64_t last_ticks=get_ticks_usec();
  921. // int frames=0;
  922. // uint64_t frame=0;
  923. while (!force_quit) {
  924. process_xevents(); // get rid of pending events
  925. process_joysticks();
  926. if (Main::iteration()==true)
  927. break;
  928. };
  929. main_loop->finish();
  930. }
  931. OS_X11::OS_X11() {
  932. #ifdef RTAUDIO_ENABLED
  933. AudioDriverManagerSW::add_driver(&driver_rtaudio);
  934. #endif
  935. #ifdef ALSA_ENABLED
  936. AudioDriverManagerSW::add_driver(&driver_alsa);
  937. #endif
  938. minimized = false;
  939. xim_style=NULL;
  940. mouse_mode=MOUSE_MODE_VISIBLE;
  941. };