x86UNIXWindow.cc 29 KB

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