DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/gui/sdlmain.cpp
00001 
00011 /*
00012  *  Copyright (C) 2002-2013  The DOSBox Team
00013  *
00014  *  This program is free software; you can redistribute it and/or modify
00015  *  it under the terms of the GNU General Public License as published by
00016  *  the Free Software Foundation; either version 2 of the License, or
00017  *  (at your option) any later version.
00018  *
00019  *  This program is distributed in the hope that it will be useful,
00020  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  *  GNU General Public License for more details.
00023  *
00024  *  You should have received a copy of the GNU General Public License
00025  *  along with this program; if not, write to the Free Software
00026  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00027  */
00028 
00029 #ifdef WIN32
00030 # ifndef WIN32_LEAN_AND_MEAN
00031 #  define WIN32_LEAN_AND_MEAN
00032 # endif
00033 #endif
00034 
00035 #ifdef OS2
00036 # define INCL_DOS
00037 # define INCL_WIN
00038 #endif
00039 
00040 bool OpenGL_using(void);
00041 void GFX_OpenGLRedrawScreen(void);
00042 
00043 #ifndef _GNU_SOURCE
00044 # define _GNU_SOURCE
00045 #endif
00046 
00047 #include <stdlib.h>
00048 #include <string.h>
00049 #include <stdio.h>
00050 #include <unistd.h>
00051 #include <assert.h>
00052 #include <stdarg.h>
00053 #include <sys/types.h>
00054 #include <algorithm> // std::transform
00055 #include <fcntl.h>
00056 #ifdef WIN32
00057 # include <signal.h>
00058 # include <sys/stat.h>
00059 # include <process.h>
00060 #endif
00061 
00062 #include "dosbox.h"
00063 #include "pic.h"
00064 #include "timer.h"
00065 #include "setup.h"
00066 #include "bios.h"
00067 #include "support.h"
00068 #include "debug.h"
00069 #include "ide.h"
00070 #include "bitop.h"
00071 #include "ptrop.h"
00072 #include "mapper.h"
00073 #include "sdlmain.h"
00074 #include "zipfile.h"
00075 
00076 #if C_EMSCRIPTEN
00077 # include <emscripten.h>
00078 #endif
00079 
00080 #include "../src/libs/gui_tk/gui_tk.h"
00081 
00082 #ifdef __WIN32__
00083 # include "callback.h"
00084 # include "dos_inc.h"
00085 # include <malloc.h>
00086 # include "Commdlg.h"
00087 # include "windows.h"
00088 # include "Shellapi.h"
00089 # include "shell.h"
00090 # include <cstring>
00091 # include <fstream>
00092 # include <sstream>
00093 # if defined(__MINGW32__) && !defined(HX_DOS)
00094 #  include <imm.h> // input method editor
00095 # endif
00096 #endif // WIN32
00097 
00098 #include "mapper.h"
00099 #include "vga.h"
00100 #include "keyboard.h"
00101 #include "cpu.h"
00102 #include "fpu.h"
00103 #include "cross.h"
00104 #include "keymap.h"
00105 
00106 #ifdef _MSC_VER
00107 # define MIN(a,b) ((a) < (b) ? (a) : (b))
00108 # define MAX(a,b) ((a) > (b) ? (a) : (b))
00109 #else
00110 # define MIN(a,b) std::min(a,b)
00111 # define MAX(a,b) std::max(a,b)
00112 #endif
00113 
00114 #if !defined(C_SDL2)
00115 # include "SDL_version.h"
00116 # ifndef SDL_DOSBOX_X_SPECIAL
00117 #  error This code must be compiled using the SDL 1.x library provided in this source repository
00118 # endif
00119 #endif
00120 
00121 #include "sdlmain.h"
00122 
00123 SDL_Block sdl;
00124 Bitu frames = 0;
00125 
00126 ScreenSizeInfo          screen_size_info;
00127 
00128 const char *scaler_menu_opts[][2] = {
00129     { "none",                   "None" },
00130     { "normal2x",               "Normal 2X" },
00131     { "normal3x",               "Normal 3X" },
00132     { "normal4x",               "Normal 4X" },
00133     { "normal5x",               "Normal 5X" },
00134     { "hardware_none",          "Hardware None" },
00135     { "hardware2x",             "Hardware 2X" },
00136     { "hardware3x",             "Hardware 3X" },
00137     { "hardware4x",             "Hardware 4X" },
00138     { "hardware5x",             "Hardware 5X" },
00139     { "tv2x",                   "TV 2X" },
00140     { "tv3x",                   "TV 3X" },
00141     { "scan2x",                 "Scan 2X" },
00142     { "scan3x",                 "Scan 3X" },
00143     { "rgb2x",                  "RGB 2X" },
00144     { "rgb3x",                  "RGB 3X" },
00145     { "advmame2x",              "Advanced MAME 2X" },
00146     { "advmame3x",              "Advanced MAME 3X" },
00147     { "hq2x",                   "HQ 2X" },
00148     { "hq3x",                   "HQ 3X" },
00149     { "advinterp2x",            "Advanced Interpolation 2X" },
00150     { "advinterp3x",            "Advanced Interpolation 3X" },
00151     { "2xsai",                  "2xSai" },
00152     { "super2xsai",             "Super2xSai" },
00153     { "supereagle",             "SuperEagle" },
00154 #if C_XBRZ
00155     { "xbrz",                   "xBRZ" },
00156     { "xbrz_bilinear",          "xBRZ Bilinear" },
00157 #endif
00158     { NULL, NULL }
00159 };
00160 
00161 #if defined(WIN32) && !defined(C_SDL2)
00162 bool isVirtualBox = false; /* OpenGL never works with Windows XP inside VirtualBox */
00163 HMENU MainMenu = NULL;
00164 #endif
00165 
00166 bool OpenGL_using(void);
00167 
00168 #if defined(WIN32) && !defined(S_ISREG)
00169 # define S_ISREG(x) ((x & S_IFREG) == S_IFREG)
00170 #endif
00171 
00172 #ifndef SDL_MAIN_NOEXCEPT
00173 #define SDL_MAIN_NOEXCEPT
00174 #endif
00175 
00176 using namespace std;
00177 
00178 void UpdateOverscanMenu(void);
00179 
00180 const char *DKM_to_string(const unsigned int dkm) {
00181     switch (dkm) {
00182         case DKM_US:        return "us";
00183         case DKM_DEU:       return "ger";
00184         case DKM_JPN_PC98:  return "jpn_pc98";
00185         case DKM_JPN:       return "jpn";
00186         default:            break;
00187     };
00188 
00189     return "";
00190 }
00191 
00192 const char *DKM_to_descriptive_string(const unsigned int dkm) {
00193     switch (dkm) {
00194         case DKM_US:        return "US English";
00195         case DKM_DEU:       return "German";
00196         case DKM_JPN_PC98:  return "Japanese (PC-98)";
00197         case DKM_JPN:       return "Japanese";
00198         default:            break;
00199     };
00200 
00201     return "";
00202 }
00203 
00204 unsigned int mapper_keyboard_layout = DKM_US;
00205 unsigned int host_keyboard_layout = DKM_US;
00206 
00207 void KeyboardLayoutDetect(void) {
00208     unsigned int nlayout = DKM_US;
00209 
00210 #if defined(LINUX)
00211     unsigned int Linux_GetKeyboardLayout(void);
00212     nlayout = Linux_GetKeyboardLayout();
00213 
00214 # if !defined(C_SDL2)
00215     /* BUGFIX: The xkbmap for 'jp' in Linux/X11 has a problem that maps both
00216      *         Ro and Yen to backslash, which in SDL's default state makes
00217      *         it impossible to map them properly in the mapper. */
00218     if (nlayout == DKM_JPN) {
00219         LOG_MSG("Engaging Linux/X11 fix for jp xkbmap in order to handle Ro/Yen keys");
00220 
00221         void Linux_JPXKBFix(void);
00222         Linux_JPXKBFix();
00223     }
00224 # endif
00225 #elif defined(WIN32)
00226     WORD lid = LOWORD(GetKeyboardLayout(0));
00227 
00228     LOG_MSG("Windows keyboard layout ID is 0x%04x", lid);
00229 
00230     switch (lid) {
00231         case 0x0407:    nlayout = DKM_DEU; break;
00232         case 0x0409:    nlayout = DKM_US; break;
00233         case 0x0411:    nlayout = DKM_JPN; break;
00234         default:        break;
00235     };
00236 #endif
00237 
00238     host_keyboard_layout = nlayout;
00239 
00240     LOG_MSG("Host keyboard layout is now %s (%s)",
00241         DKM_to_string(host_keyboard_layout),
00242         DKM_to_descriptive_string(host_keyboard_layout));
00243 }
00244 
00245 void SetMapperKeyboardLayout(const unsigned int dkm) {
00246     /* TODO: Make mapper re-initialize layout. If the mapper interface is visible, redraw it. */
00247     mapper_keyboard_layout = dkm;
00248 
00249     LOG_MSG("Mapper keyboard layout is now %s (%s)",
00250         DKM_to_string(mapper_keyboard_layout),
00251         DKM_to_descriptive_string(mapper_keyboard_layout));
00252 }
00253 
00254 #if defined(WIN32) && !defined(C_SDL2)
00255 extern "C" unsigned char SDL1_hax_hasLayoutChanged(void);
00256 extern "C" void SDL1_hax_ackLayoutChanged(void);
00257 #endif
00258 
00259 void CheckMapperKeyboardLayout(void) {
00260 #if defined(WIN32) && !defined(C_SDL2)
00261     if (SDL1_hax_hasLayoutChanged()) {
00262         SDL1_hax_ackLayoutChanged();
00263         LOG_MSG("Keyboard layout changed");
00264         KeyboardLayoutDetect();
00265 
00266         if (host_keyboard_layout == DKM_JPN && IS_PC98_ARCH)
00267             SetMapperKeyboardLayout(DKM_JPN_PC98);
00268         else
00269             SetMapperKeyboardLayout(host_keyboard_layout);
00270     }
00271 #endif
00272 }
00273 
00274 /* yksoft1 says that older MinGW headers lack this value --Jonathan C. */
00275 #ifndef MAPVK_VK_TO_VSC
00276 #define MAPVK_VK_TO_VSC 0
00277 #endif
00278 
00279 bool boot_debug_break = false;
00280 
00281 bool window_was_maximized = false;
00282 
00283 /* this flag is needed in order to know if we're AT the shell,
00284    or if we're in a program running under the shell. */
00285 bool dos_shell_running_program = false;
00286 
00287 Bitu userResizeWindowWidth = 0, userResizeWindowHeight = 0;
00288 Bitu currentWindowWidth = 640, currentWindowHeight = 480;
00289 
00290 int NonUserResizeCounter = 0;
00291 
00292 Bitu time_limit_ms = 0;
00293 
00294 extern bool keep_umb_on_boot;
00295 extern bool keep_private_area_on_boot;
00296 extern bool dos_kernel_disabled;
00297 bool guest_machine_power_on = false;
00298 
00299 std::string custom_savedir;
00300 
00301 void SHELL_Run();
00302 void DisableINT33();
00303 void EMS_DoShutDown();
00304 void XMS_DoShutDown();
00305 void DOS_DoShutDown();
00306 void GUS_DOS_Shutdown();
00307 void SBLASTER_DOS_Shutdown();
00308 void DOS_ShutdownDevices(void);
00309 void RemoveEMSPageFrame(void);
00310 void RemoveUMBBlock();
00311 void DOS_GetMemory_unmap();
00312 void VFILE_Shutdown(void);
00313 void PROGRAMS_Shutdown(void);
00314 void DOS_UninstallMisc(void);
00315 void CALLBACK_Shutdown(void);
00316 void DOS_ShutdownDrives();
00317 void VFILE_Shutdown(void);
00318 void DOS_ShutdownFiles();
00319 void FreeBIOSDiskList();
00320 void GFX_ShutDown(void);
00321 void MAPPER_Shutdown();
00322 void SHELL_Init(void);
00323 #if C_DYNAMIC_X86
00324 void CPU_Core_Dyn_X86_Shutdown(void);
00325 #endif
00326 
00327 void UpdateWindowMaximized(bool flag) {
00328     menu.maxwindow = flag;
00329 }
00330 
00331 void UpdateWindowDimensions(Bitu width, Bitu height)
00332 {
00333     currentWindowWidth = width;
00334     currentWindowHeight = height;
00335 }
00336 
00337 void PrintScreenSizeInfo(void) {
00338 #if 1
00339     const char *method = "?";
00340 
00341     switch (screen_size_info.method) {
00342         case ScreenSizeInfo::METHOD_NONE:       method = "None";        break;
00343         case ScreenSizeInfo::METHOD_X11:        method = "X11";         break;
00344         case ScreenSizeInfo::METHOD_XRANDR:     method = "XRandR";      break;
00345         default:                                                        break;
00346     };
00347 
00348     LOG_MSG("Screen report: Method '%s' (%.3f x %.3f pixels) (%.3f x %.3f mm) (%.3f x %.3f in) (%.3f x %.3f DPI)",
00349             method,
00350 
00351             screen_size_info.screen_dimensions_pixels.width,
00352             screen_size_info.screen_dimensions_pixels.height,
00353 
00354             screen_size_info.screen_dimensions_mm.width,
00355             screen_size_info.screen_dimensions_mm.height,
00356 
00357             screen_size_info.screen_dimensions_mm.width / 25.4,
00358             screen_size_info.screen_dimensions_mm.height / 25.4,
00359 
00360             screen_size_info.screen_dpi.width,
00361             screen_size_info.screen_dpi.height);
00362 #endif
00363 }
00364 
00365 void UpdateWindowDimensions(void)
00366 {
00367 #if defined(WIN32) && !defined(C_SDL2)
00368     // When maximized, SDL won't actually tell us our new dimensions, so get it ourselves.
00369     // FIXME: Instead of GetHWND() we need to track our own handle or add something to SDL 1.x
00370     //        to provide the handle!
00371     RECT r = { 0 };
00372 
00373     GetClientRect(GetHWND(), &r);
00374     UpdateWindowDimensions(r.right, r.bottom);
00375     UpdateWindowMaximized(IsZoomed(GetHWND()));
00376 #endif
00377 #if defined(LINUX) && !defined(C_SDL2)
00378     void UpdateWindowDimensions_Linux(void);
00379     UpdateWindowDimensions_Linux();
00380     void Linux_GetWindowDPI(ScreenSizeInfo &info);
00381     Linux_GetWindowDPI(/*&*/screen_size_info);
00382 #endif
00383     PrintScreenSizeInfo();
00384 }
00385 
00386 #if defined(C_SDL2)
00387 # define MAPPERFILE             "mapper-" VERSION ".sdl2.map"
00388 #else
00389 # define MAPPERFILE             "mapper-" VERSION ".map"
00390 #endif
00391 
00392 #if !defined(C_SDL2)
00393 void                        GUI_ResetResize(bool);
00394 void                        GUI_LoadFonts();
00395 void                        GUI_Run(bool);
00396 #endif
00397 void                        Restart(bool pressed);
00398 
00399 const char*                 titlebar = NULL;
00400 extern const char*              RunningProgram;
00401 extern bool                 CPU_CycleAutoAdjust;
00402 #if !(ENVIRON_INCLUDED)
00403 extern char**                   environ;
00404 #endif
00405 
00406 double                      rtdelta = 0;
00407 bool                        emu_paused = false;
00408 bool                        mouselocked = false; //Global variable for mapper
00409 bool                        fullscreen_switch = true;
00410 bool                        dos_kernel_disabled = true;
00411 bool                        startup_state_numlock = false; // Global for keyboard initialisation
00412 bool                        startup_state_capslock = false; // Global for keyboard initialisation
00413 bool                        startup_state_scrlock = false; // Global for keyboard initialisation
00414 
00415 #if defined(WIN32) && !defined(C_SDL2)
00416 extern "C" void SDL1_hax_SetMenu(HMENU menu);
00417 #endif
00418 
00419 #ifdef WIN32
00420 # include <windows.h>
00421 #endif
00422 
00423 #if (HAVE_DDRAW_H)
00424 # include <ddraw.h>
00425 struct private_hwdata {
00426     LPDIRECTDRAWSURFACE3            dd_surface;
00427     LPDIRECTDRAWSURFACE3            dd_writebuf;
00428 };
00429 #endif
00430 
00431 #ifdef WIN32
00432 # define STDOUT_FILE                TEXT("stdout.txt")
00433 # define STDERR_FILE                TEXT("stderr.txt")
00434 # define DEFAULT_CONFIG_FILE            "/dosbox.conf"
00435 #elif defined(MACOSX)
00436 # define DEFAULT_CONFIG_FILE            "/Library/Preferences/DOSBox Preferences"
00437 #elif defined(HAIKU)
00438 #define DEFAULT_CONFIG_FILE "~/config/settings/dosbox/dosbox.conf"
00439 #else /*linux freebsd*/
00440 # define DEFAULT_CONFIG_FILE            "/.dosboxrc"
00441 #endif
00442 
00443 #if C_SET_PRIORITY
00444 # include <sys/resource.h>
00445 # define PRIO_TOTAL             (PRIO_MAX-PRIO_MIN)
00446 #endif
00447 
00448 #ifdef OS2
00449 # include <os2.h>
00450 #endif
00451 
00452 #if defined(C_SDL2)
00453 # if defined(WIN32)
00454 HWND GetHWND()
00455 {
00456     SDL_SysWMinfo wmi;
00457     SDL_VERSION(&wmi.version);
00458     if (!SDL_GetWindowWMInfo(sdl.window, &wmi))
00459         return nullptr;
00460     return wmi.info.win.window;
00461 }
00462 
00463 HWND GetSurfaceHWND()
00464 {
00465     return GetHWND();
00466 }
00467 # endif
00468 #endif
00469 void SDL_rect_cliptoscreen(SDL_Rect &r) {
00470     if (r.x < 0) {
00471         r.w += r.x;
00472         r.x = 0;
00473     }
00474     if (r.y < 0) {
00475         r.h += r.y;
00476         r.y = 0;
00477     }
00478     if ((r.x+r.w) > sdl.surface->w)
00479         r.w = sdl.surface->w - r.x;
00480     if ((r.y+r.h) > sdl.surface->h)
00481         r.h = sdl.surface->h - r.y;
00482     /* NTS: Apparently r.w and r.h are unsigned, therefore no need to check if negative */
00483 //    if (r.w < 0) r.w = 0;
00484 //    if (r.h < 0) r.h = 0;
00485 }
00486 
00487 Bitu GUI_JoystickCount(void) {
00488     return sdl.num_joysticks;
00489 }
00490 
00491 #if !defined(MACOSX)
00492 /* TODO: should move to it's own file ================================================ */
00493 static unsigned char logo[32*32*4]= {
00494 #include "dosbox_logo.h"
00495 };
00496 #endif
00497 
00498 #if !defined(MACOSX)
00499 static void DOSBox_SetOriginalIcon(void) {
00500     SDL_Surface *logos;
00501 
00502 #if WORDS_BIGENDIAN
00503         logos = SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0xff000000,0x00ff0000,0x0000ff00,0);
00504 #else
00505         logos = SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0x000000ff,0x0000ff00,0x00ff0000,0);
00506 #endif
00507 
00508 #if defined(C_SDL2)
00509         SDL_SetWindowIcon(sdl.window, logos);
00510 #else
00511         SDL_WM_SetIcon(logos,NULL);
00512 #endif
00513 }
00514 #endif
00515 /* =================================================================================== */
00516 
00517 #if defined (WIN32)
00518 bool GFX_SDLUsingWinDIB(void) {
00519     return sdl.using_windib;
00520 }
00521 #endif
00522 
00523 void GFX_SetIcon(void) 
00524 {
00525 #if !defined(MACOSX)
00526     /* Set Icon (must be done before any sdl_setvideomode call) */
00527     /* But don't set it on OS X, as we use a nicer external icon there. */
00528     /* Made into a separate call, so it can be called again when we restart the graphics output on win32 */
00529     if (menu_compatible) { DOSBox_SetOriginalIcon(); return; }
00530 #endif
00531 
00532 #if defined(WIN32) && !defined(C_SDL2)
00533     HICON hIcon1;
00534 
00535     hIcon1 = (HICON) LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE(dosbox_ico), IMAGE_ICON,
00536         16,16,LR_DEFAULTSIZE);
00537 
00538     SendMessage(GetHWND(), WM_SETICON, ICON_SMALL, (LPARAM) hIcon1 ); 
00539 #endif
00540 }
00541 
00542 extern std::string dosbox_title;
00543 
00544 void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused){
00545     (void)frameskip;//UNUSED
00546     (void)timing;//UNUSED
00547 //  static Bits internal_frameskip=0;
00548     static Bit32s internal_cycles=0;
00549 //  static Bits internal_timing=0;
00550     char title[200] = {0};
00551 
00552     Section_prop *section = static_cast<Section_prop *>(control->GetSection("SDL"));
00553     assert(section != NULL);
00554     titlebar = section->Get_string("titlebar");
00555 
00556     if (cycles != -1) internal_cycles = cycles;
00557 //  if (timing != -1) internal_timing = timing;
00558 //  if (frameskip != -1) internal_frameskip = frameskip;
00559 
00560     sprintf(title,"%s%sDOSBox-X %s, %d cyc/ms",
00561         dosbox_title.c_str(),dosbox_title.empty()?"":": ",
00562         VERSION,(int)internal_cycles);
00563 
00564     {
00565         const char *what = (titlebar != NULL && *titlebar != 0) ? titlebar : RunningProgram;
00566 
00567         if (what != NULL && *what != 0) {
00568             char *p = title + strlen(title); // append to end of string
00569 
00570             sprintf(p,", %s",what);
00571         }
00572     }
00573 
00574     if (!menu.hidecycles) {
00575         char *p = title + strlen(title); // append to end of string
00576 
00577         sprintf(p,", FPS %2d",(int)frames);
00578     }
00579 
00580     if (menu.showrt) {
00581         char *p = title + strlen(title); // append to end of string
00582 
00583         sprintf(p,", %2d%%/RT",(int)floor((rtdelta / 10) + 0.5));
00584     }
00585 
00586     if (paused) strcat(title," PAUSED");
00587 #if defined(C_SDL2)
00588     SDL_SetWindowTitle(sdl.window,title);
00589 #else
00590     SDL_WM_SetCaption(title,VERSION);
00591 #endif
00592 }
00593 
00594 bool warn_on_mem_write = false;
00595 
00596 void CPU_Snap_Back_To_Real_Mode();
00597 
00598 static void KillSwitch(bool pressed) {
00599     if (!pressed) return;
00600     if (sdl.desktop.fullscreen) GFX_SwitchFullScreen();
00601 #if 0 /* Re-enable this hack IF DOSBox continues to have problems page-faulting on kill switch */
00602     CPU_Snap_Back_To_Real_Mode(); /* TEMPORARY HACK. There are portions of DOSBox that write to memory as if still running DOS. */
00603     /* ^ Without this hack, when running Windows NT 3.1 this Kill Switch effectively becomes the Instant Page Fault BSOD switch
00604      * because the DOSBox code attempting to write to real mode memory causes a page fault (though hitting the kill switch a
00605      * second time shuts DOSBox down properly). It's sort of the same issue behind the INT 33h emulation causing instant BSOD
00606      * in Windows NT the instant you moved or clicked the mouse. The purpose of this hack is that, before any of that DOSBox
00607      * code has a chance, we force the CPU back into real mode so that the code doesn't trigger funny page faults and DOSBox
00608      * shuts down properly. */
00609 #endif
00610     warn_on_mem_write = true;
00611     throw 1;
00612 }
00613 
00614 void GFX_SDL_Overscan(void) {
00615     sdl.overscan_color=0;
00616     if (sdl.overscan_width) {
00617         Bitu border_color =  GFX_GetRGB(vga.dac.rgb[vga.attr.overscan_color].red<<2,
00618             vga.dac.rgb[vga.attr.overscan_color].green<<2, vga.dac.rgb[vga.attr.overscan_color].blue<<2);
00619         if (border_color != sdl.overscan_color) {
00620             sdl.overscan_color = border_color;
00621 
00622         // Find four rectangles forming the border
00623             SDL_Rect *rect = &sdl.updateRects[0];
00624             rect->x = 0; rect->y = 0; rect->w = sdl.draw.width+(unsigned int)(2*sdl.clip.x); rect->h = (uint16_t)sdl.clip.y; // top
00625             if ((Bitu)rect->h > (Bitu)sdl.overscan_width) { rect->y += (int)(rect->h-sdl.overscan_width); rect->h = (uint16_t)sdl.overscan_width; }
00626             if ((Bitu)sdl.clip.x > (Bitu)sdl.overscan_width) { rect->x += (int)sdl.clip.x-(int)sdl.overscan_width; rect->w -= (uint16_t)(2*((int)sdl.clip.x-(int)sdl.overscan_width)); }
00627             rect = &sdl.updateRects[1];
00628             rect->x = 0; rect->y = sdl.clip.y; rect->w = (uint16_t)sdl.clip.x; rect->h = (uint16_t)sdl.draw.height; // left
00629             if ((unsigned int)rect->w > (unsigned int)sdl.overscan_width) { rect->x += (int)rect->w-(int)sdl.overscan_width; rect->w = (uint16_t)sdl.overscan_width; }
00630             rect = &sdl.updateRects[2];
00631             rect->x = (int)sdl.clip.x+(int)sdl.draw.width; rect->y = sdl.clip.y; rect->w = (uint16_t)sdl.clip.x; rect->h = (uint16_t)sdl.draw.height; // right
00632             if ((unsigned int)rect->w > (unsigned int)sdl.overscan_width) { rect->w = (uint16_t)sdl.overscan_width; }
00633             rect = &sdl.updateRects[3];
00634             rect->x = 0; rect->y = (int)sdl.clip.y+(int)sdl.draw.height; rect->w = sdl.draw.width+(unsigned int)(2*sdl.clip.x); rect->h = (uint16_t)sdl.clip.y; // bottom
00635             if ((Bitu)rect->h > (Bitu)sdl.overscan_width) { rect->h = (uint16_t)sdl.overscan_width; }
00636             if ((Bitu)sdl.clip.x > (Bitu)sdl.overscan_width) { rect->x += (int)sdl.clip.x-(int)sdl.overscan_width; rect->w -= (unsigned int)(2*((int)sdl.clip.x-(int)sdl.overscan_width)); }
00637 
00638             if (sdl.surface->format->BitsPerPixel == 8) { // SDL_FillRect seems to have some issues with palettized hw surfaces
00639                 Bit8u* pixelptr = (Bit8u*)sdl.surface->pixels;
00640                 Bitu linepitch = sdl.surface->pitch;
00641                 for (Bitu i=0; i<4; i++) {
00642                     rect = &sdl.updateRects[i];
00643                     Bit8u* start = pixelptr + (unsigned int)rect->y*(unsigned int)linepitch + (unsigned int)rect->x;
00644                     for (Bitu j=0; j<rect->h; j++) {
00645                         memset(start, vga.attr.overscan_color, rect->w);
00646                         start += linepitch;
00647                     }
00648                 }
00649             } else {
00650                 for (Bitu i=0; i<4; i++)
00651                     SDL_FillRect(sdl.surface, &sdl.updateRects[i], border_color);
00652 
00653 #if defined(C_SDL2)
00654                 SDL_UpdateWindowSurfaceRects(sdl.window, sdl.updateRects, 4);
00655 #else
00656                 SDL_UpdateRects(sdl.surface, 4, sdl.updateRects);
00657 #endif
00658             }
00659         }
00660     }
00661 }
00662 
00663 bool DOSBox_Paused()
00664 {
00665     return emu_paused;
00666 }
00667 
00668 bool pause_on_vsync = false;
00669 
00670 #if defined(C_SDL2)
00671 bool GFX_IsFullscreen() {
00672     if (sdl.window == NULL) return false;
00673     uint32_t windowFlags = SDL_GetWindowFlags(sdl.window);
00674     if (windowFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) return true;
00675     return false;
00676 }
00677 
00678 static bool IsFullscreen() {
00679     return GFX_IsFullscreen();
00680 }
00681 #endif
00682 
00683 void PauseDOSBox(bool pressed) {
00684     bool paused = true;
00685     SDL_Event event;
00686 
00687     if (!pressed) return;
00688 
00689     /* reflect in the menu that we're paused now */
00690     mainMenu.get_item("mapper_pause").check(true).refresh_item(mainMenu);
00691 
00692     void MAPPER_ReleaseAllKeys(void);
00693     MAPPER_ReleaseAllKeys();
00694 
00695     GFX_SetTitle(-1,-1,-1,true);
00696 //  KEYBOARD_ClrBuffer();
00697     GFX_LosingFocus();
00698     while (SDL_PollEvent(&event)); // flush event queue.
00699 
00700     // reset pause conditions
00701     pause_on_vsync = false;
00702 
00703     // give mouse to win32 (ex. alt-tab)
00704 #if defined(C_SDL2)
00705     SDL_SetRelativeMouseMode(SDL_FALSE);
00706 #else
00707     SDL_WM_GrabInput(SDL_GRAB_OFF);
00708 #endif
00709 
00710     while (paused) {
00711 #if C_EMSCRIPTEN
00712         emscripten_sleep_with_yield(0);
00713         SDL_PollEvent(&event);
00714 #else
00715         SDL_WaitEvent(&event);    // since we're not polling, cpu usage drops to 0.
00716 #endif
00717 
00718 #ifdef __WIN32__
00719   #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU
00720         if (event.type==SDL_SYSWMEVENT && event.syswm.msg->msg == WM_COMMAND && event.syswm.msg->wParam == (mainMenu.get_item("mapper_pause").get_master_id()+DOSBoxMenu::winMenuMinimumID)) {
00721             paused=false;
00722             GFX_SetTitle(-1,-1,-1,false);   
00723             break;
00724         }
00725   #endif
00726 #endif
00727         switch (event.type) {
00728 
00729             case SDL_QUIT: KillSwitch(true); break;
00730             case SDL_KEYDOWN:   // Must use Pause/Break or escape Key to resume.
00731             if(event.key.keysym.sym == SDLK_PAUSE || event.key.keysym.sym == SDLK_ESCAPE) {
00732 
00733                 paused = false;
00734                 GFX_SetTitle(-1,-1,-1,false);
00735                 break;
00736             }
00737             else if (event.key.keysym.sym == SDLK_SPACE) { /* spacebar = single frame step */
00738                 /* resume, but let the VGA code know to call us on vertical retrace */
00739                 paused = false;
00740                 pause_on_vsync = true;
00741                 GFX_SetTitle(-1,-1,-1,false);
00742                 break;
00743             }
00744 #if defined (MACOSX) && !defined(C_SDL2)
00745             if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) {
00746                 /* On macs, all apps exit when pressing cmd-q */
00747                 KillSwitch(true);
00748                 break;
00749             } 
00750 #endif
00751         }
00752     }
00753 
00754 
00755     // restore mouse state
00756     void GFX_UpdateSDLCaptureState();
00757     GFX_UpdateSDLCaptureState();
00758 
00759     void MAPPER_ReleaseAllKeys(void);
00760     MAPPER_ReleaseAllKeys();
00761 
00762 //  KEYBOARD_ClrBuffer();
00763     GFX_LosingFocus();
00764 
00765     // redraw screen (ex. fullscreen - pause - alt+tab x2 - unpause)
00766     if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackReset );
00767 
00768     /* reflect in the menu that we're paused now */
00769     mainMenu.get_item("mapper_pause").check(false).refresh_item(mainMenu);
00770 }
00771 
00772 #if defined(C_SDL2)
00773 SDL_Window* GFX_SetSDLWindowMode(Bit16u width, Bit16u height, SCREEN_TYPES screenType) 
00774 {
00775     static SCREEN_TYPES lastType = SCREEN_SURFACE;
00776     if (sdl.renderer) {
00777         SDL_DestroyRenderer(sdl.renderer);
00778         sdl.renderer=0;
00779     }
00780     if (sdl.texture.pixelFormat) {
00781         SDL_FreeFormat(sdl.texture.pixelFormat);
00782         sdl.texture.pixelFormat = 0;
00783     }
00784     if (sdl.texture.texture) {
00785         SDL_DestroyTexture(sdl.texture.texture);
00786         sdl.texture.texture=0;
00787     }
00788 #if C_OPENGL
00789     if (sdl_opengl.context) {
00790         SDL_GL_DeleteContext(sdl_opengl.context);
00791         sdl_opengl.context=0;
00792     }
00793 #endif
00794     sdl.window_desired_width = width;
00795     sdl.window_desired_height = height;
00796     int currWidth, currHeight;
00797     if (sdl.window) {
00798         //SDL_GetWindowSize(sdl.window, &currWidth, &currHeight);
00799         if (!sdl.update_window) {
00800             SDL_GetWindowSize(sdl.window, &currWidth, &currHeight);
00801             sdl.update_display_contents = ((width == currWidth) && (height == currHeight));
00802             return sdl.window;
00803         }
00804     }
00805     /* If we change screen type, recreate the window. Furthermore, if
00806      * it is our very first time then we simply create a new window.
00807      */
00808     if (!sdl.window
00809             || (lastType != screenType)
00810 //          || (currWidth != width) || (currHeight != height)
00811 //          || (glwindow != (0 != (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_OPENGL)))
00812 //          || (fullscreen && (0 == (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_FULLSCREEN)))
00813 //          || (fullscreen != (SDL_WINDOW_FULLSCREEN == (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_FULLSCREEN)))
00814 //          || (fullscreen && ((width != currWidth) || (height != currHeight)))
00815        ) {
00816         lastType = screenType;
00817         if (sdl.window) {
00818             SDL_DestroyWindow(sdl.window);
00819         }
00820         sdl.window = SDL_CreateWindow("",
00821                                       SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber),
00822                                       SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber),
00823                                       width, height,
00824                                       (GFX_IsFullscreen() ? (sdl.desktop.full.display_res ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) : 0)
00825                                       | ((screenType == SCREEN_OPENGL) ? SDL_WINDOW_OPENGL : 0) | SDL_WINDOW_SHOWN);
00826         if (sdl.window) {
00827             GFX_SetTitle(-1, -1, -1, false); //refresh title.
00828         }
00829         SDL_GetWindowSize(sdl.window, &currWidth, &currHeight);
00830         sdl.update_display_contents = ((width == currWidth) && (height == currHeight));
00831         return sdl.window;
00832     }
00833     /* Fullscreen mode switching has its limits, and is also problematic on
00834      * some window managers. For now, the following may work up to some
00835      * level. On X11, SDL_VIDEO_X11_LEGACY_FULLSCREEN=1 can also help,
00836      * although it has its own issues.
00837      * Suggestion: Use the desktop res if possible, with output=surface
00838      * if one is not interested in scaling.
00839      * On Android, desktop res is the only way.
00840      */
00841     if (GFX_IsFullscreen()) {
00842         SDL_DisplayMode displayMode;
00843         SDL_GetWindowDisplayMode(sdl.window, &displayMode);
00844         displayMode.w = width;
00845         displayMode.h = height;
00846         SDL_SetWindowDisplayMode(sdl.window, &displayMode);
00847 
00848         SDL_SetWindowFullscreen(sdl.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
00849     } else {
00850         SDL_SetWindowFullscreen(sdl.window, 0);
00851 
00852         SDL_SetWindowSize(sdl.window, width, height);
00853     }
00854     /* Maybe some requested fullscreen resolution is unsupported? */
00855     SDL_GetWindowSize(sdl.window, &currWidth, &currHeight);
00856     sdl.update_display_contents = ((width == currWidth) && (height == currHeight));
00857     return sdl.window;
00858 }
00859 
00860 // Used for the mapper UI and more: Creates a fullscreen window with desktop res
00861 // on Android, and a non-fullscreen window with the input dimensions otherwise.
00862 SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height) {
00863     return GFX_SetSDLWindowMode(width, height, SCREEN_SURFACE);
00864 }
00865 
00866 // Returns the rectangle in the current window to be used for scaling a
00867 // sub-window with the given dimensions, like the mapper UI.
00868 SDL_Rect GFX_GetSDLSurfaceSubwindowDims(Bit16u width, Bit16u height) {
00869     SDL_Rect rect;
00870     rect.x=rect.y=0;
00871     rect.w=width;
00872     rect.h=height;
00873     return rect;
00874 }
00875 
00876 # if !defined(C_SDL2)
00877 // Currently used for an initial test here
00878 static SDL_Window * GFX_SetSDLOpenGLWindow(Bit16u width, Bit16u height) {
00879     return GFX_SetSDLWindowMode(width, height, SCREEN_OPENGL);
00880 }
00881 # endif
00882 #endif
00883 
00884 #if C_OPENGL && !defined(C_SDL2) && DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00885 unsigned int SDLDrawGenFontTextureUnitPerRow = 16;
00886 unsigned int SDLDrawGenFontTextureRows = 16;
00887 unsigned int SDLDrawGenFontTextureWidth = SDLDrawGenFontTextureUnitPerRow * 8;
00888 unsigned int SDLDrawGenFontTextureHeight = SDLDrawGenFontTextureRows * 16;
00889 bool SDLDrawGenFontTextureInit = false;
00890 GLuint SDLDrawGenFontTexture = (GLuint)(~0UL);
00891 #endif
00892 
00893 #if !defined(C_SDL2)
00894 /* Reset the screen with current values in the sdl structure */
00895 Bitu GFX_GetBestMode(Bitu flags) 
00896 {
00897     Bitu retFlags = 0;
00898 
00899     switch (sdl.desktop.want_type) 
00900     {
00901         case SCREEN_SURFACE:
00902             retFlags = OUTPUT_SURFACE_GetBestMode(flags);
00903             break;
00904 
00905 #if C_OPENGL
00906         case SCREEN_OPENGL:
00907             retFlags = OUTPUT_OPENGL_GetBestMode(flags);
00908             break;
00909 #endif
00910 
00911 #if C_DIRECT3D
00912         case SCREEN_DIRECT3D:
00913             retFlags = OUTPUT_DIRECT3D_GetBestMode(flags);
00914             break;
00915 #endif
00916 
00917         default:
00918             // we should never reach here
00919             retFlags = 0;
00920             break;
00921     }
00922 
00923     if (!retFlags)
00924     {
00925         if (sdl.desktop.want_type != SCREEN_SURFACE)
00926         {
00927             // try falling back down to surface
00928             OUTPUT_SURFACE_Select();
00929             retFlags = OUTPUT_SURFACE_GetBestMode(flags);
00930         }
00931         if (retFlags == 0)
00932             LOG_MSG("SDL:Failed everything including falling back to surface GFX_GetBestMode"); // completely failed it seems
00933     }
00934 
00935     return retFlags;
00936 }
00937 #endif
00938 
00939 /* FIXME: This prepares the SDL library to accept Win32 drag+drop events from the Windows shell.
00940  *        So it should be named something like EnableDragAcceptFiles() not SDL_Prepare() */
00941 void SDL_Prepare(void) {
00942     if (menu_compatible) return;
00943 
00944 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) // Microsoft Windows specific
00945     LOG(LOG_MISC,LOG_DEBUG)("Win32: Preparing main window to accept files dragged in from the Windows shell");
00946 
00947     SDL_PumpEvents(); SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
00948     DragAcceptFiles(GetHWND(), TRUE);
00949 #endif
00950 }
00951 
00952 void GFX_ForceRedrawScreen(void) {
00953     GFX_Stop();
00954     if (sdl.draw.callback)
00955         (sdl.draw.callback)( GFX_CallBackReset );
00956     GFX_Start();
00957 }
00958 
00959 void GFX_ResetScreen(void) {
00960     fullscreen_switch=false; 
00961     GFX_Stop();
00962     if (sdl.draw.callback)
00963         (sdl.draw.callback)( GFX_CallBackReset );
00964     GFX_Start();
00965     CPU_Reset_AutoAdjust();
00966     fullscreen_switch=true;
00967 #if !defined(C_SDL2)
00968     if (!sdl.desktop.fullscreen) DOSBox_RefreshMenu(); // for menu
00969 #endif
00970 }
00971 
00972 void GFX_ForceFullscreenExit(void) {
00973     if (sdl.desktop.lazy_fullscreen) {
00974         LOG_MSG("GFX LF: invalid screen change");
00975     } else {
00976         sdl.desktop.fullscreen=false;
00977         GFX_ResetScreen();
00978     }
00979 }
00980 
00981 uint32_t GFX_Rmask;
00982 unsigned char GFX_Rshift;
00983 uint32_t GFX_Gmask;
00984 unsigned char GFX_Gshift;
00985 uint32_t GFX_Bmask;
00986 unsigned char GFX_Bshift;
00987 uint32_t GFX_Amask;
00988 unsigned char GFX_Ashift;
00989 unsigned char GFX_bpp;
00990 
00991 unsigned int GFX_GetBShift() {
00992     return sdl.surface->format->Bshift;
00993 }
00994 
00995 void GFX_LogSDLState(void) 
00996 {
00997     LOG(LOG_MISC,LOG_DEBUG)("SDL video mode: %ux%u (clip %ux%u with upper-left at %ux%u) %ubpp",
00998         (unsigned)sdl.surface->w,(unsigned)sdl.surface->h,
00999         (unsigned)sdl.clip.w,(unsigned)sdl.clip.h,
01000         (unsigned)sdl.clip.x,(unsigned)sdl.clip.y,
01001         (unsigned)sdl.surface->format->BitsPerPixel);
01002     LOG(LOG_MISC,LOG_DEBUG)("   red: shift=%u mask=0x%08lx",
01003         (unsigned)sdl.surface->format->Rshift,
01004         (unsigned long)sdl.surface->format->Rmask);
01005     LOG(LOG_MISC,LOG_DEBUG)("   green: shift=%u mask=0x%08lx",
01006         (unsigned)sdl.surface->format->Gshift,
01007         (unsigned long)sdl.surface->format->Gmask);
01008     LOG(LOG_MISC,LOG_DEBUG)("   blue: shift=%u mask=0x%08lx",
01009         (unsigned)sdl.surface->format->Bshift,
01010         (unsigned long)sdl.surface->format->Bmask);
01011     LOG(LOG_MISC,LOG_DEBUG)("   alpha: shift=%u mask=0x%08lx",
01012         (unsigned)sdl.surface->format->Ashift,
01013         (unsigned long)sdl.surface->format->Amask);
01014 
01015     GFX_bpp = sdl.surface->format->BitsPerPixel;
01016     GFX_Rmask = sdl.surface->format->Rmask;
01017     GFX_Rshift = sdl.surface->format->Rshift;
01018     GFX_Gmask = sdl.surface->format->Gmask;
01019     GFX_Gshift = sdl.surface->format->Gshift;
01020     GFX_Bmask = sdl.surface->format->Bmask;
01021     GFX_Bshift = sdl.surface->format->Bshift;
01022     GFX_Amask = sdl.surface->format->Amask;
01023     GFX_Ashift = sdl.surface->format->Ashift;
01024 }
01025 
01026 void GFX_TearDown(void) {
01027     if (sdl.updating)
01028         GFX_EndUpdate( 0 );
01029 
01030     if (sdl.blit.surface) {
01031         SDL_FreeSurface(sdl.blit.surface);
01032         sdl.blit.surface=0;
01033     }
01034 }
01035 
01036 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
01037 void MenuShadeRect(int x,int y,int w,int h) {
01038     if (OpenGL_using()) {
01039 #if C_OPENGL
01040         glShadeModel (GL_FLAT);
01041         glBlendFunc(GL_ONE, GL_SRC_ALPHA);
01042         glDisable (GL_DEPTH_TEST);
01043         glDisable (GL_LIGHTING);
01044         glEnable(GL_BLEND);
01045         glDisable(GL_CULL_FACE);
01046         glDisable(GL_ALPHA_TEST);
01047         glDisable(GL_FOG);
01048         glDisable(GL_SCISSOR_TEST);
01049         glDisable(GL_STENCIL_TEST);
01050         glDisable(GL_TEXTURE_2D);
01051 
01052         glColor4ub(0, 0, 0, 64);
01053         glBegin(GL_QUADS);
01054         glVertex2i(x  ,y  );
01055         glVertex2i(x+w,y  );
01056         glVertex2i(x+w,y+h);
01057         glVertex2i(x  ,y+h);
01058         glEnd();
01059 
01060         glBlendFunc(GL_ONE, GL_ZERO);
01061         glEnable(GL_TEXTURE_2D);
01062 #endif
01063     }
01064     else {
01065         if (x < 0) {
01066             w += x;
01067             x = 0;
01068         }
01069         if (y < 0) {
01070             y += h;
01071             y = 0;
01072         }
01073         if ((x+w) > sdl.surface->w)
01074             w = sdl.surface->w - x;
01075         if ((y+h) > sdl.surface->h)
01076             h = sdl.surface->h - y;
01077         if (w <= 0 || h <= 0)
01078             return;
01079 
01080         if (sdl.surface->format->BitsPerPixel == 32) {
01081             unsigned char *scan;
01082             uint32_t *row,mask;
01083 
01084             mask = ((sdl.surface->format->Rmask >> 2) & sdl.surface->format->Rmask) |
01085                 ((sdl.surface->format->Gmask >> 2) & sdl.surface->format->Gmask) |
01086                 ((sdl.surface->format->Bmask >> 2) & sdl.surface->format->Bmask);
01087 
01088             assert(sdl.surface->pixels != NULL);
01089 
01090             scan  = (unsigned char*)sdl.surface->pixels;
01091             scan += y * sdl.surface->pitch;
01092             scan += x * 4;
01093             while (h-- > 0) {
01094                 row = (uint32_t*)scan;
01095                 scan += sdl.surface->pitch;
01096                 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (row[c] >> 2) & mask;
01097             }
01098         }
01099         else if (sdl.surface->format->BitsPerPixel == 16) {
01100             unsigned char *scan;
01101             uint16_t *row,mask;
01102 
01103             mask = ((sdl.surface->format->Rmask >> 2) & sdl.surface->format->Rmask) |
01104                 ((sdl.surface->format->Gmask >> 2) & sdl.surface->format->Gmask) |
01105                 ((sdl.surface->format->Bmask >> 2) & sdl.surface->format->Bmask);
01106 
01107             assert(sdl.surface->pixels != NULL);
01108 
01109             scan  = (unsigned char*)sdl.surface->pixels;
01110             scan += y * sdl.surface->pitch;
01111             scan += x * 2;
01112             while (h-- > 0) {
01113                 row = (uint16_t*)scan;
01114                 scan += sdl.surface->pitch;
01115                 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (row[c] >> 2) & mask;
01116             }
01117         }
01118         else {
01119             /* TODO */
01120         }
01121     }
01122 }
01123 
01124 void MenuDrawRect(int x,int y,int w,int h,Bitu color) {
01125     if (OpenGL_using()) {
01126 #if C_OPENGL
01127         glShadeModel (GL_FLAT);
01128         glBlendFunc(GL_ONE, GL_ZERO);
01129         glDisable (GL_DEPTH_TEST);
01130         glDisable (GL_LIGHTING);
01131         glDisable(GL_BLEND);
01132         glDisable(GL_CULL_FACE);
01133         glDisable(GL_ALPHA_TEST);
01134         glDisable(GL_FOG);
01135         glDisable(GL_SCISSOR_TEST);
01136         glDisable(GL_STENCIL_TEST);
01137         glDisable(GL_TEXTURE_2D);
01138 
01139         glColor3ub((color >> 16UL) & 0xFF,(color >> 8UL) & 0xFF,(color >> 0UL) & 0xFF);
01140         glBegin(GL_QUADS);
01141         glVertex2i(x  ,y  );
01142         glVertex2i(x+w,y  );
01143         glVertex2i(x+w,y+h);
01144         glVertex2i(x  ,y+h);
01145         glEnd();
01146 
01147         glBlendFunc(GL_ONE, GL_ZERO);
01148         glEnable(GL_TEXTURE_2D);
01149 #endif
01150     }
01151     else {
01152         if (x < 0) {
01153             w += x;
01154             x = 0;
01155         }
01156         if (y < 0) {
01157             y += h;
01158             y = 0;
01159         }
01160         if ((x+w) > sdl.surface->w)
01161             w = sdl.surface->w - x;
01162         if ((y+h) > sdl.surface->h)
01163             h = sdl.surface->h - y;
01164         if (w <= 0 || h <= 0)
01165             return;
01166 
01167         if (sdl.surface->format->BitsPerPixel == 32) {
01168             unsigned char *scan;
01169             uint32_t *row;
01170 
01171             assert(sdl.surface->pixels != NULL);
01172 
01173             scan  = (unsigned char*)sdl.surface->pixels;
01174             scan += y * sdl.surface->pitch;
01175             scan += x * 4;
01176             while (h-- > 0) {
01177                 row = (uint32_t*)scan;
01178                 scan += sdl.surface->pitch;
01179                 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (uint32_t)color;
01180             }
01181         }
01182         else if (sdl.surface->format->BitsPerPixel == 16) {
01183             unsigned char *scan;
01184             uint16_t *row;
01185 
01186             assert(sdl.surface->pixels != NULL);
01187 
01188             scan  = (unsigned char*)sdl.surface->pixels;
01189             scan += y * sdl.surface->pitch;
01190             scan += x * 2;
01191             while (h-- > 0) {
01192                 row = (uint16_t*)scan;
01193                 scan += sdl.surface->pitch;
01194                 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (uint16_t)color;
01195             }
01196         }
01197         else {
01198             /* TODO */
01199         }
01200     }
01201 }
01202 
01203 extern Bit8u int10_font_14[256 * 14];
01204 extern Bit8u int10_font_16[256 * 16];
01205 
01206 void MenuDrawTextChar(int x,int y,unsigned char c,Bitu color) {
01207     static const unsigned int fontHeight = 16;
01208 
01209     if (x < 0 || y < 0 ||
01210         (unsigned int)(x+8) > (unsigned int)sdl.surface->w ||
01211         (unsigned int)(y+(int)fontHeight) > (unsigned int)sdl.surface->h)
01212         return;
01213 
01214     unsigned char *bmp = (unsigned char*)int10_font_16 + (c * fontHeight);
01215 
01216     if (OpenGL_using()) {
01217 #if C_OPENGL
01218         unsigned int tx = (c % 16u) * 8u;
01219         unsigned int ty = (c / 16u) * 16u;
01220 
01221         /* MenuDrawText() has prepared OpenGL state for us */
01222         glBegin(GL_QUADS);
01223         // lower left
01224         glTexCoord2i((int)tx+0,    (int)ty                ); glVertex2i((int)x,  (int)y                );
01225         // lower right
01226         glTexCoord2i((int)tx+8,    (int)ty                ); glVertex2i((int)x+8,(int)y                );
01227         // upper right
01228         glTexCoord2i((int)tx+8,    (int)ty+(int)fontHeight); glVertex2i((int)x+8,(int)y+(int)fontHeight);
01229         // upper left
01230         glTexCoord2i((int)tx+0,    (int)ty+(int)fontHeight); glVertex2i((int)x,  (int)y+(int)fontHeight);
01231         glEnd();
01232 #endif
01233     }
01234     else {
01235         unsigned char *scan;
01236 
01237         assert(sdl.surface->pixels != NULL);
01238 
01239         scan  = (unsigned char*)sdl.surface->pixels;
01240         scan += (unsigned int)y * (unsigned int)sdl.surface->pitch;
01241         scan += (unsigned int)x * (((unsigned int)sdl.surface->format->BitsPerPixel+7u)/8u);
01242 
01243         for (unsigned int row=0;row < fontHeight;row++) {
01244             unsigned char rb = bmp[row];
01245 
01246             if (sdl.surface->format->BitsPerPixel == 32) {
01247                 uint32_t *dp = (uint32_t*)scan;
01248                 for (unsigned int colm=0x80;colm != 0;colm >>= 1) {
01249                     if (rb & colm) *dp = (uint32_t)color;
01250                     dp++;
01251                 }
01252             }
01253             else if (sdl.surface->format->BitsPerPixel == 16) {
01254                 uint16_t *dp = (uint16_t*)scan;
01255                 for (unsigned int colm=0x80;colm != 0;colm >>= 1) {
01256                     if (rb & colm) *dp = (uint16_t)color;
01257                     dp++;
01258                 }
01259             }
01260 
01261             scan += (size_t)sdl.surface->pitch;
01262         }
01263     }
01264 }
01265 
01266 void MenuDrawTextChar2x(int x,int y,unsigned char c,Bitu color) {
01267     static const unsigned int fontHeight = 16;
01268 
01269     if (x < 0 || y < 0 ||
01270         (unsigned int)(x+8) > (unsigned int)sdl.surface->w ||
01271         (unsigned int)(y+(int)fontHeight) > (unsigned int)sdl.surface->h)
01272         return;
01273 
01274     unsigned char *bmp = (unsigned char*)int10_font_16 + (c * fontHeight);
01275 
01276     if (OpenGL_using()) {
01277 #if C_OPENGL
01278         unsigned int tx = (c % 16u) * 8u;
01279         unsigned int ty = (c / 16u) * 16u;
01280 
01281         /* MenuDrawText() has prepared OpenGL state for us */
01282         glBegin(GL_QUADS);
01283         // lower left
01284         glTexCoord2i((int)tx+0,    (int)ty                ); glVertex2i(x,      y                    );
01285         // lower right
01286         glTexCoord2i((int)tx+8,    (int)ty                ); glVertex2i(x+(8*2),y                    );
01287         // upper right
01288         glTexCoord2i((int)tx+8,    (int)ty+(int)fontHeight); glVertex2i(x+(8*2),y+((int)fontHeight*2));
01289         // upper left
01290         glTexCoord2i((int)tx+0,    (int)ty+(int)fontHeight); glVertex2i(x,      y+((int)fontHeight*2));
01291         glEnd();
01292 #endif
01293     }
01294     else { 
01295         unsigned char *scan;
01296 
01297         assert(sdl.surface->pixels != NULL);
01298 
01299         scan  = (unsigned char*)sdl.surface->pixels;
01300         scan += y * sdl.surface->pitch;
01301         scan += x * ((sdl.surface->format->BitsPerPixel+7)/8);
01302 
01303         for (unsigned int row=0;row < (fontHeight*2);row++) {
01304             unsigned char rb = bmp[row>>1U];
01305 
01306             if (sdl.surface->format->BitsPerPixel == 32) {
01307                 uint32_t *dp = (uint32_t*)scan;
01308                 for (unsigned int colm=0x80;colm != 0;colm >>= 1) {
01309                     if (rb & colm) {
01310                         *dp++ = (uint32_t)color;
01311                         *dp++ = (uint32_t)color;
01312                     }
01313                     else {
01314                         dp += 2;
01315                     }
01316                 }
01317             }
01318             else if (sdl.surface->format->BitsPerPixel == 16) {
01319                 uint16_t *dp = (uint16_t*)scan;
01320                 for (unsigned int colm=0x80;colm != 0;colm >>= 1) {
01321                     if (rb & colm) {
01322                         *dp++ = (uint16_t)color;
01323                         *dp++ = (uint16_t)color;
01324                     }
01325                     else {
01326                         dp += 2;
01327                     }
01328                 }
01329             }
01330 
01331             scan += sdl.surface->pitch;
01332         }
01333     }
01334 }
01335 
01336 void MenuDrawText(int x,int y,const char *text,Bitu color) {
01337 #if C_OPENGL
01338     if (OpenGL_using()) {
01339         glBindTexture(GL_TEXTURE_2D,SDLDrawGenFontTexture);
01340 
01341         glPushMatrix();
01342 
01343         glMatrixMode (GL_TEXTURE);
01344         glLoadIdentity ();
01345         glScaled(1.0 / SDLDrawGenFontTextureWidth, 1.0 / SDLDrawGenFontTextureHeight, 1.0);
01346 
01347         glColor4ub((color >> 16UL) & 0xFF,(color >> 8UL) & 0xFF,(color >> 0UL) & 0xFF,0xFF);
01348         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
01349 
01350         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01351         glEnable(GL_TEXTURE_2D);
01352         glEnable(GL_ALPHA_TEST);
01353         glEnable(GL_BLEND);
01354     }
01355 #endif
01356 
01357     while (*text != 0) {
01358         if (mainMenu.fontCharScale >= 2)
01359             MenuDrawTextChar2x(x,y,(unsigned char)(*text++),color);
01360         else
01361             MenuDrawTextChar(x,y,(unsigned char)(*text++),color);
01362 
01363         x += (int)mainMenu.fontCharWidth;
01364     }
01365 
01366 #if C_OPENGL
01367     if (OpenGL_using()) {
01368         glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
01369         glBlendFunc(GL_ONE, GL_ZERO);
01370         glDisable(GL_ALPHA_TEST);
01371         glEnable(GL_TEXTURE_2D);
01372 
01373         glPopMatrix();
01374 
01375         glBindTexture(GL_TEXTURE_2D,sdl_opengl.texture);
01376     }
01377 #endif
01378 }
01379 
01380 void DOSBoxMenu::item::drawMenuItem(DOSBoxMenu &menu) {
01381     (void)menu;//UNUSED
01382 
01383     Bitu bgcolor = GFX_GetRGB(63, 63, 63);
01384     Bitu fgcolor = GFX_GetRGB(191, 191, 191);
01385     Bitu fgshortcolor = GFX_GetRGB(127, 127, 191);
01386     Bitu fgcheckcolor = GFX_GetRGB(191, 191, 127);
01387 
01388     if (type >= separator_type_id) {
01389         /* separators never change visual state on hover/select */
01390     }
01391     else if (!status.enabled) {
01392         fgcolor = GFX_GetRGB(144, 144, 144);
01393         fgshortcolor = GFX_GetRGB(63, 63, 144);
01394         fgcheckcolor = GFX_GetRGB(144, 144, 63);
01395     }
01396     else if (itemHilight) {
01397         bgcolor = GFX_GetRGB(0, 0, 63);
01398         fgcolor = GFX_GetRGB(255, 255, 255);
01399         fgshortcolor = GFX_GetRGB(191, 191, 255);
01400     }
01401     else if (itemHover) {
01402         bgcolor = GFX_GetRGB(127, 127, 127);
01403         fgcolor = GFX_GetRGB(255, 255, 255);
01404         fgshortcolor = GFX_GetRGB(191, 191, 255);
01405     }
01406 
01407     if (SDL_MUSTLOCK(sdl.surface))
01408         SDL_LockSurface(sdl.surface);
01409 
01410     MenuDrawRect(screenBox.x, screenBox.y, screenBox.w, screenBox.h, bgcolor);
01411     if (checkBox.w != 0 && checkBox.h != 0) {
01412         const char *str = status.checked ? "\xFB" : " ";
01413 
01414         MenuDrawText(screenBox.x+checkBox.x, screenBox.y+checkBox.y, str, fgcheckcolor);
01415     }
01416     if (textBox.w != 0 && textBox.h != 0)
01417         MenuDrawText(screenBox.x+textBox.x, screenBox.y+textBox.y, text.c_str(), fgcolor);
01418     if (shortBox.w != 0 && shortBox.h != 0)
01419         MenuDrawText(screenBox.x+shortBox.x, screenBox.y+shortBox.y, shortcut_text.c_str(), fgshortcolor);
01420 
01421     if (type == submenu_type_id && borderTop/*not toplevel*/)
01422         MenuDrawText((int)((int)screenBox.x+(int)screenBox.w - (int)mainMenu.fontCharWidth - 1), (int)((int)screenBox.y+(int)textBox.y), "\x10", fgcheckcolor);
01423 
01424     if (type == separator_type_id)
01425         MenuDrawRect((int)screenBox.x, (int)screenBox.y + ((int)screenBox.h/2), (int)screenBox.w, 1, fgcolor);
01426     else if (type == vseparator_type_id)
01427         MenuDrawRect((int)screenBox.x + ((int)screenBox.w/2), (int)screenBox.y, 1, (int)screenBox.h, fgcolor);
01428 
01429     if (SDL_MUSTLOCK(sdl.surface))
01430         SDL_UnlockSurface(sdl.surface);
01431 }
01432 
01433 void DOSBoxMenu::displaylist::DrawDisplayList(DOSBoxMenu &menu,bool updateScreen) {
01434     for (auto &id : disp_list) {
01435         DOSBoxMenu::item &item = menu.get_item(id);
01436 
01437         item.drawMenuItem(menu);
01438         if (updateScreen) item.updateScreenFromItem(menu);
01439     }
01440 }
01441 
01442 bool DOSBox_isMenuVisible(void);
01443 
01444 void GFX_DrawSDLMenu(DOSBoxMenu &menu,DOSBoxMenu::displaylist &dl) 
01445 {
01446     if (menu.needsRedraw() && DOSBox_isMenuVisible() && (!sdl.updating || OpenGL_using()) && !sdl.desktop.fullscreen) {
01447         if (!OpenGL_using()) {
01448             if (SDL_MUSTLOCK(sdl.surface))
01449                 SDL_LockSurface(sdl.surface);
01450         }
01451 
01452         if (&dl == &menu.display_list) { /* top level menu, draw background */
01453             MenuDrawRect(menu.menuBox.x, menu.menuBox.y, menu.menuBox.w, menu.menuBox.h - 1, GFX_GetRGB(63, 63, 63));
01454             MenuDrawRect(menu.menuBox.x, menu.menuBox.y + menu.menuBox.h - 1, menu.menuBox.w, 1, GFX_GetRGB(31, 31, 31));
01455         }
01456 
01457         if (!OpenGL_using()) {
01458             if (SDL_MUSTLOCK(sdl.surface))
01459                 SDL_UnlockSurface(sdl.surface);
01460         }
01461 
01462 #if 0
01463         LOG_MSG("menudraw %u",(unsigned int)SDL_GetTicks());
01464 #endif
01465 
01466         menu.clearRedraw();
01467         menu.display_list.DrawDisplayList(menu,/*updateScreen*/false);
01468 
01469         if (!OpenGL_using()) {
01470 #if defined(C_SDL2)
01471             SDL_UpdateWindowSurfaceRects( sdl.window, &menu.menuBox, 1 );
01472 #else
01473             SDL_UpdateRects( sdl.surface, 1, &menu.menuBox );
01474 #endif
01475         }
01476     }
01477 }
01478 #endif
01479 
01480 void RENDER_Reset(void);
01481 
01482 Bitu GFX_SetSize(Bitu width, Bitu height, Bitu flags, double scalex, double scaley, GFX_CallBack_t callback) 
01483 {
01484     if (width == 0 || height == 0) {
01485         E_Exit("GFX_SetSize with width=%d height=%d zero dimensions not allowed",(int)width,(int)height);
01486         return 0;
01487     }
01488 
01489     if (sdl.updating)
01490         GFX_EndUpdate( 0 );
01491 
01492     sdl.must_redraw_all = true;
01493 
01494     sdl.draw.width = width;
01495     sdl.draw.height = height;
01496     sdl.draw.flags = flags;
01497     sdl.draw.callback = callback;
01498     sdl.draw.scalex = scalex;
01499     sdl.draw.scaley = scaley;
01500 
01501     LOG(LOG_MISC,LOG_DEBUG)("GFX_SetSize %ux%u flags=0x%x scale=%.3fx%.3f",
01502         (unsigned int)width,(unsigned int)height,
01503         (unsigned int)flags,
01504         scalex,scaley);
01505 
01506     Bitu bpp = 0;
01507     Bitu retFlags = 0;
01508 
01509     if (sdl.blit.surface) {
01510         SDL_FreeSurface(sdl.blit.surface);
01511         sdl.blit.surface=0;
01512     }
01513 
01514     switch (sdl.desktop.want_type) {
01515         case SCREEN_SURFACE:
01516             retFlags = OUTPUT_SURFACE_SetSize();
01517             break;
01518 
01519 #if C_OPENGL
01520         case SCREEN_OPENGL:
01521             retFlags = OUTPUT_OPENGL_SetSize();
01522             break;
01523 #endif
01524 
01525 #if C_DIRECT3D
01526         case SCREEN_DIRECT3D: 
01527             retFlags = OUTPUT_DIRECT3D_SetSize();
01528             break;
01529 #endif
01530 
01531         default:
01532             // we should never reach here
01533             retFlags = 0;
01534             break;
01535     }
01536 
01537     if (!retFlags)
01538     {
01539         if (sdl.desktop.want_type != SCREEN_SURFACE)
01540         {
01541             // try falling back down to surface
01542             OUTPUT_SURFACE_Select();
01543             retFlags = OUTPUT_SURFACE_SetSize();
01544         }
01545         if (retFlags == 0)
01546             LOG_MSG("SDL:Failed everything including falling back to surface in GFX_GetSize"); // completely failed it seems
01547     }
01548 
01549     // we have selected an actual desktop type
01550     sdl.desktop.type = sdl.desktop.want_type;
01551 
01552     GFX_LogSDLState();
01553 
01554     if (retFlags) 
01555         GFX_Start();
01556 
01557     if (!sdl.mouse.autoenable)
01558         SDL_ShowCursor(sdl.mouse.autolock?SDL_DISABLE:SDL_ENABLE);
01559 
01560     UpdateWindowDimensions();
01561 
01562     return retFlags;
01563 }
01564 
01565 #if defined(WIN32) && !defined(HX_DOS)
01566 // WARNING: Not recommended, there is danger you cannot exit emulator because mouse+keyboard are taken
01567 static bool enable_hook_everything = false;
01568 #endif
01569 
01570 // Whether or not to hook the keyboard and block special keys.
01571 // Setting this is recommended so that your keyboard is fully usable in the guest OS when you
01572 // enable the mouse+keyboard capture. But hooking EVERYTHING is not recommended because there is a
01573 // danger you become trapped in the DOSBox emulator!
01574 static bool enable_hook_special_keys = true;
01575 
01576 #if defined(WIN32) && !defined(HX_DOS)
01577 // Whether or not to hook Num/Scroll/Caps lock in order to give the guest OS full control of the
01578 // LEDs on the keyboard (i.e. the LEDs do not change until the guest OS changes their state).
01579 // This flag also enables code to set the LEDs to guest state when setting mouse+keyboard capture,
01580 // and restoring LED state when releasing capture.
01581 static bool enable_hook_lock_toggle_keys = true;
01582 #endif
01583 
01584 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
01585 // and this is where we store host LED state when capture is set.
01586 static bool on_capture_num_lock_was_on = true; // reasonable guess
01587 static bool on_capture_scroll_lock_was_on = false;
01588 static bool on_capture_caps_lock_was_on = false;
01589 #endif
01590 
01591 static bool exthook_enabled = false;
01592 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
01593 static HHOOK exthook_winhook = NULL;
01594 
01595 #if !defined(__MINGW32__)
01596 extern "C" void SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(unsigned char x);
01597 #endif
01598 
01599 static LRESULT CALLBACK WinExtHookKeyboardHookProc(int nCode,WPARAM wParam,LPARAM lParam) {
01600     if (nCode == HC_ACTION) {
01601         HWND myHwnd = GetHWND();
01602 
01603         if (exthook_enabled && GetFocus() == myHwnd) { /* intercept only if DOSBox-X is the focus and the keyboard is hooked */
01604             if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN || wParam == WM_SYSKEYUP || wParam == WM_KEYUP) {
01605                 KBDLLHOOKSTRUCT *st_hook = (KBDLLHOOKSTRUCT*)lParam;
01606 
01607                 if (st_hook->flags & LLKHF_INJECTED) {
01608                     // injected keys are automatically allowed, especially if we are injecting keyboard input into ourself
01609                     // to control Num/Scroll/Caps Lock LEDs. If we don't check this we cannot control the LEDs. Injecting
01610                     // keydown/keyup for Num Lock is the only means provided by Windows to control those LEDs.
01611                 }
01612                 else if (st_hook->vkCode == VK_MENU/*alt*/ || st_hook->vkCode == VK_CONTROL ||
01613                     st_hook->vkCode == VK_LSHIFT || st_hook->vkCode == VK_RSHIFT) {
01614                     // always allow modifier keys through, so other applications are not left with state inconsistent from
01615                     // actual keyboard state.
01616                 }
01617                 else {
01618                     bool nopass = enable_hook_everything; // if the user wants us to hook ALL keys then that's where this signals it
01619                     bool alternate_message = false; // send as WM_USER+0x100 instead of WM_KEYDOWN
01620 
01621                     if (!nopass) {
01622                         // hook only certain keys Windows is likely to act on by itself.
01623 
01624                         // FIXME: Hooking the keyboard does NOT prevent Fn+SPACE (zoom) from triggering screen resolution
01625                         //        changes in Windows 10! How do we stop that?
01626 
01627                         // FIXME: It might be nice to let the user decide whether or not Print Screen is intercepted.
01628 
01629                         // TODO: We do not hook the volume up/down/mute keys. This is to be kind to the user. They may
01630                         // appreciate the ability to dial down the volume if a loud DOS program comes up. But
01631                         // if the user WANTS us to, we should allow hooking those keys.
01632 
01633                         // TODO: Allow (if instructed) hooking the VK_SLEEP key so pushing the sleep key (the
01634                         // one with the icon of the moon on Microsoft keyboards) can be sent instead to the
01635                         // guest OS. Also add code where if we're not hooking the key, then we should listen
01636                         // for signals the guest OS is suspending or hibernating and auto-disconnect the
01637                         // mouse capture and keyboard hook.
01638 
01639                         switch (st_hook->vkCode) {
01640                         case VK_LWIN:   // left Windows key (normally triggers Start menu)
01641                         case VK_RWIN:   // right Windows key (normally triggers Start menu)
01642                         case VK_APPS:   // Application key (normally open to the user, but just in case)
01643                         case VK_PAUSE:  // pause key
01644                         case VK_SNAPSHOT: // print screen
01645                         case VK_TAB:    // try to catch ALT+TAB too (not blocking VK_TAB will allow host OS to switch tasks)
01646                         case VK_ESCAPE: // try to catch CTRL+ESC as well (so Windows 95 Start Menu is accessible)
01647                         case VK_SPACE:  // and space (catching VK_ZOOM isn't enough to prevent Windows 10 from changing res)
01648                         // these keys have no meaning to DOSBox and so we hook them by default to allow the guest OS to use them
01649                         case VK_BROWSER_BACK: // Browser Back key
01650                         case VK_BROWSER_FORWARD: // Browser Forward key
01651                         case VK_BROWSER_REFRESH: // Browser Refresh key
01652                         case VK_BROWSER_STOP: // Browser Stop key
01653                         case VK_BROWSER_SEARCH: // Browser Search key
01654                         case VK_BROWSER_FAVORITES: // Browser Favorites key
01655                         case VK_BROWSER_HOME: // Browser Start and Home key
01656                         case VK_MEDIA_NEXT_TRACK: // Next Track key
01657                         case VK_MEDIA_PREV_TRACK: // Previous Track key
01658                         case VK_MEDIA_STOP: // Stop Media key
01659                         case VK_MEDIA_PLAY_PAUSE: // Play / Pause Media key
01660                         case VK_LAUNCH_MAIL: // Start Mail key
01661                         case VK_LAUNCH_MEDIA_SELECT: // Select Media key
01662                         case VK_LAUNCH_APP1: // Start Application 1 key
01663                         case VK_LAUNCH_APP2: // Start Application 2 key
01664                         case VK_PLAY: // Play key
01665                         case VK_ZOOM: // Zoom key (the (+) magnifying glass keyboard shortcut laptops have these days on the spacebar?)
01666                             nopass = true;
01667                             break;
01668 
01669                             // IME Hiragana key, otherwise inaccessible to us
01670                         case 0xF2:
01671                             nopass = true; // FIXME: This doesn't (yet) cause a SDL key event.
01672                             break;
01673 
01674                             // we allow hooking Num/Scroll/Caps Lock keys so that pressing them does not toggle the LED.
01675                             // we then take Num/Scroll/Caps LED state from the guest and let THAT control the LED state.
01676                         case VK_CAPITAL:
01677                         case VK_NUMLOCK:
01678                         case VK_SCROLL:
01679                             nopass = enable_hook_lock_toggle_keys;
01680                             alternate_message = true;
01681                             break;
01682                         }
01683                     }
01684 
01685                     if (nopass) {
01686                         // convert WM_KEYDOWN/WM_KEYUP if obfuscating the message to distinguish between real and injected events
01687                         if (alternate_message) {
01688                             if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
01689                                 wParam = WM_USER + 0x100;
01690                             else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
01691                                 wParam = WM_USER + 0x101;
01692                         }
01693 
01694                         DWORD lParam =
01695                             (st_hook->scanCode << 8U) +
01696                             ((st_hook->flags & LLKHF_EXTENDED) ? 0x01000000 : 0) +
01697                             ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) ? 0xC0000000 : 0);
01698 
01699                         // catch the keystroke, post it to ourself, do not pass it on
01700                         PostMessage(myHwnd, (UINT)wParam, st_hook->vkCode, lParam);
01701                         return TRUE;
01702                     }
01703                 }
01704             }
01705         }
01706     }
01707 
01708     return CallNextHookEx(exthook_winhook, nCode, wParam, lParam);
01709 }
01710 
01711 // Microsoft doesn't have an outright "set toggle key state" call, they expect you
01712 // to know the state and then fake input to toggle. Blegh. Fine.
01713 void WinSetKeyToggleState(unsigned int vkCode, bool state) {
01714     bool curState = (GetKeyState(vkCode) & 1) ? true : false;
01715     INPUT inps;
01716 
01717     // if we're already in that state, then there is nothing to do.
01718     if (curState == state) return;
01719 
01720     // fake keyboard input.
01721     memset(&inps, 0, sizeof(inps));
01722     inps.type = INPUT_KEYBOARD;
01723     inps.ki.wVk = vkCode;
01724     inps.ki.dwFlags = KEYEVENTF_EXTENDEDKEY; // pressed, use wVk.
01725     SendInput(1, &inps, sizeof(INPUT));
01726 
01727     memset(&inps, 0, sizeof(inps));
01728     inps.type = INPUT_KEYBOARD;
01729     inps.ki.wVk = vkCode;
01730     inps.ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; // release, use wVk.
01731     SendInput(1, &inps, sizeof(INPUT));
01732 }
01733 #endif
01734 
01735 Bitu Keyboard_Guest_LED_State();
01736 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */);
01737 
01738 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */) {
01739     (void)led_state;//POSSIBLY UNUSED
01740 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) /* Microsoft Windows */
01741     if (exthook_enabled) { // ONLY if ext hook is enabled, else we risk infinite loops with keyboard events
01742         //WinSetKeyToggleState(VK_NUMLOCK, !!(led_state & 2));
01743         //WinSetKeyToggleState(VK_SCROLL, !!(led_state & 1));
01744         //WinSetKeyToggleState(VK_CAPITAL, !!(led_state & 4));
01745     }
01746 #endif
01747 }
01748 
01749 void DoExtendedKeyboardHook(bool enable) {
01750     if (exthook_enabled == enable)
01751         return;
01752 
01753 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
01754     if (enable) {
01755         if (!exthook_winhook) {
01756             exthook_winhook = SetWindowsHookEx(WH_KEYBOARD_LL, WinExtHookKeyboardHookProc, GetModuleHandle(NULL), 0);
01757             if (exthook_winhook == NULL) return;
01758         }
01759 
01760         // it's on
01761         exthook_enabled = enable;
01762 
01763         // flush out and handle pending keyboard I/O
01764         {
01765             MSG msg;
01766 
01767             while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
01768                 TranslateMessage(&msg);
01769                 DispatchMessage(&msg);
01770             }
01771         }
01772 
01773 #if !defined(__MINGW32__)
01774         // Enable the SDL hack for Win32 to handle Num/Scroll/Caps
01775         SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(1);
01776 #endif
01777 
01778         // if hooking Num/Scroll/Caps Lock then record the toggle state of those keys.
01779         // then read from the keyboard emulation the LED state set by the guest and apply it to the host keyboard.
01780         if (enable_hook_lock_toggle_keys) {
01781             // record state
01782             on_capture_num_lock_was_on = (GetKeyState(VK_NUMLOCK) & 1) ? true : false;
01783             on_capture_scroll_lock_was_on = (GetKeyState(VK_SCROLL) & 1) ? true : false;
01784             on_capture_caps_lock_was_on = (GetKeyState(VK_CAPITAL) & 1) ? true : false;
01785             // change to guest state (FIXME: Read emulated keyboard state and apply!)
01786             UpdateKeyboardLEDState(Keyboard_Guest_LED_State());
01787         }
01788     }
01789     else {
01790         if (exthook_winhook) {
01791             if (enable_hook_lock_toggle_keys) {
01792                 // restore state
01793                 //WinSetKeyToggleState(VK_NUMLOCK, on_capture_num_lock_was_on);
01794                 //WinSetKeyToggleState(VK_SCROLL, on_capture_scroll_lock_was_on);
01795                 //WinSetKeyToggleState(VK_CAPITAL, on_capture_caps_lock_was_on);
01796             }
01797 
01798             {
01799                 MSG msg;
01800 
01801                 // before we disable the SDL hack make sure we flush out and handle any pending keyboard events.
01802                 // if we don't do this the posted Num/Scroll/Caps events will stay in the queue and will be handled
01803                 // by SDL after turning off the toggle key hack.
01804                 Sleep(1); // make sure Windows posts the keystrokes
01805                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
01806                     TranslateMessage(&msg);
01807                     DispatchMessage(&msg);
01808                 }
01809             }
01810 
01811 #if !defined(__MINGW32__)
01812             // Disable the SDL hack for Win32 to handle Num/Scroll/Caps
01813             SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(0);
01814 #endif
01815 
01816             UnhookWindowsHookEx(exthook_winhook);
01817             exthook_winhook = NULL;
01818         }
01819 
01820         exthook_enabled = enable;
01821     }
01822 #endif
01823 }
01824 
01825 void GFX_ReleaseMouse(void) {
01826     if (sdl.mouse.locked)
01827         GFX_CaptureMouse();
01828 }
01829 
01830 void GFX_CaptureMouse(void) {
01831     GFX_CaptureMouse(!sdl.mouse.locked);
01832 }
01833 
01834 void GFX_CaptureMouse(bool capture) {
01835     sdl.mouse.locked=capture;
01836     if (sdl.mouse.locked) {
01837 #if defined(C_SDL2)
01838         SDL_SetRelativeMouseMode(SDL_TRUE);
01839 #else
01840         SDL_WM_GrabInput(SDL_GRAB_ON);
01841 #endif
01842         if (enable_hook_special_keys) DoExtendedKeyboardHook(true);
01843         SDL_ShowCursor(SDL_DISABLE);
01844     } else {
01845         DoExtendedKeyboardHook(false);
01846 #if defined(C_SDL2)
01847         SDL_SetRelativeMouseMode(SDL_FALSE);
01848 #else
01849         SDL_WM_GrabInput(SDL_GRAB_OFF);
01850 #endif
01851         if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE);
01852     }
01853         mouselocked=sdl.mouse.locked;
01854 
01855 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
01856         if (sdl.mouse.locked) {
01857             void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id);
01858             void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id);
01859 
01860             GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle);
01861             GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle);
01862         }
01863 #endif
01864 
01865     /* keep the menu updated (it might not exist yet) */
01866     if (mainMenu.item_exists("mapper_capmouse"))
01867         mainMenu.get_item("mapper_capmouse").check(sdl.mouse.locked).refresh_item(mainMenu);
01868 }
01869 
01870 void GFX_UpdateSDLCaptureState(void) {
01871     if (sdl.mouse.locked) {
01872 #if defined(C_SDL2)
01873         SDL_SetRelativeMouseMode(SDL_TRUE);
01874 #else
01875         SDL_WM_GrabInput(SDL_GRAB_ON);
01876 #endif
01877         if (enable_hook_special_keys) DoExtendedKeyboardHook(true);
01878         SDL_ShowCursor(SDL_DISABLE);
01879     } else {
01880         DoExtendedKeyboardHook(false);
01881 #if defined(C_SDL2)
01882         SDL_SetRelativeMouseMode(SDL_FALSE);
01883 #else
01884         SDL_WM_GrabInput(SDL_GRAB_OFF);
01885 #endif
01886         if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE);
01887     }
01888     CPU_Reset_AutoAdjust();
01889     GFX_SetTitle(-1,-1,-1,false);
01890 }
01891 
01892 #if WIN32
01893 void CaptureMouseNotifyWin32(bool lck)
01894 {
01895     switch (sdl.mouse.autolock_feedback)
01896     {
01897     case AUTOLOCK_FEEDBACK_NONE: break;
01898     case AUTOLOCK_FEEDBACK_BEEP:
01899     {
01900         const auto lo = 1000;
01901         const auto hi = 2000;
01902         const auto t1 = 50;
01903         const auto t2 = 25;
01904         const auto f1 = lck ? hi : lo;
01905         const auto f2 = lck ? lo : hi;
01906         const auto tt = lck ? t1 : t2;
01907         Beep(f1, tt);
01908         Beep(f2, tt);
01909     }
01910     break;
01911     case AUTOLOCK_FEEDBACK_FLASH:
01912     {
01913 # if !defined(HX_DOS)
01914         const auto cnt = lck ? 4 : 2;
01915         const auto tim = lck ? 80 : 40;
01916         const auto wnd = GetHWND();
01917         if (wnd != nullptr)
01918         {
01919             FLASHWINFO fi;
01920             fi.cbSize    = sizeof(FLASHWINFO);
01921             fi.hwnd      = wnd;
01922             fi.dwFlags   = FLASHW_CAPTION;
01923             fi.uCount    = cnt;
01924             fi.dwTimeout = tim;
01925             FlashWindowEx(&fi);
01926         }
01927 # endif
01928         break;
01929     }
01930     default: ;
01931     }
01932 }
01933 #endif
01934 
01935 void CaptureMouseNotify()
01936 {
01937     CaptureMouseNotify(sdl.mouse.locked);
01938 }
01939 
01940 void CaptureMouseNotify(bool capture)
01941 {
01942 #if WIN32
01943     CaptureMouseNotifyWin32(capture);
01944 #else
01945     // TODO
01946 #endif
01947 }
01948 
01949 static void CaptureMouse(bool pressed) {
01950     if (!pressed)
01951         return;
01952 
01953     CaptureMouseNotify();
01954     GFX_CaptureMouse();
01955 }
01956 
01957 #if defined (WIN32)
01958 STICKYKEYS stick_keys = {sizeof(STICKYKEYS), 0};
01959 void sticky_keys(bool restore){
01960     static bool inited = false;
01961     if (!inited){
01962         inited = true;
01963         SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0);
01964     } 
01965     if (restore) {
01966         SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0);
01967         return;
01968     }
01969     //Get current sticky keys layout:
01970     STICKYKEYS s = {sizeof(STICKYKEYS), 0};
01971     SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0);
01972     if ( !(s.dwFlags & SKF_STICKYKEYSON)) { //Not on already
01973         s.dwFlags &= ~SKF_HOTKEYACTIVE;
01974         SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0);
01975     }
01976 }
01977 #else
01978 #define sticky_keys(a)
01979 #endif
01980 
01981 void GetDesktopResolution(int* width, int* height)
01982 {
01983 #ifdef WIN32
01984     RECT rDdesk;
01985     auto hDesk = GetDesktopWindow();
01986     GetWindowRect(hDesk, &rDdesk);
01987     *width = rDdesk.right - rDdesk.left;
01988     *height = rDdesk.bottom - rDdesk.top;
01989 #elif defined(LINUX)
01990     void Linux_GetDesktopResolution(int *width,int *height);
01991     Linux_GetDesktopResolution(width,height); /* this is MESSY but there's too much namespace collision going on here */
01992 #else
01993     *width = 1024; // guess
01994     *height = 768;
01995 #endif
01996 }
01997 
01998 void res_init(void) {
01999     Section * sec = control->GetSection("sdl");
02000     Section_prop * section=static_cast<Section_prop *>(sec);
02001     sdl.desktop.full.fixed=false;
02002     const char* fullresolution=section->Get_string("fullresolution");
02003     sdl.desktop.full.width  = 0; sdl.desktop.full.height = 0;
02004     if(fullresolution && *fullresolution) {
02005         char res[100];
02006         safe_strncpy( res, fullresolution, sizeof( res ));
02007         fullresolution = lowcase (res);//so x and X are allowed
02008         if (strcmp(fullresolution,"original")) {
02009             sdl.desktop.full.fixed = true;
02010             if (strcmp(fullresolution,"desktop")) { //desktop = 0x0
02011                 char* height = const_cast<char*>(strchr(fullresolution,'x'));
02012                 if(height && * height) {
02013                     *height = 0;
02014                     sdl.desktop.full.height = atoi(height+1);
02015                     sdl.desktop.full.width  = atoi(res);
02016                 }
02017             }
02018         }
02019     }
02020 
02021     sdl.desktop.window.width  = 0;
02022     sdl.desktop.window.height = 0;
02023     const char* windowresolution=section->Get_string("windowresolution");
02024     if(windowresolution && *windowresolution) {
02025         //if(sdl.desktop.type==SCREEN_SURFACE) return;
02026         char res[100];
02027         safe_strncpy( res,windowresolution, sizeof( res ));
02028         windowresolution = lowcase (res);//so x and X are allowed
02029         if(strcmp(windowresolution,"original")) {
02030             char* height = const_cast<char*>(strchr(windowresolution,'x'));
02031             if(height && *height) {
02032                 *height = 0;
02033                 sdl.desktop.window.height = (Bit16u)atoi(height+1);
02034                 sdl.desktop.window.width  = (Bit16u)atoi(res);
02035             }
02036         }
02037     }
02038     sdl.desktop.doublebuf=section->Get_bool("fulldouble");
02039 
02040     int width = 1024;
02041     int height = 768;
02042     
02043     // fullresolution == desktop -> get/set desktop size
02044     auto sdlSection = control->GetSection("sdl");
02045     auto sdlSectionProp = static_cast<Section_prop*>(sdlSection);
02046     auto fullRes = sdlSectionProp->Get_string("fullresolution");
02047     if (!strcmp(fullRes, "desktop")) GetDesktopResolution(&width, &height);
02048     
02049     if (!sdl.desktop.full.width) {
02050         sdl.desktop.full.width=width;
02051     }
02052     if (!sdl.desktop.full.height) {
02053         sdl.desktop.full.height=height;
02054     }
02055     if(sdl.desktop.type==SCREEN_SURFACE && !sdl.desktop.fullscreen) return;
02056     else {
02057         GFX_Stop();
02058         if (sdl.draw.callback)
02059             (sdl.draw.callback)( GFX_CallBackReset );
02060         GFX_Start();
02061     }
02062 }
02063 
02064 void res_input(bool type, const char * res) {
02065     Section* sec = control->GetSection("sdl");
02066     char win_res[11];
02067     if(sec) {
02068         strcpy(win_res,res);
02069         if(type) {
02070             std::string tmp("windowresolution="); tmp.append(win_res);
02071             sec->HandleInputline(tmp);
02072         } else {
02073             std::string tmp("fullresolution="); tmp.append(win_res);
02074             sec->HandleInputline(tmp);
02075         }
02076 
02077         res_init();
02078     }
02079 }
02080 
02081 void change_output(int output) {
02082     GFX_Stop();
02083     Section * sec = control->GetSection("sdl");
02084     Section_prop * section=static_cast<Section_prop *>(sec);
02085     sdl.overscan_width=(unsigned int)section->Get_int("overscan");
02086     UpdateOverscanMenu();
02087 
02088     switch (output) {
02089     case 0:
02090         OUTPUT_SURFACE_Select();
02091         break;
02092     case 1:
02093         OUTPUT_SURFACE_Select();
02094         break;
02095     case 2: /* do nothing */
02096         break;
02097     case 3:
02098 #if C_OPENGL
02099         change_output(2);
02100         OUTPUT_OPENGL_Select();
02101 #if !defined(C_SDL2)
02102         sdl_opengl.bilinear = true;
02103 #endif
02104 #endif
02105         break;
02106     case 4:
02107 #if C_OPENGL
02108         change_output(2);
02109         OUTPUT_OPENGL_Select();
02110 #if !defined(C_SDL2)
02111         sdl_opengl.bilinear = false; //NB
02112 #endif
02113 #endif
02114         break;
02115 #if C_DIRECT3D
02116     case 5:
02117         OUTPUT_DIRECT3D_Select();
02118         break;
02119 #endif
02120     case 6:
02121         break;
02122     case 7:
02123         // do not set want_type
02124         break;
02125     case 8:
02126 #if C_DIRECT3D
02127         if (sdl.desktop.want_type == SCREEN_DIRECT3D) 
02128             OUTPUT_DIRECT3D_Select();
02129 #endif
02130         break;
02131 
02132     default:
02133         LOG_MSG("SDL:Unsupported output device %d, switching back to surface",output);
02134         OUTPUT_SURFACE_Select();
02135         break;
02136     }
02137 
02138     const char* windowresolution=section->Get_string("windowresolution");
02139     if (windowresolution && *windowresolution) 
02140     {
02141         char res[100];
02142         safe_strncpy( res,windowresolution, sizeof( res ));
02143         windowresolution = lowcase (res);//so x and X are allowed
02144         if (strcmp(windowresolution,"original")) 
02145         {
02146             if (output == 0) 
02147             {
02148                 std::string tmp("windowresolution=original");
02149                 sec->HandleInputline(tmp);
02150             }
02151         }
02152     }
02153     res_init();
02154 
02155     if (sdl.draw.callback)
02156         (sdl.draw.callback)( GFX_CallBackReset );
02157 
02158     GFX_SetTitle(CPU_CycleMax,-1,-1,false);
02159     GFX_LogSDLState();
02160 
02161     UpdateWindowDimensions();
02162 }
02163 
02164 void GFX_SwitchFullScreen(void)
02165 {
02166 #if !defined(HX_DOS)
02167     if (sdl.desktop.prevent_fullscreen)
02168         return;
02169 
02170     menu.resizeusing = true;
02171 
02172     sdl.desktop.fullscreen = !sdl.desktop.fullscreen;
02173 
02174     auto full = sdl.desktop.fullscreen;
02175 
02176     // if we're going fullscreen and current scaler exceeds screen size,
02177     // cancel the fullscreen change -> fixes scaler crashes
02178     // TODO this will need further changes to accomodate different outputs (e.g. stretched)
02179     if (full)
02180     {
02181         int width, height;
02182         GetDesktopResolution(&width, &height);
02183         auto width1 = sdl.draw.width;
02184         auto height1 = sdl.draw.height;
02185         if ((unsigned int)width < width1 || (unsigned int)height < height1) {
02186             sdl.desktop.fullscreen = false;
02187             LOG_MSG("WARNING: full screen canceled, surface size (%ix%i) exceeds screen size (%ix%i).",
02188                 width1, height1, width, height);
02189             return;
02190         }
02191     }
02192 
02193     LOG_MSG("INFO: switched to %s mode", full ? "full screen" : "window");
02194 
02195 #if !defined(C_SDL2)
02196     // (re-)assign menu to window
02197     void DOSBox_SetSysMenu(void);
02198     DOSBox_SetSysMenu();
02199 #endif
02200 
02201     // ensure mouse capture when fullscreen || (re-)capture if user said so when windowed
02202     auto locked = sdl.mouse.locked;
02203     if ((full && !locked) || (!full && locked)) GFX_CaptureMouse();
02204 
02205     // disable/enable sticky keys for fullscreen/desktop
02206 #if defined (WIN32)     
02207     sticky_keys(!full);
02208 #endif
02209 
02210     GFX_ResetScreen();
02211 
02212     // set vsync to host
02213     // NOTE why forcing ???
02214 #ifdef WIN32
02215     if (menu.startup) // NOTE should be always true I suppose ???
02216     {
02217         auto vsync = static_cast<Section_prop *>(control->GetSection("vsync"));
02218         if (vsync)
02219         {
02220             auto vsyncMode = vsync->Get_string("vsyncmode");
02221             if (!strcmp(vsyncMode, "host")) SetVal("vsync", "vsyncmode", "host");
02222         }
02223     }
02224 #endif
02225 #endif
02226 }
02227 
02228 static void SwitchFullScreen(bool pressed) {
02229     if (!pressed)
02230         return;
02231 
02232     GFX_LosingFocus();
02233     if (sdl.desktop.lazy_fullscreen) {
02234         LOG_MSG("GFX LF: fullscreen switching not supported");
02235     } else {
02236         GFX_SwitchFullScreen();
02237     }
02238 }
02239 
02240 void GFX_SwitchLazyFullscreen(bool lazy) {
02241     sdl.desktop.lazy_fullscreen=lazy;
02242     sdl.desktop.lazy_fullscreen_req=false;
02243 }
02244 
02245 void GFX_SwitchFullscreenNoReset(void) {
02246     sdl.desktop.fullscreen=!sdl.desktop.fullscreen;
02247 }
02248 
02249 bool GFX_LazyFullscreenRequested(void) {
02250     if (sdl.desktop.lazy_fullscreen) return sdl.desktop.lazy_fullscreen_req;
02251     return false;
02252 }
02253 
02254 bool GFX_GetPreventFullscreen(void) {
02255     return sdl.desktop.prevent_fullscreen;
02256 }
02257 
02258 #if defined(WIN32) && !defined(C_SDL2)
02259 extern "C" unsigned char SDL1_hax_RemoveMinimize;
02260 #endif
02261 
02262 void GFX_PreventFullscreen(bool lockout) {
02263     if (sdl.desktop.prevent_fullscreen != lockout) {
02264         sdl.desktop.prevent_fullscreen = lockout;
02265 #if defined(WIN32) && !defined(C_SDL2)
02266         void DOSBox_SetSysMenu(void);
02267         int Reflect_Menu(void);
02268 
02269         SDL1_hax_RemoveMinimize = lockout ? 1 : 0;
02270 
02271         DOSBox_SetSysMenu();
02272         Reflect_Menu();
02273 #endif
02274     }
02275 }
02276 
02277 void GFX_RestoreMode(void) {
02278     if (sdl.draw.width == 0 || sdl.draw.height == 0)
02279         return;
02280 
02281     GFX_SetSize(sdl.draw.width,sdl.draw.height,sdl.draw.flags,sdl.draw.scalex,sdl.draw.scaley,sdl.draw.callback);
02282     GFX_UpdateSDLCaptureState();
02283     GFX_ResetScreen();
02284 }
02285 
02286 #if !defined(C_SDL2)
02287 static bool GFX_GetSurfacePtrLock = false;
02288 
02289 unsigned char *GFX_GetSurfacePtr(size_t *pitch, unsigned int x, unsigned int y) {
02290     if (sdl.surface->pixels == NULL) {
02291         if (!GFX_GetSurfacePtrLock) {
02292             if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface))
02293                 return NULL;
02294 
02295             GFX_GetSurfacePtrLock = true;
02296         }
02297     }
02298 
02299     *pitch = sdl.surface->pitch;
02300     if (sdl.surface->pixels != NULL) {
02301         unsigned char *p = (unsigned char*)(sdl.surface->pixels);
02302         p += y * sdl.surface->pitch;
02303         p += x * ((unsigned int)sdl.surface->format->BitsPerPixel >> 3U);
02304         return p;
02305     }
02306 
02307     return NULL;
02308 }
02309 
02310 void GFX_ReleaseSurfacePtr(void) {
02311     if (GFX_GetSurfacePtrLock) {
02312         if (SDL_MUSTLOCK(sdl.surface))
02313             SDL_UnlockSurface(sdl.surface);
02314  
02315         GFX_GetSurfacePtrLock = false;
02316     }
02317 }
02318 #endif
02319 
02320 bool GFX_StartUpdate(Bit8u* &pixels,Bitu &pitch) 
02321 {
02322     if (!sdl.active || sdl.updating)
02323         return false;
02324 
02325     switch (sdl.desktop.type) 
02326     {
02327         case SCREEN_SURFACE:
02328             return OUTPUT_SURFACE_StartUpdate(pixels, pitch);
02329 
02330 #if C_OPENGL
02331         case SCREEN_OPENGL:
02332             return OUTPUT_OPENGL_StartUpdate(pixels, pitch);
02333 #endif
02334 
02335 #if C_DIRECT3D
02336         case SCREEN_DIRECT3D:
02337             return OUTPUT_DIRECT3D_StartUpdate(pixels, pitch);
02338 #endif
02339 
02340         default:
02341             break;
02342     }
02343 
02344     return false;
02345 }
02346 
02347 void GFX_OpenGLRedrawScreen(void) {
02348 #if C_OPENGL
02349     if (OpenGL_using()) {
02350         if (sdl_opengl.clear_countdown > 0) {
02351             sdl_opengl.clear_countdown--;
02352             glClearColor (0.0, 0.0, 0.0, 1.0);
02353             glClear(GL_COLOR_BUFFER_BIT);
02354         }
02355 
02356         if (sdl_opengl.pixel_buffer_object) {
02357             glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
02358             glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
02359             glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
02360             glCallList(sdl_opengl.displaylist);
02361         } else {
02362             glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture);
02363             glCallList(sdl_opengl.displaylist);
02364         }
02365     }
02366 #endif
02367 }
02368 
02369 void GFX_EndUpdate(const Bit16u *changedLines) {
02370 #if C_EMSCRIPTEN
02371     emscripten_sleep_with_yield(0);
02372 #endif
02373 
02374     /* don't present our output if 3Dfx is in OpenGL mode */
02375     if (sdl.desktop.prevent_fullscreen)
02376         return;
02377 
02378 #if C_DIRECT3D
02379     // we may have to do forced update in D3D case
02380     if (d3d && d3d->getForceUpdate());
02381     else
02382 #endif
02383     if (!sdl.updating)
02384         return;
02385 
02386     sdl.updating = false;
02387     switch (sdl.desktop.type) 
02388     {
02389         case SCREEN_SURFACE:
02390             OUTPUT_SURFACE_EndUpdate(changedLines);
02391             break;
02392 
02393 #if C_OPENGL
02394         case SCREEN_OPENGL:
02395             OUTPUT_OPENGL_EndUpdate(changedLines);
02396             break;
02397 #endif
02398 
02399 #if C_DIRECT3D
02400         case SCREEN_DIRECT3D:
02401             OUTPUT_DIRECT3D_EndUpdate(changedLines);
02402             break;
02403 #endif
02404 
02405         default:
02406             break;
02407     }
02408 
02409     if (changedLines != NULL) 
02410     {
02411         sdl.must_redraw_all = false;
02412 
02413 #if !defined(C_SDL2)
02414         sdl.surface->flags &= ~((unsigned int)SDL_HAX_NOREFRESH);
02415 #endif
02416 
02417         if (changedLines != NULL && sdl.deferred_resize) 
02418         {
02419             sdl.deferred_resize = false;
02420 #if !defined(C_SDL2)
02421             void GFX_RedrawScreen(Bit32u nWidth, Bit32u nHeight);
02422             GFX_RedrawScreen(sdl.draw.width, sdl.draw.height);
02423 #endif
02424         }
02425         else if (sdl.gfx_force_redraw_count > 0) 
02426         {
02427             void RENDER_CallBack( GFX_CallBackFunctions_t function );
02428             RENDER_CallBack(GFX_CallBackRedraw);
02429             sdl.gfx_force_redraw_count--;
02430         }
02431     }
02432 }
02433 
02434 void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) {
02435     (void)start;
02436     (void)count;
02437     (void)entries;
02438 #if !defined(C_SDL2)
02439     /* I should probably not change the GFX_PalEntry :) */
02440     if (sdl.surface->flags & SDL_HWPALETTE) {
02441         if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) {
02442             E_Exit("SDL:Can't set palette");
02443         }
02444     } else {
02445         if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,(SDL_Color *)entries,start,count)) {
02446             E_Exit("SDL:Can't set palette");
02447         }
02448     }
02449 #endif
02450 }
02451 
02452 Bitu GFX_GetRGB(Bit8u red, Bit8u green, Bit8u blue) {
02453     switch (sdl.desktop.type) {
02454         case SCREEN_SURFACE:
02455             return SDL_MapRGB(sdl.surface->format, red, green, blue);
02456 
02457 #if C_OPENGL
02458         case SCREEN_OPENGL:
02459             return (((unsigned int)blue << 0u) | ((unsigned int)green << 8u) | ((unsigned int)red << 16u)) | (255u << 24u);
02460 #endif
02461 
02462 #if C_DIRECT3D
02463         case SCREEN_DIRECT3D:
02464             return SDL_MapRGB(sdl.surface->format, red, green, blue);
02465 #endif
02466 
02467         default:
02468             break;
02469     }
02470     return 0;
02471 }
02472 
02473 void GFX_Stop() {
02474     if (sdl.updating)
02475         GFX_EndUpdate( 0 );
02476     sdl.active=false;
02477 }
02478 
02479 void GFX_Start() {
02480     sdl.active=true;
02481 }
02482 
02483 static void GUI_ShutDown(Section * /*sec*/) {
02484     GFX_Stop();
02485     if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop );
02486     if (sdl.mouse.locked) GFX_CaptureMouse();
02487     if (sdl.desktop.fullscreen) GFX_SwitchFullScreen();
02488     switch (sdl.desktop.type)
02489     {
02490         case SCREEN_SURFACE:
02491             OUTPUT_SURFACE_Shutdown();
02492             break;
02493 
02494 #if C_OPENGL
02495         case SCREEN_OPENGL:
02496             OUTPUT_OPENGL_Shutdown();
02497             break;
02498 #endif
02499 
02500 #if C_DIRECT3D
02501         case SCREEN_DIRECT3D:
02502             OUTPUT_DIRECT3D_Shutdown();
02503             break;
02504 #endif
02505 
02506         default:
02507                 break;
02508     }
02509 }
02510 
02511 static void SetPriority(PRIORITY_LEVELS level) {
02512 
02513 #if C_SET_PRIORITY
02514 // Do nothing if priorties are not the same and not root, else the highest
02515 // priority can not be set as users can only lower priority (not restore it)
02516 
02517     if((sdl.priority.focus != sdl.priority.nofocus ) &&
02518         (getuid()!=0) ) return;
02519 
02520 #endif
02521     switch (level) {
02522 #ifdef WIN32
02523     case PRIORITY_LEVEL_PAUSE:  // if DOSBox is paused, assume idle priority
02524     case PRIORITY_LEVEL_LOWEST:
02525         SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS);
02526         break;
02527     case PRIORITY_LEVEL_LOWER:
02528         SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS);
02529         break;
02530     case PRIORITY_LEVEL_NORMAL:
02531         SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS);
02532         break;
02533     case PRIORITY_LEVEL_HIGHER:
02534         SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);
02535         break;
02536     case PRIORITY_LEVEL_HIGHEST:
02537         SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
02538         break;
02539 #elif C_SET_PRIORITY
02540 /* Linux use group as dosbox has mulitple threads under linux */
02541     case PRIORITY_LEVEL_PAUSE:  // if DOSBox is paused, assume idle priority
02542     case PRIORITY_LEVEL_LOWEST:
02543         setpriority (PRIO_PGRP, 0,PRIO_MAX);
02544         break;
02545     case PRIORITY_LEVEL_LOWER:
02546         setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/3));
02547         break;
02548     case PRIORITY_LEVEL_NORMAL:
02549         setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/2));
02550         break;
02551     case PRIORITY_LEVEL_HIGHER:
02552         setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/5) );
02553         break;
02554     case PRIORITY_LEVEL_HIGHEST:
02555         setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/4) );
02556         break;
02557 #endif
02558     default:
02559         break;
02560     }
02561 }
02562 
02563 extern Bit8u int10_font_14[256 * 14];
02564 static void OutputString(Bitu x,Bitu y,const char * text,Bit32u color,Bit32u color2,SDL_Surface * output_surface) {
02565     Bit32u * draw=(Bit32u*)(((Bit8u *)output_surface->pixels)+((y)*output_surface->pitch))+x;
02566     while (*text) {
02567         Bit8u * font=&int10_font_14[(*text)*14];
02568         Bitu i,j;
02569         Bit32u * draw_line=draw;
02570         for (i=0;i<14;i++) {
02571             Bit8u map=*font++;
02572             for (j=0;j<8;j++) {
02573                 if (map & 0x80) *((Bit32u*)(draw_line+j))=color; else *((Bit32u*)(draw_line+j))=color2;
02574                 map<<=1;
02575             }
02576             draw_line+=output_surface->pitch/4;
02577         }
02578         text++;
02579         draw+=8;
02580     }
02581 }
02582 
02583 void ResetSystem(bool pressed) {
02584     if (!pressed) return;
02585 
02586     throw int(3);
02587 }
02588 
02589 ZIPFile savestate_zip;
02590 
02591 void GUI_EXP_LoadState(bool pressed) {
02592     if (!pressed) return;
02593 
02594     LOG_MSG("Loading state... (experimental)");
02595 
02596     if (savestate_zip.open("exsavest.zip",O_RDONLY) < 0) {
02597         LOG_MSG("Unable to open save state");
02598         return;
02599     }
02600 
02601     DispatchVMEvent(VM_EVENT_LOAD_STATE);
02602 
02603     savestate_zip.close();
02604 }
02605 
02606 void GUI_EXP_SaveState(bool pressed) {
02607     if (!pressed) return;
02608 
02609     LOG_MSG("Saving state... (experimental)");
02610 
02611     if (savestate_zip.open("exsavest.zip",O_RDWR|O_CREAT|O_TRUNC) < 0) {
02612         LOG_MSG("Unable to open save state for writing");
02613         return;
02614     }
02615 
02616     DispatchVMEvent(VM_EVENT_SAVE_STATE);
02617 
02618     savestate_zip.writeZIPFooter();
02619     savestate_zip.close();
02620 }
02621 
02622 bool has_GUI_StartUp = false;
02623 
02624 static void GUI_StartUp() {
02625     DOSBoxMenu::item *item;
02626 
02627     if (has_GUI_StartUp) return;
02628     has_GUI_StartUp = true;
02629 
02630     LOG(LOG_GUI,LOG_DEBUG)("Starting GUI");
02631 
02632 #if defined(C_SDL2)
02633     LOG(LOG_GUI,LOG_DEBUG)("This version compiled against SDL 2.x");
02634 #else
02635     LOG(LOG_GUI,LOG_DEBUG)("This version compiled against SDL 1.x");
02636 #endif
02637 
02638     AddExitFunction(AddExitFunctionFuncPair(GUI_ShutDown));
02639 #if !defined(C_SDL2)
02640     GUI_LoadFonts();
02641 #endif
02642 
02643     sdl.active=false;
02644     sdl.updating=false;
02645 #if defined(C_SDL2)
02646     sdl.update_window=true;
02647 #endif
02648 
02649     GFX_SetIcon();
02650 
02651     sdl.desktop.lazy_fullscreen=false;
02652     sdl.desktop.lazy_fullscreen_req=false;
02653     sdl.desktop.prevent_fullscreen=false;
02654 
02655     Section_prop * section=static_cast<Section_prop *>(control->GetSection("sdl"));
02656     assert(section != NULL);
02657 
02658     sdl.desktop.fullscreen=section->Get_bool("fullscreen");
02659     sdl.wait_on_error=section->Get_bool("waitonerror");
02660 
02661     Prop_multival* p=section->Get_multival("priority");
02662     std::string focus = p->GetSection()->Get_string("active");
02663     std::string notfocus = p->GetSection()->Get_string("inactive");
02664 
02665     if      (focus == "lowest")  { sdl.priority.focus = PRIORITY_LEVEL_LOWEST;  }
02666     else if (focus == "lower")   { sdl.priority.focus = PRIORITY_LEVEL_LOWER;   }
02667     else if (focus == "normal")  { sdl.priority.focus = PRIORITY_LEVEL_NORMAL;  }
02668     else if (focus == "higher")  { sdl.priority.focus = PRIORITY_LEVEL_HIGHER;  }
02669     else if (focus == "highest") { sdl.priority.focus = PRIORITY_LEVEL_HIGHEST; }
02670 
02671     if      (notfocus == "lowest")  { sdl.priority.nofocus=PRIORITY_LEVEL_LOWEST;  }
02672     else if (notfocus == "lower")   { sdl.priority.nofocus=PRIORITY_LEVEL_LOWER;   }
02673     else if (notfocus == "normal")  { sdl.priority.nofocus=PRIORITY_LEVEL_NORMAL;  }
02674     else if (notfocus == "higher")  { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHER;  }
02675     else if (notfocus == "highest") { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHEST; }
02676     else if (notfocus == "pause")   {
02677         /* we only check for pause here, because it makes no sense
02678          * for DOSBox to be paused while it has focus
02679          */
02680         sdl.priority.nofocus=PRIORITY_LEVEL_PAUSE;
02681     }
02682 
02683     SetPriority(sdl.priority.focus); //Assume focus on startup
02684     sdl.mouse.locked=false;
02685     mouselocked=false; //Global for mapper
02686     sdl.mouse.requestlock=false;
02687     sdl.desktop.full.fixed=false;
02688     const char* fullresolution=section->Get_string("fullresolution");
02689     sdl.desktop.full.width  = 0;
02690     sdl.desktop.full.height = 0;
02691     if(fullresolution && *fullresolution) {
02692         char res[100];
02693         strncpy( res, fullresolution, sizeof( res ));
02694         fullresolution = lowcase (res);//so x and X are allowed
02695         if (strcmp(fullresolution,"original")) {
02696             sdl.desktop.full.fixed = true;
02697             if (strcmp(fullresolution,"desktop")) { //desktop = 0x0
02698                 char* height = const_cast<char*>(strchr(fullresolution,'x'));
02699                 if (height && * height) {
02700                     *height = 0;
02701                     sdl.desktop.full.height = (Bit16u)atoi(height+1);
02702                     sdl.desktop.full.width  = (Bit16u)atoi(res);
02703                 }
02704             }
02705         }
02706     }
02707 
02708     sdl.desktop.window.width  = 0;
02709     sdl.desktop.window.height = 0;
02710     const char* windowresolution=section->Get_string("windowresolution");
02711     if(windowresolution && *windowresolution) {
02712         char res[100];
02713         strncpy( res,windowresolution, sizeof( res ));
02714         windowresolution = lowcase (res);//so x and X are allowed
02715         if(strcmp(windowresolution,"original")) {
02716             char* height = const_cast<char*>(strchr(windowresolution,'x'));
02717             if(height && *height) {
02718                 *height = 0;
02719                 sdl.desktop.window.height = (Bit16u)atoi(height+1);
02720                 sdl.desktop.window.width  = (Bit16u)atoi(res);
02721             }
02722         }
02723     }
02724     sdl.desktop.doublebuf=section->Get_bool("fulldouble");
02725 #if !defined(C_SDL2)
02726   #if SDL_VERSION_ATLEAST(1, 2, 10)
02727     if (!sdl.desktop.full.width || !sdl.desktop.full.height){
02728         //Can only be done on the very first call! Not restartable.
02729         const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo();
02730         if (vidinfo) {
02731             sdl.desktop.full.width = vidinfo->current_w;
02732             sdl.desktop.full.height = vidinfo->current_h;
02733         }
02734     }
02735   #endif
02736 #endif
02737 
02738     int width=1024;// int height=768;
02739     if (!sdl.desktop.full.width) {
02740         sdl.desktop.full.width=width;
02741     }
02742     if (!sdl.desktop.full.height) {
02743         sdl.desktop.full.height=width;
02744     }
02745     sdl.mouse.autoenable=section->Get_bool("autolock");
02746     if (!sdl.mouse.autoenable) SDL_ShowCursor(SDL_DISABLE);
02747     sdl.mouse.autolock=false;
02748 
02749     const std::string feedback = section->Get_string("autolock_feedback");
02750     if (feedback == "none")
02751         sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_NONE;
02752     else if (feedback == "beep")
02753         sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_BEEP;
02754     else if (feedback == "flash")
02755         sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_FLASH;
02756 
02757     sdl.mouse.sensitivity=(unsigned int)section->Get_int("sensitivity");
02758     std::string output=section->Get_string("output");
02759 
02760     const std::string emulation = section->Get_string("mouse_emulation");
02761     if (emulation == "always")
02762         sdl.mouse.emulation = MOUSE_EMULATION_ALWAYS;
02763     else if (emulation == "locked")
02764         sdl.mouse.emulation = MOUSE_EMULATION_LOCKED;
02765     else if (emulation == "integration")
02766         sdl.mouse.emulation = MOUSE_EMULATION_INTEGRATION;
02767     else if (emulation == "never")
02768         sdl.mouse.emulation = MOUSE_EMULATION_NEVER;
02769 
02770     /* Setup Mouse correctly if fullscreen */
02771     if(sdl.desktop.fullscreen) GFX_CaptureMouse();
02772 
02773 #if C_XBRZ
02774     // initialize xBRZ parameters and check output type for compatibility
02775     xBRZ_Initialize();
02776 
02777     if (sdl_xbrz.enable) {
02778         // xBRZ requirements
02779         if ((output != "surface") && (output != "direct3d") && (output != "opengl") && (output != "openglhq") && (output != "openglnb"))
02780             output = "surface";
02781     }
02782 #endif
02783 
02784     // output type selection
02785     // "overlay" was removed, pre-map to Direct3D or OpenGL or surface
02786     if (output == "overlay") 
02787     {
02788 #if C_DIRECT3D
02789         output = "direct3d";
02790 #elif C_OPENGL
02791         output = "opengl";
02792 #else
02793         output = "surface";
02794 #endif
02795     }
02796 
02797     if (output == "surface") 
02798     {
02799         OUTPUT_SURFACE_Select();
02800     } 
02801     else if (output == "ddraw") 
02802     {
02803         OUTPUT_SURFACE_Select();
02804 #if C_OPENGL
02805     } 
02806     else if (output == "opengl" || output == "openglhq") 
02807     {
02808         OUTPUT_OPENGL_Select();
02809         sdl_opengl.bilinear = true;
02810     }
02811     else if (output == "openglnb") 
02812     {
02813         OUTPUT_OPENGL_Select();
02814         sdl_opengl.bilinear = false;
02815 #endif
02816 #if C_DIRECT3D
02817     } 
02818     else if (output == "direct3d") 
02819     {
02820         OUTPUT_DIRECT3D_Select();
02821 #if LOG_D3D
02822         LOG_MSG("SDL:Direct3D activated");
02823 #endif
02824 #endif
02825     } 
02826     else 
02827     {
02828         LOG_MSG("SDL:Unsupported output device %s, switching back to surface",output.c_str());
02829         OUTPUT_SURFACE_Select(); // should not reach there anymore
02830     }
02831 
02832     sdl.overscan_width=(unsigned int)section->Get_int("overscan");
02833 //  sdl.overscan_color=section->Get_int("overscancolor");
02834 
02835 #if defined(C_SDL2)
02836     /* Initialize screen for first time */
02837     if (!GFX_SetSDLSurfaceWindow(640,400))
02838         E_Exit("Could not initialize video: %s",SDL_GetError());
02839     sdl.surface = SDL_GetWindowSurface(sdl.window);
02840 //    SDL_Rect splash_rect=GFX_GetSDLSurfaceSubwindowDims(640,400);
02841     sdl.desktop.pixelFormat = SDL_GetWindowPixelFormat(sdl.window);
02842     LOG_MSG("SDL:Current window pixel format: %s", SDL_GetPixelFormatName(sdl.desktop.pixelFormat));
02843     sdl.desktop.bpp=8*SDL_BYTESPERPIXEL(sdl.desktop.pixelFormat);
02844     if (SDL_BITSPERPIXEL(sdl.desktop.pixelFormat) == 24)
02845         LOG_MSG("SDL: You are running in 24 bpp mode, this will slow down things!");
02846 #else
02847     /* Initialize screen for first time */
02848     sdl.surface=SDL_SetVideoMode(640,400,0,SDL_RESIZABLE);
02849     if (sdl.surface == NULL) E_Exit("Could not initialize video: %s",SDL_GetError());
02850     sdl.deferred_resize = false;
02851     sdl.must_redraw_all = true;
02852     sdl.desktop.bpp=sdl.surface->format->BitsPerPixel;
02853     if (sdl.desktop.bpp==24)
02854         LOG_MSG("SDL:You are running in 24 bpp mode, this will slow down things!");
02855 #endif
02856 
02857     GFX_LogSDLState();
02858     GFX_Stop();
02859 
02860 #if defined(C_SDL2)
02861     SDL_SetWindowTitle(sdl.window,"DOSBox");
02862 #else
02863     SDL_WM_SetCaption("DOSBox",VERSION);
02864 #endif
02865 
02866     /* Please leave the Splash screen stuff in working order in DOSBox. We spend a lot of time making DOSBox. */
02867     //ShowSplashScreen();   /* I will keep the splash screen alive. But now, the BIOS will do it --J.C. */
02868 
02869     /* Get some Event handlers */
02870 #if defined(__WIN32__) && !defined(C_SDL2)
02871     MAPPER_AddHandler(ToggleMenu,MK_return,MMOD1|MMOD2,"togglemenu","ToggleMenu");
02872 #endif // WIN32
02873     MAPPER_AddHandler(ResetSystem, MK_r, MMODHOST, "reset", "Reset", &item); /* Host+R (Host+CTRL+R acts funny on my Linux system) */
02874     item->set_text("Reset guest system");
02875 
02876 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten
02877     MAPPER_AddHandler(KillSwitch,MK_f9,MMOD1,"shutdown","ShutDown", &item); /* KEEP: Most DOSBox-X users may have muscle memory for this */
02878     item->set_text("Quit");
02879 #endif
02880 
02881     MAPPER_AddHandler(CaptureMouse,MK_f10,MMOD1,"capmouse","Cap Mouse", &item); /* KEEP: Most DOSBox-X users may have muscle memory for this */
02882     item->set_text("Capture mouse");
02883 
02884     MAPPER_AddHandler(SwitchFullScreen,MK_f,MMODHOST,"fullscr","Fullscreen", &item);
02885     item->set_text("Toggle fullscreen");
02886 
02887 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten
02888     MAPPER_AddHandler(Restart,MK_nothing,0,"restart","Restart", &item); /* This is less useful, and now has no default binding */
02889     item->set_text("Restart DOSBox-X");
02890 #endif
02891 
02892     void PasteClipboard(bool bPressed); // emendelson from dbDOS adds MMOD2 to this for Ctrl-Alt-F5 for PasteClipboard
02893     MAPPER_AddHandler(PasteClipboard, MK_nothing, 0, "paste", "Paste Clipboard"); //end emendelson
02894 #if C_DEBUG
02895     /* Pause binds with activate-debugger */
02896     MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD1, "pause", "Pause");
02897 #else
02898     MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD2, "pause", "Pause");
02899 #endif
02900 #if !defined(C_SDL2)
02901     MAPPER_AddHandler(&GUI_Run, MK_nothing, 0, "gui", "ShowGUI", &item);
02902     item->set_text("Configuration GUI");
02903 
02904     MAPPER_AddHandler(&GUI_ResetResize, MK_nothing, 0, "resetsize", "ResetSize", &item);
02905     item->set_text("Reset window size");
02906 #endif
02907 
02908     /* EXPERIMENTAL!!!! */
02909     MAPPER_AddHandler(&GUI_EXP_SaveState, MK_f1, MMODHOST, "exp_savestate", "EX:SvState", &item);
02910     item->set_text("Save State (EXPERIMENTAL)");
02911 
02912     /* EXPERIMENTAL!!!! */
02913     MAPPER_AddHandler(&GUI_EXP_LoadState, MK_f2, MMODHOST, "exp_loadstate", "EX:LdState", &item);
02914     item->set_text("Load State (EXPERIMENTAL)");
02915 
02916     UpdateWindowDimensions();
02917 }
02918 
02919 void Mouse_AutoLock(bool enable) {
02920     if (sdl.mouse.autolock == enable)
02921         return;
02922 
02923     sdl.mouse.autolock=enable;
02924     if (sdl.mouse.autoenable) sdl.mouse.requestlock=enable;
02925     else {
02926         SDL_ShowCursor(enable?SDL_DISABLE:SDL_ENABLE);
02927         sdl.mouse.requestlock=false;
02928     }
02929 }
02930 
02931 bool Mouse_IsLocked()
02932 {
02933         return sdl.mouse.locked;
02934 }
02935 
02936 static void RedrawScreen(Bit32u nWidth, Bit32u nHeight) {
02937     (void)nWidth;//UNUSED
02938     (void)nHeight;//UNUSED
02939 //  int width;
02940 //  int height;
02941 #ifdef __WIN32__
02942 //   width=sdl.clip.w; 
02943 //   height=sdl.clip.h;
02944 #else
02945 //  width=sdl.draw.width; 
02946 //  height=sdl.draw.height;
02947 #endif
02948     void RENDER_CallBack( GFX_CallBackFunctions_t function );
02949 #if 0
02950     while (sdl.desktop.fullscreen) {
02951         int temp_size;
02952         temp_size=render.scale.size;
02953         if(!sdl.desktop.fullscreen) { render.scale.size=temp_size; RENDER_CallBack( GFX_CallBackReset); return; }
02954     }
02955 #endif
02956 #ifdef WIN32
02957     if(menu.resizeusing) {
02958         RENDER_CallBack( GFX_CallBackReset);
02959         return;
02960     }
02961 #endif
02962 #if 0 /* FIXME: This code misbehaves when doublescan=false on Linux/X11 */
02963     if((Bitu)nWidth == (Bitu)width && (Bitu)nHeight == (Bitu)height) {
02964         RENDER_CallBack( GFX_CallBackReset);
02965         return;
02966     }
02967     Section_prop * section=static_cast<Section_prop *>(control->GetSection("sdl")); 
02968     if ((!strcmp(section->Get_string("windowresolution"),"original") || (!strcmp(section->Get_string("windowresolution"),"desktop"))) && (render.src.dblw && render.src.dblh)) {
02969         switch (render.scale.op) {
02970             case scalerOpNormal:
02971                 if(!render.scale.hardware) {
02972                     if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) {
02973                         if (render.scale.size <= 4 && render.scale.size >=1) ++render.scale.size; break;
02974                     } else {
02975                         if (render.scale.size <= 5 && render.scale.size >= 2) --render.scale.size; break;
02976                     }
02977                 } else {
02978                     if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) {
02979                         if (render.scale.size == 1) { render.scale.size=4; break; }
02980                         if (render.scale.size == 4) { render.scale.size=6; break; }
02981                         if (render.scale.size == 6) { render.scale.size=8; break; }
02982                         if (render.scale.size == 8) { render.scale.size=10; break; }
02983                     }
02984                     if((Bitu)nWidth<(Bitu)width || (Bitu)nHeight<(Bitu)height) {
02985                         if (render.scale.size == 10) { render.scale.size=8; break; }
02986                         if (render.scale.size == 8) { render.scale.size=6; break; }
02987                         if (render.scale.size == 6) { render.scale.size=4; break; }
02988                         if (render.scale.size == 4) { render.scale.size=1; break; }
02989                     }
02990                 }
02991                 break;
02992             case scalerOpAdvMame:
02993             case scalerOpHQ:
02994             case scalerOpAdvInterp:
02995             case scalerOpTV:
02996             case scalerOpRGB:
02997             case scalerOpScan:
02998                 if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) { if (render.scale.size == 2) ++render.scale.size; }
02999                 if((Bitu)nWidth<(Bitu)width || (Bitu)nHeight<(Bitu)height) { if (render.scale.size == 3) --render.scale.size; }
03000                 break;
03001             case scalerOpSaI:
03002             case scalerOpSuperSaI:
03003             case scalerOpSuperEagle:
03004             default: // other scalers
03005                 break;
03006         }
03007     }
03008 #endif
03009     RENDER_CallBack( GFX_CallBackReset);
03010 }
03011 
03012 void GFX_RedrawScreen(Bit32u nWidth, Bit32u nHeight) {
03013     RedrawScreen(nWidth, nHeight);
03014 }
03015 
03016 #if defined(C_SDL2)
03017 void GFX_HandleVideoResize(int width, int height) {
03018     /* Maybe a screen rotation has just occurred, so we simply resize.
03019        There may be a different cause for a forced resized, though.    */
03020     if (sdl.desktop.full.display_res && IsFullscreen()) {
03021         /* Note: We should not use GFX_ObtainDisplayDimensions
03022            (SDL_GetDisplayBounds) on Android after a screen rotation:
03023            The older values from application startup are returned. */
03024         sdl.desktop.full.width = width;
03025         sdl.desktop.full.height = height;
03026     }
03027 
03028     /* Even if the new window's dimensions are actually the desired ones
03029      * we may still need to re-obtain a new window surface or do
03030      * a different thing. So we basically call GFX_SetSize, but without
03031      * touching the window itself (or else we may end in an infinite loop).
03032      *
03033      * Furthermore, if the new dimensions are *not* the desired ones, we
03034      * don't fight it. Rather than attempting to resize it back, we simply
03035      * keep the window as-is and disable screen updates. This is done
03036      * in SDL_SetSDLWindowSurface by setting sdl.update_display_contents
03037      * to false.
03038      */
03039     sdl.update_window = false;
03040     GFX_ResetScreen();
03041     sdl.update_window = true;
03042 }
03043 #else
03044 bool GFX_MustActOnResize() {
03045     if (!GFX_IsFullscreen())
03046         return false;
03047 
03048     return true;
03049 }
03050 
03051 static void HandleVideoResize(void * event) {
03052     if(sdl.desktop.fullscreen) return;
03053 
03054     /* don't act on resize events if we made the window non-resizeable.
03055      * especially if 3Dfx voodoo emulation is active. */
03056     if (!(sdl.surface->flags & SDL_RESIZABLE)) return;
03057 
03058     /* don't act if 3Dfx OpenGL emulation is active */
03059     if (GFX_GetPreventFullscreen()) return;
03060 
03061     SDL_ResizeEvent* ResizeEvent = (SDL_ResizeEvent*)event;
03062 
03063     /* assume the resize comes from user preference UNLESS the window
03064      * is fullscreen or maximized */
03065     if (!menu.maxwindow && !sdl.desktop.fullscreen && !sdl.init_ignore && NonUserResizeCounter == 0 && !window_was_maximized) {
03066         UpdateWindowDimensions();
03067         UpdateWindowDimensions((unsigned int)ResizeEvent->w, (unsigned int)ResizeEvent->h);
03068 
03069         /* if the dimensions actually changed from our surface dimensions, then
03070            assume it's the user's input. Linux/X11 is good at doing this anyway,
03071            but the Windows SDL 1.x support will return us a resize event for the
03072            window size change resulting from SDL mode set. */
03073         if (ResizeEvent->w != sdl.surface->w || ResizeEvent->h != sdl.surface->h) {
03074             userResizeWindowWidth = (unsigned int)ResizeEvent->w;
03075             userResizeWindowHeight = (unsigned int)ResizeEvent->h;
03076         }
03077     }
03078     else {
03079         UpdateWindowDimensions();
03080     }
03081 
03082     window_was_maximized = menu.maxwindow;
03083     if (NonUserResizeCounter > 0)
03084         NonUserResizeCounter--;
03085 
03086     if (sdl.updating && !GFX_MustActOnResize()) {
03087         /* act on resize when updating is complete */
03088         sdl.deferred_resize = true;
03089     }
03090     else {
03091         sdl.deferred_resize = false;
03092         RedrawScreen((unsigned int)ResizeEvent->w, (unsigned int)ResizeEvent->h);
03093     }
03094 #ifdef WIN32
03095     menu.resizeusing=false;
03096 #endif
03097 }
03098 #endif
03099 
03100 extern unsigned int mouse_notify_mode;
03101 
03102 bool user_cursor_locked = false;
03103 MOUSE_EMULATION user_cursor_emulation = MOUSE_EMULATION_NEVER;
03104 int user_cursor_x = 0,user_cursor_y = 0;
03105 int user_cursor_sw = 640,user_cursor_sh = 480;
03106 
03107 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
03108 DOSBoxMenu::item_handle_t DOSBoxMenu::displaylist::itemFromPoint(DOSBoxMenu &menu,int x,int y) {
03109     for (auto &id : disp_list) {
03110         DOSBoxMenu::item &item = menu.get_item(id);
03111         if (x >= item.screenBox.x && y >= item.screenBox.y) {
03112             int sx = x - item.screenBox.x;
03113             int sy = y - item.screenBox.y;
03114             int adj = (this != &menu.display_list && item.get_type() == DOSBoxMenu::submenu_type_id) ? 2 : 0;
03115             if (sx < (item.screenBox.w+adj) && sy < item.screenBox.h)
03116                 return id;
03117         }
03118     }
03119 
03120     return unassigned_item_handle;
03121 }
03122 
03123 void DOSBoxMenu::item::updateScreenFromItem(DOSBoxMenu &menu) {
03124     (void)menu;//UNUSED
03125     if (!OpenGL_using()) {
03126         SDL_Rect uprect = screenBox;
03127 
03128         SDL_rect_cliptoscreen(uprect);
03129 
03130 #if defined(C_SDL2)
03131         SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1);
03132 #else
03133         SDL_UpdateRects( sdl.surface, 1, &uprect );
03134 #endif
03135     }
03136 }
03137 
03138 void DOSBoxMenu::item::updateScreenFromPopup(DOSBoxMenu &menu) {
03139     (void)menu;//UNUSED
03140     if (!OpenGL_using()) {
03141         SDL_Rect uprect = popupBox;
03142 
03143         uprect.w += DOSBoxMenu::dropshadowX;
03144         uprect.h += DOSBoxMenu::dropshadowY;
03145         SDL_rect_cliptoscreen(uprect);
03146 
03147 #if defined(C_SDL2)
03148         SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1);
03149 #else
03150         SDL_UpdateRects( sdl.surface, 1, &uprect );
03151 #endif
03152     }
03153 }
03154 
03155 void DOSBoxMenu::item::drawBackground(DOSBoxMenu &menu) {
03156     (void)menu;//UNUSED
03157     Bitu bordercolor = GFX_GetRGB(31, 31, 31);
03158     Bitu bgcolor = GFX_GetRGB(63, 63, 63);
03159 
03160     if (popupBox.w <= 1 || popupBox.h <= 1)
03161         return;
03162 
03163     MenuDrawRect(popupBox.x, popupBox.y, popupBox.w, popupBox.h, bgcolor);
03164 
03165     if (borderTop)
03166         MenuDrawRect(popupBox.x, popupBox.y, popupBox.w, 1, bordercolor);
03167 
03168     MenuDrawRect(popupBox.x, popupBox.y + popupBox.h - 1, popupBox.w, 1, bordercolor);
03169 
03170     MenuDrawRect(popupBox.x, popupBox.y, 1, popupBox.h, bordercolor);
03171     MenuDrawRect(popupBox.x + popupBox.w - 1, popupBox.y, 1, popupBox.h, bordercolor);
03172 
03173     if (type == DOSBoxMenu::submenu_type_id) {
03174         MenuShadeRect((int)popupBox.x + (int)popupBox.w, (int)popupBox.y + (int)DOSBoxMenu::dropshadowY,
03175                       (int)DOSBoxMenu::dropshadowX, (int)popupBox.h);
03176         MenuShadeRect((int)popupBox.x + (int)DOSBoxMenu::dropshadowX, (int)popupBox.y + (int)popupBox.h,
03177                       (int)popupBox.w - (int)DOSBoxMenu::dropshadowX, (int)DOSBoxMenu::dropshadowY);
03178     }
03179 }
03180 #endif
03181 
03182 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
03183 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id) {
03184     (void)menu;//UNUSED
03185     if (mainMenu.menuUserHoverAt != item_id) {
03186         if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) {
03187             mainMenu.get_item(mainMenu.menuUserHoverAt).setHover(mainMenu,false);
03188             mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu);
03189             mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu);
03190         }
03191 
03192         mainMenu.menuUserHoverAt = item_id;
03193 
03194         if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) {
03195             mainMenu.get_item(mainMenu.menuUserHoverAt).setHover(mainMenu,true);
03196             mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu);
03197             mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu);
03198         }
03199 
03200         if (OpenGL_using())
03201             mainMenu.setRedraw();
03202     }
03203 }
03204 
03205 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id) {
03206     (void)menu;//UNUSED
03207     if (mainMenu.menuUserAttentionAt != item_id) {
03208         if (mainMenu.menuUserAttentionAt != DOSBoxMenu::unassigned_item_handle) {
03209             mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,false);
03210             mainMenu.get_item(mainMenu.menuUserAttentionAt).drawMenuItem(mainMenu);
03211             mainMenu.get_item(mainMenu.menuUserAttentionAt).updateScreenFromItem(mainMenu);
03212         }
03213 
03214         mainMenu.menuUserAttentionAt = item_id;
03215 
03216         if (mainMenu.menuUserAttentionAt != DOSBoxMenu::unassigned_item_handle) {
03217             mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,true);
03218             mainMenu.get_item(mainMenu.menuUserAttentionAt).drawMenuItem(mainMenu);
03219             mainMenu.get_item(mainMenu.menuUserAttentionAt).updateScreenFromItem(mainMenu);
03220         }
03221 
03222         if (OpenGL_using())
03223             mainMenu.setRedraw();
03224     }
03225 }
03226 #endif
03227 
03228 uint8_t Mouse_GetButtonState(void);
03229 
03230 static void HandleMouseMotion(SDL_MouseMotionEvent * motion) {
03231 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
03232     if (!sdl.mouse.locked && !sdl.desktop.fullscreen && mainMenu.isVisible() && motion->y < mainMenu.menuBox.h && Mouse_GetButtonState() == 0) {
03233         GFX_SDLMenuTrackHover(mainMenu,mainMenu.display_list.itemFromPoint(mainMenu,motion->x,motion->y));
03234         SDL_ShowCursor(SDL_ENABLE);
03235 
03236         if (OpenGL_using() && mainMenu.needsRedraw()) {
03237 #if C_OPENGL
03238             sdl_opengl.menudraw_countdown = 2; // two GL buffers
03239             GFX_OpenGLRedrawScreen();
03240             GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
03241             SDL_GL_SwapBuffers();
03242 #endif
03243         }
03244  
03245         return;
03246     }
03247     else {
03248         GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle);
03249 
03250         if (OpenGL_using() && mainMenu.needsRedraw()) {
03251 #if C_OPENGL
03252             sdl_opengl.menudraw_countdown = 2; // two GL buffers
03253             GFX_OpenGLRedrawScreen();
03254             GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
03255             SDL_GL_SwapBuffers();
03256 #endif
03257         }
03258     }
03259 #endif
03260     user_cursor_x      = motion->x - sdl.clip.x;
03261     user_cursor_y      = motion->y - sdl.clip.y;
03262     user_cursor_locked = sdl.mouse.locked;
03263     user_cursor_emulation = sdl.mouse.emulation;
03264     user_cursor_sw     = sdl.clip.w;
03265     user_cursor_sh     = sdl.clip.h;
03266 
03267     auto xrel = static_cast<float>(motion->xrel) * sdl.mouse.sensitivity / 100.0f;
03268     auto yrel = static_cast<float>(motion->yrel) * sdl.mouse.sensitivity / 100.0f;
03269     auto x    = static_cast<float>(motion->x - sdl.clip.x) / (sdl.clip.w - 1) * sdl.mouse.sensitivity / 100.0f;
03270     auto y    = static_cast<float>(motion->y - sdl.clip.y) / (sdl.clip.h - 1) * sdl.mouse.sensitivity / 100.0f;
03271     auto emu  = sdl.mouse.locked;
03272 
03273     const auto inside =
03274         motion->x >= sdl.clip.x && motion->x < sdl.clip.x + sdl.clip.w &&
03275         motion->y >= sdl.clip.y && motion->y < sdl.clip.y + sdl.clip.h;
03276 
03277     if (mouse_notify_mode != 0)
03278     {
03279         /* for mouse integration driver */
03280         if (!sdl.mouse.locked)
03281             xrel = yrel = x = y = 0.0f;
03282 
03283         emu               = sdl.mouse.locked;
03284         const auto isdown = Mouse_GetButtonState() != 0;
03285 
03286         if (!sdl.mouse.locked && !sdl.desktop.fullscreen)
03287             SDL_ShowCursor((isdown || inside) ? SDL_DISABLE : SDL_ENABLE);
03288         /* TODO: If guest has not read mouse cursor position within 250ms show cursor again */
03289     }
03290     else if (!user_cursor_locked)
03291     {
03292         bool MOUSE_HasInterruptSub();
03293         bool MOUSE_IsBeingPolled();
03294         bool MOUSE_IsHidden();
03295         /* Show only when DOS app is not using mouse */
03296 
03297         if (!sdl.mouse.locked && !sdl.desktop.fullscreen)
03298             SDL_ShowCursor(((!inside) || ((MOUSE_IsHidden()) && !(MOUSE_IsBeingPolled() || MOUSE_HasInterruptSub()))) ? SDL_ENABLE : SDL_DISABLE);
03299     }
03300     Mouse_CursorMoved(xrel, yrel, x, y, emu);
03301 }
03302 
03303 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
03304 void MenuFullScreenRedraw(void) {
03305 #if defined(C_SDL2)
03306     SDL_UpdateWindowSurface(sdl.window);
03307 #else
03308     SDL_Flip(sdl.surface);
03309 #endif
03310 }
03311 
03312 #if defined(C_SDL2)
03313 static const SDL_TouchID no_touch_id = (SDL_TouchID)(~0ULL);
03314 static const SDL_FingerID no_finger_id = (SDL_FingerID)(~0ULL);
03315 static SDL_FingerID touchscreen_finger_lock = no_finger_id;
03316 static SDL_TouchID touchscreen_touch_lock = no_touch_id;
03317 #endif
03318 
03319 static struct {
03320     unsigned char*      bmp = NULL;
03321     unsigned int        stride = 0,height = 0;
03322 } menuSavedScreen;
03323 
03324 void MenuSaveScreen(void) {
03325     if (!OpenGL_using()) {
03326         if (menuSavedScreen.bmp == NULL) {
03327             menuSavedScreen.height = (unsigned int)sdl.surface->h;
03328             menuSavedScreen.stride = (unsigned int)sdl.surface->pitch;
03329             menuSavedScreen.bmp = new unsigned char[menuSavedScreen.height * menuSavedScreen.stride];
03330         }
03331 
03332         if (SDL_MUSTLOCK(sdl.surface))
03333             SDL_LockSurface(sdl.surface);
03334 
03335         memcpy(menuSavedScreen.bmp, sdl.surface->pixels, menuSavedScreen.height * menuSavedScreen.stride);
03336 
03337         if (SDL_MUSTLOCK(sdl.surface))
03338             SDL_UnlockSurface(sdl.surface);
03339     }
03340 }
03341 
03342 void MenuRestoreScreen(void) {
03343     if (!OpenGL_using()) {
03344         if (menuSavedScreen.bmp == NULL)
03345             return;
03346 
03347         if (SDL_MUSTLOCK(sdl.surface))
03348             SDL_LockSurface(sdl.surface);
03349 
03350         memcpy(sdl.surface->pixels, menuSavedScreen.bmp, menuSavedScreen.height * menuSavedScreen.stride);
03351 
03352         if (SDL_MUSTLOCK(sdl.surface))
03353             SDL_UnlockSurface(sdl.surface);
03354     }
03355 }
03356 
03357 void MenuFreeScreen(void) {
03358     if (menuSavedScreen.bmp == NULL)
03359         return;
03360 
03361     delete[] menuSavedScreen.bmp;
03362     menuSavedScreen.bmp = NULL;
03363 }
03364 #endif
03365 
03366 static void HandleMouseButton(SDL_MouseButtonEvent * button) {
03367     bool inMenu = false;
03368 
03369 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
03370     if (!sdl.mouse.locked && !sdl.desktop.fullscreen && mainMenu.isVisible() && button->y < mainMenu.menuBox.h) {
03371         GFX_SDLMenuTrackHover(mainMenu,mainMenu.display_list.itemFromPoint(mainMenu,button->x,button->y));
03372         inMenu = true;
03373     }
03374     else {
03375         GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle);
03376     }
03377 
03378     if (button->button == SDL_BUTTON_LEFT) {
03379         if (button->state == SDL_PRESSED) {
03380             GFX_SDLMenuTrackHilight(mainMenu,mainMenu.menuUserHoverAt);
03381             if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) {
03382                 std::vector<DOSBoxMenu::item_handle_t> popup_stack;
03383                 DOSBoxMenu::item_handle_t choice_item;
03384                 DOSBoxMenu::item_handle_t psel_item;
03385                 DOSBoxMenu::item_handle_t sel_item;
03386                 bool button_holding=true;
03387                 bool redrawAll=false;
03388                 bool resized=false;
03389                 bool runloop=true;
03390                 SDL_Rect uprect;
03391                 SDL_Event event;
03392 
03393                 psel_item = DOSBoxMenu::unassigned_item_handle;
03394                 choice_item = mainMenu.menuUserHoverAt = mainMenu.menuUserAttentionAt;
03395 
03396                 popup_stack.push_back(mainMenu.menuUserAttentionAt);
03397 
03398 #if C_DIRECT3D
03399         if (sdl.desktop.want_type == SCREEN_DIRECT3D) {
03400             /* In output=direct3d mode, SDL still has a surface but this code ignores SDL
03401              * and draws directly to a Direct3D9 backbuffer which is presented to the window
03402              * client area. However, GDI output to the window still works, and this code
03403              * uses the SDL surface still. Therefore, for menus to draw correctly atop the
03404              * Direct3D output, this code copies the Direct3D backbuffer to the SDL surface
03405              * first.
03406              *
03407              * WARNING: This happens to work with Windows (even Windows 10 build 18xx as of
03408              * 2018/05/21) because Windows appears to permit mixing Direct3D and GDI rendering
03409              * to the window.
03410              *
03411              * Someday, if Microsoft should break that ability, this code will need to be
03412              * revised to send screen "updates" to the Direct3D backbuffer first, then
03413              * Present to the window client area. */
03414             if (d3d) d3d->UpdateRectToSDLSurface(0, 0, sdl.surface->w, sdl.surface->h);
03415         }
03416 #endif
03417 
03418                 if (OpenGL_using()) {
03419 #if C_OPENGL
03420                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,false);
03421                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,false);
03422 
03423                     /* show the menu */
03424                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,true);
03425                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,true);
03426 
03427                     glClearColor (0.0, 0.0, 0.0, 1.0);
03428                     glClear(GL_COLOR_BUFFER_BIT);
03429 
03430                     GFX_OpenGLRedrawScreen();
03431 
03432                     /* give the menu bar a drop shadow */
03433                     MenuShadeRect(
03434                             (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX,
03435                             (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h,
03436                             (int)mainMenu.menuBox.w,
03437                             (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/);
03438 
03439                     mainMenu.setRedraw();                  
03440                     GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
03441 
03442                     for (auto i=popup_stack.begin();i!=popup_stack.end();i++) {
03443                         if (mainMenu.get_item(*i).get_type() == DOSBoxMenu::submenu_type_id) {
03444                             mainMenu.get_item(*i).drawBackground(mainMenu);
03445                             mainMenu.get_item(*i).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false);
03446                         }
03447                     }
03448 
03449                     SDL_GL_SwapBuffers();
03450 #endif
03451                 }
03452                 else {
03453                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,false);
03454                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,false);
03455                     mainMenu.get_item(mainMenu.menuUserAttentionAt).drawMenuItem(mainMenu);
03456                     MenuSaveScreen();
03457 
03458                     /* give the menu bar a drop shadow */
03459                     MenuShadeRect(
03460                             (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX,
03461                             (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h,
03462                             (int)mainMenu.menuBox.w,
03463                             (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/);
03464 
03465                     uprect.x = 0;
03466                     uprect.y = mainMenu.menuBox.y + mainMenu.menuBox.h;
03467                     uprect.w = mainMenu.menuBox.w;
03468                     uprect.h = DOSBoxMenu::dropshadowY;
03469 #if defined(C_SDL2)
03470                     SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1);
03471 #else
03472                     SDL_UpdateRects( sdl.surface, 1, &uprect );
03473 #endif
03474 
03475                     /* show the menu */
03476                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,true);
03477                     mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,true);
03478                     mainMenu.get_item(mainMenu.menuUserAttentionAt).drawBackground(mainMenu);
03479                     mainMenu.get_item(mainMenu.menuUserAttentionAt).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false);
03480                     mainMenu.get_item(mainMenu.menuUserAttentionAt).updateScreenFromPopup(mainMenu);
03481                 }
03482 
03483                 /* hack */
03484                 mainMenu.menuUserAttentionAt = DOSBoxMenu::unassigned_item_handle;
03485 
03486                 /* fall into another loop to process the menu */
03487                 while (runloop) {
03488 #if C_EMSCRIPTEN
03489                     emscripten_sleep_with_yield(0);
03490                     if (!SDL_PollEvent(&event)) continue;
03491 #else
03492                     if (!SDL_WaitEvent(&event)) break;
03493 #endif
03494 
03495 #if defined(C_SDL2)
03496                     switch (event.type) {
03497                         case SDL_FINGERDOWN:
03498                             if (touchscreen_finger_lock == no_finger_id &&
03499                                 touchscreen_touch_lock == no_touch_id) {
03500                                 touchscreen_finger_lock = event.tfinger.fingerId;
03501                                 touchscreen_touch_lock = event.tfinger.touchId;
03502                                 Sint32 x,y;
03503 
03504 #if defined(WIN32)
03505                                 /* NTS: Windows versions of SDL2 do normalize the coordinates */
03506                                 x = (Sint32)(event.tfinger.x * sdl.clip.w);
03507                                 y = (Sint32)(event.tfinger.y * sdl.clip.h);
03508 #else
03509                                 /* NTS: Linux versions of SDL2 don't normalize the coordinates? */
03510                                 x = event.tfinger.x;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03511                                 y = event.tfinger.y;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03512 #endif
03513                                 
03514                                 memset(&event.button,0,sizeof(event.button));
03515                                 event.type = SDL_MOUSEBUTTONDOWN;
03516                                 event.button.x = x;
03517                                 event.button.y = y;
03518                             }
03519                             else {
03520                                 event.type = -1;
03521                             }
03522                             break;
03523                         case SDL_FINGERUP:
03524                             if (touchscreen_finger_lock == event.tfinger.fingerId &&
03525                                 touchscreen_touch_lock == event.tfinger.touchId) {
03526                                 touchscreen_finger_lock = no_finger_id;
03527                                 touchscreen_touch_lock = no_touch_id;
03528                                 Sint32 x,y;
03529 
03530 #if defined(WIN32)
03531                                 /* NTS: Windows versions of SDL2 do normalize the coordinates */
03532                                 x = (Sint32)(event.tfinger.x * sdl.clip.w);
03533                                 y = (Sint32)(event.tfinger.y * sdl.clip.h);
03534 #else
03535                                 /* NTS: Linux versions of SDL2 don't normalize the coordinates? */
03536                                 x = event.tfinger.x;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03537                                 y = event.tfinger.y;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03538 #endif
03539                                 
03540                                 memset(&event.button,0,sizeof(event.button));
03541                                 event.type = SDL_MOUSEBUTTONUP;
03542                                 event.button.x = x;
03543                                 event.button.y = y;
03544                             }
03545                             else {
03546                                 event.type = -1;
03547                             }
03548                             break;
03549                         case SDL_FINGERMOTION:
03550                             if (touchscreen_finger_lock == event.tfinger.fingerId &&
03551                                 touchscreen_touch_lock == event.tfinger.touchId) {
03552                                 Sint32 x,y;
03553 
03554 #if defined(WIN32)
03555                                 /* NTS: Windows versions of SDL2 do normalize the coordinates */
03556                                 x = (Sint32)(event.tfinger.x * sdl.clip.w);
03557                                 y = (Sint32)(event.tfinger.y * sdl.clip.h);
03558 #else
03559                                 /* NTS: Linux versions of SDL2 don't normalize the coordinates? */
03560                                 x = event.tfinger.x;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03561                                 y = event.tfinger.y;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03562 #endif
03563                                 
03564                                 memset(&event.button,0,sizeof(event.button));
03565                                 event.type = SDL_MOUSEMOTION;
03566                                 event.button.x = x;
03567                                 event.button.y = y;
03568                             }
03569                             else if (touchscreen_finger_lock != no_finger_id ||
03570                                      touchscreen_touch_lock != no_touch_id) {
03571                                 event.type = -1;
03572                             }
03573                             break;
03574                     }
03575 #endif
03576 
03577                     switch (event.type) {
03578                         case SDL_QUIT:
03579                             throw(0);
03580                             break;
03581                         case SDL_KEYUP:
03582                             if (event.key.keysym.sym == SDLK_ESCAPE) {
03583                                 choice_item = DOSBoxMenu::unassigned_item_handle;
03584                                 runloop = false;
03585                             }
03586                             break;
03587 #if !defined(C_SDL2)
03588                         case SDL_VIDEORESIZE:
03589                             UpdateWindowDimensions(); // FIXME: Use SDL window dimensions, except that on Windows, SDL won't tell us our actual dimensions
03590                             HandleVideoResize(&event.resize);
03591 
03592                             runloop = false;
03593                             resized = true;
03594                             break;
03595 #endif
03596                         case SDL_MOUSEBUTTONDOWN:
03597                             button_holding=true;
03598                             choice_item = mainMenu.menuUserHoverAt;
03599                             if (choice_item != DOSBoxMenu::unassigned_item_handle) {
03600                                 DOSBoxMenu::item &item = mainMenu.get_item(choice_item);
03601                                 item.setHilight(mainMenu,true);
03602                                 item.drawMenuItem(mainMenu);
03603                                 if (OpenGL_using())
03604                                     redrawAll = true;
03605                                 else
03606                                     item.updateScreenFromItem(mainMenu);
03607                             }
03608                             else {
03609                                 /* clicking on nothing should dismiss */
03610                                 runloop = false;
03611                             }
03612                             break;
03613                         case SDL_MOUSEBUTTONUP:
03614                             button_holding=false;
03615                             choice_item = mainMenu.menuUserHoverAt;
03616                             if (choice_item != DOSBoxMenu::unassigned_item_handle) {
03617                                 if (choice_item == psel_item) { /* clicking something twice should dismiss */
03618                                     runloop = false;
03619                                 }
03620                                 else {
03621                                     DOSBoxMenu::item &item = mainMenu.get_item(choice_item);
03622                                     if (item.get_type() == DOSBoxMenu::item_type_id && item.is_enabled())
03623                                         runloop = false;
03624                                 }
03625 
03626                                 psel_item = choice_item;
03627                             }
03628                             else {
03629                                 /* not selecting anything counts as a reason to exit */
03630                                 runloop = false;
03631                             }
03632                             break;
03633                         case SDL_MOUSEMOTION:
03634                             {
03635                                 sel_item = DOSBoxMenu::unassigned_item_handle;
03636 
03637                                 auto search = popup_stack.end();
03638                                 if (search != popup_stack.begin()) {
03639                                     do {
03640                                         search--;
03641 
03642                                         sel_item = mainMenu.get_item(*search).display_list.itemFromPoint(mainMenu,event.button.x,event.button.y);
03643                                         if (sel_item != DOSBoxMenu::unassigned_item_handle) {
03644                                             assert(search != popup_stack.end());
03645                                             search++;
03646                                             break;
03647                                         }
03648                                     } while (search != popup_stack.begin());
03649                                 }
03650 
03651                                 if (sel_item == DOSBoxMenu::unassigned_item_handle)
03652                                     sel_item = mainMenu.display_list.itemFromPoint(mainMenu,event.button.x,event.button.y);
03653 
03654                                 /* at this point:
03655                                  *  sel_item = item under cursor, or unassigned if no item
03656                                  *  search = iterator just past the item's level (to remove items if changing) */
03657 
03658                                 if (mainMenu.menuUserHoverAt != sel_item) {
03659                                     if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) {
03660                                         mainMenu.get_item(mainMenu.menuUserHoverAt).setHover(mainMenu,false);
03661                                         if (mainMenu.get_item(mainMenu.menuUserHoverAt).get_type() == DOSBoxMenu::item_type_id)
03662                                             mainMenu.get_item(mainMenu.menuUserHoverAt).setHilight(mainMenu,false);
03663                                     }
03664 
03665                                     if (sel_item != DOSBoxMenu::unassigned_item_handle) {
03666                                         if (mainMenu.get_item(sel_item).get_type() == DOSBoxMenu::submenu_type_id) {
03667                                             if (!mainMenu.get_item(sel_item).isHilight()) {
03668                                                 /* use a copy of the iterator to scan forward and un-hilight the menu items.
03669                                                  * then use the original iterator to erase from the vector. */
03670                                                 for (auto ss=search;ss != popup_stack.end();ss++) {
03671                                                     for (auto &id : mainMenu.get_item(*ss).display_list.get_disp_list())
03672                                                         mainMenu.get_item(id).setHilight(mainMenu,false).setHover(mainMenu,false);
03673 
03674                                                     mainMenu.get_item(*ss).setHilight(mainMenu,false).setHover(mainMenu,false);
03675                                                 }
03676 
03677                                                 popup_stack.erase(search,popup_stack.end());
03678                                                 mainMenu.get_item(sel_item).setHilight(mainMenu,true).setHover(mainMenu,true);
03679                                                 popup_stack.push_back(sel_item);
03680                                                 redrawAll = true;
03681                                             }
03682                                         }
03683                                         else {
03684                                             /* use a copy of the iterator to scan forward and un-hilight the menu items.
03685                                              * then use the original iterator to erase from the vector. */
03686                                             for (auto ss=search;ss != popup_stack.end();ss++) {
03687                                                 for (auto &id : mainMenu.get_item(*ss).display_list.get_disp_list())
03688                                                     mainMenu.get_item(id).setHilight(mainMenu,false).setHover(mainMenu,false);
03689 
03690                                                 mainMenu.get_item(*ss).setHilight(mainMenu,false).setHover(mainMenu,false);
03691                                                 redrawAll = true;
03692                                             }
03693 
03694                                             popup_stack.erase(search,popup_stack.end());
03695                                         }
03696 
03697                                         if (OpenGL_using())
03698                                             redrawAll = true;
03699 
03700                                         mainMenu.get_item(sel_item).setHover(mainMenu,true);
03701                                         if (mainMenu.get_item(sel_item).get_type() == DOSBoxMenu::item_type_id && button_holding)
03702                                             mainMenu.get_item(sel_item).setHilight(mainMenu,true);
03703                                     }
03704                                     else {
03705                                         if (OpenGL_using())
03706                                             redrawAll = true;
03707                                     }
03708 
03709                                     if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle && !OpenGL_using() && !redrawAll) {
03710                                         mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu);
03711                                         mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu);
03712                                     }
03713 
03714                                     mainMenu.menuUserHoverAt = sel_item;
03715 
03716                                     if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle && !OpenGL_using() && !redrawAll) {
03717                                         mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu);
03718                                         mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu);
03719                                     }
03720                                 }
03721                             }
03722                             break;
03723                     }
03724 
03725                     if (redrawAll) {
03726                         redrawAll = false;
03727 
03728 #if 0/*DEBUG*/
03729                         LOG_MSG("Redraw %u",(unsigned int)SDL_GetTicks());
03730 #endif
03731 
03732                         if (OpenGL_using()) {
03733 #if C_OPENGL
03734                             glClearColor (0.0, 0.0, 0.0, 1.0);
03735                             glClear(GL_COLOR_BUFFER_BIT);
03736 
03737                             GFX_OpenGLRedrawScreen();
03738   
03739                             mainMenu.setRedraw();                  
03740                             GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
03741 #endif
03742                         }
03743                         else {
03744                             MenuRestoreScreen();
03745                             mainMenu.display_list.DrawDisplayList(mainMenu,/*updateScreen*/false);
03746                         }
03747 
03748                         /* give the menu bar a drop shadow */
03749                         MenuShadeRect(
03750                                 (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX,
03751                                 (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h,
03752                                 (int)mainMenu.menuBox.w,
03753                                 (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/);
03754 
03755                         for (auto i=popup_stack.begin();i!=popup_stack.end();i++) {
03756                             if (mainMenu.get_item(*i).get_type() == DOSBoxMenu::submenu_type_id) {
03757                                 mainMenu.get_item(*i).drawBackground(mainMenu);
03758                                 mainMenu.get_item(*i).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false);
03759                             }
03760                         }
03761 
03762 #if C_OPENGL
03763                         if (OpenGL_using())
03764                             SDL_GL_SwapBuffers();
03765                         else
03766 #endif
03767                             MenuFullScreenRedraw();
03768                     }
03769                 }
03770 
03771 #if defined(C_SDL2)
03772                 /* force touchscreen mapping to let go */
03773                 touchscreen_finger_lock = no_finger_id;
03774                 touchscreen_touch_lock = no_touch_id;
03775 #endif
03776 
03777                 /* then return */
03778                 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle);
03779                 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle);
03780                 if (!resized) {
03781                     MenuRestoreScreen();
03782                     if (!OpenGL_using())
03783                         MenuFullScreenRedraw();
03784                 }
03785                 MenuFreeScreen();
03786 
03787                 while (!popup_stack.empty()) {
03788                     DOSBoxMenu::item &item = mainMenu.get_item(popup_stack.back());
03789 
03790                     for (auto &id : item.display_list.get_disp_list()) {
03791                         mainMenu.get_item(id).setHilight(mainMenu,false);
03792                         mainMenu.get_item(id).setHover(mainMenu,false);
03793                     }
03794 
03795                     item.setHilight(mainMenu,false);
03796                     item.setHover(mainMenu,false);
03797                     popup_stack.pop_back();
03798                 }
03799 
03800                 if (OpenGL_using()) {
03801 #if C_OPENGL
03802                     glClearColor (0.0, 0.0, 0.0, 1.0);
03803                     glClear(GL_COLOR_BUFFER_BIT);
03804         
03805                     GFX_OpenGLRedrawScreen();
03806 
03807                     mainMenu.setRedraw();
03808                     GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
03809 
03810                     SDL_GL_SwapBuffers();
03811 
03812                     sdl_opengl.clear_countdown = 2;
03813                     sdl_opengl.menudraw_countdown = 2; // two GL buffers
03814 #endif
03815                 }
03816 
03817                 /* action! */
03818                 if (!resized && choice_item != DOSBoxMenu::unassigned_item_handle) {
03819                     DOSBoxMenu::item &item = mainMenu.get_item(choice_item);
03820 
03821                     if (item.get_type() == DOSBoxMenu::item_type_id && item.is_enabled())
03822                         mainMenu.dispatchItemCommand(item);
03823                 }
03824 
03825                 return;
03826             }
03827         }
03828         else {
03829             GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle);
03830         }
03831     }
03832 #endif
03833  
03834     switch (button->state) {
03835     case SDL_PRESSED:
03836         if (inMenu) return;
03837         if (sdl.mouse.requestlock && !sdl.mouse.locked && mouse_notify_mode == 0) {
03838             CaptureMouseNotify();
03839             GFX_CaptureMouse();
03840             // Dont pass klick to mouse handler
03841             break;
03842         }
03843         if (!sdl.mouse.autoenable && sdl.mouse.autolock && mouse_notify_mode == 0 && button->button == SDL_BUTTON_MIDDLE) {
03844             GFX_CaptureMouse();
03845             break;
03846         }
03847         switch (button->button) {
03848         case SDL_BUTTON_LEFT:
03849             Mouse_ButtonPressed(0);
03850             break;
03851         case SDL_BUTTON_RIGHT:
03852             Mouse_ButtonPressed(1);
03853             break;
03854         case SDL_BUTTON_MIDDLE:
03855             Mouse_ButtonPressed(2);
03856             break;
03857 #if !defined(C_SDL2)
03858         case SDL_BUTTON_WHEELUP: /* Ick, really SDL? */
03859             Mouse_ButtonPressed(100-1);
03860             break;
03861         case SDL_BUTTON_WHEELDOWN: /* Ick, really SDL? */
03862             Mouse_ButtonPressed(100+1);
03863             break;
03864 #endif
03865         }
03866         break;
03867     case SDL_RELEASED:
03868         switch (button->button) {
03869         case SDL_BUTTON_LEFT:
03870             Mouse_ButtonReleased(0);
03871             break;
03872         case SDL_BUTTON_RIGHT:
03873             Mouse_ButtonReleased(1);
03874             break;
03875         case SDL_BUTTON_MIDDLE:
03876             Mouse_ButtonReleased(2);
03877             break;
03878 #if !defined(C_SDL2)
03879         case SDL_BUTTON_WHEELUP: /* Ick, really SDL? */
03880             Mouse_ButtonReleased(100-1);
03881             break;
03882         case SDL_BUTTON_WHEELDOWN: /* Ick, really SDL? */
03883             Mouse_ButtonReleased(100+1);
03884             break;
03885 #endif
03886         }
03887         break;
03888     }
03889 }
03890 
03891 void GFX_LosingFocus(void) {
03892     sdl.laltstate=SDL_KEYUP;
03893     sdl.raltstate=SDL_KEYUP;
03894     MAPPER_LosingFocus();
03895     DoExtendedKeyboardHook(false);
03896 }
03897 
03898 #if !defined(C_SDL2)
03899 static bool PasteClipboardNext(); // added emendelson from dbDOS
03900 #endif
03901 
03902 #if !defined(C_SDL2)
03903 bool GFX_IsFullscreen(void) {
03904     return sdl.desktop.fullscreen;
03905 }
03906 #endif
03907 
03908 #if defined(__WIN32__) && !defined(C_SDL2) && !defined(HX_DOS)
03909 void OpenFileDialog( char * path_arg ) {
03910     if(control->SecureMode()) {
03911         LOG_MSG(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW"));
03912         return;
03913     }
03914     DOS_MCB mcb(dos.psp()-1);
03915     static char pcname[9];
03916     mcb.GetFileName(pcname);
03917     if(strlen(pcname)) return;
03918 
03919     OPENFILENAME OpenFileName;
03920     char szFile[MAX_PATH];
03921     char CurrentDir[MAX_PATH];
03922     const char * Temp_CurrentDir = CurrentDir;
03923 
03924     if (Drives['C'-'A']) {
03925         if (MessageBox(GetHWND(),
03926             "Quick launch automatically mounts drive C in DOSBox.\nDrive C has already been mounted. Do you want to continue?",
03927             "Warning",MB_YESNO)==IDNO) return;
03928     }
03929 
03930     if(path_arg) goto search;
03931     szFile[0] = 0;
03932 
03933     GetCurrentDirectory( MAX_PATH, CurrentDir );
03934 
03935     OpenFileName.lStructSize = sizeof( OPENFILENAME );
03936     OpenFileName.hwndOwner = NULL;
03937     if(DOSBox_Kor())
03938         OpenFileName.lpstrFilter = "실행 파일(*.com, *.exe, *.bat)\0*.com;*.exe;*.bat\0모든 파일(*.*)\0*.*\0";
03939     else
03940         OpenFileName.lpstrFilter = "Executable files(*.com, *.exe, *.bat)\0*.com;*.exe;*.bat\0All files(*.*)\0*.*\0";
03941     OpenFileName.lpstrCustomFilter = NULL;
03942     OpenFileName.nMaxCustFilter = 0;
03943     OpenFileName.nFilterIndex = 0;
03944     OpenFileName.lpstrFile = szFile;
03945     OpenFileName.nMaxFile = sizeof( szFile );
03946     OpenFileName.lpstrFileTitle = NULL;
03947     OpenFileName.nMaxFileTitle = 0;
03948     OpenFileName.lpstrInitialDir = CurrentDir;
03949     OpenFileName.lpstrTitle = "Select an executable";
03950     OpenFileName.nFileOffset = 0;
03951     OpenFileName.nFileExtension = 0;
03952     OpenFileName.lpstrDefExt = NULL;
03953     OpenFileName.lCustData = 0;
03954     OpenFileName.lpfnHook = NULL;
03955     OpenFileName.lpTemplateName = NULL;
03956     OpenFileName.Flags = OFN_EXPLORER;
03957 
03958 search:
03959     if(GetOpenFileName( &OpenFileName ) || path_arg) {
03960         WIN32_FIND_DATA FindFileData;
03961         HANDLE hFind;
03962         char drive  [_MAX_DRIVE]; 
03963         char dir    [_MAX_DIR]; 
03964         char fname  [_MAX_FNAME]; 
03965         char ext    [_MAX_EXT]; 
03966         char * path = 0;
03967         if(path_arg) {
03968             szFile[0] = 0;
03969             sprintf(szFile,path_arg);
03970         }
03971         path = szFile;
03972         _splitpath (path, drive, dir, fname, ext);
03973         char ext_temp [_MAX_EXT]; ext_temp[0] = 0; sprintf(ext_temp,ext);
03974 
03975         hFind = FindFirstFile(szFile, &FindFileData);
03976         if (hFind == INVALID_HANDLE_VALUE) {
03977             if(strcasecmp(ext,"")) goto search;
03978             szFile[0] = 0;
03979             ext[0] = 0; sprintf(ext,".com");
03980             sprintf(szFile,"%s%s%s%s",drive,dir,fname,".com");
03981             hFind = FindFirstFile(szFile, &FindFileData);
03982             if (hFind == INVALID_HANDLE_VALUE) {
03983                 szFile[0] = 0;
03984                 ext[0] = 0; sprintf(ext,".exe");
03985                 sprintf(szFile,"%s%s%s%s",drive,dir,fname,".exe");
03986                 hFind = FindFirstFile(szFile, &FindFileData);
03987                 if (hFind == INVALID_HANDLE_VALUE) {
03988                     szFile[0] = 0;
03989                     ext[0] = 0; sprintf(ext,".bat");
03990                     sprintf(szFile,"%s%s%s%s",drive,dir,fname,".bat");
03991                     hFind = FindFirstFile(szFile, &FindFileData);
03992                     if (hFind == INVALID_HANDLE_VALUE) {
03993                         szFile[0] = 0;
03994                         ext[0]=0;
03995                         goto search;
03996                     }
03997                 }
03998             }
03999         }
04000 
04001         if((!strcmp(ext,".com")) || (!strcmp(ext,".exe")) || (!strcmp(ext,".bat"))) {
04002             char pathname[DOS_PATHLENGTH];
04003             sprintf(pathname,"%s%s",drive,dir);
04004             MountDrive_2('C',pathname,"LOCAL");
04005             DOS_SetDrive(toupper('C') - 'A');
04006         } else {
04007             LOG_MSG("GUI: Unsupported filename extension.");
04008             goto godefault;
04009         }
04010 
04011         #define DOSNAMEBUF 256
04012         char name1[DOSNAMEBUF+1];
04013         sprintf(name1,"%s%s",fname,ext);
04014         Bit16u n=1; Bit8u c='\n';
04015         DOS_WriteFile(STDOUT,&c,&n);
04016 
04017         DOS_Shell shell;
04018         DOS_MCB mcb(dos.psp()-1);
04019         static char name[9];
04020         mcb.GetFileName(name);
04021 
04022         SetCurrentDirectory( Temp_CurrentDir );
04023         do {
04024             shell.Execute(name1,(char*)(" "));
04025             if(!strcmp(ext,".bat")) shell.RunInternal();
04026             if (!strlen(name)) break;
04027         } while (1);
04028 
04029         if(strcmp(ext,".bat")) DOS_WriteFile(STDOUT,&c,&n);
04030         shell.ShowPrompt();
04031     }
04032 
04033 godefault:
04034     SetCurrentDirectory( Temp_CurrentDir );
04035     return;
04036 }
04037 
04038 void Go_Boot(const char boot_drive[_MAX_DRIVE]) {
04039     if(control->SecureMode()) {
04040         LOG_MSG(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW"));
04041         return;
04042     }
04043 
04044     OPENFILENAME OpenFileName;
04045     char szFile[MAX_PATH];
04046     char CurrentDir[MAX_PATH];
04047     const char * Temp_CurrentDir = CurrentDir;
04048     szFile[0] = 0;
04049     GetCurrentDirectory( MAX_PATH, CurrentDir );
04050 
04051     OpenFileName.lStructSize = sizeof( OPENFILENAME );
04052     OpenFileName.hwndOwner = NULL;
04053 
04054     if(DOSBox_Kor())
04055         OpenFileName.lpstrFilter = "이미지 파일(*.img, *.ima, *.pcjr, *.jrc)\0*.pcjr;*.img;*.ima;*.jrc\0모든 파일(*.*)\0*.*\0";
04056     else
04057         OpenFileName.lpstrFilter = "Image files(*.img, *.ima, *.pcjr, *.jrc)\0*.pcjr;*.img;*.ima;*.jrc\0All files(*.*)\0*.*\0";
04058 
04059     OpenFileName.lpstrCustomFilter = NULL;
04060     OpenFileName.nMaxCustFilter = 0;
04061     OpenFileName.nFilterIndex = 0;
04062     OpenFileName.lpstrFile = szFile;
04063     OpenFileName.nMaxFile = sizeof( szFile );
04064     OpenFileName.lpstrFileTitle = NULL;
04065     OpenFileName.nMaxFileTitle = 0;
04066     OpenFileName.lpstrInitialDir = CurrentDir;
04067     OpenFileName.lpstrTitle = "Select an image file";
04068     OpenFileName.nFileOffset = 0;
04069     OpenFileName.nFileExtension = 0;
04070     OpenFileName.lpstrDefExt = NULL;
04071     OpenFileName.lCustData = 0;
04072     OpenFileName.lpfnHook = NULL;
04073     OpenFileName.lpTemplateName = NULL;
04074     OpenFileName.Flags = OFN_EXPLORER;
04075 search:
04076     if(GetOpenFileName( &OpenFileName )) {
04077         WIN32_FIND_DATA FindFileData;
04078         HANDLE hFind;
04079         char drive  [_MAX_DRIVE]; 
04080         char dir    [_MAX_DIR]; 
04081         char fname  [_MAX_FNAME]; 
04082         char ext    [_MAX_EXT]; 
04083         char * path = 0;
04084         path = szFile;
04085         _splitpath (path, drive, dir, fname, ext);
04086         char ext_temp [_MAX_EXT]; ext_temp[0] = 0; sprintf(ext_temp,ext);
04087 
04088         hFind = FindFirstFile(szFile, &FindFileData);
04089         if (hFind == INVALID_HANDLE_VALUE) goto search;
04090 
04091         if((!strcmp(ext,".img")) || (!strcmp(ext,".pcjr")) || (!strcmp(ext,".jrc")) || (!strcmp(ext,".ima"))) {
04092             extern Bitu ZDRIVE_NUM;
04093             char root[4] = {(char)('A'+ZDRIVE_NUM),':','\\',0};
04094             char cmd[20];
04095             DOS_Shell shell;
04096             Bit16u n=1; Bit8u c='\n';
04097             if(strcmp(boot_drive,"a")) {
04098                 char szFile_pre[MAX_PATH];
04099                 szFile_pre[0] = 0;
04100                 strcpy(szFile_pre,boot_drive);
04101                 strcat(szFile_pre," -t hdd "); 
04102                 strcat(szFile_pre,szFile);
04103                 DOS_WriteFile(STDOUT,&c,&n);
04104                 cmd[0] = 0;
04105                 strcpy(cmd,root);
04106                 strcat(cmd,"imgmount.com");
04107                 shell.Execute(cmd,szFile_pre);
04108                 shell.RunInternal();
04109             }
04110             DOS_WriteFile(STDOUT,&c,&n);
04111             strcat(szFile," -l ");
04112             strcat(szFile,boot_drive);
04113             cmd[0] = 0;
04114             strcpy(cmd,root);
04115             strcat(cmd,"boot.com");
04116             shell.Execute(cmd,szFile);
04117             shell.RunInternal();
04118             DOS_WriteFile(STDOUT,&c,&n);
04119             shell.ShowPrompt(); // if failed
04120         } else {
04121             LOG_MSG("GUI: Unsupported filename extension.");
04122             goto godefault;
04123         }
04124     }
04125 
04126 godefault:
04127     SetCurrentDirectory( Temp_CurrentDir );
04128     return;
04129 }
04130 
04131 void Go_Boot2(const char boot_drive[_MAX_DRIVE]) {
04132     Bit16u n=1; Bit8u c='\n';
04133     DOS_WriteFile(STDOUT,&c,&n);
04134     char temp[7];
04135     extern Bitu ZDRIVE_NUM;
04136     char root[4] = {(char)('A'+ZDRIVE_NUM),':','\\',0};
04137     char cmd[20];
04138     temp[0] = 0;
04139     cmd[0] = 0;
04140     strcpy(cmd,root);
04141     strcat(cmd,"boot.com");
04142     strcpy(temp,"-l ");
04143     strcat(temp,boot_drive);
04144     DOS_Shell shell;
04145     shell.Execute(cmd,temp);
04146     shell.RunInternal();
04147     DOS_WriteFile(STDOUT,&c,&n);
04148     shell.ShowPrompt(); // if failed
04149 }
04150 
04151 /* FIXME: Unused */
04152 void Drag_Drop( char * path_arg ) {
04153     if(control->SecureMode()) {
04154         LOG_MSG(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW"));
04155         return;
04156     }
04157     DOS_MCB mcb(dos.psp()-1);
04158     static char name[9];
04159     mcb.GetFileName(name);
04160     if((!path_arg) || (strlen(name)))  return;
04161     WIN32_FIND_DATA FindFileData;
04162     HANDLE hFind;
04163     char drive  [_MAX_DRIVE]; 
04164     char dir    [_MAX_DIR]; 
04165     char fname  [_MAX_FNAME]; 
04166     char ext    [_MAX_EXT]; 
04167     char szFile[MAX_PATH];
04168 
04169     szFile[0] = 0;
04170     sprintf(szFile,path_arg);
04171     char * path = szFile;
04172     _splitpath (path, drive, dir, fname, ext);
04173     char ext_temp [_MAX_EXT];
04174     ext_temp[0] = 0;
04175     sprintf(ext_temp,ext);
04176 
04177     hFind = FindFirstFile(szFile, &FindFileData);
04178     if (hFind == INVALID_HANDLE_VALUE) return;
04179 
04180     if((!strcmp(ext,".com")) || (!strcmp(ext,".exe")) || (!strcmp(ext,".bat")))
04181         OpenFileDialog(path_arg);
04182     else
04183         LOG_MSG("GUI: Unsupported filename extension.");
04184 }
04185 
04186 HHOOK hhk;
04187 LRESULT CALLBACK CBTProc(INT nCode, WPARAM wParam, LPARAM lParam) {
04188     (void)lParam;
04189     if( HCBT_ACTIVATE == nCode ) {
04190         HWND hChildWnd;
04191         hChildWnd = (HWND)wParam;
04192         SetDlgItemText(hChildWnd,IDYES,"CD-ROM");
04193         SetDlgItemText(hChildWnd,IDNO,"Floppy");
04194         SetDlgItemText(hChildWnd,IDCANCEL,"Harddisk");
04195         UnhookWindowsHookEx(hhk);
04196     }
04197     CallNextHookEx(hhk, nCode, wParam, lParam);
04198     return 0;
04199 }
04200 
04201 int MountMessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ) {
04202     hhk = SetWindowsHookEx( WH_CBT, &CBTProc, 0, GetCurrentThreadId() );
04203     const int iRes = MessageBox( hWnd, lpText, lpCaption, uType | MB_SETFOREGROUND );
04204         return iRes;
04205 }
04206 
04207 void OpenFileDialog_Img( char drive ) {
04208     if(control->SecureMode()) {
04209         LOG_MSG(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW"));
04210         return;
04211     }
04212     if (Drives[drive-'A']) {
04213         LOG_MSG("GUI: Unmount drive %c first, and then try again.",drive);
04214         return;
04215     }
04216     OPENFILENAME OpenFileName;
04217     char szFile[MAX_PATH];
04218     char CurrentDir[MAX_PATH];
04219     const char * Temp_CurrentDir = CurrentDir;
04220 
04221     szFile[0] = 0;
04222     GetCurrentDirectory( MAX_PATH, CurrentDir );
04223     OpenFileName.lStructSize = sizeof( OPENFILENAME );
04224     OpenFileName.hwndOwner = NULL;
04225 
04226     if(DOSBox_Kor())
04227         OpenFileName.lpstrFilter = "이미지/ZIP 파일(*.ima, *.img, *.iso, *.cue, *.bin, *.mdf, *.zip, *.7z)\0*.ima;*.img;*.iso;*.mdf;*.zip;*.cue;*.bin;*.7z\0모든 파일(*.*)\0*.*\0";
04228     else
04229         OpenFileName.lpstrFilter = "Image/Zip files(*.ima, *.img, *.iso, *.cue, *.bin, *.mdf, *.zip, *.7z)\0*.ima;*.img;*.iso;*.mdf;*.zip;*.cue;*.bin;*.7z\0All files(*.*)\0*.*\0";
04230 
04231     OpenFileName.lpstrCustomFilter = NULL;
04232     OpenFileName.nMaxCustFilter = 0;
04233     OpenFileName.nFilterIndex = 0;
04234     OpenFileName.lpstrFile = szFile;
04235     OpenFileName.nMaxFile = sizeof( szFile );
04236     OpenFileName.lpstrFileTitle = NULL;
04237     OpenFileName.nMaxFileTitle = 0;
04238     OpenFileName.lpstrInitialDir = CurrentDir;
04239     OpenFileName.lpstrTitle = "Select an image file";
04240     OpenFileName.nFileOffset = 0;
04241     OpenFileName.nFileExtension = 0;
04242     OpenFileName.lpstrDefExt = NULL;
04243     OpenFileName.lCustData = 0;
04244     OpenFileName.lpfnHook = NULL;
04245     OpenFileName.lpTemplateName = NULL;
04246     OpenFileName.Flags = OFN_EXPLORER;
04247 
04248 search:
04249     if(GetOpenFileName( &OpenFileName )) {
04250         WIN32_FIND_DATA FindFileData;
04251         HANDLE hFind;
04252         hFind = FindFirstFile(szFile, &FindFileData);
04253         if (hFind == INVALID_HANDLE_VALUE) goto search;
04254         char drive2 [_MAX_DRIVE]; 
04255         char dir    [_MAX_DIR]; 
04256         char fname  [_MAX_FNAME]; 
04257         char ext    [_MAX_EXT]; 
04258         char * path = szFile;
04259 
04260         _splitpath (path, drive2, dir, fname, ext);
04261 
04262         if((!strcmp(ext,".img")) || (!strcmp(ext,".iso")) || (!strcmp(ext,".cue")) || (!strcmp(ext,".bin")) || (!strcmp(ext,".mdf"))) {
04263             if(!strcmp(ext,".img")) {
04264                 int whichval=MountMessageBox(GetHWND(),"Drive type:","Mount as Image",MB_YESNOCANCEL);
04265                 if(whichval == IDYES) Mount_Img(drive,path);// CD-ROM
04266                 else if(whichval == IDNO) Mount_Img_Floppy(drive,path); // Floppy
04267                 else if(whichval == IDCANCEL)  Mount_Img_HDD(drive,path);// Harddisk
04268             } else
04269                 Mount_Img(drive,path);
04270         } else if(!strcmp(ext,".ima")) {
04271             Mount_Img_Floppy(drive,path);
04272         } else
04273             LOG_MSG("GUI: Unsupported filename extension.");
04274     }
04275     SetCurrentDirectory( Temp_CurrentDir );
04276 }
04277 #endif
04278 
04279 void* GetSetSDLValue(int isget, std::string target, void* setval) {
04280     if (target == "wait_on_error") {
04281         if (isget) return (void*) sdl.wait_on_error;
04282         else sdl.wait_on_error = setval;
04283     }
04284     else if (target == "opengl.bilinear") {
04285 #if C_OPENGL
04286         if (isget) return (void*) sdl_opengl.bilinear;
04287         else sdl_opengl.bilinear = setval;
04288 #else
04289         if (isget) return (void*) 0;
04290 #endif
04291 /*
04292     } else if (target == "draw.callback") {
04293         if (isget) return (void*) sdl.draw.callback;
04294         else sdl.draw.callback = *static_cast<GFX_CallBack_t*>(setval);
04295     } else if (target == "desktop.full.width") {
04296         if (isget) return (void*) sdl.desktop.full.width;
04297         else sdl.desktop.full.width = *static_cast<Bit16u*>(setval);
04298     } else if (target == "desktop.full.height") {
04299         if (isget) return (void*) sdl.desktop.full.height;
04300         else sdl.desktop.full.height = *static_cast<Bit16u*>(setval);
04301     } else if (target == "desktop.full.fixed") {
04302         if (isget) return (void*) sdl.desktop.full.fixed;
04303         else sdl.desktop.full.fixed = setval;
04304     } else if (target == "desktop.window.width") {
04305         if (isget) return (void*) sdl.desktop.window.width;
04306         else sdl.desktop.window.width = *static_cast<Bit16u*>(setval);
04307     } else if (target == "desktop.window.height") {
04308         if (isget) return (void*) sdl.desktop.window.height;
04309         else sdl.desktop.window.height = *static_cast<Bit16u*>(setval);
04310 */
04311     } else if (target == "desktop.fullscreen") {
04312         if (isget) return (void*) sdl.desktop.fullscreen;
04313         else sdl.desktop.fullscreen = setval;
04314     } else if (target == "desktop.doublebuf") {
04315         if (isget) return (void*) sdl.desktop.doublebuf;
04316         else sdl.desktop.doublebuf = setval;
04317 /*
04318     } else if (target == "desktop.type") {
04319         if (isget) return (void*) sdl.desktop.type;
04320         else sdl.desktop.type = *static_cast<SCREEN_TYPES*>(setval);
04321 */
04322     } else if (target == "desktop.want_type") {
04323         if (isget) return (void*) sdl.desktop.want_type;
04324         else sdl.desktop.want_type = *static_cast<SCREEN_TYPES*>(setval);
04325 /*
04326     } else if (target == "surface") {
04327         if (isget) return (void*) sdl.surface;
04328         else sdl.surface = static_cast<SDL_Surface*>(setval);
04329     } else if (target == "overlay") {
04330         if (isget) return (void*) sdl.overlay;
04331         else sdl.overlay = static_cast<SDL_Overlay*>(setval);
04332 */
04333     } else if (target == "mouse.autoenable") {
04334         if (isget) return (void*) sdl.mouse.autoenable;
04335         else sdl.mouse.autoenable = setval;
04336 /*
04337     } else if (target == "overscan_width") {
04338         if (isget) return (void*) sdl.overscan_width;
04339         else sdl.overscan_width = *static_cast<Bitu*>(setval);
04340 */
04341 #if defined (WIN32)
04342     } else if (target == "using_windib") {
04343         if (isget) return (void*) sdl.using_windib;
04344         else sdl.using_windib = setval;
04345 #endif
04346     }
04347 
04348     return NULL;
04349 }
04350 
04351 #if defined(C_SDL2)
04352 static void FingerToFakeMouseMotion(SDL_TouchFingerEvent * finger) {
04353     SDL_MouseMotionEvent fake;
04354 
04355     memset(&fake,0,sizeof(fake));
04356 #if defined(WIN32)
04357     /* NTS: Windows versions of SDL2 do normalize the coordinates */
04358     fake.x = (Sint32)(finger->x * sdl.clip.w);
04359     fake.y = (Sint32)(finger->y * sdl.clip.h);
04360 #else
04361     /* NTS: Linux versions of SDL2 don't normalize the coordinates? */
04362     fake.x = finger->x;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
04363     fake.y = finger->y;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
04364 #endif
04365     fake.xrel = (Sint32)finger->dx;
04366     fake.yrel = (Sint32)finger->dy;
04367     HandleMouseMotion(&fake);
04368 
04369     if (finger->type == SDL_FINGERDOWN || finger->type == SDL_FINGERUP) {
04370         SDL_MouseButtonEvent fakeb;
04371 
04372         memset(&fakeb,0,sizeof(fakeb));
04373 
04374         fakeb.state = (finger->type == SDL_FINGERDOWN) ? SDL_PRESSED : SDL_RELEASED;
04375         fakeb.button = SDL_BUTTON_LEFT;
04376         fakeb.x = fake.x;
04377         fakeb.y = fake.y;
04378         HandleMouseButton(&fakeb);
04379     }
04380 }
04381 
04382 static void HandleTouchscreenFinger(SDL_TouchFingerEvent * finger) {
04383     /* Now that SDL2 can tell my mouse from my laptop touchscreen, let's
04384      * map tap events to the left mouse button. Now I can use my laptop
04385      * touchscreen with Windows 3.11 again! --J.C. */
04386     /* Now let's handle The Finger (har har) */
04387 
04388     /* NTS: This code is written to map ONLY one finger to the mouse.
04389      *      If multiple fingers are touching the screen, this code will
04390      *      only respond to the first finger that touched the screen. */
04391 
04392     if (finger->type == SDL_FINGERDOWN) {
04393         if (touchscreen_finger_lock == no_finger_id &&
04394             touchscreen_touch_lock == no_touch_id) {
04395             touchscreen_finger_lock = finger->fingerId;
04396             touchscreen_touch_lock = finger->touchId;
04397             FingerToFakeMouseMotion(finger);
04398             Mouse_ButtonPressed(0);
04399         }
04400     }
04401     else if (finger->type == SDL_FINGERUP) {
04402         if (touchscreen_finger_lock == finger->fingerId &&
04403             touchscreen_touch_lock == finger->touchId) {
04404             touchscreen_finger_lock = no_finger_id;
04405             touchscreen_touch_lock = no_touch_id;
04406             FingerToFakeMouseMotion(finger);
04407             Mouse_ButtonReleased(0);
04408         }
04409     }
04410     else if (finger->type == SDL_FINGERMOTION) {
04411         if (touchscreen_finger_lock == finger->fingerId &&
04412             touchscreen_touch_lock == finger->touchId) {
04413             FingerToFakeMouseMotion(finger);
04414         }
04415     }
04416 }
04417 #endif
04418 
04419 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
04420 void MSG_WM_COMMAND_handle(SDL_SysWMmsg &Message);
04421 #endif
04422 
04423 struct mouse_pos
04424 {
04425     long x = 0;
04426     long y = 0;
04427 } mouse_pos;
04428 
04429 bool mouse_inside = false;
04430 
04431 void GFX_EventsMouseProcess(const long x, const long y, const long rx, const long ry)
04432 {
04433     const auto x1 = sdl.clip.x;
04434     const auto x2 = x1 + sdl.clip.w - 1;
04435     const auto y1 = sdl.clip.y;
04436     const auto y2 = y1 + sdl.clip.h - 1;
04437     const auto in = x >= x1 && x <= x2 && y >= y1 && y <= y2;
04438 
04439     if (mouse_inside && !in)
04440     {
04441         const auto x3 = max((int)x1, min((int)x2, (int)x));
04442         const auto y3 = max((int)y1, min((int)y2, (int)y));
04443         SDL_Event  evt;
04444         evt.type         = SDL_MOUSEMOTION;
04445         evt.motion.state = 0;
04446         evt.motion.which = 0;
04447         evt.motion.x     = x3;
04448         evt.motion.y     = y3;
04449         evt.motion.xrel  = (Sint16)((rx >= 0) ? min(rx, 32767l) : max(rx, -32768l));
04450         evt.motion.yrel  = (Sint16)((ry >= 0) ? min(ry, 32767l) : max(ry, -32768l));
04451         SDL_PushEvent(&evt);
04452     }
04453 
04454     mouse_inside = in;
04455 }
04456 
04457 #if defined(WIN32)
04458 void GFX_EventsMouseWin32()
04459 {
04460     /* Compute relative mouse movement */
04461 
04462     POINT point;
04463 
04464     if (!GetCursorPos(&point))
04465         return;
04466 
04467     const auto hwnd = GetSurfaceHWND();
04468 
04469     if (hwnd == nullptr || !ScreenToClient(hwnd, &point))
04470         return;
04471 
04472     const auto x  = point.x;
04473     const auto y  = point.y;
04474     const auto rx = x - mouse_pos.x;
04475     const auto ry = y - mouse_pos.y;
04476 
04477     mouse_pos.x = x;
04478     mouse_pos.y = y;
04479 
04480     /* Let the method do the heavy uplifting */
04481     GFX_EventsMouseProcess(x, y, rx, ry);
04482 }
04483 #endif
04484 
04491 void GFX_EventsMouse()
04492 {
04493     if (sdl.desktop.fullscreen || sdl.mouse.locked)
04494         return;
04495 
04496 #if WIN32
04497     GFX_EventsMouseWin32();
04498 #else
04499     // TODO
04500 #endif
04501 }
04502 
04503 void GFX_Events() {
04504     CheckMapperKeyboardLayout();
04505 #if defined(C_SDL2) /* SDL 2.x---------------------------------- */
04506     SDL_Event event;
04507 #if defined (REDUCE_JOYSTICK_POLLING)
04508     static int poll_delay=0;
04509     int time=GetTicks();
04510     if (time-poll_delay>20) {
04511         poll_delay=time;
04512         if (sdl.num_joysticks>0)
04513         {
04514             SDL_JoystickUpdate();
04515             MAPPER_UpdateJoysticks();
04516         }
04517     }
04518 #endif
04519 
04520     GFX_EventsMouse();
04521 
04522 #if C_EMSCRIPTEN
04523     emscripten_sleep_with_yield(0);
04524 #endif
04525 
04526     while (SDL_PollEvent(&event)) {
04527         switch (event.type) {
04528         case SDL_WINDOWEVENT:
04529             switch (event.window.event) {
04530             case SDL_WINDOWEVENT_RESTORED:
04531                 GFX_ResetScreen();
04532                 continue;
04533             case SDL_WINDOWEVENT_RESIZED:
04534                 GFX_HandleVideoResize(event.window.data1, event.window.data2);
04535                 continue;
04536             case SDL_WINDOWEVENT_EXPOSED:
04537                 if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw );
04538                 continue;
04539             case SDL_WINDOWEVENT_FOCUS_GAINED:
04540                 if (IsFullscreen() && !sdl.mouse.locked)
04541                     GFX_CaptureMouse();
04542                 SetPriority(sdl.priority.focus);
04543                 CPU_Disable_SkipAutoAdjust();
04544                 break;
04545             case SDL_WINDOWEVENT_FOCUS_LOST:
04546                 if (sdl.mouse.locked) {
04547                     CaptureMouseNotify();
04548                     GFX_CaptureMouse();
04549                 }
04550                 SetPriority(sdl.priority.nofocus);
04551                 GFX_LosingFocus();
04552                 CPU_Enable_SkipAutoAdjust();
04553                 break;
04554             default:
04555                 ;
04556             }
04557 
04558             /* Non-focus priority is set to pause; check to see if we've lost window or input focus
04559              * i.e. has the window been minimised or made inactive?
04560              */
04561             if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) {
04562                 if ((event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (event.window.event == SDL_WINDOWEVENT_MINIMIZED)) {
04563                     /* Window has lost focus, pause the emulator.
04564                      * This is similar to what PauseDOSBox() does, but the exit criteria is different.
04565                      * Instead of waiting for the user to hit Alt-Break, we wait for the window to
04566                      * regain window or input focus.
04567                      */
04568                     bool paused = true;
04569                     SDL_Event ev;
04570 
04571                     GFX_SetTitle(-1,-1,-1,true);
04572                     KEYBOARD_ClrBuffer();
04573 //                  SDL_Delay(500);
04574 //                  while (SDL_PollEvent(&ev)) {
04575                     // flush event queue.
04576 //                  }
04577 
04578                     while (paused) {
04579 #if C_EMSCRIPTEN
04580                         emscripten_sleep_with_yield(0);
04581                         SDL_PollEvent(&ev);
04582 #else
04583                         // WaitEvent waits for an event rather than polling, so CPU usage drops to zero
04584                         SDL_WaitEvent(&ev);
04585 #endif
04586 
04587                         switch (ev.type) {
04588                         case SDL_QUIT:
04589                             throw(0);
04590                             break; // a bit redundant at linux at least as the active events gets before the quit event.
04591                         case SDL_WINDOWEVENT:     // wait until we get window focus back
04592                             if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (ev.window.event == SDL_WINDOWEVENT_MINIMIZED) || (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) {
04593                                 // We've got focus back, so unpause and break out of the loop
04594                                 if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) {
04595                                     paused = false;
04596                                     GFX_SetTitle(-1,-1,-1,false);
04597                                 }
04598 
04599                                 /* Now poke a "release ALT" command into the keyboard buffer
04600                                  * we have to do this, otherwise ALT will 'stick' and cause
04601                                  * problems with the app running in the DOSBox.
04602                                  */
04603                                 KEYBOARD_AddKey(KBD_leftalt, false);
04604                                 KEYBOARD_AddKey(KBD_rightalt, false);
04605                                 if (ev.window.event == SDL_WINDOWEVENT_RESTORED) {
04606                                     // We may need to re-create a texture and more
04607                                     GFX_ResetScreen();
04608                                 }
04609                             }
04610                             break;
04611                         }
04612                     }
04613                 }
04614             }
04615             break;
04616         case SDL_MOUSEMOTION:
04617 #if defined(C_SDL2)
04618             if (touchscreen_finger_lock == no_finger_id &&
04619                 touchscreen_touch_lock == no_touch_id &&
04620                 event.motion.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */
04621                 HandleMouseMotion(&event.motion);
04622             }
04623 #else
04624             HandleMouseMotion(&event.motion);
04625 #endif
04626             break;
04627         case SDL_MOUSEBUTTONDOWN:
04628         case SDL_MOUSEBUTTONUP:
04629 #if defined(C_SDL2)
04630             if (touchscreen_finger_lock == no_finger_id &&
04631                 touchscreen_touch_lock == no_touch_id &&
04632                 event.button.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */
04633                 HandleMouseButton(&event.button);
04634             }
04635 #else
04636             HandleMouseButton(&event.button);
04637 #endif
04638             break;
04639         case SDL_FINGERDOWN:
04640         case SDL_FINGERUP:
04641         case SDL_FINGERMOTION:
04642             HandleTouchscreenFinger(&event.tfinger);
04643             break;
04644         case SDL_QUIT:
04645             throw(0);
04646             break;
04647 #if defined (MACOSX)
04648         case SDL_KEYDOWN:
04649         case SDL_KEYUP:
04650             /* On macs CMD-Q is the default key to close an application */
04651             if (event.key.keysym.sym == SDLK_q &&
04652                     (event.key.keysym.mod == KMOD_RGUI ||
04653                      event.key.keysym.mod == KMOD_LGUI)
04654                ) {
04655                 KillSwitch(true);
04656                 break;
04657             }
04658 #endif
04659         default:
04660             void MAPPER_CheckEvent(SDL_Event * event);
04661             MAPPER_CheckEvent(&event);
04662         }
04663     }
04664 #else /* SDL 1.x---------------------------------- */
04665     SDL_Event event;
04666 #if defined (REDUCE_JOYSTICK_POLLING)
04667     static uint32_t poll_delay=0;
04668     uint32_t time=GetTicks();
04669     if ((int32_t)(time-poll_delay)>20) {
04670         poll_delay=time;
04671         if (sdl.num_joysticks>0)
04672         {
04673             SDL_JoystickUpdate();
04674             MAPPER_UpdateJoysticks();
04675         }
04676     }
04677 #endif
04678 
04679     GFX_EventsMouse();
04680 
04681 #if C_EMSCRIPTEN
04682     emscripten_sleep_with_yield(0);
04683 #endif
04684 
04685     while (SDL_PollEvent(&event)) {
04686         switch (event.type) {
04687 #ifdef __WIN32__
04688         case SDL_SYSWMEVENT : {
04689             switch( event.syswm.msg->msg ) {
04690 #if !defined(HX_DOS)
04691                 case WM_COMMAND:
04692                     MSG_WM_COMMAND_handle(/*&*/(*event.syswm.msg));
04693                     break;
04694 #endif
04695                 case WM_SYSCOMMAND:
04696                     switch (event.syswm.msg->wParam) {
04697                         case 0xF032: // FIXME: What is this?
04698                         case SC_MAXIMIZE:
04699                             userResizeWindowWidth = 0;
04700                             userResizeWindowHeight = 0;
04701                             menu.maxwindow = true;
04702                             break;
04703                         case 0xF122: // FIXME: What is this?
04704                         case SC_RESTORE:
04705                             if (sdl.desktop.fullscreen)
04706                                 GFX_SwitchFullScreen();
04707                             menu.maxwindow = false;
04708                             UpdateWindowDimensions();
04709                             RENDER_Reset();
04710                             if (OpenGL_using()) {
04711                                 UpdateWindowDimensions();
04712                                 RENDER_Reset();
04713                             }
04714                             break;
04715                         case ID_WIN_SYSMENU_RESTOREMENU:
04716                             /* prevent removing the menu in 3Dfx mode */
04717                             if (!GFX_GetPreventFullscreen()) {
04718                                 DOSBox_SetMenu();
04719                                 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu);
04720                             }
04721                             break;
04722                         case ID_WIN_SYSMENU_TOGGLEMENU:
04723                             /* prevent removing the menu in 3Dfx mode */
04724                             if (!GFX_GetPreventFullscreen())
04725                             {
04726                                 if (menu.toggle) DOSBox_NoMenu(); else DOSBox_SetMenu();
04727                                 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu);
04728                             }
04729                             break;
04730                     }
04731                 default:
04732                     break;
04733             }
04734         }
04735 #endif
04736         case SDL_ACTIVEEVENT:
04737                 if (event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) {
04738                 if (event.active.gain) {
04739                     if (sdl.desktop.fullscreen && !sdl.mouse.locked)
04740                         GFX_CaptureMouse();
04741                     SetPriority(sdl.priority.focus);
04742                     CPU_Disable_SkipAutoAdjust();
04743                                         BIOS_SynchronizeNumLock();
04744                                         BIOS_SynchronizeCapsLock();
04745                                         BIOS_SynchronizeScrollLock();
04746                                 } else {
04747                     if (sdl.mouse.locked)
04748                     {
04749                         CaptureMouseNotify();
04750                         GFX_CaptureMouse();
04751                     }
04752 
04753 #if defined(WIN32)
04754                     if (sdl.desktop.fullscreen)
04755                         GFX_ForceFullscreenExit();
04756 #endif
04757 
04758                     SetPriority(sdl.priority.nofocus);
04759                     GFX_LosingFocus();
04760                     CPU_Enable_SkipAutoAdjust();
04761                 }
04762             }
04763 
04764             /* Non-focus priority is set to pause; check to see if we've lost window or input focus
04765              * i.e. has the window been minimised or made inactive?
04766              */
04767             if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) {
04768                 if ((event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) && (!event.active.gain)) {
04769                     /* Window has lost focus, pause the emulator.
04770                      * This is similar to what PauseDOSBox() does, but the exit criteria is different.
04771                      * Instead of waiting for the user to hit Alt-Break, we wait for the window to
04772                      * regain window or input focus.
04773                      */
04774                     bool paused = true;
04775                     SDL_Event ev;
04776 
04777                     GFX_SetTitle(-1,-1,-1,true);
04778                     KEYBOARD_ClrBuffer();
04779 //                  SDL_Delay(500);
04780 //                  while (SDL_PollEvent(&ev)) {
04781                         // flush event queue.
04782 //                  }
04783 
04784                     while (paused) {
04785 #if C_EMSCRIPTEN
04786                         emscripten_sleep_with_yield(0);
04787                         SDL_PollEvent(&ev);
04788 #else
04789                         // WaitEvent waits for an event rather than polling, so CPU usage drops to zero
04790                         SDL_WaitEvent(&ev);
04791 #endif
04792 
04793                         switch (ev.type) {
04794                         case SDL_QUIT: throw(0); break; // a bit redundant at linux at least as the active events gets before the quit event.
04795                         case SDL_ACTIVEEVENT:     // wait until we get window focus back
04796                             if (ev.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) {
04797                                 // We've got focus back, so unpause and break out of the loop
04798                                 if (ev.active.gain) {
04799                                     paused = false;
04800                                     GFX_SetTitle(-1,-1,-1,false);
04801                                 }
04802 
04803                                 /* Now poke a "release ALT" command into the keyboard buffer
04804                                  * we have to do this, otherwise ALT will 'stick' and cause
04805                                  * problems with the app running in the DOSBox.
04806                                  */
04807                                 KEYBOARD_AddKey(KBD_leftalt, false);
04808                                 KEYBOARD_AddKey(KBD_rightalt, false);
04809                             }
04810                             break;
04811                         }
04812                     }
04813                 }
04814             }
04815             break;
04816         case SDL_MOUSEMOTION:
04817             HandleMouseMotion(&event.motion);
04818             break;
04819         case SDL_MOUSEBUTTONDOWN:
04820         case SDL_MOUSEBUTTONUP:
04821             HandleMouseButton(&event.button);
04822             break;
04823         case SDL_VIDEORESIZE:
04824             UpdateWindowDimensions(); // FIXME: Use SDL window dimensions, except that on Windows, SDL won't tell us our actual dimensions
04825             HandleVideoResize(&event.resize);
04826             break;
04827         case SDL_QUIT:
04828             throw(0);
04829             break;
04830         case SDL_VIDEOEXPOSE:
04831             if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw );
04832             break;
04833 #ifdef WIN32
04834         case SDL_KEYDOWN:
04835         case SDL_KEYUP:
04836             // ignore event alt+tab
04837             if (event.key.keysym.sym==SDLK_LALT) sdl.laltstate = event.key.type;
04838             if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type;
04839             if (((event.key.keysym.sym==SDLK_TAB)) &&
04840                 ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) { MAPPER_LosingFocus(); break; }
04841 #endif
04842 #if defined (MACOSX)            
04843         case SDL_KEYDOWN:
04844         case SDL_KEYUP:
04845             /* On macs CMD-Q is the default key to close an application */
04846             if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) {
04847                 KillSwitch(true);
04848                 break;
04849             } 
04850 #endif
04851         default:
04852             void MAPPER_CheckEvent(SDL_Event * event);
04853             MAPPER_CheckEvent(&event);
04854         }
04855     }
04856     // start emendelson from dbDOS
04857     // Disabled multiple characters per dispatch b/c occasionally
04858     // keystrokes get lost in the spew. (Prob b/c of DI usage on Win32, sadly..)
04859     // while (PasteClipboardNext());
04860     // Doesn't really matter though, it's fast enough as it is...
04861     static Bitu iPasteTicker = 0;
04862     if ((iPasteTicker++ % 20) == 0) // emendelson: was %2, %20 is good for WP51
04863         PasteClipboardNext();   // end added emendelson from dbDOS
04864 #endif
04865 }
04866 
04867 // added emendelson from dbDos
04868 #if defined(WIN32) && !defined(C_SDL2) && !defined(__MINGW32__)
04869 #include <cassert>
04870 
04871 // Ripped from SDL's SDL_dx5events.c, since there's no API to access it...
04872 #define DIRECTINPUT_VERSION 0x0800
04873 #include <dinput.h>
04874 #ifndef DIK_PAUSE
04875 #define DIK_PAUSE   0xC5
04876 #endif
04877 #ifndef DIK_OEM_102
04878 #define DIK_OEM_102 0x56    /* < > | on UK/Germany keyboards */
04879 #endif
04880 static SDLKey aryScanCodeToSDLKey[0xFF];
04881 static bool   bScanCodeMapInited = false;
04882 static void PasteInitMapSCToSDLKey()
04883 {
04884     /* Map the DIK scancodes to SDL keysyms */
04885     for (int i = 0; i<SDL_arraysize(aryScanCodeToSDLKey); ++i)
04886         aryScanCodeToSDLKey[i] = SDLK_UNKNOWN;
04887 
04888     /* Defined DIK_* constants */
04889     aryScanCodeToSDLKey[DIK_ESCAPE] = SDLK_ESCAPE;
04890     aryScanCodeToSDLKey[DIK_1] = SDLK_1;
04891     aryScanCodeToSDLKey[DIK_2] = SDLK_2;
04892     aryScanCodeToSDLKey[DIK_3] = SDLK_3;
04893     aryScanCodeToSDLKey[DIK_4] = SDLK_4;
04894     aryScanCodeToSDLKey[DIK_5] = SDLK_5;
04895     aryScanCodeToSDLKey[DIK_6] = SDLK_6;
04896     aryScanCodeToSDLKey[DIK_7] = SDLK_7;
04897     aryScanCodeToSDLKey[DIK_8] = SDLK_8;
04898     aryScanCodeToSDLKey[DIK_9] = SDLK_9;
04899     aryScanCodeToSDLKey[DIK_0] = SDLK_0;
04900     aryScanCodeToSDLKey[DIK_MINUS] = SDLK_MINUS;
04901     aryScanCodeToSDLKey[DIK_EQUALS] = SDLK_EQUALS;
04902     aryScanCodeToSDLKey[DIK_BACK] = SDLK_BACKSPACE;
04903     aryScanCodeToSDLKey[DIK_TAB] = SDLK_TAB;
04904     aryScanCodeToSDLKey[DIK_Q] = SDLK_q;
04905     aryScanCodeToSDLKey[DIK_W] = SDLK_w;
04906     aryScanCodeToSDLKey[DIK_E] = SDLK_e;
04907     aryScanCodeToSDLKey[DIK_R] = SDLK_r;
04908     aryScanCodeToSDLKey[DIK_T] = SDLK_t;
04909     aryScanCodeToSDLKey[DIK_Y] = SDLK_y;
04910     aryScanCodeToSDLKey[DIK_U] = SDLK_u;
04911     aryScanCodeToSDLKey[DIK_I] = SDLK_i;
04912     aryScanCodeToSDLKey[DIK_O] = SDLK_o;
04913     aryScanCodeToSDLKey[DIK_P] = SDLK_p;
04914     aryScanCodeToSDLKey[DIK_LBRACKET] = SDLK_LEFTBRACKET;
04915     aryScanCodeToSDLKey[DIK_RBRACKET] = SDLK_RIGHTBRACKET;
04916     aryScanCodeToSDLKey[DIK_RETURN] = SDLK_RETURN;
04917     aryScanCodeToSDLKey[DIK_LCONTROL] = SDLK_LCTRL;
04918     aryScanCodeToSDLKey[DIK_A] = SDLK_a;
04919     aryScanCodeToSDLKey[DIK_S] = SDLK_s;
04920     aryScanCodeToSDLKey[DIK_D] = SDLK_d;
04921     aryScanCodeToSDLKey[DIK_F] = SDLK_f;
04922     aryScanCodeToSDLKey[DIK_G] = SDLK_g;
04923     aryScanCodeToSDLKey[DIK_H] = SDLK_h;
04924     aryScanCodeToSDLKey[DIK_J] = SDLK_j;
04925     aryScanCodeToSDLKey[DIK_K] = SDLK_k;
04926     aryScanCodeToSDLKey[DIK_L] = SDLK_l;
04927     aryScanCodeToSDLKey[DIK_SEMICOLON] = SDLK_SEMICOLON;
04928     aryScanCodeToSDLKey[DIK_APOSTROPHE] = SDLK_QUOTE;
04929     aryScanCodeToSDLKey[DIK_GRAVE] = SDLK_BACKQUOTE;
04930     aryScanCodeToSDLKey[DIK_LSHIFT] = SDLK_LSHIFT;
04931     aryScanCodeToSDLKey[DIK_BACKSLASH] = SDLK_BACKSLASH;
04932     aryScanCodeToSDLKey[DIK_OEM_102] = SDLK_LESS;
04933     aryScanCodeToSDLKey[DIK_Z] = SDLK_z;
04934     aryScanCodeToSDLKey[DIK_X] = SDLK_x;
04935     aryScanCodeToSDLKey[DIK_C] = SDLK_c;
04936     aryScanCodeToSDLKey[DIK_V] = SDLK_v;
04937     aryScanCodeToSDLKey[DIK_B] = SDLK_b;
04938     aryScanCodeToSDLKey[DIK_N] = SDLK_n;
04939     aryScanCodeToSDLKey[DIK_M] = SDLK_m;
04940     aryScanCodeToSDLKey[DIK_COMMA] = SDLK_COMMA;
04941     aryScanCodeToSDLKey[DIK_PERIOD] = SDLK_PERIOD;
04942     aryScanCodeToSDLKey[DIK_SLASH] = SDLK_SLASH;
04943     aryScanCodeToSDLKey[DIK_RSHIFT] = SDLK_RSHIFT;
04944     aryScanCodeToSDLKey[DIK_MULTIPLY] = SDLK_KP_MULTIPLY;
04945     aryScanCodeToSDLKey[DIK_LMENU] = SDLK_LALT;
04946     aryScanCodeToSDLKey[DIK_SPACE] = SDLK_SPACE;
04947     aryScanCodeToSDLKey[DIK_CAPITAL] = SDLK_CAPSLOCK;
04948     aryScanCodeToSDLKey[DIK_F1] = SDLK_F1;
04949     aryScanCodeToSDLKey[DIK_F2] = SDLK_F2;
04950     aryScanCodeToSDLKey[DIK_F3] = SDLK_F3;
04951     aryScanCodeToSDLKey[DIK_F4] = SDLK_F4;
04952     aryScanCodeToSDLKey[DIK_F5] = SDLK_F5;
04953     aryScanCodeToSDLKey[DIK_F6] = SDLK_F6;
04954     aryScanCodeToSDLKey[DIK_F7] = SDLK_F7;
04955     aryScanCodeToSDLKey[DIK_F8] = SDLK_F8;
04956     aryScanCodeToSDLKey[DIK_F9] = SDLK_F9;
04957     aryScanCodeToSDLKey[DIK_F10] = SDLK_F10;
04958     aryScanCodeToSDLKey[DIK_NUMLOCK] = SDLK_NUMLOCK;
04959     aryScanCodeToSDLKey[DIK_SCROLL] = SDLK_SCROLLOCK;
04960     aryScanCodeToSDLKey[DIK_NUMPAD7] = SDLK_KP7;
04961     aryScanCodeToSDLKey[DIK_NUMPAD8] = SDLK_KP8;
04962     aryScanCodeToSDLKey[DIK_NUMPAD9] = SDLK_KP9;
04963     aryScanCodeToSDLKey[DIK_SUBTRACT] = SDLK_KP_MINUS;
04964     aryScanCodeToSDLKey[DIK_NUMPAD4] = SDLK_KP4;
04965     aryScanCodeToSDLKey[DIK_NUMPAD5] = SDLK_KP5;
04966     aryScanCodeToSDLKey[DIK_NUMPAD6] = SDLK_KP6;
04967     aryScanCodeToSDLKey[DIK_ADD] = SDLK_KP_PLUS;
04968     aryScanCodeToSDLKey[DIK_NUMPAD1] = SDLK_KP1;
04969     aryScanCodeToSDLKey[DIK_NUMPAD2] = SDLK_KP2;
04970     aryScanCodeToSDLKey[DIK_NUMPAD3] = SDLK_KP3;
04971     aryScanCodeToSDLKey[DIK_NUMPAD0] = SDLK_KP0;
04972     aryScanCodeToSDLKey[DIK_DECIMAL] = SDLK_KP_PERIOD;
04973     aryScanCodeToSDLKey[DIK_F11] = SDLK_F11;
04974     aryScanCodeToSDLKey[DIK_F12] = SDLK_F12;
04975 
04976     aryScanCodeToSDLKey[DIK_F13] = SDLK_F13;
04977     aryScanCodeToSDLKey[DIK_F14] = SDLK_F14;
04978     aryScanCodeToSDLKey[DIK_F15] = SDLK_F15;
04979 
04980     aryScanCodeToSDLKey[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS;
04981     aryScanCodeToSDLKey[DIK_NUMPADENTER] = SDLK_KP_ENTER;
04982     aryScanCodeToSDLKey[DIK_RCONTROL] = SDLK_RCTRL;
04983     aryScanCodeToSDLKey[DIK_DIVIDE] = SDLK_KP_DIVIDE;
04984     aryScanCodeToSDLKey[DIK_SYSRQ] = SDLK_PRINT;
04985     aryScanCodeToSDLKey[DIK_RMENU] = SDLK_RALT;
04986     aryScanCodeToSDLKey[DIK_PAUSE] = SDLK_PAUSE;
04987     aryScanCodeToSDLKey[DIK_HOME] = SDLK_HOME;
04988     aryScanCodeToSDLKey[DIK_UP] = SDLK_UP;
04989     aryScanCodeToSDLKey[DIK_PRIOR] = SDLK_PAGEUP;
04990     aryScanCodeToSDLKey[DIK_LEFT] = SDLK_LEFT;
04991     aryScanCodeToSDLKey[DIK_RIGHT] = SDLK_RIGHT;
04992     aryScanCodeToSDLKey[DIK_END] = SDLK_END;
04993     aryScanCodeToSDLKey[DIK_DOWN] = SDLK_DOWN;
04994     aryScanCodeToSDLKey[DIK_NEXT] = SDLK_PAGEDOWN;
04995     aryScanCodeToSDLKey[DIK_INSERT] = SDLK_INSERT;
04996     aryScanCodeToSDLKey[DIK_DELETE] = SDLK_DELETE;
04997     aryScanCodeToSDLKey[DIK_LWIN] = SDLK_LMETA;
04998     aryScanCodeToSDLKey[DIK_RWIN] = SDLK_RMETA;
04999     aryScanCodeToSDLKey[DIK_APPS] = SDLK_MENU;
05000 
05001     bScanCodeMapInited = true;
05002 }
05003 
05004 static std::string strPasteBuffer;
05005 // Just in case, to keep us from entering an unexpected KB state
05006 const  size_t      kPasteMinBufExtra = 4;
05008 static void GenKBStroke(const UINT uiScanCode, const bool bDepressed, const SDLMod keymods)
05009 {
05010     const SDLKey sdlkey = aryScanCodeToSDLKey[uiScanCode];
05011     if (sdlkey == SDLK_UNKNOWN)
05012         return;
05013 
05014     SDL_Event evntKeyStroke = { 0 };
05015     evntKeyStroke.type = bDepressed ? SDL_KEYDOWN : SDL_KEYUP;
05016     evntKeyStroke.key.keysym.scancode = (unsigned char)LOBYTE(uiScanCode);
05017     evntKeyStroke.key.keysym.sym = sdlkey;
05018     evntKeyStroke.key.keysym.mod = keymods;
05019     evntKeyStroke.key.keysym.unicode = 0;
05020     evntKeyStroke.key.state = bDepressed ? SDL_PRESSED : SDL_RELEASED;
05021     SDL_PushEvent(&evntKeyStroke);
05022 }
05023 
05024 static bool PasteClipboardNext()
05025 {
05026     if (strPasteBuffer.length() == 0)
05027         return false;
05028 
05029     if (!bScanCodeMapInited)
05030         PasteInitMapSCToSDLKey();
05031 
05032     const char cKey = strPasteBuffer[0];
05033     SHORT shVirKey = VkKeyScan(cKey); // If it fails then MapVirtK will also fail, so no bail yet
05034     UINT uiScanCode = MapVirtualKey(LOBYTE(shVirKey), MAPVK_VK_TO_VSC);
05035     if (uiScanCode)
05036     {
05037         const bool   bModShift = ((shVirKey & 0x0100) != 0);
05038         const bool   bModCntrl = ((shVirKey & 0x0200) != 0);
05039         const bool   bModAlt = ((shVirKey & 0x0400) != 0);
05040         const SDLMod sdlmModsOn = SDL_GetModState();
05041         const bool   bModShiftOn = ((sdlmModsOn & (KMOD_LSHIFT | KMOD_RSHIFT)) > 0);
05042         const bool   bModCntrlOn = ((sdlmModsOn & (KMOD_LCTRL | KMOD_RCTRL)) > 0);
05043         const bool   bModAltOn = ((sdlmModsOn & (KMOD_LALT | KMOD_RALT)) > 0);
05044         const UINT   uiScanCodeShift = MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC);
05045         const UINT   uiScanCodeCntrl = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC);
05046         const UINT   uiScanCodeAlt = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC);
05047         const SDLMod sdlmMods = (SDLMod)((sdlmModsOn & ~(KMOD_LSHIFT | KMOD_RSHIFT |
05048             KMOD_LCTRL | KMOD_RCTRL |
05049             KMOD_LALT | KMOD_RALT)) |
05050             (bModShiftOn ? KMOD_LSHIFT : 0) |
05051             (bModCntrlOn ? KMOD_LCTRL : 0) |
05052             (bModAltOn ? KMOD_LALT : 0));
05053 
05056         // Could be made more efficient, but would require tracking of more state,
05057         // so let's forgot that for now...
05058         size_t sStrokesRequired = 2; // At least the key & up/down
05059         if (bModShift != bModShiftOn) sStrokesRequired += 2; // To press/release Shift
05060         if (bModCntrl != bModCntrlOn) sStrokesRequired += 2; // To press/release Control
05061         if (bModAlt != bModAltOn) sStrokesRequired += 2; // To press/release Alt
05066         if (KEYBOARD_BufferSpaceAvail() < (sStrokesRequired + kPasteMinBufExtra))
05067             return false;
05068 
05069         if (bModShift != bModShiftOn) GenKBStroke(uiScanCodeShift, !bModShiftOn, sdlmMods);
05070         if (bModCntrl != bModCntrlOn) GenKBStroke(uiScanCodeCntrl, !bModCntrlOn, sdlmMods);
05071         if (bModAlt != bModAltOn) GenKBStroke(uiScanCodeAlt, !bModAltOn, sdlmMods);
05072         GenKBStroke(uiScanCode, true, sdlmMods);
05073         GenKBStroke(uiScanCode, false, sdlmMods);
05074         if (bModShift != bModShiftOn) GenKBStroke(uiScanCodeShift, bModShiftOn, sdlmMods);
05075         if (bModCntrl != bModCntrlOn) GenKBStroke(uiScanCodeCntrl, bModCntrlOn, sdlmMods);
05076         if (bModAlt != bModAltOn) GenKBStroke(uiScanCodeAlt, bModAltOn, sdlmMods);
05077         //putchar(cKey); // For debugging dropped strokes
05078     }
05079 
05080     // Pop head. Could be made more efficient, but this is neater.
05081     strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length()); // technically -1, but it clamps by itself anyways...
05082     return true;
05083 }
05084 
05085 void PasteClipboard(bool bPressed)
05086 {
05087     if (!bPressed) return;
05088     SDL_SysWMinfo wmiInfo;
05089     SDL_VERSION(&wmiInfo.version);
05090 
05091     if (SDL_GetWMInfo(&wmiInfo) != 1) return;
05092     if (!::OpenClipboard(wmiInfo.window)) return;
05093     if (!::IsClipboardFormatAvailable(CF_TEXT)) return;
05094 
05095     HANDLE hContents = ::GetClipboardData(CF_TEXT);
05096     if (!hContents) return;
05097 
05098     const char* szClipboard = (const char*)::GlobalLock(hContents);
05099     if (szClipboard)
05100     {
05101         // Create a copy of the string, and filter out Linefeed characters (ASCII '10')
05102         size_t sClipboardLen = strlen(szClipboard);
05103         char* szFilteredText = reinterpret_cast<char*>(alloca(sClipboardLen + 1));
05104         char* szFilterNextChar = szFilteredText;
05105         for (size_t i = 0; i < sClipboardLen; ++i)
05106             if (szClipboard[i] != 0x0A) // Skip linefeeds
05107             {
05108                 *szFilterNextChar = szClipboard[i];
05109                 ++szFilterNextChar;
05110             }
05111         *szFilterNextChar = '\0'; // Cap it.
05112 
05113         strPasteBuffer.append(szFilteredText);
05114         ::GlobalUnlock(hContents);
05115     }
05116 
05117     ::CloseClipboard();
05118 }
05120 #else // end emendelson from dbDOS
05121 void PasteClipboard(bool bPressed) {
05122     (void)bPressed;//UNUSED
05123     // stub
05124 }
05125 
05126 # if !defined(C_SDL2)
05127 bool PasteClipboardNext() {
05128     // stub
05129     return false;
05130 }
05131 # endif
05132 #endif
05133 
05134 
05135 #if defined (WIN32)
05136 static BOOL WINAPI ConsoleEventHandler(DWORD event) {
05137     switch (event) {
05138     case CTRL_SHUTDOWN_EVENT:
05139     case CTRL_LOGOFF_EVENT:
05140     case CTRL_CLOSE_EVENT:
05141     case CTRL_BREAK_EVENT:
05142         raise(SIGTERM);
05143         return TRUE;
05144     case CTRL_C_EVENT:
05145     default: //pass to the next handler
05146         return FALSE;
05147     }
05148 }
05149 #endif
05150 
05151 void Null_Init(Section *sec);
05152 
05153 void SDL_SetupConfigSection() {
05154     Section_prop * sdl_sec=control->AddSection_prop("sdl",&Null_Init);
05155 
05156     Prop_bool* Pbool;
05157     Prop_string* Pstring;
05158     Prop_int* Pint;
05159     Prop_multival* Pmulti;
05160 
05161     Pbool = sdl_sec->Add_bool("fullscreen",Property::Changeable::Always,false);
05162     Pbool->Set_help("Start dosbox directly in fullscreen. (Press ALT-Enter to go back)");
05163      
05164     Pbool = sdl_sec->Add_bool("fulldouble",Property::Changeable::Always,false);
05165     Pbool->Set_help("Use double buffering in fullscreen. It can reduce screen flickering, but it can also result in a slow DOSBox.");
05166 
05167     //Pbool = sdl_sec->Add_bool("sdlresize",Property::Changeable::Always,false);
05168     //Pbool->Set_help("Makes window resizable (depends on scalers)");
05169 
05170     Pstring = sdl_sec->Add_string("fullresolution",Property::Changeable::Always,"desktop");
05171     Pstring->Set_help("What resolution to use for fullscreen: original, desktop or a fixed size (e.g. 1024x768).\n"
05172                       "  Using your monitor's native resolution with aspect=true might give the best results.\n"
05173               "  If you end up with small window on a large screen, try an output different from surface.");
05174 
05175     Pstring = sdl_sec->Add_string("windowresolution",Property::Changeable::Always,"original");
05176     Pstring->Set_help("Scale the window to this size IF the output device supports hardware scaling.\n"
05177                       "  (output=surface does not!)");
05178 
05179     const char* outputs[] = {
05180         "surface", "overlay",
05181 #if C_OPENGL
05182         "opengl", "openglnb", "openglhq",
05183 #endif
05184         "ddraw",
05185 #if C_DIRECT3D
05186         "direct3d",
05187 #endif
05188         0 };
05189 #ifdef __WIN32__
05190 # if defined(HX_DOS)
05191         Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "surface"); /* HX DOS should stick to surface */
05192 # elif defined(__MINGW32__) && !(C_DIRECT3D) && !defined(C_SDL2)
05193         /* NTS: OpenGL output never seems to work in VirtualBox under Windows XP */
05194         Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, isVirtualBox ? "surface" : "opengl"); /* MinGW builds do not yet have Direct3D */
05195 # else
05196         Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "direct3d");
05197 #endif
05198 #else
05199         Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "surface");
05200 #endif
05201     Pstring->Set_help("What video system to use for output.");
05202     Pstring->Set_values(outputs);
05203 
05204     Pbool = sdl_sec->Add_bool("autolock",Property::Changeable::Always, false);
05205     Pbool->Set_help("Mouse will automatically lock, if you click on the screen. (Press CTRL-F10 to unlock)");
05206 
05207     const char* feeds[] = { "none", "beep", "flash", nullptr};
05208     Pstring = sdl_sec->Add_string("autolock_feedback", Property::Changeable::Always, feeds[1]);
05209     Pstring->Set_help("Autolock status feedback type, i.e. visual, auditive, none.");
05210     Pstring->Set_values(feeds);
05211 
05212     Pint = sdl_sec->Add_int("sensitivity",Property::Changeable::Always,100);
05213     Pint->SetMinMax(1,1000);
05214     Pint->Set_help("Mouse sensitivity.");
05215 
05216     const char * emulation[] = {"integration", "locked", "always", "never", nullptr};
05217     Pstring  = sdl_sec->Add_string("mouse_emulation", Property::Changeable::Always, emulation[1]);
05218     Pstring->Set_help(
05219         "When is mouse emulated ?\n"
05220         "integration: when not locked\n"
05221         "locked:      when locked\n"
05222         "always:      every time\n"
05223         "never:       at no time\n"
05224         "If disabled, the mouse position in DOSBox-X is exactly where the host OS reports it.\n"
05225         "When using a high DPI mouse, the emulation of mouse movement can noticeably reduce the\n"
05226         "sensitiveness of your device, i.e. the mouse is slower but more precise.");
05227     Pstring->Set_values(emulation);
05228 
05229     Pbool = sdl_sec->Add_bool("waitonerror",Property::Changeable::Always, true);
05230     Pbool->Set_help("Wait before closing the console if dosbox has an error.");
05231 
05232     Pmulti = sdl_sec->Add_multi("priority", Property::Changeable::Always, ",");
05233     Pmulti->SetValue("higher,normal",/*init*/true);
05234     Pmulti->Set_help("Priority levels for dosbox. Second entry behind the comma is for when dosbox is not focused/minimized.\n"
05235                      "  pause is only valid for the second entry.");
05236 
05237     const char* actt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0};
05238     Pstring = Pmulti->GetSection()->Add_string("active",Property::Changeable::Always,"higher");
05239     Pstring->Set_values(actt);
05240 
05241     const char* inactt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0};
05242     Pstring = Pmulti->GetSection()->Add_string("inactive",Property::Changeable::Always,"normal");
05243     Pstring->Set_values(inactt);
05244 
05245     Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,MAPPERFILE);
05246     Pstring->Set_help("File used to load/save the key/event mappings from. Resetmapper only works with the default value.");
05247 
05248 #if C_DIRECT3D && C_D3DSHADERS
05249     Pmulti = sdl_sec->Add_multi("pixelshader",Property::Changeable::Always," ");
05250     Pmulti->SetValue("none",/*init*/true);
05251     Pmulti->Set_help("Pixelshader program (effect file must be in Shaders subdirectory). If 'forced' is appended,\n"
05252         "then the shader will be used even if the result might not be desired.");
05253 
05254     Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"none");
05255     Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,"");
05256 #endif
05257 
05258     Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,false);
05259     Pbool->Set_help("Avoid usage of symkeys, might not work on all operating systems.");
05260 
05261     Pint = sdl_sec->Add_int("overscan",Property::Changeable::Always, 0);
05262     Pint->SetMinMax(0,10);
05263     Pint->Set_help("Width of overscan border (0 to 10). (works only if output=surface)");
05264 
05265     Pstring = sdl_sec->Add_string("titlebar", Property::Changeable::Always, "");
05266     Pstring->Set_help("Change the string displayed in the DOSBox title bar.");
05267 
05268     Pbool = sdl_sec->Add_bool("showmenu", Property::Changeable::Always, true);
05269     Pbool->Set_help("Whether to show the menu bar (if supported). Default true.");
05270 
05271 //  Pint = sdl_sec->Add_int("overscancolor",Property::Changeable::Always, 0);
05272 //  Pint->SetMinMax(0,1000);
05273 //  Pint->Set_help("Value of overscan color.");
05274 }
05275 
05276 static void show_warning(char const * const message) {
05277     bool textonly = true;
05278 #ifdef WIN32
05279     textonly = false;
05280     if ( !sdl.inited && SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) textonly = true;
05281     sdl.inited = true;
05282 #endif
05283     LOG_MSG( "Warning: %s", message);
05284     if(textonly) return;
05285 #if defined(C_SDL2)
05286     if (!sdl.window)
05287         if (!GFX_SetSDLSurfaceWindow(640,400)) return;
05288     sdl.surface = SDL_GetWindowSurface(sdl.window);
05289 #else
05290     if(!sdl.surface) sdl.surface = SDL_SetVideoMode(640,400,0,SDL_RESIZABLE);
05291     sdl.deferred_resize = false;
05292     sdl.must_redraw_all = true;
05293 #endif
05294     if(!sdl.surface) return;
05295 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
05296     Bit32u rmask = 0xff000000;
05297     Bit32u gmask = 0x00ff0000;
05298     Bit32u bmask = 0x0000ff00;
05299 #else
05300     Bit32u rmask = 0x000000ff;
05301     Bit32u gmask = 0x0000ff00;                    
05302     Bit32u bmask = 0x00ff0000;
05303 #endif
05304     SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0);
05305     if (!splash_surf) return;
05306 
05307     int x = 120,y = 20;
05308     std::string m(message),m2;
05309     std::string::size_type a,b,c,d;
05310    
05311     while(m.size()) { //Max 50 characters. break on space before or on a newline
05312         c = m.find('\n');
05313         d = m.rfind(' ',50);
05314         if(c>d) a=b=d; else a=b=c;
05315         if( a != std::string::npos) b++; 
05316         m2 = m.substr(0,a); m.erase(0,b);
05317         OutputString((unsigned int)x,(unsigned int)y,m2.c_str(),0xffffffffu,0,splash_surf);
05318         y += 20;
05319     }
05320    
05321     SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL);
05322 #if defined(C_SDL2)
05323     SDL_UpdateWindowSurface(sdl.window);
05324 #else
05325     SDL_Flip(sdl.surface);
05326 #endif
05327     SDL_Delay(12000);
05328 }
05329    
05330 static void launcheditor(std::string edit) {
05331     std::string path,file;
05332     Cross::CreatePlatformConfigDir(path);
05333     Cross::GetPlatformConfigName(file);
05334     path += file;
05335     FILE* f = fopen(path.c_str(),"r");
05336     if(!f && !control->PrintConfig(path.c_str())) {
05337         printf("tried creating %s. but failed.\n",path.c_str());
05338         exit(1);
05339     }
05340     if(f) fclose(f);
05341 
05342     execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
05343 
05344     //if you get here the launching failed!
05345     printf("can't find editor(s) specified at the command line.\n");
05346     exit(1);
05347 }
05348 #if C_DEBUG
05349 extern void DEBUG_ShutDown(Section * /*sec*/);
05350 #endif
05351 
05352 void restart_program(std::vector<std::string> & parameters) {
05353     char** newargs = new char* [parameters.size()+1];
05354     // parameter 0 is the executable path
05355     // contents of the vector follow
05356     // last one is NULL
05357     for(Bitu i = 0; i < parameters.size(); i++) newargs[i]=(char*)parameters[i].c_str();
05358     newargs[parameters.size()] = NULL;
05359     if(sdl.desktop.fullscreen) SwitchFullScreen(1);
05360     putenv((char*)("SDL_VIDEODRIVER="));
05361 #ifndef WIN32
05362     SDL_CloseAudio();
05363     SDL_Delay(50);
05364     SDL_Quit();
05365 #if C_DEBUG
05366     // shutdown curses
05367     DEBUG_ShutDown(NULL);
05368 #endif
05369 #endif
05370 
05371 #ifndef WIN32
05372     execvp(newargs[0], newargs);
05373 #endif
05374 #ifdef __MINGW32__
05375 #ifdef WIN32 // if failed under win32
05376     PROCESS_INFORMATION pi;
05377     STARTUPINFO si; 
05378     ZeroMemory(&si,sizeof(si));
05379     si.cb=sizeof(si);
05380     ZeroMemory(&pi,sizeof(pi));
05381 
05382     if(CreateProcess(NULL, newargs[0], NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
05383         CloseHandle( pi.hProcess );
05384         CloseHandle( pi.hThread );
05385         SDL_CloseAudio();
05386         SDL_Delay(50);
05387         throw(0);
05388         SDL_Quit();
05389 #if C_DEBUG
05390     // shutdown curses
05391         DEBUG_ShutDown(NULL);
05392 #endif
05393     }
05394 #endif
05395 #else // if not MINGW
05396 #ifdef WIN32
05397     char newargs_temp[32767];
05398     strcpy(newargs_temp, "");
05399     for(Bitu i = 1; i < parameters.size(); i++) {
05400         strcat(newargs_temp, " ");
05401         strcat(newargs_temp, newargs[i]);
05402     }
05403 
05404     if(ShellExecute(NULL, "open", newargs[0], newargs_temp, NULL, SW_SHOW)) {
05405         SDL_CloseAudio();
05406         SDL_Delay(50);
05407         throw(0);
05408         SDL_Quit();
05409 #if C_DEBUG
05410     // shutdown curses
05411         DEBUG_ShutDown(NULL);
05412 #endif
05413     }
05414 #endif
05415 #endif
05416     free(newargs);
05417 }
05418 
05419 void Restart(bool pressed) { // mapper handler
05420     (void)pressed;//UNUSED
05421     restart_program(control->startup_params);
05422 }
05423 
05424 static void launchcaptures(std::string const& edit) {
05425     std::string path,file;
05426     struct stat cstat;
05427     Section* t = control->GetSection("dosbox");
05428     if(t) file = t->GetPropValue("captures");
05429     if(!t || file == NO_SUCH_PROPERTY) {
05430         printf("Config system messed up.\n");
05431         exit(1);
05432     }
05433     path = ".";
05434     path += CROSS_FILESPLIT;
05435     path += file;
05436 
05437     stat(path.c_str(),&cstat);
05438     if(cstat.st_mode & S_IFDIR) {
05439         execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
05440         //if you get here the launching failed!
05441         printf("can't find filemanager %s\n",edit.c_str());
05442         exit(1);
05443     } else {
05444         path = "";
05445         Cross::CreatePlatformConfigDir(path);
05446         path += file;
05447         Cross::CreateDir(path);
05448         stat(path.c_str(),&cstat);
05449         if((cstat.st_mode & S_IFDIR) == 0) {
05450             printf("%s doesn't exist or isn't a directory.\n",path.c_str());
05451             exit(1);
05452         }
05453         execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
05454         //if you get here the launching failed!
05455         printf("can't find filemanager %s\n",edit.c_str());
05456         exit(1);
05457     }
05458 }
05459 
05460 static void launchsaves(std::string const& edit) {
05461     std::string path,file;
05462     struct stat cstat;
05463     file="SAVE";
05464     path = ".";
05465     path += CROSS_FILESPLIT;
05466     path += file;
05467     stat(path.c_str(),&cstat);
05468     if(cstat.st_mode & S_IFDIR) {
05469         execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
05470         //if you get here the launching failed!
05471         printf("can't find filemanager %s\n",edit.c_str());
05472         exit(1);
05473     } else {
05474         path = "";
05475         Cross::CreatePlatformConfigDir(path);
05476         path += file;
05477         Cross::CreateDir(path);
05478         stat(path.c_str(),&cstat);
05479         if((cstat.st_mode & S_IFDIR) == 0) {
05480             printf("%s doesn't exists or isn't a directory.\n",path.c_str());
05481             exit(1);
05482         }
05483         execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0);
05484         //if you get here the launching failed!
05485         printf("can't find filemanager %s\n",edit.c_str());
05486         exit(1);
05487     }
05488 }
05489 
05490 static void printconfiglocation() {
05491     std::string path,file;
05492     Cross::CreatePlatformConfigDir(path);
05493     Cross::GetPlatformConfigName(file);
05494     path += file;
05495      
05496     FILE* f = fopen(path.c_str(),"r");
05497     if(!f && !control->PrintConfig(path.c_str())) {
05498         printf("tried creating %s. but failed",path.c_str());
05499         exit(1);
05500     }
05501     if(f) fclose(f);
05502     printf("%s\n",path.c_str());
05503     exit(0);
05504 }
05505 
05506 static void eraseconfigfile() {
05507     FILE* f = fopen("dosbox.conf","r");
05508     if(f) {
05509         fclose(f);
05510         show_warning("Warning: dosbox.conf exists in current working directory.\nThis will override the configuration file at runtime.\n");
05511     }
05512     std::string path,file;
05513     Cross::GetPlatformConfigDir(path);
05514     Cross::GetPlatformConfigName(file);
05515     path += file;
05516     f = fopen(path.c_str(),"r");
05517     if(!f) exit(0);
05518     fclose(f);
05519     unlink(path.c_str());
05520     exit(0);
05521 }
05522 
05523 static void erasemapperfile() {
05524     FILE* g = fopen("dosbox.conf","r");
05525     if(g) {
05526         fclose(g);
05527         show_warning("Warning: dosbox.conf exists in current working directory.\nKeymapping might not be properly reset.\n"
05528                      "Please reset configuration as well and delete the dosbox.conf.\n");
05529     }
05530 
05531     std::string path,file=MAPPERFILE;
05532     Cross::GetPlatformConfigDir(path);
05533     path += file;
05534     FILE* f = fopen(path.c_str(),"r");
05535     if(!f) exit(0);
05536     fclose(f);
05537     unlink(path.c_str());
05538     exit(0);
05539 }
05540 
05541 void SetNumLock(void) {
05542 #ifdef WIN32
05543     if (control->opt_disable_numlock_check)
05544         return;
05545 
05546     // Simulate a key press
05547     keybd_event(VK_NUMLOCK,0x45,KEYEVENTF_EXTENDEDKEY | 0,0);
05548 
05549     // Simulate a key release
05550     keybd_event(VK_NUMLOCK,0x45,KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,0);
05551 #endif
05552 }
05553 
05554 void CheckNumLockState(void) {
05555 #ifdef WIN32
05556     BYTE keyState[256];
05557 
05558     GetKeyboardState((LPBYTE)(&keyState));
05559         if (keyState[VK_NUMLOCK] & 1) {
05560                 startup_state_numlock = true;
05561         }
05562 #endif
05563 }
05564 
05565 void CheckCapsLockState(void) {
05566 #ifdef WIN32
05567     BYTE keyState[256];
05568 
05569     GetKeyboardState((LPBYTE)(&keyState));
05570         if (keyState[VK_CAPITAL] & 1) {
05571                 startup_state_capslock = true;
05572         }
05573 #endif
05574 }
05575 
05576 void CheckScrollLockState(void) {
05577 #ifdef WIN32
05578     BYTE keyState[256];
05579 
05580     GetKeyboardState((LPBYTE)(&keyState));
05581         if (keyState[VK_SCROLL] & 1) {
05582                 startup_state_scrlock = true;
05583         }
05584 #endif
05585 }
05586 
05587 extern bool log_keyboard_scan_codes;
05588 
05589 bool showconsole_init = false;
05590 
05591 #if C_DEBUG
05592 bool DEBUG_IsDebuggerConsoleVisible(void);
05593 #endif
05594 
05595 void DOSBox_ShowConsole() {
05596 #if defined(WIN32) && !defined(HX_DOS)
05597     CONSOLE_SCREEN_BUFFER_INFO csbi;
05598     COORD crd;
05599     HWND hwnd;
05600 
05601 #if C_DEBUG
05602     /* if the debugger has already taken the console, do nothing */
05603     if (DEBUG_IsDebuggerConsoleVisible())
05604         return;
05605 #endif
05606 
05607     /* if WE have already opened the console, do nothing */
05608     if (showconsole_init)
05609         return;
05610 
05611     /* Microsoft Windows: Allocate a console and begin spewing to it.
05612        DOSBox is compiled on Windows platforms as a Win32 application, and therefore, no console. */
05613     /* FIXME: What about "file handles" 0/1/2 emulated by C library, for use with _open/_close/_lseek/etc? */
05614     AllocConsole();
05615 
05616     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
05617     crd = csbi.dwSize;
05618     crd.X = 130;
05619     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), crd);
05620 
05621     hwnd = GetConsoleWindow();
05622     ShowWindow(hwnd, SW_MAXIMIZE);
05623 
05624     freopen("CONIN$", "r", stdin);
05625     freopen("CONOUT$", "w", stdout);
05626     freopen("CONOUT$", "w", stderr);
05627 
05628     showconsole_init = true;
05629 #endif
05630 }
05631 
05632 void DOSBox_ConsolePauseWait() {
05633     char c;
05634 
05635     printf("Hit ENTER to continue\n");
05636     do {
05637         if (fread(&c, 1, 1, stdin) != 1) break;
05638     } while (!(c == 13 || c == 10)); /* wait for Enter key */
05639 }
05640 
05641 bool DOSBOX_parse_argv() {
05642     std::string optname,tmp;
05643 
05644     assert(control != NULL);
05645     assert(control->cmdline != NULL);
05646 
05647     control->cmdline->BeginOpt();
05648     while (control->cmdline->GetOpt(optname)) {
05649         std::transform(optname.begin(), optname.end(), optname.begin(), ::tolower);
05650 
05651         if (optname == "version") {
05652             DOSBox_ShowConsole();
05653 
05654             fprintf(stderr,"\nDOSBox version %s, copyright 2002-2015 DOSBox Team.\n\n",VERSION);
05655             fprintf(stderr,"DOSBox is written by the DOSBox Team (See AUTHORS file))\n");
05656             fprintf(stderr,"DOSBox comes with ABSOLUTELY NO WARRANTY.  This is free software,\n");
05657             fprintf(stderr,"and you are welcome to redistribute it under certain conditions;\n");
05658             fprintf(stderr,"please read the COPYING file thoroughly before doing so.\n\n");
05659 
05660 #if defined(WIN32)
05661             DOSBox_ConsolePauseWait();
05662 #endif
05663 
05664             return 0;
05665         }
05666         else if (optname == "h" || optname == "help") {
05667             DOSBox_ShowConsole();
05668 
05669             fprintf(stderr,"\ndosbox [options]\n");
05670             fprintf(stderr,"\nDOSBox version %s, copyright 2002-2015 DOSBox Team.\n\n",VERSION);
05671             fprintf(stderr,"  -h     -help                            Show this help\n");
05672             fprintf(stderr,"  -editconf                               Launch editor\n");
05673             fprintf(stderr,"  -opencaptures <param>                   Launch captures\n");
05674             fprintf(stderr,"  -opensaves <param>                      Launch saves\n");
05675             fprintf(stderr,"  -eraseconf                              Erase config file\n");
05676             fprintf(stderr,"  -resetconf                              Erase config file\n");
05677             fprintf(stderr,"  -printconf                              Print config file location\n");
05678             fprintf(stderr,"  -erasemapper                            Erase mapper file\n");
05679             fprintf(stderr,"  -resetmapper                            Erase mapper file\n");
05680             fprintf(stderr,"  -console                                Show console (win32)\n");
05681             fprintf(stderr,"  -noconsole                              Don't show console (debug+win32 only)\n");
05682             fprintf(stderr,"  -nogui                                  Don't show gui (win32 only)\n");
05683             fprintf(stderr,"  -nomenu                                 Don't show menu (win32 only)\n");
05684             fprintf(stderr,"  -userconf                               Create user level config file\n");
05685             fprintf(stderr,"  -conf <param>                           Use config file <param>\n");
05686             fprintf(stderr,"  -startui -startgui                      Start DOSBox-X with UI\n");
05687             fprintf(stderr,"  -startmapper                            Start DOSBox-X with mapper\n");
05688             fprintf(stderr,"  -showcycles                             Show cycles count\n");
05689             fprintf(stderr,"  -showrt                                 Show emulation speed relative to realtime\n");
05690             fprintf(stderr,"  -fullscreen                             Start in fullscreen\n");
05691             fprintf(stderr,"  -savedir <path>                         Save path\n");
05692             fprintf(stderr,"  -disable-numlock-check                  Disable numlock check (win32 only)\n");
05693             fprintf(stderr,"  -date-host-forced                       Force synchronization of date with host\n");
05694             fprintf(stderr,"  -debug                                  Set all logging levels to debug\n");
05695             fprintf(stderr,"  -early-debug                            Log early initialization messages in DOSBox (implies -console)\n");
05696             fprintf(stderr,"  -keydbg                                 Log all SDL key events (debugging)\n");
05697             fprintf(stderr,"  -lang <message file>                    Use specific message file instead of language= setting\n");
05698             fprintf(stderr,"  -nodpiaware                             Ignore (don't signal) Windows DPI awareness\n");
05699             fprintf(stderr,"  -securemode                             Enable secure mode\n");
05700             fprintf(stderr,"  -noautoexec                             Don't execute AUTOEXEC.BAT config section\n");
05701             fprintf(stderr,"  -exit                                   Exit after executing AUTOEXEC.BAT\n");
05702             fprintf(stderr,"  -c <command string>                     Execute this command in addition to AUTOEXEC.BAT.\n");
05703             fprintf(stderr,"                                          Make sure to surround the command in quotes to cover spaces.\n");
05704             fprintf(stderr,"  -break-start                            Break into debugger at startup\n");
05705             fprintf(stderr,"  -time-limit <n>                         Kill the emulator after 'n' seconds\n");
05706             fprintf(stderr,"  -fastbioslogo                           Fast BIOS logo (skip 1-second pause)\n");
05707             fprintf(stderr,"  -log-con                                Log CON output to a log file\n");
05708 
05709 #if defined(WIN32)
05710             DOSBox_ConsolePauseWait();
05711 #endif
05712 
05713             return 0;
05714         }
05715         else if (optname == "c") {
05716             if (!control->cmdline->NextOptArgv(tmp)) return false;
05717             control->opt_c.push_back(tmp);
05718         }
05719         else if (optname == "log-con") {
05720             control->opt_log_con = true;
05721         }
05722         else if (optname == "time-limit") {
05723             if (!control->cmdline->NextOptArgv(tmp)) return false;
05724             control->opt_time_limit = atof(tmp.c_str());
05725         }
05726         else if (optname == "break-start") {
05727             control->opt_break_start = true;
05728         }
05729         else if (optname == "exit") {
05730             control->opt_exit = true;
05731         }
05732         else if (optname == "noautoexec") {
05733             control->opt_noautoexec = true;
05734         }
05735         else if (optname == "securemode") {
05736             control->opt_securemode = true;
05737         }
05738         else if (optname == "nodpiaware") {
05739             control->opt_disable_dpi_awareness = true;
05740         }
05741         else if (optname == "keydbg") {
05742             log_keyboard_scan_codes = true;
05743         }
05744         else if (optname == "date-host-forced" || optname == "date_host_forced") {
05745             control->opt_date_host_forced = true;
05746         }
05747         else if (optname == "showrt") {
05748             control->opt_showrt = true;
05749         }
05750         else if (optname == "showcycles") {
05751             control->opt_showcycles = true;
05752         }
05753         else if (optname == "startmapper") {
05754             control->opt_startmapper = true;
05755         }
05756         else if (optname == "fullscreen") {
05757             control->opt_fullscreen = true;
05758         }
05759         else if (optname == "startui" || optname == "startgui") {
05760             control->opt_startui = true;
05761         }
05762         else if (optname == "disable-numlock-check" || optname == "disable_numlock_check") {
05763             /* mainline DOSBox expects -disable_numlock_check so we support that here too */
05764             control->opt_disable_numlock_check = true;
05765         }
05766         else if (optname == "savedir") {
05767             if (!control->cmdline->NextOptArgv(custom_savedir)) return false;
05768         }
05769         else if (optname == "userconf") {
05770             control->opt_userconf = true;
05771         }
05772         else if (optname == "lang") {
05773             if (!control->cmdline->NextOptArgv(control->opt_lang)) return false;
05774         }
05775         else if (optname == "fastbioslogo") {
05776             control->opt_fastbioslogo = true;
05777         }
05778         else if (optname == "conf") {
05779             if (!control->cmdline->NextOptArgv(tmp)) return false;
05780             control->config_file_list.push_back(tmp);
05781         }
05782         else if (optname == "editconf") {
05783             if (!control->cmdline->NextOptArgv(control->opt_editconf)) return false;
05784         }
05785         else if (optname == "opencaptures") {
05786             if (!control->cmdline->NextOptArgv(control->opt_opencaptures)) return false;
05787         }
05788         else if (optname == "opensaves") {
05789             if (!control->cmdline->NextOptArgv(control->opt_opensaves)) return false;
05790         }
05791         else if (optname == "eraseconf") {
05792             control->opt_eraseconf = true;
05793         }
05794         else if (optname == "resetconf") {
05795             control->opt_resetconf = true;
05796         }
05797         else if (optname == "printconf") {
05798             control->opt_printconf = true;
05799         }
05800         else if (optname == "erasemapper") {
05801             control->opt_erasemapper = true;
05802         }
05803         else if (optname == "resetmapper") {
05804             control->opt_resetmapper = true;
05805         }
05806         else if (optname == "noconsole") {
05807             control->opt_noconsole = true;
05808             control->opt_console = false;
05809         }
05810         else if (optname == "console") {
05811             control->opt_noconsole = false;
05812             control->opt_console = true;
05813         }
05814         else if (optname == "nomenu") {
05815             control->opt_nomenu = true;
05816         }
05817         else if (optname == "nogui") {
05818             control->opt_nogui = true;
05819         }
05820         else if (optname == "debug") {
05821             control->opt_debug = true;
05822         }
05823         else if (optname == "early-debug") {
05824             control->opt_earlydebug = true;
05825             control->opt_console = true;
05826         }
05827         else {
05828             printf("WARNING: Unknown option %s (first parsing stage)\n",optname.c_str());
05829         }
05830     }
05831 
05832     /* now that the above loop has eaten all the options from the command
05833      * line, scan the command line for batch files to run.
05834      * https://github.com/joncampbell123/dosbox-x/issues/369 */
05835     control->cmdline->BeginOpt(/*don't eat*/false);
05836     while (!control->cmdline->CurrentArgvEnd()) {
05837         control->cmdline->GetCurrentArgv(tmp);
05838 
05839         {
05840             struct stat st;
05841             const char *ext = strrchr(tmp.c_str(),'.');
05842             if (ext != NULL) { /* if it looks like a file... with an extension */
05843                 if (stat(tmp.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
05844                     if (!strcasecmp(ext,".bat")) { /* .BAT files given on the command line trigger automounting C: to run it */
05845                         control->auto_bat_additional.push_back(tmp);
05846                         control->cmdline->EatCurrentArgv();
05847                         continue;
05848                     }
05849                 }
05850             }
05851         }
05852 
05853         control->cmdline->NextArgv();
05854     }
05855 
05856     return true;
05857 }
05858 
05859 void MSG_Init();
05860 void DOSBOX_RealInit();
05861 void DOSBOX_InitTickLoop();
05862 void TIMER_ShutdownTickHandlers();
05863 void DOSBOX_SetupConfigSections(void);
05864 void PAGING_Init();
05865 void IO_Init();
05866 void Init_VGABIOS();
05867 void Init_AddressLimitAndGateMask();
05868 void Init_RAM();
05869 void Init_MemHandles();
05870 void Init_MemoryAccessArray();
05871 void Init_PCJR_CartridgeROM();
05872 void Init_PS2_Port_92h();
05873 void Init_A20_Gate();
05874 void HARDWARE_Init();
05875 void CAPTURE_Init();
05876 void ROMBIOS_Init();
05877 void CALLBACK_Init();
05878 void Init_DMA();
05879 void Init_PIC();
05880 void PCIBUS_Init();
05881 void PROGRAMS_Init();
05882 void RENDER_Init();
05883 void TIMER_Init();
05884 void CMOS_Init();
05885 void VGA_Init();
05886 void CPU_Init();
05887 void ISAPNP_Cfg_Init();
05888 #if C_FPU
05889 void FPU_Init();
05890 #endif
05891 void KEYBOARD_Init();
05892 void VOODOO_Init();
05893 void MIXER_Init();
05894 void MIDI_Init();
05895 
05896 /* Init all the sections */
05897 void MPU401_Init();
05898 #if C_DEBUG
05899 void DEBUG_Init();
05900 #endif
05901 void SBLASTER_Init();
05902 void GUS_Init();
05903 void INNOVA_Init();
05904 void PCSPEAKER_Init();
05905 void TANDYSOUND_Init();
05906 void DISNEY_Init();
05907 void PS1SOUND_Init();
05908 void BIOS_Init();
05909 void INT10_Init();
05910 void JOYSTICK_Init();
05911 void SERIAL_Init();
05912 #if C_PRINTER
05913 void PRINTER_Init();
05914 #endif
05915 void PARALLEL_Init();
05916 void DONGLE_Init();
05917 void DOS_Init();
05918 void XMS_Init();
05919 void EMS_Init();
05920 void MOUSE_Init();
05921 void DOS_KeyboardLayout_Init();
05922 void MSCDEX_Init();
05923 void DRIVES_Init();
05924 void IPX_Init();
05925 void IDE_Init();
05926 void NE2K_Init();
05927 void FDC_Primary_Init();
05928 void AUTOEXEC_Init();
05929 
05930 #if defined(WIN32)
05931 extern bool dpi_aware_enable;
05932 
05933 // NTS: I intend to add code that not only indicates High DPI awareness but also queries the monitor DPI
05934 //      and then factor the DPI into DOSBox's scaler and UI decisions.
05935 void Windows_DPI_Awareness_Init() {
05936     // if the user says not to from the command line, or disables it from dosbox.conf, then don't enable DPI awareness.
05937     if (!dpi_aware_enable || control->opt_disable_dpi_awareness)
05938         return;
05939 
05940     /* log it */
05941     LOG(LOG_MISC,LOG_DEBUG)("Win32: I will announce High DPI awareness to Windows to eliminate upscaling");
05942 
05943     // turn off DPI scaling so DOSBox-X doesn't look so blurry on Windows 8 & Windows 10.
05944     // use GetProcAddress and LoadLibrary so that these functions are not hard dependencies that prevent us from
05945     // running under Windows 7 or XP.
05946     // 
05947     // I'm also told that Windows 8.1 has SetProcessDPIAwareness but nobody seems to know where it is.
05948     // Perhaps the tooth fairy can find it for me. Come on, Microsoft get your act together! [https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx]
05949     BOOL (WINAPI *__SetProcessDPIAware)(void) = NULL; // vista/7/8/10
05950     HMODULE __user32;
05951 
05952     __user32 = GetModuleHandle("USER32.DLL");
05953 
05954     if (__user32)
05955         __SetProcessDPIAware = (BOOL(WINAPI *)(void))GetProcAddress(__user32, "SetProcessDPIAware");
05956 
05957     if (__SetProcessDPIAware) {
05958         LOG(LOG_MISC,LOG_DEBUG)("USER32.DLL exports SetProcessDPIAware function, calling it to signal we are DPI aware.");
05959         __SetProcessDPIAware();
05960     }
05961 }
05962 #endif
05963 
05964 bool VM_Boot_DOSBox_Kernel() {
05965     if (!dos_kernel_disabled) {
05966         RemoveEMSPageFrame();
05967         RemoveUMBBlock();
05968         DisableINT33();
05969         DOS_GetMemory_unmap();
05970         VFILE_Shutdown();
05971         PROGRAMS_Shutdown();
05972         DOS_UninstallMisc();
05973         SBLASTER_DOS_Shutdown();
05974         GUS_DOS_Shutdown();
05975         EMS_DoShutDown();
05976         XMS_DoShutDown();
05977         DOS_DoShutDown();
05978 
05979         DispatchVMEvent(VM_EVENT_DOS_SURPRISE_REBOOT); // <- apparently we rebooted without any notification (such as jmp'ing to FFFF:0000)
05980 
05981         dos_kernel_disabled = true;
05982 
05983 #if defined(WIN32) && !defined(C_SDL2)
05984         int Reflect_Menu(void);
05985         Reflect_Menu();
05986 #endif
05987     }
05988 
05989     if (dos_kernel_disabled) {
05990         DispatchVMEvent(VM_EVENT_DOS_BOOT); // <- just starting the DOS kernel now
05991 
05992         /* DOS kernel init */
05993         dos_kernel_disabled = false; // FIXME: DOS_Init should install VM callback handler to set this
05994         void DOS_Startup(Section* sec);
05995         DOS_Startup(NULL);
05996 
05997 #if defined(WIN32) && !defined(C_SDL2)
05998         int Reflect_Menu(void);
05999         Reflect_Menu();
06000 #endif
06001 
06002         void update_pc98_function_row(bool enable);
06003 
06004         void DRIVES_Startup(Section *s);
06005         DRIVES_Startup(NULL);
06006 
06007         /* NEC's function key row seems to be deeply embedded in the CON driver. Am I wrong? */
06008         if (IS_PC98_ARCH) update_pc98_function_row(true);
06009 
06010         DispatchVMEvent(VM_EVENT_DOS_INIT_KERNEL_READY); // <- kernel is ready
06011 
06012         /* keyboard mapping, at this point in CONFIG.SYS parsing, right? */
06013         void DOS_KeyboardLayout_Startup(Section* sec);
06014         DOS_KeyboardLayout_Startup(NULL);
06015 
06016         /* Most MS-DOS installations have a DEVICE=C:\HIMEM.SYS somewhere near the top of their CONFIG.SYS */
06017         void XMS_Startup(Section *sec);
06018         XMS_Startup(NULL);
06019 
06020         /* And then after that, usually a DEVICE=C:\EMM386.EXE just after HIMEM.SYS */
06021         void EMS_Startup(Section* sec);
06022         EMS_Startup(NULL);
06023 
06024         DispatchVMEvent(VM_EVENT_DOS_INIT_CONFIG_SYS_DONE); // <- we just finished executing CONFIG.SYS
06025         SHELL_Init(); // <- NTS: this will change CPU instruction pointer!
06026         DispatchVMEvent(VM_EVENT_DOS_INIT_SHELL_READY); // <- we just finished loading the shell (COMMAND.COM)
06027 
06028         /* it's time to init parsing AUTOEXEC.BAT */
06029         void AUTOEXEC_Startup(Section *sec);
06030         AUTOEXEC_Startup(NULL);
06031 
06032         /* Most MS-DOS installations run MSCDEX.EXE from somewhere in AUTOEXEC.BAT. We do the same here, in a fashion. */
06033         /* TODO: Can we make this an OPTION if the user doesn't want to make MSCDEX.EXE resident? */
06034         /* TODO: When we emulate executing AUTOEXEC.BAT between INIT_SHELL_READY and AUTOEXEC_BAT_DONE, can we make a fake MSCDEX.EXE within drive Z:\
06035          *       and auto-add a Z:\MSCDEX.EXE to the top of AUTOEXEC.BAT, command line switches and all. if the user has not already added it? */
06036         void MSCDEX_Startup(Section* sec);
06037         MSCDEX_Startup(NULL);
06038 
06039         /* Some installations load the MOUSE.COM driver from AUTOEXEC.BAT as well */
06040         /* TODO: Can we make this an option? Can we add a fake MOUSE.COM to the Z:\ drive as well? */
06041         void MOUSE_Startup(Section *sec);
06042         MOUSE_Startup(NULL);
06043 
06044         DispatchVMEvent(VM_EVENT_DOS_INIT_AUTOEXEC_BAT_DONE); // <- we just finished executing AUTOEXEC.BAT
06045         DispatchVMEvent(VM_EVENT_DOS_INIT_AT_PROMPT); // <- now, we're at the DOS prompt
06046         SHELL_Run();
06047     }
06048 
06049     return true;
06050 }
06051 
06052 bool VM_PowerOn() {
06053     if (!guest_machine_power_on) {
06054         // powering on means power on event, followed by reset assert, then reset deassert
06055         guest_machine_power_on = true;
06056         DispatchVMEvent(VM_EVENT_POWERON);
06057         DispatchVMEvent(VM_EVENT_RESET);
06058         DispatchVMEvent(VM_EVENT_RESET_END);
06059     }
06060 
06061     return true;
06062 }
06063 
06064 #if !defined(C_EMSCRIPTEN)
06065 void update_capture_fmt_menu(void);
06066 #endif
06067 
06068 bool capture_fmt_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem);
06069 
06070 void update_pc98_clock_pit_menu(void) {
06071     Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06072 
06073     int pc98rate = dosbox_section->Get_int("pc-98 timer master frequency");
06074     if (pc98rate > 6) pc98rate /= 2;
06075     if (pc98rate == 0) pc98rate = 5; /* Pick the most likely to work with DOS games (FIXME: This is a GUESS!! Is this correct?) */
06076     else if (pc98rate < 5) pc98rate = 4;
06077     else pc98rate = 5;
06078 
06079     mainMenu.get_item("dos_pc98_pit_4mhz").check(pc98rate == 4).refresh_item(mainMenu);
06080     mainMenu.get_item("dos_pc98_pit_5mhz").check(pc98rate == 5).refresh_item(mainMenu);
06081 }
06082 
06083 bool dos_pc98_clock_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06084     (void)menu;//UNUSED
06085     (void)menuitem;//UNUSED
06086     void TIMER_OnEnterPC98_Phase2(Section*);
06087     void TIMER_OnEnterPC98_Phase2_UpdateBDA(void);
06088 
06089     const char *ts = menuitem->get_name().c_str();
06090     if (!strncmp(ts,"dos_pc98_pit_",13))
06091         ts += 13;
06092     else
06093         return true;
06094 
06095     std::string tmp = "pc-98 timer master frequency=";
06096 
06097     {
06098         char tmp1[64];
06099         sprintf(tmp1,"%u",atoi(ts));
06100         tmp += tmp1;
06101     }
06102 
06103     Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06104     dosbox_section->HandleInputline(tmp.c_str());
06105 
06106     TIMER_OnEnterPC98_Phase2(NULL);
06107     TIMER_OnEnterPC98_Phase2_UpdateBDA();
06108 
06109     update_pc98_clock_pit_menu();
06110     return true;
06111 }
06112 
06113 void SetScaleForced(bool forced);
06114 void OutputSettingMenuUpdate(void);
06115 
06116 bool scaler_forced_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06117     (void)menu;//UNUSED
06118     (void)menuitem;//UNUSED
06119     SetScaleForced(!render.scale.forced);
06120     return true;
06121 }
06122 
06123 void MENU_swapstereo(bool enabled);
06124 bool MENU_get_swapstereo(void);
06125 
06126 bool mixer_swapstereo_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06127     (void)menu;//UNUSED
06128     (void)menuitem;//UNUSED
06129     MENU_swapstereo(!MENU_get_swapstereo());
06130     return true;
06131 }
06132 
06133 void MENU_mute(bool enabled);
06134 bool MENU_get_mute(void);
06135 
06136 bool mixer_mute_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06137     (void)menu;//UNUSED
06138     (void)menuitem;//UNUSED
06139     MENU_mute(!MENU_get_mute());
06140     return true;
06141 }
06142 
06143 bool dos_mouse_enable_int33_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06144     (void)menu;//UNUSED
06145     (void)menuitem;//UNUSED
06146     extern bool Mouse_Drv;
06147     Mouse_Drv = !Mouse_Drv;
06148     mainMenu.get_item("dos_mouse_enable_int33").check(Mouse_Drv).refresh_item(mainMenu);
06149     return true;
06150 }
06151 
06152 bool dos_mouse_y_axis_reverse_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06153     (void)menu;//UNUSED
06154     (void)menuitem;//UNUSED
06155     extern bool Mouse_Vertical;
06156     Mouse_Vertical = !Mouse_Vertical;
06157     mainMenu.get_item("dos_mouse_y_axis_reverse").check(Mouse_Vertical).refresh_item(mainMenu);
06158     return true;
06159 }
06160 
06161 bool dos_mouse_sensitivity_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06162     (void)menu;//UNUSED
06163     (void)menuitem;//UNUSED
06164 #if !defined(C_SDL2)
06165     GUI_Shortcut(2);
06166 #endif
06167     return true;
06168 }
06169 
06170 bool vid_pc98_5mhz_gdc_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06171     (void)menu;//UNUSED
06172     (void)menuitem;//UNUSED
06173     if (IS_PC98_ARCH) {
06174         void gdc_5mhz_mode_update_vars(void);
06175         extern bool gdc_5mhz_mode;
06176 
06177         gdc_5mhz_mode = !gdc_5mhz_mode;
06178         gdc_5mhz_mode_update_vars();
06179 
06180         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06181         if (gdc_5mhz_mode)
06182             dosbox_section->HandleInputline("pc-98 start gdc at 5mhz=1");
06183         else
06184             dosbox_section->HandleInputline("pc-98 start gdc at 5mhz=0");
06185 
06186         mainMenu.get_item("pc98_5mhz_gdc").check(gdc_5mhz_mode).refresh_item(mainMenu);
06187     }
06188 
06189     return true;
06190 }
06191 
06192 bool vid_pc98_200scanline_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06193     (void)menu;//UNUSED
06194     (void)menuitem;//UNUSED
06195     if (IS_PC98_ARCH) {
06196         extern bool pc98_allow_scanline_effect;
06197 
06198         pc98_allow_scanline_effect = !pc98_allow_scanline_effect;
06199 
06200         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06201         if (pc98_allow_scanline_effect)
06202             dosbox_section->HandleInputline("pc-98 allow scanline effect=1");
06203         else
06204             dosbox_section->HandleInputline("pc-98 allow scanline effect=0");
06205 
06206         mainMenu.get_item("pc98_allow_200scanline").check(pc98_allow_scanline_effect).refresh_item(mainMenu);
06207     }
06208 
06209     return true;
06210 }
06211 
06212 bool vid_pc98_4parts_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06213     (void)menu;//UNUSED
06214     (void)menuitem;//UNUSED
06215     if (IS_PC98_ARCH) {
06216         extern bool pc98_allow_4_display_partitions;
06217         void updateGDCpartitions4(bool enable);
06218 
06219         updateGDCpartitions4(!pc98_allow_4_display_partitions);
06220 
06221         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06222         if (pc98_allow_4_display_partitions)
06223             dosbox_section->HandleInputline("pc-98 allow 4 display partition graphics=1");
06224         else
06225             dosbox_section->HandleInputline("pc-98 allow 4 display partition graphics=0");
06226 
06227         mainMenu.get_item("pc98_allow_4partitions").check(pc98_allow_4_display_partitions).refresh_item(mainMenu);
06228     }
06229 
06230     return true;
06231 }
06232 
06233 bool vid_pc98_enable_188user_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06234     (void)menu;//UNUSED
06235     (void)menuitem;//UNUSED
06236     void gdc_egc_enable_update_vars(void);
06237     extern bool enable_pc98_egc;
06238     extern bool enable_pc98_grcg;
06239     extern bool enable_pc98_16color;
06240     extern bool enable_pc98_188usermod;
06241 
06242     if(IS_PC98_ARCH) {
06243         enable_pc98_188usermod = !enable_pc98_188usermod;
06244         gdc_egc_enable_update_vars();
06245 
06246         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06247         if (enable_pc98_188usermod)
06248             dosbox_section->HandleInputline("pc-98 enable 188 user cg=1");
06249         else
06250             dosbox_section->HandleInputline("pc-98 enable 188 user cg=0");
06251 
06252         mainMenu.get_item("pc98_enable_188user").check(enable_pc98_188usermod).refresh_item(mainMenu);
06253     }
06254     
06255     return true;
06256 }
06257 
06258 bool vid_pc98_enable_egc_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06259     (void)menu;//UNUSED
06260     (void)menuitem;//UNUSED
06261     void gdc_egc_enable_update_vars(void);
06262     extern bool enable_pc98_egc;
06263     extern bool enable_pc98_grcg;
06264     extern bool enable_pc98_16color;
06265     extern bool enable_pc98_188usermod;
06266 
06267     if(IS_PC98_ARCH) {
06268         enable_pc98_egc = !enable_pc98_egc;
06269         gdc_egc_enable_update_vars();
06270 
06271         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06272         if (enable_pc98_egc) {
06273             dosbox_section->HandleInputline("pc-98 enable egc=1");
06274 
06275             if(!enable_pc98_grcg) { //Also enable GRCG if GRCG is disabled when enabling EGC
06276                 enable_pc98_grcg = !enable_pc98_grcg;
06277                 mem_writeb(0x54C,(enable_pc98_grcg ? 0x02 : 0x00) | (enable_pc98_16color ? 0x04 : 0x00));   
06278                 dosbox_section->HandleInputline("pc-98 enable grcg=1");
06279             }
06280         }
06281         else
06282             dosbox_section->HandleInputline("pc-98 enable egc=0");
06283 
06284         mainMenu.get_item("pc98_enable_egc").check(enable_pc98_egc).refresh_item(mainMenu);
06285         mainMenu.get_item("pc98_enable_grcg").check(enable_pc98_grcg).refresh_item(mainMenu);
06286     }
06287     
06288     return true;
06289 }
06290 
06291 bool vid_pc98_enable_grcg_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06292     (void)menu;//UNUSED
06293     (void)menuitem;//UNUSED
06294     extern bool enable_pc98_grcg;
06295     extern bool enable_pc98_egc;
06296     void gdc_grcg_enable_update_vars(void);
06297 
06298     if(IS_PC98_ARCH) {
06299         enable_pc98_grcg = !enable_pc98_grcg;
06300         gdc_grcg_enable_update_vars();
06301 
06302         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06303         if (enable_pc98_grcg)
06304             dosbox_section->HandleInputline("pc-98 enable grcg=1");
06305         else
06306             dosbox_section->HandleInputline("pc-98 enable grcg=0");
06307 
06308         if ((!enable_pc98_grcg) && enable_pc98_egc) { // Also disable EGC if switching off GRCG
06309             void gdc_egc_enable_update_vars(void);
06310             enable_pc98_egc = !enable_pc98_egc;
06311             gdc_egc_enable_update_vars();   
06312             dosbox_section->HandleInputline("pc-98 enable egc=0");
06313         }
06314 
06315         mainMenu.get_item("pc98_enable_egc").check(enable_pc98_egc).refresh_item(mainMenu);
06316         mainMenu.get_item("pc98_enable_grcg").check(enable_pc98_grcg).refresh_item(mainMenu);
06317     }
06318 
06319     return true;
06320 }
06321 
06322 bool vid_pc98_enable_analog_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06323     (void)menu;//UNUSED
06324     (void)menuitem;//UNUSED
06325     //NOTE: I thought that even later PC-9801s and some PC-9821s could use EGC features in digital 8-colors mode? 
06326     extern bool enable_pc98_16color;
06327     void gdc_16color_enable_update_vars(void);
06328 
06329     if(IS_PC98_ARCH) {
06330         enable_pc98_16color = !enable_pc98_16color;
06331         gdc_16color_enable_update_vars();
06332 
06333         Section_prop * dosbox_section = static_cast<Section_prop *>(control->GetSection("dosbox"));
06334         if (enable_pc98_16color)
06335             dosbox_section->HandleInputline("pc-98 enable 16-color=1");
06336         else
06337             dosbox_section->HandleInputline("pc-98 enable 16-color=0");
06338 
06339         mainMenu.get_item("pc98_enable_analog").check(enable_pc98_16color).refresh_item(mainMenu);
06340     }
06341 
06342     return true;
06343 }
06344 
06345 bool vid_pc98_cleartext_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06346     (void)menu;//UNUSED
06347     (void)menuitem;//UNUSED
06348     void pc98_clear_text(void);
06349     if (IS_PC98_ARCH) pc98_clear_text();
06350     return true;
06351 }
06352 
06353 bool vid_pc98_graphics_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06354     (void)menu;//UNUSED
06355     (void)menuitem;//UNUSED
06356     void pc98_clear_graphics(void);
06357     if (IS_PC98_ARCH) pc98_clear_graphics();
06358     return true;
06359 }
06360 
06361 bool overscan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06362     (void)menu;//UNUSED
06363     int f = atoi(menuitem->get_text().c_str()); /* Off becomes 0 */
06364     char tmp[64];
06365 
06366     sprintf(tmp,"%u",f);
06367     SetVal("sdl", "overscan", tmp);
06368     change_output(7);
06369     return true;
06370 }
06371 
06372 void UpdateOverscanMenu(void) {
06373     for (size_t i=0;i <= 10;i++) {
06374         char tmp[64];
06375         sprintf(tmp,"overscan_%zu",i);
06376         mainMenu.get_item(tmp).check(sdl.overscan_width == i).refresh_item(mainMenu);
06377     }
06378 }
06379 
06380 bool vsync_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06381     (void)menu;//UNUSED
06382     (void)menuitem;//UNUSED
06383 #if !defined(C_SDL2)
06384     const char *val = menuitem->get_name().c_str();
06385     if (!strncmp(val,"vsync_",6))
06386         val += 6;
06387     else
06388         return true;
06389 
06390     SetVal("vsync", "vsyncmode", val);
06391 
06392     void change_output(int output);
06393     change_output(8);
06394 
06395     VGA_Vsync VGA_Vsync_Decode(const char *vsyncmodestr);
06396     void VGA_VsyncUpdateMode(VGA_Vsync vsyncmode);
06397     VGA_VsyncUpdateMode(VGA_Vsync_Decode(val));
06398 #endif
06399     return true;
06400 }
06401 
06402 bool vsync_set_syncrate_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06403     (void)menu;//UNUSED
06404     (void)menuitem;//UNUSED
06405 #if !defined(C_SDL2)
06406     GUI_Shortcut(17);
06407 #endif
06408     return true;
06409 }
06410 
06411 bool output_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06412     (void)menu;//UNUSED
06413 
06414     const char *what = menuitem->get_name().c_str();
06415 
06416     if (!strncmp(what,"output_",7))
06417         what += 7;
06418     else
06419         return true;
06420 
06421     if (!strcmp(what,"surface")) {
06422         if (sdl.desktop.want_type == SCREEN_SURFACE) return true;
06423         change_output(0);
06424     }
06425     else if (!strcmp(what,"opengl")) {
06426 #if C_OPENGL
06427         if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear) return true;
06428         change_output(3);
06429 #endif
06430     }
06431     else if (!strcmp(what,"openglnb")) {
06432 #if C_OPENGL
06433         if (sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear) return true;
06434         change_output(4);
06435 #endif
06436     }
06437     else if (!strcmp(what,"direct3d")) {
06438 #if C_DIRECT3D
06439         if (sdl.desktop.want_type == SCREEN_DIRECT3D) return true;
06440         change_output(5);
06441 #endif
06442     }
06443 
06444     SetVal("sdl", "output", what);
06445     OutputSettingMenuUpdate();
06446     return true;
06447 }
06448 
06449 bool MENU_SetBool(std::string secname, std::string value);
06450 
06451 bool vga_9widetext_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06452     (void)menu;//UNUSED
06453     (void)menuitem;//UNUSED
06454     MENU_SetBool("render", "char9");
06455     return true;
06456 }
06457 
06458 bool doublescan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06459     (void)menu;//UNUSED
06460     (void)menuitem;//UNUSED
06461     MENU_SetBool("render", "doublescan");
06462     return true;
06463 }
06464 
06465 bool scaler_set_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06466     (void)menu;//UNUSED
06467 
06468     const char *scaler = menuitem->get_name().c_str();
06469     if (!strncmp(scaler,"scaler_set_",11))
06470         scaler += 11;
06471     else
06472         abort();
06473 
06474     auto value = std::string(scaler) + (render.scale.forced ? " forced" : "");
06475     SetVal("render", "scaler", value);
06476 
06477     void RENDER_UpdateFromScalerSetting(void);
06478     RENDER_UpdateFromScalerSetting();
06479 
06480     void RENDER_UpdateScalerMenu(void);
06481     RENDER_UpdateScalerMenu();
06482 
06483     void RENDER_CallBack( GFX_CallBackFunctions_t function );
06484     RENDER_CallBack(GFX_CallBackReset);
06485 
06486     return true;
06487 }
06488 
06489 void CALLBACK_Idle(void);
06490 
06491 bool pausewithinterrupts_enable = false;
06492 
06493 void PauseWithInterruptsEnabled(Bitu /*val*/) {
06494     /* we can ONLY do this when the CPU is either in real mode or v86 mode.
06495      * doing this from protected mode will only crash the game.
06496      * also require that interrupts are enabled before pausing. */
06497         if (cpu.pmode) {
06498         if (!(reg_flags & FLAG_VM)) {
06499             PIC_AddEvent(PauseWithInterruptsEnabled,0.001);
06500             return;
06501         }
06502     }
06503 
06504     if (!(reg_flags & FLAG_IF)) {
06505         PIC_AddEvent(PauseWithInterruptsEnabled,0.001);
06506         return;
06507     }
06508 
06509     while (pausewithinterrupts_enable) CALLBACK_Idle();
06510 }
06511 
06512 void PauseWithInterrupts_mapper_shortcut(bool pressed) {
06513     if (!pressed) return;
06514 
06515     if (!pausewithinterrupts_enable) {
06516         pausewithinterrupts_enable = true;
06517         PIC_AddEvent(PauseWithInterruptsEnabled,0.001);
06518     }
06519     else {
06520         pausewithinterrupts_enable = false;
06521     }
06522 
06523     mainMenu.get_item("mapper_pauseints").check(pausewithinterrupts_enable).refresh_item(mainMenu);
06524 }
06525 
06526 bool video_frameskip_common_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06527     (void)menu;//UNUSED
06528 
06529     int f = atoi(menuitem->get_text().c_str()); /* Off becomes 0 */
06530     char tmp[64];
06531 
06532     sprintf(tmp,"%u",f);
06533     SetVal("render", "frameskip", tmp);
06534     return true;
06535 }
06536 
06537 bool show_console_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
06538 #if !defined(C_EMSCRIPTEN)
06539     (void)menu;//UNUSED
06540     (void)menuitem;//UNUSED
06541     DOSBox_ShowConsole();
06542     mainMenu.get_item("show_console").check(true).refresh_item(mainMenu);
06543 #endif
06544     return true;
06545 }
06546 
06547 bool wait_on_error_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) {
06548 #if !defined(C_EMSCRIPTEN)
06549     (void)menu;//UNUSED
06550     (void)menuitem;//UNUSED
06551     sdl.wait_on_error = !sdl.wait_on_error;
06552     mainMenu.get_item("wait_on_error").check(sdl.wait_on_error).refresh_item(mainMenu);
06553 #endif
06554     return true;
06555 }
06556 
06557 bool autolock_mouse_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) {
06558     (void)menu;//UNUSED
06559     (void)menuitem;//UNUSED
06560     sdl.mouse.autoenable = !sdl.mouse.autoenable;
06561     mainMenu.get_item("auto_lock_mouse").check(sdl.mouse.autoenable).refresh_item(mainMenu);
06562     return true;
06563 }
06564 
06565 bool doublebuf_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) {
06566     (void)menu;//UNUSED
06567     (void)menuitem;//UNUSED
06568     SetVal("sdl", "fulldouble", (GetSetSDLValue(1, "desktop.doublebuf", 0)) ? "false" : "true"); res_init();
06569     mainMenu.get_item("doublebuf").check(!!GetSetSDLValue(1, "desktop.doublebuf", 0)).refresh_item(mainMenu);
06570     return true;
06571 }
06572 
06573 #if defined(LINUX) && !defined(C_SDL2)
06574 bool x11_on_top = false;
06575 #endif
06576 
06577 #if defined(MACOSX) && !defined(C_SDL2)
06578 bool macosx_on_top = false;
06579 #endif
06580 
06581 bool is_always_on_top(void) {
06582 #if defined(_WIN32) && !defined(C_SDL2)
06583     DWORD dwExStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE);
06584     return !!(dwExStyle & WS_EX_TOPMOST);
06585 #elif defined(MACOSX) && !defined(C_SDL2)
06586     return macosx_on_top;
06587 #elif defined(LINUX) && !defined(C_SDL2)
06588     return x11_on_top;
06589 #else
06590     return false;
06591 #endif
06592 }
06593 
06594 #if defined(_WIN32) && !defined(C_SDL2)
06595 extern "C" void sdl1_hax_set_topmost(unsigned char topmost);
06596 #endif
06597 #if defined(MACOSX) && !defined(C_SDL2)
06598 extern "C" void sdl1_hax_set_topmost(unsigned char topmost);
06599 #endif
06600 
06601 void toggle_always_on_top(void) {
06602     bool cur = is_always_on_top();
06603 #if defined(_WIN32) && !defined(C_SDL2)
06604     sdl1_hax_set_topmost(!cur);
06605 #elif defined(MACOSX) && !defined(C_SDL2)
06606     sdl1_hax_set_topmost(macosx_on_top = (!cur));
06607 #elif defined(LINUX) && !defined(C_SDL2)
06608     void LinuxX11_OnTop(bool f);
06609     LinuxX11_OnTop(x11_on_top = (!cur));
06610 #else
06611     (void)cur;
06612 #endif
06613 }
06614 
06615 bool showdetails_menu_callback(DOSBoxMenu * const xmenu, DOSBoxMenu::item * const menuitem) {
06616     (void)xmenu;//UNUSED
06617     (void)menuitem;//UNUSED
06618     menu.hidecycles = !menu.hidecycles;
06619     GFX_SetTitle(CPU_CycleMax, -1, -1, false);
06620     mainMenu.get_item("showdetails").check(!menu.hidecycles).refresh_item(mainMenu);
06621     return true;
06622 }
06623 
06624 bool alwaysontop_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) {
06625     (void)menu;//UNUSED
06626     (void)menuitem;//UNUSED
06627     toggle_always_on_top();
06628     mainMenu.get_item("alwaysontop").check(is_always_on_top()).refresh_item(mainMenu);
06629     return true;
06630 }
06631 
06632 bool sendkey_preset_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) {
06633     (void)menu;//UNUSED
06634     if (menuitem->get_name() == "sendkey_ctrlesc") {
06635         KEYBOARD_AddKey(KBD_leftctrl, true);
06636         KEYBOARD_AddKey(KBD_esc, true);
06637         KEYBOARD_AddKey(KBD_leftctrl, false);
06638         KEYBOARD_AddKey(KBD_esc, false);
06639     }
06640     else if (menuitem->get_name() == "sendkey_alttab") {
06641         KEYBOARD_AddKey(KBD_leftalt, true);
06642         KEYBOARD_AddKey(KBD_tab, true);
06643         KEYBOARD_AddKey(KBD_leftalt, false);
06644         KEYBOARD_AddKey(KBD_tab, false);
06645     }
06646     else if (menuitem->get_name() == "sendkey_winlogo") {
06647         KEYBOARD_AddKey(KBD_lwindows, true);
06648         KEYBOARD_AddKey(KBD_lwindows, false);
06649     }
06650     else if (menuitem->get_name() == "sendkey_winmenu") {
06651         KEYBOARD_AddKey(KBD_rwinmenu, true);
06652         KEYBOARD_AddKey(KBD_rwinmenu, false);
06653     }
06654     else if (menuitem->get_name() == "sendkey_cad") {
06655         KEYBOARD_AddKey(KBD_leftctrl, true);
06656         KEYBOARD_AddKey(KBD_leftalt, true);
06657         KEYBOARD_AddKey(KBD_delete, true);
06658         KEYBOARD_AddKey(KBD_leftctrl, false);
06659         KEYBOARD_AddKey(KBD_leftalt, false);
06660         KEYBOARD_AddKey(KBD_delete, false);
06661     }
06662 
06663     return true;
06664 }
06665 
06666 void SetCyclesCount_mapper_shortcut_RunInternal(void) {
06667 #if !defined(C_SDL2)
06668     void MAPPER_ReleaseAllKeys(void);
06669     MAPPER_ReleaseAllKeys();
06670 
06671     GFX_LosingFocus();
06672 
06673     GUI_Shortcut(16);
06674 
06675     void MAPPER_ReleaseAllKeys(void);
06676     MAPPER_ReleaseAllKeys();
06677 
06678     GFX_LosingFocus();
06679 #endif
06680 }
06681 
06682 void SetCyclesCount_mapper_shortcut_RunEvent(Bitu /*val*/) {
06683     KEYBOARD_ClrBuffer();   //Clear buffer
06684     GFX_LosingFocus();      //Release any keys pressed (buffer gets filled again).
06685     SetCyclesCount_mapper_shortcut_RunInternal();
06686 }
06687 
06688 void SetCyclesCount_mapper_shortcut(bool pressed) {
06689     if (!pressed) return;
06690     PIC_AddEvent(SetCyclesCount_mapper_shortcut_RunEvent, 0.0001f); //In case mapper deletes the key object that ran it
06691 }
06692 
06693 void AspectRatio_mapper_shortcut(bool pressed) {
06694     if (!pressed) return;
06695 
06696     if (!GFX_GetPreventFullscreen()) {
06697         SetVal("render", "aspect", render.aspect ? "false" : "true");
06698         mainMenu.get_item("mapper_aspratio").check(render.aspect).refresh_item(mainMenu);
06699     }
06700 }
06701 
06702 void HideMenu_mapper_shortcut(bool pressed) {
06703     if (!pressed) return;
06704 
06705     void ToggleMenu(bool pressed);
06706     ToggleMenu(true);
06707 
06708     mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu);
06709 }
06710 
06711 void OutputSettingMenuUpdate(void) {
06712     mainMenu.get_item("output_surface").check(sdl.desktop.want_type == SCREEN_SURFACE).refresh_item(mainMenu);
06713 #if C_DIRECT3D
06714     mainMenu.get_item("output_direct3d").check(sdl.desktop.want_type == SCREEN_DIRECT3D).refresh_item(mainMenu);
06715 #endif
06716 #if C_OPENGL
06717     mainMenu.get_item("output_opengl").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear).refresh_item(mainMenu);
06718     mainMenu.get_item("output_openglnb").check(sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear).refresh_item(mainMenu);
06719 #endif
06720 }
06721 
06722 bool custom_bios = false;
06723 
06724 //extern void UI_Init(void);
06725 int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT {
06726     CommandLine com_line(argc,argv);
06727     Config myconf(&com_line);
06728 
06729 #if C_EMSCRIPTEN
06730     control->opt_debug = true;
06731     control->opt_earlydebug = true;
06732 #endif
06733 
06734     bitop::self_test();
06735     ptrop::self_test();
06736 
06737     memset(&sdl, 0, sizeof(sdl));
06738 
06739     // initialize output libraries
06740     OUTPUT_SURFACE_Initialize();
06741 #if C_OPENGL
06742     OUTPUT_OPENGL_Initialize();
06743 #endif
06744 #if C_DIRECT3D
06745     OUTPUT_DIRECT3D_Initialize();
06746 #endif
06747 
06748     // initialize some defaults in SDL structure here
06749     sdl.srcAspect.x = 4; sdl.srcAspect.y = 3; 
06750     sdl.srcAspect.xToY = (double)sdl.srcAspect.x / sdl.srcAspect.y;
06751     sdl.srcAspect.yToX = (double)sdl.srcAspect.y / sdl.srcAspect.x;
06752 
06753     control=&myconf;
06754 #if defined(WIN32) && !defined(HX_DOS)
06755     /* Microsoft's IME does not play nice with DOSBox */
06756     ImmDisableIME((DWORD)(-1));
06757 #endif
06758 
06759 #if defined(MACOSX)
06760     /* The resource system of DOSBox-X relies on being able to locate the Resources subdirectory
06761        within the DOSBox-X .app bundle. To do this, we have to first know where our own executable
06762        is, which Mac OS X helpfully puts int argv[0] for us */
06763     /* NTS: Experimental testing shows that when we are run from the desktop (double-clicking on
06764             the .app bundle from the Finder) the current working directory is / (fs root). */
06765     extern std::string MacOSXEXEPath;
06766     extern std::string MacOSXResPath;
06767     MacOSXEXEPath = argv[0];
06768 
06769     /* The path should be something like /blah/blah/dosbox-x.app/Contents/MacOS/DosBox */
06770     /* If that's true, then we can move one level up the tree and look for */
06771     /* /blah/blah/dosbox-x.app/Contents/Resources */
06772     {
06773     const char *ref = argv[0];
06774     const char *s = strrchr(ref,'/');
06775     if (s != NULL) {
06776         if (s > ref) s--;
06777         while (s > ref && *s != '/') s--;
06778         if (!strncasecmp(s,"/MacOS/",7)) {
06779             MacOSXResPath = std::string(ref,(size_t)(s-ref)) + "/Resources";
06780         }
06781     }
06782     }
06783 
06784     /* If we were launched by the Finder, the current working directory will usually be
06785        the root of the filesystem (/) which is useless. If we see that, change instead
06786        to the user's home directory */
06787     {
06788         char *home = getenv("HOME");
06789         char cwd[512];
06790 
06791         cwd[0]=0;
06792         getcwd(cwd,sizeof(cwd)-1);
06793 
06794         if (!strcmp(cwd,"/")) {
06795             /* Only the Finder would do that.
06796                Even if the user somehow did this from the Terminal app, it's still
06797                worth changing to the home directory because certain directories
06798                including / are locked readonly even for sudo in Mac OS X */
06799             /* NTS: HOME is usually an absolute path */
06800             if (home != NULL) chdir(home);
06801         }
06802     }
06803 #endif
06804 
06805     {
06806         std::string tmp,config_path;
06807 
06808         /* -- parse command line arguments */
06809         if (!DOSBOX_parse_argv()) return 1;
06810 
06811         if (control->opt_time_limit > 0)
06812             time_limit_ms = (Bitu)(control->opt_time_limit * 1000);
06813 
06814         if (control->opt_console)
06815             DOSBox_ShowConsole();
06816 
06817         /* -- Handle some command line options */
06818         if (control->opt_eraseconf || control->opt_resetconf)
06819             eraseconfigfile();
06820         if (control->opt_printconf)
06821             printconfiglocation();
06822         if (control->opt_erasemapper || control->opt_resetmapper)
06823             erasemapperfile();
06824 
06825         /* -- Early logging init, in case these details are needed to debug problems at this level */
06826         /*    If --early-debug was given this opens up logging to STDERR until Log::Init() */
06827         LOG::EarlyInit();
06828 
06829 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
06830         {
06831             DISPLAY_DEVICE dd;
06832             unsigned int i = 0;
06833 
06834             do {
06835                 memset(&dd, 0, sizeof(dd));
06836                 dd.cb = sizeof(dd);
06837                 if (!EnumDisplayDevices(NULL, i, &dd, 0)) break;
06838                 LOG_MSG("Win32 EnumDisplayDevices #%d: name=%s string=%s", i, dd.DeviceName, dd.DeviceString);
06839                 i++;
06840 
06841                 if (strstr(dd.DeviceString, "VirtualBox") != NULL)
06842                     isVirtualBox = true;
06843             } while (1);
06844         }
06845 #endif
06846 
06847         /* -- Init the configuration system and add default values */
06848         CheckNumLockState();
06849         CheckCapsLockState();
06850         CheckScrollLockState();
06851 
06852         /* -- setup the config sections for config parsing */
06853         LOG::SetupConfigSection();
06854         SDL_SetupConfigSection();
06855         DOSBOX_SetupConfigSections();
06856 
06857         /* -- Parse configuration files */
06858         Cross::GetPlatformConfigDir(config_path);
06859 
06860         /* -- -- first the user config file */
06861         if (control->opt_userconf) {
06862             tmp.clear();
06863             Cross::GetPlatformConfigDir(config_path);
06864             Cross::GetPlatformConfigName(tmp);
06865             config_path += tmp;
06866 
06867             LOG(LOG_MISC,LOG_DEBUG)("Loading config file according to -userconf from %s",config_path.c_str());
06868             control->ParseConfigFile(config_path.c_str());
06869             if (!control->configfiles.size()) {
06870                 //Try to create the userlevel configfile.
06871                 tmp.clear();
06872                 Cross::CreatePlatformConfigDir(config_path);
06873                 Cross::GetPlatformConfigName(tmp);
06874                 config_path += tmp;
06875 
06876                 LOG(LOG_MISC,LOG_DEBUG)("Attempting to write config file according to -userconf, to %s",config_path.c_str());
06877                 if (control->PrintConfig(config_path.c_str())) {
06878                     LOG(LOG_MISC,LOG_NORMAL)("Generating default configuration. Writing it to %s",config_path.c_str());
06879                     //Load them as well. Makes relative paths much easier
06880                     control->ParseConfigFile(config_path.c_str());
06881                 }
06882             }
06883         }
06884 
06885         /* -- -- second the -conf switches from the command line */
06886         for (size_t si=0;si < control->config_file_list.size();si++) {
06887             std::string &cfg = control->config_file_list[si];
06888             if (!control->ParseConfigFile(cfg.c_str())) {
06889                 // try to load it from the user directory
06890                 control->ParseConfigFile((config_path + cfg).c_str());
06891             }
06892         }
06893 
06894         /* -- -- if none found, use dosbox.conf */
06895         if (!control->configfiles.size()) control->ParseConfigFile("dosbox.conf");
06896 
06897         /* -- -- if none found, use userlevel conf */
06898         if (!control->configfiles.size()) {
06899             tmp.clear();
06900             Cross::GetPlatformConfigName(tmp);
06901             control->ParseConfigFile((config_path + tmp).c_str());
06902         }
06903 
06904 #if (ENVIRON_LINKED)
06905         /* -- parse environment block (why?) */
06906         control->ParseEnv(environ);
06907 #endif
06908 
06909         /* -- initialize logging first, so that higher level inits can report problems to the log file */
06910         LOG::Init();
06911 
06912 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
06913         {
06914             DISPLAY_DEVICE dd;
06915             unsigned int i = 0;
06916 
06917             do {
06918                 memset(&dd, 0, sizeof(dd));
06919                 dd.cb = sizeof(dd);
06920                 if (!EnumDisplayDevices(NULL, i, &dd, 0)) break;
06921                 LOG_MSG("Win32 EnumDisplayDevices #%d: name=%s string=%s", i, dd.DeviceName, dd.DeviceString);
06922                 i++;
06923             } while (1);
06924         }
06925 
06926         if (isVirtualBox) LOG_MSG("Win32 VirtualBox graphics adapter detected");
06927 #endif
06928 
06929         /* -- Welcome to DOSBox-X! */
06930         LOG_MSG("DOSBox-X version %s",VERSION);
06931         LOG(LOG_MISC,LOG_NORMAL)("Copyright 2002-2015 enhanced branch by The Great Codeholio, forked from the main project by the DOSBox Team, published under GNU GPL.");
06932 
06933 #if defined(MACOSX)
06934         LOG_MSG("Mac OS X EXE path: %s",MacOSXEXEPath.c_str());
06935         LOG_MSG("Mac OS X Resource path: %s",MacOSXResPath.c_str());
06936 #endif
06937 
06938         /* -- [debug] setup console */
06939 #if C_DEBUG
06940 # if defined(WIN32) && !defined(HX_DOS)
06941         /* Can't disable the console with debugger enabled */
06942         if (control->opt_noconsole) {
06943             LOG(LOG_MISC,LOG_DEBUG)("-noconsole: hiding Win32 console window");
06944             ShowWindow(GetConsoleWindow(), SW_HIDE);
06945             DestroyWindow(GetConsoleWindow());
06946         }
06947 # endif
06948 #endif
06949 
06950 #if defined(WIN32)
06951         /* -- Windows: set console control handler */
06952         SetConsoleCtrlHandler((PHANDLER_ROUTINE) ConsoleEventHandler,TRUE);
06953 #endif
06954 
06955 #if !defined(C_SDL2)
06956         {
06957             int id, major, minor;
06958 
06959             DOSBox_CheckOS(id, major, minor);
06960             if (id == 1) menu.compatible=true;
06961 
06962             /* use all variables to shut up the compiler about unused vars */
06963             LOG(LOG_MISC,LOG_DEBUG)("DOSBox_CheckOS results: id=%u major=%u minor=%u",id,major,minor);
06964         }
06965 #endif
06966 
06967         /* -- SDL init hackery */
06968 #if SDL_VERSION_ATLEAST(1, 2, 14)
06969         /* hack: On debian/ubuntu with older libsdl version as they have done this themselves, but then differently.
06970          * with this variable they will work correctly. I've only tested the 1.2.14 behaviour against the windows version of libsdl */
06971         putenv(const_cast<char*>("SDL_DISABLE_LOCK_KEYS=1"));
06972         LOG(LOG_GUI,LOG_DEBUG)("SDL 1.2.14 hack: SDL_DISABLE_LOCK_KEYS=1");
06973 #endif
06974 
06975 #ifdef WIN32
06976         /* hack: Encourage SDL to use windib if not otherwise specified */
06977         if (getenv("SDL_VIDEODRIVER") == NULL) {
06978 #if defined(C_SDL2)
06979             LOG(LOG_GUI, LOG_DEBUG)("Win32 hack: setting SDL_VIDEODRIVER=windows because environ variable is not set");
06980             putenv("SDL_VIDEODRIVER=windows");
06981 #else
06982             LOG(LOG_GUI,LOG_DEBUG)("Win32 hack: setting SDL_VIDEODRIVER=windib because environ variable is not set");
06983             putenv("SDL_VIDEODRIVER=windib");
06984 #endif
06985             sdl.using_windib=true;
06986         }
06987 #endif
06988 
06989 #if defined(WIN32) && defined(C_SDL2)
06990         /* HACK: WASAPI output on Windows 10 isn't working... */
06991         if (getenv("SDL_AUDIODRIVER") == NULL) {
06992             LOG(LOG_GUI, LOG_DEBUG)("Win32: using directsound audio driver");
06993             putenv("SDL_AUDIODRIVER=directsound");
06994         }
06995 #endif
06996 
06997         sdl.init_ignore = true;
06998 
06999 #ifdef WIN32
07000         /* Windows Vista/7/8/10 DPI awareness. If we don't tell Windows we're high DPI aware, the DWM will
07001          * upscale our window to emulate a 96 DPI display which on high res screen will make our UI look blurry.
07002          * But we obey the user if they don't want us to do that. */
07003         Windows_DPI_Awareness_Init();
07004 #endif
07005 
07006         /* -- SDL init */
07007 #if defined(C_SDL2)
07008         if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|/*SDL_INIT_CDROM|*/SDL_INIT_NOPARACHUTE) >= 0)
07009 #else
07010         if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_CDROM|SDL_INIT_NOPARACHUTE) >= 0)
07011 #endif
07012             sdl.inited = true;
07013         else
07014             E_Exit("Can't init SDL %s",SDL_GetError());
07015 
07016         /* -- -- decide whether to show menu in GUI */
07017         if (control->opt_nogui || menu.compatible)
07018             menu.gui=false;
07019 
07020         /* -- -- helpful advice */
07021         LOG(LOG_GUI,LOG_NORMAL)("Press Ctrl-F10 to capture/release mouse, Alt-F10 for configuration.");
07022 
07023         /* -- -- other steps to prepare SDL window/output */
07024         SDL_Prepare();
07025 
07026         /* -- -- Keyboard layout detection and setup */
07027         KeyboardLayoutDetect();
07028         SetMapperKeyboardLayout(host_keyboard_layout);
07029 
07030         /* -- -- Initialise Joystick seperately. This way we can warn when it fails instead of exiting the application */
07031         LOG(LOG_MISC,LOG_DEBUG)("Initializing SDL joystick subsystem...");
07032         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0) {
07033             sdl.num_joysticks = (Bitu)SDL_NumJoysticks();
07034             LOG(LOG_MISC,LOG_DEBUG)("SDL reports %u joysticks",(unsigned int)sdl.num_joysticks);
07035         }
07036         else {
07037             LOG(LOG_GUI,LOG_WARN)("Failed to init joystick support");
07038             sdl.num_joysticks = 0;
07039         }
07040 
07041         /* must redraw after modeset */
07042         sdl.must_redraw_all = true;
07043         sdl.deferred_resize = false;
07044 
07045         /* assume L+R ALT keys are up */
07046         sdl.laltstate = SDL_KEYUP;
07047         sdl.raltstate = SDL_KEYUP;
07048 
07049 #if defined(WIN32) && !defined(C_SDL2)
07050 # if SDL_VERSION_ATLEAST(1, 2, 10)
07051         sdl.using_windib=true;
07052 # else
07053         sdl.using_windib=false;
07054 # endif
07055 
07056         if (getenv("SDL_VIDEODRIVER")==NULL) {
07057             putenv("SDL_VIDEODRIVER=windib");
07058             if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) E_Exit("Can't init SDL Video %s",SDL_GetError());
07059             sdl.using_windib=true;
07060         } else {
07061             char* sdl_videodrv = getenv("SDL_VIDEODRIVER");
07062 
07063             LOG(LOG_MISC,LOG_DEBUG)("Win32: SDL_VIDEODRIVER is '%s', so I will obey it",sdl_videodrv);
07064             if (strcmp(sdl_videodrv,"directx")==0) sdl.using_windib = false;
07065             else if (strcmp(sdl_videodrv,"windib")==0) sdl.using_windib = true;
07066         }
07067 #endif
07068 
07069         /* GUI init */
07070         GUI_StartUp();
07071 
07072         /* FIXME: We need a more general "init list", outside of the section-based design,
07073          *        that we then execute serially here. */
07074         /* TODO: Each section currently uses "AddDestroyFunction" per section. We need to
07075          *       change over that code to a global destroy callback list instead. */
07076         /* TODO: Get rid of "init" and "destroy" callback lists per section. */
07077         /* TODO: Add a global (within the Config object) init and destroy callback list.
07078          *       On each call, init functions are added to the end of the list, and
07079          *       destroy functions added to the beginning of the list. That way, init
07080          *       is lowest level to highest, destroy is highest level to lowest. */
07081         /* TODO: Config object should also have a "reset" callback list. On system
07082          *       reset each device would be notified so that it can emulate hardware
07083          *       reset (the RESET line on ISA/PCI bus), lowest level to highest. */
07084         /* TODO: Each "init" function should do the work of getting the section object,
07085          *       whatever section it wants to read, instead of us doing the work. When
07086          *       that's complete, the call to init should be without parameters (void).
07087          *       The hope is that the init functions can read whatever sections it wants,
07088          *       both newer DOSBox-X sections and existing DOSBox (mainline) compatible
07089          *       sections. */
07090 
07091         /* The order is important here:
07092          * Init functions are called low-level first to high level last,
07093          * because some init functions rely on others. */
07094 
07095 #if !defined(C_SDL2)
07096 # if defined(WIN32)
07097         Reflect_Menu();
07098 # endif
07099 
07100         if (control->opt_startui)
07101             GUI_Run(false);
07102 #endif
07103         if (control->opt_editconf.length() != 0)
07104             launcheditor(control->opt_editconf);
07105         if (control->opt_opencaptures.length() != 0)
07106             launchcaptures(control->opt_opencaptures);
07107         if (control->opt_opensaves.length() != 0)
07108             launchsaves(control->opt_opensaves);
07109 
07110         {
07111             /* Some extra SDL Functions */
07112             Section_prop *sdl_sec = static_cast<Section_prop*>(control->GetSection("sdl"));
07113 
07114             if (control->opt_fullscreen || sdl_sec->Get_bool("fullscreen")) {
07115                 LOG(LOG_MISC,LOG_DEBUG)("Going fullscreen immediately, during startup");
07116 
07117 #if !defined(C_SDL2)
07118                 void DOSBox_SetSysMenu(void);
07119                 DOSBox_SetSysMenu();
07120 #endif
07121                 //only switch if not already in fullscreen
07122                 if (!sdl.desktop.fullscreen) GFX_SwitchFullScreen();
07123             }
07124         }
07125 
07126         /* stock top-level menu items */
07127         {
07128             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"MainMenu");
07129             item.set_text("Main");
07130             {
07131                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"MainSendKey");
07132                 item.set_text("Send Key");
07133             }
07134         }
07135         {
07136             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuMenu");
07137             item.set_text("CPU");
07138             {
07139                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuCoreMenu");
07140                 item.set_text("CPU core");
07141             }
07142             {
07143                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuTypeMenu");
07144                 item.set_text("CPU type");
07145             }
07146         }
07147         {
07148             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoMenu");
07149             item.set_text("Video");
07150             {
07151                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoFrameskipMenu");
07152                 item.set_text("Frameskip");
07153         
07154                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"frameskip_0").set_text("Off").
07155                     set_callback_function(video_frameskip_common_menu_callback);
07156 
07157                 for (unsigned int f=1;f <= 10;f++) {
07158                     char tmp1[64],tmp2[64];
07159 
07160                     sprintf(tmp1,"frameskip_%u",f);
07161                     sprintf(tmp2,"%u frame",f);
07162 
07163                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,tmp1).set_text(tmp2).
07164                         set_callback_function(video_frameskip_common_menu_callback);
07165                 }
07166             }
07167             {
07168                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoScalerMenu");
07169                 item.set_text("Scaler");
07170 
07171                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"scaler_forced").set_text("Force scaler").
07172                     set_callback_function(scaler_forced_menu_callback);
07173 
07174                 for (size_t i=0;scaler_menu_opts[i][0] != NULL;i++) {
07175                     const std::string name = std::string("scaler_set_") + scaler_menu_opts[i][0];
07176 
07177                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,name).set_text(scaler_menu_opts[i][1]).
07178                         set_callback_function(scaler_set_menu_callback);
07179                 }
07180             }
07181             {
07182                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoCompatMenu");
07183                 item.set_text("Compatibility");
07184 
07185                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vga_9widetext").set_text("Allow 9-pixel wide text mode").
07186                     set_callback_function(vga_9widetext_menu_callback);
07187                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"doublescan").set_text("Doublescan").
07188                     set_callback_function(doublescan_menu_callback);
07189             }
07190             {
07191                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoOutputMenu");
07192                 item.set_text("Output");
07193 
07194                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_surface").set_text("Surface").
07195                     set_callback_function(output_menu_callback);
07196                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_direct3d").set_text("Direct3D").
07197                     set_callback_function(output_menu_callback);
07198                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_opengl").set_text("OpenGL").
07199                     set_callback_function(output_menu_callback);
07200                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_openglnb").set_text("OpenGL NB").
07201                     set_callback_function(output_menu_callback);
07202             }
07203             {
07204                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoVsyncMenu");
07205                 item.set_text("V-Sync");
07206 
07207                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_on").set_text("On").
07208                     set_callback_function(vsync_menu_callback);
07209                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_force").set_text("Force").
07210                     set_callback_function(vsync_menu_callback);
07211                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_host").set_text("Host").
07212                     set_callback_function(vsync_menu_callback);
07213                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_off").set_text("Off").
07214                     set_callback_function(vsync_menu_callback);
07215                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_set_syncrate").set_text("Set syncrate").
07216                     set_callback_function(vsync_set_syncrate_menu_callback);
07217             }
07218             {
07219                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoOverscanMenu");
07220                 item.set_text("Overscan");
07221 
07222                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"overscan_0").set_text("Off").
07223                     set_callback_function(overscan_menu_callback);
07224 
07225                 for (size_t i=1;i <= 10;i++) {
07226                     char tmp1[64],tmp2[64];
07227 
07228                     sprintf(tmp1,"overscan_%zu",i);
07229                     sprintf(tmp2,"%zu",i);
07230                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,tmp1).set_text(tmp2).
07231                         set_callback_function(overscan_menu_callback);
07232                 }
07233             }
07234             {
07235                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoPC98Menu");
07236                 item.set_text("PC-98");
07237 
07238                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_5mhz_gdc").set_text("5MHz GDC clock").
07239                     set_callback_function(vid_pc98_5mhz_gdc_menu_callback);
07240                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_allow_200scanline").set_text("Allow 200-line scanline effect").
07241                     set_callback_function(vid_pc98_200scanline_menu_callback);
07242                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_allow_4partitions").set_text("Allow 4 display partitions in graphics layer").
07243                     set_callback_function(vid_pc98_4parts_menu_callback);
07244                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_egc").set_text("Enable EGC").
07245                     set_callback_function(vid_pc98_enable_egc_menu_callback);
07246                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_grcg").set_text("Enable GRCG").
07247                     set_callback_function(vid_pc98_enable_grcg_menu_callback);
07248                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_analog").set_text("Enable analog display").
07249                     set_callback_function(vid_pc98_enable_analog_menu_callback);
07250                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_188user").set_text("Enable 188+ user CG cells").
07251                     set_callback_function(vid_pc98_enable_188user_menu_callback);
07252                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_clear_text").set_text("Clear text layer").
07253                     set_callback_function(vid_pc98_cleartext_menu_callback);
07254                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_clear_graphics").set_text("Clear graphics layer").
07255                     set_callback_function(vid_pc98_graphics_menu_callback);
07256             }
07257         }
07258         {
07259             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"SoundMenu");
07260             item.set_text("Sound");
07261 
07262             {
07263                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"mixer_swapstereo").set_text("Swap stereo").
07264                     set_callback_function(mixer_swapstereo_menu_callback);
07265                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"mixer_mute").set_text("Mute").
07266                     set_callback_function(mixer_mute_menu_callback);
07267             }
07268         }
07269         {
07270             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSMenu");
07271             item.set_text("DOS");
07272 
07273             {
07274                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSMouseMenu");
07275                 item.set_text("Mouse");
07276 
07277                 {
07278                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_enable_int33").set_text("Internal Emulation").
07279                         set_callback_function(dos_mouse_enable_int33_menu_callback);
07280                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_y_axis_reverse").set_text("Y-axis Reverse").
07281                         set_callback_function(dos_mouse_y_axis_reverse_menu_callback);
07282                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_sensitivity").set_text("Sensitivity").
07283                         set_callback_function(dos_mouse_sensitivity_menu_callback);
07284                 }
07285             }
07286 
07287             {
07288                 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSPC98Menu");
07289                 item.set_text("PC-98 PIT master clock");
07290 
07291                 {
07292                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_pc98_pit_4mhz").set_text("4MHz/8MHz").
07293                         set_callback_function(dos_pc98_clock_menu_callback);
07294                     mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_pc98_pit_5mhz").set_text("5MHz/10MHz").
07295                         set_callback_function(dos_pc98_clock_menu_callback);
07296                 }
07297             }
07298         }
07299 #if !defined(C_EMSCRIPTEN)
07300         {
07301             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CaptureMenu");
07302             item.set_text("Capture");
07303         }
07304 # if (C_SSHOT)
07305         {
07306             DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CaptureFormatMenu");
07307             item.set_text("Capture format");
07308 
07309             {
07310                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"capture_fmt_avi_zmbv").set_text("AVI + ZMBV").
07311                     set_callback_function(capture_fmt_menu_callback);
07312 #  if (C_AVCODEC)
07313                 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"capture_fmt_mpegts_h264").set_text("MPEG-TS + H.264").
07314                     set_callback_function(capture_fmt_menu_callback);
07315 #  endif
07316             }
07317         }
07318 # endif
07319 #endif
07320 
07321         /* more */
07322         {
07323             DOSBoxMenu::item *item;
07324 
07325             MAPPER_AddHandler(&SetCyclesCount_mapper_shortcut, MK_nothing, 0, "editcycles", "EditCycles", &item);
07326             item->set_text("Edit cycles");
07327 
07328             MAPPER_AddHandler(&HideMenu_mapper_shortcut, MK_escape, MMODHOST, "togmenu", "TogMenu", &item);
07329             item->set_text("Hide/show menu bar");
07330             item->check(!menu.toggle);
07331 
07332             MAPPER_AddHandler(&PauseWithInterrupts_mapper_shortcut, MK_nothing, 0, "pauseints", "PauseInts", &item);
07333             item->set_text("Pause with interrupts enabled");
07334         }
07335 
07336         /* Start up main machine */
07337 
07338         // Shows menu bar (window)
07339         menu.startup = true;
07340         menu.showrt = control->opt_showrt;
07341         menu.hidecycles = (control->opt_showcycles ? false : true);
07342 
07343 #if defined(WIN32) && !defined(C_SDL2)
07344         {
07345             Section_prop *sec = static_cast<Section_prop *>(control->GetSection("dosbox"));
07346             enable_hook_special_keys = sec->Get_bool("keyboard hook");
07347         }
07348 #endif
07349 
07350         MSG_Init();
07351         MAPPER_StartUp();
07352         DOSBOX_InitTickLoop();
07353         DOSBOX_RealInit();
07354 
07355         /* at this point: If the machine type is PC-98, and the mapper keyboard layout was "Japanese",
07356          * then change the mapper layout to "Japanese PC-98" */
07357         if (host_keyboard_layout == DKM_JPN && IS_PC98_ARCH)
07358             SetMapperKeyboardLayout(DKM_JPN_PC98);
07359 
07360         RENDER_Init();
07361 
07362         { /* Depends on RENDER_Init */
07363             DOSBoxMenu::item *item;
07364 
07365             MAPPER_AddHandler(&AspectRatio_mapper_shortcut, MK_nothing, 0, "aspratio", "AspRatio", &item);
07366             item->set_text("Fit to aspect ratio");
07367             item->check(render.aspect);
07368         }
07369 
07370         CAPTURE_Init();
07371         IO_Init();
07372         HARDWARE_Init();
07373         Init_AddressLimitAndGateMask(); /* <- need to init address mask so Init_RAM knows the maximum amount of RAM possible */
07374         Init_MemoryAccessArray(); /* <- NTS: In DOSBox-X this is the "cache" of devices that responded to memory access */
07375         Init_A20_Gate(); // FIXME: Should be handled by motherboard!
07376         Init_PS2_Port_92h(); // FIXME: Should be handled by motherboard!
07377         Init_RAM();
07378         Init_DMA();
07379         Init_PIC();
07380         TIMER_Init();
07381         PCIBUS_Init();
07382         PAGING_Init(); /* <- NTS: At this time, must come before memory init because paging is so well integrated into emulation code */
07383         CMOS_Init();
07384         ROMBIOS_Init();
07385         CALLBACK_Init(); /* <- NTS: This relies on ROM BIOS allocation and it must happen AFTER ROMBIOS init */
07386 #if C_DEBUG
07387         DEBUG_Init(); /* <- NTS: Relies on callback system */
07388 #endif
07389         Init_VGABIOS();
07390         VOODOO_Init();
07391         PROGRAMS_Init(); /* <- NTS: Does not init programs, it inits the callback used later when creating the .COM programs on drive Z: */
07392         PCSPEAKER_Init();
07393         TANDYSOUND_Init();
07394         MPU401_Init();
07395         MIXER_Init();
07396         MIDI_Init();
07397         CPU_Init();
07398 #if C_FPU
07399         FPU_Init();
07400 #endif
07401         VGA_Init();
07402         ISAPNP_Cfg_Init();
07403         FDC_Primary_Init();
07404         KEYBOARD_Init();
07405         SBLASTER_Init();
07406         JOYSTICK_Init();
07407         PS1SOUND_Init();
07408         DISNEY_Init();
07409         GUS_Init();
07410         IDE_Init();
07411         INNOVA_Init();
07412         BIOS_Init();
07413         INT10_Init();
07414         SERIAL_Init();
07415         DONGLE_Init();
07416 #if C_PRINTER
07417         PRINTER_Init();
07418 #endif
07419         PARALLEL_Init();
07420 #if C_NE2000
07421         NE2K_Init();
07422 #endif
07423 
07424 #if defined(WIN32) && !defined(C_SDL2)
07425         Reflect_Menu();
07426 #endif
07427 
07428         /* If PCjr emulation, map cartridge ROM */
07429         if (machine == MCH_PCJR)
07430             Init_PCJR_CartridgeROM();
07431 
07432         /* let's assume motherboards are sane on boot because A20 gate is ENABLED on first boot */
07433         MEM_A20_Enable(true);
07434 
07435         /* OS init now */
07436         DOS_Init();
07437         DRIVES_Init();
07438         DOS_KeyboardLayout_Init();
07439         MOUSE_Init(); // FIXME: inits INT 15h and INT 33h at the same time. Also uses DOS_GetMemory() which is why DOS_Init must come first
07440         XMS_Init();
07441         EMS_Init();
07442         AUTOEXEC_Init();
07443 #if C_IPX
07444         IPX_Init();
07445 #endif
07446         MSCDEX_Init();
07447 
07448         /* Init memhandle system. This part is used by DOSBox's XMS/EMS emulation to associate handles
07449          * per page. FIXME: I would like to push this down to the point that it's never called until
07450          * XMS/EMS emulation needs it. I would also like the code to free the mhandle array immediately
07451          * upon booting into a guest OS, since memory handles no longer have meaning in the guest OS
07452          * memory layout. */
07453         Init_MemHandles();
07454 
07455         /* finally, the mapper */
07456         MAPPER_Init();
07457 
07458         /* stop at this point, and show the mapper, if instructed */
07459         if (control->opt_startmapper) {
07460             LOG(LOG_MISC,LOG_DEBUG)("Running mapper interface, during startup, as instructed");
07461             MAPPER_RunInternal();
07462         }
07463 
07464         /* more */
07465 #if !defined(C_EMSCRIPTEN)
07466         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"show_console").set_text("Show console").set_callback_function(show_console_menu_callback);
07467 #endif
07468         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"wait_on_error").set_text("Wait on error").set_callback_function(wait_on_error_menu_callback).check(sdl.wait_on_error);
07469         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"auto_lock_mouse").set_text("Autolock mouse").set_callback_function(autolock_mouse_menu_callback).check(sdl.mouse.autoenable);
07470         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_ctrlesc").set_text("Ctrl+Esc").set_callback_function(sendkey_preset_menu_callback);
07471         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_alttab").set_text("Alt+Tab").set_callback_function(sendkey_preset_menu_callback);
07472         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_winlogo").set_text("Logo key").set_callback_function(sendkey_preset_menu_callback);
07473         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_winmenu").set_text("Menu key").set_callback_function(sendkey_preset_menu_callback);
07474         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_cad").set_text("Ctrl+Alt+Del").set_callback_function(sendkey_preset_menu_callback);
07475         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"doublebuf").set_text("Double Buffering (Fullscreen)").set_callback_function(doublebuf_menu_callback).check(!!GetSetSDLValue(1, "desktop.doublebuf", 0));
07476         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"alwaysontop").set_text("Always on top").set_callback_function(alwaysontop_menu_callback).check(is_always_on_top());
07477         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"showdetails").set_text("Show details").set_callback_function(showdetails_menu_callback).check(!menu.hidecycles);
07478 
07479         bool MENU_get_swapstereo(void);
07480         mainMenu.get_item("mixer_swapstereo").check(MENU_get_swapstereo()).refresh_item(mainMenu);
07481 
07482         bool MENU_get_mute(void);
07483         mainMenu.get_item("mixer_mute").check(MENU_get_mute()).refresh_item(mainMenu);
07484 
07485         mainMenu.get_item("scaler_forced").check(render.scale.forced);
07486 
07487         mainMenu.get_item("vga_9widetext").enable(!IS_PC98_ARCH);
07488         mainMenu.get_item("doublescan").enable(!IS_PC98_ARCH);
07489 
07490         mainMenu.get_item("pc98_5mhz_gdc").enable(IS_PC98_ARCH);
07491         mainMenu.get_item("pc98_allow_200scanline").enable(IS_PC98_ARCH);
07492         mainMenu.get_item("pc98_allow_4partitions").enable(IS_PC98_ARCH);
07493         mainMenu.get_item("pc98_enable_egc").enable(IS_PC98_ARCH);
07494         mainMenu.get_item("pc98_enable_grcg").enable(IS_PC98_ARCH);
07495         mainMenu.get_item("pc98_enable_analog").enable(IS_PC98_ARCH);
07496         mainMenu.get_item("pc98_enable_188user").enable(IS_PC98_ARCH);
07497         mainMenu.get_item("pc98_clear_text").enable(IS_PC98_ARCH);
07498         mainMenu.get_item("pc98_clear_graphics").enable(IS_PC98_ARCH);
07499         mainMenu.get_item("dos_pc98_pit_4mhz").enable(IS_PC98_ARCH);
07500         mainMenu.get_item("dos_pc98_pit_5mhz").enable(IS_PC98_ARCH);
07501 
07502         extern bool Mouse_Vertical;
07503         extern bool Mouse_Drv;
07504 
07505         mainMenu.get_item("dos_mouse_enable_int33").check(Mouse_Drv).refresh_item(mainMenu);
07506         mainMenu.get_item("dos_mouse_y_axis_reverse").check(Mouse_Vertical).refresh_item(mainMenu);
07507 #if !defined(C_EMSCRIPTEN)
07508         mainMenu.get_item("show_console").check(showconsole_init).refresh_item(mainMenu);
07509 #endif
07510 
07511         OutputSettingMenuUpdate();
07512         update_pc98_clock_pit_menu();
07513 #if !defined(C_EMSCRIPTEN)
07514         update_capture_fmt_menu();
07515 #endif
07516 
07517         /* The machine just "powered on", and then reset finished */
07518         if (!VM_PowerOn()) E_Exit("VM failed to power on");
07519 
07520         /* go! */
07521         sdl.init_ignore = false;
07522         UpdateWindowDimensions();
07523         userResizeWindowWidth = 0;
07524         userResizeWindowHeight = 0;
07525 
07526         UpdateOverscanMenu();
07527 
07528 #if !defined(C_SDL2)
07529         void GUI_ResetResize(bool pressed);
07530         GUI_ResetResize(true);
07531 #endif
07532 
07533         void ConstructMenu(void);
07534         ConstructMenu();
07535 
07536 #if 0
07537         mainMenu.dump_log_debug(); /*DEBUG*/
07538 #endif
07539         mainMenu.rebuild();
07540 
07541 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU
07542         /* -- menu */
07543         MainMenu = mainMenu.getWinMenu();
07544 #endif
07545 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
07546         mainMenu.screenWidth = (unsigned int)sdl.surface->w;
07547         mainMenu.updateRect();
07548 #endif
07549 
07550         {
07551             Section_prop *section = static_cast<Section_prop *>(control->GetSection("SDL"));
07552             assert(section != NULL);
07553 
07554             bool cfg_want_menu = section->Get_bool("showmenu");
07555 
07556             /* -- -- decide whether to set menu */
07557             if (menu_gui && !control->opt_nomenu && cfg_want_menu)
07558                 DOSBox_SetMenu();
07559             else
07560                 DOSBox_NoMenu();
07561         }
07562 
07563 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU
07564         int Reflect_Menu(void);
07565         Reflect_Menu();
07566 #endif
07567 
07568         bool reboot_dos;
07569         bool run_machine;
07570         bool wait_debugger;
07571         bool reboot_machine;
07572         bool dos_kernel_shutdown;
07573 
07574 fresh_boot:
07575         reboot_dos = false;
07576         run_machine = false;
07577         wait_debugger = false;
07578         reboot_machine = false;
07579         dos_kernel_shutdown = false;
07580 
07581         /* NTS: CPU reset handler, and BIOS init, has the instruction pointer poised to run through BIOS initialization,
07582          *      which will then "boot" into the DOSBox kernel, and then the shell, by calling VM_Boot_DOSBox_Kernel() */
07583         /* FIXME: throwing int() is a stupid and nondescriptive way to signal shutdown/reset. */
07584         try {
07585 #if C_DEBUG
07586             if (control->opt_break_start) DEBUG_EnableDebugger();
07587 #endif
07588             DOSBOX_RunMachine();
07589         } catch (int x) {
07590             if (x == 2) { /* booting a guest OS. "boot" has already done the work to load the image and setup CPU registers */
07591                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to boot guest OS");
07592 
07593                 run_machine = true; /* make note. don't run the whole shebang from an exception handler! */
07594                 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */
07595             }
07596             else if (x == 3) { /* reboot the system */
07597                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot the system");
07598 
07599                 reboot_machine = true;
07600                 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */
07601             }
07602             else if (x == 5) { /* go to PC-98 mode */
07603                 E_Exit("Obsolete int signal");
07604             }
07605             else if (x == 6) { /* reboot DOS kernel */
07606                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot DOS kernel");
07607 
07608                 reboot_dos = true;
07609                 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */
07610             }
07611             else if (x == 7) { /* DOS kernel corruption error (need to restart the DOS kernel) */
07612                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot DOS kernel");
07613 
07614                 reboot_dos = true;
07615                 wait_debugger = true;
07616                 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */
07617             }
07618             else if (x == 8) { /* Booting to a BIOS, shutting down DOSBox BIOS */
07619                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to boot into BIOS image");
07620 
07621                 reboot_machine = true;
07622                 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */
07623             }
07624             else {
07625                 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw DOSBox kill switch signal");
07626 
07627                 // kill switch (see instances of throw(0) and throw(1) elsewhere in DOSBox)
07628                 run_machine = false;
07629                 dos_kernel_shutdown = false;
07630             }
07631         }
07632         catch (...) {
07633             throw;
07634         }
07635 
07636 #if defined(WIN32) && !defined(C_SDL2)
07637         int Reflect_Menu(void);
07638         Reflect_Menu();
07639 #endif
07640 
07641         if (dos_kernel_shutdown) {
07642             /* NTS: we take different paths depending on whether we're just shutting down DOS
07643              *      or doing a hard reboot. */
07644 
07645             if (wait_debugger) {
07646 #if C_DEBUG
07647                 Bitu DEBUG_EnableDebugger(void);
07648                 void DEBUG_WaitNoExecute(void);
07649 
07650                 LOG_MSG("Starting debugger.");
07651                 DEBUG_EnableDebugger();
07652                 DEBUG_WaitNoExecute();
07653 #endif
07654             }
07655 
07656             /* new code: fire event */
07657             if (reboot_machine)
07658                 DispatchVMEvent(VM_EVENT_DOS_EXIT_REBOOT_BEGIN);
07659             else
07660                 DispatchVMEvent(VM_EVENT_DOS_EXIT_BEGIN);
07661 
07662             /* older shutdown code */
07663             RemoveEMSPageFrame();
07664 
07665             /* remove UMB block */
07666             if (!keep_umb_on_boot) RemoveUMBBlock();
07667 
07668             /* disable INT 33h mouse services. it can interfere with guest OS paging and control of the mouse */
07669             DisableINT33();
07670 
07671             /* unmap the DOSBox kernel private segment. if the user told us not to,
07672              * but the segment exists below 640KB, then we must, because the guest OS
07673              * will trample it and assume control of that region of RAM. */
07674             if (!keep_private_area_on_boot || reboot_machine)
07675                 DOS_GetMemory_unmap();
07676             else if (DOS_PRIVATE_SEGMENT < 0xA000)
07677                 DOS_GetMemory_unmap();
07678 
07679             /* revector some dos-allocated interrupts */
07680             if (!reboot_machine) {
07681                 real_writed(0,0x01*4,BIOS_DEFAULT_HANDLER_LOCATION);
07682                 real_writed(0,0x03*4,BIOS_DEFAULT_HANDLER_LOCATION);
07683             }
07684 
07685             /* shutdown DOSBox's virtual drive Z */
07686             VFILE_Shutdown();
07687 
07688             /* shutdown the programs */
07689             PROGRAMS_Shutdown();        /* FIXME: Is this safe? Or will this cause use-after-free bug? */
07690 
07691             /* remove environment variables for some components */
07692             DOS_UninstallMisc();
07693             SBLASTER_DOS_Shutdown();
07694             GUS_DOS_Shutdown();
07695             /* disable Expanded Memory. EMM is a DOS API, not a BIOS API */
07696             EMS_DoShutDown();
07697             /* and XMS, also a DOS API */
07698             XMS_DoShutDown();
07699             /* and the DOS API in general */
07700             DOS_DoShutDown();
07701 
07702             /* set the "disable DOS kernel" flag so other parts of this program
07703              * do not attempt to manipulate now-defunct parts of the kernel
07704              * such as the environment block */
07705             dos_kernel_disabled = true;
07706 
07707             /* new code: fire event */
07708             if (reboot_machine)
07709                 DispatchVMEvent(VM_EVENT_DOS_EXIT_REBOOT_KERNEL);
07710             else
07711                 DispatchVMEvent(VM_EVENT_DOS_EXIT_KERNEL);
07712 
07713 #if defined(WIN32) && !defined(C_SDL2)
07714             int Reflect_Menu(void);
07715             Reflect_Menu();
07716 #endif
07717         }
07718 
07719 #if defined(WIN32) && !defined(C_SDL2)
07720         int Reflect_Menu(void);
07721         Reflect_Menu();
07722 #endif
07723 
07724         if (run_machine) {
07725             bool disable_a20 = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("turn off a20 gate on boot");
07726 
07727             /* if instructed, turn off A20 at boot */
07728             if (disable_a20) MEM_A20_Enable(false);
07729 
07730             /* PC-98: hide the cursor */
07731             if (IS_PC98_ARCH) {
07732                 void PC98_show_cursor(bool show);
07733                 PC98_show_cursor(false);
07734             }
07735 
07736             /* new code: fire event */
07737             DispatchVMEvent(VM_EVENT_GUEST_OS_BOOT);
07738 
07739             LOG_MSG("Alright: DOS kernel shutdown, booting a guest OS\n");
07740             LOG_MSG("  CS:IP=%04x:%04x SS:SP=%04x:%04x AX=%04x BX=%04x CX=%04x DX=%04x\n",
07741                 SegValue(cs),reg_ip,
07742                 SegValue(ss),reg_sp,
07743                 reg_ax,reg_bx,reg_cx,reg_dx);
07744 
07745 #if C_DEBUG
07746             if (boot_debug_break) {
07747                 boot_debug_break = false;
07748 
07749                 void DEBUG_Enable(bool pressed);
07750                 DEBUG_Enable(true);
07751             }
07752 #endif
07753 
07754             /* run again */
07755             goto fresh_boot;
07756         }
07757 
07758 #if defined(WIN32) && !defined(C_SDL2)
07759         int Reflect_Menu(void);
07760         Reflect_Menu();
07761 #endif
07762 
07763         if (reboot_machine) {
07764             LOG_MSG("Rebooting the system\n");
07765 
07766             void CPU_Snap_Back_Forget();
07767             /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */
07768             CPU_Snap_Back_To_Real_Mode();
07769             CPU_Snap_Back_Forget();
07770 
07771             /* new code: fire event */
07772             DispatchVMEvent(VM_EVENT_RESET);
07773 
07774             extern bool custom_bios;
07775             if (custom_bios) {
07776                 /* need to relocate BIOS allocations */
07777                 void ROMBIOS_InitForCustomBIOS(void);
07778                 ROMBIOS_InitForCustomBIOS();
07779 
07780                 void CALLBACK_Init();
07781                 CALLBACK_Init();
07782 
07783 #if C_DEBUG
07784                 void DEBUG_ReinitCallback(void);
07785                 DEBUG_ReinitCallback();
07786 #endif
07787             }
07788 
07789             DispatchVMEvent(VM_EVENT_RESET_END);
07790 
07791             /* HACK: EGA/VGA modes will need VGA BIOS mapped in, ready to go */
07792             if (IS_EGAVGA_ARCH) {
07793                 void INT10_Startup(Section *sec);
07794                 INT10_Startup(NULL);
07795             }
07796 
07797 #if C_DEBUG
07798             if (boot_debug_break) {
07799                 boot_debug_break = false;
07800 
07801                 void DEBUG_Enable(bool pressed);
07802                 DEBUG_Enable(true);
07803             }
07804 #endif
07805 
07806             /* run again */
07807             goto fresh_boot;
07808         }
07809         else if (reboot_dos) { /* typically (at this time) to enter/exit PC-98 mode */
07810             LOG_MSG("Rebooting DOS\n");
07811 
07812             void CPU_Snap_Back_Forget();
07813             /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */
07814             CPU_Snap_Back_To_Real_Mode();
07815             CPU_Snap_Back_Forget();
07816 
07817             /* all hardware devices need to know to reregister themselves PC-98 style */
07818 
07819             /* begin booting DOS again. */
07820             void BIOS_Enter_Boot_Phase(void);
07821             BIOS_Enter_Boot_Phase();
07822 
07823             /* run again */
07824             goto fresh_boot;
07825         }
07826 
07827 #if defined(WIN32) && !defined(C_SDL2)
07828         int Reflect_Menu(void);
07829         Reflect_Menu();
07830 #endif
07831 
07832         /* and then shutdown */
07833         GFX_ShutDown();
07834 
07835         void CPU_Snap_Back_Forget();
07836         /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */
07837         CPU_Snap_Back_To_Real_Mode();
07838         CPU_Snap_Back_Forget();
07839 
07840         /* NTS: The "control" object destructor is called here because the "myconf" object leaves scope.
07841          * The destructor calls all section destroy functions here. After this point, all sections have
07842          * freed resources. */
07843     }
07844 
07845     void CALLBACK_Dump(void);
07846     CALLBACK_Dump();
07847 
07848     /* GUI font registry shutdown */
07849 #if !defined(C_SDL2)
07850     GUI::Font::registry_freeall();
07851 #endif
07852     DOS_ShutdownDrives();
07853     DOS_ShutdownFiles();
07854     DOS_ShutdownDevices();
07855     CALLBACK_Shutdown();
07856 #if C_DYNAMIC_X86
07857     CPU_Core_Dyn_X86_Shutdown();
07858 #endif
07859     FreeBIOSDiskList();
07860     MAPPER_Shutdown();
07861     VFILE_Shutdown();
07862     PROGRAMS_Shutdown();
07863     TIMER_ShutdownTickHandlers();
07864 #if C_DEBUG
07865     DEBUG_ShutDown(NULL);
07866 #endif
07867 
07868     sticky_keys(true); //Might not be needed if the shutdown function switches to windowed mode, but it doesn't hurt
07869 
07870     //Force visible mouse to end user. Somehow this sometimes doesn't happen
07871 #if defined(C_SDL2)
07872     SDL_SetRelativeMouseMode(SDL_FALSE);
07873 #else
07874     SDL_WM_GrabInput(SDL_GRAB_OFF);
07875 #endif
07876     SDL_ShowCursor(SDL_ENABLE);
07877 
07878     /* Exit functions */
07879     while (!exitfunctions.empty()) {
07880         Function_wrapper &ent = exitfunctions.front();
07881 
07882         LOG(LOG_MISC,LOG_DEBUG)("Calling exit function (%p) '%s'",(void*)((uintptr_t)ent.function),ent.name.c_str());
07883         ent.function(NULL);
07884         exitfunctions.pop_front();
07885     }
07886 
07887     LOG::Exit();
07888 
07889 #if defined(WIN32) && !defined(C_SDL2)
07890 # if !defined(HX_DOS)
07891     ShowWindow(GetHWND(), SW_HIDE);
07892     SDL1_hax_SetMenu(NULL);/* detach menu from window, or else Windows will destroy the menu out from under the C++ class */
07893 # endif
07894 #endif
07895 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU
07896     void sdl_hax_macosx_setmenu(void *nsMenu);
07897     sdl_hax_macosx_setmenu(NULL);
07898 #endif
07899 
07900     SDL_Quit();//Let's hope sdl will quit as well when it catches an exception
07901 
07902     mainMenu.unbuild();
07903     mainMenu.clear_all_menu_items();
07904 
07905     return 0;
07906 }
07907 
07908 void GFX_GetSize(int &width, int &height, bool &fullscreen) {
07909     width = sdl.clip.w; // draw.width
07910     height = sdl.clip.h; // draw.height
07911     fullscreen = sdl.desktop.fullscreen;
07912 }
07913 
07914 void GFX_ShutDown(void) {
07915     LOG(LOG_MISC,LOG_DEBUG)("Shutting down GFX renderer");
07916     GFX_Stop();
07917     if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop );
07918     if (sdl.mouse.locked) GFX_CaptureMouse();
07919     if (sdl.desktop.fullscreen) GFX_SwitchFullScreen();
07920 }
07921 
07922 bool OpenGL_using(void) {
07923 #if C_OPENGL
07924     return (sdl.desktop.want_type==SCREEN_OPENGL?true:false);
07925 #else
07926     return false;
07927 #endif
07928 }
07929 
07930 bool Get_Custom_SaveDir(std::string& savedir) {
07931     (void)savedir;//UNUSED
07932     if (custom_savedir.length() != 0)
07933         return true;
07934 
07935     return false;
07936 }
07937 
07938 #if !defined(C_SDL2)
07939 void GUI_ResetResize(bool pressed) {
07940     void RENDER_CallBack( GFX_CallBackFunctions_t function );
07941 
07942     if (!pressed) return;
07943     userResizeWindowWidth = 0;
07944     userResizeWindowHeight = 0;
07945 
07946     if (GFX_GetPreventFullscreen())
07947         return;
07948 
07949     if (sdl.updating && !GFX_MustActOnResize()) {
07950         /* act on resize when updating is complete */
07951         sdl.deferred_resize = true;
07952     }
07953     else {
07954         sdl.deferred_resize = false;
07955         RENDER_CallBack(GFX_CallBackReset);
07956     }
07957 }
07958 #endif
07959 
07960 bool MOUSE_IsLocked()
07961 {
07962         return sdl.mouse.locked;
07963 }