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