From 8d04ca7d7d307ca8f85624c571ccfd4eb23a26e0 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sat, 30 Jan 2021 22:46:43 +1100 Subject: Debuger updates: * Improved behaviour of bottom line in Qt and win32 debugger views. * Ported memory tracking feature from Qt to win32 module. --- src/osd/modules/debugger/qt/debuggerview.cpp | 19 ++- src/osd/modules/debugger/qt/memorywindow.cpp | 2 +- src/osd/modules/debugger/win/debugbaseinfo.cpp | 23 ++-- src/osd/modules/debugger/win/debugviewinfo.cpp | 175 +++++++++++++++--------- src/osd/modules/debugger/win/memoryviewinfo.cpp | 85 ++++++++++++ src/osd/modules/debugger/win/memoryviewinfo.h | 15 ++ 6 files changed, 242 insertions(+), 77 deletions(-) diff --git a/src/osd/modules/debugger/qt/debuggerview.cpp b/src/osd/modules/debugger/qt/debuggerview.cpp index fcbbda81f54..263fcfe1e73 100644 --- a/src/osd/modules/debugger/qt/debuggerview.cpp +++ b/src/osd/modules/debugger/qt/debuggerview.cpp @@ -66,11 +66,13 @@ void DebuggerView::paintEvent(QPaintEvent *event) // Handle the scroll bars int const horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x; horizontalScrollBar()->setRange(0, (std::max)(0, horizontalScrollCharDiff)); + horizontalScrollBar()->setPageStep(lineWidth - 1); int const verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y; int const verticalScrollSize = (std::max)(0, verticalScrollCharDiff); bool const atEnd = verticalScrollBar()->value() == verticalScrollBar()->maximum(); verticalScrollBar()->setRange(0, verticalScrollSize); + verticalScrollBar()->setPageStep((contentHeight / fontHeight) - 1); if (m_preferBottom && atEnd) verticalScrollBar()->setValue(verticalScrollSize); @@ -147,9 +149,24 @@ void DebuggerView::paintEvent(QPaintEvent *event) x * fontWidth, y * fontHeight, ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)), - ((y + 1) < visibleCharDims.y) ? fontHeight : (contentHeight - (y * fontHeight)), + fontHeight, bgBrush); + if (((y + 1) == visibleCharDims.y) && (contentHeight > (visibleCharDims.y * fontHeight))) + { + if (textAttr & DCA_ANCILLARY) + bgColor.setRgb(0xe0, 0xe0, 0xe0); + else + bgColor.setRgb(0xff, 0xff, 0xff); + bgBrush.setColor(bgColor); + painter.fillRect( + x * fontWidth, + visibleCharDims.y * fontHeight, + ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)), + contentHeight - (visibleCharDims.y * fontHeight), + bgBrush); + } + // There is a touchy interplay between font height, drawing difference, visible position, etc // Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed. painter.drawText(x * fontWidth, (y * fontHeight + (fontHeight * 0.80)), text); diff --git a/src/osd/modules/debugger/qt/memorywindow.cpp b/src/osd/modules/debugger/qt/memorywindow.cpp index 149729e247d..6f25c6bc964 100644 --- a/src/osd/modules/debugger/qt/memorywindow.cpp +++ b/src/osd/modules/debugger/qt/memorywindow.cpp @@ -326,7 +326,7 @@ void DebuggerMemView::addItemsToContextMenu(QMenu *menu) if (addressSpace) { // get the last known PC to write to this memory location - debug_view_xy const pos = view()->cursor_position(); + debug_view_xy const pos = memView.cursor_position(); offs_t const address = memView.addressAtCursorPosition(pos); offs_t a = address & addressSpace->logaddrmask(); bool good = false; diff --git a/src/osd/modules/debugger/win/debugbaseinfo.cpp b/src/osd/modules/debugger/win/debugbaseinfo.cpp index 4914d54cfad..1be4f892da7 100644 --- a/src/osd/modules/debugger/win/debugbaseinfo.cpp +++ b/src/osd/modules/debugger/win/debugbaseinfo.cpp @@ -21,12 +21,10 @@ debugbase_info::debugbase_info(debugger_windows_interface &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 + RECT curbounds; GetWindowRect(wnd, &curbounds); - if (parent != nullptr) + if (parent) { RECT parentbounds; GetWindowRect(parent, &parentbounds); @@ -37,6 +35,7 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const & } // if the position matches, don't change it + int flags = 0; if (curbounds.top == bounds.top && curbounds.left == bounds.left) flags |= SWP_NOMOVE; if ((curbounds.bottom - curbounds.top) == (bounds.bottom - bounds.top) && @@ -45,17 +44,19 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const & // if we need to, reposition the window if (flags != (SWP_NOMOVE | SWP_NOSIZE)) - SetWindowPos(wnd, nullptr, - bounds.left, bounds.top, - bounds.right - bounds.left, bounds.bottom - bounds.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags); + { + SetWindowPos( + wnd, nullptr, + 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)) + bool const visible = bool(IsWindowVisible(wnd)); + if (visible != show) ShowWindow(wnd, show ? SW_SHOW : SW_HIDE); } diff --git a/src/osd/modules/debugger/win/debugviewinfo.cpp b/src/osd/modules/debugger/win/debugviewinfo.cpp index e2b3e9f07a3..d6e94c1ba3e 100644 --- a/src/osd/modules/debugger/win/debugviewinfo.cpp +++ b/src/osd/modules/debugger/win/debugviewinfo.cpp @@ -401,6 +401,7 @@ void debugview_info::draw_contents(HDC windc) // get the client rect RECT client; GetClientRect(m_wnd, &client); + bool const need_filldown = client.bottom > (metrics().debug_font_height() * visarea.y); // create a compatible DC and an offscreen bitmap HDC const dc = CreateCompatibleDC(windc); @@ -413,6 +414,9 @@ void debugview_info::draw_contents(HDC windc) return; } HGDIOBJ const oldbitmap = SelectObject(dc, bitmap); + bool const show_hscroll = m_hscroll && IsWindowVisible(m_hscroll); + if (show_hscroll) + client.bottom -= metrics().hscroll_height(); // set the font HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font()); @@ -423,6 +427,8 @@ void debugview_info::draw_contents(HDC windc) // iterate over rows and columns for (uint32_t row = 0; row < visarea.y; row++) { + bool do_filldown = (row == (visarea.y - 1)) && need_filldown; + // loop twice; once to fill the background and once to draw the text for (int iter = 0; iter < 2; iter++) { @@ -451,16 +457,16 @@ void debugview_info::draw_contents(HDC windc) { COLORREF oldbg = bgcolor; - // reset to standard colors - fgcolor = RGB(0x00,0x00,0x00); + // pick new background color 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); + + // pick new foreground color + fgcolor = RGB(0x00,0x00,0x00); 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); @@ -471,21 +477,41 @@ void debugview_info::draw_contents(HDC windc) { bounds.right = bounds.left + (count * metrics().debug_font_width()); if (iter == 0) + { FillRect(dc, &bounds, bgbrush); + if (do_filldown) + { + COLORREF const filldown = (last_attrib & DCA_ANCILLARY) ? RGB(0xe0,0xe0,0xe0) : RGB(0xff,0xff,0xff); + if (oldbg != filldown) + { + DeleteObject(bgbrush); + bgbrush = CreateSolidBrush(filldown); + oldbg = filldown; + } + RECT padding = bounds; + padding.top = padding.bottom; + padding.bottom = client.bottom; + FillRect(dc, &padding, bgbrush); + } + } else + { ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr); + } bounds.left = bounds.right; count = 0; } // set the new colors - if (iter == 0 && oldbg != bgcolor) + if (iter == 1) + { + SetTextColor(dc, fgcolor); + } + else if (oldbg != bgcolor) { DeleteObject(bgbrush); bgbrush = CreateSolidBrush(bgcolor); } - else if (iter == 1) - SetTextColor(dc, fgcolor); last_attrib = viewdata[col].attrib; } @@ -494,33 +520,43 @@ void debugview_info::draw_contents(HDC windc) } // 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, nullptr, buffer, count, nullptr); - } - - // erase to the end of the line + bounds.right = bounds.left + (count * metrics().debug_font_width()); if (iter == 0) { - bounds.left = bounds.right; + // erase to the end of the line bounds.right = client.right; FillRect(dc, &bounds, bgbrush); + if (do_filldown) + { + COLORREF const filldown = (last_attrib & DCA_ANCILLARY) ? RGB(0xe0,0xe0,0xe0) : RGB(0xff,0xff,0xff); + if (bgcolor != filldown) + { + DeleteObject(bgbrush); + bgbrush = CreateSolidBrush(filldown); + } + bounds.top = bounds.bottom; + bounds.bottom = client.bottom; + FillRect(dc, &bounds, bgbrush); + } DeleteObject(bgbrush); } + else if (count > 0) + { + ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr); + } } // 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)); + // prevent garbage from showing in the corner + if (show_hscroll) + { + client.top = client.bottom; + client.bottom = client.top + metrics().hscroll_height(); + FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH)); + } // reset the font SetBkMode(dc, oldbkmode); @@ -539,47 +575,48 @@ void debugview_info::draw_contents(HDC windc) 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 updated total rows/cols and left row/col + debug_view_xy const totalsize = m_view->total_size(); + debug_view_xy topleft = m_view->visible_position(); + // get the view window bounds + RECT bounds; GetClientRect(m_wnd, &bounds); + debug_view_xy visiblesize; 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()) + bool const fit_hscroll = (bounds.bottom - bounds.top) > metrics().hscroll_height(); + bool show_hscroll = fit_hscroll && (totalsize.x > visiblesize.x); + if (show_hscroll) { 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()) + bool const fit_vscroll = (bounds.right - bounds.left) > metrics().vscroll_width(); + bool const show_vscroll = fit_vscroll && (totalsize.y > visiblesize.y); + if (show_vscroll) { bounds.right -= metrics().vscroll_width(); visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); - show_vscroll = true; + if (fit_hscroll && !show_hscroll && (totalsize.x > visiblesize.x)) + { + bounds.bottom -= metrics().hscroll_height(); + visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); + show_hscroll = true; + } } // compute the bounds of the scrollbars + RECT vscroll_bounds; GetClientRect(m_wnd, &vscroll_bounds); vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width(); if (show_hscroll) vscroll_bounds.bottom -= metrics().hscroll_height(); - + RECT hscroll_bounds; GetClientRect(m_wnd, &hscroll_bounds); hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height(); if (show_vscroll) @@ -592,26 +629,34 @@ void debugview_info::update() topleft.x = std::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); + if (m_vscroll) + { + 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); + if (m_hscroll) + { + 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++; + if (((bounds.right - bounds.left) > (visiblesize.x * metrics().debug_font_width())) && ((topleft.x + visiblesize.x) < totalsize.x)) + visiblesize.x++; + if (((bounds.bottom - bounds.top) > (visiblesize.y * metrics().debug_font_height())) && ((topleft.y + visiblesize.y) < totalsize.y)) + visiblesize.y++; m_view->set_visible_size(visiblesize); m_view->set_visible_position(topleft); @@ -691,7 +736,7 @@ uint32_t debugview_info::process_scroll(WORD type, HWND wnd) scrollinfo.nPos = result; SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE); - return (uint32_t)result; + return uint32_t(result); } @@ -864,10 +909,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: { - debug_view_xy topleft = m_view->visible_position(); + debug_view_xy const topleft = m_view->visible_position(); + debug_view_xy const visiblesize = m_view->visible_size(); 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(); + newpos.x = std::max(std::min(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0); + newpos.y = std::max(std::min(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0); m_view->process_click((message == WM_LBUTTONDOWN) ? DCK_LEFT_CLICK : DCK_MIDDLE_CLICK, newpos); SetFocus(m_wnd); break; @@ -877,10 +923,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) case WM_RBUTTONDOWN: if (m_view->cursor_supported()) { - debug_view_xy topleft = m_view->visible_position(); + debug_view_xy const topleft = m_view->visible_position(); + debug_view_xy const visiblesize = m_view->visible_size(); 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(); + newpos.x = std::max(std::min(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0); + newpos.y = std::max(std::min(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0); m_view->set_cursor_position(newpos); m_view->set_cursor_visible(true); } diff --git a/src/osd/modules/debugger/win/memoryviewinfo.cpp b/src/osd/modules/debugger/win/memoryviewinfo.cpp index 423679f26a9..9575a128c33 100644 --- a/src/osd/modules/debugger/win/memoryviewinfo.cpp +++ b/src/osd/modules/debugger/win/memoryviewinfo.cpp @@ -11,6 +11,8 @@ #include "debug/dvmemory.h" +#include "strconv.h" + memoryview_info::memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) : debugview_info(debugger, owner, parent, DVT_MEMORY) @@ -71,3 +73,86 @@ void memoryview_info::set_physical(bool physical) { view()->set_physical(physical); } + + +void memoryview_info::add_items_to_context_menu(HMENU menu) +{ + debugview_info::add_items_to_context_menu(menu); + + AppendMenu(menu, MF_DISABLED | MF_SEPARATOR, 0, TEXT("")); + AppendMenu(menu, MF_GRAYED, ID_CONTEXT_LAST_PC, TEXT("Last PC")); +} + +void memoryview_info::update_context_menu(HMENU menu) +{ + debugview_info::update_context_menu(menu); + + bool enable = false; + debug_view_memory &memview(*view()); + debug_view_memory_source const &source = downcast(*memview.source()); + address_space *const space = source.space(); + if (space) + { + if (memview.cursor_visible()) + { + // get the last known PC to write to this memory location + debug_view_xy const pos = memview.cursor_position(); + offs_t const address = memview.addressAtCursorPosition(pos); + offs_t a = address & space->logaddrmask(); + if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a)) + { + m_lastpc = "Bad address"; + } + else + { + uint64_t memval = space->unmap(); + auto dis = space->device().machine().disable_side_effects(); + switch (space->data_width()) + { + case 8: memval = space->read_byte(a); break; + case 16: memval = space->read_word_unaligned(a); break; + case 32: memval = space->read_dword_unaligned(a); break; + case 64: memval = space->read_qword_unaligned(a); break; + } + + offs_t const pc = source.device()->debug()->track_mem_pc_from_space_address_data( + space->spacenum(), + address, + memval); + if (pc != offs_t(-1)) + { + m_lastpc = util::string_format("Address %x written at PC=%x", address, pc); + enable = true; + } + else + { + m_lastpc = "Unknown PC"; + } + } + } + else + { + m_lastpc = "No address"; + } + } + else + { + m_lastpc = "Not an address space"; + } + ModifyMenuW(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND, ID_CONTEXT_LAST_PC, osd::text::to_wstring(m_lastpc).c_str()); + EnableMenuItem(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED)); +} + +void memoryview_info::handle_context_menu(unsigned command) +{ + switch (command) + { + case ID_CONTEXT_LAST_PC: + // TODO: copy to clipboard + return; + + default: + debugview_info::handle_context_menu(command); + }; + +} diff --git a/src/osd/modules/debugger/win/memoryviewinfo.h b/src/osd/modules/debugger/win/memoryviewinfo.h index d2c5d719abe..7766da9ac30 100644 --- a/src/osd/modules/debugger/win/memoryviewinfo.h +++ b/src/osd/modules/debugger/win/memoryviewinfo.h @@ -14,6 +14,8 @@ #include "debugviewinfo.h" +#include + class memoryview_info : public debugview_info { @@ -31,6 +33,19 @@ public: void set_chunks_per_row(uint32_t rowchunks); void set_reverse(bool reverse); void set_physical(bool physical); + +protected: + enum + { + ID_CONTEXT_LAST_PC = 101 + }; + + virtual void add_items_to_context_menu(HMENU menu) override; + virtual void update_context_menu(HMENU menu) override; + virtual void handle_context_menu(unsigned command) override; + +private: + std::string m_lastpc; }; #endif // MAME_DEBUGGER_WIN_MEMORYVIEWINFO_H -- cgit v1.2.3