sys_win.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // sys_win.h
  16. #include "quakedef.h"
  17. #include "winquake.h"
  18. #include "resource.h"
  19. #include "errno.h"
  20. #include "fcntl.h"
  21. #include <limits.h>
  22. #define MINIMUM_WIN_MEMORY 0x0c00000
  23. #define MAXIMUM_WIN_MEMORY 0x1000000
  24. #define PAUSE_SLEEP 50 // sleep time on pause or minimization
  25. #define NOT_FOCUS_SLEEP 20 // sleep time when not focus
  26. int starttime;
  27. qboolean ActiveApp, Minimized;
  28. qboolean WinNT;
  29. HWND hwnd_dialog; // startup dialog box
  30. static double pfreq;
  31. static double curtime = 0.0;
  32. static double lastcurtime = 0.0;
  33. static int lowshift;
  34. static HANDLE hinput, houtput;
  35. HANDLE qwclsemaphore;
  36. static HANDLE tevent;
  37. void Sys_InitFloatTime (void);
  38. void MaskExceptions (void);
  39. void Sys_PopFPCW (void);
  40. void Sys_PushFPCW_SetHigh (void);
  41. void Sys_DebugLog(char *file, char *fmt, ...)
  42. {
  43. va_list argptr;
  44. static char data[1024];
  45. int fd;
  46. va_start(argptr, fmt);
  47. vsprintf(data, fmt, argptr);
  48. va_end(argptr);
  49. fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
  50. write(fd, data, strlen(data));
  51. close(fd);
  52. };
  53. /*
  54. ===============================================================================
  55. FILE IO
  56. ===============================================================================
  57. */
  58. /*
  59. ================
  60. filelength
  61. ================
  62. */
  63. int filelength (FILE *f)
  64. {
  65. int pos;
  66. int end;
  67. pos = ftell (f);
  68. fseek (f, 0, SEEK_END);
  69. end = ftell (f);
  70. fseek (f, pos, SEEK_SET);
  71. return end;
  72. }
  73. int Sys_FileTime (char *path)
  74. {
  75. FILE *f;
  76. int t, retval;
  77. t = VID_ForceUnlockedAndReturnState ();
  78. f = fopen(path, "rb");
  79. if (f)
  80. {
  81. fclose(f);
  82. retval = 1;
  83. }
  84. else
  85. {
  86. retval = -1;
  87. }
  88. VID_ForceLockState (t);
  89. return retval;
  90. }
  91. void Sys_mkdir (char *path)
  92. {
  93. _mkdir (path);
  94. }
  95. /*
  96. ===============================================================================
  97. SYSTEM IO
  98. ===============================================================================
  99. */
  100. /*
  101. ================
  102. Sys_MakeCodeWriteable
  103. ================
  104. */
  105. void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
  106. {
  107. DWORD flOldProtect;
  108. //@@@ copy on write or just read-write?
  109. if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
  110. Sys_Error("Protection change failed\n");
  111. }
  112. /*
  113. ================
  114. Sys_Init
  115. ================
  116. */
  117. void Sys_Init (void)
  118. {
  119. LARGE_INTEGER PerformanceFreq;
  120. unsigned int lowpart, highpart;
  121. OSVERSIONINFO vinfo;
  122. #ifndef SERVERONLY
  123. // allocate a named semaphore on the client so the
  124. // front end can tell if it is alive
  125. // mutex will fail if semephore allready exists
  126. qwclsemaphore = CreateMutex(
  127. NULL, /* Security attributes */
  128. 0, /* owner */
  129. "qwcl"); /* Semaphore name */
  130. if (!qwclsemaphore)
  131. Sys_Error ("QWCL is already running on this system");
  132. CloseHandle (qwclsemaphore);
  133. qwclsemaphore = CreateSemaphore(
  134. NULL, /* Security attributes */
  135. 0, /* Initial count */
  136. 1, /* Maximum count */
  137. "qwcl"); /* Semaphore name */
  138. #endif
  139. MaskExceptions ();
  140. Sys_SetFPCW ();
  141. #if 0
  142. if (!QueryPerformanceFrequency (&PerformanceFreq))
  143. Sys_Error ("No hardware timer available");
  144. // get 32 out of the 64 time bits such that we have around
  145. // 1 microsecond resolution
  146. lowpart = (unsigned int)PerformanceFreq.LowPart;
  147. highpart = (unsigned int)PerformanceFreq.HighPart;
  148. lowshift = 0;
  149. while (highpart || (lowpart > 2000000.0))
  150. {
  151. lowshift++;
  152. lowpart >>= 1;
  153. lowpart |= (highpart & 1) << 31;
  154. highpart >>= 1;
  155. }
  156. pfreq = 1.0 / (double)lowpart;
  157. Sys_InitFloatTime ();
  158. #endif
  159. // make sure the timer is high precision, otherwise
  160. // NT gets 18ms resolution
  161. timeBeginPeriod( 1 );
  162. vinfo.dwOSVersionInfoSize = sizeof(vinfo);
  163. if (!GetVersionEx (&vinfo))
  164. Sys_Error ("Couldn't get OS info");
  165. if ((vinfo.dwMajorVersion < 4) ||
  166. (vinfo.dwPlatformId == VER_PLATFORM_WIN32s))
  167. {
  168. Sys_Error ("QuakeWorld requires at least Win95 or NT 4.0");
  169. }
  170. if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  171. WinNT = true;
  172. else
  173. WinNT = false;
  174. }
  175. void Sys_Error (char *error, ...)
  176. {
  177. va_list argptr;
  178. char text[1024], text2[1024];
  179. DWORD dummy;
  180. Host_Shutdown ();
  181. va_start (argptr, error);
  182. vsprintf (text, error, argptr);
  183. va_end (argptr);
  184. MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
  185. #ifndef SERVERONLY
  186. CloseHandle (qwclsemaphore);
  187. #endif
  188. exit (1);
  189. }
  190. void Sys_Printf (char *fmt, ...)
  191. {
  192. va_list argptr;
  193. char text[1024];
  194. DWORD dummy;
  195. va_start (argptr,fmt);
  196. vprintf (fmt, argptr);
  197. va_end (argptr);
  198. }
  199. void Sys_Quit (void)
  200. {
  201. VID_ForceUnlockedAndReturnState ();
  202. Host_Shutdown();
  203. #ifndef SERVERONLY
  204. if (tevent)
  205. CloseHandle (tevent);
  206. if (qwclsemaphore)
  207. CloseHandle (qwclsemaphore);
  208. #endif
  209. exit (0);
  210. }
  211. #if 0
  212. /*
  213. ================
  214. Sys_DoubleTime
  215. ================
  216. */
  217. double Sys_DoubleTime (void)
  218. {
  219. static int sametimecount;
  220. static unsigned int oldtime;
  221. static int first = 1;
  222. LARGE_INTEGER PerformanceCount;
  223. unsigned int temp, t2;
  224. double time;
  225. Sys_PushFPCW_SetHigh ();
  226. QueryPerformanceCounter (&PerformanceCount);
  227. temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) |
  228. ((unsigned int)PerformanceCount.HighPart << (32 - lowshift));
  229. if (first)
  230. {
  231. oldtime = temp;
  232. first = 0;
  233. }
  234. else
  235. {
  236. // check for turnover or backward time
  237. if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000))
  238. {
  239. oldtime = temp; // so we can't get stuck
  240. }
  241. else
  242. {
  243. t2 = temp - oldtime;
  244. time = (double)t2 * pfreq;
  245. oldtime = temp;
  246. curtime += time;
  247. if (curtime == lastcurtime)
  248. {
  249. sametimecount++;
  250. if (sametimecount > 100000)
  251. {
  252. curtime += 1.0;
  253. sametimecount = 0;
  254. }
  255. }
  256. else
  257. {
  258. sametimecount = 0;
  259. }
  260. lastcurtime = curtime;
  261. }
  262. }
  263. Sys_PopFPCW ();
  264. return curtime;
  265. }
  266. /*
  267. ================
  268. Sys_InitFloatTime
  269. ================
  270. */
  271. void Sys_InitFloatTime (void)
  272. {
  273. int j;
  274. Sys_DoubleTime ();
  275. j = COM_CheckParm("-starttime");
  276. if (j)
  277. {
  278. curtime = (double) (Q_atof(com_argv[j+1]));
  279. }
  280. else
  281. {
  282. curtime = 0.0;
  283. }
  284. lastcurtime = curtime;
  285. }
  286. #endif
  287. double Sys_DoubleTime (void)
  288. {
  289. static DWORD starttime;
  290. static qboolean first = true;
  291. DWORD now;
  292. double t;
  293. now = timeGetTime();
  294. if (first) {
  295. first = false;
  296. starttime = now;
  297. return 0.0;
  298. }
  299. if (now < starttime) // wrapped?
  300. return (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
  301. if (now - starttime == 0)
  302. return 0.0;
  303. return (now - starttime) / 1000.0;
  304. }
  305. char *Sys_ConsoleInput (void)
  306. {
  307. static char text[256];
  308. static int len;
  309. INPUT_RECORD recs[1024];
  310. int count;
  311. int i, dummy;
  312. int ch, numread, numevents;
  313. HANDLE th;
  314. char *clipText, *textCopied;
  315. for ( ;; )
  316. {
  317. if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
  318. Sys_Error ("Error getting # of console events");
  319. if (numevents <= 0)
  320. break;
  321. if (!ReadConsoleInput(hinput, recs, 1, &numread))
  322. Sys_Error ("Error reading console input");
  323. if (numread != 1)
  324. Sys_Error ("Couldn't read console input");
  325. if (recs[0].EventType == KEY_EVENT)
  326. {
  327. if (!recs[0].Event.KeyEvent.bKeyDown)
  328. {
  329. ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
  330. switch (ch)
  331. {
  332. case '\r':
  333. WriteFile(houtput, "\r\n", 2, &dummy, NULL);
  334. if (len)
  335. {
  336. text[len] = 0;
  337. len = 0;
  338. return text;
  339. }
  340. break;
  341. case '\b':
  342. WriteFile(houtput, "\b \b", 3, &dummy, NULL);
  343. if (len)
  344. {
  345. len--;
  346. putch('\b');
  347. }
  348. break;
  349. default:
  350. Con_Printf("Stupid: %d\n", recs[0].Event.KeyEvent.dwControlKeyState);
  351. if (((ch=='V' || ch=='v') && (recs[0].Event.KeyEvent.dwControlKeyState &
  352. (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) || ((recs[0].Event.KeyEvent.dwControlKeyState
  353. & SHIFT_PRESSED) && (recs[0].Event.KeyEvent.wVirtualKeyCode
  354. ==VK_INSERT))) {
  355. if (OpenClipboard(NULL)) {
  356. th = GetClipboardData(CF_TEXT);
  357. if (th) {
  358. clipText = GlobalLock(th);
  359. if (clipText) {
  360. textCopied = malloc(GlobalSize(th)+1);
  361. strcpy(textCopied, clipText);
  362. /* Substitutes a NULL for every token */strtok(textCopied, "\n\r\b");
  363. i = strlen(textCopied);
  364. if (i+len>=256)
  365. i=256-len;
  366. if (i>0) {
  367. textCopied[i]=0;
  368. text[len]=0;
  369. strcat(text, textCopied);
  370. len+=dummy;
  371. WriteFile(houtput, textCopied, i, &dummy, NULL);
  372. }
  373. free(textCopied);
  374. }
  375. GlobalUnlock(th);
  376. }
  377. CloseClipboard();
  378. }
  379. } else if (ch >= ' ')
  380. {
  381. WriteFile(houtput, &ch, 1, &dummy, NULL);
  382. text[len] = ch;
  383. len = (len + 1) & 0xff;
  384. }
  385. break;
  386. }
  387. }
  388. }
  389. }
  390. return NULL;
  391. }
  392. void Sys_Sleep (void)
  393. {
  394. }
  395. void Sys_SendKeyEvents (void)
  396. {
  397. MSG msg;
  398. while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  399. {
  400. // we always update if there are any event, even if we're paused
  401. scr_skipupdate = 0;
  402. if (!GetMessage (&msg, NULL, 0, 0))
  403. Sys_Quit ();
  404. TranslateMessage (&msg);
  405. DispatchMessage (&msg);
  406. }
  407. }
  408. /*
  409. ==============================================================================
  410. WINDOWS CRAP
  411. ==============================================================================
  412. */
  413. /*
  414. ==================
  415. WinMain
  416. ==================
  417. */
  418. void SleepUntilInput (int time)
  419. {
  420. MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT);
  421. }
  422. /*
  423. ==================
  424. WinMain
  425. ==================
  426. */
  427. HINSTANCE global_hInstance;
  428. int global_nCmdShow;
  429. char *argv[MAX_NUM_ARGVS];
  430. static char *empty_string = "";
  431. HWND hwnd_dialog;
  432. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  433. {
  434. MSG msg;
  435. quakeparms_t parms;
  436. double time, oldtime, newtime;
  437. MEMORYSTATUS lpBuffer;
  438. static char cwd[1024];
  439. int t;
  440. RECT rect;
  441. /* previous instances do not exist in Win32 */
  442. if (hPrevInstance)
  443. return 0;
  444. global_hInstance = hInstance;
  445. global_nCmdShow = nCmdShow;
  446. lpBuffer.dwLength = sizeof(MEMORYSTATUS);
  447. GlobalMemoryStatus (&lpBuffer);
  448. if (!GetCurrentDirectory (sizeof(cwd), cwd))
  449. Sys_Error ("Couldn't determine current directory");
  450. if (cwd[Q_strlen(cwd)-1] == '/')
  451. cwd[Q_strlen(cwd)-1] = 0;
  452. parms.basedir = cwd;
  453. parms.cachedir = NULL;
  454. parms.argc = 1;
  455. argv[0] = empty_string;
  456. while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
  457. {
  458. while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
  459. lpCmdLine++;
  460. if (*lpCmdLine)
  461. {
  462. argv[parms.argc] = lpCmdLine;
  463. parms.argc++;
  464. while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
  465. lpCmdLine++;
  466. if (*lpCmdLine)
  467. {
  468. *lpCmdLine = 0;
  469. lpCmdLine++;
  470. }
  471. }
  472. }
  473. parms.argv = argv;
  474. COM_InitArgv (parms.argc, parms.argv);
  475. parms.argc = com_argc;
  476. parms.argv = com_argv;
  477. hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
  478. if (hwnd_dialog)
  479. {
  480. if (GetWindowRect (hwnd_dialog, &rect))
  481. {
  482. if (rect.left > (rect.top * 2))
  483. {
  484. SetWindowPos (hwnd_dialog, 0,
  485. (rect.left / 2) - ((rect.right - rect.left) / 2),
  486. rect.top, 0, 0,
  487. SWP_NOZORDER | SWP_NOSIZE);
  488. }
  489. }
  490. ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
  491. UpdateWindow (hwnd_dialog);
  492. SetForegroundWindow (hwnd_dialog);
  493. }
  494. // take the greater of all the available memory or half the total memory,
  495. // but at least 8 Mb and no more than 16 Mb, unless they explicitly
  496. // request otherwise
  497. parms.memsize = lpBuffer.dwAvailPhys;
  498. if (parms.memsize < MINIMUM_WIN_MEMORY)
  499. parms.memsize = MINIMUM_WIN_MEMORY;
  500. if (parms.memsize < (lpBuffer.dwTotalPhys >> 1))
  501. parms.memsize = lpBuffer.dwTotalPhys >> 1;
  502. if (parms.memsize > MAXIMUM_WIN_MEMORY)
  503. parms.memsize = MAXIMUM_WIN_MEMORY;
  504. if (COM_CheckParm ("-heapsize"))
  505. {
  506. t = COM_CheckParm("-heapsize") + 1;
  507. if (t < com_argc)
  508. parms.memsize = Q_atoi (com_argv[t]) * 1024;
  509. }
  510. parms.membase = malloc (parms.memsize);
  511. if (!parms.membase)
  512. Sys_Error ("Not enough memory free; check disk space\n");
  513. tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
  514. if (!tevent)
  515. Sys_Error ("Couldn't create event");
  516. Sys_Init ();
  517. // because sound is off until we become active
  518. S_BlockSound ();
  519. Sys_Printf ("Host_Init\n");
  520. Host_Init (&parms);
  521. oldtime = Sys_DoubleTime ();
  522. /* main window message loop */
  523. while (1)
  524. {
  525. // yield the CPU for a little while when paused, minimized, or not the focus
  526. if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing)
  527. {
  528. SleepUntilInput (PAUSE_SLEEP);
  529. scr_skipupdate = 1; // no point in bothering to draw
  530. }
  531. else if (!ActiveApp && !DDActive)
  532. {
  533. SleepUntilInput (NOT_FOCUS_SLEEP);
  534. }
  535. newtime = Sys_DoubleTime ();
  536. time = newtime - oldtime;
  537. Host_Frame (time);
  538. oldtime = newtime;
  539. }
  540. /* return success of application */
  541. return TRUE;
  542. }