1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles, Vas Crabb
3 //============================================================
4 //
5 // debugview.c - Win32 debug window handling
6 //
7 //============================================================
8
9 #include "emu.h"
10 #include "debugviewinfo.h"
11
12 #include "debugwininfo.h"
13 #include "uimetrics.h"
14 #include "debugger.h"
15 #include "debug/debugcon.h"
16 #include "debug/debugcpu.h"
17
18 #include "strconv.h"
19
20 #include "winutil.h"
21
22
23 // debugger view styles
24 #define DEBUG_VIEW_STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
25 #define DEBUG_VIEW_STYLE_EX 0
26
27 // combo box styles
28 #define COMBO_BOX_STYLE WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL
29 #define COMBO_BOX_STYLE_EX 0
30
31 // horizontal scroll bar styles
32 #define HSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_HORZ
33 #define HSCROLL_STYLE_EX 0
34
35 // vertical scroll bar styles
36 #define VSCROLL_STYLE WS_CHILD | WS_VISIBLE | SBS_VERT
37 #define VSCROLL_STYLE_EX 0
38
39
40 bool debugview_info::s_window_class_registered = false;
41
42
debugview_info(debugger_windows_interface & debugger,debugwin_info & owner,HWND parent,debug_view_type type)43 debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent, debug_view_type type) :
44 debugbase_info(debugger),
45 m_owner(owner),
46 m_view(nullptr),
47 m_wnd(nullptr),
48 m_hscroll(nullptr),
49 m_vscroll(nullptr)
50 {
51 register_window_class();
52
53 // create the child view
54 m_wnd = CreateWindowEx(DEBUG_VIEW_STYLE_EX, TEXT("MAMEDebugView"), nullptr, DEBUG_VIEW_STYLE,
55 0, 0, 100, 100, parent, nullptr, GetModuleHandleUni(), this);
56 if (m_wnd == nullptr)
57 goto cleanup;
58
59 // create the scroll bars
60 m_hscroll = CreateWindowEx(HSCROLL_STYLE_EX, TEXT("SCROLLBAR"), nullptr, HSCROLL_STYLE,
61 0, 0, 100, CW_USEDEFAULT, m_wnd, nullptr, GetModuleHandleUni(), this);
62 m_vscroll = CreateWindowEx(VSCROLL_STYLE_EX, TEXT("SCROLLBAR"), nullptr, VSCROLL_STYLE,
63 0, 0, CW_USEDEFAULT, 100, m_wnd, nullptr, GetModuleHandleUni(), this);
64 if ((m_hscroll == nullptr) || (m_vscroll == nullptr))
65 goto cleanup;
66
67 // create the debug view
68 m_view = machine().debug_view().alloc_view(type, &debugview_info::static_update, this);
69 if (m_view == nullptr)
70 goto cleanup;
71
72 return;
73
74 cleanup:
75 if (m_hscroll != nullptr)
76 DestroyWindow(m_hscroll);
77 m_hscroll = nullptr;
78 if (m_vscroll != nullptr)
79 DestroyWindow(m_vscroll);
80 m_vscroll = nullptr;
81 if (m_wnd != nullptr)
82 DestroyWindow(m_wnd);
83 m_wnd = nullptr;
84 if (m_view != nullptr)
85 machine().debug_view().free_view(*m_view);
86 m_view = nullptr;
87 }
88
89
~debugview_info()90 debugview_info::~debugview_info()
91 {
92 if (m_wnd != nullptr)
93 DestroyWindow(m_wnd);
94 if (m_view)
95 machine().debug_view().free_view(*m_view);
96 }
97
98
is_valid() const99 bool debugview_info::is_valid() const
100 {
101 return m_view && m_hscroll && m_vscroll && m_wnd;
102 }
103
104
prefwidth() const105 uint32_t debugview_info::prefwidth() const
106 {
107 return (m_view->total_size().x * metrics().debug_font_width()) + metrics().vscroll_width();
108 }
109
110
maxwidth()111 uint32_t debugview_info::maxwidth()
112 {
113 uint32_t max = m_view->total_size().x;
114 debug_view_source const *const cursource = m_view->source();
115 for (auto &source : m_view->source_list())
116 {
117 m_view->set_source(*source);
118 uint32_t const chars = m_view->total_size().x;
119 if (max < chars)
120 max = chars;
121 }
122 if (cursource != nullptr)
123 m_view->set_source(*cursource);
124 return (max * metrics().debug_font_width()) + metrics().vscroll_width();
125 }
126
127
get_bounds(RECT & bounds) const128 void debugview_info::get_bounds(RECT &bounds) const
129 {
130 GetWindowRect(m_wnd, &bounds);
131 }
132
133
set_bounds(RECT const & newbounds)134 void debugview_info::set_bounds(RECT const &newbounds)
135 {
136 // account for the edges and set the bounds
137 if (m_wnd)
138 smart_set_window_bounds(m_wnd, GetParent(m_wnd), newbounds);
139
140 // update
141 update();
142 }
143
144
send_vscroll(int delta)145 void debugview_info::send_vscroll(int delta)
146 {
147 if (m_vscroll)
148 {
149 int message_type = SB_LINEUP;
150 if (delta < 0)
151 {
152 message_type = SB_LINEDOWN;
153 delta = -delta;
154 }
155 while (delta > 0)
156 {
157 SendMessage(m_wnd, WM_VSCROLL, message_type, (LPARAM)m_vscroll);
158 delta--;
159 }
160 }
161 }
162
163
send_pageup()164 void debugview_info::send_pageup()
165 {
166 if (m_vscroll)
167 {
168 SendMessage(m_wnd, WM_VSCROLL, SB_PAGELEFT, (LPARAM)m_vscroll);
169 }
170 }
171
172
send_pagedown()173 void debugview_info::send_pagedown()
174 {
175 if (m_vscroll)
176 {
177 SendMessage(m_wnd, WM_VSCROLL, SB_PAGERIGHT, (LPARAM)m_vscroll);
178 }
179 }
180
181
source_name() const182 char const *debugview_info::source_name() const
183 {
184 if (m_view != nullptr)
185 {
186 debug_view_source const *const source = m_view->source();
187 if (source != nullptr)
188 return source->name();
189 }
190 return "";
191 }
192
193
source_device() const194 device_t *debugview_info::source_device() const
195 {
196 if (m_view != nullptr)
197 {
198 debug_view_source const *const source = m_view->source();
199 if (source != nullptr)
200 return source->device();
201 }
202 return nullptr;
203 }
204
205
source_is_visible_cpu() const206 bool debugview_info::source_is_visible_cpu() const
207 {
208 if (m_view != nullptr)
209 {
210 const debug_view_source *const source = m_view->source();
211 return (source != nullptr) && (machine().debugger().console().get_visible_cpu() == source->device());
212 }
213 return false;
214 }
215
216
set_source_index(int index)217 bool debugview_info::set_source_index(int index)
218 {
219 if (m_view != nullptr)
220 {
221 const debug_view_source *const source = m_view->source(index);
222 if (source != nullptr)
223 {
224 m_view->set_source(*source);
225 return true;
226 }
227 }
228 return false;
229 }
230
231
set_source_for_device(device_t & device)232 bool debugview_info::set_source_for_device(device_t &device)
233 {
234 if (m_view != nullptr)
235 {
236 const debug_view_source *const source = m_view->source_for_device(&device);
237 if (source != nullptr)
238 {
239 m_view->set_source(*source);
240 return true;
241 }
242 }
243 return false;
244 }
245
246
set_source_for_visible_cpu()247 bool debugview_info::set_source_for_visible_cpu()
248 {
249 device_t *const curcpu = machine().debugger().console().get_visible_cpu();
250 if (curcpu != nullptr)
251 return set_source_for_device(*curcpu);
252 else
253 return false;
254 }
255
256
create_source_combobox(HWND parent,LONG_PTR userdata)257 HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata)
258 {
259 // create a combo box
260 HWND const result = CreateWindowEx(COMBO_BOX_STYLE_EX, TEXT("COMBOBOX"), nullptr, COMBO_BOX_STYLE,
261 0, 0, 100, 1000, parent, nullptr, GetModuleHandleUni(), nullptr);
262 SetWindowLongPtr(result, GWLP_USERDATA, userdata);
263 SendMessage(result, WM_SETFONT, (WPARAM)metrics().debug_font(), (LPARAM)FALSE);
264
265 // populate the combobox
266 debug_view_source const *const cursource = m_view->source();
267 int maxlength = 0;
268 for (auto &source : m_view->source_list())
269 {
270 int const length = strlen(source->name());
271 if (length > maxlength)
272 maxlength = length;
273 auto t_name = osd::text::to_tstring(source->name());
274 SendMessage(result, CB_ADDSTRING, 0, (LPARAM)t_name.c_str());
275 }
276 if (cursource != nullptr)
277 {
278 SendMessage(result, CB_SETCURSEL, m_view->source_index(*cursource), 0);
279 SendMessage(result, CB_SETDROPPEDWIDTH, ((maxlength + 2) * metrics().debug_font_width()) + metrics().vscroll_width(), 0);
280 m_view->set_source(*cursource);
281 }
282 return result;
283 }
284
285
draw_contents(HDC windc)286 void debugview_info::draw_contents(HDC windc)
287 {
288 debug_view_char const *viewdata = m_view->viewdata();
289 debug_view_xy const visarea = m_view->visible_size();
290
291 // get the client rect
292 RECT client;
293 GetClientRect(m_wnd, &client);
294
295 // create a compatible DC and an offscreen bitmap
296 HDC const dc = CreateCompatibleDC(windc);
297 if (dc == nullptr)
298 return;
299 HBITMAP const bitmap = CreateCompatibleBitmap(windc, client.right, client.bottom);
300 if (bitmap == nullptr)
301 {
302 DeleteDC(dc);
303 return;
304 }
305 HGDIOBJ const oldbitmap = SelectObject(dc, bitmap);
306
307 // set the font
308 HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font());
309 COLORREF const oldfgcolor = GetTextColor(dc);
310 int const oldbkmode = GetBkMode(dc);
311 SetBkMode(dc, TRANSPARENT);
312
313 // iterate over rows and columns
314 for (uint32_t row = 0; row < visarea.y; row++)
315 {
316 // loop twice; once to fill the background and once to draw the text
317 for (int iter = 0; iter < 2; iter++)
318 {
319 COLORREF fgcolor;
320 COLORREF bgcolor = RGB(0xff,0xff,0xff);
321 HBRUSH bgbrush = nullptr;
322 int last_attrib = -1;
323 TCHAR buffer[256];
324 int count = 0;
325 RECT bounds;
326
327 // initialize the text bounds
328 bounds.left = bounds.right = 0;
329 bounds.top = row * metrics().debug_font_height();
330 bounds.bottom = bounds.top + metrics().debug_font_height();
331
332 // start with a brush on iteration #0
333 if (iter == 0)
334 bgbrush = CreateSolidBrush(bgcolor);
335
336 // iterate over columns
337 for (uint32_t col = 0; col < visarea.x; col++)
338 {
339 // if the attribute changed, adjust the colors
340 if (viewdata[col].attrib != last_attrib)
341 {
342 COLORREF oldbg = bgcolor;
343
344 // reset to standard colors
345 fgcolor = RGB(0x00,0x00,0x00);
346 bgcolor = RGB(0xff,0xff,0xff);
347
348 // pick new fg/bg colors
349 if (viewdata[col].attrib & DCA_VISITED) bgcolor = RGB(0xc6, 0xe2, 0xff);
350 if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0);
351 if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80);
352 if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00);
353 if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80);
354 if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00);
355 if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff);
356 if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2);
357 if (viewdata[col].attrib & DCA_COMMENT) fgcolor = RGB(0x00,0x80,0x00);
358
359 // flush any pending drawing
360 if (count > 0)
361 {
362 bounds.right = bounds.left + (count * metrics().debug_font_width());
363 if (iter == 0)
364 FillRect(dc, &bounds, bgbrush);
365 else
366 ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
367 bounds.left = bounds.right;
368 count = 0;
369 }
370
371 // set the new colors
372 if (iter == 0 && oldbg != bgcolor)
373 {
374 DeleteObject(bgbrush);
375 bgbrush = CreateSolidBrush(bgcolor);
376 }
377 else if (iter == 1)
378 SetTextColor(dc, fgcolor);
379 last_attrib = viewdata[col].attrib;
380 }
381
382 // add this character to the buffer
383 buffer[count++] = viewdata[col].byte;
384 }
385
386 // flush any remaining stuff
387 if (count > 0)
388 {
389 bounds.right = bounds.left + (count * metrics().debug_font_width());
390 if (iter == 0)
391 FillRect(dc, &bounds, bgbrush);
392 else
393 ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
394 }
395
396 // erase to the end of the line
397 if (iter == 0)
398 {
399 bounds.left = bounds.right;
400 bounds.right = client.right;
401 FillRect(dc, &bounds, bgbrush);
402 DeleteObject(bgbrush);
403 }
404 }
405
406 // advance viewdata
407 viewdata += visarea.x;
408 }
409
410 // erase anything beyond the bottom with white
411 GetClientRect(m_wnd, &client);
412 client.top = visarea.y * metrics().debug_font_height();
413 FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
414
415 // reset the font
416 SetBkMode(dc, oldbkmode);
417 SetTextColor(dc, oldfgcolor);
418 SelectObject(dc, oldfont);
419
420 // blit the final results
421 BitBlt(windc, 0, 0, client.right, client.bottom, dc, 0, 0, SRCCOPY);
422
423 // undo the offscreen stuff
424 SelectObject(dc, oldbitmap);
425 DeleteObject(bitmap);
426 DeleteDC(dc);
427 }
428
429
update()430 void debugview_info::update()
431 {
432 RECT bounds, vscroll_bounds, hscroll_bounds;
433 debug_view_xy totalsize, visiblesize, topleft;
434 bool show_vscroll, show_hscroll;
435 SCROLLINFO scrollinfo;
436
437 // get the view window bounds
438 GetClientRect(m_wnd, &bounds);
439 visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
440 visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
441
442 // get the updated total rows/cols and left row/col
443 totalsize = m_view->total_size();
444 topleft = m_view->visible_position();
445
446 // determine if we need to show the scrollbars
447 show_vscroll = show_hscroll = false;
448 if (totalsize.x > visiblesize.x && bounds.bottom >= metrics().hscroll_height())
449 {
450 bounds.bottom -= metrics().hscroll_height();
451 visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
452 show_hscroll = true;
453 }
454 if (totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
455 {
456 bounds.right -= metrics().vscroll_width();
457 visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
458 show_vscroll = true;
459 }
460 if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
461 {
462 bounds.right -= metrics().vscroll_width();
463 visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
464 show_vscroll = true;
465 }
466
467 // compute the bounds of the scrollbars
468 GetClientRect(m_wnd, &vscroll_bounds);
469 vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width();
470 if (show_hscroll)
471 vscroll_bounds.bottom -= metrics().hscroll_height();
472
473 GetClientRect(m_wnd, &hscroll_bounds);
474 hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height();
475 if (show_vscroll)
476 hscroll_bounds.right -= metrics().vscroll_width();
477
478 // if we hid the scrollbars, make sure we reset the top/left corners
479 if (topleft.y + visiblesize.y > totalsize.y)
480 topleft.y = std::max(totalsize.y - visiblesize.y, 0);
481 if (topleft.x + visiblesize.x > totalsize.x)
482 topleft.x = std::max(totalsize.x - visiblesize.x, 0);
483
484 // fill out the scroll info struct for the vertical scrollbar
485 scrollinfo.cbSize = sizeof(scrollinfo);
486 scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
487 scrollinfo.nMin = 0;
488 scrollinfo.nMax = totalsize.y - 1;
489 scrollinfo.nPage = visiblesize.y;
490 scrollinfo.nPos = topleft.y;
491 SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE);
492
493 // fill out the scroll info struct for the horizontal scrollbar
494 scrollinfo.cbSize = sizeof(scrollinfo);
495 scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
496 scrollinfo.nMin = 0;
497 scrollinfo.nMax = totalsize.x - 1;
498 scrollinfo.nPage = visiblesize.x;
499 scrollinfo.nPos = topleft.x;
500 SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE);
501
502 // update window info
503 visiblesize.y++;
504 visiblesize.x++;
505 m_view->set_visible_size(visiblesize);
506 m_view->set_visible_position(topleft);
507
508 // invalidate the bounds
509 InvalidateRect(m_wnd, nullptr, FALSE);
510
511 // adjust the bounds of the scrollbars and show/hide them
512 if (m_vscroll)
513 {
514 if (show_vscroll)
515 smart_set_window_bounds(m_vscroll, m_wnd, vscroll_bounds);
516 smart_show_window(m_vscroll, show_vscroll);
517 }
518 if (m_hscroll)
519 {
520 if (show_hscroll)
521 smart_set_window_bounds(m_hscroll, m_wnd, hscroll_bounds);
522 smart_show_window(m_hscroll, show_hscroll);
523 }
524 }
525
526
process_scroll(WORD type,HWND wnd)527 uint32_t debugview_info::process_scroll(WORD type, HWND wnd)
528 {
529 // get the current info
530 SCROLLINFO scrollinfo;
531 scrollinfo.cbSize = sizeof(scrollinfo);
532 scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
533 GetScrollInfo(wnd, SB_CTL, &scrollinfo);
534
535 // by default we stay put
536 int32_t result = scrollinfo.nPos;
537
538 // determine the maximum value
539 int32_t const maxval = (scrollinfo.nMax > scrollinfo.nPage) ? (scrollinfo.nMax - scrollinfo.nPage + 1) : 0;
540
541 // handle the message
542 switch (type)
543 {
544 case SB_THUMBTRACK:
545 result = scrollinfo.nTrackPos;
546 break;
547
548 case SB_LEFT:
549 result = 0;
550 break;
551
552 case SB_RIGHT:
553 result = maxval;
554 break;
555
556 case SB_LINELEFT:
557 result -= 1;
558 break;
559
560 case SB_LINERIGHT:
561 result += 1;
562 break;
563
564 case SB_PAGELEFT:
565 result -= scrollinfo.nPage - 1;
566 break;
567
568 case SB_PAGERIGHT:
569 result += scrollinfo.nPage - 1;
570 break;
571 }
572
573 // generic rangecheck
574 if (result < 0)
575 result = 0;
576 if (result > maxval)
577 result = maxval;
578
579 // set the new position
580 scrollinfo.fMask = SIF_POS;
581 scrollinfo.nPos = result;
582 SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE);
583
584 return (uint32_t)result;
585 }
586
587
view_proc(UINT message,WPARAM wparam,LPARAM lparam)588 LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
589 {
590 // handle a few messages
591 switch (message)
592 {
593 // paint: redraw the last bitmap
594 case WM_PAINT:
595 {
596 PAINTSTRUCT pstruct;
597 HDC const dc = BeginPaint(m_wnd, &pstruct);
598 draw_contents(dc);
599 EndPaint(m_wnd, &pstruct);
600 break;
601 }
602
603 // keydown: handle debugger keys
604 case WM_SYSKEYDOWN:
605 if (wparam != VK_F10)
606 return DefWindowProc(m_wnd, message, wparam, lparam);
607 // (fall through)
608 case WM_KEYDOWN:
609 {
610 if (m_owner.handle_key(wparam, lparam))
611 {
612 m_owner.set_ignore_char_lparam(lparam);
613 }
614 else
615 {
616 switch (wparam)
617 {
618 case VK_UP:
619 m_view->process_char(DCH_UP);
620 m_owner.set_ignore_char_lparam(lparam);
621 break;
622
623 case VK_DOWN:
624 m_view->process_char(DCH_DOWN);
625 m_owner.set_ignore_char_lparam(lparam);
626 break;
627
628 case VK_LEFT:
629 if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
630 m_view->process_char(DCH_CTRLLEFT);
631 else
632 m_view->process_char(DCH_LEFT);
633 m_owner.set_ignore_char_lparam(lparam);
634 break;
635
636 case VK_RIGHT:
637 if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
638 m_view->process_char(DCH_CTRLRIGHT);
639 else
640 m_view->process_char(DCH_RIGHT);
641 m_owner.set_ignore_char_lparam(lparam);
642 break;
643
644 case VK_PRIOR:
645 m_view->process_char(DCH_PUP);
646 m_owner.set_ignore_char_lparam(lparam);
647 break;
648
649 case VK_NEXT:
650 m_view->process_char(DCH_PDOWN);
651 m_owner.set_ignore_char_lparam(lparam);
652 break;
653
654 case VK_HOME:
655 if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
656 m_view->process_char(DCH_CTRLHOME);
657 else
658 m_view->process_char(DCH_HOME);
659 m_owner.set_ignore_char_lparam(lparam);
660 break;
661
662 case VK_END:
663 if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
664 m_view->process_char(DCH_CTRLEND);
665 else
666 m_view->process_char(DCH_END);
667 m_owner.set_ignore_char_lparam(lparam);
668 break;
669
670 case VK_ESCAPE:
671 m_owner.set_default_focus();
672 m_owner.set_ignore_char_lparam(lparam);
673 break;
674
675 case VK_TAB:
676 if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
677 m_owner.prev_view(this);
678 else
679 m_owner.next_view(this);
680 m_owner.set_ignore_char_lparam(lparam);
681 break;
682 }
683 }
684 break;
685 }
686
687 // char: ignore chars associated with keys we've handled
688 case WM_CHAR:
689 if (m_owner.check_ignore_char_lparam(lparam))
690 {
691 if (waiting_for_debugger() || !seq_pressed())
692 {
693 if (wparam >= 32 && wparam < 127)
694 {
695 if (m_view->cursor_supported())
696 m_view->set_cursor_visible(true);
697 m_view->process_char(wparam);
698 }
699 else
700 {
701 return DefWindowProc(m_wnd, message, wparam, lparam);
702 }
703 }
704 }
705 break;
706
707 // gaining focus
708 case WM_SETFOCUS:
709 if (m_view->cursor_supported())
710 m_view->set_cursor_visible(true);
711 break;
712
713 // losing focus
714 case WM_KILLFOCUS:
715 if (m_view->cursor_supported())
716 m_view->set_cursor_visible(false);
717 break;
718
719 // mouse click
720 case WM_LBUTTONDOWN:
721 {
722 debug_view_xy topleft = m_view->visible_position();
723 debug_view_xy newpos;
724 newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width();
725 newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height();
726 m_view->process_click(DCK_LEFT_CLICK, newpos);
727 SetFocus(m_wnd);
728 break;
729 }
730
731 // hscroll
732 case WM_HSCROLL:
733 {
734 debug_view_xy topleft = m_view->visible_position();
735 topleft.x = process_scroll(LOWORD(wparam), (HWND)lparam);
736 m_view->set_visible_position(topleft);
737 machine().debug_view().flush_osd_updates();
738 break;
739 }
740
741 // vscroll
742 case WM_VSCROLL:
743 {
744 debug_view_xy topleft = m_view->visible_position();
745 topleft.y = process_scroll(LOWORD(wparam), (HWND)lparam);
746 m_view->set_visible_position(topleft);
747 machine().debug_view().flush_osd_updates();
748 break;
749 }
750
751 // everything else: defaults
752 default:
753 return DefWindowProc(m_wnd, message, wparam, lparam);
754 }
755
756 return 0;
757 }
758
759
static_update(debug_view & view,void * osdprivate)760 void debugview_info::static_update(debug_view &view, void *osdprivate)
761 {
762 auto *const info = (debugview_info *)osdprivate;
763 assert(info->m_view == &view);
764 info->update();
765 }
766
767
static_view_proc(HWND wnd,UINT message,WPARAM wparam,LPARAM lparam)768 LRESULT CALLBACK debugview_info::static_view_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
769 {
770 if (message == WM_CREATE)
771 {
772 // set the info pointer
773 CREATESTRUCT const *const createinfo = (CREATESTRUCT *)lparam;
774 SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams);
775 return 0;
776 }
777
778 auto *const info = (debugview_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA);
779 if (info == nullptr)
780 return DefWindowProc(wnd, message, wparam, lparam);
781
782 assert((info->m_wnd == wnd) || (info->m_wnd == nullptr));
783 return info->view_proc(message, wparam, lparam);
784 }
785
786
register_window_class()787 void debugview_info::register_window_class()
788 {
789 if (!s_window_class_registered)
790 {
791 WNDCLASS wc = { 0 };
792
793 // initialize the description of the window class
794 wc.lpszClassName = TEXT("MAMEDebugView");
795 wc.hInstance = GetModuleHandleUni();
796 wc.lpfnWndProc = &debugview_info::static_view_proc;
797 wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
798 wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(2));
799 wc.lpszMenuName = nullptr;
800 wc.hbrBackground = nullptr;
801 wc.style = 0;
802 wc.cbClsExtra = 0;
803 wc.cbWndExtra = 0;
804
805 UnregisterClass(wc.lpszClassName, wc.hInstance);
806
807 // register the class; fail if we can't
808 if (!RegisterClass(&wc))
809 fatalerror("Unable to register debug view class\n");
810
811 s_window_class_registered = true;
812 }
813 }
814