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