diff options
author | Miodrag Milanović <mmicko@gmail.com> | 2015-02-21 06:43:19 +0100 |
---|---|---|
committer | Miodrag Milanović <mmicko@gmail.com> | 2015-02-21 06:43:19 +0100 |
commit | fe91dfe9f127cb4bcbc36d1056951dda3efecc39 (patch) | |
tree | ae8650bc88fd58bd4b370ea7ee5164930228ecaf | |
parent | 75aaa54c2b7e98918be78871c872fa4ef15028c3 (diff) | |
parent | 2edbf5565ee8dba382b71b0696c5f7d8db5e569b (diff) |
Merge pull request #139 from cuavas/master
Debugger love: Windows edition
37 files changed, 3983 insertions, 3020 deletions
diff --git a/src/emu/debug/dvbpoints.c b/src/emu/debug/dvbpoints.c index 9b48bc96787..5619adff0bd 100644 --- a/src/emu/debug/dvbpoints.c +++ b/src/emu/debug/dvbpoints.c @@ -73,26 +73,6 @@ void debug_view_breakpoints::enumerate_sources() //------------------------------------------------- -// view_notify - handle notification of updates -// to cursor changes -//------------------------------------------------- - -void debug_view_breakpoints::view_notify(debug_view_notification type) -{ -} - - -//------------------------------------------------- -// view_char - handle a character typed within -// the current view -//------------------------------------------------- - -void debug_view_breakpoints::view_char(int chval) -{ -} - - -//------------------------------------------------- // view_click - handle a mouse click within the // current view //------------------------------------------------- @@ -134,7 +114,7 @@ void debug_view_breakpoints::view_click(const int button, const debug_view_xy& p device_debug::breakpoint** bpList = NULL; const int numBPs = breakpoints(SORT_NONE, bpList); - const int bpIndex = pos.y-1; + const int bpIndex = pos.y - 1; if (bpIndex > numBPs || bpIndex < 0) return; @@ -147,7 +127,9 @@ void debug_view_breakpoints::view_click(const int button, const debug_view_xy& p delete[] bpList; } - view_update(); + begin_update(); + m_update_pending = true; + end_update(); } @@ -331,7 +313,7 @@ int debug_view_breakpoints::breakpoints(SortMode sort, device_debug::breakpoint* //------------------------------------------------- // view_update - update the contents of the -// disassembly view +// breakpoints view //------------------------------------------------- void debug_view_breakpoints::view_update() diff --git a/src/emu/debug/dvbpoints.h b/src/emu/debug/dvbpoints.h index 38cd30de800..bb80b840ebb 100644 --- a/src/emu/debug/dvbpoints.h +++ b/src/emu/debug/dvbpoints.h @@ -58,14 +58,11 @@ public: protected: // view overrides virtual void view_update(); - virtual void view_notify(debug_view_notification type); - virtual void view_char(int chval); virtual void view_click(const int button, const debug_view_xy& pos); private: // internal helpers void enumerate_sources(); - bool recompute(offs_t pc, int startline, int lines); void pad_astring_to_length(astring& str, int len); int breakpoints(SortMode sort, device_debug::breakpoint**& bpList); diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h index f6811c5d7e1..69db37b3102 100644 --- a/src/emu/debug/dvmemory.h +++ b/src/emu/debug/dvmemory.h @@ -54,7 +54,7 @@ public: // getters const char *expression() { return m_expression.string(); } UINT8 bytes_per_chunk() { flush_updates(); return m_bytes_per_chunk; } - UINT8 chunks_per_row() { flush_updates(); return m_chunks_per_row; } + UINT32 chunks_per_row() { flush_updates(); return m_chunks_per_row; } bool reverse() const { return m_reverse_view; } bool ascii() const { return m_ascii_view; } bool physical() const { return m_no_translation; } diff --git a/src/emu/debug/dvwpoints.c b/src/emu/debug/dvwpoints.c index e9ff9a8754d..b7054b4e4bb 100644 --- a/src/emu/debug/dvwpoints.c +++ b/src/emu/debug/dvwpoints.c @@ -72,26 +72,6 @@ void debug_view_watchpoints::enumerate_sources() //------------------------------------------------- -// view_notify - handle notification of updates -// to cursor changes -//------------------------------------------------- - -void debug_view_watchpoints::view_notify(debug_view_notification type) -{ -} - - -//------------------------------------------------- -// view_char - handle a character typed within -// the current view -//------------------------------------------------- - -void debug_view_watchpoints::view_char(int chval) -{ -} - - -//------------------------------------------------- // view_click - handle a mouse click within the // current view //------------------------------------------------- @@ -141,7 +121,7 @@ void debug_view_watchpoints::view_click(const int button, const debug_view_xy& p device_debug::watchpoint** wpList = NULL; const int numWPs = watchpoints(SORT_NONE, wpList); - const int wpIndex = pos.y-1; + const int wpIndex = pos.y - 1; if (wpIndex > numWPs || wpIndex < 0) return; @@ -154,7 +134,9 @@ void debug_view_watchpoints::view_click(const int button, const debug_view_xy& p delete[] wpList; } - view_update(); + begin_update(); + m_update_pending = true; + end_update(); } @@ -387,7 +369,7 @@ int debug_view_watchpoints::watchpoints(SortMode sort, device_debug::watchpoint* //------------------------------------------------- // view_update - update the contents of the -// disassembly view +// watchpoints view //------------------------------------------------- void debug_view_watchpoints::view_update() diff --git a/src/emu/debug/dvwpoints.h b/src/emu/debug/dvwpoints.h index 7c35e9278b6..6414b3b0424 100644 --- a/src/emu/debug/dvwpoints.h +++ b/src/emu/debug/dvwpoints.h @@ -62,14 +62,11 @@ public: protected: // view overrides virtual void view_update(); - virtual void view_notify(debug_view_notification type); - virtual void view_char(int chval); virtual void view_click(const int button, const debug_view_xy& pos); private: // internal helpers void enumerate_sources(); - bool recompute(offs_t pc, int startline, int lines); void pad_astring_to_length(astring& str, int len); int watchpoints(SortMode sort, device_debug::watchpoint**& bpList); diff --git a/src/osd/modules/debugger/debugwin.c b/src/osd/modules/debugger/debugwin.c index 658731bc09c..448f35b122c 100644 --- a/src/osd/modules/debugger/debugwin.c +++ b/src/osd/modules/debugger/debugwin.c @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb //============================================================ // // debugwin.c - Win32 debug window handling @@ -11,3090 +11,257 @@ #if defined(OSD_WINDOWS) /*|| defined(SDLMAME_WIN32)*/ -// standard windows headers -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <windowsx.h> -#include <tchar.h> -#include <commdlg.h> -#ifdef _MSC_VER -#include <zmouse.h> -#endif +#include "win/debugwin.h" + +#include "win/consolewininfo.h" +#include "win/debugwininfo.h" +#include "win/disasmwininfo.h" +#include "win/logwininfo.h" +#include "win/memorywininfo.h" +#include "win/pointswininfo.h" +#include "win/uimetrics.h" -// MAME headers #include "emu.h" #include "uiinput.h" -#include "imagedev/cassette.h" #include "debugger.h" -#include "debug/debugvw.h" -#include "debug/dvdisasm.h" -#include "debug/dvmemory.h" -#include "debug/dvstate.h" -#include "debug/debugvw.h" -#include "debug/debugcon.h" -#include "debug/debugcpu.h" -// MAMEOS headers -#include "winmain.h" #include "window.h" +#include "winmain.h" #include "../../windows/input.h" -#include "strconv.h" -#include "winutf8.h" -class debugger_windows : public osd_module, public debug_module + +class debugger_windows : public osd_module, public debug_module, protected debugger_windows_interface { public: - debugger_windows() - : osd_module(OSD_DEBUG_PROVIDER, "windows"), debug_module(), - m_machine(NULL) + debugger_windows() : + osd_module(OSD_DEBUG_PROVIDER, "windows"), + debug_module(), + m_machine(NULL), + m_metrics(), + m_waiting_for_debugger(false), + m_window_list(), + m_main_console(NULL) { } virtual ~debugger_windows() { } - virtual int init() { return 0;} + virtual int init() { return 0; } virtual void exit(); virtual void init_debugger(running_machine &machine); virtual void wait_for_debugger(device_t &device, bool firststop); virtual void debugger_update(); -private: - running_machine *m_machine; -}; -//============================================================ -// PARAMETERS -//============================================================ - -#define MAX_VIEWS 4 -#define EDGE_WIDTH 3 -#define MAX_EDIT_STRING 256 -#define HISTORY_LENGTH 20 -#define MAX_OTHER_WND 4 - -// debugger window styles -#define DEBUG_WINDOW_STYLE (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN) & (~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX) -#define DEBUG_WINDOW_STYLE_EX 0 - -// debugger view styles -#define DEBUG_VIEW_STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN -#define DEBUG_VIEW_STYLE_EX 0 +protected: + virtual running_machine &machine() const { return *m_machine; } -// edit box styles -#define EDIT_BOX_STYLE WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL -#define EDIT_BOX_STYLE_EX 0 + virtual ui_metrics &metrics() const { return *m_metrics; } -// combo box styles -#define COMBO_BOX_STYLE WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL -#define COMBO_BOX_STYLE_EX 0 + virtual bool const &waiting_for_debugger() const { return m_waiting_for_debugger; } + virtual bool seq_pressed() const; -// horizontal scroll bar styles -#define HSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_HORZ -#define HSCROLL_STYLE_EX 0 + virtual void create_memory_window() { create_window<memorywin_info>(); } + virtual void create_disasm_window() { create_window<disasmwin_info>(); } + virtual void create_log_window() { create_window<logwin_info>(); } + virtual void create_points_window() { create_window<pointswin_info>(); } + virtual void remove_window(debugwin_info &info); -// vertical scroll bar styles -#define VSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_VERT -#define VSCROLL_STYLE_EX 0 - - -enum -{ - ID_NEW_MEMORY_WND = 1, - ID_NEW_DISASM_WND, - ID_NEW_LOG_WND, - ID_RUN, - ID_RUN_AND_HIDE, - ID_RUN_VBLANK, - ID_RUN_IRQ, - ID_NEXT_CPU, - ID_STEP, - ID_STEP_OVER, - ID_STEP_OUT, - ID_HARD_RESET, - ID_SOFT_RESET, - ID_EXIT, - - ID_1_BYTE_CHUNKS, - ID_2_BYTE_CHUNKS, - ID_4_BYTE_CHUNKS, - ID_8_BYTE_CHUNKS, - ID_LOGICAL_ADDRESSES, - ID_PHYSICAL_ADDRESSES, - ID_REVERSE_VIEW, - ID_INCREASE_MEM_WIDTH, - ID_DECREASE_MEM_WIDTH, - - ID_SHOW_RAW, - ID_SHOW_ENCRYPTED, - ID_SHOW_COMMENTS, - ID_RUN_TO_CURSOR, - ID_TOGGLE_BREAKPOINT, - - ID_DEVICE_OPTIONS // keep this always at the end -}; - - - -//============================================================ -// TYPES -//============================================================ - -struct debugview_info; -class debugwin_info; + virtual void show_all(); + virtual void hide_all(); +private: + template <typename T> T *create_window(); -struct debugview_info -{ - debugwin_info * owner; - debug_view * view; - HWND wnd; - HWND hscroll; - HWND vscroll; + running_machine *m_machine; + auto_pointer<ui_metrics> m_metrics; + bool m_waiting_for_debugger; + simple_list<debugwin_info> m_window_list; + consolewin_info *m_main_console; }; -class debugwin_info +void debugger_windows::exit() { -public: - debugwin_info(running_machine &machine) - : m_machine(machine) { } - - running_machine &machine() const { return m_machine; } - - debugwin_info * next; - HWND wnd; - HWND focuswnd; - WNDPROC handler; - - UINT32 minwidth, maxwidth; - UINT32 minheight, maxheight; - void (*recompute_children)(debugwin_info *); - void (*update_menu)(debugwin_info *); - - int (*handle_command)(debugwin_info *, WPARAM, LPARAM); - int (*handle_key)(debugwin_info *, WPARAM, LPARAM); - UINT16 ignore_char_lparam; - - debugview_info view[MAX_VIEWS]; - - HWND editwnd; - char edit_defstr[256]; - void (*process_string)(debugwin_info *, const char *); - WNDPROC original_editproc; - TCHAR history[HISTORY_LENGTH][MAX_EDIT_STRING]; - int history_count; - int last_history; - - HWND otherwnd[MAX_OTHER_WND]; - -private: - running_machine & m_machine; -}; - - -//============================================================ -// LOCAL VARIABLES -//============================================================ - -static debugwin_info *window_list = NULL; -static debugwin_info *main_console; -static UINT32 main_console_regwidth; - -static UINT8 waiting_for_debugger; - -static HFONT debug_font; -static UINT32 debug_font_height; -static UINT32 debug_font_width; -static UINT32 debug_font_ascent; - -static UINT32 hscroll_height; -static UINT32 vscroll_width; - - - -//============================================================ -// PROTOTYPES -//============================================================ - -static debugwin_info *debugwin_window_create(running_machine &machine, LPCSTR title, WNDPROC handler); -static void debugwin_window_free(debugwin_info *info); -static LRESULT CALLBACK debugwin_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); - -static void debugwin_view_draw_contents(debugview_info *view, HDC dc); -static LRESULT CALLBACK debugwin_view_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); -static void debugwin_view_update(debug_view &view, void *osdprivate); -static int debugwin_view_create(debugwin_info *info, int which, debug_view_type type); - -static LRESULT CALLBACK debugwin_edit_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); - -//static void generic_create_window(int type); -static void generic_recompute_children(debugwin_info *info); - -static void memory_create_window(running_machine &machine); -static void memory_recompute_children(debugwin_info *info); -static void memory_process_string(debugwin_info *info, const char *string); -static void memory_update_menu(debugwin_info *info); -static int memory_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static int memory_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static void memory_update_caption(running_machine &machine, HWND wnd); - -static void disasm_create_window(running_machine &machine); -static void disasm_recompute_children(debugwin_info *info); -static void disasm_process_string(debugwin_info *info, const char *string); -static void disasm_update_menu(debugwin_info *info); -static int disasm_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static int disasm_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static void disasm_update_caption(running_machine &machine, HWND wnd); + // loop over windows and free them + while (m_window_list.first() != NULL) + m_window_list.first()->destroy(); -static void console_create_window(running_machine &machine); -static void console_recompute_children(debugwin_info *info); -static void console_process_string(debugwin_info *info, const char *string); -static void console_set_cpu(device_t *device); + m_main_console = NULL; + m_metrics.reset(); + m_machine = NULL; +} -static HMENU create_standard_menubar(void); -static int global_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static int global_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam); -static void smart_set_window_bounds(HWND wnd, HWND parent, RECT *bounds); -static void smart_show_window(HWND wnd, BOOL show); -static void smart_show_all(BOOL show); -static void image_update_menu(debugwin_info *info); +void debugger_windows::init_debugger(running_machine &machine) +{ + m_machine = &machine; + m_metrics.reset(global_alloc(ui_metrics(downcast<windows_options &>(m_machine->options())))); +} -//============================================================ -// wait_for_debugger -//============================================================ - void debugger_windows::wait_for_debugger(device_t &device, bool firststop) { - MSG message; - // create a console window - if (main_console == NULL) - console_create_window(*m_machine); + if (m_main_console == NULL) + m_main_console = create_window<consolewin_info>(); // update the views in the console to reflect the current CPU - if (main_console != NULL) - console_set_cpu(&device); + if (m_main_console != NULL) + m_main_console->set_cpu(device); // when we are first stopped, adjust focus to us - if (firststop && main_console != NULL) + if (firststop && (m_main_console != NULL)) { - SetForegroundWindow(main_console->wnd); + m_main_console->set_foreground(); if (winwindow_has_focus()) - SetFocus(main_console->editwnd); + m_main_console->set_default_focus(); } // make sure the debug windows are visible - waiting_for_debugger = TRUE; - smart_show_all(TRUE); + m_waiting_for_debugger = true; + show_all(); // run input polling to ensure that our status is in sync wininput_poll(*m_machine); // get and process messages + MSG message; GetMessage(&message, NULL, 0, 0); switch (message.message) { - // check for F10 -- we need to capture that ourselves - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - if (message.wParam == VK_F4 && message.message == WM_SYSKEYDOWN) - SendMessage(GetAncestor(GetFocus(), GA_ROOT), WM_CLOSE, 0, 0); - if (message.wParam == VK_F10) - SendMessage(GetAncestor(GetFocus(), GA_ROOT), (message.message == WM_SYSKEYDOWN) ? WM_KEYDOWN : WM_KEYUP, message.wParam, message.lParam); - break; + // check for F10 -- we need to capture that ourselves + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + if (message.wParam == VK_F4 && message.message == WM_SYSKEYDOWN) + SendMessage(GetAncestor(GetFocus(), GA_ROOT), WM_CLOSE, 0, 0); + if (message.wParam == VK_F10) + SendMessage(GetAncestor(GetFocus(), GA_ROOT), (message.message == WM_SYSKEYDOWN) ? WM_KEYDOWN : WM_KEYUP, message.wParam, message.lParam); + break; - // process everything else - default: - winwindow_dispatch_message(*m_machine, &message); - break; + // process everything else + default: + winwindow_dispatch_message(*m_machine, &message); + break; } // mark the debugger as active - waiting_for_debugger = FALSE; + m_waiting_for_debugger = false; } - -//============================================================ -// debugwin_seq_pressed -//============================================================ - -static int debugwin_seq_pressed(running_machine &machine) -{ - const input_seq &seq = machine.ioport().type_seq(IPT_UI_DEBUG_BREAK); - int result = FALSE; - int invert = FALSE; - int first = TRUE; - int codenum; - - // iterate over all of the codes - int length = seq.length(); - for (codenum = 0; codenum < length; codenum++) - { - input_code code = seq[codenum]; - - // handle NOT - if (code == input_seq::not_code) - invert = TRUE; - - // handle OR and END - else if (code == input_seq::or_code || code == input_seq::end_code) - { - // if we have a positive result from the previous set, we're done - if (result || code == input_seq::end_code) - break; - - // otherwise, reset our state - result = FALSE; - invert = FALSE; - first = TRUE; - } - - // handle everything else as a series of ANDs - else - { - int vkey = wininput_vkey_for_mame_code(code); - int pressed = (vkey != 0 && (GetAsyncKeyState(vkey) & 0x8000) != 0); - - // if this is the first in the sequence, result is set equal - if (first) - result = pressed ^ invert; - - // further values are ANDed - else if (result) - result &= pressed ^ invert; - - // no longer first, and clear the invert flag - first = invert = FALSE; - } - } - - // return the result if we queried at least one switch - return result; -} - - - -//============================================================ -// debugwin_init_windows -//============================================================ - -void debugger_windows::init_debugger(running_machine &machine) -{ - static int class_registered; - - m_machine = &machine; - // register the window classes - if (!class_registered) - { - WNDCLASS wc = { 0 }; - - // initialize the description of the window class - wc.lpszClassName = TEXT("MAMEDebugWindow"); - wc.hInstance = GetModuleHandle(NULL); - wc.lpfnWndProc = debugwin_window_proc; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(2)); - wc.lpszMenuName = NULL; - wc.hbrBackground = NULL; - wc.style = 0; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - // register the class; fail if we can't - if (!RegisterClass(&wc)) - fatalerror("Unable to register debug window class\n"); - - // initialize the description of the view class - wc.lpszClassName = TEXT("MAMEDebugView"); - wc.lpfnWndProc = debugwin_view_proc; - - // register the class; fail if we can't - if (!RegisterClass(&wc)) - fatalerror("Unable to register debug view class\n"); - - class_registered = TRUE; - } - - // create the font - if (debug_font == NULL) - { - // create a temporary DC - HDC temp_dc = GetDC(NULL); - TEXTMETRIC metrics; - HGDIOBJ old_font; - - if (temp_dc != NULL) - { - windows_options &options = downcast<windows_options &>(m_machine->options()); - int size = options.debugger_font_size(); - TCHAR *t_face; - - // create a standard font - t_face = tstring_from_utf8(options.debugger_font()); - debug_font = CreateFont(-MulDiv(size, GetDeviceCaps(temp_dc, LOGPIXELSY), 72), 0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE, - ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, t_face); - osd_free(t_face); - t_face = NULL; - - if (debug_font == NULL) - fatalerror("Unable to create debugger font\n"); - - // get the metrics - old_font = SelectObject(temp_dc, debug_font); - if (GetTextMetrics(temp_dc, &metrics)) - { - debug_font_width = metrics.tmAveCharWidth; - debug_font_height = metrics.tmHeight; - debug_font_ascent = metrics.tmAscent + metrics.tmExternalLeading; - } - SelectObject(temp_dc, old_font); - ReleaseDC(NULL, temp_dc); - } - } - - // get other metrics - hscroll_height = GetSystemMetrics(SM_CYHSCROLL); - vscroll_width = GetSystemMetrics(SM_CXVSCROLL); -} - - - -//============================================================ -// debugwin_destroy_windows -//============================================================ - -void debugger_windows::exit() -{ - // loop over windows and free them - while (window_list != NULL) - { - // clear the view list because they will be freed by the core - memset(window_list->view, 0, sizeof(window_list->view)); - DestroyWindow(window_list->wnd); - } - - main_console = NULL; -} - - - -//============================================================ -// debugger_update -//============================================================ - void debugger_windows::debugger_update() { // if we're running live, do some checks - if (!winwindow_has_focus() && !debug_cpu_is_stopped(*m_machine) && m_machine->phase() == MACHINE_PHASE_RUNNING) + if (!winwindow_has_focus() && !debug_cpu_is_stopped(*m_machine) && (m_machine->phase() == MACHINE_PHASE_RUNNING)) { // see if the interrupt key is pressed and break if it is - if (debugwin_seq_pressed(*m_machine)) + if (seq_pressed()) { - HWND focuswnd = GetFocus(); - debugwin_info *info; + HWND const focuswnd = GetFocus(); debug_cpu_get_visible_cpu(*m_machine)->debug()->halt_on_next_instruction("User-initiated break\n"); // if we were focused on some window's edit box, reset it to default - for (info = window_list; info != NULL; info = info->next) - if (focuswnd == info->editwnd) - { - SendMessage(focuswnd, WM_SETTEXT, (WPARAM)0, (LPARAM)info->edit_defstr); - SendMessage(focuswnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - } - } - } -} - - - -//============================================================ -// debugwin_window_create -//============================================================ - -static debugwin_info *debugwin_window_create(running_machine &machine, LPCSTR title, WNDPROC handler) -{ - debugwin_info *info = NULL; - RECT work_bounds; - - // allocate memory - info = global_alloc_clear(debugwin_info(machine)); - - // create the window - info->handler = handler; - info->wnd = win_create_window_ex_utf8(DEBUG_WINDOW_STYLE_EX, "MAMEDebugWindow", title, DEBUG_WINDOW_STYLE, - 0, 0, 100, 100, win_window_list->m_hwnd, create_standard_menubar(), GetModuleHandle(NULL), info); - if (info->wnd == NULL) - goto cleanup; - - // fill in some defaults - SystemParametersInfo(SPI_GETWORKAREA, 0, &work_bounds, 0); - info->minwidth = 200; - info->minheight = 200; - info->maxwidth = work_bounds.right - work_bounds.left; - info->maxheight = work_bounds.bottom - work_bounds.top; - - // set the default handlers - info->handle_command = global_handle_command; - info->handle_key = global_handle_key; - strcpy(info->edit_defstr, ""); - - // hook us in - info->next = window_list; - window_list = info; - - return info; - -cleanup: - if (info->wnd != NULL) - DestroyWindow(info->wnd); - global_free(info); - return NULL; -} - - - -//============================================================ -// debugwin_window_free -//============================================================ - -static void debugwin_window_free(debugwin_info *info) -{ - debugwin_info **scanptr; - int viewnum; - - // first unlink us from the list - for (scanptr = &window_list; *scanptr != NULL; scanptr = &(*scanptr)->next) - if (*scanptr == info) - { - *scanptr = info->next; - break; + for (debugwin_info *info = m_window_list.first(); info != NULL; info = info->next()) + info->restore_field(focuswnd); } - - // free any views - for (viewnum = 0; viewnum < ARRAY_LENGTH(info->view); viewnum++) - if (info->view[viewnum].view != NULL) - { - info->machine().debug_view().free_view(*info->view[viewnum].view); - info->view[viewnum].view = NULL; - } - - // free our memory - global_free(info); -} - - - -//============================================================ -// debugwin_window_draw_contents -//============================================================ - -static void debugwin_window_draw_contents(debugwin_info *info, HDC dc) -{ - RECT bounds, parent; - int curview, curwnd; - - // fill the background with light gray - GetClientRect(info->wnd, &parent); - FillRect(dc, &parent, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); - - // get the parent bounds in screen coords - ClientToScreen(info->wnd, &((POINT *)&parent)[0]); - ClientToScreen(info->wnd, &((POINT *)&parent)[1]); - - // draw edges around all views - for (curview = 0; curview < MAX_VIEWS; curview++) - if (info->view[curview].wnd) - { - GetWindowRect(info->view[curview].wnd, &bounds); - bounds.top -= parent.top; - bounds.bottom -= parent.top; - bounds.left -= parent.left; - bounds.right -= parent.left; - InflateRect(&bounds, EDGE_WIDTH, EDGE_WIDTH); - DrawEdge(dc, &bounds, EDGE_SUNKEN, BF_RECT); - } - - // draw edges around all children - if (info->editwnd) - { - GetWindowRect(info->editwnd, &bounds); - bounds.top -= parent.top; - bounds.bottom -= parent.top; - bounds.left -= parent.left; - bounds.right -= parent.left; - InflateRect(&bounds, EDGE_WIDTH, EDGE_WIDTH); - DrawEdge(dc, &bounds, EDGE_SUNKEN, BF_RECT); } - - for (curwnd = 0; curwnd < MAX_OTHER_WND; curwnd++) - if (info->otherwnd[curwnd]) - { - GetWindowRect(info->otherwnd[curwnd], &bounds); - bounds.top -= parent.top; - bounds.bottom -= parent.top; - bounds.left -= parent.left; - bounds.right -= parent.left; - InflateRect(&bounds, EDGE_WIDTH, EDGE_WIDTH); - DrawEdge(dc, &bounds, EDGE_SUNKEN, BF_RECT); - } } - -//============================================================ -// debugwin_window_proc -//============================================================ - -static LRESULT CALLBACK debugwin_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +bool debugger_windows::seq_pressed() const { - debugwin_info *info = (debugwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); - - // handle a few messages - switch (message) - { - // set the info pointer - case WM_CREATE: - { - CREATESTRUCT *createinfo = (CREATESTRUCT *)lparam; - info = (debugwin_info *)createinfo->lpCreateParams; - SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams); - if (info->handler) - SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)info->handler); - break; - } - - // paint: draw bezels as necessary - case WM_PAINT: - { - PAINTSTRUCT pstruct; - HDC dc = BeginPaint(wnd, &pstruct); - debugwin_window_draw_contents(info, dc); - EndPaint(wnd, &pstruct); - break; - } - - // keydown: handle debugger keys - case WM_KEYDOWN: - if ((*info->handle_key)(info, wparam, lparam)) - info->ignore_char_lparam = lparam >> 16; - break; - - // char: ignore chars associated with keys we've handled - case WM_CHAR: - if (info->ignore_char_lparam == (lparam >> 16)) - info->ignore_char_lparam = 0; - else if (waiting_for_debugger || !debugwin_seq_pressed(info->machine())) - return DefWindowProc(wnd, message, wparam, lparam); - break; - - // activate: set the focus - case WM_ACTIVATE: - if (wparam != WA_INACTIVE && info->focuswnd != NULL) - SetFocus(info->focuswnd); - break; - - // get min/max info: set the minimum window size - case WM_GETMINMAXINFO: - { - MINMAXINFO *minmax = (MINMAXINFO *)lparam; - if (info) - { - minmax->ptMinTrackSize.x = info->minwidth; - minmax->ptMinTrackSize.y = info->minheight; - minmax->ptMaxSize.x = minmax->ptMaxTrackSize.x = info->maxwidth; - minmax->ptMaxSize.y = minmax->ptMaxTrackSize.y = info->maxheight; - } - break; - } - - // sizing: recompute child window locations - case WM_SIZE: - case WM_SIZING: - if (info->recompute_children != NULL) - (*info->recompute_children)(info); - InvalidateRect(wnd, NULL, FALSE); - break; - - // mouse wheel: forward to the first view - case WM_MOUSEWHEEL: - { - static int units_carryover = 0; - - UINT lines_per_click; - if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines_per_click, 0)) - lines_per_click = 3; - - int units = GET_WHEEL_DELTA_WPARAM(wparam) + units_carryover; - int clicks = units / WHEEL_DELTA; - units_carryover = units % WHEEL_DELTA; - - int delta = clicks * lines_per_click; - int viewnum = 0; - POINT point; - HWND child; - - // figure out which view we are hovering over - GetCursorPos(&point); - ScreenToClient(info->wnd, &point); - child = ChildWindowFromPoint(info->wnd, point); - if (child) - { - for (viewnum = 0; viewnum < MAX_VIEWS; viewnum++) - if (info->view[viewnum].wnd == child) - break; - if (viewnum == MAX_VIEWS) - break; - } - - // send the appropriate message to this view's scrollbar - if (info->view[viewnum].wnd && info->view[viewnum].vscroll) - { - int message_type = SB_LINEUP; - if (delta < 0) - { - message_type = SB_LINEDOWN; - delta = -delta; - } - while (delta > 0) - { - SendMessage(info->view[viewnum].wnd, WM_VSCROLL, message_type, (LPARAM)info->view[viewnum].vscroll); - delta--; - } - } - break; - } - - // activate: set the focus - case WM_INITMENU: - if (info->update_menu != NULL) - (*info->update_menu)(info); - break; - - // command: handle a comment - case WM_COMMAND: - if (!(*info->handle_command)(info, wparam, lparam)) - return DefWindowProc(wnd, message, wparam, lparam); - break; + input_seq const &seq = m_machine->ioport().type_seq(IPT_UI_DEBUG_BREAK); + bool result = false; + bool invert = false; + bool first = true; - // close: close the window if it's not the main console - case WM_CLOSE: - if (main_console && main_console->wnd == wnd) - { - smart_show_all(FALSE); - debug_cpu_get_visible_cpu(info->machine())->debug()->go(); - } - else - DestroyWindow(wnd); - break; - - // destroy: close down the window - case WM_NCDESTROY: - debugwin_window_free(info); - break; - - // everything else: defaults - default: - return DefWindowProc(wnd, message, wparam, lparam); - } - - return 0; -} - - - -//============================================================ -// debugwin_view_create -//============================================================ - -static int debugwin_view_create(debugwin_info *info, int which, debug_view_type type) -{ - debugview_info *view = &info->view[which]; - - // set the owner - view->owner = info; - - // create the child view - view->wnd = CreateWindowEx(DEBUG_VIEW_STYLE_EX, TEXT("MAMEDebugView"), NULL, DEBUG_VIEW_STYLE, - 0, 0, 100, 100, info->wnd, NULL, GetModuleHandle(NULL), view); - if (view->wnd == NULL) - goto cleanup; - - // create the scroll bars - view->hscroll = CreateWindowEx(HSCROLL_STYLE_EX, TEXT("SCROLLBAR"), NULL, HSCROLL_STYLE, - 0, 0, 100, CW_USEDEFAULT, view->wnd, NULL, GetModuleHandle(NULL), view); - view->vscroll = CreateWindowEx(VSCROLL_STYLE_EX, TEXT("SCROLLBAR"), NULL, VSCROLL_STYLE, - 0, 0, CW_USEDEFAULT, 100, view->wnd, NULL, GetModuleHandle(NULL), view); - if (view->hscroll == NULL || view->vscroll == NULL) - goto cleanup; - - // create the debug view - view->view = info->machine().debug_view().alloc_view(type, debugwin_view_update, view); - if (view->view == NULL) - goto cleanup; - - return 1; - -cleanup: - if (view->view) - info->machine().debug_view().free_view(*view->view); - if (view->hscroll) - DestroyWindow(view->hscroll); - if (view->vscroll) - DestroyWindow(view->vscroll); - if (view->wnd) - DestroyWindow(view->wnd); - return 0; -} - - - -//============================================================ -// debugwin_view_set_bounds -//============================================================ - -static void debugwin_view_set_bounds(debugview_info *info, HWND parent, const RECT *newbounds) -{ - RECT bounds = *newbounds; - - // account for the edges and set the bounds - if (info->wnd) - smart_set_window_bounds(info->wnd, parent, &bounds); - - // update - debugwin_view_update(*info->view, info); -} - - - -//============================================================ -// debugwin_view_draw_contents -//============================================================ - -static void debugwin_view_draw_contents(debugview_info *view, HDC windc) -{ - const debug_view_char *viewdata = view->view->viewdata(); - debug_view_xy visarea = view->view->visible_size(); - HGDIOBJ oldfont, oldbitmap; - COLORREF oldfgcolor; - UINT32 col, row; - HBITMAP bitmap; - int oldbkmode; - RECT client; - HDC dc; - - // get the client rect - GetClientRect(view->wnd, &client); - - // create a compatible DC and an offscreen bitmap - dc = CreateCompatibleDC(windc); - if (dc == NULL) - return; - bitmap = CreateCompatibleBitmap(windc, client.right, client.bottom); - if (bitmap == NULL) - { - DeleteDC(dc); - return; - } - oldbitmap = SelectObject(dc, bitmap); - - // set the font - oldfont = SelectObject(dc, debug_font); - oldfgcolor = GetTextColor(dc); - oldbkmode = GetBkMode(dc); - SetBkMode(dc, TRANSPARENT); - - // iterate over rows and columns - for (row = 0; row < visarea.y; row++) - { - int iter; - - // loop twice; once to fill the background and once to draw the text - for (iter = 0; iter < 2; iter++) - { - COLORREF fgcolor = RGB(0x00,0x00,0x00); - COLORREF bgcolor = RGB(0xff,0xff,0xff); - HBRUSH bgbrush = NULL; - int last_attrib = -1; - TCHAR buffer[256]; - int count = 0; - RECT bounds; - - // initialize the text bounds - bounds.left = bounds.right = 0; - bounds.top = row * debug_font_height; - bounds.bottom = bounds.top + debug_font_height; - - // start with a brush on iteration #0 - if (iter == 0) - bgbrush = CreateSolidBrush(bgcolor); - - // iterate over columns - for (col = 0; col < visarea.x; col++) - { - // if the attribute changed, adjust the colors - if (viewdata[col].attrib != last_attrib) - { - COLORREF oldbg = bgcolor; - - // reset to standard colors - fgcolor = RGB(0x00,0x00,0x00); - bgcolor = RGB(0xff,0xff,0xff); - - // pick new fg/bg colors - if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0); - if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80); - if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00); - if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80); - if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00); - if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff); - if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2); - if (viewdata[col].attrib & DCA_COMMENT) fgcolor = RGB(0x00,0x80,0x00); - - // flush any pending drawing - if (count > 0) - { - bounds.right = bounds.left + count * debug_font_width; - if (iter == 0) - FillRect(dc, &bounds, bgbrush); - else - ExtTextOut(dc, bounds.left, bounds.top, 0, NULL, buffer, count, NULL); - bounds.left = bounds.right; - count = 0; - } - - // set the new colors - if (iter == 0 && oldbg != bgcolor) - { - DeleteObject(bgbrush); - bgbrush = CreateSolidBrush(bgcolor); - } - else if (iter == 1) - SetTextColor(dc, fgcolor); - last_attrib = viewdata[col].attrib; - } - - // add this character to the buffer - buffer[count++] = viewdata[col].byte; - } - - // flush any remaining stuff - if (count > 0) - { - bounds.right = bounds.left + count * debug_font_width; - if (iter == 0) - FillRect(dc, &bounds, bgbrush); - else - ExtTextOut(dc, bounds.left, bounds.top, 0, NULL, buffer, count, NULL); - } - - // erase to the end of the line - if (iter == 0) - { - bounds.left = bounds.right; - bounds.right = client.right; - FillRect(dc, &bounds, bgbrush); - DeleteObject(bgbrush); - } - } - - // advance viewdata - viewdata += visarea.x; - } - - // erase anything beyond the bottom with white - GetClientRect(view->wnd, &client); - client.top = visarea.y * debug_font_height; - FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH)); - - // reset the font - SetBkMode(dc, oldbkmode); - SetTextColor(dc, oldfgcolor); - SelectObject(dc, oldfont); - - // blit the final results - BitBlt(windc, 0, 0, client.right, client.bottom, dc, 0, 0, SRCCOPY); - - // undo the offscreen stuff - SelectObject(dc, oldbitmap); - DeleteObject(bitmap); - DeleteDC(dc); -} - - - -//============================================================ -// debugwin_view_update -//============================================================ - -static void debugwin_view_update(debug_view &view, void *osdprivate) -{ - debugview_info *info = (debugview_info *)osdprivate; - RECT bounds, vscroll_bounds, hscroll_bounds; - debug_view_xy totalsize, visiblesize, topleft; - int show_vscroll, show_hscroll; - SCROLLINFO scrollinfo; - - assert(info->view == &view); - - // get the view window bounds - GetClientRect(info->wnd, &bounds); - visiblesize.x = (bounds.right - bounds.left) / debug_font_width; - visiblesize.y = (bounds.bottom - bounds.top) / debug_font_height; - - // get the updated total rows/cols and left row/col - totalsize = view.total_size(); - topleft = view.visible_position(); - - // determine if we need to show the scrollbars - show_vscroll = show_hscroll = FALSE; - if (totalsize.x > visiblesize.x && bounds.bottom >= hscroll_height) - { - bounds.bottom -= hscroll_height; - visiblesize.y = (bounds.bottom - bounds.top) / debug_font_height; - show_hscroll = TRUE; - } - if (totalsize.y > visiblesize.y && bounds.right >= vscroll_width) - { - bounds.right -= vscroll_width; - visiblesize.x = (bounds.right - bounds.left) / debug_font_width; - show_vscroll = TRUE; - } - if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= vscroll_width) - { - bounds.right -= vscroll_width; - visiblesize.x = (bounds.right - bounds.left) / debug_font_width; - show_vscroll = TRUE; - } - - // compute the bounds of the scrollbars - GetClientRect(info->wnd, &vscroll_bounds); - vscroll_bounds.left = vscroll_bounds.right - vscroll_width; - if (show_hscroll) - vscroll_bounds.bottom -= hscroll_height; - - GetClientRect(info->wnd, &hscroll_bounds); - hscroll_bounds.top = hscroll_bounds.bottom - hscroll_height; - if (show_vscroll) - hscroll_bounds.right -= vscroll_width; - - // if we hid the scrollbars, make sure we reset the top/left corners - if (topleft.y + visiblesize.y > totalsize.y) - topleft.y = MAX(totalsize.y - visiblesize.y, 0); - if (topleft.x + visiblesize.x > totalsize.x) - topleft.x = MAX(totalsize.x - visiblesize.x, 0); - - // fill out the scroll info struct for the vertical scrollbar - scrollinfo.cbSize = sizeof(scrollinfo); - scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - scrollinfo.nMin = 0; - scrollinfo.nMax = totalsize.y - 1; - scrollinfo.nPage = visiblesize.y; - scrollinfo.nPos = topleft.y; - SetScrollInfo(info->vscroll, SB_CTL, &scrollinfo, TRUE); - - // fill out the scroll info struct for the horizontal scrollbar - scrollinfo.cbSize = sizeof(scrollinfo); - scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - scrollinfo.nMin = 0; - scrollinfo.nMax = totalsize.x - 1; - scrollinfo.nPage = visiblesize.x; - scrollinfo.nPos = topleft.x; - SetScrollInfo(info->hscroll, SB_CTL, &scrollinfo, TRUE); - - // update window info - visiblesize.y++; - visiblesize.x++; - view.set_visible_size(visiblesize); - view.set_visible_position(topleft); - - // invalidate the bounds - InvalidateRect(info->wnd, NULL, FALSE); - - // adjust the bounds of the scrollbars and show/hide them - if (info->vscroll) - { - if (show_vscroll) - smart_set_window_bounds(info->vscroll, info->wnd, &vscroll_bounds); - smart_show_window(info->vscroll, show_vscroll); - } - if (info->hscroll) - { - if (show_hscroll) - smart_set_window_bounds(info->hscroll, info->wnd, &hscroll_bounds); - smart_show_window(info->hscroll, show_hscroll); - } -} - - - -//============================================================ -// debugwin_view_process_scroll -//============================================================ - -static UINT32 debugwin_view_process_scroll(debugview_info *info, WORD type, HWND wnd) -{ - SCROLLINFO scrollinfo; - INT32 maxval; - INT32 result; - - // get the current info - scrollinfo.cbSize = sizeof(scrollinfo); - scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; - GetScrollInfo(wnd, SB_CTL, &scrollinfo); - - // by default we stay put - result = scrollinfo.nPos; - - // determine the maximum value - maxval = (scrollinfo.nMax > scrollinfo.nPage) ? (scrollinfo.nMax - scrollinfo.nPage + 1) : 0; - - // handle the message - switch (type) - { - case SB_THUMBTRACK: - result = scrollinfo.nTrackPos; - break; - - case SB_LEFT: - result = 0; - break; - - case SB_RIGHT: - result = maxval; - break; - - case SB_LINELEFT: - result -= 1; - break; - - case SB_LINERIGHT: - result += 1; - break; - - case SB_PAGELEFT: - result -= scrollinfo.nPage - 1; - break; - - case SB_PAGERIGHT: - result += scrollinfo.nPage - 1; - break; - } - - // generic rangecheck - if (result < 0) - result = 0; - if (result > maxval) - result = maxval; - - // set the new position - scrollinfo.fMask = SIF_POS; - scrollinfo.nPos = result; - SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE); - - return (UINT32)result; -} - - - -//============================================================ -// debugwin_view_prev_view -//============================================================ - -static void debugwin_view_prev_view(debugwin_info *info, debugview_info *curview) -{ - int curindex = 1; - int numviews; - - // count the number of views - for (numviews = 0; numviews < MAX_VIEWS; numviews++) - if (info->view[numviews].wnd == NULL) - break; - - // if we have a curview, find out its index - if (curview) - curindex = curview - &info->view[0]; - - // loop until we find someone to take focus - while (1) - { - // advance to the previous index - curindex--; - if (curindex < -1) - curindex = numviews - 1; - - // negative numbers mean the focuswnd - if (curindex < 0 && info->focuswnd != NULL) - { - SetFocus(info->focuswnd); - break; - } - - // positive numbers mean a view - else if (curindex >= 0 && info->view[curindex].wnd != NULL && info->view[curindex].view->cursor_supported()) - { - SetFocus(info->view[curindex].wnd); - break; - } - } -} - - - -//============================================================ -// debugwin_view_next_view -//============================================================ - -static void debugwin_view_next_view(debugwin_info *info, debugview_info *curview) -{ - int curindex = -1; - int numviews; - - // count the number of views - for (numviews = 0; numviews < MAX_VIEWS; numviews++) - if (info->view[numviews].wnd == NULL) - break; - - // if we have a curview, find out its index - if (curview) - curindex = curview - &info->view[0]; - - // loop until we find someone to take focus - while (1) - { - // advance to the previous index - curindex++; - if (curindex >= numviews) - curindex = -1; - - // negative numbers mean the focuswnd - if (curindex < 0 && info->focuswnd != NULL) - { - SetFocus(info->focuswnd); - break; - } - - // positive numbers mean a view - else if (curindex >= 0 && info->view[curindex].wnd != NULL && info->view[curindex].view->cursor_supported()) - { - SetFocus(info->view[curindex].wnd); - InvalidateRect(info->view[curindex].wnd, NULL, FALSE); - break; - } - } -} - - - -//============================================================ -// debugwin_view_proc -//============================================================ - -static LRESULT CALLBACK debugwin_view_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - debugview_info *info = (debugview_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); - - // handle a few messages - switch (message) + // iterate over all of the codes + for (int codenum = 0, length = seq.length(); codenum < length; codenum++) { - // set the info pointer - case WM_CREATE: - { - CREATESTRUCT *createinfo = (CREATESTRUCT *)lparam; - SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams); - break; - } - - // paint: redraw the last bitmap - case WM_PAINT: - { - PAINTSTRUCT pstruct; - HDC dc = BeginPaint(wnd, &pstruct); - debugwin_view_draw_contents(info, dc); - EndPaint(wnd, &pstruct); - break; - } - - // keydown: handle debugger keys - case WM_SYSKEYDOWN: - if (wparam != VK_F10) - return DefWindowProc(wnd, message, wparam, lparam); - // (fall through) - case WM_KEYDOWN: - { - if ((*info->owner->handle_key)(info->owner, wparam, lparam)) - info->owner->ignore_char_lparam = lparam >> 16; - else - { - switch (wparam) - { - case VK_UP: - info->view->process_char(DCH_UP); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_DOWN: - info->view->process_char(DCH_DOWN); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_LEFT: - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - info->view->process_char(DCH_CTRLLEFT); - else - info->view->process_char(DCH_LEFT); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_RIGHT: - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - info->view->process_char(DCH_CTRLRIGHT); - else - info->view->process_char(DCH_RIGHT); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_PRIOR: - info->view->process_char(DCH_PUP); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_NEXT: - info->view->process_char(DCH_PDOWN); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_HOME: - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - info->view->process_char(DCH_CTRLHOME); - else - info->view->process_char(DCH_HOME); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_END: - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - info->view->process_char(DCH_CTRLEND); - else - info->view->process_char(DCH_END); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_ESCAPE: - if (info->owner->focuswnd != NULL) - SetFocus(info->owner->focuswnd); - info->owner->ignore_char_lparam = lparam >> 16; - break; - - case VK_TAB: - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - debugwin_view_prev_view(info->owner, info); - else - debugwin_view_next_view(info->owner, info); - info->owner->ignore_char_lparam = lparam >> 16; - break; - } - } - break; - } - - // char: ignore chars associated with keys we've handled - case WM_CHAR: - { - if (info->owner->ignore_char_lparam == (lparam >> 16)) - info->owner->ignore_char_lparam = 0; - else if (waiting_for_debugger || !debugwin_seq_pressed(info->owner->machine())) - { - if (wparam >= 32 && wparam < 127 && info->view->cursor_supported()) - info->view->process_char(wparam); - else - return DefWindowProc(wnd, message, wparam, lparam); - } - break; - } - - // gaining focus - case WM_SETFOCUS: - { - if (info->view->cursor_supported()) - info->view->set_cursor_visible(true); - break; - } - - // losing focus - case WM_KILLFOCUS: - { - if (info->view->cursor_supported()) - info->view->set_cursor_visible(false); - break; - } - - // mouse click - case WM_LBUTTONDOWN: - { - if (info->view->cursor_supported()) - { - debug_view_xy topleft = info->view->visible_position(); - debug_view_xy newpos; - newpos.x = topleft.x + GET_X_LPARAM(lparam) / debug_font_width; - newpos.y = topleft.y + GET_Y_LPARAM(lparam) / debug_font_height; - info->view->set_cursor_position(newpos); - SetFocus(wnd); - } - break; - } + input_code code = seq[codenum]; - // hscroll - case WM_HSCROLL: + if (code == input_seq::not_code) { - debug_view_xy topleft = info->view->visible_position(); - topleft.x = debugwin_view_process_scroll(info, LOWORD(wparam), (HWND)lparam); - info->view->set_visible_position(topleft); - info->owner->machine().debug_view().flush_osd_updates(); - break; + // handle NOT + invert = true; } - - // vscroll - case WM_VSCROLL: + else if (code == input_seq::or_code || code == input_seq::end_code) { - debug_view_xy topleft = info->view->visible_position(); - topleft.y = debugwin_view_process_scroll(info, LOWORD(wparam), (HWND)lparam); - info->view->set_visible_position(topleft); - info->owner->machine().debug_view().flush_osd_updates(); - break; - } - - // everything else: defaults - default: - return DefWindowProc(wnd, message, wparam, lparam); - } - - return 0; -} - - - -//============================================================ -// debugwin_edit_proc -//============================================================ - -static LRESULT CALLBACK debugwin_edit_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - debugwin_info *info = (debugwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); - TCHAR buffer[MAX_EDIT_STRING]; - - // handle a few messages - switch (message) - { - // key down: handle navigation in the attached view - case WM_SYSKEYDOWN: - if (wparam != VK_F10) - return CallWindowProc(info->original_editproc, wnd, message, wparam, lparam); - // (fall through) - case WM_KEYDOWN: - switch (wparam) - { - case VK_UP: - if (info->last_history < info->history_count - 1) - info->last_history++; - else - info->last_history = 0; - SendMessage(wnd, WM_SETTEXT, (WPARAM)0, (LPARAM)&info->history[info->last_history][0]); - SendMessage(wnd, EM_SETSEL, (WPARAM)MAX_EDIT_STRING, (LPARAM)MAX_EDIT_STRING); - break; - - case VK_DOWN: - if (info->last_history > 0) - info->last_history--; - else if (info->history_count > 0) - info->last_history = info->history_count - 1; - else - info->last_history = 0; - SendMessage(wnd, WM_SETTEXT, (WPARAM)0, (LPARAM)&info->history[info->last_history][0]); - SendMessage(wnd, EM_SETSEL, (WPARAM)MAX_EDIT_STRING, (LPARAM)MAX_EDIT_STRING); - break; - - case VK_PRIOR: - if (info->view[0].wnd && info->view[0].vscroll) - SendMessage(info->view[0].wnd, WM_VSCROLL, SB_PAGELEFT, (LPARAM)info->view[0].vscroll); - break; - - case VK_NEXT: - if (info->view[0].wnd && info->view[0].vscroll) - SendMessage(info->view[0].wnd, WM_VSCROLL, SB_PAGERIGHT, (LPARAM)info->view[0].vscroll); - break; - - case VK_TAB: - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - debugwin_view_prev_view(info, NULL); - else - debugwin_view_next_view(info, NULL); - info->ignore_char_lparam = lparam >> 16; - break; - - default: - if ((*info->handle_key)(info, wparam, lparam)) - info->ignore_char_lparam = lparam >> 16; - else - return CallWindowProc(info->original_editproc, wnd, message, wparam, lparam); - break; - } - break; - - // char: handle the return key - case WM_CHAR: - - // ignore chars associated with keys we've handled - if (info->ignore_char_lparam == (lparam >> 16)) - info->ignore_char_lparam = 0; - else if (waiting_for_debugger || !debugwin_seq_pressed(info->machine())) - { - switch (wparam) - { - case 13: - { - // fetch the text - SendMessage(wnd, WM_GETTEXT, (WPARAM)ARRAY_LENGTH(buffer), (LPARAM)buffer); - - // add to the history if it's not a repeat of the last one - if (buffer[0] != 0 && _tcscmp(buffer, &info->history[0][0])) - { - memmove(&info->history[1][0], &info->history[0][0], (HISTORY_LENGTH - 1) * MAX_EDIT_STRING); - _tcscpy(&info->history[0][0], buffer); - if (info->history_count < HISTORY_LENGTH) - info->history_count++; - } - info->last_history = info->history_count - 1; - - // process - if (info->process_string) - { - char *utf8_buffer = utf8_from_tstring(buffer); - if (utf8_buffer != NULL) - { - (*info->process_string)(info, utf8_buffer); - osd_free(utf8_buffer); - } - } - break; - } - - case 27: - { - // fetch the text - SendMessage(wnd, WM_GETTEXT, (WPARAM)sizeof(buffer), (LPARAM)buffer); - - // if it's not empty, clear the text - if (_tcslen(buffer) > 0) - { - info->ignore_char_lparam = lparam >> 16; - SendMessage(wnd, WM_SETTEXT, (WPARAM)0, (LPARAM)info->edit_defstr); - } - break; - } - - default: - return CallWindowProc(info->original_editproc, wnd, message, wparam, lparam); - } - } - break; - - // everything else: defaults - default: - return CallWindowProc(info->original_editproc, wnd, message, wparam, lparam); - } - - return 0; -} - - + // handle OR and END -//============================================================ -// generic_create_window -//============================================================ - -#ifdef UNUSED_FUNCTION -static void generic_create_window(running_machine &machine, debug_view_type type) -{ - debugwin_info *info; - char title[256]; - - // create the window - _snprintf(title, ARRAY_LENGTH(title), "Debug: %s [%s]", machine.system().description, machine.system().name); - info = debugwin_window_create(machine, title, NULL); - if (info == NULL || !debugwin_view_create(info, 0, type)) - return; - - // set the child function - info->recompute_children = generic_recompute_children; - - // recompute the children once to get the maxwidth - generic_recompute_children(info); - - // position the window and recompute children again - SetWindowPos(info->wnd, HWND_TOP, 100, 100, info->maxwidth, 200, SWP_SHOWWINDOW); - generic_recompute_children(info); -} -#endif - - - -//============================================================ -// generic_recompute_children -//============================================================ - -static void generic_recompute_children(debugwin_info *info) -{ - debug_view_xy totalsize = info->view[0].view->total_size(); - RECT parent; - RECT bounds; - - // compute a client rect - bounds.top = bounds.left = 0; - bounds.right = totalsize.x * debug_font_width + vscroll_width + 2 * EDGE_WIDTH; - bounds.bottom = 200; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - - // clamp the min/max size - info->maxwidth = bounds.right - bounds.left; - - // get the parent's dimensions - GetClientRect(info->wnd, &parent); - - // view gets the remaining space - InflateRect(&parent, -EDGE_WIDTH, -EDGE_WIDTH); - debugwin_view_set_bounds(&info->view[0], info->wnd, &parent); -} - - - -//============================================================ -// log_create_window -//============================================================ - -static void log_create_window(running_machine &machine) -{ - debug_view_xy totalsize; - debugwin_info *info; - char title[256]; - RECT bounds; - - // create the window - _snprintf(title, ARRAY_LENGTH(title), "Errorlog: %s [%s]", machine.system().description, machine.system().name); - info = debugwin_window_create(machine, title, NULL); - if (info == NULL || !debugwin_view_create(info, 0, DVT_LOG)) - return; - - // set the child function - info->recompute_children = generic_recompute_children; - - // get the view width - totalsize = info->view[0].view->total_size(); - - // compute a client rect - bounds.top = bounds.left = 0; - bounds.right = totalsize.x * debug_font_width + vscroll_width + 2 * EDGE_WIDTH; - bounds.bottom = 200; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - - // clamp the min/max size - info->maxwidth = bounds.right - bounds.left; - - // position the window at the bottom-right - SetWindowPos(info->wnd, HWND_TOP, - 100, 100, - bounds.right - bounds.left, bounds.bottom - bounds.top, - SWP_SHOWWINDOW); - - // recompute the children and set focus on the edit box - generic_recompute_children(info); -} - - - -//============================================================ -// memory_create_window -//============================================================ - -static void memory_create_window(running_machine &machine) -{ - device_t *curcpu = debug_cpu_get_visible_cpu(machine); - debugwin_info *info; - HMENU optionsmenu; - - // create the window - info = debugwin_window_create(machine, "Memory", NULL); - if (info == NULL || !debugwin_view_create(info, 0, DVT_MEMORY)) - return; - - // set the handlers - info->handle_command = memory_handle_command; - info->handle_key = memory_handle_key; - info->update_menu = memory_update_menu; - - // create the options menu - optionsmenu = CreatePopupMenu(); - AppendMenu(optionsmenu, MF_ENABLED, ID_1_BYTE_CHUNKS, TEXT("1-byte chunks\tCtrl+1")); - AppendMenu(optionsmenu, MF_ENABLED, ID_2_BYTE_CHUNKS, TEXT("2-byte chunks\tCtrl+2")); - AppendMenu(optionsmenu, MF_ENABLED, ID_4_BYTE_CHUNKS, TEXT("4-byte chunks\tCtrl+4")); - AppendMenu(optionsmenu, MF_ENABLED, ID_8_BYTE_CHUNKS, TEXT("8-byte chunks\tCtrl+8")); - AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(optionsmenu, MF_ENABLED, ID_LOGICAL_ADDRESSES, TEXT("Logical Addresses\tCtrl+L")); - AppendMenu(optionsmenu, MF_ENABLED, ID_PHYSICAL_ADDRESSES, TEXT("Physical Addresses\tCtrl+Y")); - AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(optionsmenu, MF_ENABLED, ID_REVERSE_VIEW, TEXT("Reverse View\tCtrl+R")); - AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(optionsmenu, MF_ENABLED, ID_INCREASE_MEM_WIDTH, TEXT("Increase bytes per line\tCtrl+P")); - AppendMenu(optionsmenu, MF_ENABLED, ID_DECREASE_MEM_WIDTH, TEXT("Decrease bytes per line\tCtrl+O")); - AppendMenu(GetMenu(info->wnd), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); - - // set up the view to track the initial expression - downcast<debug_view_memory *>(info->view[0].view)->set_expression("0"); - strcpy(info->edit_defstr, "0"); - - // create an edit box and override its key handling - info->editwnd = CreateWindowEx(EDIT_BOX_STYLE_EX, TEXT("EDIT"), NULL, EDIT_BOX_STYLE, - 0, 0, 100, 100, info->wnd, NULL, GetModuleHandle(NULL), NULL); - info->original_editproc = (WNDPROC)(FPTR)GetWindowLongPtr(info->editwnd, GWLP_WNDPROC); - SetWindowLongPtr(info->editwnd, GWLP_USERDATA, (LONG_PTR)info); - SetWindowLongPtr(info->editwnd, GWLP_WNDPROC, (LONG_PTR)debugwin_edit_proc); - SendMessage(info->editwnd, WM_SETFONT, (WPARAM)debug_font, (LPARAM)FALSE); - SendMessage(info->editwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)TEXT("0")); - SendMessage(info->editwnd, EM_LIMITTEXT, (WPARAM)MAX_EDIT_STRING, (LPARAM)0); - SendMessage(info->editwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - - // create a combo box - info->otherwnd[0] = CreateWindowEx(COMBO_BOX_STYLE_EX, TEXT("COMBOBOX"), NULL, COMBO_BOX_STYLE, - 0, 0, 100, 1000, info->wnd, NULL, GetModuleHandle(NULL), NULL); - SetWindowLongPtr(info->otherwnd[0], GWLP_USERDATA, (LONG_PTR)info); - SendMessage(info->otherwnd[0], WM_SETFONT, (WPARAM)debug_font, (LPARAM)FALSE); - - // populate the combobox - int maxlength = 0; - for (const debug_view_source *source = info->view[0].view->first_source(); source != NULL; source = source->next()) - { - int length = strlen(source->name()); - if (length > maxlength) - maxlength = length; - TCHAR *t_name = tstring_from_utf8(source->name()); - SendMessage(info->otherwnd[0], CB_ADDSTRING, 0, (LPARAM)t_name); - osd_free(t_name); - } - const debug_view_source *source = info->view[0].view->source_for_device(curcpu); - SendMessage(info->otherwnd[0], CB_SETCURSEL, info->view[0].view->source_list().indexof(*source), 0); - SendMessage(info->otherwnd[0], CB_SETDROPPEDWIDTH, (maxlength + 2) * debug_font_width + vscroll_width, 0); - info->view[0].view->set_source(*source); - - // set the child functions - info->recompute_children = memory_recompute_children; - info->process_string = memory_process_string; - - // set the caption - memory_update_caption(machine, info->wnd); - - // recompute the children once to get the maxwidth - memory_recompute_children(info); - - // position the window and recompute children again - SetWindowPos(info->wnd, HWND_TOP, 100, 100, info->maxwidth, 200, SWP_SHOWWINDOW); - memory_recompute_children(info); - - // mark the edit box as the default focus and set it - info->focuswnd = info->editwnd; - SetFocus(info->editwnd); -} - - - -//============================================================ -// memory_recompute_children -//============================================================ - -static void memory_recompute_children(debugwin_info *info) -{ - debug_view_xy totalsize = info->view[0].view->total_size(); - RECT parent, memrect, editrect, comborect; - RECT bounds; - - // compute a client rect - bounds.top = bounds.left = 0; - bounds.right = totalsize.x * debug_font_width + vscroll_width + 2 * EDGE_WIDTH; - bounds.bottom = 200; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - - // clamp the min/max size - info->maxwidth = bounds.right - bounds.left; - - // get the parent's dimensions - GetClientRect(info->wnd, &parent); - - // edit box gets half of the width - editrect.top = parent.top + EDGE_WIDTH; - editrect.bottom = editrect.top + debug_font_height + 4; - editrect.left = parent.left + EDGE_WIDTH; - editrect.right = parent.left + (parent.right - parent.left) / 2 - EDGE_WIDTH; - - // combo box gets the other half of the width - comborect.top = editrect.top; - comborect.bottom = editrect.bottom; - comborect.left = editrect.right + 2 * EDGE_WIDTH; - comborect.right = parent.right - EDGE_WIDTH; - - // memory view gets the rest - memrect.top = editrect.bottom + 2 * EDGE_WIDTH; - memrect.bottom = parent.bottom - EDGE_WIDTH; - memrect.left = parent.left + EDGE_WIDTH; - memrect.right = parent.right - EDGE_WIDTH; - - // set the bounds of things - debugwin_view_set_bounds(&info->view[0], info->wnd, &memrect); - smart_set_window_bounds(info->editwnd, info->wnd, &editrect); - smart_set_window_bounds(info->otherwnd[0], info->wnd, &comborect); -} - - - -//============================================================ -// memory_process_string -//============================================================ - -static void memory_process_string(debugwin_info *info, const char *string) -{ - // set the string to the memory view - downcast<debug_view_memory *>(info->view[0].view)->set_expression(string); - - // select everything in the edit text box - SendMessage(info->editwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - - // update the default string to match - strncpy(info->edit_defstr, string, sizeof(info->edit_defstr) - 1); -} - - - -//============================================================ -// memory_update_menu -//============================================================ - -static void memory_update_menu(debugwin_info *info) -{ - debug_view_memory *memview = downcast<debug_view_memory *>(info->view[0].view); - CheckMenuItem(GetMenu(info->wnd), ID_1_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 1 ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_2_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 2 ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_4_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 4 ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_8_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 8 ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_LOGICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_UNCHECKED : MF_CHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_PHYSICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_REVERSE_VIEW, MF_BYCOMMAND | (memview->reverse() ? MF_CHECKED : MF_UNCHECKED)); -} - - - -//============================================================ -// memory_handle_command -//============================================================ - -static int memory_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam) -{ - debug_view_memory *memview = downcast<debug_view_memory *>(info->view[0].view); - switch (HIWORD(wparam)) - { - // combo box selection changed - case CBN_SELCHANGE: - { - int sel = SendMessage((HWND)lparam, CB_GETCURSEL, 0, 0); - if (sel != CB_ERR) - { - memview->set_source(*memview->source_list().find(sel)); - memory_update_caption(info->machine(), info->wnd); + // if we have a positive result from the previous set, we're done + if (result || code == input_seq::end_code) + break; - // reset the focus - SetFocus(info->focuswnd); - return 1; - } - break; + // otherwise, reset our state + result = false; + invert = false; + first = true; } - - // menu selections - case 0: - switch (LOWORD(wparam)) - { - case ID_1_BYTE_CHUNKS: - memview->set_bytes_per_chunk(1); - return 1; - - case ID_2_BYTE_CHUNKS: - memview->set_bytes_per_chunk(2); - return 1; - - case ID_4_BYTE_CHUNKS: - memview->set_bytes_per_chunk(4); - return 1; - - case ID_8_BYTE_CHUNKS: - memview->set_bytes_per_chunk(8); - return 1; - - case ID_LOGICAL_ADDRESSES: - memview->set_physical(false); - return 1; - - case ID_PHYSICAL_ADDRESSES: - memview->set_physical(true); - return 1; - - case ID_REVERSE_VIEW: - memview->set_reverse(!memview->reverse()); - return 1; - - case ID_INCREASE_MEM_WIDTH: - memview->set_chunks_per_row(memview->chunks_per_row() + 1); - return 1; - - case ID_DECREASE_MEM_WIDTH: - memview->set_chunks_per_row(memview->chunks_per_row() - 1); - return 1; - } - break; - } - return global_handle_command(info, wparam, lparam); -} - - - -//============================================================ -// memory_handle_key -//============================================================ - -static int memory_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam) -{ - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - switch (wparam) + else { - case '1': - SendMessage(info->wnd, WM_COMMAND, ID_1_BYTE_CHUNKS, 0); - return 1; - - case '2': - SendMessage(info->wnd, WM_COMMAND, ID_2_BYTE_CHUNKS, 0); - return 1; - - case '4': - SendMessage(info->wnd, WM_COMMAND, ID_4_BYTE_CHUNKS, 0); - return 1; - - case '8': - SendMessage(info->wnd, WM_COMMAND, ID_8_BYTE_CHUNKS, 0); - return 1; - - case 'L': - SendMessage(info->wnd, WM_COMMAND, ID_LOGICAL_ADDRESSES, 0); - return 1; - - case 'Y': - SendMessage(info->wnd, WM_COMMAND, ID_PHYSICAL_ADDRESSES, 0); - return 1; + // handle everything else as a series of ANDs + int const vkey = wininput_vkey_for_mame_code(code); + bool const pressed = (vkey != 0) && ((GetAsyncKeyState(vkey) & 0x8000) != 0); - case 'R': - SendMessage(info->wnd, WM_COMMAND, ID_REVERSE_VIEW, 0); - return 1; - - case 'P': - SendMessage(info->wnd, WM_COMMAND, ID_INCREASE_MEM_WIDTH, 0); - return 1; + if (first) // if this is the first in the sequence, result is set equal + result = pressed ^ invert; + else if (result) // further values are ANDed + result = result && (pressed ^ invert); - case 'O': - SendMessage(info->wnd, WM_COMMAND, ID_DECREASE_MEM_WIDTH, 0); - return 1; + // no longer first, and clear the invert flag + first = invert = false; } } - return global_handle_key(info, wparam, lparam); -} - - - -//============================================================ -// memory_update_caption -//============================================================ - -static void memory_update_caption(running_machine &machine, HWND wnd) -{ - debugwin_info *info = (debugwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); - astring title; - - title.printf("Memory: %s", info->view[0].view->source()->name()); - win_set_window_text_utf8(wnd, title); -} - - - -//============================================================ -// disasm_create_window -//============================================================ - -static void disasm_create_window(running_machine &machine) -{ - device_t *curcpu = debug_cpu_get_visible_cpu(machine); - debugwin_info *info; - HMENU optionsmenu; - - // create the window - info = debugwin_window_create(machine, "Disassembly", NULL); - if (info == NULL || !debugwin_view_create(info, 0, DVT_DISASSEMBLY)) - return; - - // create the options menu - optionsmenu = CreatePopupMenu(); - AppendMenu(optionsmenu, MF_ENABLED, ID_TOGGLE_BREAKPOINT, TEXT("Set breakpoint at cursor\tF9")); - AppendMenu(optionsmenu, MF_ENABLED, ID_RUN_TO_CURSOR, TEXT("Run to cursor\tF4")); - AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_RAW, TEXT("Raw opcodes\tCtrl+R")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_ENCRYPTED, TEXT("Encrypted opcodes\tCtrl+E")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_COMMENTS, TEXT("Comments\tCtrl+M")); - AppendMenu(GetMenu(info->wnd), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); - - // set the handlers - info->handle_command = disasm_handle_command; - info->handle_key = disasm_handle_key; - info->update_menu = disasm_update_menu; - - // set up the view to track the initial expression - downcast<debug_view_disasm *>(info->view[0].view)->set_expression("curpc"); - strcpy(info->edit_defstr, "curpc"); - - // create an edit box and override its key handling - info->editwnd = CreateWindowEx(EDIT_BOX_STYLE_EX, TEXT("EDIT"), NULL, EDIT_BOX_STYLE, - 0, 0, 100, 100, info->wnd, NULL, GetModuleHandle(NULL), NULL); - info->original_editproc = (WNDPROC)(FPTR)GetWindowLongPtr(info->editwnd, GWLP_WNDPROC); - SetWindowLongPtr(info->editwnd, GWLP_USERDATA, (LONG_PTR)info); - SetWindowLongPtr(info->editwnd, GWLP_WNDPROC, (LONG_PTR)debugwin_edit_proc); - SendMessage(info->editwnd, WM_SETFONT, (WPARAM)debug_font, (LPARAM)FALSE); - SendMessage(info->editwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)TEXT("curpc")); - SendMessage(info->editwnd, EM_LIMITTEXT, (WPARAM)MAX_EDIT_STRING, (LPARAM)0); - SendMessage(info->editwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - - // create a combo box - info->otherwnd[0] = CreateWindowEx(COMBO_BOX_STYLE_EX, TEXT("COMBOBOX"), NULL, COMBO_BOX_STYLE, - 0, 0, 100, 1000, info->wnd, NULL, GetModuleHandle(NULL), NULL); - SetWindowLongPtr(info->otherwnd[0], GWLP_USERDATA, (LONG_PTR)info); - SendMessage(info->otherwnd[0], WM_SETFONT, (WPARAM)debug_font, (LPARAM)FALSE); - - // populate the combobox - int maxlength = 0; - for (const debug_view_source *source = info->view[0].view->first_source(); source != NULL; source = source->next()) - { - int length = strlen(source->name()); - if (length > maxlength) - maxlength = length; - TCHAR *t_name = tstring_from_utf8(source->name()); - SendMessage(info->otherwnd[0], CB_ADDSTRING, 0, (LPARAM)t_name); - osd_free(t_name); - } - const debug_view_source *source = info->view[0].view->source_for_device(curcpu); - SendMessage(info->otherwnd[0], CB_SETCURSEL, info->view[0].view->source_list().indexof(*source), 0); - SendMessage(info->otherwnd[0], CB_SETDROPPEDWIDTH, (maxlength + 2) * debug_font_width + vscroll_width, 0); - info->view[0].view->set_source(*source); - - // set the child functions - info->recompute_children = disasm_recompute_children; - info->process_string = disasm_process_string; - - // set the caption - disasm_update_caption(machine, info->wnd); - - // recompute the children once to get the maxwidth - disasm_recompute_children(info); - - // position the window and recompute children again - SetWindowPos(info->wnd, HWND_TOP, 100, 100, info->maxwidth, 200, SWP_SHOWWINDOW); - disasm_recompute_children(info); - - // mark the edit box as the default focus and set it - info->focuswnd = info->editwnd; - SetFocus(info->editwnd); -} - - - -//============================================================ -// disasm_recompute_children -//============================================================ - -static void disasm_recompute_children(debugwin_info *info) -{ - debug_view_xy totalsize = info->view[0].view->total_size(); - RECT parent, dasmrect, editrect, comborect; - RECT bounds; - // compute a client rect - bounds.top = bounds.left = 0; - bounds.right = totalsize.x * debug_font_width + vscroll_width + 2 * EDGE_WIDTH; - bounds.bottom = 200; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - - // clamp the min/max size - info->maxwidth = bounds.right - bounds.left; - - // get the parent's dimensions - GetClientRect(info->wnd, &parent); - - // edit box gets half of the width - editrect.top = parent.top + EDGE_WIDTH; - editrect.bottom = editrect.top + debug_font_height + 4; - editrect.left = parent.left + EDGE_WIDTH; - editrect.right = parent.left + (parent.right - parent.left) / 2 - EDGE_WIDTH; - - // combo box gets the other half of the width - comborect.top = editrect.top; - comborect.bottom = editrect.bottom; - comborect.left = editrect.right + 2 * EDGE_WIDTH; - comborect.right = parent.right - EDGE_WIDTH; - - // disasm view gets the rest - dasmrect.top = editrect.bottom + 2 * EDGE_WIDTH; - dasmrect.bottom = parent.bottom - EDGE_WIDTH; - dasmrect.left = parent.left + EDGE_WIDTH; - dasmrect.right = parent.right - EDGE_WIDTH; - - // set the bounds of things - debugwin_view_set_bounds(&info->view[0], info->wnd, &dasmrect); - smart_set_window_bounds(info->editwnd, info->wnd, &editrect); - smart_set_window_bounds(info->otherwnd[0], info->wnd, &comborect); + // return the result if we queried at least one switch + return result; } - -//============================================================ -// disasm_process_string -//============================================================ - -static void disasm_process_string(debugwin_info *info, const char *string) +void debugger_windows::remove_window(debugwin_info &info) { - // set the string to the disasm view - downcast<debug_view_disasm *>(info->view[0].view)->set_expression(string); - - // select everything in the edit text box - SendMessage(info->editwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - - // update the default string to match - strncpy(info->edit_defstr, string, sizeof(info->edit_defstr) - 1); + m_window_list.remove(info); } - -//============================================================ -// disasm_update_menu -//============================================================ - -static void disasm_update_menu(debugwin_info *info) +void debugger_windows::show_all() { - disasm_right_column rightcol = downcast<debug_view_disasm *>(info->view[0].view)->right_column(); - CheckMenuItem(GetMenu(info->wnd), ID_SHOW_RAW, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_RAW ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_SHOW_ENCRYPTED, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_ENCRYPTED ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(GetMenu(info->wnd), ID_SHOW_COMMENTS, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_COMMENTS ? MF_CHECKED : MF_UNCHECKED)); + for (debugwin_info *info = m_window_list.first(); info != NULL; info = info->next()) + info->show(); } - -//============================================================ -// disasm_handle_command -//============================================================ - -static int disasm_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam) +void debugger_windows::hide_all() { - debug_view_disasm *dasmview = downcast<debug_view_disasm *>(info->view[0].view); - char command[64]; - - switch (HIWORD(wparam)) - { - // combo box selection changed - case CBN_SELCHANGE: - { - int sel = SendMessage((HWND)lparam, CB_GETCURSEL, 0, 0); - if (sel != CB_ERR) - { - dasmview->set_source(*dasmview->source_list().find(sel)); - disasm_update_caption(info->machine(), info->wnd); - - // reset the focus - SetFocus(info->focuswnd); - return 1; - } - break; - } - - // menu selections - case 0: - switch (LOWORD(wparam)) - { - case ID_SHOW_RAW: - dasmview->set_right_column(DASM_RIGHTCOL_RAW); - (*info->recompute_children)(info); - return 1; - - case ID_SHOW_ENCRYPTED: - dasmview->set_right_column(DASM_RIGHTCOL_ENCRYPTED); - (*info->recompute_children)(info); - return 1; - - case ID_SHOW_COMMENTS: - dasmview->set_right_column(DASM_RIGHTCOL_COMMENTS); - (*info->recompute_children)(info); - return 1; - - case ID_RUN_TO_CURSOR: - if (dasmview->cursor_visible() && debug_cpu_get_visible_cpu(info->machine()) == dasmview->source()->device()) - { - offs_t address = dasmview->selected_address(); - sprintf(command, "go 0x%X", address); - debug_console_execute_command(info->machine(), command, 1); - } - return 1; - - case ID_TOGGLE_BREAKPOINT: - if (dasmview->cursor_visible() && debug_cpu_get_visible_cpu(info->machine()) == dasmview->source()->device()) - { - offs_t address = dasmview->selected_address(); - device_debug *debug = dasmview->source()->device()->debug(); - INT32 bpindex = -1; - - /* first find an existing breakpoint at this address */ - for (device_debug::breakpoint *bp = debug->breakpoint_first(); bp != NULL; bp = bp->next()) - if (address == bp->address()) - { - bpindex = bp->index(); - break; - } - - /* if it doesn't exist, add a new one */ - if (bpindex == -1) - sprintf(command, "bpset 0x%X", address); - else - sprintf(command, "bpclear 0x%X", bpindex); - debug_console_execute_command(info->machine(), command, 1); - } - return 1; - } - break; - } - return global_handle_command(info, wparam, lparam); + SetForegroundWindow(win_window_list->m_hwnd); + for (debugwin_info *info = m_window_list.first(); info != NULL; info = info->next()) + info->hide(); } - -//============================================================ -// disasm_handle_key -//============================================================ - -static int disasm_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam) +template <typename T> T *debugger_windows::create_window() { - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - switch (wparam) - { - case 'R': - SendMessage(info->wnd, WM_COMMAND, ID_SHOW_RAW, 0); - return 1; - - case 'E': - SendMessage(info->wnd, WM_COMMAND, ID_SHOW_ENCRYPTED, 0); - return 1; - - case 'N': - SendMessage(info->wnd, WM_COMMAND, ID_SHOW_COMMENTS, 0); - return 1; - } - } - - switch (wparam) - { - /* ajg - steals the F4 from the global key handler - but ALT+F4 didn't work anyways ;) */ - case VK_F4: - SendMessage(info->wnd, WM_COMMAND, ID_RUN_TO_CURSOR, 0); - return 1; - - case VK_F9: - SendMessage(info->wnd, WM_COMMAND, ID_TOGGLE_BREAKPOINT, 0); - return 1; - - case VK_RETURN: - if (info->view[0].view->cursor_visible()) - { - SendMessage(info->wnd, WM_COMMAND, ID_STEP, 0); - return 1; - } - break; - } - - return global_handle_key(info, wparam, lparam); -} - - - -//============================================================ -// disasm_update_caption -//============================================================ - -static void disasm_update_caption(running_machine &machine, HWND wnd) -{ - debugwin_info *info = (debugwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); - astring title; - - title.printf("Disassembly: %s", info->view[0].view->source()->name()); - win_set_window_text_utf8(wnd, title); -} - - -enum -{ - DEVOPTION_OPEN, - DEVOPTION_CREATE, - DEVOPTION_CLOSE, - DEVOPTION_CASSETTE_STOPPAUSE, - DEVOPTION_CASSETTE_PLAY, - DEVOPTION_CASSETTE_RECORD, - DEVOPTION_CASSETTE_REWIND, - DEVOPTION_CASSETTE_FASTFORWARD, - DEVOPTION_MAX -}; - -//============================================================ -// memory_update_menu -//============================================================ - -static void image_update_menu(debugwin_info *info) -{ - UINT32 cnt = 0; - HMENU devicesmenu; - - DeleteMenu(GetMenu(info->wnd), 2, MF_BYPOSITION); - - // create the image menu - devicesmenu = CreatePopupMenu(); - image_interface_iterator iter(info->machine().root_device()); - for (device_image_interface *img = iter.first(); img != NULL; img = iter.next()) - { - astring temp; - UINT flags_for_exists; - UINT flags_for_writing; - HMENU devicesubmenu = CreatePopupMenu(); - - UINT_PTR new_item = ID_DEVICE_OPTIONS + (cnt * DEVOPTION_MAX); - - flags_for_exists = MF_ENABLED | MF_STRING; - - if (!img->exists()) - flags_for_exists |= MF_GRAYED; - - flags_for_writing = flags_for_exists; - if (img->is_readonly()) - flags_for_writing |= MF_GRAYED; - - AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_OPEN, TEXT("Mount...")); - - /*if (img->is_creatable()) - AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_CREATE, TEXT("Create...")); - */ - AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CLOSE, TEXT("Unmount")); - - if (img->device().type() == CASSETTE) - { - cassette_state state; - state = (cassette_state)(img->exists() ? (dynamic_cast<cassette_image_device*>(&img->device())->get_state() & CASSETTE_MASK_UISTATE) : CASSETTE_STOPPED); - AppendMenu(devicesubmenu, MF_SEPARATOR, 0, NULL); - AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_STOPPED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_STOPPAUSE, TEXT("Pause/Stop")); - AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_PLAY) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_PLAY, TEXT("Play")); - AppendMenu(devicesubmenu, flags_for_writing | ((state == CASSETTE_RECORD) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_RECORD, TEXT("Record")); - AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_REWIND, TEXT("Rewind")); - AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_FASTFORWARD, TEXT("Fast Forward")); - } - - temp.format("%s :%s", img->device().name(), img->exists() ? img->filename() : "[empty slot]"); - - AppendMenu(devicesmenu, MF_ENABLED | MF_POPUP, (UINT_PTR)devicesubmenu, tstring_from_utf8(temp.cstr())); - - cnt++; - } - AppendMenu(GetMenu(info->wnd), MF_ENABLED | MF_POPUP, (UINT_PTR)devicesmenu, TEXT("Images")); - -} - -//============================================================ -// console_create_window -//============================================================ - -void console_create_window(running_machine &machine) -{ - debugwin_info *info; - int bestwidth, bestheight; - RECT bounds, work_bounds; - HMENU optionsmenu; - UINT32 conchars; - - // create the window - info = debugwin_window_create(machine, "Debug", NULL); - if (info == NULL) - return; - main_console = info; - - // create the views - if (!debugwin_view_create(info, 0, DVT_DISASSEMBLY)) - goto cleanup; - if (!debugwin_view_create(info, 1, DVT_STATE)) - goto cleanup; - if (!debugwin_view_create(info, 2, DVT_CONSOLE)) - goto cleanup; - - // create the options menu - optionsmenu = CreatePopupMenu(); - AppendMenu(optionsmenu, MF_ENABLED, ID_TOGGLE_BREAKPOINT, TEXT("Set breakpoint at cursor\tF9")); - AppendMenu(optionsmenu, MF_ENABLED, ID_RUN_TO_CURSOR, TEXT("Run to cursor\tF4")); - AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_RAW, TEXT("Raw opcodes\tCtrl+R")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_ENCRYPTED, TEXT("Encrypted opcodes\tCtrl+E")); - AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_COMMENTS, TEXT("Comments\tCtrl+N")); - AppendMenu(GetMenu(info->wnd), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); - - // Add image menu only if image devices exist - { - image_interface_iterator iter(machine.root_device()); - if (iter.first() != NULL) { - info->update_menu = image_update_menu; - image_update_menu(info); - } - } - - // set the handlers - info->handle_command = disasm_handle_command; - info->handle_key = disasm_handle_key; - - // create an edit box and override its key handling - info->editwnd = CreateWindowEx(EDIT_BOX_STYLE_EX, TEXT("EDIT"), NULL, EDIT_BOX_STYLE, - 0, 0, 100, 100, info->wnd, NULL, GetModuleHandle(NULL), NULL); - info->original_editproc = (WNDPROC)(FPTR)GetWindowLongPtr(info->editwnd, GWLP_WNDPROC); - SetWindowLongPtr(info->editwnd, GWLP_USERDATA, (LONG_PTR)info); - SetWindowLongPtr(info->editwnd, GWLP_WNDPROC, (LONG_PTR)debugwin_edit_proc); - SendMessage(info->editwnd, WM_SETFONT, (WPARAM)debug_font, (LPARAM)FALSE); - SendMessage(info->editwnd, EM_LIMITTEXT, (WPARAM)MAX_EDIT_STRING, (LPARAM)0); - - // set the child functions - info->recompute_children = console_recompute_children; - info->process_string = console_process_string; - - // loop over all register views and get the maximum size - main_console_regwidth = 0; - for (const debug_view_source *source = info->view[1].view->first_source(); source != NULL; source = source->next()) - { - UINT32 regchars; - - // set the view and fetch the width - info->view[1].view->set_source(*source); - regchars = info->view[1].view->total_size().x; - - // track the maximum - main_console_regwidth = MAX(regchars, main_console_regwidth); - } - - // determine the width of the console (this is fixed) - conchars = info->view[2].view->total_size().x; - - // loop over all CPUs and compute the width range based on dasm width - info->minwidth = 0; - info->maxwidth = 0; - for (const debug_view_source *source = info->view[0].view->first_source(); source != NULL; source = source->next()) + // allocate memory + T *info = global_alloc(T(*this)); + if (info->is_valid()) { - UINT32 minwidth, maxwidth, dischars; - - // set the view and fetch the width - info->view[0].view->set_source(*source); - dischars = info->view[0].view->total_size().x; - - // compute the preferred width - minwidth = EDGE_WIDTH + main_console_regwidth * debug_font_width + vscroll_width + 2 * EDGE_WIDTH + 100 + EDGE_WIDTH; - maxwidth = EDGE_WIDTH + main_console_regwidth * debug_font_width + vscroll_width + 2 * EDGE_WIDTH + MAX(dischars, conchars) * debug_font_width + vscroll_width + EDGE_WIDTH; - info->minwidth = MAX(info->minwidth, minwidth); - info->maxwidth = MAX(info->maxwidth, maxwidth); + m_window_list.prepend(*info); + return info; } - - // get the work bounds - SystemParametersInfo(SPI_GETWORKAREA, 0, &work_bounds, 0); - - // adjust the min/max sizes for the window style - bounds.top = bounds.left = 0; - bounds.right = bounds.bottom = info->minwidth; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - info->minwidth = bounds.right - bounds.left; - - bounds.top = bounds.left = 0; - bounds.right = bounds.bottom = info->maxwidth; - AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); - info->maxwidth = bounds.right - bounds.left; - - // position the window at the bottom-right - bestwidth = (info->maxwidth < (work_bounds.right - work_bounds.left)) ? info->maxwidth : (work_bounds.right - work_bounds.left); - bestheight = (500 < (work_bounds.bottom - work_bounds.top)) ? 500 : (work_bounds.bottom - work_bounds.top); - SetWindowPos(info->wnd, HWND_TOP, - work_bounds.right - bestwidth, work_bounds.bottom - bestheight, - bestwidth, bestheight, - SWP_SHOWWINDOW); - - // recompute the children - console_set_cpu(debug_cpu_get_visible_cpu(machine)); - - // set up the disassembly view to track the current pc - downcast<debug_view_disasm *>(info->view[0].view)->set_expression("curpc"); - - // mark the edit box as the default focus and set it - info->focuswnd = info->editwnd; - SetFocus(info->editwnd); - return; - -cleanup: - if (info->view[2].view) - machine.debug_view().free_view(*info->view[2].view); - if (info->view[1].view) - machine.debug_view().free_view(*info->view[1].view); - if (info->view[0].view) - machine.debug_view().free_view(*info->view[0].view); -} - - - -//============================================================ -// console_recompute_children -//============================================================ - -static void console_recompute_children(debugwin_info *info) -{ - RECT parent, regrect, disrect, conrect, editrect; - UINT32 regchars;//, dischars, conchars; - - // get the parent's dimensions - GetClientRect(info->wnd, &parent); - - // get the total width of all three children - //dischars = info->view[0].view->total_size().x; - regchars = main_console_regwidth; - //conchars = info->view[2].view->total_size().x; - - // registers always get their desired width, and span the entire height - regrect.top = parent.top + EDGE_WIDTH; - regrect.bottom = parent.bottom - EDGE_WIDTH; - regrect.left = parent.left + EDGE_WIDTH; - regrect.right = regrect.left + debug_font_width * regchars + vscroll_width; - - // edit box goes at the bottom of the remaining area - editrect.bottom = parent.bottom - EDGE_WIDTH; - editrect.top = editrect.bottom - debug_font_height - 4; - editrect.left = regrect.right + EDGE_WIDTH * 2; - editrect.right = parent.right - EDGE_WIDTH; - - // console and disassembly split the difference - disrect.top = parent.top + EDGE_WIDTH; - disrect.bottom = (editrect.top - parent.top) / 2 - EDGE_WIDTH; - disrect.left = regrect.right + EDGE_WIDTH * 2; - disrect.right = parent.right - EDGE_WIDTH; - - conrect.top = disrect.bottom + EDGE_WIDTH * 2; - conrect.bottom = editrect.top - EDGE_WIDTH; - conrect.left = regrect.right + EDGE_WIDTH * 2; - conrect.right = parent.right - EDGE_WIDTH; - - // set the bounds of things - debugwin_view_set_bounds(&info->view[0], info->wnd, &disrect); - debugwin_view_set_bounds(&info->view[1], info->wnd, ®rect); - debugwin_view_set_bounds(&info->view[2], info->wnd, &conrect); - smart_set_window_bounds(info->editwnd, info->wnd, &editrect); -} - - - -//============================================================ -// console_process_string -//============================================================ - -static void console_process_string(debugwin_info *info, const char *string) -{ - TCHAR buffer = 0; - - // an empty string is a single step - if (string[0] == 0) - debug_cpu_get_visible_cpu(info->machine())->debug()->single_step(); - - // otherwise, just process the command else - debug_console_execute_command(info->machine(), string, 1); - - // clear the edit text box - SendMessage(info->editwnd, WM_SETTEXT, 0, (LPARAM)&buffer); -} - - - -//============================================================ -// console_set_cpu -//============================================================ - -static void console_set_cpu(device_t *device) -{ - // first set all the views to the new cpu number - main_console->view[0].view->set_source(*main_console->view[0].view->source_for_device(device)); - main_console->view[1].view->set_source(*main_console->view[1].view->source_for_device(device)); - - // then update the caption - char curtitle[256]; - astring title; - - title.printf("Debug: %s - %s '%s'", device->machine().system().name, device->name(), device->tag()); - win_get_window_text_utf8(main_console->wnd, curtitle, ARRAY_LENGTH(curtitle)); - if (title.cmp(curtitle) != 0) - win_set_window_text_utf8(main_console->wnd, title); - - // and recompute the children - console_recompute_children(main_console); -} - - - -//============================================================ -// create_standard_menubar -//============================================================ - -static HMENU create_standard_menubar(void) -{ - HMENU menubar, debugmenu; - - // create the debug menu - debugmenu = CreatePopupMenu(); - if (debugmenu == NULL) - return NULL; - AppendMenu(debugmenu, MF_ENABLED, ID_NEW_MEMORY_WND, TEXT("New Memory Window\tCtrl+M")); - AppendMenu(debugmenu, MF_ENABLED, ID_NEW_DISASM_WND, TEXT("New Disassembly Window\tCtrl+D")); - AppendMenu(debugmenu, MF_ENABLED, ID_NEW_LOG_WND, TEXT("New Error Log Window\tCtrl+L")); - AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(debugmenu, MF_ENABLED, ID_RUN, TEXT("Run\tF5")); - AppendMenu(debugmenu, MF_ENABLED, ID_RUN_AND_HIDE, TEXT("Run and Hide Debugger\tF12")); - AppendMenu(debugmenu, MF_ENABLED, ID_NEXT_CPU, TEXT("Run to Next CPU\tF6")); - AppendMenu(debugmenu, MF_ENABLED, ID_RUN_IRQ, TEXT("Run until Next Interrupt on This CPU\tF7")); - AppendMenu(debugmenu, MF_ENABLED, ID_RUN_VBLANK, TEXT("Run until Next VBLANK\tF8")); - AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(debugmenu, MF_ENABLED, ID_STEP, TEXT("Step Into\tF11")); - AppendMenu(debugmenu, MF_ENABLED, ID_STEP_OVER, TEXT("Step Over\tF10")); - AppendMenu(debugmenu, MF_ENABLED, ID_STEP_OUT, TEXT("Step Out\tShift+F11")); - AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); - AppendMenu(debugmenu, MF_ENABLED, ID_SOFT_RESET, TEXT("Soft Reset\tF3")); - AppendMenu(debugmenu, MF_ENABLED, ID_HARD_RESET, TEXT("Hard Reset\tShift+F3")); - AppendMenu(debugmenu, MF_ENABLED, ID_EXIT, TEXT("Exit")); - - // create the menu bar - menubar = CreateMenu(); - if (menubar == NULL) { - DestroyMenu(debugmenu); + global_free(info); return NULL; } - AppendMenu(menubar, MF_ENABLED | MF_POPUP, (UINT_PTR)debugmenu, TEXT("Debug")); - - return menubar; -} - -//============================================================ -// copy_extension_list -//============================================================ - -static int copy_extension_list(char *dest, size_t dest_len, const char *extensions) -{ - const char *s; - int pos = 0; - - // our extension lists are comma delimited; Win32 expects to see lists - // delimited by semicolons - s = extensions; - while(*s) - { - // append a semicolon if not at the beginning - if (s != extensions) - pos += snprintf(&dest[pos], dest_len - pos, ";"); - - // append ".*" - pos += snprintf(&dest[pos], dest_len - pos, "*."); - - // append the file extension - while(*s && (*s != ',')) - { - pos += snprintf(&dest[pos], dest_len - pos, "%c", *s); - s++; - } - - // if we found a comma, advance - while(*s == ',') - s++; - } - return pos; -} - -//============================================================ -// add_filter_entry -//============================================================ - -static int add_filter_entry(char *dest, size_t dest_len, const char *description, const char *extensions) -{ - int pos = 0; - - // add the description - pos += snprintf(&dest[pos], dest_len - pos, "%s (", description); - - // add the extensions to the description - pos += copy_extension_list(&dest[pos], dest_len - pos, extensions); - - // add the trailing rparen and '|' character - pos += snprintf(&dest[pos], dest_len - pos, ")|"); - - // now add the extension list itself - pos += copy_extension_list(&dest[pos], dest_len - pos, extensions); - - // append a '|' - pos += snprintf(&dest[pos], dest_len - pos, "|"); - - return pos; -} -//============================================================ -// build_generic_filter -//============================================================ - -static void build_generic_filter(device_image_interface *img, int is_save, char *filter, size_t filter_len) -{ - char *s; - - const char *file_extension; - - /* copy the string */ - file_extension = img->file_extensions(); - - // start writing the filter - s = filter; - - // common image types - s += add_filter_entry(filter, filter_len, "Common image types", file_extension); - - // all files - s += sprintf(s, "All files (*.*)|*.*|"); - - // compressed - if (!is_save) - s += sprintf(s, "Compressed Images (*.zip)|*.zip|"); - - *(s++) = '\0'; -} - -//============================================================ -// global_handle_command -//============================================================ - -static int global_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lparam) -{ - if (HIWORD(wparam) == 0) - switch (LOWORD(wparam)) - { - case ID_NEW_MEMORY_WND: - memory_create_window(info->machine()); - return 1; - - case ID_NEW_DISASM_WND: - disasm_create_window(info->machine()); - return 1; - - case ID_NEW_LOG_WND: - log_create_window(info->machine()); - return 1; - - case ID_RUN_AND_HIDE: - smart_show_all(FALSE); - case ID_RUN: - debug_cpu_get_visible_cpu(info->machine())->debug()->go(); - return 1; - - case ID_NEXT_CPU: - debug_cpu_get_visible_cpu(info->machine())->debug()->go_next_device(); - return 1; - - case ID_RUN_VBLANK: - debug_cpu_get_visible_cpu(info->machine())->debug()->go_vblank(); - return 1; - - case ID_RUN_IRQ: - debug_cpu_get_visible_cpu(info->machine())->debug()->go_interrupt(); - return 1; - - case ID_STEP: - debug_cpu_get_visible_cpu(info->machine())->debug()->single_step(); - return 1; - - case ID_STEP_OVER: - debug_cpu_get_visible_cpu(info->machine())->debug()->single_step_over(); - return 1; - - case ID_STEP_OUT: - debug_cpu_get_visible_cpu(info->machine())->debug()->single_step_out(); - return 1; - - case ID_HARD_RESET: - info->machine().schedule_hard_reset(); - return 1; - - case ID_SOFT_RESET: - info->machine().schedule_soft_reset(); - debug_cpu_get_visible_cpu(info->machine())->debug()->go(); - return 1; - - case ID_EXIT: - if (info->focuswnd != NULL) - SetFocus(info->focuswnd); - info->machine().schedule_exit(); - return 1; - } - if (LOWORD(wparam) >= ID_DEVICE_OPTIONS) { - UINT32 devid = (LOWORD(wparam) - ID_DEVICE_OPTIONS) / DEVOPTION_MAX; - image_interface_iterator iter(info->machine().root_device()); - device_image_interface *img = iter.byindex(devid); - if (img!=NULL) { - switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX) - { - case DEVOPTION_OPEN : - { - char filter[2048]; - build_generic_filter(img, FALSE, filter, ARRAY_LENGTH(filter)); - - TCHAR selectedFilename[MAX_PATH]; - selectedFilename[0] = '\0'; - LPTSTR buffer; - LPTSTR t_filter = NULL; - - buffer = tstring_from_utf8(filter); - - // convert a pipe-char delimited string into a NUL delimited string - t_filter = (LPTSTR) alloca((_tcslen(buffer) + 2) * sizeof(*t_filter)); - int i = 0; - for (i = 0; buffer[i] != '\0'; i++) - t_filter[i] = (buffer[i] != '|') ? buffer[i] : '\0'; - t_filter[i++] = '\0'; - t_filter[i++] = '\0'; - osd_free(buffer); - - - OPENFILENAME ofn; - memset(&ofn,0,sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = NULL; - ofn.lpstrFile = selectedFilename; - ofn.lpstrFile[0] = '\0'; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrFilter = t_filter; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - - if (GetOpenFileName(&ofn)) { - img->load(utf8_from_tstring(selectedFilename)); - } - } - return 1; -/* case DEVOPTION_CREATE: - return 1;*/ - case DEVOPTION_CLOSE: - img->unload(); - return 1; - default: - if (img->device().type() == CASSETTE) { - cassette_image_device* cassette = dynamic_cast<cassette_image_device*>(&img->device()); - switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX) - { - case DEVOPTION_CASSETTE_STOPPAUSE: - cassette->change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); - return 1; - case DEVOPTION_CASSETTE_PLAY: - cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); - return 1; - case DEVOPTION_CASSETTE_RECORD: - cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); - return 1; - case DEVOPTION_CASSETTE_REWIND: - cassette->seek(-60.0, SEEK_CUR); - return 1; - case DEVOPTION_CASSETTE_FASTFORWARD: - cassette->seek(+60.0, SEEK_CUR); - return 1; - } - } - } - } - } - return 0; -} - - - -//============================================================ -// global_handle_key -//============================================================ - -static int global_handle_key(debugwin_info *info, WPARAM wparam, LPARAM lparam) -{ - /* ignore any keys that are received while the debug key is down */ - if (!waiting_for_debugger && debugwin_seq_pressed(info->machine())) - return 1; - - switch (wparam) - { - case VK_F3: - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - SendMessage(info->wnd, WM_COMMAND, ID_HARD_RESET, 0); - else - SendMessage(info->wnd, WM_COMMAND, ID_SOFT_RESET, 0); - return 1; - - case VK_F4: - if (GetAsyncKeyState(VK_MENU) & 0x8000) - { - /* ajg - never gets here since 'alt' seems to be captured somewhere else - menu maybe? */ - SendMessage(info->wnd, WM_COMMAND, ID_EXIT, 0); - return 1; - } - break; - - case VK_F5: - SendMessage(info->wnd, WM_COMMAND, ID_RUN, 0); - return 1; - - case VK_F6: - SendMessage(info->wnd, WM_COMMAND, ID_NEXT_CPU, 0); - return 1; - - case VK_F7: - SendMessage(info->wnd, WM_COMMAND, ID_RUN_IRQ, 0); - return 1; - - case VK_F8: - SendMessage(info->wnd, WM_COMMAND, ID_RUN_VBLANK, 0); - return 1; - - case VK_F10: - SendMessage(info->wnd, WM_COMMAND, ID_STEP_OVER, 0); - return 1; - - case VK_F11: - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - SendMessage(info->wnd, WM_COMMAND, ID_STEP_OUT, 0); - else - SendMessage(info->wnd, WM_COMMAND, ID_STEP, 0); - return 1; - - case VK_F12: - SendMessage(info->wnd, WM_COMMAND, ID_RUN_AND_HIDE, 0); - return 1; - - case 'M': - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - SendMessage(info->wnd, WM_COMMAND, ID_NEW_MEMORY_WND, 0); - return 1; - } - break; - - case 'D': - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - SendMessage(info->wnd, WM_COMMAND, ID_NEW_DISASM_WND, 0); - return 1; - } - break; - - case 'L': - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - SendMessage(info->wnd, WM_COMMAND, ID_NEW_LOG_WND, 0); - return 1; - } - break; - } - - return 0; -} - - - -//============================================================ -// smart_set_window_bounds -//============================================================ - -static void smart_set_window_bounds(HWND wnd, HWND parent, RECT *bounds) -{ - RECT curbounds; - int flags = 0; - - // first get the current bounds, relative to the parent - GetWindowRect(wnd, &curbounds); - if (parent != NULL) - { - RECT parentbounds; - GetWindowRect(parent, &parentbounds); - curbounds.top -= parentbounds.top; - curbounds.bottom -= parentbounds.top; - curbounds.left -= parentbounds.left; - curbounds.right -= parentbounds.left; - } - - // if the position matches, don't change it - if (curbounds.top == bounds->top && curbounds.left == bounds->left) - flags |= SWP_NOMOVE; - if ((curbounds.bottom - curbounds.top) == (bounds->bottom - bounds->top) && - (curbounds.right - curbounds.left) == (bounds->right - bounds->left)) - flags |= SWP_NOSIZE; - - // if we need to, reposition the window - if (flags != (SWP_NOMOVE | SWP_NOSIZE)) - SetWindowPos(wnd, NULL, - bounds->left, bounds->top, - bounds->right - bounds->left, bounds->bottom - bounds->top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags); } - -//============================================================ -// smart_show_window -//============================================================ - -static void smart_show_window(HWND wnd, BOOL show) -{ - BOOL visible = IsWindowVisible(wnd); - if ((visible && !show) || (!visible && show)) - ShowWindow(wnd, show ? SW_SHOW : SW_HIDE); -} - - - -//============================================================ -// smart_show_all -//============================================================ - -static void smart_show_all(BOOL show) -{ - debugwin_info *info; - if (!show) - SetForegroundWindow(win_window_list->m_hwnd); - for (info = window_list; info != NULL; info = info->next) - smart_show_window(info->wnd, show); -} #else /* not windows */ - MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows") +MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows") #endif MODULE_DEFINITION(DEBUG_WINDOWS, debugger_windows) diff --git a/src/osd/modules/debugger/osx/debugview.m b/src/osd/modules/debugger/osx/debugview.m index dbe0bc271a8..92e483bc606 100644 --- a/src/osd/modules/debugger/osx/debugview.m +++ b/src/osd/modules/debugger/osx/debugview.m @@ -540,7 +540,6 @@ static void debugwin_view_update(debug_view &view, void *osdprivate) : (modifiers & NSAlternateKeyMask) ? DCK_MIDDLE_CLICK : DCK_LEFT_CLICK, [self convertLocation:location]); - [self setNeedsDisplay:YES]; } diff --git a/src/osd/modules/debugger/win/consolewininfo.c b/src/osd/modules/debugger/win/consolewininfo.c new file mode 100644 index 00000000000..771f2d604ce --- /dev/null +++ b/src/osd/modules/debugger/win/consolewininfo.c @@ -0,0 +1,373 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// consolewininfo.c - Win32 debug window handling +// +//============================================================ + +#include "consolewininfo.h" + +#include "debugviewinfo.h" +#include "disasmviewinfo.h" +#include "uimetrics.h" + +#include "debug/debugcon.h" +#include "debug/debugcpu.h" +#include "imagedev/cassette.h" + +#include "strconv.h" +#include "winutf8.h" + + +consolewin_info::consolewin_info(debugger_windows_interface &debugger) : + disasmbasewin_info(debugger, true, "Debug", NULL), + m_devices_menu(NULL) +{ + if ((window() == NULL) || (m_views[0] == NULL)) + goto cleanup; + + // create the views + m_views[1].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_STATE))); + if (!m_views[1]->is_valid()) + goto cleanup; + m_views[2].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_CONSOLE))); + if (!m_views[2]->is_valid()) + goto cleanup; + + { + // Add image menu only if image devices exist + image_interface_iterator iter(machine().root_device()); + device_image_interface *img = iter.first(); + if (img != NULL) + { + m_devices_menu = CreatePopupMenu(); + for ( ; img != NULL; img = iter.next()) + { + astring temp; + temp.format("%s : %s", img->device().name(), img->exists() ? img->filename() : "[no image]"); + TCHAR *tc_buf = tstring_from_utf8(temp); + if (tc_buf != NULL) + { + AppendMenu(m_devices_menu, MF_ENABLED, 0, tc_buf); + osd_free(tc_buf); + } + } + AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)m_devices_menu, TEXT("Images")); + } + + // get the work bounds + RECT work_bounds, bounds; + SystemParametersInfo(SPI_GETWORKAREA, 0, &work_bounds, 0); + + // adjust the min/max sizes for the window style + bounds.top = bounds.left = 0; + bounds.right = bounds.bottom = EDGE_WIDTH + m_views[1]->maxwidth() + (2 * EDGE_WIDTH) + 100 + EDGE_WIDTH; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + set_minwidth(bounds.right - bounds.left); + + bounds.top = bounds.left = 0; + bounds.right = bounds.bottom = EDGE_WIDTH + m_views[1]->maxwidth() + (2 * EDGE_WIDTH) + MAX(m_views[0]->maxwidth(), m_views[2]->maxwidth()) + EDGE_WIDTH; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + set_maxwidth(bounds.right - bounds.left); + + // position the window at the bottom-right + int const bestwidth = MIN(maxwidth(), work_bounds.right - work_bounds.left); + int const bestheight = MIN(500, work_bounds.bottom - work_bounds.top); + SetWindowPos(window(), HWND_TOP, + work_bounds.right - bestwidth, work_bounds.bottom - bestheight, + bestwidth, bestheight, + SWP_SHOWWINDOW); + } + + // recompute the children + set_cpu(*debug_cpu_get_visible_cpu(machine())); + + // mark the edit box as the default focus and set it + set_default_focus(); + return; + +cleanup: + m_views[2].reset(); + m_views[1].reset(); + m_views[0].reset(); +} + + +consolewin_info::~consolewin_info() +{ +} + + +void consolewin_info::set_cpu(device_t &device) +{ + // first set all the views to the new cpu number + m_views[0]->set_source_for_device(device); + m_views[1]->set_source_for_device(device); + + // then update the caption + char curtitle[256]; + astring title; + + title.printf("Debug: %s - %s '%s'", device.machine().system().name, device.name(), device.tag()); + win_get_window_text_utf8(window(), curtitle, ARRAY_LENGTH(curtitle)); + if (title.cmp(curtitle) != 0) + win_set_window_text_utf8(window(), title); + + // and recompute the children + recompute_children(); +} + + +void consolewin_info::recompute_children() +{ + // get the parent's dimensions + RECT parent; + GetClientRect(window(), &parent); + + // registers always get their desired width, and span the entire height + RECT regrect; + regrect.top = parent.top + EDGE_WIDTH; + regrect.bottom = parent.bottom - EDGE_WIDTH; + regrect.left = parent.left + EDGE_WIDTH; + regrect.right = regrect.left + m_views[1]->maxwidth(); + + // edit box goes at the bottom of the remaining area + RECT editrect; + editrect.bottom = parent.bottom - EDGE_WIDTH; + editrect.top = editrect.bottom - metrics().debug_font_height() - 4; + editrect.left = regrect.right + (EDGE_WIDTH * 2); + editrect.right = parent.right - EDGE_WIDTH; + + // console and disassembly split the difference + RECT disrect; + disrect.top = parent.top + EDGE_WIDTH; + disrect.bottom = ((editrect.top - parent.top) / 2) - EDGE_WIDTH; + disrect.left = regrect.right + (EDGE_WIDTH * 2); + disrect.right = parent.right - EDGE_WIDTH; + + RECT conrect; + conrect.top = disrect.bottom + (EDGE_WIDTH * 2); + conrect.bottom = editrect.top - EDGE_WIDTH; + conrect.left = regrect.right + (EDGE_WIDTH * 2); + conrect.right = parent.right - EDGE_WIDTH; + + // set the bounds of things + m_views[0]->set_bounds(disrect); + m_views[1]->set_bounds(regrect); + m_views[2]->set_bounds(conrect); + set_editwnd_bounds(editrect); +} + + +void consolewin_info::update_menu() +{ + disasmbasewin_info::update_menu(); + + if (m_devices_menu != NULL) + { + // create the image menu + image_interface_iterator iter(machine().root_device()); + device_image_interface *img; + UINT32 cnt; + for (img = iter.first(), cnt = 0; img != NULL; img = iter.next(), cnt++) + { + HMENU const devicesubmenu = CreatePopupMenu(); + + UINT_PTR const new_item = ID_DEVICE_OPTIONS + (cnt * DEVOPTION_MAX); + + UINT flags_for_exists = MF_ENABLED | MF_STRING; + if (!img->exists()) + flags_for_exists |= MF_GRAYED; + + UINT flags_for_writing = flags_for_exists; + if (img->is_readonly()) + flags_for_writing |= MF_GRAYED; + + AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_OPEN, TEXT("Mount...")); + + //if (img->is_creatable()) + //AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_CREATE, TEXT("Create...")); + AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CLOSE, TEXT("Unmount")); + + if (img->device().type() == CASSETTE) + { + cassette_state const state = (cassette_state)(img->exists() ? (downcast<cassette_image_device *>(&img->device())->get_state() & CASSETTE_MASK_UISTATE) : CASSETTE_STOPPED); + AppendMenu(devicesubmenu, MF_SEPARATOR, 0, NULL); + AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_STOPPED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_STOPPAUSE, TEXT("Pause/Stop")); + AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_PLAY) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_PLAY, TEXT("Play")); + AppendMenu(devicesubmenu, flags_for_writing | ((state == CASSETTE_RECORD) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_RECORD, TEXT("Record")); + AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_REWIND, TEXT("Rewind")); + AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_FASTFORWARD, TEXT("Fast Forward")); + } + + astring temp; + temp.format("%s :%s", img->device().name(), img->exists() ? img->filename() : "[empty slot]"); + TCHAR *tc_buf = tstring_from_utf8(temp); + if (tc_buf != NULL) + { + ModifyMenu(m_devices_menu, cnt, MF_BYPOSITION | MF_POPUP, (UINT_PTR)devicesubmenu, tc_buf); + osd_free(tc_buf); + } + } + } +} + + +bool consolewin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + if ((HIWORD(wparam) == 0) && (LOWORD(wparam) >= ID_DEVICE_OPTIONS)) + { + UINT32 const devid = (LOWORD(wparam) - ID_DEVICE_OPTIONS) / DEVOPTION_MAX; + image_interface_iterator iter(machine().root_device()); + device_image_interface *const img = iter.byindex(devid); + if (img != NULL) + { + switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX) + { + case DEVOPTION_OPEN : + { + astring filter; + build_generic_filter(img, false, filter); + LPTSTR t_filter = tstring_from_utf8(filter); + if (t_filter) + { + // convert a pipe-char delimited string into a NUL delimited string + for (int i = 0; t_filter[i] != '\0'; i++) + { + if (t_filter[i] == '|') + t_filter[i] = '\0'; + } + + TCHAR selectedFilename[MAX_PATH]; + selectedFilename[0] = '\0'; + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFile = selectedFilename; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrFilter = t_filter; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + if (GetOpenFileName(&ofn)) + { + char *utf8_buf = utf8_from_tstring(selectedFilename); + if (utf8_buf != NULL) + { + img->load(utf8_buf); + osd_free(utf8_buf); + } + } + osd_free(t_filter); + } + } + return true; + //case DEVOPTION_CREATE: + //return true; + case DEVOPTION_CLOSE: + img->unload(); + return 1; + } + if (img->device().type() == CASSETTE) + { + cassette_image_device *const cassette = downcast<cassette_image_device *>(&img->device()); + switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX) + { + case DEVOPTION_CASSETTE_STOPPAUSE: + cassette->change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); + return true; + case DEVOPTION_CASSETTE_PLAY: + cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); + return true; + case DEVOPTION_CASSETTE_RECORD: + cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); + return true; + case DEVOPTION_CASSETTE_REWIND: + cassette->seek(-60.0, SEEK_CUR); + return true; + case DEVOPTION_CASSETTE_FASTFORWARD: + cassette->seek(+60.0, SEEK_CUR); + return true; + } + } + } + } + return disasmbasewin_info::handle_command(wparam, lparam); +} + + +void consolewin_info::process_string(char const *string) +{ + if (string[0] == 0) // an empty string is a single step + debug_cpu_get_visible_cpu(machine())->debug()->single_step(); + else // otherwise, just process the command + debug_console_execute_command(machine(), string, 1); + + // clear the edit text box + set_editwnd_text(""); +} + + +void consolewin_info::build_generic_filter(device_image_interface *img, bool is_save, astring &filter) +{ + // common image types + add_filter_entry(filter, "Common image types", img->file_extensions()); + + // compressed + if (!is_save) + filter.cat("Compressed Images (*.zip)|*.zip|"); + + // all files + filter.cat("All files (*.*)|*.*|"); +} + + +void consolewin_info::add_filter_entry(astring &dest, const char *description, const char *extensions) +{ + // add the description + dest.cat(description); + dest.catformat(" ("); + + // add the extensions to the description + copy_extension_list(dest, extensions); + + // add the trailing rparen and '|' character + dest.cat(")|"); + + // now add the extension list itself + copy_extension_list(dest, extensions); + + // append a '|' + dest.cat('|'); +} + + +void consolewin_info::copy_extension_list(astring &dest, const char *extensions) +{ + // our extension lists are comma delimited; Win32 expects to see lists + // delimited by semicolons + char const *s = extensions; + while (*s) + { + // append a semicolon if not at the beginning + if (s != extensions) + dest.cat(';'); + + // append ".*" + dest.cat("*."); + + // append the file extension + while (*s && (*s != ',')) + dest.cat(*s++); + + // if we found a comma, advance + while(*s == ',') + s++; + } +} diff --git a/src/osd/modules/debugger/win/consolewininfo.h b/src/osd/modules/debugger/win/consolewininfo.h new file mode 100644 index 00000000000..08790fb66b3 --- /dev/null +++ b/src/osd/modules/debugger/win/consolewininfo.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// consolewininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_CONSOLE_WIN_INFO_H__ +#define __DEBUG_WIN_CONSOLE_WIN_INFO_H__ + +#include "debugwin.h" + +#include "disasmbasewininfo.h" + + +class consolewin_info : public disasmbasewin_info +{ +public: + consolewin_info(debugger_windows_interface &debugger); + virtual ~consolewin_info(); + + void set_cpu(device_t &device); + +protected: + virtual void recompute_children(); + virtual void update_menu(); + virtual bool handle_command(WPARAM wparam, LPARAM lparam); + +private: + enum + { + DEVOPTION_OPEN, + DEVOPTION_CREATE, + DEVOPTION_CLOSE, + DEVOPTION_CASSETTE_STOPPAUSE, + DEVOPTION_CASSETTE_PLAY, + DEVOPTION_CASSETTE_RECORD, + DEVOPTION_CASSETTE_REWIND, + DEVOPTION_CASSETTE_FASTFORWARD, + DEVOPTION_MAX + }; + + virtual void process_string(char const *string); + + static void build_generic_filter(device_image_interface *img, bool is_save, astring &filter); + static void add_filter_entry(astring &dest, char const *description, char const *extensions); + static void copy_extension_list(astring &dest, char const *extensions); + + HMENU m_devices_menu; +}; + +#endif diff --git a/src/osd/modules/debugger/win/debugbaseinfo.c b/src/osd/modules/debugger/win/debugbaseinfo.c new file mode 100644 index 00000000000..34451875063 --- /dev/null +++ b/src/osd/modules/debugger/win/debugbaseinfo.c @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugbaseinfo.c - Win32 debug window handling +// +//============================================================ + +#include "debugbaseinfo.h" + + +debugbase_info::debugbase_info(debugger_windows_interface &debugger) : + m_debugger(debugger), + m_machine(debugger.machine()), + m_metrics(debugger.metrics()), + m_waiting_for_debugger(debugger.waiting_for_debugger()) +{ +} + + +void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &bounds) +{ + RECT curbounds; + int flags = 0; + + // first get the current bounds, relative to the parent + GetWindowRect(wnd, &curbounds); + if (parent != NULL) + { + RECT parentbounds; + GetWindowRect(parent, &parentbounds); + curbounds.top -= parentbounds.top; + curbounds.bottom -= parentbounds.top; + curbounds.left -= parentbounds.left; + curbounds.right -= parentbounds.left; + } + + // if the position matches, don't change it + if (curbounds.top == bounds.top && curbounds.left == bounds.left) + flags |= SWP_NOMOVE; + if ((curbounds.bottom - curbounds.top) == (bounds.bottom - bounds.top) && + (curbounds.right - curbounds.left) == (bounds.right - bounds.left)) + flags |= SWP_NOSIZE; + + // if we need to, reposition the window + if (flags != (SWP_NOMOVE | SWP_NOSIZE)) + SetWindowPos(wnd, NULL, + bounds.left, bounds.top, + bounds.right - bounds.left, bounds.bottom - bounds.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags); +} + + + +void debugbase_info::smart_show_window(HWND wnd, bool show) +{ + BOOL const visible = IsWindowVisible(wnd); + if ((visible && !show) || (!visible && show)) + ShowWindow(wnd, show ? SW_SHOW : SW_HIDE); +} diff --git a/src/osd/modules/debugger/win/debugbaseinfo.h b/src/osd/modules/debugger/win/debugbaseinfo.h new file mode 100644 index 00000000000..9aee28b49ef --- /dev/null +++ b/src/osd/modules/debugger/win/debugbaseinfo.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugbaseinfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DEBUG_BASE_INFO_H__ +#define __DEBUG_WIN_DEBUG_BASE_INFO_H__ + +#include "debugwin.h" + +#include "emu.h" + + +class debugbase_info +{ +protected: + debugbase_info(debugger_windows_interface &debugger); + + debugger_windows_interface &debugger() const { return m_debugger; } + running_machine &machine() const { return m_machine; } + ui_metrics const &metrics() const { return m_metrics; } + + bool waiting_for_debugger() const { return m_waiting_for_debugger; } + bool seq_pressed() const { return m_debugger.seq_pressed(); } + + static void smart_set_window_bounds(HWND wnd, HWND parent, RECT const &bounds); + static void smart_show_window(HWND wnd, bool show); + +private: + debugger_windows_interface &m_debugger; + running_machine &m_machine; + ui_metrics const &m_metrics; + bool const &m_waiting_for_debugger; +}; + + +#endif diff --git a/src/osd/modules/debugger/win/debugviewinfo.c b/src/osd/modules/debugger/win/debugviewinfo.c new file mode 100644 index 00000000000..e474ab5ebcb --- /dev/null +++ b/src/osd/modules/debugger/win/debugviewinfo.c @@ -0,0 +1,809 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugview.c - Win32 debug window handling +// +//============================================================ + +#include "debugviewinfo.h" + +#include "debugwininfo.h" +#include "uimetrics.h" + +#include "debug/debugcpu.h" + +#include "strconv.h" + + +// debugger view styles +#define DEBUG_VIEW_STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN +#define DEBUG_VIEW_STYLE_EX 0 + +// combo box styles +#define COMBO_BOX_STYLE WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL +#define COMBO_BOX_STYLE_EX 0 + +// horizontal scroll bar styles +#define HSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_HORZ +#define HSCROLL_STYLE_EX 0 + +// vertical scroll bar styles +#define VSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_VERT +#define VSCROLL_STYLE_EX 0 + + +bool debugview_info::s_window_class_registered = false; + + +debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent, debug_view_type type) : + debugbase_info(debugger), + m_owner(owner), + m_view(NULL), + m_wnd(NULL), + m_hscroll(NULL), + m_vscroll(NULL) +{ + register_window_class(); + + // create the child view + m_wnd = CreateWindowEx(DEBUG_VIEW_STYLE_EX, TEXT("MAMEDebugView"), NULL, DEBUG_VIEW_STYLE, + 0, 0, 100, 100, parent, NULL, GetModuleHandle(NULL), this); + if (m_wnd == NULL) + goto cleanup; + + // create the scroll bars + m_hscroll = CreateWindowEx(HSCROLL_STYLE_EX, TEXT("SCROLLBAR"), NULL, HSCROLL_STYLE, + 0, 0, 100, CW_USEDEFAULT, m_wnd, NULL, GetModuleHandle(NULL), this); + m_vscroll = CreateWindowEx(VSCROLL_STYLE_EX, TEXT("SCROLLBAR"), NULL, VSCROLL_STYLE, + 0, 0, CW_USEDEFAULT, 100, m_wnd, NULL, GetModuleHandle(NULL), this); + if ((m_hscroll == NULL) || (m_vscroll == NULL)) + goto cleanup; + + // create the debug view + m_view = machine().debug_view().alloc_view(type, &debugview_info::static_update, this); + if (m_view == NULL) + goto cleanup; + + return; + +cleanup: + if (m_view != NULL) + machine().debug_view().free_view(*m_view); + m_view = NULL; + if (m_hscroll != NULL) + DestroyWindow(m_hscroll); + m_hscroll = NULL; + if (m_vscroll != NULL) + DestroyWindow(m_vscroll); + m_vscroll = NULL; + if (m_wnd != NULL) + DestroyWindow(m_wnd); + m_wnd = NULL; +} + + +debugview_info::~debugview_info() +{ + if (m_view) + machine().debug_view().free_view(*m_view); + if (m_wnd != NULL) + DestroyWindow(m_wnd); +} + + +bool debugview_info::is_valid() const +{ + return m_view && m_hscroll && m_vscroll && m_wnd; +} + + +UINT32 debugview_info::prefwidth() const +{ + return (m_view->total_size().x * metrics().debug_font_width()) + metrics().vscroll_width(); +} + + +UINT32 debugview_info::maxwidth() +{ + UINT32 max = m_view->total_size().x; + debug_view_source const *const cursource = m_view->source(); + for (debug_view_source const *source = m_view->first_source(); source != NULL; source = source->next()) + { + m_view->set_source(*source); + UINT32 const chars = m_view->total_size().x; + if (max < chars) + max = chars; + } + if (cursource != NULL) + m_view->set_source(*cursource); + return (max * metrics().debug_font_width()) + metrics().vscroll_width(); +} + + +void debugview_info::get_bounds(RECT &bounds) const +{ + GetWindowRect(m_wnd, &bounds); +} + + +void debugview_info::set_bounds(RECT const &newbounds) +{ + // account for the edges and set the bounds + if (m_wnd) + smart_set_window_bounds(m_wnd, GetParent(m_wnd), newbounds); + + // update + update(); +} + + +void debugview_info::send_vscroll(int delta) +{ + if (m_vscroll) + { + int message_type = SB_LINEUP; + if (delta < 0) + { + message_type = SB_LINEDOWN; + delta = -delta; + } + while (delta > 0) + { + SendMessage(m_wnd, WM_VSCROLL, message_type, (LPARAM)m_vscroll); + delta--; + } + } +} + + +void debugview_info::send_pageup() +{ + if (m_vscroll) + { + SendMessage(m_wnd, WM_VSCROLL, SB_PAGELEFT, (LPARAM)m_vscroll); + } +} + + +void debugview_info::send_pagedown() +{ + if (m_vscroll) + { + SendMessage(m_wnd, WM_VSCROLL, SB_PAGERIGHT, (LPARAM)m_vscroll); + } +} + + +char const *debugview_info::source_name() const +{ + if (m_view != NULL) + { + debug_view_source const *const source = m_view->source(); + if (source != NULL) + return source->name(); + } + return ""; +} + + +device_t *debugview_info::source_device() const +{ + if (m_view != NULL) + { + debug_view_source const *const source = m_view->source(); + if (source != NULL) + return source->device(); + } + return NULL; +} + + +bool debugview_info::source_is_visible_cpu() const +{ + if (m_view != NULL) + { + const debug_view_source *const source = m_view->source(); + return (source != NULL) && (debug_cpu_get_visible_cpu(machine()) == source->device()); + } + return false; +} + + +bool debugview_info::set_source_index(int index) +{ + if (m_view != NULL) + { + const debug_view_source *const source = m_view->source_list().find(index); + if (source != NULL) + { + m_view->set_source(*source); + return true; + } + } + return false; +} + + +bool debugview_info::set_source_for_device(device_t &device) +{ + if (m_view != NULL) + { + const debug_view_source *const source = m_view->source_for_device(&device); + if (source != NULL) + { + m_view->set_source(*source); + return true; + } + } + return false; +} + + +bool debugview_info::set_source_for_visible_cpu() +{ + device_t *const curcpu = debug_cpu_get_visible_cpu(machine()); + if (curcpu != NULL) + return set_source_for_device(*curcpu); + else + return false; +} + + +HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata) +{ + // create a combo box + HWND const result = CreateWindowEx(COMBO_BOX_STYLE_EX, TEXT("COMBOBOX"), NULL, COMBO_BOX_STYLE, + 0, 0, 100, 1000, parent, NULL, GetModuleHandle(NULL), NULL); + SetWindowLongPtr(result, GWLP_USERDATA, userdata); + SendMessage(result, WM_SETFONT, (WPARAM)metrics().debug_font(), (LPARAM)FALSE); + + // populate the combobox + debug_view_source const *const cursource = m_view->source(); + int maxlength = 0; + for (debug_view_source const *source = m_view->first_source(); source != NULL; source = source->next()) + { + int const length = strlen(source->name()); + if (length > maxlength) + maxlength = length; + TCHAR *t_name = tstring_from_utf8(source->name()); + SendMessage(result, CB_ADDSTRING, 0, (LPARAM)t_name); + osd_free(t_name); + } + if (cursource != NULL) + { + SendMessage(result, CB_SETCURSEL, m_view->source_list().indexof(*cursource), 0); + SendMessage(result, CB_SETDROPPEDWIDTH, ((maxlength + 2) * metrics().debug_font_width()) + metrics().vscroll_width(), 0); + m_view->set_source(*cursource); + } + return result; +} + + +void debugview_info::draw_contents(HDC windc) +{ + debug_view_char const *viewdata = m_view->viewdata(); + debug_view_xy const visarea = m_view->visible_size(); + + // get the client rect + RECT client; + GetClientRect(m_wnd, &client); + + // create a compatible DC and an offscreen bitmap + HDC const dc = CreateCompatibleDC(windc); + if (dc == NULL) + return; + HBITMAP const bitmap = CreateCompatibleBitmap(windc, client.right, client.bottom); + if (bitmap == NULL) + { + DeleteDC(dc); + return; + } + HGDIOBJ const oldbitmap = SelectObject(dc, bitmap); + + // set the font + HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font()); + COLORREF const oldfgcolor = GetTextColor(dc); + int const oldbkmode = GetBkMode(dc); + SetBkMode(dc, TRANSPARENT); + + // iterate over rows and columns + for (UINT32 row = 0; row < visarea.y; row++) + { + + // loop twice; once to fill the background and once to draw the text + for (int iter = 0; iter < 2; iter++) + { + COLORREF fgcolor = RGB(0x00,0x00,0x00); + COLORREF bgcolor = RGB(0xff,0xff,0xff); + HBRUSH bgbrush = NULL; + int last_attrib = -1; + TCHAR buffer[256]; + int count = 0; + RECT bounds; + + // initialize the text bounds + bounds.left = bounds.right = 0; + bounds.top = row * metrics().debug_font_height(); + bounds.bottom = bounds.top + metrics().debug_font_height(); + + // start with a brush on iteration #0 + if (iter == 0) + bgbrush = CreateSolidBrush(bgcolor); + + // iterate over columns + for (UINT32 col = 0; col < visarea.x; col++) + { + // if the attribute changed, adjust the colors + if (viewdata[col].attrib != last_attrib) + { + COLORREF oldbg = bgcolor; + + // reset to standard colors + fgcolor = RGB(0x00,0x00,0x00); + bgcolor = RGB(0xff,0xff,0xff); + + // pick new fg/bg colors + if (viewdata[col].attrib & DCA_VISITED) bgcolor = RGB(0xc6, 0xe2, 0xff); + if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0); + if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80); + if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00); + if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80); + if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00); + if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff); + if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2); + if (viewdata[col].attrib & DCA_COMMENT) fgcolor = RGB(0x00,0x80,0x00); + + // flush any pending drawing + if (count > 0) + { + bounds.right = bounds.left + (count * metrics().debug_font_width()); + if (iter == 0) + FillRect(dc, &bounds, bgbrush); + else + ExtTextOut(dc, bounds.left, bounds.top, 0, NULL, buffer, count, NULL); + bounds.left = bounds.right; + count = 0; + } + + // set the new colors + if (iter == 0 && oldbg != bgcolor) + { + DeleteObject(bgbrush); + bgbrush = CreateSolidBrush(bgcolor); + } + else if (iter == 1) + SetTextColor(dc, fgcolor); + last_attrib = viewdata[col].attrib; + } + + // add this character to the buffer + buffer[count++] = viewdata[col].byte; + } + + // flush any remaining stuff + if (count > 0) + { + bounds.right = bounds.left + (count * metrics().debug_font_width()); + if (iter == 0) + FillRect(dc, &bounds, bgbrush); + else + ExtTextOut(dc, bounds.left, bounds.top, 0, NULL, buffer, count, NULL); + } + + // erase to the end of the line + if (iter == 0) + { + bounds.left = bounds.right; + bounds.right = client.right; + FillRect(dc, &bounds, bgbrush); + DeleteObject(bgbrush); + } + } + + // advance viewdata + viewdata += visarea.x; + } + + // erase anything beyond the bottom with white + GetClientRect(m_wnd, &client); + client.top = visarea.y * metrics().debug_font_height(); + FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH)); + + // reset the font + SetBkMode(dc, oldbkmode); + SetTextColor(dc, oldfgcolor); + SelectObject(dc, oldfont); + + // blit the final results + BitBlt(windc, 0, 0, client.right, client.bottom, dc, 0, 0, SRCCOPY); + + // undo the offscreen stuff + SelectObject(dc, oldbitmap); + DeleteObject(bitmap); + DeleteDC(dc); +} + + +void debugview_info::update() +{ + RECT bounds, vscroll_bounds, hscroll_bounds; + debug_view_xy totalsize, visiblesize, topleft; + bool show_vscroll, show_hscroll; + SCROLLINFO scrollinfo; + + // get the view window bounds + GetClientRect(m_wnd, &bounds); + visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); + visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); + + // get the updated total rows/cols and left row/col + totalsize = m_view->total_size(); + topleft = m_view->visible_position(); + + // determine if we need to show the scrollbars + show_vscroll = show_hscroll = false; + if (totalsize.x > visiblesize.x && bounds.bottom >= metrics().hscroll_height()) + { + bounds.bottom -= metrics().hscroll_height(); + visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); + show_hscroll = true; + } + if (totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width()) + { + bounds.right -= metrics().vscroll_width(); + visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); + show_vscroll = true; + } + if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width()) + { + bounds.right -= metrics().vscroll_width(); + visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); + show_vscroll = true; + } + + // compute the bounds of the scrollbars + GetClientRect(m_wnd, &vscroll_bounds); + vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width(); + if (show_hscroll) + vscroll_bounds.bottom -= metrics().hscroll_height(); + + GetClientRect(m_wnd, &hscroll_bounds); + hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height(); + if (show_vscroll) + hscroll_bounds.right -= metrics().vscroll_width(); + + // if we hid the scrollbars, make sure we reset the top/left corners + if (topleft.y + visiblesize.y > totalsize.y) + topleft.y = MAX(totalsize.y - visiblesize.y, 0); + if (topleft.x + visiblesize.x > totalsize.x) + topleft.x = MAX(totalsize.x - visiblesize.x, 0); + + // fill out the scroll info struct for the vertical scrollbar + scrollinfo.cbSize = sizeof(scrollinfo); + scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + scrollinfo.nMin = 0; + scrollinfo.nMax = totalsize.y - 1; + scrollinfo.nPage = visiblesize.y; + scrollinfo.nPos = topleft.y; + SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE); + + // fill out the scroll info struct for the horizontal scrollbar + scrollinfo.cbSize = sizeof(scrollinfo); + scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + scrollinfo.nMin = 0; + scrollinfo.nMax = totalsize.x - 1; + scrollinfo.nPage = visiblesize.x; + scrollinfo.nPos = topleft.x; + SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE); + + // update window info + visiblesize.y++; + visiblesize.x++; + m_view->set_visible_size(visiblesize); + m_view->set_visible_position(topleft); + + // invalidate the bounds + InvalidateRect(m_wnd, NULL, FALSE); + + // adjust the bounds of the scrollbars and show/hide them + if (m_vscroll) + { + if (show_vscroll) + smart_set_window_bounds(m_vscroll, m_wnd, vscroll_bounds); + smart_show_window(m_vscroll, show_vscroll); + } + if (m_hscroll) + { + if (show_hscroll) + smart_set_window_bounds(m_hscroll, m_wnd, hscroll_bounds); + smart_show_window(m_hscroll, show_hscroll); + } +} + + +UINT32 debugview_info::process_scroll(WORD type, HWND wnd) +{ + // get the current info + SCROLLINFO scrollinfo; + scrollinfo.cbSize = sizeof(scrollinfo); + scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; + GetScrollInfo(wnd, SB_CTL, &scrollinfo); + + // by default we stay put + INT32 result = scrollinfo.nPos; + + // determine the maximum value + INT32 const maxval = (scrollinfo.nMax > scrollinfo.nPage) ? (scrollinfo.nMax - scrollinfo.nPage + 1) : 0; + + // handle the message + switch (type) + { + case SB_THUMBTRACK: + result = scrollinfo.nTrackPos; + break; + + case SB_LEFT: + result = 0; + break; + + case SB_RIGHT: + result = maxval; + break; + + case SB_LINELEFT: + result -= 1; + break; + + case SB_LINERIGHT: + result += 1; + break; + + case SB_PAGELEFT: + result -= scrollinfo.nPage - 1; + break; + + case SB_PAGERIGHT: + result += scrollinfo.nPage - 1; + break; + } + + // generic rangecheck + if (result < 0) + result = 0; + if (result > maxval) + result = maxval; + + // set the new position + scrollinfo.fMask = SIF_POS; + scrollinfo.nPos = result; + SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE); + + return (UINT32)result; +} + + +LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) +{ + // handle a few messages + switch (message) + { + // paint: redraw the last bitmap + case WM_PAINT: + { + PAINTSTRUCT pstruct; + HDC const dc = BeginPaint(m_wnd, &pstruct); + draw_contents(dc); + EndPaint(m_wnd, &pstruct); + break; + } + + // keydown: handle debugger keys + case WM_SYSKEYDOWN: + if (wparam != VK_F10) + return DefWindowProc(m_wnd, message, wparam, lparam); + // (fall through) + case WM_KEYDOWN: + { + if (m_owner.handle_key(wparam, lparam)) + { + m_owner.set_ignore_char_lparam(lparam); + } + else + { + switch (wparam) + { + case VK_UP: + m_view->process_char(DCH_UP); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_DOWN: + m_view->process_char(DCH_DOWN); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_LEFT: + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + m_view->process_char(DCH_CTRLLEFT); + else + m_view->process_char(DCH_LEFT); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_RIGHT: + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + m_view->process_char(DCH_CTRLRIGHT); + else + m_view->process_char(DCH_RIGHT); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_PRIOR: + m_view->process_char(DCH_PUP); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_NEXT: + m_view->process_char(DCH_PDOWN); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_HOME: + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + m_view->process_char(DCH_CTRLHOME); + else + m_view->process_char(DCH_HOME); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_END: + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + m_view->process_char(DCH_CTRLEND); + else + m_view->process_char(DCH_END); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_ESCAPE: + m_owner.set_default_focus(); + m_owner.set_ignore_char_lparam(lparam); + break; + + case VK_TAB: + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + m_owner.prev_view(this); + else + m_owner.next_view(this); + m_owner.set_ignore_char_lparam(lparam); + break; + } + } + break; + } + + // char: ignore chars associated with keys we've handled + case WM_CHAR: + if (m_owner.check_ignore_char_lparam(lparam)) + { + if (waiting_for_debugger() || !seq_pressed()) + { + if (wparam >= 32 && wparam < 127) + { + if (m_view->cursor_supported()) + m_view->set_cursor_visible(true); + m_view->process_char(wparam); + } + else + { + return DefWindowProc(m_wnd, message, wparam, lparam); + } + } + } + break; + + // gaining focus + case WM_SETFOCUS: + if (m_view->cursor_supported()) + m_view->set_cursor_visible(true); + break; + + // losing focus + case WM_KILLFOCUS: + if (m_view->cursor_supported()) + m_view->set_cursor_visible(false); + break; + + // mouse click + case WM_LBUTTONDOWN: + { + debug_view_xy topleft = m_view->visible_position(); + debug_view_xy newpos; + newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(); + newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(); + m_view->process_click(DCK_LEFT_CLICK, newpos); + SetFocus(m_wnd); + break; + } + + // hscroll + case WM_HSCROLL: + { + debug_view_xy topleft = m_view->visible_position(); + topleft.x = process_scroll(LOWORD(wparam), (HWND)lparam); + m_view->set_visible_position(topleft); + machine().debug_view().flush_osd_updates(); + break; + } + + // vscroll + case WM_VSCROLL: + { + debug_view_xy topleft = m_view->visible_position(); + topleft.y = process_scroll(LOWORD(wparam), (HWND)lparam); + m_view->set_visible_position(topleft); + machine().debug_view().flush_osd_updates(); + break; + } + + // everything else: defaults + default: + return DefWindowProc(m_wnd, message, wparam, lparam); + } + + return 0; +} + + +void debugview_info::static_update(debug_view &view, void *osdprivate) +{ + debugview_info *const info = (debugview_info *)osdprivate; + assert(info->m_view == &view); + info->update(); +} + + +LRESULT CALLBACK debugview_info::static_view_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_CREATE) + { + // set the info pointer + CREATESTRUCT const *const createinfo = (CREATESTRUCT *)lparam; + SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams); + return 0; + } + + debugview_info *const info = (debugview_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); + if (!info) + return DefWindowProc(wnd, message, wparam, lparam); + + assert(info->m_wnd == wnd); + return info->view_proc(message, wparam, lparam); +} + + +void debugview_info::register_window_class() +{ + if (!s_window_class_registered) + { + WNDCLASS wc = { 0 }; + + // initialize the description of the window class + wc.lpszClassName = TEXT("MAMEDebugView"); + wc.hInstance = GetModuleHandle(NULL); + wc.lpfnWndProc = &debugview_info::static_view_proc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(2)); + wc.lpszMenuName = NULL; + wc.hbrBackground = NULL; + wc.style = 0; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + // register the class; fail if we can't + if (!RegisterClass(&wc)) + fatalerror("Unable to register debug view class\n"); + + s_window_class_registered = true; + } +} diff --git a/src/osd/modules/debugger/win/debugviewinfo.h b/src/osd/modules/debugger/win/debugviewinfo.h new file mode 100644 index 00000000000..d804554778a --- /dev/null +++ b/src/osd/modules/debugger/win/debugviewinfo.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugviewinfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DEBUG_VIEW_INFO_H__ +#define __DEBUG_WIN_DEBUG_VIEW_INFO_H__ + +#include "debugwin.h" + +#include "debugbaseinfo.h" + +#include "emu.h" +#include "debug/debugvw.h" + + +class debugview_info : protected debugbase_info +{ +public: + debugview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent, debug_view_type type); + virtual ~debugview_info(); + + bool is_valid() const; + + bool owns_window(HWND wnd) const { return m_wnd == wnd; } + + UINT32 prefwidth() const; + UINT32 maxwidth(); + void get_bounds(RECT &bounds) const; + void set_bounds(RECT const &newbounds); + + void send_vscroll(int delta); + void send_pageup(); + void send_pagedown(); + void set_focus() { SetFocus(m_wnd); } + + debug_view_type type() const { return m_view->type(); } + debug_view_xy total_size() const { return m_view->total_size(); } + bool cursor_supported() const { return m_view->cursor_supported(); } + bool cursor_visible() const { return m_view->cursor_visible(); } + + char const *source_name() const; + device_t *source_device() const; + bool source_is_visible_cpu() const; + bool set_source_index(int index); + bool set_source_for_device(device_t &device); + bool set_source_for_visible_cpu(); + + HWND create_source_combobox(HWND parent, LONG_PTR userdata); + +protected: + template <typename T> T *view() const { return downcast<T *>(m_view); } + +private: + void draw_contents(HDC windc); + void update(); + UINT32 process_scroll(WORD type, HWND wnd); + LRESULT view_proc(UINT message, WPARAM wparam, LPARAM lparam); + + static void static_update(debug_view &view, void *osdprivate); + static LRESULT CALLBACK static_view_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); + + static void register_window_class(); + + debugwin_info &m_owner; + debug_view *m_view; + HWND m_wnd; + HWND m_hscroll; + HWND m_vscroll; + + static bool s_window_class_registered; +}; + +#endif diff --git a/src/osd/modules/debugger/win/debugwin.h b/src/osd/modules/debugger/win/debugwin.h new file mode 100644 index 00000000000..6971e7f93c0 --- /dev/null +++ b/src/osd/modules/debugger/win/debugwin.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugwin.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DEBUG_WIN_H__ +#define __DEBUG_WIN_DEBUG_WIN_H__ + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <windowsx.h> +#include <tchar.h> +#include <commdlg.h> +#ifdef _MSC_VER +#include <zmouse.h> +#endif + +#include "emu.h" + + +class debugview_info; +class debugwin_info; +class ui_metrics; + + +class debugger_windows_interface +{ +public: + virtual ~debugger_windows_interface() { } + + virtual running_machine &machine() const = 0; + + virtual ui_metrics &metrics() const = 0; + + virtual bool const &waiting_for_debugger() const = 0; + virtual bool seq_pressed() const = 0; + + virtual void create_memory_window() = 0; + virtual void create_disasm_window() = 0; + virtual void create_log_window() = 0; + virtual void create_points_window() = 0; + virtual void remove_window(debugwin_info &info) = 0; + + virtual void show_all() = 0; + virtual void hide_all() = 0; +}; + +#endif diff --git a/src/osd/modules/debugger/win/debugwininfo.c b/src/osd/modules/debugger/win/debugwininfo.c new file mode 100644 index 00000000000..3c32db35d9c --- /dev/null +++ b/src/osd/modules/debugger/win/debugwininfo.c @@ -0,0 +1,599 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugwininfo.c - Win32 debug window handling +// +//============================================================ + +#include "debugwininfo.h" + +#include "debugviewinfo.h" + +#include "debug/debugcpu.h" +#include "imagedev/cassette.h" + +#include "strconv.h" +#include "window.h" +#include "winutf8.h" + + +bool debugwin_info::s_window_class_registered = false; + + +debugwin_info::debugwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler) : + debugbase_info(debugger), + m_is_main_console(is_main_console), + m_next(NULL), + m_wnd(NULL), + m_handler(handler), + m_minwidth(200), + m_maxwidth(0), + m_minheight(200), + m_maxheight(0), + m_ignore_char_lparam(0) +{ + register_window_class(); + + m_wnd = win_create_window_ex_utf8(DEBUG_WINDOW_STYLE_EX, "MAMEDebugWindow", title, DEBUG_WINDOW_STYLE, + 0, 0, 100, 100, win_window_list->m_hwnd, create_standard_menubar(), GetModuleHandle(NULL), this); + if (m_wnd == NULL) + return; + + RECT work_bounds; + SystemParametersInfo(SPI_GETWORKAREA, 0, &work_bounds, 0); + m_maxwidth = work_bounds.right - work_bounds.left; + m_maxheight = work_bounds.bottom - work_bounds.top; +} + + +debugwin_info::~debugwin_info() +{ +} + + +void debugwin_info::destroy() +{ + for (int curview = 0; curview < MAX_VIEWS; curview++) + m_views[curview].reset(); + DestroyWindow(m_wnd); +} + +bool debugwin_info::set_default_focus() +{ + return false; +} + + +void debugwin_info::prev_view(debugview_info *curview) +{ + // count the number of views + int numviews; + for (numviews = 0; numviews < MAX_VIEWS; numviews++) + { + if (m_views[numviews] == NULL) + break; + } + + // if we have a curview, find out its index + int curindex = 1; + if (curview) + { + for (curindex = numviews - 1; curindex > 0; curindex--) + { + if (m_views[curindex] == curview) + break; + } + if (curindex < 0) + curindex = 1; + } + + // loop until we find someone to take focus + while (1) + { + // advance to the previous index + curindex--; + if (curindex < -1) + curindex = numviews - 1; + + if (curindex < 0 && set_default_focus()) + { + // negative numbers mean the focuswnd + break; + } + else if (curindex >= 0 && m_views[curindex] != NULL && m_views[curindex]->cursor_supported()) + { + // positive numbers mean a view + m_views[curindex]->set_focus(); + break; + } + } +} + + +void debugwin_info::next_view(debugview_info *curview) +{ + // count the number of views + int numviews; + for (numviews = 0; numviews < MAX_VIEWS; numviews++) + { + if (m_views[numviews] == NULL) + break; + } + + // if we have a curview, find out its index + int curindex = -1; + if (curview) + { + for (curindex = numviews - 1; curindex > 0; curindex--) + { + if (m_views[curindex] == curview) + break; + } + } + + // loop until we find someone to take focus + while (1) + { + // advance to the previous index + curindex++; + if (curindex >= numviews) + curindex = -1; + + if (curindex < 0 && set_default_focus()) + { + // negative numbers mean the focuswnd + break; + } + else if (curindex >= 0 && m_views[curindex] != NULL && m_views[curindex]->cursor_supported()) + { + // positive numbers mean a view + m_views[curindex]->set_focus(); + break; + } + } +} + + +bool debugwin_info::handle_key(WPARAM wparam, LPARAM lparam) +{ + /* ignore any keys that are received while the debug key is down */ + if (!waiting_for_debugger() && seq_pressed()) + return true; + + switch (wparam) + { + case VK_F3: + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + SendMessage(m_wnd, WM_COMMAND, ID_HARD_RESET, 0); + else + SendMessage(m_wnd, WM_COMMAND, ID_SOFT_RESET, 0); + return true; + + case VK_F4: + if (GetAsyncKeyState(VK_MENU) & 0x8000) + { + /* ajg - never gets here since 'alt' seems to be captured somewhere else - menu maybe? */ + SendMessage(m_wnd, WM_COMMAND, ID_EXIT, 0); + return true; + } + break; + + case VK_F5: + SendMessage(m_wnd, WM_COMMAND, ID_RUN, 0); + return true; + + case VK_F6: + SendMessage(m_wnd, WM_COMMAND, ID_NEXT_CPU, 0); + return true; + + case VK_F7: + SendMessage(m_wnd, WM_COMMAND, ID_RUN_IRQ, 0); + return true; + + case VK_F8: + SendMessage(m_wnd, WM_COMMAND, ID_RUN_VBLANK, 0); + return true; + + case VK_F10: + SendMessage(m_wnd, WM_COMMAND, ID_STEP_OVER, 0); + return true; + + case VK_F11: + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + SendMessage(m_wnd, WM_COMMAND, ID_STEP_OUT, 0); + else + SendMessage(m_wnd, WM_COMMAND, ID_STEP, 0); + return true; + + case VK_F12: + SendMessage(m_wnd, WM_COMMAND, ID_RUN_AND_HIDE, 0); + return true; + + case 'M': + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + SendMessage(m_wnd, WM_COMMAND, ID_NEW_MEMORY_WND, 0); + return true; + } + break; + + case 'D': + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + SendMessage(m_wnd, WM_COMMAND, ID_NEW_DISASM_WND, 0); + return true; + } + break; + + case 'L': + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + SendMessage(m_wnd, WM_COMMAND, ID_NEW_LOG_WND, 0); + return true; + } + break; + + case 'B': + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + SendMessage(m_wnd, WM_COMMAND, ID_NEW_POINTS_WND, 0); + return true; + } + break; + } + + return false; +} + + +void debugwin_info::recompute_children() +{ + if (m_views[0] != NULL) + { + // compute a client rect + RECT bounds; + bounds.top = bounds.left = 0; + bounds.right = m_views[0]->prefwidth() + (2 * EDGE_WIDTH); + bounds.bottom = 200; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + + // clamp the min/max size + set_maxwidth(bounds.right - bounds.left); + + // get the parent's dimensions + RECT parent; + GetClientRect(window(), &parent); + + // view gets the remaining space + InflateRect(&parent, -EDGE_WIDTH, -EDGE_WIDTH); + m_views[0]->set_bounds(parent); + } +} + + +bool debugwin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + if (HIWORD(wparam) == 0) + { + switch (LOWORD(wparam)) + { + case ID_NEW_MEMORY_WND: + debugger().create_memory_window(); + return true; + + case ID_NEW_DISASM_WND: + debugger().create_disasm_window(); + return true; + + case ID_NEW_LOG_WND: + debugger().create_log_window(); + return true; + + case ID_NEW_POINTS_WND: + debugger().create_points_window(); + return true; + + case ID_RUN_AND_HIDE: + debugger().hide_all(); + case ID_RUN: + debug_cpu_get_visible_cpu(machine())->debug()->go(); + return true; + + case ID_NEXT_CPU: + debug_cpu_get_visible_cpu(machine())->debug()->go_next_device(); + return true; + + case ID_RUN_VBLANK: + debug_cpu_get_visible_cpu(machine())->debug()->go_vblank(); + return true; + + case ID_RUN_IRQ: + debug_cpu_get_visible_cpu(machine())->debug()->go_interrupt(); + return true; + + case ID_STEP: + debug_cpu_get_visible_cpu(machine())->debug()->single_step(); + return true; + + case ID_STEP_OVER: + debug_cpu_get_visible_cpu(machine())->debug()->single_step_over(); + return true; + + case ID_STEP_OUT: + debug_cpu_get_visible_cpu(machine())->debug()->single_step_out(); + return true; + + case ID_HARD_RESET: + machine().schedule_hard_reset(); + return true; + + case ID_SOFT_RESET: + machine().schedule_soft_reset(); + debug_cpu_get_visible_cpu(machine())->debug()->go(); + return true; + + case ID_EXIT: + set_default_focus(); + machine().schedule_exit(); + return true; + } + } + return false; +} + + +void debugwin_info::draw_contents(HDC dc) +{ + // fill the background with light gray + RECT parent; + GetClientRect(m_wnd, &parent); + FillRect(dc, &parent, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + + // draw edges around all views + for (int curview = 0; curview < MAX_VIEWS; curview++) + { + if (m_views[curview] != NULL) + { + RECT bounds; + m_views[curview]->get_bounds(bounds); + draw_border(dc, bounds); + } + } +} + + +void debugwin_info::draw_border(HDC dc, RECT &bounds) +{ + ScreenToClient(m_wnd, &((POINT *)&bounds)[0]); + ScreenToClient(m_wnd, &((POINT *)&bounds)[1]); + InflateRect(&bounds, EDGE_WIDTH, EDGE_WIDTH); + DrawEdge(dc, &bounds, EDGE_SUNKEN, BF_RECT); +} + + +void debugwin_info::draw_border(HDC dc, HWND child) +{ + RECT bounds; + GetWindowRect(child, &bounds); + draw_border(dc, bounds); +} + + +LRESULT debugwin_info::window_proc(UINT message, WPARAM wparam, LPARAM lparam) +{ + // handle a few messages + switch (message) + { + // paint: draw bezels as necessary + case WM_PAINT: + { + PAINTSTRUCT pstruct; + HDC dc = BeginPaint(m_wnd, &pstruct); + draw_contents(dc); + EndPaint(m_wnd, &pstruct); + break; + } + + // keydown: handle debugger keys + case WM_KEYDOWN: + if (handle_key(wparam, lparam)) + set_ignore_char_lparam(lparam); + break; + + // char: ignore chars associated with keys we've handled + case WM_CHAR: + if (check_ignore_char_lparam(lparam)) + { + if (waiting_for_debugger() || !seq_pressed()) + return DefWindowProc(m_wnd, message, wparam, lparam); + } + break; + + // activate: set the focus + case WM_ACTIVATE: + if (wparam != WA_INACTIVE) + set_default_focus(); + break; + + // get min/max info: set the minimum window size + case WM_GETMINMAXINFO: + { + MINMAXINFO *minmax = (MINMAXINFO *)lparam; + minmax->ptMinTrackSize.x = m_minwidth; + minmax->ptMinTrackSize.y = m_minheight; + minmax->ptMaxSize.x = minmax->ptMaxTrackSize.x = m_maxwidth; + minmax->ptMaxSize.y = minmax->ptMaxTrackSize.y = m_maxheight; + break; + } + + // sizing: recompute child window locations + case WM_SIZE: + case WM_SIZING: + recompute_children(); + InvalidateRect(m_wnd, NULL, FALSE); + break; + + // mouse wheel: forward to the first view + case WM_MOUSEWHEEL: + { + static int units_carryover = 0; + + UINT lines_per_click; + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines_per_click, 0)) + lines_per_click = 3; + + int const units = GET_WHEEL_DELTA_WPARAM(wparam) + units_carryover; + int const clicks = units / WHEEL_DELTA; + units_carryover = units % WHEEL_DELTA; + + int const delta = clicks * lines_per_click; + int viewnum = 0; + POINT point; + + // figure out which view we are hovering over + GetCursorPos(&point); + ScreenToClient(m_wnd, &point); + HWND const child = ChildWindowFromPoint(m_wnd, point); + if (child) + { + for (viewnum = 0; viewnum < MAX_VIEWS; viewnum++) + { + if ((m_views[viewnum] != NULL) && m_views[viewnum]->owns_window(child)) + break; + } + if (viewnum == MAX_VIEWS) + break; + } + + // send the appropriate message to this view's scrollbar + if (m_views[viewnum] != NULL) + m_views[viewnum]->send_vscroll(delta); + + break; + } + + // activate: set the focus + case WM_INITMENU: + update_menu(); + break; + + // command: handle a comment + case WM_COMMAND: + if (!handle_command(wparam, lparam)) + return DefWindowProc(m_wnd, message, wparam, lparam); + break; + + // close: close the window if it's not the main console + case WM_CLOSE: + if (m_is_main_console) + { + debugger().hide_all(); + debug_cpu_get_visible_cpu(machine())->debug()->go(); + } + else + { + destroy(); + } + break; + + // destroy: close down the window + case WM_NCDESTROY: + m_wnd = NULL; + debugger().remove_window(*this); + break; + + // everything else: defaults + default: + return DefWindowProc(m_wnd, message, wparam, lparam); + } + + return 0; +} + + +HMENU debugwin_info::create_standard_menubar() +{ + // create the debug menu + HMENU const debugmenu = CreatePopupMenu(); + if (debugmenu == NULL) + return NULL; + AppendMenu(debugmenu, MF_ENABLED, ID_NEW_MEMORY_WND, TEXT("New Memory Window\tCtrl+M")); + AppendMenu(debugmenu, MF_ENABLED, ID_NEW_DISASM_WND, TEXT("New Disassembly Window\tCtrl+D")); + AppendMenu(debugmenu, MF_ENABLED, ID_NEW_LOG_WND, TEXT("New Error Log Window\tCtrl+L")); + AppendMenu(debugmenu, MF_ENABLED, ID_NEW_POINTS_WND, TEXT("New (Break|Watch)points Window\tCtrl+B")); + AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(debugmenu, MF_ENABLED, ID_RUN, TEXT("Run\tF5")); + AppendMenu(debugmenu, MF_ENABLED, ID_RUN_AND_HIDE, TEXT("Run and Hide Debugger\tF12")); + AppendMenu(debugmenu, MF_ENABLED, ID_NEXT_CPU, TEXT("Run to Next CPU\tF6")); + AppendMenu(debugmenu, MF_ENABLED, ID_RUN_IRQ, TEXT("Run until Next Interrupt on This CPU\tF7")); + AppendMenu(debugmenu, MF_ENABLED, ID_RUN_VBLANK, TEXT("Run until Next VBLANK\tF8")); + AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(debugmenu, MF_ENABLED, ID_STEP, TEXT("Step Into\tF11")); + AppendMenu(debugmenu, MF_ENABLED, ID_STEP_OVER, TEXT("Step Over\tF10")); + AppendMenu(debugmenu, MF_ENABLED, ID_STEP_OUT, TEXT("Step Out\tShift+F11")); + AppendMenu(debugmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(debugmenu, MF_ENABLED, ID_SOFT_RESET, TEXT("Soft Reset\tF3")); + AppendMenu(debugmenu, MF_ENABLED, ID_HARD_RESET, TEXT("Hard Reset\tShift+F3")); + AppendMenu(debugmenu, MF_ENABLED, ID_EXIT, TEXT("Exit")); + + // create the menu bar + HMENU const menubar = CreateMenu(); + if (menubar == NULL) + { + DestroyMenu(debugmenu); + return NULL; + } + AppendMenu(menubar, MF_ENABLED | MF_POPUP, (UINT_PTR)debugmenu, TEXT("Debug")); + + return menubar; +} + + +LRESULT CALLBACK debugwin_info::static_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_CREATE) + { + // set the info pointer + CREATESTRUCT const *const createinfo = (CREATESTRUCT *)lparam; + debugwin_info *const info = (debugwin_info *)createinfo->lpCreateParams; + SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams); + if (info->m_handler) + SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)info->m_handler); + return 0; + } + + debugwin_info *const info = (debugwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); + if (!info) + return DefWindowProc(wnd, message, wparam, lparam); + + assert(info->m_wnd == wnd); + return info->window_proc(message, wparam, lparam); +} + + +void debugwin_info::register_window_class() +{ + if (!s_window_class_registered) + { + WNDCLASS wc = { 0 }; + + // initialize the description of the window class + wc.lpszClassName = TEXT("MAMEDebugWindow"); + wc.hInstance = GetModuleHandle(NULL); + wc.lpfnWndProc = &debugwin_info::static_window_proc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(2)); + wc.lpszMenuName = NULL; + wc.hbrBackground = NULL; + wc.style = 0; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + // register the class; fail if we can't + if (!RegisterClass(&wc)) + fatalerror("Unable to register debug window class\n"); + + s_window_class_registered = true; + } +} diff --git a/src/osd/modules/debugger/win/debugwininfo.h b/src/osd/modules/debugger/win/debugwininfo.h new file mode 100644 index 00000000000..148d79a651e --- /dev/null +++ b/src/osd/modules/debugger/win/debugwininfo.h @@ -0,0 +1,142 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// debugwininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DEBUG_WIN_INFO_H__ +#define __DEBUG_WIN_DEBUG_WIN_INFO_H__ + +#include "debugwin.h" + +#include "debugbaseinfo.h" + +#include "emu.h" + + +class debugwin_info : protected debugbase_info +{ +public: + template<class U> friend class simple_list; + + debugwin_info(debugger_windows_interface &debugger, bool main_console, LPCSTR title, WNDPROC handler); + virtual ~debugwin_info(); + + bool is_valid() const { return m_wnd != NULL; } + debugwin_info *next() const { return m_next; } + + void set_ignore_char_lparam(LPARAM value) { m_ignore_char_lparam = value >> 16; } + bool check_ignore_char_lparam(LPARAM value) + { + if (m_ignore_char_lparam == (value >> 16)) + { + m_ignore_char_lparam = 0; + return false; + } + else + { + return true; + } + } + + void show() { smart_show_window(m_wnd, true); } + void hide() { smart_show_window(m_wnd, false); } + void set_foreground() { SetForegroundWindow(m_wnd); } + void destroy(); + + virtual bool set_default_focus(); + void prev_view(debugview_info *curview); + void next_view(debugview_info *curview); + virtual bool restore_field(HWND wnd) { return false; } + + virtual bool handle_key(WPARAM wparam, LPARAM lparam); + +protected: + static DWORD const DEBUG_WINDOW_STYLE = (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN) & (~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX); + static DWORD const DEBUG_WINDOW_STYLE_EX = 0; + + static int const MAX_VIEWS = 4; + static int const EDGE_WIDTH = 3; + + enum + { + ID_NEW_MEMORY_WND = 1, + ID_NEW_DISASM_WND, + ID_NEW_LOG_WND, + ID_NEW_POINTS_WND, + ID_RUN, + ID_RUN_AND_HIDE, + ID_RUN_VBLANK, + ID_RUN_IRQ, + ID_NEXT_CPU, + ID_STEP, + ID_STEP_OVER, + ID_STEP_OUT, + ID_HARD_RESET, + ID_SOFT_RESET, + ID_EXIT, + + ID_1_BYTE_CHUNKS, + ID_2_BYTE_CHUNKS, + ID_4_BYTE_CHUNKS, + ID_8_BYTE_CHUNKS, + ID_LOGICAL_ADDRESSES, + ID_PHYSICAL_ADDRESSES, + ID_REVERSE_VIEW, + ID_INCREASE_MEM_WIDTH, + ID_DECREASE_MEM_WIDTH, + + ID_TOGGLE_BREAKPOINT, + ID_DISABLE_BREAKPOINT, + ID_RUN_TO_CURSOR, + ID_SHOW_RAW, + ID_SHOW_ENCRYPTED, + ID_SHOW_COMMENTS, + + ID_SHOW_BREAKPOINTS, + ID_SHOW_WATCHPOINTS, + + ID_DEVICE_OPTIONS // always keep this at the end + }; + + HWND window() const { return m_wnd; } + UINT32 minwidth() const { return m_minwidth; } + UINT32 maxwidth() const { return m_maxwidth; } + void set_minwidth(UINT32 value) { m_minwidth = value; } + void set_maxwidth(UINT32 value) { m_maxwidth = value; } + + virtual void recompute_children(); + virtual void update_menu() { } + virtual bool handle_command(WPARAM wparam, LPARAM lparam); + virtual void draw_contents(HDC dc); + void draw_border(HDC dc, RECT &bounds); + void draw_border(HDC dc, HWND child); + + auto_pointer<debugview_info> m_views[MAX_VIEWS]; + +private: + LRESULT window_proc(UINT message, WPARAM wparam, LPARAM lparam); + + HMENU create_standard_menubar(); + + static LRESULT CALLBACK static_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); + + static void register_window_class(); + + bool const m_is_main_console; + + debugwin_info *m_next; + HWND m_wnd; + WNDPROC const m_handler; + + UINT32 m_minwidth, m_maxwidth; + UINT32 m_minheight, m_maxheight; + + UINT16 m_ignore_char_lparam; + + static bool s_window_class_registered; +}; + +#endif diff --git a/src/osd/modules/debugger/win/disasmbasewininfo.c b/src/osd/modules/debugger/win/disasmbasewininfo.c new file mode 100644 index 00000000000..e636bec57a7 --- /dev/null +++ b/src/osd/modules/debugger/win/disasmbasewininfo.c @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmbasewininfo.c - Win32 debug window handling +// +//============================================================ + +#include "disasmbasewininfo.h" + +#include "debugviewinfo.h" +#include "disasmviewinfo.h" + +#include "debugger.h" +#include "debug/debugcon.h" +#include "debug/debugcpu.h" + +//#include "winutf8.h" + + +disasmbasewin_info::disasmbasewin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler) : + editwin_info(debugger, is_main_console, title, handler) +{ + if (!window()) + return; + + m_views[0].reset(global_alloc(disasmview_info(debugger, *this, window()))); + if ((m_views[0] == NULL) || !m_views[0]->is_valid()) + { + m_views[0].reset(); + return; + } + + // create the options menu + HMENU const optionsmenu = CreatePopupMenu(); + AppendMenu(optionsmenu, MF_ENABLED, ID_TOGGLE_BREAKPOINT, TEXT("Toggle breakpoint at cursor\tF9")); + AppendMenu(optionsmenu, MF_ENABLED, ID_DISABLE_BREAKPOINT, TEXT("Disable breakpoint at cursor\tShift+F9")); + AppendMenu(optionsmenu, MF_ENABLED, ID_RUN_TO_CURSOR, TEXT("Run to cursor\tF4")); + AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_RAW, TEXT("Raw opcodes\tCtrl+R")); + AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_ENCRYPTED, TEXT("Encrypted opcodes\tCtrl+E")); + AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_COMMENTS, TEXT("Comments\tCtrl+M")); + AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); + + // set up the view to track the initial expression + downcast<disasmview_info *>(m_views[0].get())->set_expression("curpc"); + m_views[0]->set_source_for_visible_cpu(); +} + + +disasmbasewin_info::~disasmbasewin_info() +{ +} + + +bool disasmbasewin_info::handle_key(WPARAM wparam, LPARAM lparam) +{ + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + switch (wparam) + { + case 'R': + SendMessage(window(), WM_COMMAND, ID_SHOW_RAW, 0); + return true; + + case 'E': + SendMessage(window(), WM_COMMAND, ID_SHOW_ENCRYPTED, 0); + return true; + + case 'N': + SendMessage(window(), WM_COMMAND, ID_SHOW_COMMENTS, 0); + return true; + } + } + + switch (wparam) + { + // ajg - steals the F4 from the global key handler - but ALT+F4 didn't work anyways ;) + case VK_F4: + SendMessage(window(), WM_COMMAND, ID_RUN_TO_CURSOR, 0); + return true; + + case VK_F9: + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + SendMessage(window(), WM_COMMAND, ID_DISABLE_BREAKPOINT, 0); + else + SendMessage(window(), WM_COMMAND, ID_TOGGLE_BREAKPOINT, 0); + return true; + + case VK_RETURN: + if (m_views[0]->cursor_visible() && m_views[0]->source_is_visible_cpu()) + { + SendMessage(window(), WM_COMMAND, ID_STEP, 0); + return true; + } + break; + } + + return editwin_info::handle_key(wparam, lparam); +} + + +void disasmbasewin_info::update_menu() +{ + editwin_info::update_menu(); + + disasmview_info *const dasmview = downcast<disasmview_info *>(m_views[0].get()); + HMENU const menu = GetMenu(window()); + + bool const disasm_cursor_visible = dasmview->cursor_visible(); + if (disasm_cursor_visible) + { + offs_t const address = dasmview->selected_address(); + device_debug *const debug = dasmview->source_device()->debug(); + + // first find an existing breakpoint at this address + device_debug::breakpoint *bp = debug->breakpoint_first(); + while ((bp != NULL) && (bp->address() != address)) + bp = bp->next(); + + if (bp == NULL) + { + ModifyMenu(menu, ID_TOGGLE_BREAKPOINT, MF_BYCOMMAND, ID_TOGGLE_BREAKPOINT, TEXT("Set breakpoint at cursor\tF9")); + ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Disable breakpoint at cursor\tShift+F9")); + } + else + { + ModifyMenu(menu, ID_TOGGLE_BREAKPOINT, MF_BYCOMMAND, ID_TOGGLE_BREAKPOINT, TEXT("Clear breakpoint at cursor\tF9")); + if (bp->enabled()) + ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Disable breakpoint at cursor\tShift+F9")); + else + ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Enable breakpoint at cursor\tShift+F9")); + } + EnableMenuItem(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND | (bp != NULL ? MF_ENABLED : MF_GRAYED)); + } + else + { + ModifyMenu(menu, ID_TOGGLE_BREAKPOINT, MF_BYCOMMAND, ID_TOGGLE_BREAKPOINT, TEXT("Toggle breakpoint at cursor\tF9")); + ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Disable breakpoint at cursor\tShift+F9")); + EnableMenuItem(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND | MF_GRAYED); + } + EnableMenuItem(menu, ID_TOGGLE_BREAKPOINT, MF_BYCOMMAND | (disasm_cursor_visible ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(menu, ID_RUN_TO_CURSOR, MF_BYCOMMAND | (disasm_cursor_visible ? MF_ENABLED : MF_GRAYED)); + + disasm_right_column const rightcol = dasmview->right_column(); + CheckMenuItem(menu, ID_SHOW_RAW, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_RAW ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_SHOW_ENCRYPTED, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_ENCRYPTED ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_SHOW_COMMENTS, MF_BYCOMMAND | (rightcol == DASM_RIGHTCOL_COMMENTS ? MF_CHECKED : MF_UNCHECKED)); +} + + +bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + disasmview_info *const dasmview = downcast<disasmview_info *>(m_views[0].get()); + + switch (HIWORD(wparam)) + { + // menu selections + case 0: + switch (LOWORD(wparam)) + { + case ID_TOGGLE_BREAKPOINT: + if (dasmview->cursor_visible()) + { + offs_t const address = dasmview->selected_address(); + device_debug *const debug = dasmview->source_device()->debug(); + INT32 bpindex = -1; + + // first find an existing breakpoint at this address + for (device_debug::breakpoint *bp = debug->breakpoint_first(); bp != NULL; bp = bp->next()) + { + if (address == bp->address()) + { + bpindex = bp->index(); + break; + } + } + + // if it doesn't exist, add a new one + if (dasmview->source_is_visible_cpu()) + { + astring command; + if (bpindex == -1) + command.printf("bpset 0x%X", address); + else + command.printf("bpclear 0x%X", bpindex); + debug_console_execute_command(machine(), command, 1); + } + else + { + if (bpindex == -1) + { + bpindex = debug->breakpoint_set(address, NULL, NULL); + debug_console_printf(machine(), "Breakpoint %X set\n", bpindex); + } + else + { + debug->breakpoint_clear(bpindex); + debug_console_printf(machine(), "Breakpoint %X cleared\n", bpindex); + } + machine().debug_view().update_all(); + debugger_refresh_display(machine()); + } + } + return true; + + case ID_DISABLE_BREAKPOINT: + if (dasmview->cursor_visible()) + { + offs_t const address = dasmview->selected_address(); + device_debug *const debug = dasmview->source_device()->debug(); + + // first find an existing breakpoint at this address + device_debug::breakpoint *bp = debug->breakpoint_first(); + while ((bp != NULL) && (bp->address() != address)) + bp = bp->next(); + + // if it doesn't exist, add a new one + if (bp != NULL) + { + if (dasmview->source_is_visible_cpu()) + { + astring command; + command.printf(bp->enabled() ? "bpdisable 0x%X" : "bpenable 0x%X", (UINT32)bp->index()); + debug_console_execute_command(machine(), command, 1); + } + else + { + debug->breakpoint_enable(bp->index(), !bp->enabled()); + debug_console_printf(machine(), "Breakpoint %X %s\n", (UINT32)bp->index(), bp->enabled() ? "enabled" : "disabled"); + machine().debug_view().update_all(); + debugger_refresh_display(machine()); + } + } + } + return true; + + case ID_RUN_TO_CURSOR: + if (dasmview->cursor_visible()) + { + offs_t const address = dasmview->selected_address(); + if (dasmview->source_is_visible_cpu()) + { + astring command; + command.printf("go 0x%X", address); + debug_console_execute_command(machine(), command, 1); + } + else + { + dasmview->source_device()->debug()->go(address); + } + } + return true; + + case ID_SHOW_RAW: + dasmview->set_right_column(DASM_RIGHTCOL_RAW); + recompute_children(); + return true; + + case ID_SHOW_ENCRYPTED: + dasmview->set_right_column(DASM_RIGHTCOL_ENCRYPTED); + recompute_children(); + return true; + + case ID_SHOW_COMMENTS: + dasmview->set_right_column(DASM_RIGHTCOL_COMMENTS); + recompute_children(); + return true; + } + break; + } + return editwin_info::handle_command(wparam, lparam); +} diff --git a/src/osd/modules/debugger/win/disasmbasewininfo.h b/src/osd/modules/debugger/win/disasmbasewininfo.h new file mode 100644 index 00000000000..a74b5196b44 --- /dev/null +++ b/src/osd/modules/debugger/win/disasmbasewininfo.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmbasewininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DISASM_BASE_WIN_INFO_H__ +#define __DEBUG_WIN_DISASM_BASE_WIN_INFO_H__ + +#include "debugwin.h" + +#include "editwininfo.h" + + +class disasmbasewin_info : public editwin_info +{ +public: + disasmbasewin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler); + virtual ~disasmbasewin_info(); + + virtual bool handle_key(WPARAM wparam, LPARAM lparam); + +protected: + virtual void update_menu(); + virtual bool handle_command(WPARAM wparam, LPARAM lparam); +}; + +#endif diff --git a/src/osd/modules/debugger/win/disasmviewinfo.c b/src/osd/modules/debugger/win/disasmviewinfo.c new file mode 100644 index 00000000000..98ff1188188 --- /dev/null +++ b/src/osd/modules/debugger/win/disasmviewinfo.c @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmviewinfo.c - Win32 debug window handling +// +//============================================================ + +#include "disasmviewinfo.h" + + +disasmview_info::disasmview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) : + debugview_info(debugger, owner, parent, DVT_DISASSEMBLY) +{ +} + + +disasmview_info::~disasmview_info() +{ +} + + +disasm_right_column disasmview_info::right_column() const +{ + return view<debug_view_disasm>()->right_column(); +} + + +offs_t disasmview_info::selected_address() const +{ + return view<debug_view_disasm>()->selected_address(); +} + + +void disasmview_info::set_expression(char const *string) +{ + view<debug_view_disasm>()->set_expression(string); +} + + +void disasmview_info::set_right_column(disasm_right_column contents) +{ + view<debug_view_disasm>()->set_right_column(contents); +}
\ No newline at end of file diff --git a/src/osd/modules/debugger/win/disasmviewinfo.h b/src/osd/modules/debugger/win/disasmviewinfo.h new file mode 100644 index 00000000000..bfd8e73cd95 --- /dev/null +++ b/src/osd/modules/debugger/win/disasmviewinfo.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmviewinfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DISASM_VIEW_INFO_H__ +#define __DEBUG_WIN_DISASM_VIEW_INFO_H__ + +#include "debugwin.h" + +#include "debugviewinfo.h" + +#include "debug/dvdisasm.h" + + +class disasmview_info : public debugview_info +{ +public: + disasmview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent); + virtual ~disasmview_info(); + + disasm_right_column right_column() const; + offs_t selected_address() const; + + void set_expression(const char *expression); + void set_right_column(disasm_right_column contents); +}; + +#endif diff --git a/src/osd/modules/debugger/win/disasmwininfo.c b/src/osd/modules/debugger/win/disasmwininfo.c new file mode 100644 index 00000000000..9f2db09919c --- /dev/null +++ b/src/osd/modules/debugger/win/disasmwininfo.c @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmwininfo.c - Win32 debug window handling +// +//============================================================ + +#include "disasmwininfo.h" + +#include "debugviewinfo.h" +#include "disasmviewinfo.h" +#include "uimetrics.h" + +#include "debugger.h" +#include "debug/debugcon.h" +#include "debug/debugcpu.h" + +#include "winutf8.h" + + +disasmwin_info::disasmwin_info(debugger_windows_interface &debugger) : + disasmbasewin_info(debugger, false, "Disassembly", NULL), + m_combownd(NULL) +{ + if ((window() == NULL) || (m_views[0] == NULL)) + return; + + // set up the view to track the initial expression + set_edit_defstr("curpc"); + set_editwnd_text("curpc"); + editwnd_select_all(); + + // create a combo box + m_combownd = m_views[0]->create_source_combobox(window(), (LONG_PTR)this); + + // set the caption + update_caption(); + + // recompute the children once to get the maxwidth + recompute_children(); + + // position the window and recompute children again + SetWindowPos(window(), HWND_TOP, 100, 100, maxwidth(), 200, SWP_SHOWWINDOW); + recompute_children(); + + // mark the edit box as the default focus and set it + set_default_focus(); +} + + +disasmwin_info::~disasmwin_info() +{ +} + + +void disasmwin_info::recompute_children() +{ + // compute a client rect + RECT bounds; + bounds.top = bounds.left = 0; + bounds.right = m_views[0]->prefwidth() + (2 * EDGE_WIDTH); + bounds.bottom = 200; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + + // clamp the min/max size + set_maxwidth(bounds.right - bounds.left); + + // get the parent's dimensions + RECT parent; + GetClientRect(window(), &parent); + + // edit box gets half of the width + RECT editrect; + editrect.top = parent.top + EDGE_WIDTH; + editrect.bottom = editrect.top + metrics().debug_font_height() + 4; + editrect.left = parent.left + EDGE_WIDTH; + editrect.right = parent.left + ((parent.right - parent.left) / 2) - EDGE_WIDTH; + + // combo box gets the other half of the width + RECT comborect; + comborect.top = editrect.top; + comborect.bottom = editrect.bottom; + comborect.left = editrect.right + (2 * EDGE_WIDTH); + comborect.right = parent.right - EDGE_WIDTH; + + // disasm view gets the rest + RECT dasmrect; + dasmrect.top = editrect.bottom + (2 * EDGE_WIDTH); + dasmrect.bottom = parent.bottom - EDGE_WIDTH; + dasmrect.left = parent.left + EDGE_WIDTH; + dasmrect.right = parent.right - EDGE_WIDTH; + + // set the bounds of things + m_views[0]->set_bounds(dasmrect); + set_editwnd_bounds(editrect); + smart_set_window_bounds(m_combownd, window(), comborect); +} + + +bool disasmwin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + switch (HIWORD(wparam)) + { + // combo box selection changed + case CBN_SELCHANGE: + { + int const sel = SendMessage((HWND)lparam, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + m_views[0]->set_source_index(sel); + update_caption(); + + // reset the focus + set_default_focus(); + return true; + } + break; + } + } + return disasmbasewin_info::handle_command(wparam, lparam); +} + + +void disasmwin_info::draw_contents(HDC dc) +{ + disasmbasewin_info::draw_contents(dc); + if (m_combownd) + draw_border(dc, m_combownd); +} + + +void disasmwin_info::process_string(char const *string) +{ + // set the string to the disasm view + downcast<disasmview_info *>(m_views[0].get())->set_expression(string); + + // select everything in the edit text box + editwnd_select_all(); + + // update the default string to match + set_edit_defstr(string); +} + + +void disasmwin_info::update_caption() +{ + win_set_window_text_utf8(window(), astring("Disassembly: ", m_views[0]->source_name())); +} diff --git a/src/osd/modules/debugger/win/disasmwininfo.h b/src/osd/modules/debugger/win/disasmwininfo.h new file mode 100644 index 00000000000..7817aa9f456 --- /dev/null +++ b/src/osd/modules/debugger/win/disasmwininfo.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// disasmwininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_DISASM_WIN_INFO_H__ +#define __DEBUG_WIN_DISASM_WIN_INFO_H__ + +#include "debugwin.h" + +#include "disasmbasewininfo.h" + + +class disasmwin_info : public disasmbasewin_info +{ +public: + disasmwin_info(debugger_windows_interface &debugger); + virtual ~disasmwin_info(); + +protected: + virtual void recompute_children(); + virtual bool handle_command(WPARAM wparam, LPARAM lparam); + virtual void draw_contents(HDC dc); + +private: + virtual void process_string(char const *string); + + void update_caption(); + + HWND m_combownd; +}; + +#endif diff --git a/src/osd/modules/debugger/win/editwininfo.c b/src/osd/modules/debugger/win/editwininfo.c new file mode 100644 index 00000000000..98361430b35 --- /dev/null +++ b/src/osd/modules/debugger/win/editwininfo.c @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// editwininfo.c - Win32 debug window handling +// +//============================================================ + +#include "editwininfo.h" + +#include "debugviewinfo.h" +#include "uimetrics.h" + +#include "strconv.h" + + +// edit box styles +#define EDIT_BOX_STYLE WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL +#define EDIT_BOX_STYLE_EX 0 + + +editwin_info::editwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler) : + debugwin_info(debugger, is_main_console, title, handler), + m_editwnd(NULL), + m_edit_defstr(), + m_original_editproc(NULL), + m_history_count(0), + m_last_history(0) +{ + if (window() == NULL) + return; + + // create an edit box and override its key handling + m_editwnd = CreateWindowEx(EDIT_BOX_STYLE_EX, TEXT("EDIT"), NULL, EDIT_BOX_STYLE, + 0, 0, 100, 100, window(), NULL, GetModuleHandle(NULL), NULL); + m_original_editproc = (WNDPROC)(FPTR)GetWindowLongPtr(m_editwnd, GWLP_WNDPROC); + SetWindowLongPtr(m_editwnd, GWLP_USERDATA, (LONG_PTR)this); + SetWindowLongPtr(m_editwnd, GWLP_WNDPROC, (LONG_PTR)&editwin_info::static_edit_proc); + SendMessage(m_editwnd, WM_SETFONT, (WPARAM)metrics().debug_font(), (LPARAM)FALSE); + SendMessage(m_editwnd, EM_LIMITTEXT, (WPARAM)MAX_EDIT_STRING, (LPARAM)0); + set_editwnd_text(""); +} + + +editwin_info::~editwin_info() +{ +} + + +bool editwin_info::restore_field(HWND wnd) +{ + if (wnd == m_editwnd) + { + set_editwnd_text(m_edit_defstr); + editwnd_select_all(); + return true; + } + else + { + return false; + } +} + + +bool editwin_info::set_default_focus() +{ + SetFocus(m_editwnd); + return true; +} + + +void editwin_info::set_editwnd_bounds(RECT const &bounds) +{ + smart_set_window_bounds(m_editwnd, window(), bounds); +} + + +void editwin_info::set_editwnd_text(char const *text) +{ + TCHAR *tc_buffer = tstring_from_utf8(text); + if (tc_buffer != NULL) + { + SendMessage(m_editwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)tc_buffer); + osd_free(tc_buffer); + } +} + + +void editwin_info::editwnd_select_all() +{ + SendMessage(m_editwnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); +} + + +void editwin_info::draw_contents(HDC dc) +{ + debugwin_info::draw_contents(dc); + if (m_editwnd) + draw_border(dc, m_editwnd); +} + + +LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam) +{ + TCHAR buffer[MAX_EDIT_STRING]; + + // handle a few messages + switch (message) + { + // key down: handle navigation in the attached view + case WM_SYSKEYDOWN: + if (wparam != VK_F10) + return CallWindowProc(m_original_editproc, m_editwnd, message, wparam, lparam); + // (fall through) + case WM_KEYDOWN: + switch (wparam) + { + case VK_UP: + if (m_last_history < (m_history_count - 1)) + m_last_history++; + else + m_last_history = 0; + SendMessage(m_editwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)&m_history[m_last_history][0]); + SendMessage(m_editwnd, EM_SETSEL, (WPARAM)MAX_EDIT_STRING, (LPARAM)MAX_EDIT_STRING); + break; + + case VK_DOWN: + if (m_last_history > 0) + m_last_history--; + else if (m_history_count > 0) + m_last_history = m_history_count - 1; + else + m_last_history = 0; + SendMessage(m_editwnd, WM_SETTEXT, (WPARAM)0, (LPARAM)&m_history[m_last_history][0]); + SendMessage(m_editwnd, EM_SETSEL, (WPARAM)MAX_EDIT_STRING, (LPARAM)MAX_EDIT_STRING); + break; + + case VK_PRIOR: + if (m_views[0] != NULL) + m_views[0]->send_pageup(); + break; + + case VK_NEXT: + if (m_views[0] != NULL) + m_views[0]->send_pagedown(); + break; + + case VK_TAB: + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + prev_view(NULL); + else + next_view(NULL); + set_ignore_char_lparam(lparam); + break; + + default: + if (handle_key(wparam, lparam)) + set_ignore_char_lparam(lparam); + else + return CallWindowProc(m_original_editproc, m_editwnd, message, wparam, lparam); + break; + } + break; + + // char: handle the return key + case WM_CHAR: + + // ignore chars associated with keys we've handled + if (check_ignore_char_lparam(lparam)) + { + if (waiting_for_debugger() || !seq_pressed()) + { + switch (wparam) + { + case 13: + { + // fetch the text + SendMessage(m_editwnd, WM_GETTEXT, (WPARAM)ARRAY_LENGTH(buffer), (LPARAM)buffer); + + // add to the history if it's not a repeat of the last one + if (buffer[0] != 0 && _tcscmp(buffer, &m_history[0][0])) + { + memmove(&m_history[1][0], &m_history[0][0], (HISTORY_LENGTH - 1) * MAX_EDIT_STRING * sizeof(TCHAR)); + _tcscpy(&m_history[0][0], buffer); + if (m_history_count < HISTORY_LENGTH) + m_history_count++; + } + m_last_history = m_history_count - 1; + + // process + char *utf8_buffer = utf8_from_tstring(buffer); + if (utf8_buffer != NULL) + { + process_string(utf8_buffer); + osd_free(utf8_buffer); + } + break; + } + + case 27: + { + // fetch the text + SendMessage(m_editwnd, WM_GETTEXT, (WPARAM)sizeof(buffer), (LPARAM)buffer); + + // if it's not empty, clear the text + if (_tcslen(buffer) > 0) + { + set_ignore_char_lparam(lparam); + set_editwnd_text(m_edit_defstr); + editwnd_select_all(); + } + break; + } + + default: + return CallWindowProc(m_original_editproc, m_editwnd, message, wparam, lparam); + } + } + } + break; + + // everything else: defaults + default: + return CallWindowProc(m_original_editproc, m_editwnd, message, wparam, lparam); + } + + return 0; +} + + +LRESULT CALLBACK editwin_info::static_edit_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + editwin_info *const info = (editwin_info *)(FPTR)GetWindowLongPtr(wnd, GWLP_USERDATA); + assert(info.m_editwnd == wnd); + return info->edit_proc(message, wparam, lparam); +} diff --git a/src/osd/modules/debugger/win/editwininfo.h b/src/osd/modules/debugger/win/editwininfo.h new file mode 100644 index 00000000000..b89a710781a --- /dev/null +++ b/src/osd/modules/debugger/win/editwininfo.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// editwininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_EDIT_WIN_INFO_H__ +#define __DEBUG_WIN_EDIT_WIN_INFO_H__ + +#include "debugwin.h" + +#include "debugwininfo.h" + + +class editwin_info : public debugwin_info +{ +public: + editwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler); + virtual ~editwin_info(); + + virtual bool restore_field(HWND wnd); + + virtual bool set_default_focus(); + +protected: + static DWORD const COMBO_BOX_STYLE = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; + static DWORD const COMBO_BOX_STYLE_EX = 0; + + void set_editwnd_bounds(RECT const &bounds); + void set_editwnd_text(char const *text); + void editwnd_select_all(); + void set_edit_defstr(char const *string) { m_edit_defstr = string; } + + virtual void draw_contents(HDC dc); + +private: + virtual void process_string(char const *string) = 0; + + LRESULT edit_proc(UINT message, WPARAM wparam, LPARAM lparam); + + static LRESULT CALLBACK static_edit_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); + + static int const MAX_EDIT_STRING = 256; + static int const HISTORY_LENGTH = 20; + + HWND m_editwnd; + astring m_edit_defstr; + WNDPROC m_original_editproc; + TCHAR m_history[HISTORY_LENGTH][MAX_EDIT_STRING]; + int m_history_count; + int m_last_history; +}; + +#endif diff --git a/src/osd/modules/debugger/win/logwininfo.c b/src/osd/modules/debugger/win/logwininfo.c new file mode 100644 index 00000000000..2f2b06c349d --- /dev/null +++ b/src/osd/modules/debugger/win/logwininfo.c @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// logwininfo.c - Win32 debug window handling +// +//============================================================ + +#include "logwininfo.h" + +#include "debugviewinfo.h" + + +logwin_info::logwin_info(debugger_windows_interface &debugger) : + debugwin_info(debugger, false, astring("Errorlog: ", debugger.machine().system().description, " [", debugger.machine().system().name, "]"), NULL) +{ + if (!window()) + return; + + m_views[0].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_LOG))); + if ((m_views[0] == NULL) || !m_views[0]->is_valid()) + { + m_views[0].reset(); + return; + } + + // compute a client rect + RECT bounds; + bounds.top = bounds.left = 0; + bounds.right = m_views[0]->maxwidth() + (2 * EDGE_WIDTH); + bounds.bottom = 200; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + + // clamp the min/max size + set_maxwidth(bounds.right - bounds.left); + + // position the window at the bottom-right + SetWindowPos(window(), HWND_TOP, 100, 100, bounds.right - bounds.left, bounds.bottom - bounds.top, SWP_SHOWWINDOW); + + // recompute the children + recompute_children(); +} + + +logwin_info::~logwin_info() +{ +} diff --git a/src/osd/modules/debugger/win/logwininfo.h b/src/osd/modules/debugger/win/logwininfo.h new file mode 100644 index 00000000000..f26a557b2cb --- /dev/null +++ b/src/osd/modules/debugger/win/logwininfo.h @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// logwininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_LOG_WIN_INFO_H__ +#define __DEBUG_WIN_LOG_WIN_INFO_H__ + +#include "debugwin.h" + +#include "debugwininfo.h" + + +class logwin_info : public debugwin_info +{ +public: + logwin_info(debugger_windows_interface &debugger); + virtual ~logwin_info(); +}; + +#endif diff --git a/src/osd/modules/debugger/win/memoryviewinfo.c b/src/osd/modules/debugger/win/memoryviewinfo.c new file mode 100644 index 00000000000..4c5bdc44c7e --- /dev/null +++ b/src/osd/modules/debugger/win/memoryviewinfo.c @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// memoryviewinfo.c - Win32 debug window handling +// +//============================================================ + +#include "memoryviewinfo.h" + +#include "debug/dvmemory.h" + + +memoryview_info::memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) : + debugview_info(debugger, owner, parent, DVT_MEMORY) +{ +} + + +memoryview_info::~memoryview_info() +{ +} + + +UINT8 memoryview_info::bytes_per_chunk() const +{ + return view<debug_view_memory>()->bytes_per_chunk(); +} + + +UINT32 memoryview_info::chunks_per_row() const +{ + return view<debug_view_memory>()->chunks_per_row(); +} + + +bool memoryview_info::reverse() const +{ + return view<debug_view_memory>()->reverse(); +} + + +bool memoryview_info::physical() const +{ + return view<debug_view_memory>()->physical(); +} + + +void memoryview_info::set_expression(char const *string) +{ + view<debug_view_memory>()->set_expression(string); +} + +void memoryview_info::set_bytes_per_chunk(UINT8 chunkbytes) +{ + view<debug_view_memory>()->set_bytes_per_chunk(chunkbytes); +} + +void memoryview_info::set_chunks_per_row(UINT32 rowchunks) +{ + view<debug_view_memory>()->set_chunks_per_row(rowchunks); +} + +void memoryview_info::set_reverse(bool reverse) +{ + view<debug_view_memory>()->set_reverse(reverse); +} + +void memoryview_info::set_physical(bool physical) +{ + view<debug_view_memory>()->set_physical(physical); +} diff --git a/src/osd/modules/debugger/win/memoryviewinfo.h b/src/osd/modules/debugger/win/memoryviewinfo.h new file mode 100644 index 00000000000..1951473d68b --- /dev/null +++ b/src/osd/modules/debugger/win/memoryviewinfo.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// memoryviewinfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_MEMORY_VIEW_INFO_H__ +#define __DEBUG_WIN_MEMORY_VIEW_INFO_H__ + +#include "debugwin.h" + +#include "debugviewinfo.h" + + +class memoryview_info : public debugview_info +{ +public: + memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent); + virtual ~memoryview_info(); + + UINT8 bytes_per_chunk() const; + UINT32 chunks_per_row() const; + bool reverse() const; + bool ascii() const; + bool physical() const; + + void set_expression(char const *string); + void set_bytes_per_chunk(UINT8 chunkbytes); + void set_chunks_per_row(UINT32 rowchunks); + void set_reverse(bool reverse); + void set_physical(bool physical); +}; + +#endif diff --git a/src/osd/modules/debugger/win/memorywininfo.c b/src/osd/modules/debugger/win/memorywininfo.c new file mode 100644 index 00000000000..19a4b121de9 --- /dev/null +++ b/src/osd/modules/debugger/win/memorywininfo.c @@ -0,0 +1,279 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// memorywininfo.c - Win32 debug window handling +// +//============================================================ + +#include "memorywininfo.h" + +#include "debugviewinfo.h" +#include "memoryviewinfo.h" +#include "uimetrics.h" + +#include "winutf8.h" + + +memorywin_info::memorywin_info(debugger_windows_interface &debugger) : + editwin_info(debugger, false, "Memory", NULL), + m_combownd(NULL) +{ + if (!window()) + return; + + m_views[0].reset(global_alloc(memoryview_info(debugger, *this, window()))); + if ((m_views[0] == NULL) || !m_views[0]->is_valid()) + { + m_views[0].reset(); + return; + } + + // create the options menu + HMENU const optionsmenu = CreatePopupMenu(); + AppendMenu(optionsmenu, MF_ENABLED, ID_1_BYTE_CHUNKS, TEXT("1-byte chunks\tCtrl+1")); + AppendMenu(optionsmenu, MF_ENABLED, ID_2_BYTE_CHUNKS, TEXT("2-byte chunks\tCtrl+2")); + AppendMenu(optionsmenu, MF_ENABLED, ID_4_BYTE_CHUNKS, TEXT("4-byte chunks\tCtrl+4")); + AppendMenu(optionsmenu, MF_ENABLED, ID_8_BYTE_CHUNKS, TEXT("8-byte chunks\tCtrl+8")); + AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(optionsmenu, MF_ENABLED, ID_LOGICAL_ADDRESSES, TEXT("Logical Addresses\tCtrl+L")); + AppendMenu(optionsmenu, MF_ENABLED, ID_PHYSICAL_ADDRESSES, TEXT("Physical Addresses\tCtrl+Y")); + AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(optionsmenu, MF_ENABLED, ID_REVERSE_VIEW, TEXT("Reverse View\tCtrl+R")); + AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(optionsmenu, MF_ENABLED, ID_INCREASE_MEM_WIDTH, TEXT("Increase bytes per line\tCtrl+P")); + AppendMenu(optionsmenu, MF_ENABLED, ID_DECREASE_MEM_WIDTH, TEXT("Decrease bytes per line\tCtrl+O")); + AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); + + // set up the view to track the initial expression + downcast<memoryview_info *>(m_views[0].get())->set_expression("0"); + set_edit_defstr("0"); + set_editwnd_text("0"); + editwnd_select_all(); + + // create a combo box + m_views[0]->set_source_for_visible_cpu(); + m_combownd = m_views[0]->create_source_combobox(window(), (LONG_PTR)this); + + // set the caption + update_caption(); + + // recompute the children once to get the maxwidth + recompute_children(); + + // position the window and recompute children again + SetWindowPos(window(), HWND_TOP, 100, 100, maxwidth(), 200, SWP_SHOWWINDOW); + recompute_children(); + + // mark the edit box as the default focus and set it + set_default_focus(); +} + + +memorywin_info::~memorywin_info() +{ +} + + +bool memorywin_info::handle_key(WPARAM wparam, LPARAM lparam) +{ + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + switch (wparam) + { + case '1': + SendMessage(window(), WM_COMMAND, ID_1_BYTE_CHUNKS, 0); + return true; + + case '2': + SendMessage(window(), WM_COMMAND, ID_2_BYTE_CHUNKS, 0); + return true; + + case '4': + SendMessage(window(), WM_COMMAND, ID_4_BYTE_CHUNKS, 0); + return true; + + case '8': + SendMessage(window(), WM_COMMAND, ID_8_BYTE_CHUNKS, 0); + return true; + + case 'L': + SendMessage(window(), WM_COMMAND, ID_LOGICAL_ADDRESSES, 0); + return true; + + case 'Y': + SendMessage(window(), WM_COMMAND, ID_PHYSICAL_ADDRESSES, 0); + return true; + + case 'R': + SendMessage(window(), WM_COMMAND, ID_REVERSE_VIEW, 0); + return true; + + case 'P': + SendMessage(window(), WM_COMMAND, ID_INCREASE_MEM_WIDTH, 0); + return true; + + case 'O': + SendMessage(window(), WM_COMMAND, ID_DECREASE_MEM_WIDTH, 0); + return true; + } + } + return editwin_info::handle_key(wparam, lparam); +} + + +void memorywin_info::recompute_children() +{ + // compute a client rect + RECT bounds; + bounds.top = bounds.left = 0; + bounds.right = m_views[0]->prefwidth() + (2 * EDGE_WIDTH); + bounds.bottom = 200; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + + // clamp the min/max size + set_maxwidth(bounds.right - bounds.left); + + // get the parent's dimensions + RECT parent; + GetClientRect(window(), &parent); + + // edit box gets half of the width + RECT editrect; + editrect.top = parent.top + EDGE_WIDTH; + editrect.bottom = editrect.top + metrics().debug_font_height() + 4; + editrect.left = parent.left + EDGE_WIDTH; + editrect.right = parent.left + ((parent.right - parent.left) / 2) - EDGE_WIDTH; + + // combo box gets the other half of the width + RECT comborect; + comborect.top = editrect.top; + comborect.bottom = editrect.bottom; + comborect.left = editrect.right + (2 * EDGE_WIDTH); + comborect.right = parent.right - EDGE_WIDTH; + + // memory view gets the rest + RECT memrect; + memrect.top = editrect.bottom + (2 * EDGE_WIDTH); + memrect.bottom = parent.bottom - EDGE_WIDTH; + memrect.left = parent.left + EDGE_WIDTH; + memrect.right = parent.right - EDGE_WIDTH; + + // set the bounds of things + m_views[0]->set_bounds(memrect); + set_editwnd_bounds(editrect); + smart_set_window_bounds(m_combownd, window(), comborect); +} + + +void memorywin_info::update_menu() +{ + editwin_info::update_menu(); + + memoryview_info *const memview = downcast<memoryview_info *>(m_views[0].get()); + HMENU const menu = GetMenu(window()); + CheckMenuItem(menu, ID_1_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 1 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_2_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 2 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_4_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 4 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_8_BYTE_CHUNKS, MF_BYCOMMAND | (memview->bytes_per_chunk() == 8 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_LOGICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_UNCHECKED : MF_CHECKED)); + CheckMenuItem(menu, ID_PHYSICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_REVERSE_VIEW, MF_BYCOMMAND | (memview->reverse() ? MF_CHECKED : MF_UNCHECKED)); + EnableMenuItem(menu, ID_DECREASE_MEM_WIDTH, MF_BYCOMMAND | ((memview->chunks_per_row() > 1) ? MF_ENABLED : MF_GRAYED)); +} + + +bool memorywin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + memoryview_info *const memview = downcast<memoryview_info *>(m_views[0].get()); + switch (HIWORD(wparam)) + { + // combo box selection changed + case CBN_SELCHANGE: + { + int const sel = SendMessage((HWND)lparam, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + memview->set_source_index(sel); + update_caption(); + + // reset the focus + set_default_focus(); + return true; + } + break; + } + + // menu selections + case 0: + switch (LOWORD(wparam)) + { + case ID_1_BYTE_CHUNKS: + memview->set_bytes_per_chunk(1); + return true; + + case ID_2_BYTE_CHUNKS: + memview->set_bytes_per_chunk(2); + return true; + + case ID_4_BYTE_CHUNKS: + memview->set_bytes_per_chunk(4); + return true; + + case ID_8_BYTE_CHUNKS: + memview->set_bytes_per_chunk(8); + return true; + + case ID_LOGICAL_ADDRESSES: + memview->set_physical(false); + return true; + + case ID_PHYSICAL_ADDRESSES: + memview->set_physical(true); + return true; + + case ID_REVERSE_VIEW: + memview->set_reverse(!memview->reverse()); + return true; + + case ID_INCREASE_MEM_WIDTH: + memview->set_chunks_per_row(memview->chunks_per_row() + 1); + recompute_children(); + return true; + + case ID_DECREASE_MEM_WIDTH: + memview->set_chunks_per_row(memview->chunks_per_row() - 1); + recompute_children(); + return true; + } + break; + } + return editwin_info::handle_command(wparam, lparam); +} + + +void memorywin_info::draw_contents(HDC dc) +{ + editwin_info::draw_contents(dc); + if (m_combownd) + draw_border(dc, m_combownd); +} + + +void memorywin_info::process_string(char const *string) +{ + // set the string to the memory view + downcast<memoryview_info *>(m_views[0].get())->set_expression(string); + + // select everything in the edit text box + editwnd_select_all(); + + // update the default string to match + set_edit_defstr(string); +} + + +void memorywin_info::update_caption() +{ + win_set_window_text_utf8(window(), astring("Memory: ", m_views[0]->source_name())); +} diff --git a/src/osd/modules/debugger/win/memorywininfo.h b/src/osd/modules/debugger/win/memorywininfo.h new file mode 100644 index 00000000000..a6e71f8fdcd --- /dev/null +++ b/src/osd/modules/debugger/win/memorywininfo.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// memorywininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_MEMORY_WIN_INFO_H__ +#define __DEBUG_WIN_MEMORY_WIN_INFO_H__ + +#include "debugwin.h" + +#include "editwininfo.h" + + +class memorywin_info : public editwin_info +{ +public: + memorywin_info(debugger_windows_interface &debugger); + virtual ~memorywin_info(); + + virtual bool handle_key(WPARAM wparam, LPARAM lparam); + +protected: + virtual void recompute_children(); + virtual void update_menu(); + virtual bool handle_command(WPARAM wparam, LPARAM lparam); + virtual void draw_contents(HDC dc); + +private: + virtual void process_string(char const *string); + + void update_caption(); + + HWND m_combownd; +}; + +#endif diff --git a/src/osd/modules/debugger/win/pointswininfo.c b/src/osd/modules/debugger/win/pointswininfo.c new file mode 100644 index 00000000000..a958a285046 --- /dev/null +++ b/src/osd/modules/debugger/win/pointswininfo.c @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// pointswininfo.c - Win32 debug window handling +// +//============================================================ + +#include "pointswininfo.h" + +#include "debugviewinfo.h" + +#include "winutf8.h" + + +pointswin_info::pointswin_info(debugger_windows_interface &debugger) : + debugwin_info(debugger, false, astring("All Breakpoints"), NULL) +{ + if (!window()) + return; + + m_views[0].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_BREAK_POINTS))); + if ((m_views[0] == NULL) || !m_views[0]->is_valid()) + { + m_views[0].reset(); + return; + } + + // create the options menu + HMENU const optionsmenu = CreatePopupMenu(); + AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_BREAKPOINTS, TEXT("Breakpoints\tCtrl+1")); + AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_WATCHPOINTS, TEXT("Watchpoints\tCtrl+2")); + AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options")); + + // compute a client rect + RECT bounds; + bounds.top = bounds.left = 0; + bounds.right = m_views[0]->maxwidth() + (2 * EDGE_WIDTH); + bounds.bottom = 200; + AdjustWindowRectEx(&bounds, DEBUG_WINDOW_STYLE, FALSE, DEBUG_WINDOW_STYLE_EX); + + // clamp the min/max size + set_maxwidth(bounds.right - bounds.left); + + // position the window at the bottom-right + SetWindowPos(window(), HWND_TOP, 100, 100, bounds.right - bounds.left, bounds.bottom - bounds.top, SWP_SHOWWINDOW); + + // recompute the children + recompute_children(); +} + + +pointswin_info::~pointswin_info() +{ +} + + +bool pointswin_info::handle_key(WPARAM wparam, LPARAM lparam) +{ + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + switch (wparam) + { + case '1': + SendMessage(window(), WM_COMMAND, ID_SHOW_BREAKPOINTS, 0); + return true; + + case '2': + SendMessage(window(), WM_COMMAND, ID_SHOW_WATCHPOINTS, 0); + return true; + } + } + + return debugwin_info::handle_key(wparam, lparam); +} + + +void pointswin_info::update_menu() +{ + debugwin_info::update_menu(); + + HMENU const menu = GetMenu(window()); + CheckMenuItem(menu, ID_SHOW_BREAKPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_BREAK_POINTS ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, ID_SHOW_WATCHPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_WATCH_POINTS ? MF_CHECKED : MF_UNCHECKED)); +} + + +bool pointswin_info::handle_command(WPARAM wparam, LPARAM lparam) +{ + switch (HIWORD(wparam)) + { + // menu selections + case 0: + switch (LOWORD(wparam)) + { + case ID_SHOW_BREAKPOINTS: + m_views[0].reset(); + m_views[0].reset(global_alloc(debugview_info(debugger(), *this, window(), DVT_BREAK_POINTS))); + if (!m_views[0]->is_valid()) + m_views[0].reset(); + win_set_window_text_utf8(window(), "All Breakpoints"); + recompute_children(); + return true; + + case ID_SHOW_WATCHPOINTS: + m_views[0].reset(); + m_views[0].reset(global_alloc(debugview_info(debugger(), *this, window(), DVT_WATCH_POINTS))); + if (!m_views[0]->is_valid()) + m_views[0].reset(); + win_set_window_text_utf8(window(), "All Watchpoints"); + recompute_children(); + return true; + } + break; + } + return debugwin_info::handle_command(wparam, lparam); +} diff --git a/src/osd/modules/debugger/win/pointswininfo.h b/src/osd/modules/debugger/win/pointswininfo.h new file mode 100644 index 00000000000..e04a467bb0a --- /dev/null +++ b/src/osd/modules/debugger/win/pointswininfo.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// pointswininfo.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_POINTS_WIN_INFO_H__ +#define __DEBUG_WIN_POINTS_WIN_INFO_H__ + +#include "debugwin.h" + +#include "debugwininfo.h" + + +class pointswin_info : public debugwin_info +{ +public: + pointswin_info(debugger_windows_interface &debugger); + virtual ~pointswin_info(); + + virtual bool handle_key(WPARAM wparam, LPARAM lparam); + +protected: + virtual void update_menu(); + virtual bool handle_command(WPARAM wparam, LPARAM lparam); +}; + +#endif diff --git a/src/osd/modules/debugger/win/uimetrics.c b/src/osd/modules/debugger/win/uimetrics.c new file mode 100644 index 00000000000..f61b90275da --- /dev/null +++ b/src/osd/modules/debugger/win/uimetrics.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// uimetrics.c - Win32 debug window handling +// +//============================================================ + +#include "uimetrics.h" + +#include "strconv.h" + + +ui_metrics::ui_metrics(windows_options const &options) : + m_debug_font(NULL), + m_debug_font_height(0), + m_debug_font_width(0), + m_debug_font_ascent(0), + m_hscroll_height(GetSystemMetrics(SM_CYHSCROLL)), + m_vscroll_width(GetSystemMetrics(SM_CXVSCROLL)) +{ + // create a temporary DC + HDC const temp_dc = GetDC(NULL); + if (temp_dc != NULL) + { + int const size = options.debugger_font_size(); + + // create a standard font + TCHAR *t_face = tstring_from_utf8(options.debugger_font()); + m_debug_font = CreateFont(-MulDiv(size, GetDeviceCaps(temp_dc, LOGPIXELSY), 72), 0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE, + ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, t_face); + osd_free(t_face); + t_face = NULL; + + if (m_debug_font == NULL) + fatalerror("Unable to create debugger font\n"); + + // get the metrics + HGDIOBJ const old_font = SelectObject(temp_dc, m_debug_font); + TEXTMETRIC metrics; + if (GetTextMetrics(temp_dc, &metrics)) + { + m_debug_font_width = metrics.tmAveCharWidth; + m_debug_font_height = metrics.tmHeight; + m_debug_font_ascent = metrics.tmAscent + metrics.tmExternalLeading; + } + SelectObject(temp_dc, old_font); + ReleaseDC(NULL, temp_dc); + } +} + + +ui_metrics::ui_metrics(ui_metrics const &that) : + m_debug_font(NULL), + m_debug_font_height(that.m_debug_font_height), + m_debug_font_width(that.m_debug_font_width), + m_debug_font_ascent(that.m_debug_font_ascent), + m_hscroll_height(that.m_hscroll_height), + m_vscroll_width(that.m_vscroll_width) +{ + LOGFONT lf; + if (GetObject(that.m_debug_font, sizeof(lf), &lf)) + m_debug_font = CreateFontIndirect(&lf); +} + + +ui_metrics::~ui_metrics() +{ + if (m_debug_font) + DeleteObject(m_debug_font); +} diff --git a/src/osd/modules/debugger/win/uimetrics.h b/src/osd/modules/debugger/win/uimetrics.h new file mode 100644 index 00000000000..54db03c1be4 --- /dev/null +++ b/src/osd/modules/debugger/win/uimetrics.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Vas Crabb +//============================================================ +// +// uimetrics.h - Win32 debug window handling +// +//============================================================ + +#ifndef __DEBUG_WIN_UI_METRICS_H__ +#define __DEBUG_WIN_UI_METRICS_H__ + +#include "debugwin.h" + +#include "emu.h" + +#include "winmain.h" + + +class ui_metrics +{ +public: + ui_metrics(windows_options const &options); + ui_metrics(ui_metrics const &that); + ~ui_metrics(); + + HFONT debug_font() const { return m_debug_font; } + UINT32 debug_font_height() const { return m_debug_font_height; } + UINT32 debug_font_width() const { return m_debug_font_width; } + UINT32 debug_font_ascent() const { return m_debug_font_ascent; } + + UINT32 hscroll_height() const { return m_hscroll_height; } + UINT32 vscroll_width() const { return m_vscroll_width; } + +private: + HFONT m_debug_font; + UINT32 m_debug_font_height; + UINT32 m_debug_font_width; + UINT32 m_debug_font_ascent; + + UINT32 const m_hscroll_height; + UINT32 const m_vscroll_width; +}; + +#endif diff --git a/src/osd/sdl/sdl.mak b/src/osd/sdl/sdl.mak index e0dcfdce356..da6bd17a727 100644 --- a/src/osd/sdl/sdl.mak +++ b/src/osd/sdl/sdl.mak @@ -767,7 +767,7 @@ OSDOBJS += \ $(OSDOBJ)/modules/debugger/none.o \ $(OSDOBJ)/modules/debugger/debugint.o \ $(OSDOBJ)/modules/debugger/debugwin.o \ - $(OSDOBJ)/modules/debugger/debugqt.o \ + $(OSDOBJ)/modules/debugger/debugqt.o #------------------------------------------------- # BGFX diff --git a/src/osd/windows/windows.mak b/src/osd/windows/windows.mak index b9cc10886cb..e9c868a4753 100644 --- a/src/osd/windows/windows.mak +++ b/src/osd/windows/windows.mak @@ -93,6 +93,7 @@ OBJDIRS += $(WINOBJ) \ $(OSDOBJ)/modules/midi \ $(OSDOBJ)/modules/font \ $(OSDOBJ)/modules/netdev \ + $(OSDOBJ)/modules/debugger/win ifdef USE_QTDEBUG OBJDIRS += $(OSDOBJ)/modules/debugger/qt @@ -411,9 +412,22 @@ $(WINOBJ)/drawgdi.o : $(SRC)/emu/rendersw.inc # add debug-specific files OSDOBJS += \ $(OSDOBJ)/modules/debugger/debugwin.o \ + $(OSDOBJ)/modules/debugger/win/consolewininfo.o \ + $(OSDOBJ)/modules/debugger/win/debugbaseinfo.o \ + $(OSDOBJ)/modules/debugger/win/debugviewinfo.o \ + $(OSDOBJ)/modules/debugger/win/debugwininfo.o \ + $(OSDOBJ)/modules/debugger/win/disasmbasewininfo.o \ + $(OSDOBJ)/modules/debugger/win/disasmviewinfo.o \ + $(OSDOBJ)/modules/debugger/win/disasmwininfo.o \ + $(OSDOBJ)/modules/debugger/win/editwininfo.o \ + $(OSDOBJ)/modules/debugger/win/logwininfo.o \ + $(OSDOBJ)/modules/debugger/win/memoryviewinfo.o \ + $(OSDOBJ)/modules/debugger/win/memorywininfo.o \ + $(OSDOBJ)/modules/debugger/win/pointswininfo.o \ + $(OSDOBJ)/modules/debugger/win/uimetrics.o \ $(OSDOBJ)/modules/debugger/debugint.o \ $(OSDOBJ)/modules/debugger/debugqt.o \ - $(OSDOBJ)/modules/debugger/none.o \ + $(OSDOBJ)/modules/debugger/none.o # add a stub resource file RESFILE = $(WINOBJ)/mame.res diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index d732ccf3bf2..dc76254660e 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -6,6 +6,9 @@ // //============================================================ +#ifndef __WINDOWS_WINMAIN_H__ +#define __WINDOWS_WINMAIN_H__ + #include "clifront.h" #include "osdepend.h" #include "modules/lib/osdobj_common.h" @@ -292,3 +295,5 @@ extern int osd_num_processors; // use this to ping the watchdog void winmain_watchdog_ping(void); void winmain_dump_stack(); + +#endif
\ No newline at end of file |