x86UNIXWindow.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "io/fileStream.h"
  24. #include "game/resource.h"
  25. #include "game/version.h"
  26. #include "math/mRandom.h"
  27. #include "platformX86UNIX/platformX86UNIX.h"
  28. #include "platformX86UNIX/x86UNIXStdConsole.h"
  29. #include "platform/event.h"
  30. #include "game/gameInterface.h"
  31. #include "platform/platform.h"
  32. #include "platform/platformAL.h"
  33. #include "platform/platformInput.h"
  34. #include "platform/platformVideo.h"
  35. #include "debug/profiler.h"
  36. #include "platformX86UNIX/platformGL.h"
  37. #include "platformX86UNIX/x86UNIXOGLVideo.h"
  38. #include "platformX86UNIX/x86UNIXState.h"
  39. #ifndef DEDICATED
  40. #include "platformX86UNIX/x86UNIXMessageBox.h"
  41. #include "platformX86UNIX/x86UNIXInputManager.h"
  42. #endif
  43. #include <errno.h>
  44. #include <signal.h>
  45. #include <stdlib.h>
  46. #include <unistd.h> // fork, execvp, chdir
  47. #include <time.h> // nanosleep
  48. #ifndef DEDICATED
  49. #include <SDL/SDL.h>
  50. #include <SDL/SDL_syswm.h>
  51. #include <SDL/SDL_version.h>
  52. #endif
  53. x86UNIXPlatformState *x86UNIXState;
  54. bool DisplayPtrManager::sgDisplayLocked = false;
  55. LockFunc_t DisplayPtrManager::sgLockFunc = NULL;
  56. LockFunc_t DisplayPtrManager::sgUnlockFunc = NULL;
  57. static U32 lastTimeTick;
  58. #ifndef DEDICATED
  59. extern bool InitOpenGL();
  60. // This is called when some X client sends
  61. // a selection event (e.g. SelectionRequest)
  62. // to the window
  63. extern void NotifySelectionEvent(XEvent& event);
  64. #endif
  65. //------------------------------------------------------------------------------
  66. static S32 ParseCommandLine(S32 argc, const char **argv,
  67. Vector<char*>& newCommandLine)
  68. {
  69. x86UNIXState->setExePathName(argv[0]);
  70. bool foundDedicated = false;
  71. for ( int i=0; i < argc; i++ )
  72. {
  73. // look for platform specific args
  74. if (dStrcmp(argv[i], "-version") == 0)
  75. {
  76. dPrintf("%s (built on %s)\n", getVersionString(), getCompileTimeString());
  77. dPrintf("gcc: %s\n", __VERSION__);
  78. return 1;
  79. }
  80. if (dStrcmp(argv[i], "-dedicated") == 0)
  81. {
  82. foundDedicated = true;
  83. // no continue because dedicated is also handled by script
  84. }
  85. if (dStrcmp(argv[i], "-dsleep") == 0)
  86. {
  87. x86UNIXState->setDSleep(true);
  88. continue;
  89. }
  90. if (dStrcmp(argv[i], "-nohomedir") == 0)
  91. {
  92. x86UNIXState->setUseRedirect(false);
  93. continue;
  94. }
  95. if (dStrcmp(argv[i], "-chdir") == 0)
  96. {
  97. if ( ++i >= argc )
  98. {
  99. dPrintf("Follow -chdir option with the desired working directory.\n");
  100. return 1;
  101. }
  102. if (chdir(argv[i]) == -1)
  103. {
  104. dPrintf("Unable to chdir to %s: %s\n", argv[i], strerror(errno));
  105. return 1;
  106. }
  107. continue;
  108. }
  109. // copy the arg into newCommandLine
  110. int argLen = dStrlen(argv[i]) + 1;
  111. char* argBuf = new char[argLen]; // this memory is deleted in main()
  112. dStrncpy(argBuf, argv[i], argLen);
  113. newCommandLine.push_back(argBuf);
  114. }
  115. x86UNIXState->setDedicated(foundDedicated);
  116. #if defined(DEDICATED) && !defined(TORQUE_ENGINE)
  117. if (!foundDedicated)
  118. {
  119. dPrintf("This is a dedicated server build. You must supply the -dedicated command line parameter.\n");
  120. return 1;
  121. }
  122. #endif
  123. return 0;
  124. }
  125. static void DetectWindowingSystem()
  126. {
  127. #ifndef DEDICATED
  128. Display* dpy = XOpenDisplay(NULL);
  129. if (dpy != NULL)
  130. {
  131. x86UNIXState->setXWindowsRunning(true);
  132. XCloseDisplay(dpy);
  133. }
  134. #endif
  135. }
  136. //------------------------------------------------------------------------------
  137. static void InitWindow(const Point2I &initialSize, const char *name)
  138. {
  139. x86UNIXState->setWindowSize(initialSize);
  140. x86UNIXState->setWindowName(name);
  141. }
  142. #ifndef DEDICATED
  143. //------------------------------------------------------------------------------
  144. static bool InitSDL()
  145. {
  146. if (SDL_Init(SDL_INIT_VIDEO) != 0)
  147. return false;
  148. atexit(SDL_Quit);
  149. SDL_SysWMinfo sysinfo;
  150. SDL_VERSION(&sysinfo.version);
  151. if (SDL_GetWMInfo(&sysinfo) == 0)
  152. return false;
  153. x86UNIXState->setDisplayPointer(sysinfo.info.x11.display);
  154. DisplayPtrManager::setDisplayLockFunction(sysinfo.info.x11.lock_func);
  155. DisplayPtrManager::setDisplayUnlockFunction(sysinfo.info.x11.unlock_func);
  156. DisplayPtrManager xdisplay;
  157. Display* display = xdisplay.getDisplayPointer();
  158. x86UNIXState->setScreenNumber(
  159. DefaultScreen( display ) );
  160. x86UNIXState->setScreenPointer(
  161. DefaultScreenOfDisplay( display ) );
  162. x86UNIXState->setDesktopSize(
  163. (S32) DisplayWidth(
  164. display,
  165. x86UNIXState->getScreenNumber()),
  166. (S32) DisplayHeight(
  167. display,
  168. x86UNIXState->getScreenNumber())
  169. );
  170. x86UNIXState->setDesktopBpp(
  171. (S32) DefaultDepth(
  172. display,
  173. x86UNIXState->getScreenNumber()));
  174. // indicate that we want sys WM messages
  175. SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
  176. return true;
  177. }
  178. //------------------------------------------------------------------------------
  179. static void ProcessSYSWMEvent(const SDL_Event& event)
  180. {
  181. XEvent& xevent = event.syswm.msg->event.xevent;
  182. //Con::printf("xevent : %d", xevent.type);
  183. switch (xevent.type)
  184. {
  185. case SelectionRequest:
  186. // somebody wants our clipboard
  187. NotifySelectionEvent(xevent);
  188. break;
  189. }
  190. }
  191. //------------------------------------------------------------------------------
  192. static void SetAppState()
  193. {
  194. U8 state = SDL_GetAppState();
  195. // if we're not active but we have appactive and inputfocus, set window
  196. // active and reactivate input
  197. if ((!x86UNIXState->windowActive() || !Input::isActive()) &&
  198. state & SDL_APPACTIVE &&
  199. state & SDL_APPINPUTFOCUS)
  200. {
  201. x86UNIXState->setWindowActive(true);
  202. Input::reactivate();
  203. }
  204. // if we are active, but we don't have appactive or input focus,
  205. // deactivate input (if window not locked) and clear windowActive
  206. else if (x86UNIXState->windowActive() &&
  207. !(state & SDL_APPACTIVE && state & SDL_APPINPUTFOCUS))
  208. {
  209. if (x86UNIXState->windowLocked())
  210. Input::deactivate();
  211. x86UNIXState->setWindowActive(false);
  212. }
  213. }
  214. //------------------------------------------------------------------------------
  215. static S32 NumEventsPending()
  216. {
  217. static const int MaxEvents = 255;
  218. static SDL_Event events[MaxEvents];
  219. SDL_PumpEvents();
  220. return SDL_PeepEvents(events, MaxEvents, SDL_PEEKEVENT, SDL_ALLEVENTS);
  221. }
  222. //------------------------------------------------------------------------------
  223. static void PrintSDLEventQueue()
  224. {
  225. static const int MaxEvents = 255;
  226. static SDL_Event events[MaxEvents];
  227. SDL_PumpEvents();
  228. S32 numEvents = SDL_PeepEvents(
  229. events, MaxEvents, SDL_PEEKEVENT, SDL_ALLEVENTS);
  230. if (numEvents <= 0)
  231. {
  232. dPrintf("SDL Event Queue is empty\n");
  233. return;
  234. }
  235. dPrintf("SDL Event Queue:\n");
  236. for (int i = 0; i < numEvents; ++i)
  237. {
  238. const char *eventType;
  239. switch (events[i].type)
  240. {
  241. case SDL_NOEVENT: eventType = "SDL_NOEVENT"; break;
  242. case SDL_ACTIVEEVENT: eventType = "SDL_ACTIVEEVENT"; break;
  243. case SDL_KEYDOWN: eventType = "SDL_KEYDOWN"; break;
  244. case SDL_KEYUP: eventType = "SDL_KEYUP"; break;
  245. case SDL_MOUSEMOTION: eventType = "SDL_MOUSEMOTION"; break;
  246. case SDL_MOUSEBUTTONDOWN: eventType = "SDL_MOUSEBUTTONDOWN"; break;
  247. case SDL_MOUSEBUTTONUP: eventType = "SDL_MOUSEBUTTONUP"; break;
  248. case SDL_JOYAXISMOTION: eventType = "SDL_JOYAXISMOTION"; break;
  249. case SDL_JOYBALLMOTION: eventType = "SDL_JOYBALLMOTION"; break;
  250. case SDL_JOYHATMOTION: eventType = "SDL_JOYHATMOTION"; break;
  251. case SDL_JOYBUTTONDOWN: eventType = "SDL_JOYBUTTONDOWN"; break;
  252. case SDL_JOYBUTTONUP: eventType = "SDL_JOYBUTTONUP"; break;
  253. case SDL_QUIT: eventType = "SDL_QUIT"; break;
  254. case SDL_SYSWMEVENT: eventType = "SDL_SYSWMEVENT"; break;
  255. case SDL_VIDEORESIZE: eventType = "SDL_VIDEORESIZE"; break;
  256. case SDL_VIDEOEXPOSE: eventType = "SDL_VIDEOEXPOSE"; break;
  257. /* Events SDL_USEREVENT through SDL_MAXEVENTS-1 are for your use */
  258. case SDL_USEREVENT: eventType = "SDL_USEREVENT"; break;
  259. default: eventType = "UNKNOWN!"; break;
  260. }
  261. dPrintf("Event %d: %s\n", i, eventType);
  262. }
  263. }
  264. //------------------------------------------------------------------------------
  265. static bool ProcessMessages()
  266. {
  267. static const int MaxEvents = 255;
  268. static const U32 Mask =
  269. SDL_QUITMASK | SDL_VIDEORESIZEMASK | SDL_VIDEOEXPOSEMASK |
  270. SDL_ACTIVEEVENTMASK | SDL_SYSWMEVENTMASK |
  271. SDL_EVENTMASK(SDL_USEREVENT);
  272. static SDL_Event events[MaxEvents];
  273. SDL_PumpEvents();
  274. S32 numEvents = SDL_PeepEvents(events, MaxEvents, SDL_GETEVENT, Mask);
  275. if (numEvents == 0)
  276. return true;
  277. for (int i = 0; i < numEvents; ++i)
  278. {
  279. SDL_Event& event = events[i];
  280. switch (event.type)
  281. {
  282. case SDL_QUIT:
  283. return false;
  284. break;
  285. case SDL_VIDEORESIZE:
  286. case SDL_VIDEOEXPOSE:
  287. Game->refreshWindow();
  288. break;
  289. case SDL_USEREVENT:
  290. if (event.user.code == TORQUE_SETVIDEOMODE)
  291. {
  292. SetAppState();
  293. // SDL will send a motion event to restore the mouse position
  294. // on the new window. Ignore that if the window is locked.
  295. if (x86UNIXState->windowLocked())
  296. {
  297. SDL_Event tempEvent;
  298. SDL_PeepEvents(&tempEvent, 1, SDL_GETEVENT,
  299. SDL_MOUSEMOTIONMASK);
  300. }
  301. }
  302. break;
  303. case SDL_ACTIVEEVENT:
  304. SetAppState();
  305. break;
  306. case SDL_SYSWMEVENT:
  307. ProcessSYSWMEvent(event);
  308. break;
  309. }
  310. }
  311. return true;
  312. }
  313. //------------------------------------------------------------------------------
  314. // send a destroy window event to the window. assumes
  315. // window is created.
  316. void SendQuitEvent()
  317. {
  318. SDL_Event quitevent;
  319. quitevent.type = SDL_QUIT;
  320. SDL_PushEvent(&quitevent);
  321. }
  322. #endif // DEDICATED
  323. //------------------------------------------------------------------------------
  324. static inline void Sleep(int secs, int nanoSecs)
  325. {
  326. timespec sleeptime;
  327. sleeptime.tv_sec = secs;
  328. sleeptime.tv_nsec = nanoSecs;
  329. nanosleep(&sleeptime, NULL);
  330. }
  331. #ifndef DEDICATED
  332. struct AlertWinState
  333. {
  334. bool fullScreen;
  335. bool cursorHidden;
  336. bool inputGrabbed;
  337. };
  338. //------------------------------------------------------------------------------
  339. void DisplayErrorAlert(const char* errMsg, bool showSDLError)
  340. {
  341. char fullErrMsg[2048];
  342. dStrncpy(fullErrMsg, errMsg, sizeof(fullErrMsg));
  343. if (showSDLError)
  344. {
  345. char* sdlerror = SDL_GetError();
  346. if (sdlerror != NULL && dStrlen(sdlerror) > 0)
  347. {
  348. dStrcat(fullErrMsg, " (Error: ");
  349. dStrcat(fullErrMsg, sdlerror);
  350. dStrcat(fullErrMsg, ")");
  351. }
  352. }
  353. Platform::AlertOK("Error", fullErrMsg);
  354. }
  355. //------------------------------------------------------------------------------
  356. static inline void AlertDisableVideo(AlertWinState& state)
  357. {
  358. state.fullScreen = Video::isFullScreen();
  359. state.cursorHidden = (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE);
  360. state.inputGrabbed = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
  361. if (state.fullScreen)
  362. SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
  363. if (state.cursorHidden)
  364. SDL_ShowCursor(SDL_ENABLE);
  365. if (state.inputGrabbed)
  366. SDL_WM_GrabInput(SDL_GRAB_OFF);
  367. }
  368. //------------------------------------------------------------------------------
  369. static inline void AlertEnableVideo(AlertWinState& state)
  370. {
  371. if (state.fullScreen)
  372. SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
  373. if (state.cursorHidden)
  374. SDL_ShowCursor(SDL_DISABLE);
  375. if (state.inputGrabbed)
  376. SDL_WM_GrabInput(SDL_GRAB_ON);
  377. }
  378. #endif // DEDICATED
  379. //------------------------------------------------------------------------------
  380. void Platform::AlertOK(const char *windowTitle, const char *message)
  381. {
  382. #ifndef DEDICATED
  383. if (x86UNIXState->isXWindowsRunning())
  384. {
  385. AlertWinState state;
  386. AlertDisableVideo(state);
  387. DisplayPtrManager xdisplay;
  388. XMessageBox mBox(xdisplay.getDisplayPointer());
  389. mBox.alertOK(windowTitle, message);
  390. AlertEnableVideo(state);
  391. }
  392. else
  393. #endif
  394. {
  395. if (Con::isActive() && StdConsole::isEnabled())
  396. Con::printf("Alert: %s %s", windowTitle, message);
  397. else
  398. dPrintf("Alert: %s %s\n", windowTitle, message);
  399. }
  400. }
  401. //------------------------------------------------------------------------------
  402. bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
  403. {
  404. #ifndef DEDICATED
  405. if (x86UNIXState->isXWindowsRunning())
  406. {
  407. AlertWinState state;
  408. AlertDisableVideo(state);
  409. DisplayPtrManager xdisplay;
  410. XMessageBox mBox(xdisplay.getDisplayPointer());
  411. bool val =
  412. mBox.alertOKCancel(windowTitle, message) == XMessageBox::OK;
  413. AlertEnableVideo(state);
  414. return val;
  415. }
  416. else
  417. #endif
  418. {
  419. if (Con::isActive() && StdConsole::isEnabled())
  420. Con::printf("Alert: %s %s", windowTitle, message);
  421. else
  422. dPrintf("Alert: %s %s\n", windowTitle, message);
  423. return false;
  424. }
  425. }
  426. //------------------------------------------------------------------------------
  427. bool Platform::AlertRetry(const char *windowTitle, const char *message)
  428. {
  429. #ifndef DEDICATED
  430. if (x86UNIXState->isXWindowsRunning())
  431. {
  432. AlertWinState state;
  433. AlertDisableVideo(state);
  434. DisplayPtrManager xdisplay;
  435. XMessageBox mBox(xdisplay.getDisplayPointer());
  436. bool val =
  437. mBox.alertRetryCancel(windowTitle, message) == XMessageBox::Retry;
  438. AlertEnableVideo(state);
  439. return val;
  440. }
  441. else
  442. #endif
  443. {
  444. if (Con::isActive() && StdConsole::isEnabled())
  445. Con::printf("Alert: %s %s", windowTitle, message);
  446. else
  447. dPrintf("Alert: %s %s\n", windowTitle, message);
  448. return false;
  449. }
  450. }
  451. //Luma: YesNo alert message
  452. bool Platform::AlertYesNo(const char *windowTitle, const char *message)
  453. {
  454. #ifndef DEDICATED
  455. if (x86UNIXState->isXWindowsRunning())
  456. {
  457. AlertWinState state;
  458. AlertDisableVideo(state);
  459. DisplayPtrManager xdisplay;
  460. XMessageBox mBox(xdisplay.getDisplayPointer());
  461. bool val =
  462. mBox.alertYesNo(windowTitle, message) == XMessageBox::OK;
  463. AlertEnableVideo(state);
  464. return val;
  465. }
  466. else
  467. #endif
  468. {
  469. if (Con::isActive() && StdConsole::isEnabled())
  470. Con::printf("Alert: %s %s", windowTitle, message);
  471. else
  472. dPrintf("Alert: %s %s\n", windowTitle, message);
  473. return false;
  474. }
  475. }
  476. // Very hacky, doesn't support buttons or icons
  477. S32 Platform::messageBox(const UTF8 *title, const UTF8 *message, MBButtons buttons, MBIcons icon)
  478. {
  479. Platform::AlertOK(title, message);
  480. return 0;
  481. }
  482. //------------------------------------------------------------------------------
  483. void Platform::enableKeyboardTranslation(void)
  484. {
  485. #ifndef DEDICATED
  486. // JMQ: not sure if this is needed for i18n keyboards
  487. //SDL_EnableUNICODE( 1 );
  488. // SDL_EnableKeyRepeat(
  489. // SDL_DEFAULT_REPEAT_DELAY,
  490. // SDL_DEFAULT_REPEAT_INTERVAL);
  491. #endif
  492. }
  493. //------------------------------------------------------------------------------
  494. void Platform::disableKeyboardTranslation(void)
  495. {
  496. #ifndef DEDICATED
  497. //SDL_EnableUNICODE( 0 );
  498. // SDL_EnableKeyRepeat(0, 0);
  499. #endif
  500. }
  501. //------------------------------------------------------------------------------
  502. void Platform::minimizeWindow()
  503. {
  504. #ifndef DEDICATED
  505. if (x86UNIXState->windowCreated())
  506. SDL_WM_IconifyWindow();
  507. #endif
  508. }
  509. void Platform::restoreWindow()
  510. {
  511. }
  512. //------------------------------------------------------------------------------
  513. void Platform::process()
  514. {
  515. PROFILE_START(XUX_PlatformProcess);
  516. stdConsole->process();
  517. if (x86UNIXState->windowCreated())
  518. {
  519. #ifndef DEDICATED
  520. // process window events
  521. PROFILE_START(XUX_ProcessMessages);
  522. bool quit = !ProcessMessages();
  523. PROFILE_END();
  524. if(quit)
  525. {
  526. // generate a quit event
  527. Event quitEvent;
  528. quitEvent.type = QuitEventType;
  529. Game->postEvent(quitEvent);
  530. }
  531. // process input events
  532. PROFILE_START(XUX_InputProcess);
  533. Input::process();
  534. PROFILE_END();
  535. // if we're not the foreground window, sleep for 1 ms
  536. if (!x86UNIXState->windowActive())
  537. Sleep(0, getBackgroundSleepTime() * 1000000);
  538. #endif
  539. }
  540. else
  541. {
  542. // no window
  543. // if we're not in journal mode, sleep for 1 ms
  544. // JMQ: since linux's minimum sleep latency seems to be 20ms, this can
  545. // increase player pings by 10-20ms in the dedicated server. So
  546. // you have to use -dsleep to enable it. the server sleeps anyway when
  547. // there are no players connected.
  548. // JMQ: recent kernels (such as RH 8.0 2.4.18) reduce the latency
  549. // to 2-4 ms on average.
  550. if (!Game->isJournalReading() && (x86UNIXState->getDSleep() ||
  551. Con::getIntVariable("Server::PlayerCount") -
  552. Con::getIntVariable("Server::BotCount") <= 0))
  553. {
  554. PROFILE_START(XUX_Sleep);
  555. Sleep(0, getBackgroundSleepTime() * 1000000);
  556. PROFILE_END();
  557. }
  558. }
  559. #ifndef DEDICATED
  560. #if 0
  561. // JMQ: disabled this because it may fire mistakenly in some configurations.
  562. // sdl's default event handling scheme should be enough.
  563. // crude check to make sure that we're not loading up events. the sdl
  564. // event queue should never have more than (say) 25 events in it at this
  565. // point
  566. const int MaxEvents = 25;
  567. if (NumEventsPending() > MaxEvents)
  568. {
  569. PrintSDLEventQueue();
  570. AssertFatal(false, "The SDL event queue has too many events!");
  571. }
  572. #endif
  573. #endif
  574. PROFILE_END();
  575. }
  576. // extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );
  577. // #if defined(DEBUG) || defined(INTERNAL_RELEASE)
  578. // static U32 stubCRC = 0;
  579. // #else
  580. // static U32 stubCRC = 0xEA63F56C;
  581. // #endif
  582. //------------------------------------------------------------------------------
  583. const Point2I &Platform::getWindowSize()
  584. {
  585. return x86UNIXState->getWindowSize();
  586. }
  587. //------------------------------------------------------------------------------
  588. void Platform::setWindowSize( U32 newWidth, U32 newHeight )
  589. {
  590. x86UNIXState->setWindowSize( (S32) newWidth, (S32) newHeight );
  591. }
  592. //------------------------------------------------------------------------------
  593. void Platform::shutdown()
  594. {
  595. Cleanup();
  596. }
  597. //------------------------------------------------------------------------------
  598. void Platform::init()
  599. {
  600. // Set the platform variable for the scripts
  601. Con::setVariable( "$platform", "x86UNIX" );
  602. #if defined(__linux__)
  603. Con::setVariable( "$platformUnixType", "Linux" );
  604. #elif defined(__OpenBSD__)
  605. Con::setVariable( "$platformUnixType", "OpenBSD" );
  606. #else
  607. Con::setVariable( "$platformUnixType", "Unknown" );
  608. #endif
  609. StdConsole::create();
  610. #ifndef DEDICATED
  611. // if we're not dedicated do more initialization
  612. if (!x86UNIXState->isDedicated())
  613. {
  614. // init SDL
  615. if (!InitSDL())
  616. {
  617. DisplayErrorAlert("Unable to initialize SDL.");
  618. ImmediateShutdown(1);
  619. } else {
  620. Con::printf("SDL Initialized");
  621. }
  622. // initialize input
  623. Input::init();
  624. Con::printf( "Video Init:" );
  625. // load gl library
  626. if (!GLLoader::OpenGLInit())
  627. {
  628. DisplayErrorAlert("Unable to initialize OpenGL.");
  629. ImmediateShutdown(1);
  630. }
  631. // initialize video
  632. Video::init();
  633. if ( Video::installDevice( OpenGLDevice::create() ) )
  634. Con::printf( " OpenGL display device detected." );
  635. else
  636. Con::printf( " OpenGL display device not detected." );
  637. Con::printf(" ");
  638. }
  639. #endif
  640. // if we are dedicated, do sleep timing and display results
  641. if (x86UNIXState->isDedicated())
  642. {
  643. const S32 MaxSleepIter = 10;
  644. U32 totalSleepTime = 0;
  645. U32 start;
  646. for (S32 i = 0; i < MaxSleepIter; ++i)
  647. {
  648. start = Platform::getRealMilliseconds();
  649. Sleep(0, 1000000);
  650. totalSleepTime += Platform::getRealMilliseconds() - start;
  651. }
  652. U32 average = static_cast<U32>(totalSleepTime / MaxSleepIter);
  653. Con::printf("Sleep latency: %ums", average);
  654. // dPrintf as well, since console output won't be visible yet
  655. dPrintf("Sleep latency: %ums\n", average);
  656. if (!x86UNIXState->getDSleep() && average < 10)
  657. {
  658. const char* msg = "Sleep latency ok, enabling dsleep for lower cpu " \
  659. "utilization";
  660. Con::printf("%s", msg);
  661. dPrintf("%s\n", msg);
  662. x86UNIXState->setDSleep(true);
  663. }
  664. }
  665. }
  666. //------------------------------------------------------------------------------
  667. void Platform::initWindow(const Point2I &initialSize, const char *name)
  668. {
  669. #ifndef DEDICATED
  670. // initialize window
  671. InitWindow(initialSize, name);
  672. if (!InitOpenGL())
  673. ImmediateShutdown(1);
  674. #endif
  675. }
  676. //------------------------------------------------------------------------------
  677. // Web browser function:
  678. //------------------------------------------------------------------------------
  679. bool Platform::openWebBrowser( const char* webAddress )
  680. {
  681. if (!webAddress || dStrlen(webAddress)==0)
  682. return false;
  683. // look for a browser preference variable
  684. // JMQTODO: be nice to implement some UI to customize this
  685. const char* webBrowser = Con::getVariable("Pref::Unix::WebBrowser");
  686. if (dStrlen(webBrowser) == 0)
  687. webBrowser = NULL;
  688. pid_t pid = fork();
  689. if (pid == -1)
  690. {
  691. Con::printf("WARNING: Platform::openWebBrowser failed to fork");
  692. return false;
  693. }
  694. else if (pid != 0)
  695. {
  696. // parent
  697. if (Video::isFullScreen())
  698. Video::toggleFullScreen();
  699. return true;
  700. }
  701. else if (pid == 0)
  702. {
  703. // child
  704. char* argv[3];
  705. argv[0] = 0;
  706. argv[1] = const_cast<char*>(webAddress);
  707. argv[2] = 0;
  708. int ok = -1;
  709. // if execvp returns, it means it couldn't execute the program
  710. if (webBrowser != NULL)
  711. ok = execvp(webBrowser, argv);
  712. ok = execvp("xdg-open", argv);
  713. ok = execvp("firefox", argv);
  714. ok = execvp("konqueror", argv);
  715. ok = execvp("mozilla", argv);
  716. // use dPrintf instead of Con here since we're now in another process,
  717. dPrintf("WARNING: Platform::openWebBrowser: couldn't launch a web browser\n");
  718. _exit(-1);
  719. return false;
  720. }
  721. else
  722. {
  723. Con::printf("WARNING: Platform::openWebBrowser: forking problem");
  724. return false;
  725. }
  726. }
  727. void Platform::setMouseLock(bool locked)
  728. {
  729. // Not implemented
  730. }
  731. //-------------------------------------------------------------------------------
  732. void TimeManager::process()
  733. {
  734. U32 curTime = Platform::getRealMilliseconds();
  735. TimeEvent event;
  736. event.elapsedTime = curTime - lastTimeTick;
  737. if(event.elapsedTime > sgTimeManagerProcessInterval)
  738. {
  739. lastTimeTick = curTime;
  740. Game->postEvent(event);
  741. }
  742. }
  743. //------------------------------------------------------------------------------
  744. ConsoleFunction( getDesktopResolution, const char*, 1, 1,
  745. "getDesktopResolution()" )
  746. {
  747. if (!x86UNIXState->windowCreated())
  748. return "0 0 0";
  749. char buffer[256];
  750. char* returnString = Con::getReturnBuffer( dStrlen( buffer ) + 1 );
  751. dSprintf( buffer, sizeof( buffer ), "%d %d %d",
  752. x86UNIXState->getDesktopSize().x,
  753. x86UNIXState->getDesktopSize().y,
  754. x86UNIXState->getDesktopBpp() );
  755. dStrcpy( returnString, buffer );
  756. return( returnString );
  757. }
  758. //------------------------------------------------------------------------------
  759. int main(S32 argc, const char **argv)
  760. {
  761. // init platform state
  762. x86UNIXState = new x86UNIXPlatformState;
  763. // parse the command line for unix-specific params
  764. Vector<char *> newCommandLine;
  765. S32 returnVal = ParseCommandLine(argc, argv, newCommandLine);
  766. if (returnVal != 0)
  767. return returnVal;
  768. // init lastTimeTick for TimeManager::process()
  769. lastTimeTick = Platform::getRealMilliseconds();
  770. // init process control stuff
  771. ProcessControlInit();
  772. // check to see if X is running
  773. DetectWindowingSystem();
  774. Game->mainInitialize(argc, argv);
  775. // run the game
  776. while ( Game->isRunning() )
  777. {
  778. Game->mainLoop();
  779. }
  780. Game->mainShutdown();
  781. // dispose of command line
  782. for(U32 i = 0; i < newCommandLine.size(); i++)
  783. delete [] newCommandLine[i];
  784. // dispose of state
  785. delete x86UNIXState;
  786. return returnVal;
  787. }
  788. void Platform::setWindowTitle( const char* title )
  789. {
  790. #ifndef DEDICATED
  791. x86UNIXState->setWindowName(title);
  792. SDL_WM_SetCaption(x86UNIXState->getWindowName(), NULL);
  793. #endif
  794. }
  795. Resolution Video::getDesktopResolution()
  796. {
  797. Resolution Result;
  798. Result.h = x86UNIXState->getDesktopSize().x;
  799. Result.w = x86UNIXState->getDesktopSize().y;
  800. Result.bpp = x86UNIXState->getDesktopBpp();
  801. return Result;
  802. }