main.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. Copyright (c) 2013 Daniele Bartolini, Michele Rossi
  3. Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
  4. Permission is hereby granted, free of charge, to any person
  5. obtaining a copy of this software and associated documentation
  6. files (the "Software"), to deal in the Software without
  7. restriction, including without limitation the rights to use,
  8. copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the
  10. Software is furnished to do so, subject to the following
  11. conditions:
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  16. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  19. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <X11/Xutil.h>
  24. #include <X11/Xatom.h>
  25. #include <X11/Xlib.h>
  26. #include <X11/XKBlib.h>
  27. #include <X11/extensions/Xrandr.h>
  28. #include "config.h"
  29. #include "crown.h"
  30. #include "device.h"
  31. #include "os_types.h"
  32. #include "os_event_queue.h"
  33. #include "bundle_compiler.h"
  34. #include "memory.h"
  35. namespace crown
  36. {
  37. extern void set_x11_display_and_window(Display* dpy, Window win);
  38. //-----------------------------------------------------------------------------
  39. void init()
  40. {
  41. crown::memory::init();
  42. }
  43. //-----------------------------------------------------------------------------
  44. void shutdown()
  45. {
  46. crown::memory::shutdown();
  47. }
  48. //-----------------------------------------------------------------------------
  49. static KeyboardButton::Enum x11_translate_key(KeySym x11_key)
  50. {
  51. if ((x11_key > 0x40 && x11_key < 0x5B) || (x11_key > 0x60 && x11_key < 0x7B) || (x11_key > 0x2F && x11_key < 0x3A))
  52. {
  53. return (KeyboardButton::Enum) x11_key;
  54. }
  55. switch (x11_key)
  56. {
  57. case XK_BackSpace: return KeyboardButton::BACKSPACE;
  58. case XK_Tab: return KeyboardButton::TAB;
  59. case XK_space: return KeyboardButton::SPACE;
  60. case XK_Escape: return KeyboardButton::ESCAPE;
  61. case XK_Return: return KeyboardButton::ENTER;
  62. case XK_F1: return KeyboardButton::F1;
  63. case XK_F2: return KeyboardButton::F2;
  64. case XK_F3: return KeyboardButton::F3;
  65. case XK_F4: return KeyboardButton::F4;
  66. case XK_F5: return KeyboardButton::F5;
  67. case XK_F6: return KeyboardButton::F6;
  68. case XK_F7: return KeyboardButton::F7;
  69. case XK_F8: return KeyboardButton::F8;
  70. case XK_F9: return KeyboardButton::F9;
  71. case XK_F10: return KeyboardButton::F10;
  72. case XK_F11: return KeyboardButton::F11;
  73. case XK_F12: return KeyboardButton::F12;
  74. case XK_Home: return KeyboardButton::HOME;
  75. case XK_Left: return KeyboardButton::LEFT;
  76. case XK_Up: return KeyboardButton::UP;
  77. case XK_Right: return KeyboardButton::RIGHT;
  78. case XK_Down: return KeyboardButton::DOWN;
  79. case XK_Page_Up: return KeyboardButton::PAGE_UP;
  80. case XK_Page_Down: return KeyboardButton::PAGE_DOWN;
  81. case XK_Shift_L: return KeyboardButton::LSHIFT;
  82. case XK_Shift_R: return KeyboardButton::RSHIFT;
  83. case XK_Control_L: return KeyboardButton::LCONTROL;
  84. case XK_Control_R: return KeyboardButton::RCONTROL;
  85. case XK_Caps_Lock: return KeyboardButton::CAPS_LOCK;
  86. case XK_Alt_L: return KeyboardButton::LALT;
  87. case XK_Alt_R: return KeyboardButton::RALT;
  88. case XK_Super_L: return KeyboardButton::LSUPER;
  89. case XK_Super_R: return KeyboardButton::RSUPER;
  90. case XK_KP_0: return KeyboardButton::KP_0;
  91. case XK_KP_1: return KeyboardButton::KP_1;
  92. case XK_KP_2: return KeyboardButton::KP_2;
  93. case XK_KP_3: return KeyboardButton::KP_3;
  94. case XK_KP_4: return KeyboardButton::KP_4;
  95. case XK_KP_5: return KeyboardButton::KP_5;
  96. case XK_KP_6: return KeyboardButton::KP_6;
  97. case XK_KP_7: return KeyboardButton::KP_7;
  98. case XK_KP_8: return KeyboardButton::KP_8;
  99. case XK_KP_9: return KeyboardButton::KP_9;
  100. default: return KeyboardButton::NONE;
  101. }
  102. }
  103. struct MainArgs
  104. {
  105. int argc;
  106. char** argv;
  107. class LinuxDevice* device;
  108. };
  109. class LinuxDevice : public Device
  110. {
  111. public:
  112. //-----------------------------------------------------------------------------
  113. LinuxDevice()
  114. : m_x11_display(NULL)
  115. , m_x11_window(None)
  116. , m_x11_parent_window(None)
  117. , m_x11_hidden_cursor(None)
  118. , m_screen_config(NULL)
  119. , m_exit(false)
  120. , m_x(0)
  121. , m_y(0)
  122. , m_width(1000)
  123. , m_height(625)
  124. , m_parent_window_handle(0)
  125. , m_fullscreen(0)
  126. , m_compile(0)
  127. , m_continue(0)
  128. , m_wait_console(0)
  129. {
  130. }
  131. //-----------------------------------------------------------------------------
  132. void init(int argc, char** argv)
  133. {
  134. parse_command_line(argc, argv);
  135. check_preferred_settings();
  136. #if defined(CROWN_DEBUG)
  137. m_console = CE_NEW(default_allocator(), ConsoleServer)();
  138. m_console->init(m_console_port, (bool) m_wait_console);
  139. if (m_compile == 1)
  140. {
  141. m_bundle_compiler = CE_NEW(default_allocator(), BundleCompiler);
  142. if (!m_bundle_compiler->compile(m_bundle_dir, m_source_dir))
  143. {
  144. CE_DELETE(default_allocator(), m_bundle_compiler);
  145. CE_LOGE("Exiting.");
  146. exit(EXIT_FAILURE);
  147. }
  148. if (!m_continue)
  149. {
  150. CE_DELETE(default_allocator(), m_bundle_compiler);
  151. exit(EXIT_SUCCESS);
  152. }
  153. }
  154. #endif
  155. read_configuration();
  156. m_argc = argc;
  157. m_argv = argv;
  158. }
  159. //-----------------------------------------------------------------------------
  160. void shutdown()
  161. {
  162. #if defined(CROWN_DEBUG)
  163. CE_DELETE(default_allocator(), m_bundle_compiler);
  164. m_console->shutdown();
  165. CE_DELETE(default_allocator(), m_console);
  166. #endif
  167. }
  168. //-----------------------------------------------------------------------------
  169. void display_modes(Array<DisplayMode>& modes)
  170. {
  171. int num_rrsizes = 0;
  172. XRRScreenSize* rrsizes = XRRConfigSizes(m_screen_config, &num_rrsizes);
  173. for (int i = 0; i < num_rrsizes; i++)
  174. {
  175. DisplayMode dm;
  176. dm.id = (uint32_t) i;
  177. dm.width = rrsizes[i].width;
  178. dm.height = rrsizes[i].height;
  179. array::push_back(modes, dm);
  180. }
  181. }
  182. //-----------------------------------------------------------------------------
  183. void set_display_mode(uint32_t id)
  184. {
  185. // Check if id is valid
  186. int num_rrsizes = 0;
  187. XRRScreenSize* rrsizes = XRRConfigSizes(m_screen_config, &num_rrsizes);
  188. (void) rrsizes;
  189. if ((int) id >= num_rrsizes)
  190. return;
  191. XRRSetScreenConfig(m_x11_display,
  192. m_screen_config,
  193. RootWindow(m_x11_display, DefaultScreen(m_x11_display)),
  194. (int) id,
  195. RR_Rotate_0,
  196. CurrentTime);
  197. }
  198. //-----------------------------------------------------------------------------
  199. void set_fullscreen(bool full)
  200. {
  201. XEvent e;
  202. e.xclient.type = ClientMessage;
  203. e.xclient.window = m_x11_window;
  204. e.xclient.message_type = XInternAtom(m_x11_display, "_NET_WM_STATE", False );
  205. e.xclient.format = 32;
  206. e.xclient.data.l[0] = full ? 1 : 0;
  207. e.xclient.data.l[1] = XInternAtom(m_x11_display, "_NET_WM_STATE_FULLSCREEN", False);
  208. XSendEvent(m_x11_display, DefaultRootWindow(m_x11_display), False, SubstructureNotifyMask, &e);
  209. }
  210. //-----------------------------------------------------------------------------
  211. int32_t run(int argc, char** argv)
  212. {
  213. init(argc, argv);
  214. XInitThreads();
  215. CE_ASSERT(m_width != 0 || m_height != 0, "Width and height must differ from zero");
  216. m_x11_display = XOpenDisplay(NULL);
  217. CE_ASSERT(m_x11_display != NULL, "Unable to open X11 display");
  218. int screen = DefaultScreen(m_x11_display);
  219. int depth = DefaultDepth(m_x11_display, screen);
  220. Visual* visual = DefaultVisual(m_x11_display, screen);
  221. if (m_parent_window_handle != 0)
  222. {
  223. m_x11_parent_window = (Window) m_parent_window_handle;
  224. }
  225. else
  226. {
  227. m_x11_parent_window = RootWindow(m_x11_display, screen);
  228. }
  229. // We want to track keyboard and mouse events
  230. XSetWindowAttributes win_attribs;
  231. win_attribs.background_pixmap = 0;
  232. win_attribs.border_pixel = 0;
  233. win_attribs.event_mask = FocusChangeMask | StructureNotifyMask | KeyPressMask |
  234. KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
  235. m_x11_window = XCreateWindow(
  236. m_x11_display,
  237. m_x11_parent_window,
  238. 0, 0,
  239. m_width, m_height,
  240. 0,
  241. depth,
  242. InputOutput,
  243. visual,
  244. CWBorderPixel | CWEventMask,
  245. &win_attribs
  246. );
  247. CE_ASSERT(m_x11_window != None, "Unable to create X window");
  248. // Check presence of detectable autorepeat
  249. Bool detectable;
  250. m_x11_detectable_autorepeat = (bool) XkbSetDetectableAutoRepeat(m_x11_display, true, &detectable);
  251. // Build hidden cursor
  252. Pixmap bm_no;
  253. XColor black, dummy;
  254. Colormap colormap;
  255. static char no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  256. colormap = XDefaultColormap(m_x11_display, screen);
  257. XAllocNamedColor(m_x11_display, colormap, "black", &black, &dummy);
  258. bm_no = XCreateBitmapFromData(m_x11_display, m_x11_window, no_data, 8, 8);
  259. m_x11_hidden_cursor = XCreatePixmapCursor(m_x11_display, bm_no, bm_no, &black, &black, 0, 0);
  260. m_wm_delete_message = XInternAtom(m_x11_display, "WM_DELETE_WINDOW", False);
  261. XSetWMProtocols(m_x11_display, m_x11_window, &m_wm_delete_message, 1);
  262. XMapRaised(m_x11_display, m_x11_window);
  263. oswindow_set_window(m_x11_display, m_x11_window);
  264. set_x11_display_and_window(m_x11_display, m_x11_window);
  265. // Get screen configuration
  266. m_screen_config = XRRGetScreenInfo(m_x11_display, RootWindow(m_x11_display, screen));
  267. Rotation rr_old_rot;
  268. const SizeID rr_old_sizeid = XRRConfigCurrentConfiguration(m_screen_config, &rr_old_rot);
  269. Thread game_thread;
  270. game_thread.start(main_loop, (void*)this);
  271. while (!m_exit)
  272. {
  273. LinuxDevice::pump_events();
  274. }
  275. game_thread.stop();
  276. // Restore previous screen configuration if changed
  277. Rotation rr_cur_rot;
  278. const SizeID rr_cur_sizeid = XRRConfigCurrentConfiguration(m_screen_config, &rr_cur_rot);
  279. if (rr_cur_rot != rr_old_rot || rr_cur_sizeid != rr_old_sizeid)
  280. {
  281. XRRSetScreenConfig(m_x11_display,
  282. m_screen_config,
  283. RootWindow(m_x11_display, screen),
  284. rr_old_sizeid,
  285. rr_old_rot,
  286. CurrentTime);
  287. }
  288. XRRFreeScreenConfigInfo(m_screen_config);
  289. LinuxDevice::shutdown();
  290. XDestroyWindow(m_x11_display, m_x11_window);
  291. XCloseDisplay(m_x11_display);
  292. return EXIT_SUCCESS;
  293. }
  294. //-----------------------------------------------------------------------------
  295. int32_t loop()
  296. {
  297. Device::init();
  298. while(!process_events() && is_running())
  299. {
  300. #if defined(CROWN_DEBUG)
  301. m_console->update();
  302. #endif
  303. Device::frame();
  304. m_keyboard->update();
  305. m_mouse->update();
  306. }
  307. Device::shutdown();
  308. m_exit = true;
  309. return 0;
  310. }
  311. //-----------------------------------------------------------------------------
  312. static int32_t main_loop(void* thiz)
  313. {
  314. return ((LinuxDevice*)thiz)->loop();
  315. }
  316. //-----------------------------------------------------------------------------
  317. bool process_events()
  318. {
  319. OsEvent event;
  320. bool exit = false;
  321. while(m_queue.pop_event(event))
  322. {
  323. if (event.type == OsEvent::NONE) continue;
  324. switch (event.type)
  325. {
  326. case OsEvent::MOUSE:
  327. {
  328. const OsMouseEvent& ev = event.mouse;
  329. switch (ev.type)
  330. {
  331. case OsMouseEvent::BUTTON: m_mouse->set_button_state(ev.x, ev.y, ev.button, ev.pressed); break;
  332. case OsMouseEvent::MOVE: m_mouse->set_position(ev.x, ev.y); break;
  333. default: CE_FATAL("Oops, unknown mouse event type"); break;
  334. }
  335. break;
  336. }
  337. case OsEvent::KEYBOARD:
  338. {
  339. const OsKeyboardEvent& ev = event.keyboard;
  340. m_keyboard->set_button_state(ev.button, ev.pressed);
  341. break;
  342. }
  343. case OsEvent::METRICS:
  344. {
  345. const OsMetricsEvent& ev = event.metrics;
  346. m_mouse->set_metrics(ev.width, ev.height);
  347. m_window->m_x = ev.x;
  348. m_window->m_y = ev.y;
  349. m_window->m_width = ev.width;
  350. m_window->m_height = ev.height;
  351. break;
  352. }
  353. case OsEvent::EXIT:
  354. {
  355. exit = true;
  356. break;
  357. }
  358. default:
  359. {
  360. CE_FATAL("Unknown Os Event");
  361. break;
  362. }
  363. }
  364. }
  365. return exit;
  366. }
  367. //-----------------------------------------------------------------------------
  368. void pump_events()
  369. {
  370. while (XPending(m_x11_display))
  371. {
  372. XEvent event;
  373. XNextEvent(m_x11_display, &event);
  374. switch (event.type)
  375. {
  376. case ClientMessage:
  377. {
  378. if ((Atom)event.xclient.data.l[0] == m_wm_delete_message)
  379. {
  380. m_queue.push_exit_event(0);
  381. }
  382. break;
  383. }
  384. case ConfigureNotify:
  385. {
  386. m_x = event.xconfigure.x;
  387. m_y = event.xconfigure.y;
  388. m_width = event.xconfigure.width;
  389. m_height = event.xconfigure.height;
  390. m_queue.push_metrics_event(event.xconfigure.x, event.xconfigure.y,
  391. event.xconfigure.width, event.xconfigure.height);
  392. break;
  393. }
  394. case ButtonPress:
  395. case ButtonRelease:
  396. {
  397. MouseButton::Enum mb;
  398. switch (event.xbutton.button)
  399. {
  400. case Button1: mb = MouseButton::LEFT; break;
  401. case Button2: mb = MouseButton::MIDDLE; break;
  402. case Button3: mb = MouseButton::RIGHT; break;
  403. default: mb = MouseButton::NONE; break;
  404. }
  405. if (mb != MouseButton::NONE)
  406. {
  407. m_queue.push_mouse_event(event.xbutton.x, event.xbutton.y, mb, event.type == ButtonPress);
  408. }
  409. break;
  410. }
  411. case MotionNotify:
  412. {
  413. m_queue.push_mouse_event(event.xmotion.x, event.xmotion.y);
  414. break;
  415. }
  416. case KeyPress:
  417. case KeyRelease:
  418. {
  419. char string[4] = {0, 0, 0, 0};
  420. KeySym key;
  421. XLookupString(&event.xkey, string, 4, &key, NULL);
  422. KeyboardButton::Enum kb = x11_translate_key(key);
  423. // Check if any modifier key is pressed or released
  424. int32_t modifier_mask = 0;
  425. if (kb == KeyboardButton::LSHIFT || kb == KeyboardButton::RSHIFT)
  426. {
  427. (event.type == KeyPress) ? modifier_mask |= ModifierButton::SHIFT : modifier_mask &= ~ModifierButton::SHIFT;
  428. }
  429. else if (kb == KeyboardButton::LCONTROL || kb == KeyboardButton::RCONTROL)
  430. {
  431. (event.type == KeyPress) ? modifier_mask |= ModifierButton::CTRL : modifier_mask &= ~ModifierButton::CTRL;
  432. }
  433. else if (kb == KeyboardButton::LALT || kb == KeyboardButton::RALT)
  434. {
  435. (event.type == KeyPress) ? modifier_mask |= ModifierButton::ALT : modifier_mask &= ~ModifierButton::ALT;
  436. }
  437. m_queue.push_keyboard_event(modifier_mask, kb, event.type == KeyPress);
  438. // // Text input part
  439. // if (event.type == KeyPress && len > 0)
  440. // {
  441. // //crownEvent.event_type = ET_TEXT;m_queue
  442. // //crownEvent.text.type = TET_TEXT_INPUT;
  443. // strncpy(keyboardEvent.text, string, 4);
  444. // if (mListener)
  445. // {
  446. // mListener->TextInput(keyboardEvent);
  447. // }
  448. // }
  449. break;
  450. }
  451. case KeymapNotify:
  452. {
  453. XRefreshKeyboardMapping(&event.xmapping);
  454. break;
  455. }
  456. default:
  457. {
  458. break;
  459. }
  460. }
  461. }
  462. }
  463. //-----------------------------------------------------------------------------
  464. void parse_command_line(int argc, char** argv)
  465. {
  466. static const char* help_message =
  467. "Usage: crown [options]\n"
  468. "Options:\n\n"
  469. "All of the following options take precedence over\n"
  470. "environment variables and configuration files.\n\n"
  471. " --help Show this help.\n"
  472. " --bundle-dir <path> Use <path> as the source directory for compiled resources.\n"
  473. " --width <width> Set the <width> of the main window.\n"
  474. " --height <width> Set the <height> of the main window.\n"
  475. " --fullscreen Start in fullscreen.\n"
  476. " --parent-window <handle> Set the parent window <handle> of the main window.\n"
  477. " Used only by tools.\n"
  478. "\nAvailable only in debug and development builds:\n\n"
  479. " --source-dir <path> Use <path> as the source directory for resource compilation.\n"
  480. " --compile Do a full compile of the resources.\n"
  481. " --continue Continue the execution after the resource compilation step.\n"
  482. " --file-server Read resources from a remote engine instance.\n"
  483. " --console-port Set the network port of the console server.\n"
  484. " --wait-console Wait for a console connection before starting up.\n";
  485. static ArgsOption options[] =
  486. {
  487. { "help", AOA_NO_ARGUMENT, NULL, 'i' },
  488. { "source-dir", AOA_REQUIRED_ARGUMENT, NULL, 's' },
  489. { "bundle-dir", AOA_REQUIRED_ARGUMENT, NULL, 'b' },
  490. { "compile", AOA_NO_ARGUMENT, &m_compile, 1 },
  491. { "continue", AOA_NO_ARGUMENT, &m_continue, 1 },
  492. { "width", AOA_REQUIRED_ARGUMENT, NULL, 'w' },
  493. { "height", AOA_REQUIRED_ARGUMENT, NULL, 'h' },
  494. { "fullscreen", AOA_NO_ARGUMENT, &m_fullscreen, 1 },
  495. { "parent-window", AOA_REQUIRED_ARGUMENT, NULL, 'p' },
  496. { "file-server", AOA_NO_ARGUMENT, &m_fileserver, 1 },
  497. { "console-port", AOA_REQUIRED_ARGUMENT, NULL, 'c' },
  498. { "wait-console", AOA_NO_ARGUMENT, &m_wait_console, 1 },
  499. { NULL, 0, NULL, 0 }
  500. };
  501. Args args(argc, argv, "", options);
  502. int32_t opt;
  503. while ((opt = args.getopt()) != -1)
  504. {
  505. switch (opt)
  506. {
  507. case 0:
  508. {
  509. break;
  510. }
  511. // Source directory
  512. case 's':
  513. {
  514. string::strncpy(m_source_dir, args.optarg(), MAX_PATH_LENGTH);
  515. break;
  516. }
  517. // Bundle directory
  518. case 'b':
  519. {
  520. string::strncpy(m_bundle_dir, args.optarg(), MAX_PATH_LENGTH);
  521. break;
  522. }
  523. // Window width
  524. case 'w':
  525. {
  526. m_width = atoi(args.optarg());
  527. break;
  528. }
  529. // Window height
  530. case 'h':
  531. {
  532. m_height = atoi(args.optarg());
  533. break;
  534. }
  535. // Parent window
  536. case 'p':
  537. {
  538. m_parent_window_handle = string::parse_uint(args.optarg());
  539. break;
  540. }
  541. // Console port
  542. case 'c':
  543. {
  544. m_console_port = string::parse_uint(args.optarg());
  545. break;
  546. }
  547. case 'i':
  548. case '?':
  549. default:
  550. {
  551. printf(help_message);
  552. exit(EXIT_FAILURE);
  553. }
  554. }
  555. }
  556. }
  557. //-----------------------------------------------------------------------------
  558. void check_preferred_settings()
  559. {
  560. if (m_compile == 1)
  561. {
  562. if (string::strcmp(m_source_dir, "") == 0)
  563. {
  564. CE_LOGE("You have to specify the source directory when running in compile mode.");
  565. exit(EXIT_FAILURE);
  566. }
  567. if (!os::is_absolute_path(m_source_dir))
  568. {
  569. CE_LOGE("The source directory must be absolute.");
  570. exit(EXIT_FAILURE);
  571. }
  572. }
  573. if (!os::is_absolute_path(m_bundle_dir))
  574. {
  575. CE_LOGE("The bundle directory must be absolute.");
  576. exit(EXIT_FAILURE);
  577. }
  578. if (m_width == 0 || m_height == 0)
  579. {
  580. CE_LOGE("Window width and height must be greater than zero.");
  581. exit(EXIT_FAILURE);
  582. }
  583. }
  584. //-------------------------------------------------------------------------
  585. void read_configuration()
  586. {
  587. DiskFilesystem fs(m_bundle_dir);
  588. // crown.config is mandatory
  589. CE_ASSERT(fs.is_file("crown.config"), "Unable to open crown.config");
  590. File* config_file = fs.open("crown.config", FOM_READ);
  591. TempAllocator4096 alloc;
  592. char* json_string = (char*)alloc.allocate(config_file->size());
  593. config_file->read(json_string, config_file->size());
  594. fs.close(config_file);
  595. // Parse crown.config
  596. JSONParser parser(json_string);
  597. JSONElement root = parser.root();
  598. // Boot
  599. if (root.has_key("boot"))
  600. {
  601. DynamicString boot;
  602. root.key("boot").to_string(boot);
  603. string::strncpy(m_boot_file, boot.c_str(), (boot.length() > MAX_PATH_LENGTH) ? MAX_PATH_LENGTH : boot.length() + 1);
  604. }
  605. // Window width
  606. if (root.has_key("window_width"))
  607. {
  608. m_width = root.key("window_width").to_int();
  609. }
  610. // Window height
  611. if (root.has_key("window_height"))
  612. {
  613. m_height = root.key("window_height").to_int();
  614. }
  615. }
  616. private:
  617. Display* m_x11_display;
  618. Window m_x11_window;
  619. Window m_x11_parent_window;
  620. Cursor m_x11_hidden_cursor;
  621. Atom m_wm_delete_message;
  622. XRRScreenConfiguration* m_screen_config;
  623. bool m_exit;
  624. uint32_t m_x;
  625. uint32_t m_y;
  626. uint32_t m_width;
  627. uint32_t m_height;
  628. bool m_x11_detectable_autorepeat;
  629. uint32_t m_parent_window_handle;
  630. int32_t m_fullscreen;
  631. int32_t m_compile;
  632. int32_t m_continue;
  633. int32_t m_wait_console;
  634. OsEventQueue m_queue;
  635. };
  636. } // namespace crown
  637. int main(int argc, char** argv)
  638. {
  639. crown::init();
  640. crown::LinuxDevice* engine = CE_NEW(crown::default_allocator(), crown::LinuxDevice)();
  641. crown::set_device(engine);
  642. int32_t ret = engine->run(argc, argv);
  643. CE_DELETE(crown::default_allocator(), engine);
  644. crown::shutdown();
  645. return ret;
  646. }