summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/debugger/win/debugwininfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/debugger/win/debugwininfo.cpp')
-rw-r--r--src/osd/modules/debugger/win/debugwininfo.cpp603
1 files changed, 603 insertions, 0 deletions
diff --git a/src/osd/modules/debugger/win/debugwininfo.cpp b/src/osd/modules/debugger/win/debugwininfo.cpp
new file mode 100644
index 00000000000..078a87c15c7
--- /dev/null
+++ b/src/osd/modules/debugger/win/debugwininfo.cpp
@@ -0,0 +1,603 @@
+// 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"
+
+#include "winutil.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(), GetModuleHandleUni(), 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 == NULL)
+ return DefWindowProc(wnd, message, wparam, lparam);
+
+ assert((info->m_wnd == wnd) || (info->m_wnd == NULL));
+ 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 = GetModuleHandleUni();
+ 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;
+
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
+
+ // register the class; fail if we can't
+ if (!RegisterClass(&wc))
+ fatalerror("Unable to register debug window class\n");
+
+ s_window_class_registered = true;
+ }
+}