main_linux.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /*
  2. * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE
  4. */
  5. #include "config.h"
  6. #if CROWN_PLATFORM_LINUX
  7. #include "bundle_compiler.h"
  8. #include "command_line.h"
  9. #include "console_server.h"
  10. #include "device.h"
  11. #include "display.h"
  12. #include "os_event_queue.h"
  13. #include "thread.h"
  14. #include "window.h"
  15. #include <stdlib.h>
  16. #include <X11/extensions/Xrandr.h>
  17. #include <X11/Xatom.h>
  18. #include <X11/XKBlib.h>
  19. #include <X11/Xlib.h>
  20. #include <X11/Xutil.h>
  21. #include <bgfx/bgfxplatform.h>
  22. namespace crown
  23. {
  24. static KeyboardButton::Enum x11_translate_key(KeySym x11_key)
  25. {
  26. switch (x11_key)
  27. {
  28. case XK_BackSpace: return KeyboardButton::BACKSPACE;
  29. case XK_Tab: return KeyboardButton::TAB;
  30. case XK_space: return KeyboardButton::SPACE;
  31. case XK_Escape: return KeyboardButton::ESCAPE;
  32. case XK_Return: return KeyboardButton::ENTER;
  33. case XK_F1: return KeyboardButton::F1;
  34. case XK_F2: return KeyboardButton::F2;
  35. case XK_F3: return KeyboardButton::F3;
  36. case XK_F4: return KeyboardButton::F4;
  37. case XK_F5: return KeyboardButton::F5;
  38. case XK_F6: return KeyboardButton::F6;
  39. case XK_F7: return KeyboardButton::F7;
  40. case XK_F8: return KeyboardButton::F8;
  41. case XK_F9: return KeyboardButton::F9;
  42. case XK_F10: return KeyboardButton::F10;
  43. case XK_F11: return KeyboardButton::F11;
  44. case XK_F12: return KeyboardButton::F12;
  45. case XK_Home: return KeyboardButton::HOME;
  46. case XK_Left: return KeyboardButton::LEFT;
  47. case XK_Up: return KeyboardButton::UP;
  48. case XK_Right: return KeyboardButton::RIGHT;
  49. case XK_Down: return KeyboardButton::DOWN;
  50. case XK_Page_Up: return KeyboardButton::PAGE_UP;
  51. case XK_Page_Down: return KeyboardButton::PAGE_DOWN;
  52. case XK_Insert: return KeyboardButton::INSERT;
  53. case XK_Delete: return KeyboardButton::DELETE;
  54. case XK_End: return KeyboardButton::END;
  55. case XK_Shift_L: return KeyboardButton::LEFT_SHIFT;
  56. case XK_Shift_R: return KeyboardButton::RIGHT_SHIFT;
  57. case XK_Control_L: return KeyboardButton::LEFT_CTRL;
  58. case XK_Control_R: return KeyboardButton::RIGHT_CTRL;
  59. case XK_Caps_Lock: return KeyboardButton::CAPS_LOCK;
  60. case XK_Alt_L: return KeyboardButton::LEFT_ALT;
  61. case XK_Alt_R: return KeyboardButton::RIGHT_ALT;
  62. case XK_Super_L: return KeyboardButton::LEFT_SUPER;
  63. case XK_Super_R: return KeyboardButton::RIGHT_SUPER;
  64. case XK_Num_Lock: return KeyboardButton::NUM_LOCK;
  65. case XK_KP_Enter: return KeyboardButton::NUMPAD_ENTER;
  66. case XK_KP_Delete: return KeyboardButton::NUMPAD_DELETE;
  67. case XK_KP_Multiply: return KeyboardButton::NUMPAD_MULTIPLY;
  68. case XK_KP_Add: return KeyboardButton::NUMPAD_ADD;
  69. case XK_KP_Subtract: return KeyboardButton::NUMPAD_SUBTRACT;
  70. case XK_KP_Divide: return KeyboardButton::NUMPAD_DIVIDE;
  71. case XK_KP_Insert:
  72. case XK_KP_0: return KeyboardButton::NUMPAD_0;
  73. case XK_KP_End:
  74. case XK_KP_1: return KeyboardButton::NUMPAD_1;
  75. case XK_KP_Down:
  76. case XK_KP_2: return KeyboardButton::NUMPAD_2;
  77. case XK_KP_Page_Down: // or XK_KP_Next
  78. case XK_KP_3: return KeyboardButton::NUMPAD_3;
  79. case XK_KP_Left:
  80. case XK_KP_4: return KeyboardButton::NUMPAD_4;
  81. case XK_KP_Begin:
  82. case XK_KP_5: return KeyboardButton::NUMPAD_5;
  83. case XK_KP_Right:
  84. case XK_KP_6: return KeyboardButton::NUMPAD_6;
  85. case XK_KP_Home:
  86. case XK_KP_7: return KeyboardButton::NUMPAD_7;
  87. case XK_KP_Up:
  88. case XK_KP_8: return KeyboardButton::NUMPAD_8;
  89. case XK_KP_Page_Up: // or XK_KP_Prior
  90. case XK_KP_9: return KeyboardButton::NUMPAD_9;
  91. case '0': return KeyboardButton::NUMBER_0;
  92. case '1': return KeyboardButton::NUMBER_1;
  93. case '2': return KeyboardButton::NUMBER_2;
  94. case '3': return KeyboardButton::NUMBER_3;
  95. case '4': return KeyboardButton::NUMBER_4;
  96. case '5': return KeyboardButton::NUMBER_5;
  97. case '6': return KeyboardButton::NUMBER_6;
  98. case '7': return KeyboardButton::NUMBER_7;
  99. case '8': return KeyboardButton::NUMBER_8;
  100. case '9': return KeyboardButton::NUMBER_9;
  101. case 'a': return KeyboardButton::A;
  102. case 'b': return KeyboardButton::B;
  103. case 'c': return KeyboardButton::C;
  104. case 'd': return KeyboardButton::D;
  105. case 'e': return KeyboardButton::E;
  106. case 'f': return KeyboardButton::F;
  107. case 'g': return KeyboardButton::G;
  108. case 'h': return KeyboardButton::H;
  109. case 'i': return KeyboardButton::I;
  110. case 'j': return KeyboardButton::J;
  111. case 'k': return KeyboardButton::K;
  112. case 'l': return KeyboardButton::L;
  113. case 'm': return KeyboardButton::M;
  114. case 'n': return KeyboardButton::N;
  115. case 'o': return KeyboardButton::O;
  116. case 'p': return KeyboardButton::P;
  117. case 'q': return KeyboardButton::Q;
  118. case 'r': return KeyboardButton::R;
  119. case 's': return KeyboardButton::S;
  120. case 't': return KeyboardButton::T;
  121. case 'u': return KeyboardButton::U;
  122. case 'v': return KeyboardButton::V;
  123. case 'w': return KeyboardButton::W;
  124. case 'x': return KeyboardButton::X;
  125. case 'y': return KeyboardButton::Y;
  126. case 'z': return KeyboardButton::Z;
  127. default: return KeyboardButton::COUNT;
  128. }
  129. }
  130. #define JS_EVENT_BUTTON 0x01 /* button pressed/released */
  131. #define JS_EVENT_AXIS 0x02 /* joystick moved */
  132. #define JS_EVENT_INIT 0x80 /* initial state of device */
  133. #define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
  134. #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
  135. #define XINPUT_GAMEPAD_THRESHOLD 30
  136. static u8 s_button[] =
  137. {
  138. JoypadButton::A,
  139. JoypadButton::B,
  140. JoypadButton::X,
  141. JoypadButton::Y,
  142. JoypadButton::LEFT_SHOULDER,
  143. JoypadButton::RIGHT_SHOULDER,
  144. JoypadButton::BACK,
  145. JoypadButton::START,
  146. JoypadButton::GUIDE,
  147. JoypadButton::LEFT_THUMB,
  148. JoypadButton::RIGHT_THUMB,
  149. JoypadButton::UP, // FIXME (reported as axis...)
  150. JoypadButton::DOWN,
  151. JoypadButton::LEFT,
  152. JoypadButton::RIGHT
  153. };
  154. static u16 s_deadzone[] =
  155. {
  156. XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
  157. XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
  158. XINPUT_GAMEPAD_THRESHOLD,
  159. XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
  160. XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
  161. XINPUT_GAMEPAD_THRESHOLD
  162. };
  163. struct JoypadEvent
  164. {
  165. u32 time; /* event timestamp in milliseconds */
  166. s16 value; /* value */
  167. u8 type; /* event type */
  168. u8 number; /* axis/button number */
  169. };
  170. struct Joypad
  171. {
  172. void init()
  173. {
  174. char jspath[] = "/dev/input/jsX";
  175. char* num = strchr(jspath, 'X');
  176. for (u8 i = 0; i < CROWN_MAX_JOYPADS; ++i)
  177. {
  178. *num = '0' + i;
  179. _fd[i] = open(jspath, O_RDONLY | O_NONBLOCK);
  180. }
  181. memset(_connected, 0, sizeof(_connected));
  182. memset(_axis, 0, sizeof(_axis));
  183. }
  184. void shutdown()
  185. {
  186. for (u8 i = 0; i < CROWN_MAX_JOYPADS; ++i)
  187. {
  188. if (_fd[i] != -1)
  189. close(_fd[i]);
  190. }
  191. }
  192. void update(OsEventQueue& queue)
  193. {
  194. JoypadEvent ev;
  195. memset(&ev, 0, sizeof(ev));
  196. for (u8 i = 0; i < CROWN_MAX_JOYPADS; ++i)
  197. {
  198. const int fd = _fd[i];
  199. const bool connected = fd != -1;
  200. if (connected != _connected[i])
  201. queue.push_joypad_event(i, connected);
  202. _connected[i] = connected;
  203. if (!connected)
  204. continue;
  205. while(read(fd, &ev, sizeof(ev)) != -1)
  206. {
  207. const u8 num = ev.number;
  208. const s16 val = ev.value;
  209. switch (ev.type &= ~JS_EVENT_INIT)
  210. {
  211. case JS_EVENT_AXIS:
  212. {
  213. AxisData& axis = _axis[i];
  214. // Indices into axis.left/right respectively
  215. const u8 axis_idx[] = { 0, 1, 2, 0, 1, 2 };
  216. const s16 deadzone = s_deadzone[num];
  217. s16 value = val > deadzone || val < -deadzone ? val : 0;
  218. // Remap triggers to [0, INT16_MAX]
  219. if (num == 2 || num == 5)
  220. value = (value + INT16_MAX) >> 1;
  221. f32* values = num > 2 ? axis.right : axis.left;
  222. values[axis_idx[num]] = value != 0
  223. ? f32(value + (value < 0 ? deadzone : -deadzone)) / f32(INT16_MAX - deadzone)
  224. : 0.0f
  225. ;
  226. queue.push_joypad_event(i
  227. , num > 2 ? 1 : 0
  228. , values[0]
  229. , -values[1]
  230. , values[2]
  231. );
  232. break;
  233. }
  234. case JS_EVENT_BUTTON:
  235. {
  236. if (ev.number < CE_COUNTOF(s_button))
  237. {
  238. queue.push_joypad_event(i
  239. , s_button[ev.number]
  240. , val == 1
  241. );
  242. }
  243. break;
  244. }
  245. }
  246. }
  247. }
  248. }
  249. int _fd[CROWN_MAX_JOYPADS];
  250. bool _connected[CROWN_MAX_JOYPADS];
  251. struct AxisData
  252. {
  253. f32 left[3];
  254. f32 right[3];
  255. };
  256. AxisData _axis[CROWN_MAX_JOYPADS];
  257. };
  258. static bool s_exit = false;
  259. struct MainThreadArgs
  260. {
  261. DeviceOptions* opts;
  262. };
  263. s32 func(void* data)
  264. {
  265. MainThreadArgs* args = (MainThreadArgs*)data;
  266. crown::init(*args->opts);
  267. crown::update();
  268. crown::shutdown();
  269. s_exit = true;
  270. return EXIT_SUCCESS;
  271. }
  272. struct LinuxDevice
  273. {
  274. LinuxDevice()
  275. : _x11_display(NULL)
  276. , _screen_config(NULL)
  277. , _x11_detectable_autorepeat(false)
  278. {
  279. }
  280. int run(DeviceOptions* opts)
  281. {
  282. // http://tronche.com/gui/x/xlib/display/XInitThreads.html
  283. Status xs = XInitThreads();
  284. CE_ASSERT(xs != 0, "XInitThreads: error");
  285. CE_UNUSED(xs);
  286. _x11_display = XOpenDisplay(NULL);
  287. CE_ASSERT(_x11_display != NULL, "XOpenDisplay: error");
  288. ::Window root_window = RootWindow(_x11_display, DefaultScreen(_x11_display));
  289. // Do we have detectable autorepeat?
  290. Bool detectable;
  291. _x11_detectable_autorepeat = (bool)XkbSetDetectableAutoRepeat(_x11_display, true, &detectable);
  292. _wm_delete_message = XInternAtom(_x11_display, "WM_DELETE_WINDOW", False);
  293. // Save screen configuration
  294. _screen_config = XRRGetScreenInfo(_x11_display, root_window);
  295. Rotation rr_old_rot;
  296. const SizeID rr_old_sizeid = XRRConfigCurrentConfiguration(_screen_config, &rr_old_rot);
  297. // Start main thread
  298. MainThreadArgs mta;
  299. mta.opts = opts;
  300. Thread main_thread;
  301. main_thread.start(func, &mta);
  302. _joypad.init();
  303. while (!s_exit)
  304. {
  305. pump_events();
  306. }
  307. _joypad.shutdown();
  308. main_thread.stop();
  309. // Restore previous screen configuration
  310. Rotation rr_rot;
  311. const SizeID rr_sizeid = XRRConfigCurrentConfiguration(_screen_config, &rr_rot);
  312. if (rr_rot != rr_old_rot || rr_sizeid != rr_old_sizeid)
  313. {
  314. XRRSetScreenConfig(_x11_display
  315. , _screen_config
  316. , root_window
  317. , rr_old_sizeid
  318. , rr_old_rot
  319. , CurrentTime
  320. );
  321. }
  322. XRRFreeScreenConfigInfo(_screen_config);
  323. XCloseDisplay(_x11_display);
  324. return EXIT_SUCCESS;
  325. }
  326. void pump_events()
  327. {
  328. _joypad.update(_queue);
  329. while (XPending(_x11_display))
  330. {
  331. XEvent event;
  332. XNextEvent(_x11_display, &event);
  333. switch (event.type)
  334. {
  335. case EnterNotify:
  336. {
  337. _queue.push_mouse_event(event.xcrossing.x, event.xcrossing.y);
  338. break;
  339. }
  340. case ClientMessage:
  341. {
  342. if ((Atom)event.xclient.data.l[0] == _wm_delete_message)
  343. {
  344. _queue.push_exit_event(0);
  345. }
  346. break;
  347. }
  348. case ConfigureNotify:
  349. {
  350. _queue.push_metrics_event(event.xconfigure.x
  351. , event.xconfigure.y
  352. , event.xconfigure.width
  353. , event.xconfigure.height
  354. );
  355. break;
  356. }
  357. case ButtonPress:
  358. case ButtonRelease:
  359. {
  360. if (event.xbutton.button == Button4 || event.xbutton.button == Button5)
  361. {
  362. _queue.push_mouse_event(event.xbutton.x
  363. , event.xbutton.y
  364. , event.xbutton.button == Button4 ? 1.0f : -1.0f
  365. );
  366. break;
  367. }
  368. MouseButton::Enum mb;
  369. switch (event.xbutton.button)
  370. {
  371. case Button1: mb = MouseButton::LEFT; break;
  372. case Button2: mb = MouseButton::MIDDLE; break;
  373. case Button3: mb = MouseButton::RIGHT; break;
  374. default: mb = MouseButton::COUNT; break;
  375. }
  376. if (mb != MouseButton::COUNT)
  377. {
  378. _queue.push_mouse_event(event.xbutton.x
  379. , event.xbutton.y
  380. , mb
  381. , event.type == ButtonPress
  382. );
  383. }
  384. break;
  385. }
  386. case MotionNotify:
  387. {
  388. _queue.push_mouse_event(event.xmotion.x, event.xmotion.y);
  389. break;
  390. }
  391. case KeyPress:
  392. case KeyRelease:
  393. {
  394. KeySym keysym = XLookupKeysym(&event.xkey, 0);
  395. KeyboardButton::Enum kb = x11_translate_key(keysym);
  396. if (kb != KeyboardButton::COUNT)
  397. _queue.push_keyboard_event(kb, event.type == KeyPress);
  398. break;
  399. }
  400. case KeymapNotify:
  401. {
  402. XRefreshKeyboardMapping(&event.xmapping);
  403. break;
  404. }
  405. default:
  406. {
  407. break;
  408. }
  409. }
  410. }
  411. }
  412. public:
  413. ::Display* _x11_display;
  414. Atom _wm_delete_message;
  415. XRRScreenConfiguration* _screen_config;
  416. bool _x11_detectable_autorepeat;
  417. OsEventQueue _queue;
  418. Joypad _joypad;
  419. };
  420. static LinuxDevice s_ldvc;
  421. class WindowX11 : public Window
  422. {
  423. ::Display* _x11_display;
  424. ::Window _x11_window;
  425. Cursor _x11_hidden_cursor;
  426. Atom _wm_delete_message;
  427. public:
  428. WindowX11()
  429. : _x11_display(NULL)
  430. , _x11_window(None)
  431. , _x11_hidden_cursor(None)
  432. {
  433. _x11_display = s_ldvc._x11_display;
  434. }
  435. void open(u16 x, u16 y, u16 width, u16 height, u32 parent)
  436. {
  437. int screen = DefaultScreen(_x11_display);
  438. int depth = DefaultDepth(_x11_display, screen);
  439. Visual* visual = DefaultVisual(_x11_display, screen);
  440. ::Window root_window = RootWindow(_x11_display, screen);
  441. ::Window parent_window = (parent == 0) ? root_window : (::Window)parent;
  442. // Create main window
  443. XSetWindowAttributes win_attribs;
  444. win_attribs.background_pixmap = 0;
  445. win_attribs.border_pixel = 0;
  446. win_attribs.event_mask = FocusChangeMask
  447. | StructureNotifyMask
  448. ;
  449. if (!parent)
  450. {
  451. win_attribs.event_mask |= KeyPressMask
  452. | KeyReleaseMask
  453. | ButtonPressMask
  454. | ButtonReleaseMask
  455. | PointerMotionMask
  456. | EnterWindowMask
  457. ;
  458. }
  459. _x11_window = XCreateWindow(_x11_display
  460. , parent_window
  461. , x
  462. , y
  463. , width
  464. , height
  465. , 0
  466. , depth
  467. , InputOutput
  468. , visual
  469. , CWBorderPixel | CWEventMask
  470. , &win_attribs
  471. );
  472. CE_ASSERT(_x11_window != None, "XCreateWindow: error");
  473. // Build hidden cursor
  474. Pixmap bm_no;
  475. XColor black, dummy;
  476. Colormap colormap;
  477. static char no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  478. colormap = XDefaultColormap(_x11_display, screen);
  479. XAllocNamedColor(_x11_display, colormap, "black", &black, &dummy);
  480. bm_no = XCreateBitmapFromData(_x11_display, _x11_window, no_data, 8, 8);
  481. _x11_hidden_cursor = XCreatePixmapCursor(_x11_display, bm_no, bm_no, &black, &black, 0, 0);
  482. _wm_delete_message = XInternAtom(_x11_display, "WM_DELETE_WINDOW", False);
  483. XSetWMProtocols(_x11_display, _x11_window, &_wm_delete_message, 1);
  484. XMapRaised(_x11_display, _x11_window);
  485. }
  486. void close()
  487. {
  488. XDestroyWindow(_x11_display, _x11_window);
  489. }
  490. void bgfx_setup()
  491. {
  492. bgfx::x11SetDisplayWindow(_x11_display, _x11_window);
  493. }
  494. void show()
  495. {
  496. XMapRaised(_x11_display, _x11_window);
  497. }
  498. void hide()
  499. {
  500. XUnmapWindow(_x11_display, _x11_window);
  501. }
  502. void resize(u16 width, u16 height)
  503. {
  504. XResizeWindow(_x11_display, _x11_window, width, height);
  505. }
  506. void move(u16 x, u16 y)
  507. {
  508. XMoveWindow(_x11_display, _x11_window, x, y);
  509. }
  510. void minimize()
  511. {
  512. }
  513. void restore()
  514. {
  515. }
  516. const char* title()
  517. {
  518. static char buf[512];
  519. memset(buf, 0, sizeof(buf));
  520. char* name;
  521. XFetchName(_x11_display, _x11_window, &name);
  522. strncpy(buf, name, sizeof(buf));
  523. XFree(name);
  524. return buf;
  525. }
  526. void set_title (const char* title)
  527. {
  528. XStoreName(_x11_display, _x11_window, title);
  529. }
  530. void* handle()
  531. {
  532. return (void*)(uintptr_t)_x11_window;
  533. }
  534. void show_cursor(bool show)
  535. {
  536. XDefineCursor(_x11_display
  537. , _x11_window
  538. , show ? None : _x11_hidden_cursor
  539. );
  540. }
  541. };
  542. Window* Window::create(Allocator& a)
  543. {
  544. return CE_NEW(a, WindowX11)();
  545. }
  546. void Window::destroy(Allocator& a, Window& w)
  547. {
  548. CE_DELETE(a, &w);
  549. }
  550. class DisplayXRandr : public Display
  551. {
  552. ::Display* _x11_display;
  553. XRRScreenConfiguration* _screen_config;
  554. public:
  555. DisplayXRandr()
  556. : _x11_display(NULL)
  557. , _screen_config(NULL)
  558. {
  559. _x11_display = s_ldvc._x11_display;
  560. _screen_config = s_ldvc._screen_config;
  561. }
  562. void modes(Array<DisplayMode>& modes)
  563. {
  564. int num = 0;
  565. XRRScreenSize* sizes = XRRConfigSizes(_screen_config, &num);
  566. if (!sizes)
  567. return;
  568. for (int i = 0; i < num; ++i)
  569. {
  570. DisplayMode dm;
  571. dm.id = (u32)i;
  572. dm.width = sizes[i].width;
  573. dm.height = sizes[i].height;
  574. array::push_back(modes, dm);
  575. }
  576. }
  577. void set_mode(u32 id)
  578. {
  579. int num = 0;
  580. XRRScreenSize* sizes = XRRConfigSizes(_screen_config, &num);
  581. if (!sizes || (int)id >= num)
  582. return;
  583. XRRSetScreenConfig(_x11_display
  584. , _screen_config
  585. , RootWindow(_x11_display, DefaultScreen(_x11_display))
  586. , (int)id
  587. , RR_Rotate_0
  588. , CurrentTime
  589. );
  590. }
  591. // void set_fullscreen(bool full)
  592. // {
  593. // XEvent e;
  594. // e.xclient.type = ClientMessage;
  595. // e.xclient.window = m_x11_window;
  596. // e.xclient.message_type = XInternAtom(_x11_display, "_NET_WM_STATE", False );
  597. // e.xclient.format = 32;
  598. // e.xclient.data.l[0] = full ? 1 : 0;
  599. // e.xclient.data.l[1] = XInternAtom(_x11_display, "_NET_WM_STATE_FULLSCREEN", False);
  600. // XSendEvent(_x11_display, DefaultRootWindow(_x11_display), False, SubstructureNotifyMask, &e);
  601. // }
  602. };
  603. Display* Display::create(Allocator& a)
  604. {
  605. return CE_NEW(a, DisplayXRandr)();
  606. }
  607. void Display::destroy(Allocator& a, Display& d)
  608. {
  609. CE_DELETE(a, &d);
  610. }
  611. bool next_event(OsEvent& ev)
  612. {
  613. return s_ldvc._queue.pop_event(ev);
  614. }
  615. } // namespace crown
  616. int main(int argc, char** argv)
  617. {
  618. using namespace crown;
  619. memory_globals::init();
  620. DeviceOptions opts(argc, argv);
  621. int exitcode = opts.parse();
  622. if (exitcode == EXIT_FAILURE)
  623. {
  624. return exitcode;
  625. }
  626. console_server_globals::init(opts.console_port(), opts.wait_console());
  627. bool do_continue = true;
  628. if (opts.do_compile())
  629. {
  630. bundle_compiler_globals::init(opts.source_dir(), opts.bundle_dir());
  631. do_continue = bundle_compiler::main(opts.do_compile(), opts.do_continue(), opts.platform());
  632. }
  633. if (do_continue)
  634. exitcode = crown::s_ldvc.run(&opts);
  635. if (opts.do_compile())
  636. bundle_compiler_globals::shutdown();
  637. console_server_globals::shutdown();
  638. memory_globals::shutdown();
  639. return exitcode;
  640. }
  641. #endif // CROWN_PLATFORM_LINUX