mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-09-27 08:54:30 +00:00
2e95c43bf2
Rather, use an address override prefix (0x67) though Intel Core optimization reference guide says to avoid LCP prefixes. In practise, impact on performance is measurably marginal on e.g. Speedometer tests.
703 lines
15 KiB
C++
Executable File
703 lines
15 KiB
C++
Executable File
/*
|
|
* main_windows.cpp - Startup code for Windows
|
|
*
|
|
* Basilisk II (C) 1997-2005 Christian Bauer
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "sysdeps.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
|
|
#include <SDL.h>
|
|
#include <SDL_mutex.h>
|
|
#include <SDL_thread.h>
|
|
|
|
#include <string>
|
|
using std::string;
|
|
|
|
#include "cpu_emulation.h"
|
|
#include "sys.h"
|
|
#include "rom_patches.h"
|
|
#include "xpram.h"
|
|
#include "timer.h"
|
|
#include "video.h"
|
|
#include "cdrom.h"
|
|
#include "emul_op.h"
|
|
#include "prefs.h"
|
|
#include "prefs_editor.h"
|
|
#include "macos_util.h"
|
|
#include "user_strings.h"
|
|
#include "version.h"
|
|
#include "main.h"
|
|
#include "vm_alloc.h"
|
|
#include "sigsegv.h"
|
|
#include "util_windows.h"
|
|
#include "kernel_windows.h"
|
|
|
|
#if USE_JIT
|
|
extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp
|
|
#endif
|
|
|
|
#ifdef ENABLE_MON
|
|
# include "mon.h"
|
|
#endif
|
|
|
|
#define DEBUG 0
|
|
#include "debug.h"
|
|
|
|
|
|
// Constants
|
|
const char ROM_FILE_NAME[] = "ROM";
|
|
const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area
|
|
|
|
|
|
// CPU and FPU type, addressing mode
|
|
int CPUType;
|
|
bool CPUIs68060;
|
|
int FPUType;
|
|
bool TwentyFourBitAddressing;
|
|
|
|
|
|
// Global variables
|
|
HANDLE emul_thread = NULL; // Handle of MacOS emulation thread (main thread)
|
|
|
|
static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
|
|
static bool xpram_thread_active = false; // Flag: XPRAM watchdog installed
|
|
static volatile bool xpram_thread_cancel = false; // Flag: Cancel XPRAM thread
|
|
static SDL_Thread *xpram_thread = NULL; // XPRAM watchdog
|
|
|
|
static bool tick_thread_active = false; // Flag: 60Hz thread installed
|
|
static volatile bool tick_thread_cancel = false; // Flag: Cancel 60Hz thread
|
|
static SDL_Thread *tick_thread; // 60Hz thread
|
|
|
|
static SDL_mutex *intflag_lock = NULL; // Mutex to protect InterruptFlags
|
|
#define LOCK_INTFLAGS SDL_LockMutex(intflag_lock)
|
|
#define UNLOCK_INTFLAGS SDL_UnlockMutex(intflag_lock)
|
|
|
|
DWORD win_os; // Windows OS id
|
|
DWORD win_os_major; // Windows OS version major
|
|
|
|
#if USE_SCRATCHMEM_SUBTERFUGE
|
|
uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes
|
|
#endif
|
|
|
|
#if REAL_ADDRESSING
|
|
static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
|
|
#endif
|
|
|
|
|
|
// Prototypes
|
|
static int xpram_func(void *arg);
|
|
static int tick_func(void *arg);
|
|
static void one_tick(...);
|
|
|
|
|
|
/*
|
|
* Ersatz functions
|
|
*/
|
|
|
|
extern "C" {
|
|
|
|
#ifndef HAVE_STRDUP
|
|
char *strdup(const char *s)
|
|
{
|
|
char *n = (char *)malloc(strlen(s) + 1);
|
|
strcpy(n, s);
|
|
return n;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Map memory that can be accessed from the Mac side
|
|
*/
|
|
|
|
void *vm_acquire_mac(size_t size)
|
|
{
|
|
return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT);
|
|
}
|
|
|
|
|
|
/*
|
|
* SIGSEGV handler
|
|
*/
|
|
|
|
static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
|
|
{
|
|
#if ENABLE_VOSF
|
|
// Handle screen fault
|
|
extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
|
|
if (Screen_fault_handler(fault_address, fault_instruction))
|
|
return SIGSEGV_RETURN_SUCCESS;
|
|
#endif
|
|
|
|
#ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
|
|
// Ignore writes to ROM
|
|
if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
|
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
|
|
|
|
// Ignore all other faults, if requested
|
|
if (PrefsFindBool("ignoresegv"))
|
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
|
|
#endif
|
|
|
|
return SIGSEGV_RETURN_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Dump state when everything went wrong after a SEGV
|
|
*/
|
|
|
|
static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
|
|
{
|
|
fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
|
|
if (fault_instruction != SIGSEGV_INVALID_PC)
|
|
fprintf(stderr, " [IP=%p]", fault_instruction);
|
|
fprintf(stderr, "\n");
|
|
uaecptr nextpc;
|
|
extern void m68k_dumpstate(uaecptr *nextpc);
|
|
m68k_dumpstate(&nextpc);
|
|
#if USE_JIT && JIT_DEBUG
|
|
extern void compiler_dumpstate(void);
|
|
compiler_dumpstate();
|
|
#endif
|
|
VideoQuitFullScreen();
|
|
#ifdef ENABLE_MON
|
|
char *arg[4] = {"mon", "-m", "-r", NULL};
|
|
mon(3, arg);
|
|
QuitEmulator();
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Main program
|
|
*/
|
|
|
|
static void usage(const char *prg_name)
|
|
{
|
|
printf(
|
|
"Usage: %s [OPTION...]\n"
|
|
"\nUnix options:\n"
|
|
" --config FILE\n read/write configuration from/to FILE\n"
|
|
" --display STRING\n X display to use\n"
|
|
" --break ADDRESS\n set ROM breakpoint\n"
|
|
" --rominfo\n dump ROM information\n", prg_name
|
|
);
|
|
LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
|
|
PrefsPrintUsage();
|
|
exit(0);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char str[256];
|
|
bool cd_boot = false;
|
|
|
|
// Initialize variables
|
|
RAMBaseHost = NULL;
|
|
ROMBaseHost = NULL;
|
|
srand(time(NULL));
|
|
tzset();
|
|
|
|
// Print some info
|
|
printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
|
|
printf(" %s\n", GetString(STR_ABOUT_TEXT2));
|
|
|
|
// Parse command line arguments
|
|
for (int i=1; i<argc; i++) {
|
|
if (strcmp(argv[i], "--help") == 0) {
|
|
usage(argv[0]);
|
|
} else if (strcmp(argv[i], "--break") == 0) {
|
|
argv[i++] = NULL;
|
|
if (i < argc) {
|
|
ROMBreakpoint = strtol(argv[i], NULL, 0);
|
|
argv[i] = NULL;
|
|
}
|
|
} else if (strcmp(argv[i], "--config") == 0) {
|
|
argv[i++] = NULL;
|
|
if (i < argc) {
|
|
extern string UserPrefsPath; // from prefs_unix.cpp
|
|
UserPrefsPath = argv[i];
|
|
argv[i] = NULL;
|
|
}
|
|
} else if (strcmp(argv[i], "--rominfo") == 0) {
|
|
argv[i] = NULL;
|
|
PrintROMInfo = true;
|
|
} else if (strcmp(argv[i], "--cdboot") == 0) {
|
|
argv[i] = NULL;
|
|
cd_boot = true;
|
|
}
|
|
}
|
|
|
|
// Remove processed arguments
|
|
for (int i=1; i<argc; i++) {
|
|
int k;
|
|
for (k=i; k<argc; k++)
|
|
if (argv[k] != NULL)
|
|
break;
|
|
if (k > i) {
|
|
k -= i;
|
|
for (int j=i+k; j<argc; j++)
|
|
argv[j-k] = argv[j];
|
|
argc -= k;
|
|
}
|
|
}
|
|
|
|
// Read preferences
|
|
PrefsInit(argc, argv);
|
|
|
|
// Boot MacOS from CD-ROM?
|
|
if (cd_boot)
|
|
PrefsReplaceInt32("bootdriver", CDROMRefNum);
|
|
|
|
// Any command line arguments left?
|
|
for (int i=1; i<argc; i++) {
|
|
if (argv[i][0] == '-') {
|
|
fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
|
|
usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
// Check we are using a Windows NT kernel >= 4.0
|
|
OSVERSIONINFO osvi;
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osvi)) {
|
|
ErrorAlert("Could not determine OS type");
|
|
QuitEmulator();
|
|
}
|
|
win_os = osvi.dwPlatformId;
|
|
win_os_major = osvi.dwMajorVersion;
|
|
if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
|
|
ErrorAlert(STR_NO_WIN32_NT_4);
|
|
QuitEmulator();
|
|
}
|
|
|
|
// Check that drivers are installed
|
|
if (!check_drivers())
|
|
QuitEmulator();
|
|
|
|
// Load win32 libraries
|
|
KernelInit();
|
|
|
|
// FIXME: default to DIB driver
|
|
if (getenv("SDL_VIDEODRIVER") == NULL)
|
|
putenv("SDL_VIDEODRIVER=windib");
|
|
|
|
// Initialize SDL system
|
|
int sdl_flags = 0;
|
|
#ifdef USE_SDL_VIDEO
|
|
sdl_flags |= SDL_INIT_VIDEO;
|
|
#endif
|
|
#ifdef USE_SDL_AUDIO
|
|
sdl_flags |= SDL_INIT_AUDIO;
|
|
#endif
|
|
assert(sdl_flags != 0);
|
|
if (SDL_Init(sdl_flags) == -1) {
|
|
char str[256];
|
|
sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
|
|
ErrorAlert(str);
|
|
QuitEmulator();
|
|
}
|
|
atexit(SDL_Quit);
|
|
|
|
// Init system routines
|
|
SysInit();
|
|
|
|
// Show preferences editor
|
|
if (!PrefsFindBool("nogui"))
|
|
if (!PrefsEditor())
|
|
QuitEmulator();
|
|
|
|
// Install the handler for SIGSEGV
|
|
if (!sigsegv_install_handler(sigsegv_handler)) {
|
|
sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
|
|
ErrorAlert(str);
|
|
QuitEmulator();
|
|
}
|
|
|
|
// Register dump state function when we got mad after a segfault
|
|
sigsegv_set_dump_state(sigsegv_dump_state);
|
|
|
|
// Read RAM size
|
|
RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
|
|
if (RAMSize < 1024*1024) {
|
|
WarningAlert(GetString(STR_SMALL_RAM_WARN));
|
|
RAMSize = 1024*1024;
|
|
}
|
|
|
|
// Initialize VM system
|
|
vm_init();
|
|
|
|
// Create areas for Mac RAM and ROM
|
|
RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize);
|
|
ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000);
|
|
if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
|
|
ErrorAlert(STR_NO_MEM_ERR);
|
|
QuitEmulator();
|
|
}
|
|
|
|
#if USE_SCRATCHMEM_SUBTERFUGE
|
|
// Allocate scratch memory
|
|
ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
|
|
if (ScratchMem == VM_MAP_FAILED) {
|
|
ErrorAlert(STR_NO_MEM_ERR);
|
|
QuitEmulator();
|
|
}
|
|
ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
|
|
#endif
|
|
|
|
#if DIRECT_ADDRESSING
|
|
// RAMBaseMac shall always be zero
|
|
MEMBaseDiff = (uintptr)RAMBaseHost;
|
|
RAMBaseMac = 0;
|
|
ROMBaseMac = Host2MacAddr(ROMBaseHost);
|
|
#endif
|
|
D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
|
|
D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
|
|
|
|
// Get rom file path from preferences
|
|
const char *rom_path = PrefsFindString("rom");
|
|
|
|
// Load Mac ROM
|
|
HANDLE rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME,
|
|
GENERIC_READ,
|
|
0, NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (rom_fh == INVALID_HANDLE_VALUE) {
|
|
ErrorAlert(STR_NO_ROM_FILE_ERR);
|
|
QuitEmulator();
|
|
}
|
|
printf(GetString(STR_READING_ROM_FILE));
|
|
ROMSize = GetFileSize(rom_fh, NULL);
|
|
if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
|
|
ErrorAlert(STR_ROM_SIZE_ERR);
|
|
CloseHandle(rom_fh);
|
|
QuitEmulator();
|
|
}
|
|
DWORD bytes_read;
|
|
if (ReadFile(rom_fh, ROMBaseHost, ROMSize, &bytes_read, NULL) == 0 || bytes_read != ROMSize) {
|
|
ErrorAlert(STR_ROM_FILE_READ_ERR);
|
|
CloseHandle(rom_fh);
|
|
QuitEmulator();
|
|
}
|
|
|
|
// Initialize native timers
|
|
timer_init();
|
|
|
|
// Initialize everything
|
|
if (!InitAll())
|
|
QuitEmulator();
|
|
D(bug("Initialization complete\n"));
|
|
|
|
// Get handle of main thread
|
|
emul_thread = GetCurrentThread();
|
|
|
|
// SDL threads available, start 60Hz thread
|
|
tick_thread_active = ((tick_thread = SDL_CreateThread(tick_func, NULL)) != NULL);
|
|
if (!tick_thread_active) {
|
|
sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
|
|
ErrorAlert(str);
|
|
QuitEmulator();
|
|
}
|
|
D(bug("60Hz thread started\n"));
|
|
|
|
// Start XPRAM watchdog thread
|
|
memcpy(last_xpram, XPRAM, XPRAM_SIZE);
|
|
xpram_thread_active = ((xpram_thread = SDL_CreateThread(xpram_func, NULL)) != NULL);
|
|
D(bug("XPRAM thread started\n"));
|
|
|
|
// Start 68k and jump to ROM boot routine
|
|
D(bug("Starting emulation...\n"));
|
|
Start680x0();
|
|
|
|
QuitEmulator();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Quit emulator
|
|
*/
|
|
|
|
void QuitEmulator(void)
|
|
{
|
|
D(bug("QuitEmulator\n"));
|
|
|
|
// Exit 680x0 emulation
|
|
Exit680x0();
|
|
|
|
// Stop 60Hz thread
|
|
if (tick_thread_active) {
|
|
tick_thread_cancel = true;
|
|
SDL_WaitThread(tick_thread, NULL);
|
|
}
|
|
|
|
// Stop XPRAM watchdog thread
|
|
if (xpram_thread_active) {
|
|
xpram_thread_cancel = true;
|
|
SDL_WaitThread(xpram_thread, NULL);
|
|
}
|
|
|
|
// Deinitialize everything
|
|
ExitAll();
|
|
|
|
// Free ROM/RAM areas
|
|
if (RAMBaseHost != VM_MAP_FAILED) {
|
|
vm_release(RAMBaseHost, RAMSize);
|
|
RAMBaseHost = NULL;
|
|
}
|
|
if (ROMBaseHost != VM_MAP_FAILED) {
|
|
vm_release(ROMBaseHost, 0x100000);
|
|
ROMBaseHost = NULL;
|
|
}
|
|
|
|
#if USE_SCRATCHMEM_SUBTERFUGE
|
|
// Delete scratch memory area
|
|
if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
|
|
vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
|
|
ScratchMem = NULL;
|
|
}
|
|
#endif
|
|
|
|
// Exit VM wrappers
|
|
vm_exit();
|
|
|
|
// Exit system routines
|
|
SysExit();
|
|
|
|
// Exit preferences
|
|
PrefsExit();
|
|
|
|
// Release win32 libraries
|
|
KernelExit();
|
|
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Code was patched, flush caches if neccessary (i.e. when using a real 680x0
|
|
* or a dynamically recompiling emulator)
|
|
*/
|
|
|
|
void FlushCodeCache(void *start, uint32 size)
|
|
{
|
|
#if USE_JIT
|
|
if (UseJIT)
|
|
flush_icache_range((uint8 *)start, size);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Mutexes
|
|
*/
|
|
|
|
struct B2_mutex {
|
|
B2_mutex() { m = SDL_CreateMutex(); }
|
|
~B2_mutex() { if (m) SDL_DestroyMutex(m); }
|
|
SDL_mutex *m;
|
|
};
|
|
|
|
B2_mutex *B2_create_mutex(void)
|
|
{
|
|
return new B2_mutex;
|
|
}
|
|
|
|
void B2_lock_mutex(B2_mutex *mutex)
|
|
{
|
|
if (mutex)
|
|
SDL_LockMutex(mutex->m);
|
|
}
|
|
|
|
void B2_unlock_mutex(B2_mutex *mutex)
|
|
{
|
|
if (mutex)
|
|
SDL_UnlockMutex(mutex->m);
|
|
}
|
|
|
|
void B2_delete_mutex(B2_mutex *mutex)
|
|
{
|
|
delete mutex;
|
|
}
|
|
|
|
|
|
/*
|
|
* Interrupt flags (must be handled atomically!)
|
|
*/
|
|
|
|
uint32 InterruptFlags = 0;
|
|
|
|
void SetInterruptFlag(uint32 flag)
|
|
{
|
|
LOCK_INTFLAGS;
|
|
InterruptFlags |= flag;
|
|
UNLOCK_INTFLAGS;
|
|
}
|
|
|
|
void ClearInterruptFlag(uint32 flag)
|
|
{
|
|
LOCK_INTFLAGS;
|
|
InterruptFlags &= ~flag;
|
|
UNLOCK_INTFLAGS;
|
|
}
|
|
|
|
|
|
/*
|
|
* XPRAM watchdog thread (saves XPRAM every minute)
|
|
*/
|
|
|
|
static void xpram_watchdog(void)
|
|
{
|
|
if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
|
|
memcpy(last_xpram, XPRAM, XPRAM_SIZE);
|
|
SaveXPRAM();
|
|
}
|
|
}
|
|
|
|
static int xpram_func(void *arg)
|
|
{
|
|
while (!xpram_thread_cancel) {
|
|
for (int i=0; i<60 && !xpram_thread_cancel; i++)
|
|
Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
|
|
xpram_watchdog();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* 60Hz thread (really 60.15Hz)
|
|
*/
|
|
|
|
static void one_second(void)
|
|
{
|
|
// Pseudo Mac 1Hz interrupt, update local time
|
|
WriteMacInt32(0x20c, TimerDateTime());
|
|
|
|
SetInterruptFlag(INTFLAG_1HZ);
|
|
TriggerInterrupt();
|
|
}
|
|
|
|
static void one_tick(...)
|
|
{
|
|
static int tick_counter = 0;
|
|
if (++tick_counter > 60) {
|
|
tick_counter = 0;
|
|
one_second();
|
|
}
|
|
|
|
// Trigger 60Hz interrupt
|
|
if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
|
|
SetInterruptFlag(INTFLAG_60HZ);
|
|
TriggerInterrupt();
|
|
}
|
|
}
|
|
|
|
static int tick_func(void *arg)
|
|
{
|
|
uint64 start = GetTicks_usec();
|
|
int64 ticks = 0;
|
|
uint64 next = GetTicks_usec();
|
|
while (!tick_thread_cancel) {
|
|
one_tick();
|
|
next += 16625;
|
|
int64 delay = next - GetTicks_usec();
|
|
if (delay > 0)
|
|
Delay_usec(delay);
|
|
else if (delay < -16625)
|
|
next = GetTicks_usec();
|
|
ticks++;
|
|
}
|
|
uint64 end = GetTicks_usec();
|
|
D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get the main window handle
|
|
*/
|
|
|
|
#ifdef USE_SDL_VIDEO
|
|
#include <SDL_syswm.h>
|
|
HWND GetMainWindowHandle(void)
|
|
{
|
|
SDL_SysWMinfo wmInfo;
|
|
SDL_VERSION(&wmInfo.version);
|
|
return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Display alert
|
|
*/
|
|
|
|
static void display_alert(int title_id, const char *text, int flags)
|
|
{
|
|
HWND hMainWnd = GetMainWindowHandle();
|
|
MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
|
|
}
|
|
|
|
|
|
/*
|
|
* Display error alert
|
|
*/
|
|
|
|
void ErrorAlert(const char *text)
|
|
{
|
|
if (PrefsFindBool("nogui"))
|
|
return;
|
|
|
|
VideoQuitFullScreen();
|
|
display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
|
|
}
|
|
|
|
|
|
/*
|
|
* Display warning alert
|
|
*/
|
|
|
|
void WarningAlert(const char *text)
|
|
{
|
|
if (PrefsFindBool("nogui"))
|
|
return;
|
|
|
|
display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
|
|
}
|
|
|
|
|
|
/*
|
|
* Display choice alert
|
|
*/
|
|
|
|
bool ChoiceAlert(const char *text, const char *pos, const char *neg)
|
|
{
|
|
printf(GetString(STR_SHELL_WARNING_PREFIX), text);
|
|
return false; //!!
|
|
}
|