mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 13:01:29 -10:00
git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10468 387891d4-d844-0410-90c0-e4c51a9137d3
505 lines
11 KiB
C++
505 lines
11 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "io/key.h"
|
|
#include "palman/palman.h"
|
|
#include "io/mouse.h"
|
|
#include "osapi/outwnd.h"
|
|
#include "sound/sound.h"
|
|
#include "freespace2/freespaceresource.h"
|
|
#include "playerman/managepilot.h"
|
|
#include "io/joy.h"
|
|
#include "io/joy_ff.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "freespace2/freespace.h"
|
|
#include "osapi/osregistry.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "sound/voicerec.h"
|
|
#include "graphics/2d.h"
|
|
#include "cmdline/cmdline.h"
|
|
|
|
#ifdef __linux__
|
|
#include <execinfo.h>
|
|
#endif
|
|
|
|
#define THREADED // to use the proper set of macros
|
|
#include "osapi/osapi.h"
|
|
|
|
#include "SDL_syswm.h"
|
|
|
|
|
|
// used to be a THREADED define but only use multiple process threads if this is defined
|
|
// NOTE: may hang if set
|
|
//#define THREADED_PROCESS
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// PLATFORM SPECIFIC FUNCTION FOLLOWING
|
|
//
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
// Windows specific includes
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <io.h>
|
|
#include <winsock.h>
|
|
#include <direct.h>
|
|
|
|
// For FRED
|
|
void os_set_window_from_hwnd(HWND handle)
|
|
{
|
|
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
|
|
|
if (SDL_GL_LoadLibrary(NULL) < 0)
|
|
Error(LOCATION, "Failed to load OpenGL library: %s!", SDL_GetError());
|
|
|
|
SDL_Window* window = SDL_CreateWindowFrom((void*) handle);
|
|
|
|
os_set_window(window);
|
|
}
|
|
|
|
// go through all windows and try and find the one that matches the search string
|
|
BOOL __stdcall os_enum_windows( HWND hwnd, char * search_string )
|
|
{
|
|
char tmp[128];
|
|
int len;
|
|
|
|
len = GetWindowText( hwnd, tmp, 127 );
|
|
|
|
if ( len ) {
|
|
if ( strstr( tmp, search_string )) {
|
|
Os_debugger_running = 1; // found the search string!
|
|
return FALSE; // stop enumerating windows
|
|
}
|
|
}
|
|
|
|
return TRUE; // continue enumeration
|
|
}
|
|
|
|
// Fills in the Os_debugger_running with non-zero if debugger detected.
|
|
void os_check_debugger()
|
|
{
|
|
HMODULE hMod;
|
|
char search_string[256];
|
|
char myname[128];
|
|
int namelen;
|
|
char * p;
|
|
|
|
Os_debugger_running = 0; // Assume its not
|
|
|
|
// Find my EXE file name
|
|
hMod = GetModuleHandle(NULL);
|
|
if ( !hMod ) return;
|
|
namelen = GetModuleFileName( hMod, myname, 127 );
|
|
if ( namelen < 1 ) return;
|
|
|
|
// Strip off the .EXE
|
|
p = strstr( myname, ".exe" );
|
|
if (!p) return;
|
|
*p = '\0';
|
|
|
|
// Move p to point to first letter of EXE filename
|
|
while( (*p!='\\') && (*p!='/') && (*p!=':') )
|
|
p--;
|
|
p++;
|
|
if ( strlen(p) < 1 ) return;
|
|
|
|
// Build what the debugger's window title would be if the debugger is running...
|
|
sprintf( search_string, "[run] - %s -", p );
|
|
|
|
// ... and then search for it.
|
|
EnumWindows( (int (__stdcall *)(struct HWND__ *,long))os_enum_windows, (long)&search_string );
|
|
}
|
|
|
|
void os_set_process_affinity()
|
|
{
|
|
HANDLE pHandle = GetCurrentProcess();
|
|
DWORD pMaskProcess = 0, pMaskSystem = 0;
|
|
|
|
if ( GetProcessAffinityMask(pHandle, &pMaskProcess, &pMaskSystem) ) {
|
|
// only do this if we have at least 2 procs
|
|
if (pMaskProcess >= 3) {
|
|
// prefer running on the second processor by default
|
|
pMaskProcess = os_config_read_uint(NULL, "ProcessorAffinity", 2);
|
|
|
|
if (pMaskProcess > 0) {
|
|
SetProcessAffinityMask(pHandle, pMaskProcess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // WIN32
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI DEFINES/VARS
|
|
//
|
|
|
|
static SDL_Window* main_window = NULL;
|
|
|
|
// os-wide globals
|
|
static int fAppActive = 0;
|
|
static char szWinTitle[128];
|
|
static char szWinClass[128];
|
|
static int Os_inited = 0;
|
|
|
|
static SDL_mutex* Os_lock;
|
|
|
|
int Os_debugger_running = 0;
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FORWARD DECLARATIONS
|
|
//
|
|
|
|
// called at shutdown. Makes sure all thread processing terminates.
|
|
void os_deinit();
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FUNCTIONS
|
|
//
|
|
|
|
// detect home/base directory (placeholder for possible future Win32 userdir support, just returns current directory for now)
|
|
char Cur_path[MAX_PATH_LEN];
|
|
const char *detect_home(void)
|
|
{
|
|
#ifdef WIN32
|
|
if ( strlen(Cfile_root_dir) )
|
|
return Cfile_root_dir;
|
|
|
|
memset( Cur_path, 0, MAX_PATH_LEN );
|
|
GetCurrentDirectory( MAX_PATH_LEN-1, Cur_path );
|
|
|
|
return Cur_path;
|
|
#else
|
|
return (getenv("HOME"));
|
|
#endif
|
|
}
|
|
|
|
// initialization/shutdown functions -----------------------------------------------
|
|
|
|
// If app_name is NULL or ommited, then TITLE is used
|
|
// for the app name, which is where registry keys are stored.
|
|
void os_init(const char * wclass, const char * title, const char *app_name, const char *version_string )
|
|
{
|
|
// create default ini entries for the user
|
|
if (os_config_read_string(NULL, NOX("VideocardFs2open"), NULL) == NULL)
|
|
os_config_write_string(NULL, NOX("VideocardFs2open"), NOX("OGL -(640x480)x16 bit"));
|
|
|
|
os_init_registry_stuff(Osreg_company_name, title, version_string);
|
|
|
|
strcpy_s( szWinTitle, title );
|
|
strcpy_s( szWinClass, wclass );
|
|
|
|
Os_lock = SDL_CreateMutex();
|
|
|
|
mprintf((" Initializing SDL...\n"));
|
|
|
|
if (SDL_Init(0) < 0)
|
|
{
|
|
fprintf(stderr, "Couldn't init SDL: %s", SDL_GetError());
|
|
mprintf(("Couldn't init SDL: %s", SDL_GetError()));
|
|
|
|
exit(1);
|
|
return;
|
|
}
|
|
|
|
#ifdef FS2_VOICER
|
|
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); // We currently only need this for voice recognition
|
|
#endif
|
|
|
|
// initialized
|
|
Os_inited = 1;
|
|
|
|
#ifdef WIN32
|
|
// check to see if we're running under msdev
|
|
os_check_debugger();
|
|
|
|
// deal with processor affinity
|
|
os_set_process_affinity();
|
|
#endif // WIN32
|
|
|
|
atexit(os_deinit);
|
|
}
|
|
|
|
// set the main window title
|
|
void os_set_title( const char * title )
|
|
{
|
|
strcpy_s( szWinTitle, title );
|
|
|
|
SDL_SetWindowTitle(main_window, szWinTitle);
|
|
}
|
|
|
|
extern void gr_opengl_shutdown();
|
|
// call at program end
|
|
void os_cleanup()
|
|
{
|
|
gr_opengl_shutdown();
|
|
|
|
#ifndef NDEBUG
|
|
outwnd_close();
|
|
#endif
|
|
}
|
|
|
|
// window management -----------------------------------------------------------------
|
|
|
|
// Returns 1 if app is not the foreground app.
|
|
int os_foreground()
|
|
{
|
|
return fAppActive;
|
|
}
|
|
|
|
// Returns the handle to the main window
|
|
SDL_Window* os_get_window()
|
|
{
|
|
return main_window;
|
|
}
|
|
|
|
// Returns the handle to the main window
|
|
void os_set_window(SDL_Window* new_handle)
|
|
{
|
|
main_window = new_handle;
|
|
}
|
|
|
|
// process management -----------------------------------------------------------------
|
|
|
|
// Sleeps for n milliseconds or until app becomes active.
|
|
void os_sleep(uint ms)
|
|
{
|
|
#ifdef __APPLE__
|
|
// ewwww, I hate this!! SDL_Delay() is causing issues for us though and this
|
|
// basically matches Apple examples of the same thing. Same as SDL_Delay() but
|
|
// we aren't hitting up the system for anything during the process
|
|
uint then = SDL_GetTicks() + ms;
|
|
|
|
while (then > SDL_GetTicks());
|
|
#else
|
|
SDL_Delay(ms);
|
|
#endif
|
|
}
|
|
|
|
// Used to stop message processing
|
|
void os_suspend()
|
|
{
|
|
SDL_LockMutex( Os_lock );
|
|
}
|
|
|
|
// resume message processing
|
|
void os_resume()
|
|
{
|
|
SDL_UnlockMutex( Os_lock );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------------
|
|
// OSAPI FORWARD DECLARATIONS
|
|
//
|
|
|
|
// called at shutdown. Makes sure all thread processing terminates.
|
|
void os_deinit()
|
|
{
|
|
SDL_DestroyMutex(Os_lock);
|
|
|
|
SDL_Quit();
|
|
}
|
|
|
|
extern SCP_map<int, int> SDLtoFS2;
|
|
extern void joy_set_button_state(int button, int state);
|
|
extern void joy_set_hat_state(int position);
|
|
|
|
void os_poll()
|
|
{
|
|
SDL_Event event;
|
|
|
|
while (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_WINDOWEVENT: {
|
|
if (event.window.windowID == SDL_GetWindowID(os_get_window())) {
|
|
switch (event.window.event) {
|
|
case SDL_WINDOWEVENT_MINIMIZED:
|
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
{
|
|
if (fAppActive) {
|
|
if (!Cmdline_no_unfocus_pause) {
|
|
game_pause();
|
|
}
|
|
|
|
fAppActive = false;
|
|
}
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
|
case SDL_WINDOWEVENT_RESTORED:
|
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
{
|
|
if (!fAppActive) {
|
|
if (!Cmdline_no_unfocus_pause) {
|
|
game_unpause();
|
|
}
|
|
|
|
fAppActive = true;
|
|
}
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_CLOSE:
|
|
gameseq_post_event(GS_EVENT_QUIT_GAME);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Cmdline_no_unfocus_pause) {
|
|
gr_activate(fAppActive);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SDL_SYSWMEVENT:
|
|
#ifdef WIN32
|
|
#ifdef FS2_VOICER
|
|
switch(event.syswm.msg->msg.win.msg)
|
|
{
|
|
case WM_RECOEVENT:
|
|
if ( Game_mode & GM_IN_MISSION && Cmdline_voice_recognition)
|
|
{
|
|
VOICEREC_process_event( event.syswm.msg->msg.win.hwnd );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif // FS2_VOICER
|
|
#endif // WIN32
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
if (SDLtoFS2[event.key.keysym.scancode]) {
|
|
key_mark(SDLtoFS2[event.key.keysym.scancode], 1, 0);
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
if (SDLtoFS2[event.key.keysym.scancode]) {
|
|
key_mark(SDLtoFS2[event.key.keysym.scancode], 0, 0);
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
case SDL_MOUSEBUTTONUP:
|
|
if (event.button.button == SDL_BUTTON_LEFT)
|
|
mouse_mark_button(MOUSE_LEFT_BUTTON, event.button.state);
|
|
else if (event.button.button == SDL_BUTTON_MIDDLE)
|
|
mouse_mark_button(MOUSE_MIDDLE_BUTTON, event.button.state);
|
|
else if (event.button.button == SDL_BUTTON_RIGHT)
|
|
mouse_mark_button(MOUSE_RIGHT_BUTTON, event.button.state);
|
|
|
|
break;
|
|
|
|
case SDL_JOYHATMOTION:
|
|
joy_set_hat_state(event.jhat.value);
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
case SDL_JOYBUTTONUP:
|
|
if (event.jbutton.button < JOY_NUM_BUTTONS) {
|
|
joy_set_button_state(event.jbutton.button, event.jbutton.state);
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
mouse_event(event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void debug_int3(char *file, int line)
|
|
{
|
|
mprintf(("Int3(): From %s at line %d\n", file, line));
|
|
|
|
gr_activate(0);
|
|
|
|
|
|
#ifndef NDEBUG
|
|
// Try to get a backtrace on linux
|
|
|
|
# ifdef WIN32
|
|
# if defined(_MSC_VER) && _MSC_VER >= 1400
|
|
__debugbreak( );
|
|
# elif defined(_MSC_VER)
|
|
_asm int 3;
|
|
# elif defined __GNUC__
|
|
asm("int $3");
|
|
# else
|
|
# error debug_int3: unknown compiler
|
|
# endif
|
|
# elif defined(__linux__)
|
|
# define SIZE 1024
|
|
char **symbols;
|
|
int i, numstrings;
|
|
void *buffer[SIZE];
|
|
|
|
numstrings = backtrace(buffer, SIZE);
|
|
symbols = backtrace_symbols(buffer, numstrings);
|
|
|
|
if(symbols != NULL)
|
|
{
|
|
for(i = 0; i < numstrings; i++)
|
|
{
|
|
mprintf(("%s\n", symbols[i]));
|
|
}
|
|
}
|
|
free(symbols);
|
|
# endif
|
|
#endif
|
|
|
|
gr_activate(1);
|
|
// we have to call os_deinit() before abort() so we make sure that SDL gets
|
|
// closed out and we don't lose video/input control
|
|
os_deinit();
|
|
|
|
abort();
|
|
}
|
|
|
|
void SCP_Messagebox(MessageBoxType type, const char* message, const char* title)
|
|
{
|
|
int flags = 1;
|
|
|
|
switch (type)
|
|
{
|
|
case MESSAGEBOX_ERROR:
|
|
flags = SDL_MESSAGEBOX_ERROR;
|
|
if (title == NULL)
|
|
title = "Error";
|
|
break;
|
|
case MESSAGEBOX_INFORMATION:
|
|
flags = SDL_MESSAGEBOX_INFORMATION;
|
|
if (title == NULL)
|
|
title = "Information";
|
|
break;
|
|
case MESSAGEBOX_WARNING:
|
|
flags = SDL_MESSAGEBOX_WARNING;
|
|
if (title == NULL)
|
|
title = "Warning";
|
|
break;
|
|
default:
|
|
Int3();
|
|
title = ""; // Remove warning about unitialized variable
|
|
break;
|
|
}
|
|
|
|
SDL_ShowSimpleMessageBox(flags, title, message, os_get_window());
|
|
}
|