From eff3664fecbfeabe9227d18f266a20985aeaa3dd Mon Sep 17 00:00:00 2001 From: Volker Ruppert Date: Sun, 1 Jan 2017 17:45:06 +0000 Subject: [PATCH] Implemented VGA console support in the common gui code and the X11 specific code. Now the runtime configuration runs in the Bochs window instead of console / xterm. The simulation screen is restored when the simulation continues. This feature can be implemented for all guis without gui dialog box support (e.g. sdl2/sdl2 on non-win32 platforms, rfb). --- bochs/CHANGES | 4 + bochs/gui/gui.cc | 159 ++++++++++++++++++++++++- bochs/gui/gui.h | 34 +++++- bochs/gui/paramtree.h | 26 ++--- bochs/gui/siminterface.cc | 35 +++++- bochs/gui/siminterface.h | 8 +- bochs/gui/textconfig.cc | 239 +++++++++++++++++++------------------- bochs/gui/x.cc | 100 +++++++++++----- 8 files changed, 434 insertions(+), 171 deletions(-) diff --git a/bochs/CHANGES b/bochs/CHANGES index 68a671290..391e97c2e 100644 --- a/bochs/CHANGES +++ b/bochs/CHANGES @@ -9,6 +9,10 @@ Changes after 2.6.8 release: - Configure and compile - Added Android host platform support. +- GUI and display libraries + - X11: Show the runtime configuration in the Bochs VGA window instead of + console / xterm. + - CPU / CPUDB - Bugfixes for CPU emulation correctness (critical bugfix for x86-64 and AVX opcodes emulation, fixed assertion failures in proc_ctrl.cc) diff --git a/bochs/gui/gui.cc b/bochs/gui/gui.cc index 4320cba51..24775303b 100644 --- a/bochs/gui/gui.cc +++ b/bochs/gui/gui.cc @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2015 The Bochs Project +// Copyright (C) 2002-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -36,6 +36,8 @@ #include "gui/bitmaps/userbutton.h" #include "gui/bitmaps/saverestore.h" +#include "sdl.h" + #if BX_WITH_MACOS # include #endif @@ -102,6 +104,7 @@ bx_gui_c::bx_gui_c(void): disp_mode(DISP_MODE_SIM) led_timer_index = BX_NULL_TIMER_HANDLE; framebuffer = NULL; guest_textmode = 1; + guest_fsize = (16 << 4) | 8; guest_xres = 640; guest_yres = 480; guest_bpp = 8; @@ -115,6 +118,11 @@ bx_gui_c::~bx_gui_c() if (framebuffer != NULL) { delete [] framebuffer; } +#if BX_USE_TEXTCONFIG + if (console.running) { + console_cleanup(); + } +#endif } void bx_gui_c::init(int argc, char **argv, unsigned max_xres, unsigned max_yres, @@ -129,7 +137,10 @@ void bx_gui_c::init(int argc, char **argv, unsigned max_xres, unsigned max_yres, BX_GUI_THIS x_tilesize = tilewidth; BX_GUI_THIS y_tilesize = tileheight; BX_GUI_THIS dialog_caps = BX_GUI_DLG_RUNTIME | BX_GUI_DLG_SAVE_RESTORE; - +#if BX_USE_TEXTCONFIG + BX_GUI_THIS console.present = 0; + BX_GUI_THIS console.running = 0; +#endif BX_GUI_THIS toggle_method = SIM->get_param_enum(BXPN_MOUSE_TOGGLE)->get(); BX_GUI_THIS toggle_keystate = 0; switch (toggle_method) { @@ -1053,3 +1064,147 @@ void bx_gui_c::close_debug_dialog() CloseDebugDialog(); } #endif + +#if BX_USE_TEXTCONFIG + +#define BX_CONSOLE_BUFSIZE 4000 + +void bx_gui_c::console_init(void) +{ + int i; + + console.screen = new Bit8u[BX_CONSOLE_BUFSIZE]; + console.oldscreen = new Bit8u[BX_CONSOLE_BUFSIZE]; + for (i = 0; i < BX_CONSOLE_BUFSIZE; i+=2) { + console.screen[i] = 0x20; + console.screen[i+1] = 0x07; + } + memset(console.oldscreen, 0xff, BX_CONSOLE_BUFSIZE); + console.saved_xres = guest_xres; + console.saved_yres = guest_yres; + console.saved_bpp = guest_bpp; + console.saved_fsize = guest_fsize; + for (i = 0; i < 256; i++) { + memcpy(&BX_GUI_THIS vga_charmap[0]+i*32, &sdl_font8x16[i], 16); + BX_GUI_THIS char_changed[i] = 1; + } + BX_GUI_THIS charmap_updated = 1; + console.cursor_x = 0; + console.cursor_y = 0; + memset(&console.tminfo, 0, sizeof(bx_vga_tminfo_t)); + console.tminfo.line_offset = 160; + console.tminfo.line_compare = 1023; + console.tminfo.cs_start = 14; + console.tminfo.cs_end = 15; + console.tminfo.blink_flags = BX_TEXT_BLINK_MODE | BX_TEXT_BLINK_STATE; + console.tminfo.actl_palette[7] = 0x07; + dimension_update(720, 400, 16, 9, 8); + console.n_keys = 0; + console.running = 1; +} + +void bx_gui_c::console_cleanup(void) +{ + delete [] console.screen; + delete [] console.oldscreen; + unsigned fheight = (console.saved_fsize >> 4); + unsigned fwidth = (console.saved_fsize & 0x0f); + dimension_update(console.saved_xres, console.saved_yres, fheight, fwidth, + console.saved_bpp); + console.running = 0; +} + +void bx_gui_c::console_refresh(bx_bool force) +{ + if (force) memset(console.oldscreen, 0xff, BX_CONSOLE_BUFSIZE); + text_update(console.oldscreen, console.screen, console.cursor_x, + console.cursor_y, &console.tminfo); + memcpy(console.oldscreen, console.screen, BX_CONSOLE_BUFSIZE); +} + +void bx_gui_c::console_key_enq(Bit8u key) +{ + if (console.n_keys < 16) { + console.keys[console.n_keys++] = key; + } +} + +int bx_gui_c::bx_printf(const char *s) +{ + unsigned offset; + + if (!console.running) { + console_init(); + } + for (unsigned i = 0; i < strlen(s); i++) { + offset = console.cursor_y * 160 + console.cursor_x * 2; + if ((s[i] != 0x08) && (s[i] != 0x0a)) { + console.screen[offset] = s[i]; + console.screen[offset+1] = 0x07; + console.cursor_x++; + } + if ((s[i] == 0x0a) || (console.cursor_x == 80)) { + console.cursor_x = 0; + console.cursor_y++; + } + if (s[i] == 0x08) { + if (offset > 0) { + console.screen[offset-2] = 0x20; + console.screen[offset-1] = 0x07; + if (console.cursor_x > 0) { + console.cursor_x--; + } else { + console.cursor_x = 79; + console.cursor_y--; + } + } + } + if (console.cursor_y == 25) { + memcpy(console.screen, console.screen+160, BX_CONSOLE_BUFSIZE-160); + console.cursor_y--; + offset = console.cursor_y * 160 + console.cursor_x * 2; + for (int j = 0; j < 160; j+=2) { + console.screen[offset+j] = 0x20; + console.screen[offset+j+1] = 0x07; + } + } + } + console_refresh(0); + return strlen(s); +} + +char* bx_gui_c::bx_gets(char *s, int size) +{ + char keystr[2]; + int pos = 0, done = 0; + + keystr[1] = 0; + do { + handle_events(); + while ((console.n_keys > 0) && !done) { + if ((console.keys[0] >= 0x20) && (pos < (size-1))) { + s[pos++] = console.keys[0]; + keystr[0] = console.keys[0]; + bx_printf(keystr); + } else if (console.keys[0] == 0x0d) { + s[pos] = 0x00; + keystr[0] = 0x0a; + bx_printf(keystr); + done = 1; + } else if ((console.keys[0] == 0x08) && (pos > 0)) { + pos--; + keystr[0] = 0x08; + bx_printf(keystr); + } + memcpy(&console.keys[0], &console.keys[1], 15); + console.n_keys--; + } +#if BX_HAVE_USLEEP + usleep(25000); +#else + msleep(25); +#endif + } while (!done); + return s; +} +#endif diff --git a/bochs/gui/gui.h b/bochs/gui/gui.h index 7f9896292..a48576888 100644 --- a/bochs/gui/gui.h +++ b/bochs/gui/gui.h @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2015 The Bochs Project +// Copyright (C) 2002-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -162,6 +162,14 @@ public: void init_debug_dialog(void); void close_debug_dialog(void); #endif +#if BX_USE_TEXTCONFIG + // gui console support + bx_bool has_gui_console(void) {return console.present;} + void console_refresh(bx_bool force); + void console_key_enq(Bit8u key); + int bx_printf(const char *s); + char* bx_gets(char *s, int size); +#endif protected: // And these are defined and used privately in gui.cc @@ -183,6 +191,11 @@ protected: // status bar LED timer static void led_timer_handler(void *); void led_timer(void); +#if BX_USE_TEXTCONFIG + // gui console support + void console_init(void); + void console_cleanup(void); +#endif // header bar buttons bx_bool floppyA_status; @@ -231,6 +244,7 @@ protected: unsigned y_tilesize; // current guest display settings bx_bool guest_textmode; + unsigned guest_fsize; unsigned guest_xres; unsigned guest_yres; unsigned guest_bpp; @@ -252,6 +266,24 @@ protected: int user_shortcut_len; // gui dialog capabilities Bit32u dialog_caps; +#if BX_USE_TEXTCONFIG + // gui console support + struct { + bx_bool present; + bx_bool running; + Bit8u *screen; + Bit8u *oldscreen; + unsigned saved_fsize; + unsigned saved_xres; + unsigned saved_yres; + unsigned saved_bpp; + unsigned cursor_x; + unsigned cursor_y; + bx_vga_tminfo_t tminfo; + Bit8u keys[16]; + Bit8u n_keys; + } console; +#endif }; diff --git a/bochs/gui/paramtree.h b/bochs/gui/paramtree.h index c828022d0..c01327074 100644 --- a/bochs/gui/paramtree.h +++ b/bochs/gui/paramtree.h @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2010-2015 The Bochs Project +// Copyright (C) 2010-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -167,8 +167,8 @@ public: void *get_device_param() { return device; } #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *fp) {} - virtual int text_ask(FILE *fpin, FILE *fpout) { return -1; } + virtual void text_print() {} + virtual int text_ask() { return -1; } #endif virtual int parse_param(const char *value) { return -1; } @@ -230,8 +230,8 @@ public: static Bit32u set_default_base(Bit32u val); static Bit32u get_default_base() { return default_base; } #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *fp); - virtual int text_ask(FILE *fpin, FILE *fpout); + virtual void text_print(); + virtual int text_ask(); #endif virtual int parse_param(const char *value); }; @@ -314,8 +314,8 @@ public: Bit64s initial_val, bx_bool is_shadow = 0); #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *fp); - virtual int text_ask(FILE *fpin, FILE *fpout); + virtual void text_print(); + virtual int text_ask(); #endif virtual int parse_param(const char *value); }; @@ -363,8 +363,8 @@ public: Bit64u get_dependent_bitmap(Bit64s value); virtual void set_enabled(int enabled); #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *fp); - virtual int text_ask(FILE *fpin, FILE *fpout); + virtual void text_print(); + virtual int text_ask(); #endif virtual int parse_param(const char *value); }; @@ -412,8 +412,8 @@ public: bx_bool isempty(); int sprint(char *buf, int buflen, bx_bool dquotes); #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *fp); - virtual int text_ask(FILE *fpin, FILE *fpout); + virtual void text_print(); + virtual int text_ask(); #endif virtual int parse_param(const char *value); }; @@ -541,8 +541,8 @@ public: void set_restore_handler(void *devptr, list_restore_handler restore); void restore(); #if BX_USE_TEXTCONFIG - virtual void text_print(FILE *); - virtual int text_ask(FILE *fpin, FILE *fpout); + virtual void text_print(); + virtual int text_ask(); #endif }; diff --git a/bochs/gui/siminterface.cc b/bochs/gui/siminterface.cc index 4d78ce69e..13644eede 100644 --- a/bochs/gui/siminterface.cc +++ b/bochs/gui/siminterface.cc @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2016 The Bochs Project +// Copyright (C) 2002-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -218,6 +218,11 @@ public: const char *param, int maxports, bx_list_c *base); virtual int write_param_list(FILE *fp, bx_list_c *base, const char *optname, bx_bool multiline); virtual int write_usb_options(FILE *fp, int maxports, bx_list_c *base); +#if BX_USE_TEXTCONFIG + // gui console support + virtual int bx_printf(const char *fmt, ...); + virtual char* bx_gets(char *s, int size, FILE *stream); +#endif private: bx_bool save_sr_param(FILE *fp, bx_param_c *node, const char *sr_path, int level); @@ -1571,3 +1576,31 @@ int bx_real_sim_c::write_usb_options(FILE *fp, int maxports, bx_list_c *base) { return bx_write_usb_options(fp, maxports, base); } + +#if BX_USE_TEXTCONFIG +int bx_real_sim_c::bx_printf(const char *fmt, ...) +{ + va_list ap; + char buf[1025]; + + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + if (get_init_done()) { + if (bx_gui->has_gui_console()) { + return bx_gui->bx_printf(buf); + } + } + return printf(buf); +} + +char* bx_real_sim_c::bx_gets(char *s, int size, FILE *stream) +{ + if (get_init_done()) { + if (bx_gui->has_gui_console()) { + return bx_gui->bx_gets(s, size); + } + } + return fgets(s, size, stream); +} +#endif diff --git a/bochs/gui/siminterface.h b/bochs/gui/siminterface.h index 00bdff36b..f15cedd3e 100644 --- a/bochs/gui/siminterface.h +++ b/bochs/gui/siminterface.h @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2001-2016 The Bochs Project +// Copyright (C) 2001-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -826,6 +826,12 @@ public: const char *param, int maxports, bx_list_c *base) {return 0;} virtual int write_param_list(FILE *fp, bx_list_c *base, const char *optname, bx_bool multiline) {return 0;} virtual int write_usb_options(FILE *fp, int maxports, bx_list_c *base) {return 0;} + +#if BX_USE_TEXTCONFIG + // gui console support + virtual int bx_printf(const char *fmt, ...) {return 0;} + virtual char* bx_gets(char *s, int size, FILE *stream) {return NULL;} +#endif }; BOCHSAPI extern bx_simulator_interface_c *SIM; diff --git a/bochs/gui/textconfig.cc b/bochs/gui/textconfig.cc index dd27ad026..cf0e88eda 100644 --- a/bochs/gui/textconfig.cc +++ b/bochs/gui/textconfig.cc @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2002-2016 The Bochs Project +// Copyright (C) 2002-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -55,6 +55,9 @@ extern "C" { #define CI_PATH_LENGTH 512 +#define bx_printf SIM->bx_printf +#define bx_fgets SIM->bx_gets + /* functions for changing particular options */ void bx_config_interface_init(); int bx_read_rc(char *rc); @@ -94,9 +97,9 @@ int ask_uint(const char *prompt, const char *help, Bit32u min, Bit32u max, Bit32 int illegal; assert(base==10 || base==16); while (1) { - printf(prompt, the_default); + bx_printf(prompt, the_default); fflush(stdout); - if (!fgets(buffer, sizeof(buffer), stdin)) + if (!bx_fgets(buffer, sizeof(buffer), stdin)) return -1; clean = clean_string(buffer); if (strlen(clean) < 1) { @@ -105,11 +108,11 @@ int ask_uint(const char *prompt, const char *help, Bit32u min, Bit32u max, Bit32 return 0; } if ((clean[0] == '?') && (strlen(help) > 0)) { - printf("\n%s\n", help); + bx_printf("\n%s\n", help); if (base == 10) { - printf("Your choice must be an integer between %u and %u.\n\n", min, max); + bx_printf("Your choice must be an integer between %u and %u.\n\n", min, max); } else { - printf("Your choice must be an integer between 0x%x and 0x%x.\n\n", min, max); + bx_printf("Your choice must be an integer between 0x%x and 0x%x.\n\n", min, max); } continue; } @@ -117,10 +120,10 @@ int ask_uint(const char *prompt, const char *help, Bit32u min, Bit32u max, Bit32 illegal = (1 != sscanf(buffer, format, &n)); if (illegal || nmax) { if (base == 10) { - printf("Your choice (%s) was not an integer between %u and %u.\n\n", + bx_printf("Your choice (%s) was not an integer between %u and %u.\n\n", clean, min, max); } else { - printf("Your choice (%s) was not an integer between 0x%x and 0x%x.\n\n", + bx_printf("Your choice (%s) was not an integer between 0x%x and 0x%x.\n\n", clean, min, max); } } else { @@ -139,9 +142,9 @@ int ask_int(const char *prompt, const char *help, Bit32s min, Bit32s max, Bit32s char *clean; int illegal; while (1) { - printf(prompt, the_default); + bx_printf(prompt, the_default); fflush(stdout); - if (!fgets(buffer, sizeof(buffer), stdin)) + if (!bx_fgets(buffer, sizeof(buffer), stdin)) return -1; clean = clean_string(buffer); if (strlen(clean) < 1) { @@ -150,13 +153,13 @@ int ask_int(const char *prompt, const char *help, Bit32s min, Bit32s max, Bit32s return 0; } if ((clean[0] == '?') && (strlen(help) > 0)) { - printf("\n%s\n", help); - printf("Your choice must be an integer between %u and %u.\n\n", min, max); + bx_printf("\n%s\n", help); + bx_printf("Your choice must be an integer between %u and %u.\n\n", min, max); continue; } illegal = (1 != sscanf(buffer, "%d", &n)); if (illegal || nmax) { - printf("Your choice (%s) was not an integer between %d and %d.\n\n", + bx_printf("Your choice (%s) was not an integer between %d and %d.\n\n", clean, min, max); } else { // choice is okay @@ -173,9 +176,9 @@ int ask_menu(const char *prompt, const char *help, int n_choices, const char *ch int i; *out = -1; while (1) { - printf(prompt, choice[the_default]); + bx_printf(prompt, choice[the_default]); fflush(stdout); - if (!fgets(buffer, sizeof(buffer), stdin)) + if (!bx_fgets(buffer, sizeof(buffer), stdin)) return -1; clean = clean_string(buffer); if (strlen(clean) < 1) { @@ -191,15 +194,15 @@ int ask_menu(const char *prompt, const char *help, int n_choices, const char *ch } } if (clean[0] != '?') { - printf("Your choice (%s) did not match any of the choices:\n", clean); + bx_printf("Your choice (%s) did not match any of the choices:\n", clean); } else if (strlen(help) > 0) { - printf("\n%s\nValid values are: ", help); + bx_printf("\n%s\nValid values are: ", help); } for (i=0; i0) printf(", "); - printf("%s", choice[i]); + if (i>0) bx_printf(", "); + bx_printf("%s", choice[i]); } - printf("\n"); + bx_printf("\n"); } } @@ -210,9 +213,9 @@ int ask_yn(const char *prompt, const char *help, Bit32u the_default, Bit32u *out *out = 1<<31; while (1) { // if there's a %s field, substitute in the default yes/no. - printf(prompt, the_default ? "yes" : "no"); + bx_printf(prompt, the_default ? "yes" : "no"); fflush(stdout); - if (!fgets(buffer, sizeof(buffer), stdin)) + if (!bx_fgets(buffer, sizeof(buffer), stdin)) return -1; clean = clean_string(buffer); if (strlen(clean) < 1) { @@ -225,11 +228,11 @@ int ask_yn(const char *prompt, const char *help, Bit32u the_default, Bit32u *out case 'n': *out=0; return 0; case '?': if (strlen(help) > 0) { - printf("\n%s\n", help); + bx_printf("\n%s\n", help); } break; } - printf("Please type either yes or no.\n"); + bx_printf("Please type either yes or no.\n"); } } @@ -243,9 +246,9 @@ int ask_string(const char *prompt, const char *the_default, char *out) char *clean; assert(the_default != out); out[0] = 0; - printf(prompt, the_default); + bx_printf(prompt, the_default); fflush(stdout); - if (fgets(buffer, sizeof(buffer), stdin) == NULL) + if (bx_fgets(buffer, sizeof(buffer), stdin) == NULL) return -1; clean = clean_string(buffer); if (clean[0] == '?') @@ -339,10 +342,10 @@ static const char *plugin_ctrl_prompt = "Please choose one: [0] "; #define NOT_IMPLEMENTED(choice) \ - fprintf(stderr, "ERROR: choice %d not implemented\n", choice); + bx_printf("ERROR: choice %d not implemented\n", choice); #define BAD_OPTION(menu,choice) \ - do {fprintf(stderr, "ERROR: menu %d has no choice %d\n", menu, choice); \ + do {bx_printf("ERROR: menu %d has no choice %d\n", menu, choice); \ assert(0); } while (0) void build_runtime_options_prompt(const char *format, char *buf, int size) @@ -372,7 +375,7 @@ int do_menu(const char *pname) bx_list_c *menu = (bx_list_c *)SIM->get_param(pname, NULL); while (1) { menu->set_choice(0); - int status = menu->text_ask(stdin, stderr); + int status = menu->text_ask(); if (status < 0) return status; if (menu->get_choice() < 1) return menu->get_choice(); @@ -382,25 +385,19 @@ int do_menu(const char *pname) assert(chosen != NULL); if (chosen->get_enabled()) { if (SIM->get_init_done() && !chosen->get_runtime_param()) { - fprintf(stderr, "\nWARNING: parameter not available at runtime!\n"); + bx_printf("\nWARNING: parameter not available at runtime!\n"); } else if (chosen->get_type() == BXT_LIST) { char chosen_pname[80]; chosen->get_param_path(chosen_pname, 80); do_menu(chosen_pname); } else { - chosen->text_ask(stdin, stderr); + chosen->text_ask(); } } } } } -void askparam(char *pname) -{ - bx_param_c *param = SIM->get_param(pname); - param->text_ask(stdin, stderr); -} - int bx_config_interface(int menu) { Bit32u choice; @@ -430,7 +427,7 @@ int bx_config_interface(int menu) if (ask_uint(startup_menu_prompt, "", 1, n_choices, default_choice, &choice, 10) < 0) return -1; switch (choice) { case 1: - fprintf(stderr, "I reset all options back to their factory defaults.\n\n"); + bx_printf("I reset all options back to their factory defaults.\n\n"); SIM->reset_all_param(); SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_EDIT_START); break; @@ -509,10 +506,10 @@ int bx_config_interface(int menu) break; case BX_CI_RT_CONT: SIM->update_runtime_options(); - fprintf(stderr, "Continuing simulation\n"); + bx_printf("Continuing simulation\n"); return 0; case BX_CI_RT_QUIT: - fprintf(stderr, "You chose quit on the configuration interface.\n"); + bx_printf("You chose quit on the configuration interface.\n"); bx_user_quit = 1; #if !BX_DEBUGGER bx_atexit(); @@ -521,12 +518,12 @@ int bx_config_interface(int menu) bx_dbg_exit(1); #endif return -1; - default: fprintf(stderr, "Menu choice %d not implemented.\n", choice); + default: bx_printf("Menu choice %d not implemented.\n", choice); } } break; default: - fprintf(stderr, "Unknown config interface menu type.\n"); + bx_printf("Unknown config interface menu type.\n"); assert(menu >=0 && menu < BX_CI_N_MENUS); } } @@ -535,18 +532,18 @@ int bx_config_interface(int menu) static void bx_print_log_action_table() { // just try to print all the prefixes first. - fprintf(stderr, "Current log settings:\n"); - fprintf(stderr, " Debug Info Error Panic\n"); - fprintf(stderr, "ID Device Action Action Action Action\n"); - fprintf(stderr, "---- --------- --------- --------- ---------- ----------\n"); + bx_printf("Current log settings:\n"); + bx_printf(" Debug Info Error Panic\n"); + bx_printf("ID Device Action Action Action Action\n"); + bx_printf("---- --------- --------- --------- ---------- ----------\n"); int i, j, imax=SIM->get_n_log_modules(); for (i=0; iget_prefix(i), BX_NULL_PREFIX)) { - fprintf(stderr, "%3d. %s ", i, SIM->get_prefix(i)); + bx_printf("%3d. %s ", i, SIM->get_prefix(i)); for (j=0; jget_max_log_level(); j++) { - fprintf(stderr, "%10s ", SIM->get_action_name(SIM->get_log_action(i, j))); + bx_printf("%10s ", SIM->get_action_name(SIM->get_log_action(i, j))); } - fprintf(stderr, "\n"); + bx_printf("\n"); } } } @@ -566,7 +563,7 @@ void bx_log_options(int individual) if (ask_int(log_options_prompt1, "", -1, maxid-1, -1, &id) < 0) return; if (id < 0) return; - fprintf(stderr, "Editing log options for the device %s\n", SIM->get_prefix(id)); + bx_printf("Editing log options for the device %s\n", SIM->get_prefix(id)); for (level=0; levelget_max_log_level(); level++) { char prompt[1024]; int default_action = SIM->get_log_action(id, level); @@ -579,7 +576,7 @@ void bx_log_options(int individual) if (!BX_LOG_OPTS_EXCLUDE(level, action)) { SIM->set_log_action(id, level, action); } else { - fprintf(stderr, "Event type '%s' does not support log action '%s'.\n", + bx_printf("Event type '%s' does not support log action '%s'.\n", SIM->get_log_level_name(level), log_level_choices[action]); } } @@ -599,7 +596,7 @@ void bx_log_options(int individual) SIM->set_default_log_action(level, action); SIM->set_log_action(-1, level, action); } else { - fprintf(stderr, "Event type '%s' does not support log action '%s'.\n", + bx_printf("Event type '%s' does not support log action '%s'.\n", SIM->get_log_level_name(level), log_level_choices[action]); } } @@ -618,7 +615,7 @@ int bx_read_rc(char *rc) if (ask_string("\nWhat is the configuration file name?\nTo cancel, type 'none'. [%s] ", oldrc, newrc) < 0) return -1; if (!strcmp(newrc, "none")) return -1; if (SIM->read_rc(newrc) >= 0) return 0; - fprintf(stderr, "The file '%s' could not be found.\n", newrc); + bx_printf("The file '%s' could not be found.\n", newrc); } } @@ -638,7 +635,7 @@ int bx_write_rc(char *rc) // try with overwrite off first int status = SIM->write_rc(newrc, 0); if (status >= 0) { - fprintf(stderr, "Wrote configuration to '%s'.\n", newrc); + bx_printf("Wrote configuration to '%s'.\n", newrc); return 0; } else if (status == -2) { // return code -2 indicates the file already exists, and overwrite @@ -650,10 +647,10 @@ int bx_write_rc(char *rc) if (!overwrite) continue; // if "no", start loop over, asking for a different file // they confirmed, so try again with overwrite bit set if (SIM->write_rc(newrc, 1) >= 0) { - fprintf(stderr, "Overwriting existing configuration '%s'.\n", newrc); + bx_printf("Overwriting existing configuration '%s'.\n", newrc); return 0; } else { - fprintf(stderr, "Write failed to '%s'.\n", newrc); + bx_printf("Write failed to '%s'.\n", newrc); } } } @@ -674,27 +671,27 @@ void bx_plugin_ctrl() plugin_ctrl = (bx_list_c*) SIM->get_param(BXPN_PLUGIN_CTRL); count = plugin_ctrl->get_size(); if (count == 0) { - fprintf(stderr, "\nNo optional plugins loaded\n"); + bx_printf("\nNo optional plugins loaded\n"); } else { - fprintf(stderr, "\nCurrently loaded plugins:"); + bx_printf("\nCurrently loaded plugins:"); for (int i = 0; i < count; i++) { - if (i > 0) fprintf(stderr, ","); - fprintf(stderr, " %s", plugin_ctrl->get(i)->get_name()); + if (i > 0) bx_printf(","); + bx_printf(" %s", plugin_ctrl->get(i)->get_name()); } - fprintf(stderr, "\n"); + bx_printf("\n"); } if (choice == 1) { ask_string("\nEnter the name of the plugin to load.\nTo cancel, type 'none'. [%s] ", "none", plugname); if (strcmp(plugname, "none")) { if (!SIM->opt_plugin_ctrl(plugname, 1)) { - fprintf(stderr, "\nPlugin already loaded.\n"); + bx_printf("\nPlugin already loaded.\n"); } } } else { ask_string("\nEnter the name of the plugin to unload.\nTo cancel, type 'none'. [%s] ", "none", plugname); if (strcmp(plugname, "none")) { if (!SIM->opt_plugin_ctrl(plugname, 0)) { - fprintf(stderr, "\nNo plugin unloaded.\n"); + bx_printf("\nNo plugin unloaded.\n"); } } } @@ -715,7 +712,7 @@ config_interface_notify_callback(void *unused, BxEvent *event) event->retcode = 0; return event; case BX_SYNC_EVT_ASK_PARAM: - event->retcode = event->u.param.param->text_ask(stdin, stderr); + event->retcode = event->u.param.param->text_ask(); return event; case BX_SYNC_EVT_LOG_DLG: if (event->u.logmsg.mode == BX_LOG_DLG_ASK) { @@ -774,97 +771,97 @@ void bx_config_interface_init() ///////////////////////////////////////////////////////////////////// // implement the text_* methods for bx_param types. -void bx_param_num_c::text_print(FILE *fp) +void bx_param_num_c::text_print() { if (get_long_format()) { - fprintf(fp, get_long_format(), get()); + bx_printf(get_long_format(), get()); } else { const char *format = "%s: %d"; assert(base==10 || base==16); if (base==16) format = "%s: 0x%x"; if (get_label()) { - fprintf(fp, format, get_label(), get()); + bx_printf(format, get_label(), get()); } else { - fprintf(fp, format, get_name(), get()); + bx_printf(format, get_name(), get()); } } } -void bx_param_bool_c::text_print(FILE *fp) +void bx_param_bool_c::text_print() { if (get_format()) { - fprintf(fp, get_format(), get() ? "yes" : "no"); + bx_printf(get_format(), get() ? "yes" : "no"); } else { const char *format = "%s: %s"; if (get_label()) { - fprintf(fp, format, get_label(), get() ? "yes" : "no"); + bx_printf(format, get_label(), get() ? "yes" : "no"); } else { - fprintf(fp, format, get_name(), get() ? "yes" : "no"); + bx_printf(format, get_name(), get() ? "yes" : "no"); } } } -void bx_param_enum_c::text_print(FILE *fp) +void bx_param_enum_c::text_print() { int n = get(); assert(n >= min && n <= max); const char *choice = choices[n - min]; if (get_format()) { - fprintf(fp, get_format(), choice); + bx_printf(get_format(), choice); } else { const char *format = "%s: %s"; if (get_label()) { - fprintf(fp, format, get_label(), choice); + bx_printf(format, get_label(), choice); } else { - fprintf(fp, format, get_name(), choice); + bx_printf(format, get_name(), choice); } } } -void bx_param_string_c::text_print(FILE *fp) +void bx_param_string_c::text_print() { char value[1024]; this->sprint(value, 1024, 0); if (get_format()) { - fprintf(fp, get_format(), value); + bx_printf(get_format(), value); } else { if (get_label()) { - fprintf(fp, "%s: %s", get_label(), value); + bx_printf("%s: %s", get_label(), value); } else { - fprintf(fp, "%s: %s", get_name(), value); + bx_printf("%s: %s", get_name(), value); } } } -void bx_list_c::text_print(FILE *fp) +void bx_list_c::text_print() { bx_listitem_t *item; int i = 0; - fprintf(fp, "%s: ", get_name()); + bx_printf("%s: ", get_name()); for (item = list; item; item = item->next) { if (item->param->get_enabled()) { if ((i > 0) && (options & SERIES_ASK)) - fprintf(fp, ", "); - item->param->text_print(fp); + bx_printf(", "); + item->param->text_print(); if (!(options & SERIES_ASK)) - fprintf(fp, "\n"); + bx_printf("\n"); } i++; } } -int bx_param_num_c::text_ask(FILE *fpin, FILE *fpout) +int bx_param_num_c::text_ask() { - fprintf(fpout, "\n"); + bx_printf("\n"); int status; const char *prompt = get_ask_format(); const char *help = get_description(); if (prompt == NULL) { // default prompt, if they didn't set an ask format string - text_print(fpout); - fprintf(fpout, "\n"); + text_print(); + bx_printf("\n"); prompt = "Enter new value or '?' for help: [%d] "; if (base==16) prompt = "Enter new value in hex or '?' for help: [%x] "; @@ -876,9 +873,9 @@ int bx_param_num_c::text_ask(FILE *fpin, FILE *fpout) return 0; } -int bx_param_bool_c::text_ask(FILE *fpin, FILE *fpout) +int bx_param_bool_c::text_ask() { - fprintf(fpout, "\n"); + bx_printf("\n"); int status; const char *prompt = get_ask_format(); const char *help = get_description(); @@ -900,16 +897,16 @@ int bx_param_bool_c::text_ask(FILE *fpin, FILE *fpout) return 0; } -int bx_param_enum_c::text_ask(FILE *fpin, FILE *fpout) +int bx_param_enum_c::text_ask() { - fprintf(fpout, "\n"); + bx_printf("\n"); const char *prompt = get_ask_format(); const char *help = get_description(); if (prompt == NULL) { // default prompt, if they didn't set an ask format string - fprintf(fpout, "%s = ", get_name()); - text_print(fpout); - fprintf(fpout, "\n"); + bx_printf("%s = ", get_name()); + text_print(); + bx_printf("\n"); prompt = "Enter new value or '?' for help: [%s] "; } Bit32s n = (Bit32s)(get() - min); @@ -941,19 +938,19 @@ int parse_raw_bytes(char *dest, char *src, int destsize, char separator) return 0; } -int bx_param_string_c::text_ask(FILE *fpin, FILE *fpout) +int bx_param_string_c::text_ask() { - fprintf(fpout, "\n"); + bx_printf("\n"); int status; const char *prompt = get_ask_format(); if (prompt == NULL) { if (options & SELECT_FOLDER_DLG) { - fprintf(fpout, "%s\n\n", get_label()); + bx_printf("%s\n\n", get_label()); prompt = "Enter a path to an existing folder or press enter to cancel\n"; } else { // default prompt, if they didn't set an ask format string - text_print(fpout); - fprintf(fpout, "\n"); + text_print(); + bx_printf("\n"); prompt = "Enter a new value, '?' for help, or press return for no change.\n"; } } @@ -961,7 +958,7 @@ int bx_param_string_c::text_ask(FILE *fpin, FILE *fpout) char buffer[1024]; status = ask_string(prompt, getptr(), buffer); if (status == -2) { - fprintf(fpout, "\n%s\n", get_description()); + bx_printf("\n%s\n", get_description()); continue; } if (status < 0) return status; @@ -973,7 +970,7 @@ int bx_param_string_c::text_ask(FILE *fpin, FILE *fpout) // copy raw hex into buffer status = parse_raw_bytes(buffer, buffer2, maxsize, separator); if (status < 0) { - fprintf(fpout, "Illegal raw byte format. I expected something like 3A%c03%c12%c...\n", separator, separator, separator); + bx_printf("Illegal raw byte format. I expected something like 3A%c03%c12%c...\n", separator, separator, separator); continue; } } @@ -983,54 +980,54 @@ int bx_param_string_c::text_ask(FILE *fpin, FILE *fpout) } } -int bx_list_c::text_ask(FILE *fpin, FILE *fpout) +int bx_list_c::text_ask() { bx_listitem_t *item; bx_list_c *child; const char *my_title = title; - fprintf(fpout, "\n"); + bx_printf("\n"); int i, imax = strlen(my_title); - for (i=0; inext) { if (item->param->get_enabled()) { if (!SIM->get_init_done() || item->param->get_runtime_param()) { - item->param->text_ask(fpin, fpout); + item->param->text_ask(); } } } } else { if (options & SHOW_PARENT) - fprintf(fpout, "0. Return to previous menu\n"); + bx_printf("0. Return to previous menu\n"); int i = 0; for (item = list; item; item = item->next) { - fprintf(fpout, "%d. ", i+1); + bx_printf("%d. ", i+1); if ((item->param->get_enabled()) && (!SIM->get_init_done() || item->param->get_runtime_param())) { if (item->param->get_type() == BXT_LIST) { child = (bx_list_c*)item->param; - fprintf(fpout, "%s\n", child->get_title()); + bx_printf("%s\n", child->get_title()); } else { if ((options & SHOW_GROUP_NAME) && (item->param->get_group() != NULL)) - fprintf(fpout, "%s ", item->param->get_group()); - item->param->text_print(fpout); - fprintf(fpout, "\n"); + bx_printf("%s ", item->param->get_group()); + item->param->text_print(); + bx_printf("\n"); } } else { if (item->param->get_type() == BXT_LIST) { child = (bx_list_c*)item->param; - fprintf(fpout, "%s (disabled)\n", child->get_title()); + bx_printf("%s (disabled)\n", child->get_title()); } else { - fprintf(fpout, "(disabled)\n"); + bx_printf("(disabled)\n"); } } i++; } - fprintf(fpout, "\n"); + bx_printf("\n"); int min = (options & SHOW_PARENT) ? 0 : 1; int max = size; int status = ask_uint("Please choose one: [%d] ", "", min, max, choice, &choice, 10); @@ -1046,10 +1043,10 @@ static int ci_callback(void *userdata, ci_command_t command) case CI_START: bx_config_interface_init(); if (SIM->get_param_enum(BXPN_BOCHS_START)->get() == BX_QUICK_START) - bx_config_interface(BX_CI_START_SIMULATION); + bx_config_interface(BX_CI_START_SIMULATION); else { if (!SIM->test_for_text_console()) - return CI_ERR_NO_TEXT_CONSOLE; + return CI_ERR_NO_TEXT_CONSOLE; bx_config_interface(BX_CI_START_MENU); } break; diff --git a/bochs/gui/x.cc b/bochs/gui/x.cc index 8f2b3e16f..c51e8b0f2 100644 --- a/bochs/gui/x.cc +++ b/bochs/gui/x.cc @@ -2,7 +2,7 @@ // $Id$ ///////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2001-2016 The Bochs Project +// Copyright (C) 2001-2017 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -63,12 +63,17 @@ public: #endif virtual void beep_on(float frequency); virtual void beep_off(); + virtual void set_display_mode(disp_mode_t newmode); virtual void statusbar_setitem_specific(int element, bx_bool active, bx_bool w); virtual void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp); virtual void set_mouse_mode_absxy(bx_bool mode); #if BX_SHOW_IPS virtual void show_ips(Bit32u ips_count); #endif +private: + void headerbar_click(int x); + void send_mouse_status(void); + void xkeypress(KeySym keysym, int press_release); }; // declare one instance of the gui object and call macro to insert the @@ -170,8 +175,6 @@ static char x11_ips_text[20]; static Bit8u x11_mouse_msg_counter = 0; #endif -static void headerbar_click(int x, int y); -static void send_keyboard_mouse_status(void); static void set_status_text(int element, const char *text, bx_bool active, bx_bool w=0); @@ -301,7 +304,6 @@ Bit32u ascii_to_key_event[0x5f] = { extern Bit8u graphics_snapshot[32 * 1024]; static void create_internal_vga_font(void); -static void xkeypress(KeySym keysym, int press_release); // extern "C" void select_visual(void); #define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3)) @@ -693,6 +695,9 @@ void bx_x_gui_c::specific_init(int argc, char **argv, unsigned headerbar_y) new_gfx_api = 1; dialog_caps |= (BX_GUI_DLG_USER | BX_GUI_DLG_SNAPSHOT | BX_GUI_DLG_CDROM); +#if BX_USE_TEXTCONFIG + console.present = 1; +#endif } void set_status_text(int element, const char *text, bx_bool active, bx_bool w) @@ -836,17 +841,20 @@ void bx_x_gui_c::handle_events(void) y = 0; } - DEV_vga_redraw_area( - (unsigned) expose_event->x, - y, - (unsigned) expose_event->width, - height); - +#if BX_USE_TEXTCONFIG + if (console.running) { + console_refresh(1); + } else +#endif + { + DEV_vga_redraw_area((unsigned) expose_event->x, y, + (unsigned) expose_event->width, height); + } /* Always draw headerbar, even if not touched by expose event. * As a small optimization, only do it on last contigous expose. */ if (expose_event->count == 0) { - show_headerbar(); + show_headerbar(); } break; @@ -865,12 +873,12 @@ void bx_x_gui_c::handle_events(void) BX_DEBUG(("xxx: in headerbar")); if (mouse_update) { BX_DEBUG(("xxx: mouse_update=1")); - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; } prev_x = current_x = -1; prev_y = current_y = -1; - headerbar_click(button_event->x, button_event->y); + headerbar_click(button_event->x); break; } current_x = button_event->x; @@ -880,7 +888,7 @@ void bx_x_gui_c::handle_events(void) switch (button_event->button) { case Button1: mouse_button_state |= 0x01; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; case Button2: @@ -888,13 +896,13 @@ void bx_x_gui_c::handle_events(void) toggle_mouse_enable(); } else { mouse_button_state |= 0x04; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; } break; case Button3: mouse_button_state |= 0x02; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; } @@ -904,7 +912,7 @@ void bx_x_gui_c::handle_events(void) button_event = (XButtonEvent *) &report; if (button_event->y < BX_HEADER_BAR_Y) { if (mouse_update) { - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; } prev_x = current_x = -1; @@ -918,28 +926,28 @@ void bx_x_gui_c::handle_events(void) switch (button_event->button) { case Button1: mouse_button_state &= ~0x01; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; case Button2: mouse_toggle_check(BX_MT_MBUTTON, 0); mouse_button_state &= ~0x04; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; case Button3: mouse_button_state &= ~0x02; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; case Button4: current_z = 1; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; case Button5: current_z = -1; - send_keyboard_mouse_status(); + send_mouse_status(); mouse_update = 0; break; } @@ -1004,7 +1012,7 @@ void bx_x_gui_c::handle_events(void) if (mouse_update) { BX_DEBUG(("handle_events(): send mouse status")); - send_keyboard_mouse_status(); + send_mouse_status(); } #if BX_SHOW_IPS if (x11_ips_update) { @@ -1014,12 +1022,15 @@ void bx_x_gui_c::handle_events(void) #endif } -void send_keyboard_mouse_status(void) +void bx_x_gui_c::send_mouse_status(void) { int dx, dy, dz; BX_DEBUG(("XXX: prev=(%d,%d) curr=(%d,%d)", prev_x, prev_y, current_x, current_y)); +#if BX_USE_TEXTCONFIG + if (console.running) return; +#endif if (x11_mouse_mode_absxy) { if ((current_y >= (int)bx_headerbar_y) && (current_y < (int)(dimension_y + bx_headerbar_y))) { dx = current_x * 0x7fff / dimension_x; @@ -1059,22 +1070,31 @@ void bx_x_gui_c::flush(void) XFlush(bx_x_display); } -void xkeypress(KeySym keysym, int press_release) +void bx_x_gui_c::xkeypress(KeySym keysym, int press_release) { Bit32u key_event; bx_bool mouse_toggle = 0; +#if BX_USE_TEXTCONFIG + if (console.running && !press_release) { + if (((keysym >= XK_space) && (keysym <= XK_asciitilde)) || + (keysym == XK_Return) || (keysym == XK_BackSpace)) { + console_key_enq((Bit8u)(keysym & 0xff)); + } + return; + } +#endif if ((keysym == XK_Control_L) || (keysym == XK_Control_R)) { - mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_CTRL, !press_release); + mouse_toggle = mouse_toggle_check(BX_MT_KEY_CTRL, !press_release); } else if (keysym == XK_Alt_L) { - mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_ALT, !press_release); + mouse_toggle = mouse_toggle_check(BX_MT_KEY_ALT, !press_release); } else if (keysym == XK_F10) { - mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F10, !press_release); + mouse_toggle = mouse_toggle_check(BX_MT_KEY_F10, !press_release); } else if (keysym == XK_F12) { mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F12, !press_release); } if (mouse_toggle) { - bx_gui->toggle_mouse_enable(); + toggle_mouse_enable(); return; } @@ -1738,6 +1758,7 @@ void bx_x_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsi BX_PANIC(("%d bpp graphics mode not supported", bpp)); } guest_textmode = (fheight > 0); + guest_fsize = (fheight << 4) | fwidth; guest_xres = x; guest_yres = y; if (guest_textmode) { @@ -1868,18 +1889,20 @@ void bx_x_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id) xorigin, 0, 1); } -void headerbar_click(int x, int y) +void bx_x_gui_c::headerbar_click(int x) { int xorigin; - // assuming y is in bounds - UNUSED(y); for (unsigned i=0; i=xorigin) && (x<(xorigin+int(bx_headerbar_entry[i].xdim)))) { +#if BX_USE_TEXTCONFIG + if (console.running && (i != power_hbar_id)) + return; +#endif bx_headerbar_entry[i].f(); return; } @@ -2123,6 +2146,19 @@ void bx_x_gui_c::show_ips(Bit32u ips_count) } #endif +void bx_x_gui_c::set_display_mode(disp_mode_t newmode) +{ + // if no mode change, do nothing. + if (disp_mode == newmode) return; + // remember the display mode for next time + disp_mode = newmode; +#if BX_USE_TEXTCONFIG + if ((newmode == DISP_MODE_SIM) && console.running) { + console_cleanup(); + } +#endif +} + // X11 control class enum {