home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / gtkcallbacks.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  82.7 KB  |  3,411 lines

  1. #ifdef HAVE_CONFIG_H
  2. #  include <config.h>
  3. #endif
  4.  
  5. #include <gtk/gtk.h>
  6. #include <gdk/gdkkeysyms.h>
  7.  
  8. #if 0 && defined(UNDER_WIN32)
  9. #define WIN32_LEAN_AND_MEAN
  10. #include <gdk/win32/gdkwin32.h>
  11. #endif
  12.  
  13. #include "gtkcallbacks.h"
  14. #include "gtkinterface.h"
  15. #include "gtksupport.h"
  16.  
  17. #include "gtk_v99filesel.h"
  18.  
  19. #include "gtkloop.h"
  20.  
  21. #include "v9t9_common.h"
  22. #include "v9t9.h"
  23. #include "moduleconfig.h"
  24. #include "moduledb.h"
  25. #include "debugger.h"
  26. #include "dsr.h"
  27. #include "vdp.h"
  28. #include "fiad.h"
  29. #include "roms.h"
  30. #include "timer.h"
  31. #include "config.h"
  32.  
  33. #define _L LOG_VIDEO
  34. #include "log.h"
  35.  
  36. /*
  37.  *    Initial window size configured?
  38.  */
  39. int GTK_size_configured;
  40.  
  41. /*
  42.  *    Size of TI screen
  43.  */
  44. int GTK_x_size, GTK_y_size;
  45.  
  46. /*
  47.  *    Size of drawing area (as of last configure_event)
  48.  *    and multiple of x_size and y_size this is 
  49.  */
  50. int GTK_x_pixels, GTK_y_pixels, GTK_x_mult, GTK_y_mult;
  51. int GTK_user_size_configured;
  52.  
  53. /*
  54.  *    "Pause" button
  55.  */
  56. GtkButton    *v9t9_window_pause_button;
  57.  
  58. /*
  59.  *    Make a tag for a widget used in setting unique names
  60.  *    for repeated members of an object
  61.  */
  62. static char *
  63. widget_tag(const char *base, int number, int mag)
  64. {
  65.     static char widget_tag_buf[32];
  66.     int len = strlen(base);
  67.     unsigned int nyb = mag;
  68.     memcpy(widget_tag_buf, base, len);
  69.     while (nyb) {
  70.         widget_tag_buf[len++] = "0123456789ABCDEF"[number & nyb];
  71.         nyb >>= 4;
  72.     }
  73.     widget_tag_buf[len] = 0;
  74.     return widget_tag_buf;
  75. }
  76.  
  77. void
  78. on_v9t9_window_destroy                 (GtkObject       *object,
  79.                                         gpointer         user_data)
  80. {
  81.     gtk_main_quit();
  82.     v9t9_sigterm(1);
  83. }
  84.  
  85.  
  86. gboolean
  87. on_v9t9_draw_area_configure_event      (GtkWidget       *widget,
  88.                                         GdkEventConfigure *event,
  89.                                         gpointer         user_data)
  90. {
  91. /*    g_print("configure_event, ev =%d,%d req=%d,%d alloc=%d,%d\n",
  92.             event->width, event->height,
  93.             widget->requisition.width, widget->requisition.height,
  94.             widget->allocation.width, widget->allocation.height);*/
  95.  
  96. #if defined(UNDER_WIN32)
  97.     if (gtkVideo.runtimeflags & vmRTUnselected)
  98.     {
  99.         if (v9t9_drawing_area)
  100.         {
  101.             gtk_widget_destroy(v9t9_drawing_area);
  102.             v9t9_drawing_area = NULL;
  103.         }
  104.     }
  105. #endif
  106.  
  107. #if 0 && defined(UNDER_WIN32)    
  108.     // an attempt to make an actual window be reparented
  109.     // inside the v9t9_drawing_area... doesn't seem to work
  110.     {
  111.         GdkWindow    *window;
  112.         GtkWidget *parent;
  113.         GtkWidget *area;
  114.         extern HWND hWndWindow;
  115.         
  116.         parent = v9t9_drawing_area->parent;
  117.         window = gdk_window_foreign_new ((guint32) hWndWindow);
  118.         gtk_widget_destroy(v9t9_drawing_area);
  119.         v9t9_drawing_area = gtk_drawing_area_new();
  120.         v9t9_drawing_area->window = window;
  121.         gtk_widget_show(v9t9_drawing_area);
  122. //        area = gtk_widget_new();
  123. //        area->window = window;
  124.         
  125.         gtk_container_add(GTK_CONTAINER(parent), v9t9_drawing_area);
  126.     }
  127.  
  128. #endif
  129.  
  130.     GTK_x_mult = (widget->requisition.width) / GTK_x_size;
  131.     GTK_y_mult = (widget->requisition.height) / GTK_y_size;
  132.  
  133.     if (!GTK_x_mult)    GTK_x_mult = 1;
  134.     if (!GTK_y_mult)    GTK_y_mult = 1;
  135.  
  136.     if (GTK_x_size * GTK_x_mult != GTK_x_pixels ||
  137.         GTK_y_size * GTK_y_mult != GTK_y_pixels) 
  138.     {
  139.         GTK_x_pixels = GTK_x_size * GTK_x_mult;
  140.         GTK_y_pixels = GTK_y_size * GTK_y_mult;
  141.  
  142.         vdpcompleteredraw();
  143.     }
  144.  
  145.     return TRUE;
  146. }
  147.  
  148. /*
  149.  *    Make sure the size of the widget is a multiple of 256 and 192
  150.  */
  151. void
  152. on_v9t9_draw_area_size_request         (GtkWidget       *widget,
  153.                                         GtkRequisition  *requisition,
  154.                                         gpointer         user_data)
  155. {
  156.     int psx, psy;
  157.     GtkWidget *main;
  158.  
  159. /*    g_print("size_request, Req=%d,%d, req=%d,%d alloc=%d,%d\n",
  160.             requisition->width, requisition->height,
  161.             widget->requisition.width, widget->requisition.height,
  162.             widget->allocation.width, widget->allocation.height);
  163.     
  164.     g_print("\tparent's parent's size is %d,%d\n", 
  165.             widget->parent->parent->allocation.width,
  166.             widget->parent->parent->allocation.height);*/
  167.  
  168.     // base our size on main window size
  169.     main = widget->parent;
  170.     while (main && !GTK_IS_WINDOW(main)) {
  171.         main = main->parent;
  172.     }
  173.  
  174.     g_assert(main);
  175.  
  176.     if (!GTK_x_size)    GTK_x_size = 256;
  177.     if (!GTK_y_size)    GTK_y_size = 192;
  178.  
  179.     if (GTK_size_configured || GTK_user_size_configured) {
  180.  
  181.         // did user specify the size?
  182.         if (GTK_user_size_configured) {
  183.             psx = GTK_x_mult * 256;
  184.             psy = GTK_y_mult * 192;
  185.             GTK_user_size_configured = 0;
  186.         } else {
  187.             // else, use parent's size
  188.             psx = widget->allocation.width;
  189.             psy = widget->allocation.height;
  190.  
  191.             // ignore smaller window size and keep existing size
  192.             if (psx < 256 || psy < 192) {
  193.                 psx = main->allocation.width;
  194.                 psy = main->allocation.height;
  195.             }
  196.  
  197.             if (psx < 256 || psy < 192) {
  198.                 psx = 256;
  199.                 psy = 192;
  200.             }
  201.         } 
  202.  
  203.     } else {
  204.  
  205.         // if sizes not set up yet (say, by v9t9 reading -geometry),
  206.         // take up 1/2 of the screen
  207.  
  208.         psx = gdk_screen_width() / 2 / GTK_x_size;
  209.         psy = gdk_screen_height() / 2 / GTK_y_size;
  210.  
  211.         // fix to an aspected multiple of 256x192
  212.         if (psx < 1) psx = 1;
  213.         if (psy < 1) psy = 1;
  214.         if (psx < psy) psx = psy;
  215.         psx *= GTK_x_size;
  216.         psy *= GTK_y_size;
  217.     }
  218.  
  219.     GTK_size_configured = 1;
  220.  
  221.     if (psx > 16384) {
  222.         psx = 16384;
  223.     }
  224.     if (psy > 16384) {
  225.         psy = 16384;
  226.     }
  227.  
  228.     // don't resize to 240 for text mode, since when the mode switches
  229.     // back to graphics, the window will shrink to 1/2 size
  230.     requisition->width = (psx / 256 /*GTK_x_size*/) * 256 /*GTK_x_size*/;
  231.     if (requisition->width < 256 /*GTK_x_size*/) requisition->width = 256 /*GTK_x_size*/;
  232.     requisition->height = (psy / GTK_y_size) * GTK_y_size;
  233.     if (requisition->height < GTK_y_size) requisition->height = GTK_y_size;
  234. }
  235.  
  236. #if 0 && defined(UNDER_WIN32)
  237. extern HWND hWndWindow;
  238. extern LRESULT CALLBACK WindowWndProc( HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam );
  239. void gtk_window_paint(RECT *updaterect);
  240. #endif
  241.  
  242. gboolean
  243. on_v9t9_draw_area_expose_event         (GtkWidget       *widget,
  244.                                         GdkEventExpose  *event,
  245.                                         gpointer         user_data)
  246. {
  247.     gint x,y,sx,sy;
  248.     int xoffs;
  249.  
  250.     xoffs = (256 - GTK_x_size) * GTK_x_mult / 2;
  251.     x = (event->area.x - xoffs);
  252.     y = (event->area.y);
  253.  
  254.     sx = (event->area.width);
  255.     sy = (event->area.height);
  256.  
  257.     // we can get expose events for stuff outside window
  258.     if (x < 0)    { sx += x;  x = 0; }
  259.     if (x >= GTK_x_pixels) return FALSE;
  260.     if (y < 0)    { sy += y;  y = 0; }
  261.     if (y >= GTK_y_pixels) return FALSE;
  262.  
  263.     if (sx + x > GTK_x_pixels)    sx = GTK_x_pixels - x;
  264.     if (sy + y > GTK_y_pixels)    sy = GTK_y_pixels - y;
  265.  
  266.     sx = (sx + (x % GTK_x_mult) + GTK_x_mult - 1) / GTK_x_mult;
  267.     sy = (sy + (y % GTK_y_mult) + GTK_y_mult - 1) / GTK_y_mult;
  268.     x /= GTK_x_mult;
  269.     y /= GTK_y_mult;
  270.  
  271.     logger(_L|L_2, "for expose %d,%d, dirtying (%d,%d) to (%d,%d)\n",
  272.            GTK_x_mult, GTK_y_mult, x,y,x+sx,y+sy);
  273.  
  274. #if 0 && defined(UNDER_WIN32)
  275. {
  276.     RECT updaterect;
  277.     #define AREA(x) event->area.x
  278.     updaterect.left = AREA(x);
  279.     updaterect.right = AREA(x) + AREA(width);
  280.     updaterect.top = AREA(y);
  281.     updaterect.bottom = AREA(y) + AREA(height);
  282.  
  283.     vdp_dirty_screen(x, y, sx, sy);
  284.     //gtk_window_paint(&updaterect);
  285.     //ValidateRect(hWndWindow, NULL);
  286.     return TRUE;
  287. }
  288. #else
  289.     GTK_clear_sides(256, GTK_x_size);
  290.     vdp_dirty_screen(x, y, sx, sy);
  291.  
  292. #endif
  293.  
  294.     return TRUE;
  295. }
  296.  
  297.  
  298. gboolean
  299. on_v9t9_draw_area_draw                 (GtkWidget       *widget,
  300.                                         GdkRectangle  *area,
  301.                                         gpointer         user_data)
  302. {
  303.     return FALSE;
  304. }
  305.  
  306. /*
  307.  *    bring up command dialog on right click
  308.  */
  309. gboolean
  310. on_v9t9_drawing_area_button_press_event
  311.                                         (GtkWidget       *widget,
  312.                                         GdkEventButton  *event,
  313.                                         gpointer         user_data)
  314. {
  315.     // bring up v9t9 window
  316.     if (event->button == 1) {
  317.         gdk_window_raise(v9t9_window->window);
  318.     }
  319.     // raise command dialog to center on cursor
  320.     else if (event->button > 1) {
  321.         gdk_window_raise(command_center->window);
  322.         gtk_widget_activate(command_center);
  323.         gtk_widget_set_uposition(command_center, 
  324.                                  event->x_root - command_center->allocation.width / 2, 
  325.                                  event->y_root - command_center->allocation.height / 2);
  326.     }
  327.     return TRUE;
  328. }
  329.  
  330.  
  331. gboolean
  332. on_v9t9_key_press_event                (GtkWidget       *widget,
  333.                                         GdkEventKey     *event,
  334.                                         gpointer         user_data)
  335. {    
  336.     GTK_keyboard_set_key(event->keyval, 1);
  337.     return TRUE;
  338. }
  339.  
  340.  
  341. gboolean
  342. on_v9t9_key_release_event              (GtkWidget       *widget,
  343.                                         GdkEventKey     *event,
  344.                                         gpointer         user_data)
  345. {
  346.     GTK_keyboard_set_key(event->keyval, 0);
  347.     return TRUE;
  348. }
  349.  
  350. /*
  351. gboolean
  352. on_v9t9_draw_area_focus_out_event      (GtkWidget       *widget,
  353.                                         GdkEventFocus   *event,
  354.                                         gpointer         user_data)
  355. {
  356.     g_print("focused out!\n");
  357. //    gtk_window_set_focus(widget->parent->parent, widget);
  358.     return TRUE;
  359. }
  360. */
  361.  
  362. #define GTK_RESTORE_FOCUS \
  363.     gtk_widget_grab_focus(v9t9_window);\
  364.     gtk_window_set_focus(GTK_WINDOW(v9t9_window), v9t9_drawing_area)
  365.  
  366. gboolean
  367. on_v9t9_window_enter_notify_event      (GtkWidget       *widget,
  368.                                         GdkEventCrossing *event,
  369.                                         gpointer         user_data)
  370. {
  371. //    g_print("v9t9_window_enter\n");
  372.     GTK_RESTORE_FOCUS;
  373.     return FALSE;
  374. }
  375.  
  376.  
  377. gboolean
  378. on_v9t9_draw_area_enter_notify_event   (GtkWidget       *widget,
  379.                                         GdkEventCrossing *event,
  380.                                         gpointer         user_data)
  381. {
  382. //    g_print("v9t9_drawing_area_enter\n");
  383.     GTK_RESTORE_FOCUS;
  384.  
  385.     return FALSE;
  386. }
  387.  
  388. #if 0
  389. #pragma mark -
  390. #endif
  391.  
  392. /*
  393.  *    This is a callback for a generic button that has a fixed 
  394.  *    command string in user_data.
  395.  */
  396. void
  397. on_v9t9_button_clicked                 (GtkButton       *button,
  398.                                         gpointer         user_data)
  399. {
  400.     GTK_send_command((const gchar *)user_data);
  401. }
  402.  
  403. /*
  404.  *    This is for a generic cancel button which will unpause the
  405.  *    computer.
  406.  */
  407. void
  408. on_v9t9_button_cancel                  (GtkButton       *button,
  409.                                         gpointer         user_data)
  410. {
  411.     if (!debugger_enabled())
  412.         execution_pause(false);
  413.  
  414.     gtk_widget_destroy(GTK_WIDGET(user_data));
  415. }
  416.  
  417.  
  418. void
  419. on_v9t9_pause_button_clicked           (GtkButton       *button,
  420.                                         gpointer         user_data)
  421. {
  422.     v9t9_window_pause_button = button;
  423.     execution_pause(!execution_paused());
  424. }
  425.  
  426.  
  427. void
  428. on_quit_button_clicked                 (GtkButton       *button,
  429.                                         gpointer         user_data)
  430. {
  431.     GtkWidget *dialog = create_quit_dialog();
  432.     gtk_widget_show(dialog);
  433.  
  434.     if (!debugger_enabled())
  435.         execution_pause(true);
  436. }
  437.  
  438. gboolean
  439. on_v9t9_window_configure_event         (GtkWidget       *widget,
  440.                                         GdkEventConfigure *event,
  441.                                         gpointer         user_data)
  442. {
  443. //    gtk_window_set_focus(GTK_WINDOW(widget), v9t9_drawing_area);
  444.     return FALSE;
  445. }
  446.  
  447. /***********************************/
  448. #if 0
  449. #pragma mark -
  450. #endif
  451.  
  452. typedef struct {
  453.     GList *lines;
  454.     int index;
  455. }    History;
  456.  
  457. static GtkWidget *command_text_entry;
  458. static History *command_text_history;
  459.  
  460. static History *history_get(History **where)
  461. {
  462.     if (!*where) {
  463.         *where = (History *)g_malloc(sizeof(History));
  464.  
  465.         (*where)->lines = g_list_alloc();
  466.         (*where)->index = 0;
  467.     }
  468.     return *where;
  469. }
  470.  
  471. static void    history_append(History *history, gpointer data)
  472. {
  473.     g_list_append(history->lines, data);
  474.     history->index = g_list_length(history->lines);
  475. }
  476.  
  477. static void    history_update(History *history, gpointer data)
  478. {
  479.     if (history->index == g_list_length(history->lines)) {
  480.         
  481.     }
  482. }
  483.  
  484. static void    history_remove(History *history)
  485. {
  486.     int length = g_list_length(history->lines);
  487.     if (length) {
  488.         g_list_free(g_list_last(history->lines));
  489.         history->index = MIN(history->index, length);
  490.     }
  491. }
  492.  
  493. static gpointer *history_prev(History *history)
  494. {
  495.     if (history->index > 0) {
  496.         history->index--;
  497.     }
  498.     return g_list_nth_data(history->lines, history->index);
  499. }
  500.  
  501. static gpointer *history_next(History *history)
  502. {
  503.     if (history->index + 1 < g_list_length(history->lines)) {
  504.         history->index++;
  505.     }
  506.     return g_list_nth_data(history->lines, history->index);
  507. }
  508.  
  509. /*
  510.  *    Someone has entered text in the window.  
  511.  *    Need to turn on interactive mode temporarily, or 
  512.  *    make the entry insensitive.
  513.  *
  514.  *    user_data is the text box
  515.  */
  516. void
  517. on_command_text_entry_activate         (GtkEditable     *editable,
  518.                                         gpointer         user_data)
  519. {
  520.     History *history = history_get(&command_text_history);
  521.  
  522.     // get line of text
  523.     gchar *text = gtk_editable_get_chars(editable, 0, -1);
  524.  
  525.     // execute text
  526.     GTK_send_command(text);
  527.  
  528.     // append it
  529.     history_append(history, text);
  530.  
  531. //    g_free(text);
  532.  
  533.     // select text so it can be cleared
  534.     gtk_editable_select_region(editable, 0, -1);
  535. }
  536.  
  537. gboolean
  538. on_command_text_entry_key_press_event  (GtkWidget       *widget,
  539.                                         GdkEventKey     *event,
  540.                                         gpointer         user_data)
  541. {
  542.     gchar *text;
  543.     History *history = history_get(&command_text_history);
  544.     gint pos;
  545.     GtkEditable *editable = GTK_EDITABLE(widget);
  546.  
  547.     // handle up and down arrow for history
  548.     switch (event->keyval) 
  549.     {
  550.     case GDK_Up:
  551.     case GDK_Page_Up:
  552.         text = gtk_editable_get_chars(editable, 0, -1);
  553.         history_update(history, text);
  554.         text = (gchar *)history_prev(history);
  555.         if (text) {
  556.             gtk_editable_delete_text(editable, 0, -1);
  557.             pos = 0;
  558.             gtk_editable_insert_text(editable, 
  559.                                      text, strlen(text),
  560.                                      &pos);
  561.         } else {
  562.             //    history_remove(history);
  563.         }
  564.         break;
  565.     case GDK_Down:
  566.     case GDK_Page_Down:
  567.         text = gtk_editable_get_chars(editable, 0, -1);
  568.         history_update(history, text);
  569.         text = (gchar *)history_next(history);
  570.         if (text) {
  571.             gtk_editable_delete_text(editable, 0, -1);
  572.             pos = 0;
  573.             gtk_editable_insert_text(editable, 
  574.                                      text, strlen(text),
  575.                                      &pos);
  576.         } else {
  577.             //        history_remove(history);
  578.         }
  579.         break;
  580.  
  581.         // notice these keys
  582.     case GDK_End:
  583.     case GDK_Left:
  584.         if (editable->has_selection) {
  585.             text = gtk_editable_get_chars(editable, 0, -1);
  586.             gtk_editable_select_region(editable, 0, 0);
  587.             gtk_editable_set_position(editable, strlen(text));
  588.             g_free(text);
  589.         }
  590.         break;
  591.  
  592.     case GDK_Home:
  593.     case GDK_Right:
  594.         if (editable->has_selection) {
  595.             gtk_editable_select_region(editable, 0, 0);
  596.             gtk_editable_set_position(editable, 0);
  597.         }
  598.         break;
  599.  
  600.  
  601.     default:
  602.         return TRUE;
  603.     }
  604.     return TRUE;
  605. }
  606.  
  607. void
  608. on_log_text_box_realize_event          (GtkWidget       *widget,
  609.                                         gpointer         user_data)
  610. {
  611.     v9t9_command_log = widget;
  612. }
  613.  
  614. /*
  615.  *    Flush text in command log
  616.  */
  617. void
  618. on_flush_item_activate                 (GtkMenuItem     *menuitem,
  619.                                         gpointer         user_data)
  620. {
  621.     GTK_flush_log();
  622. }
  623.  
  624. #if 0
  625. #pragma mark -
  626. #endif
  627.  
  628. /*
  629.  *    Select text font
  630.  */
  631.  
  632. static GtkWidget *font_selector;
  633. static gchar     *last_font_selected;
  634.  
  635. void
  636. on_font_item_activate                  (GtkMenuItem     *menuitem,
  637.                                         gpointer         user_data)
  638. {
  639.     if (!VALID_WINDOW(font_selector)) {
  640.         font_selector = create_command_log_font_selector();
  641.     } else {
  642.         gtk_widget_hide(font_selector);
  643.     }
  644.  
  645.     if (last_font_selected) {
  646.         gtk_font_selection_dialog_set_font_name(
  647.             GTK_FONT_SELECTION_DIALOG(font_selector),
  648.             last_font_selected);
  649.     }
  650.  
  651.     gtk_widget_show(font_selector);
  652. }
  653.  
  654.  
  655. void
  656. on_command_log_font_selector_ok_button1_clicked
  657.                                         (GtkButton       *button,
  658.                                         gpointer         user_data)
  659. {
  660.     char *fontname;
  661.  
  662.     fontname = gtk_font_selection_dialog_get_font_name(
  663.         GTK_FONT_SELECTION_DIALOG(font_selector));
  664.     GTK_change_log_font(fontname);
  665.  
  666.     if (last_font_selected)
  667.         g_free(last_font_selected);
  668.  
  669.     last_font_selected = fontname;
  670.     gtk_widget_hide(font_selector);
  671. }
  672.  
  673.  
  674. void
  675. on_command_log_font_selector_apply_button1_clicked
  676.                                         (GtkButton       *button,
  677.                                         gpointer         user_data)
  678. {
  679.     gchar *fontname;
  680.  
  681.     fontname = gtk_font_selection_dialog_get_font_name(
  682.         GTK_FONT_SELECTION_DIALOG(font_selector));
  683.     GTK_change_log_font(fontname);
  684.  
  685.     g_free(fontname);
  686. }
  687.  
  688.  
  689. void
  690. on_command_log_font_cancel1_button_clicked
  691.                                         (GtkButton       *button,
  692.                                         gpointer         user_data)
  693. {
  694.     GTK_change_log_font(last_font_selected);
  695.     gtk_widget_hide(font_selector);
  696. }
  697.  
  698.  
  699.  
  700.  
  701. gboolean
  702. on_command_text_entry_event            (GtkWidget       *widget,
  703.                                         GdkEvent        *event,
  704.                                         gpointer         user_data)
  705. {
  706.   return FALSE;
  707. }
  708.  
  709.  
  710. gboolean
  711. on_command_dialog_key_press_event      (GtkWidget       *widget,
  712.                                         GdkEventKey     *event,
  713.                                         gpointer         user_data)
  714. {
  715. /*    if (event->keyval == GDK_Up || event->keyval == GDK_Down) {
  716.         gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
  717.         gtk_signal_emit_by_name(GTK_OBJECT(user_data), "key_press_event", event);
  718.     }
  719. */
  720.     return FALSE;
  721. }
  722.  
  723.  
  724. void
  725. on_command_dialog_destroy        (GtkObject                *object,
  726.                                   gpointer                 user_data)
  727. {
  728.     gtk_main_quit();
  729.     v9t9_sigterm(1);
  730. }
  731.  
  732. /***********************************************************************/
  733. #if 0
  734. #pragma mark -
  735. #endif
  736.  
  737. /*
  738.  *    Module selection dialog
  739.  */
  740.  
  741. static GtkWidget *module_dialog;
  742. static GtkToggleButton *module_reset_toggle;
  743.  
  744. /*    These must correspond with columns in dialog */
  745. enum
  746. {
  747.     mc_text_name,
  748.     mc_tag_name,
  749.     mc_setup_commands
  750. };
  751.  
  752. static void
  753. module_clist_prefix_clear(GtkWidget *widget);
  754.  
  755. void
  756. on_v9t9_window_module_button_clicked   (GtkButton       *button,
  757.                                         gpointer         user_data)
  758. {
  759.     GtkWidget *clist;
  760.  
  761.     if (!VALID_WINDOW(module_dialog)) {
  762.         module_dialog = create_modules_dialog();
  763.         module_reset_toggle = 0L;
  764.     } else {
  765.         gtk_widget_hide(module_dialog);
  766.     }
  767.  
  768.     clist = gtk_object_get_data((GtkObject *)module_dialog, "module_clist");
  769.     if (clist) module_clist_prefix_clear(clist);
  770.     gtk_widget_show(module_dialog);
  771. }
  772.  
  773. void
  774. on_module_clist_load_button_clicked    (GtkButton       *button,
  775.                                         gpointer         user_data)
  776. {
  777.     GtkCList *clist;
  778.     GList *list;
  779.  
  780.     g_return_if_fail(GTK_IS_CLIST(clist = user_data));
  781.  
  782.     // Step through list of selected modules 
  783.     // and load them up
  784.     list = clist->selection;
  785.  
  786.     while (list) 
  787.     {
  788.         gint row = (gint)(list->data);
  789.         ModuleEntry *ent = (ModuleEntry *)gtk_clist_get_row_data(clist, row);
  790.  
  791.         if (ent) module_load(ent);
  792.         list = list->next;
  793.     }
  794.  
  795.     if (clist->selection
  796.         && (!module_reset_toggle ||
  797.             gtk_toggle_button_get_active(module_reset_toggle)))
  798.     {
  799.         GTK_send_command("ResetComputer\n");
  800.     }
  801.  
  802.     // Unselect items
  803.     gtk_clist_unselect_all(clist);
  804.  
  805.     GTK_RESTORE_FOCUS;
  806. }
  807.  
  808.  
  809. void
  810. on_module_clist_close_button_clicked  (GtkButton       *button,
  811.                                        gpointer         user_data)
  812. {
  813.     GtkCList *clist;
  814.     g_return_if_fail(GTK_IS_CLIST(clist = user_data));
  815.  
  816.     // Unselect items
  817.     gtk_clist_unselect_all(clist);
  818.  
  819.     gtk_widget_hide(module_dialog);
  820. //    module_reset_toggle = 0L;
  821. //    module_dialog = 0L;
  822.  
  823.     GTK_RESTORE_FOCUS;
  824. }
  825.  
  826. #define ALT_KEY(x)        \
  827.      ((x) == GDK_Meta_L ||\
  828.       (x) == GDK_Meta_R ||\
  829.       (x) == GDK_Alt_L ||\
  830.       (x) == GDK_Alt_R)
  831.  
  832. /*
  833.  *    Don't intercept ALT-key shortcuts
  834.  */
  835. gboolean
  836. on_clist_key_release_event             (GtkWidget       *widget,
  837.                                         GdkEventKey     *event,
  838.                                         gpointer         user_data)
  839. {
  840.     if (ALT_KEY(event->keyval)) {
  841.         gtk_object_set_data(GTK_OBJECT(widget), "alt_down", (gpointer)0);
  842.     }
  843.     return FALSE;
  844. }
  845.  
  846. /*
  847.  *    Key was pressed in (module) clist.
  848.  *
  849.  *    Create a prefix string from the keys pressed and find
  850.  *    a suitable match in the given column in (int)user_data.
  851.  */
  852. gboolean
  853. on_clist_key_press_event               (GtkWidget       *widget,
  854.                                         GdkEventKey     *event,
  855.                                         gpointer         user_data)
  856. {
  857.     GtkCList *clist;
  858.     gchar *old;
  859.     char *prefix_name;
  860.     gchar *prefix;
  861.     int row;
  862.     int col = (int)user_data;
  863.     GList *list;
  864.     int current;
  865.     gboolean matched;
  866.  
  867.     g_return_val_if_fail(GTK_IS_CLIST(widget), false);
  868.  
  869.     clist = GTK_CLIST(widget);
  870.  
  871.     prefix_name = widget_tag("prefix_string_", col, 1);
  872.     old = gtk_object_get_data(GTK_OBJECT(widget), prefix_name);
  873.  
  874.     /*
  875.      *    Don't intercept ALT keys
  876.      */
  877.     if (ALT_KEY(event->keyval))
  878.     {
  879.         gtk_object_set_data(GTK_OBJECT(widget), "alt_down", (gpointer)1);
  880.         return false;
  881.     }
  882.  
  883.     if ((int)gtk_object_get_data(GTK_OBJECT(widget), "alt_down"))
  884.     {
  885.         return false;
  886.     }
  887.  
  888.     /*
  889.      *    Ignore accelerator keys
  890.      */
  891.     if (event->keyval == GDK_Escape)
  892.     {
  893.         return false;
  894.     }
  895.  
  896.     /*
  897.      *    Start off with some old prefix value to compare against
  898.      */
  899.     if (!old)
  900.         old = g_strdup("");
  901.  
  902.     /*
  903.      *    Don't append non-printable characters, which we assume
  904.      *    are control characters intended to clear the prefix.
  905.      */
  906.     if (event->string && *event->string && isprint(*event->string))
  907.     {
  908.         prefix = g_strconcat(old, event->string, 0L);
  909.     }
  910.     else
  911.     {
  912.         gtk_clist_unselect_all(clist);
  913.         prefix = g_strdup("");
  914.     }
  915.  
  916.     /* find current selection */
  917.     list = clist->selection;
  918.     
  919.     /* find item with this prefix */
  920.     current = (list ? (gint)list->data : -1);
  921.     matched = false;
  922.  
  923. //    g_print("prefix='%s', current=%d\n", prefix, current);
  924.  
  925.     if (*prefix)
  926.     for (row = 0; row < clist->rows; row++) {
  927.         gchar *text;
  928.         if (gtk_clist_get_text(clist, row, col, &text)
  929.             && strncasecmp(text, prefix, strlen(prefix)) == 0) {
  930.             current = row;
  931.             matched = true;
  932.             break;
  933.         }
  934.     }
  935.  
  936. //    g_print("old='%s', event='%s'\n", old, event->string);
  937.  
  938.     /* if we couldn't find one with new prefix,
  939.        and this new key is a suffix of the last
  940.        prefix, look for another one matching... */
  941.  
  942.     if (!matched
  943.         && event->string && *event->string 
  944.         && strcasecmp(old + strlen(old) - strlen(event->string),
  945.                       event->string) == 0)
  946.     {
  947.         if (list) {
  948.             current = (gint)list->data;
  949.             if (current < 0 || current >= clist->rows)
  950.                 current = 0;
  951.         }
  952.         else
  953.             current = 0;
  954.  
  955. //        g_print("current=%d, list->data=%d\n", current, list->data);
  956.         g_free(prefix);
  957.         prefix = g_strdup(old);
  958.  
  959.         for (row = current + 1; row != current; 
  960.              row = (row + 1 >= clist->rows ? 0 : row + 1)) {
  961.             gchar *text;
  962.             if (gtk_clist_get_text(clist, row, col, &text)
  963.                 && strncasecmp(text, prefix, strlen(prefix)) == 0) {
  964.                 current = row;
  965.                 matched = true;
  966.                 break;
  967.             }
  968.         }
  969.     }
  970.  
  971.     gtk_object_set_data(GTK_OBJECT(widget), prefix_name, prefix);
  972.  
  973.     if (matched && current != -1) {
  974.         gtk_clist_undo_selection(clist);
  975.         clist->focus_row = current;
  976.         gtk_clist_select_row(clist, current, 0 /*col*/);
  977.         gtk_clist_moveto(clist, current, 0 /*col*/, 0.5, 0.5);
  978.     } else if (!matched) {
  979.         gtk_clist_undo_selection(clist);
  980.     }
  981.  
  982.     g_free(old);
  983.     return TRUE;
  984. }
  985.  
  986. static void
  987. module_clist_prefix_clear(GtkWidget *widget)
  988. {
  989.     gchar *prefix;
  990.     int i;
  991.     for (i=0; i < 2; i++) {
  992.         char *name = widget_tag("prefix_string_", i, 1);
  993.         prefix = (gchar *)gtk_object_get_data(GTK_OBJECT(widget), name);
  994.         if (prefix) g_free(prefix);
  995.         gtk_object_set_data(GTK_OBJECT(widget), name, 0L);
  996.     }
  997. }
  998.  
  999. gboolean
  1000. on_module_clist_event                  (GtkWidget       *widget,
  1001.                                         GdkEvent        *event,
  1002.                                         gpointer         user_data)
  1003. {
  1004.     if ((event->type == GDK_KEY_PRESS 
  1005.          && event->key.keyval == GDK_Return) ||
  1006.         event->type == GDK_2BUTTON_PRESS)
  1007.     {
  1008.         on_module_clist_load_button_clicked(NULL, user_data);
  1009.  
  1010.         gtk_widget_hide(module_dialog);
  1011.  
  1012.         GTK_RESTORE_FOCUS;
  1013.     }
  1014.     return FALSE;
  1015. }
  1016.  
  1017. /* Create clist from module database */
  1018. void
  1019. on_module_clist_realize                (GtkWidget       *widget,
  1020.                                         gpointer         user_data)
  1021. {
  1022.     ModuleEntry *ent;
  1023.     GtkCList *clist = GTK_CLIST(widget);
  1024.     int old_selection;
  1025.  
  1026.     old_selection = (clist->selection ? (gint)clist->selection->data : 0);
  1027.  
  1028.     // Clear clist
  1029.     gtk_clist_clear(clist);
  1030.  
  1031.     // Freeze display
  1032.     gtk_clist_freeze(clist);
  1033.  
  1034.     // Add an entry for each item
  1035.     ent = moddb;
  1036.     while (ent)
  1037.     {
  1038.         gchar *items[3];
  1039.         gint row;
  1040.  
  1041.         items[0] = ent->name;
  1042.         items[1] = ent->tag;
  1043.         items[2] = ent->commands;
  1044.  
  1045.         // add row
  1046.         row = gtk_clist_append(clist, items);
  1047.  
  1048.         // associate row with ModuleEntry
  1049.         gtk_clist_set_row_data(clist, row, ent);
  1050.  
  1051.         ent = ent->next;
  1052.     }
  1053.  
  1054.     // Unfreeze 
  1055.     gtk_clist_thaw(clist);
  1056.  
  1057.     // Reselect old selection
  1058.     gtk_clist_select_row(clist, old_selection, 0 /*col*/);
  1059.     gtk_clist_moveto(clist, old_selection, 0 /*col*/, 0.5, 0.5);
  1060.  
  1061.     gtk_clist_set_column_max_width(clist, mc_tag_name, 50);
  1062. }
  1063.  
  1064. void
  1065. on_module_clist_click_column           (GtkCList        *clist,
  1066.                                         gint             column,
  1067.                                         gpointer         user_data)
  1068. {
  1069.     gboolean swap = (clist->sort_column == column);
  1070.     GtkSortType sort = swap 
  1071.         ? (clist->sort_type == GTK_SORT_ASCENDING ? 
  1072.            GTK_SORT_DESCENDING : 
  1073.            GTK_SORT_ASCENDING)
  1074.         : GTK_SORT_ASCENDING;
  1075.  
  1076.     gtk_clist_set_sort_column(clist, column);
  1077.     gtk_clist_set_sort_type(clist, sort);
  1078.     gtk_clist_sort(clist);
  1079.     module_clist_prefix_clear(GTK_WIDGET(clist));
  1080. }
  1081.  
  1082. /*
  1083.  *    Toggled "show setup commands" button
  1084.  */
  1085. void
  1086. on_show_commands_cb_toggled            (GtkToggleButton *togglebutton,
  1087.                                         gpointer         user_data)
  1088. {
  1089.     GtkCList *clist;
  1090.     g_return_if_fail(GTK_IS_CLIST(clist = user_data));
  1091.  
  1092.     gtk_clist_set_column_visibility(clist, mc_setup_commands, 
  1093.                                     gtk_toggle_button_get_active(togglebutton));
  1094.     gtk_clist_set_column_max_width(clist, mc_tag_name, 50);
  1095. }
  1096.  
  1097. /*
  1098.  *    Toggled "reset computer after load" button
  1099.  */
  1100. void
  1101. on_reset_computer_cb_toggled           (GtkToggleButton *togglebutton,
  1102.                                         gpointer         user_data)
  1103. {
  1104.     module_reset_toggle = togglebutton;
  1105. }
  1106.  
  1107.  
  1108. void
  1109. on_modules_refresh_button_clicked      (GtkButton       *button,
  1110.                                         gpointer         user_data)
  1111. {
  1112.     g_return_if_fail(GTK_IS_CLIST(user_data));
  1113.     GTK_send_command("InitModuleDatabase\n"
  1114.                      "LoadConfigFile \"modules.inf\"\n");
  1115.     module_clist_prefix_clear(GTK_WIDGET(user_data));
  1116.     on_module_clist_realize(GTK_WIDGET(user_data), 0L);
  1117. }
  1118.  
  1119. void
  1120. on_unload_current_button_clicked       (GtkButton       *button,
  1121.                                         gpointer         user_data)
  1122. {
  1123.     GTK_send_command("UnloadModuleOnly\n");
  1124. }
  1125.  
  1126.  
  1127.  
  1128. /******************************************************************/
  1129. #if 0
  1130. #pragma mark -
  1131. #endif
  1132.  
  1133. /*
  1134.  *    Disk selection dialog
  1135.  */
  1136.  
  1137. static GtkWidget *disk_dialog;
  1138. static GtkTable *disk_dialog_table;
  1139.  
  1140. enum
  1141. {
  1142.     ddt_disk_name,
  1143.     ddt_combo_history,
  1144.     ddt_choose_button
  1145. };
  1146.  
  1147. void
  1148. on_v9t9_window_disks_button_clicked    (GtkButton       *button,
  1149.                                         gpointer         user_data)
  1150. {
  1151.     if (!VALID_WINDOW(disk_dialog)) {
  1152.         disk_dialog = create_disks_dialog();
  1153.     } else {
  1154.         gtk_widget_hide(disk_dialog);
  1155.     }
  1156.     gtk_widget_show(disk_dialog);
  1157. }
  1158.  
  1159. /*
  1160.  *    Clicked 'apply' button on dialog
  1161.  */
  1162. void
  1163. on_disk_dialog_apply_button_clicked   (GtkButton       *button,
  1164.                                         gpointer         user_data)
  1165. {
  1166.     GTK_RESTORE_FOCUS;
  1167. }
  1168.  
  1169. /*
  1170.  *    Clicked 'close' button on dialog
  1171.  */
  1172. void
  1173. on_disk_dialog_close_button_clicked    (GtkButton       *button,
  1174.                                         gpointer         user_data)
  1175. {
  1176.     gtk_widget_hide(disk_dialog);
  1177. //    disk_dialog = 0L;
  1178. //    disk_dialog_table = 0L;
  1179.  
  1180.     GTK_RESTORE_FOCUS;
  1181. }
  1182.  
  1183. /*
  1184.  *    Setup disk table.  Format is:
  1185.  *    column 0:      label DSKx
  1186.  *    column 1:      combo box, history of names used [not implemented]
  1187.  *    column 2:    'choose' button, which triggers on_disk_choose_button_clicked(row)
  1188.  */
  1189.  
  1190. /*
  1191.  *    Icky!  No accessor functions.
  1192.  */
  1193. static GtkWidget *table_get_widget(GtkTable *table, gint row, gint column)
  1194. {
  1195.     GList *list;
  1196.  
  1197.     for (list = table->children; list; list = list->next) {
  1198.         GtkTableChild *child;
  1199.  
  1200.         child = (GtkTableChild *)list->data;
  1201.         if (child->top_attach == row && child->left_attach == column)
  1202.             return child->widget;
  1203.     }
  1204.     return 0L;
  1205. }
  1206.  
  1207. void
  1208. on_disk_info_table_realize             (GtkWidget       *widget,
  1209.                                         gpointer         user_data)
  1210. {
  1211.     gint row;
  1212.     GtkTable *table;
  1213.     GtkWidget *kid;
  1214.  
  1215.     g_return_if_fail(GTK_IS_TABLE(table = GTK_TABLE(widget)));
  1216.  
  1217.     disk_dialog_table = table;
  1218.  
  1219.     for (row = 0; row < dsr_get_disk_count(); row++) {
  1220.         GtkWidget *label, *combo, *choose;
  1221.         const char *path;
  1222.  
  1223.         label = table_get_widget(table, row, ddt_disk_name);
  1224.         combo = table_get_widget(table, row, ddt_combo_history);
  1225.         choose = table_get_widget(table, row, ddt_choose_button);
  1226.  
  1227.         // enable widgets for disks we can use
  1228.         gtk_widget_set_sensitive(label, TRUE);
  1229.         gtk_widget_set_sensitive(combo, TRUE);
  1230.         gtk_widget_set_sensitive(choose, TRUE);
  1231.  
  1232.         path = dsr_get_disk_info(row + 1);
  1233. //        gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), path ? path : "");
  1234.         gtk_entry_set_text(GTK_ENTRY(combo), path ? path : "");
  1235.     }
  1236.  
  1237.     // Disable inaccessible kids
  1238.     for (; row < 5; row++) {
  1239.         int col;
  1240.         for (col = 0; col < 3; col++) {
  1241.             kid = table_get_widget(table, row, col);
  1242.             gtk_widget_set_sensitive(kid, FALSE);
  1243.         }
  1244.     }
  1245. }
  1246.  
  1247. /*
  1248.  *    Canonicalize a path to either a directory or a filename
  1249.  */
  1250. static gchar *disk_file_canonicalize(gchar **searchpath, gchar *syssearchpath, 
  1251.                                      gboolean dir, const char *path, 
  1252.                                      OSSpec *spec, gboolean add_dir)
  1253. {
  1254.     char *fptr;
  1255.     gchar *copy;
  1256.  
  1257.     fptr = (char *)OS_GetFileNamePtr(path);
  1258.     if (dir) {
  1259.         // don't accept a file as a directory
  1260.         if (OS_MakeFileSpec(path, spec) == OS_NOERR &&
  1261.             OS_Status(spec) == OS_NOERR) {
  1262.             *fptr = 0;
  1263.         }
  1264.         if (OS_MakeSpec(path, spec, NULL) == OS_NOERR) {
  1265.             copy = g_strdup(OS_PathSpecToString1(&spec->path));
  1266.         } else {
  1267.             copy = g_strdup(path);
  1268.         }
  1269.     } else {
  1270.         // find file in the path, or add it.
  1271.         if (!findbinary(*searchpath, syssearchpath, fptr, spec)) {
  1272.             if (add_dir && *fptr) {
  1273.                 char *list = (char *)xmalloc((*searchpath ? strlen(*searchpath) : 0) 
  1274.                                              + (fptr - path) + 1 + 1);
  1275.                 sprintf(list, "%s%c%.*s", *searchpath ? *searchpath : "", OS_ENVSEP, fptr - path, path);
  1276.                 xfree(*searchpath);
  1277.                 *searchpath = list;
  1278.             }
  1279.             copy = g_strdup(fptr);
  1280.         } else {
  1281.             copy = g_strdup(OS_NameSpecToString1(&spec->name));
  1282.         }
  1283.     }
  1284.  
  1285.     return copy;
  1286. }
  1287.  
  1288.  
  1289. #if 0
  1290. // um, this combo crap really doesn't make sense...
  1291.  
  1292. /*
  1293.  *    Text in combo box changed for disk in user_data (1..x)
  1294.  */
  1295. void
  1296. on_disk_combo_entry_activate           (GtkEditable     *editable,
  1297.                                         gpointer         user_data)
  1298. {
  1299.     char msg[256];
  1300.     GtkCombo *combo;
  1301.     gint disk;
  1302.     gchar *path;
  1303.     gchar *canon;
  1304.  
  1305.     g_return_if_fail(GTK_IS_COMBO(combo = GTK_COMBO(GTK_WIDGET(editable)->parent)));
  1306.  
  1307.     disk = (gint)user_data;
  1308.     path = gtk_editable_get_chars(editable, 0, -1);
  1309.  
  1310.     snprintf(msg, sizeof(msg), "Changing DSK%d to '%s'\n", disk, path);
  1311.     GTK_append_log(msg, NULL, NULL);
  1312.  
  1313.     // if not an error, add to history
  1314.     if (dsr_set_disk_info(disk, path) && (canon = dsr_get_disk_info(disk))) {
  1315.         GtkList *strings = GTK_LIST(combo->list);
  1316.         GList *items;
  1317.         GtkWidget *item;
  1318.  
  1319.         gint pos;
  1320.  
  1321.         gtk_editable_delete_text(editable, 0, -1);
  1322.         pos = 0;
  1323.         gtk_editable_insert_text(editable, canon, strlen(canon), &pos);
  1324.  
  1325.         items = g_list_alloc();
  1326.         g_list_append(items, (gpointer)editable);
  1327.         gtk_list_prepend_items(strings, items);
  1328.  
  1329. // ???
  1330. //        gtk_combo_set_popdown_strings(combo, strings);
  1331. //        combo->list = strings;
  1332.     }
  1333.  
  1334.     g_free(path);
  1335. }
  1336. #endif
  1337.  
  1338. /*
  1339.  *    Text in combo box changed for disk in user_data (1..x)
  1340.  */
  1341. void
  1342. on_disk_combo_entry_activate           (GtkEditable     *editable,
  1343.                                         gpointer         user_data)
  1344. {
  1345.     char msg[256];
  1346.     gint disk;
  1347.     char *path;
  1348.     gchar *copy;
  1349.     OSSpec spec;
  1350.  
  1351.     disk = (gint)user_data;
  1352.     path = gtk_editable_get_chars(editable, 0, -1);
  1353.  
  1354.     copy = disk_file_canonicalize(&diskimagepath, 0L,
  1355.                                   dsr_is_emu_disk(disk), path, &spec, true /*add_dir*/);
  1356.  
  1357.     snprintf(msg, sizeof(msg), "Changing DSK%d to '%s'\n", disk, copy);
  1358.     GTK_append_log(msg, NULL, NULL);
  1359.  
  1360.     dsr_set_disk_info(disk, copy);
  1361.  
  1362.     g_free(path);
  1363.     g_free(copy);
  1364. }
  1365.  
  1366.  
  1367. static GtkWidget*
  1368. create_disk_file_selection (gchar *title)
  1369. {
  1370.   GtkWidget *disk_file_selection;
  1371.   GtkWidget *ok_button2;
  1372.   GtkWidget *cancel_button2;
  1373.  
  1374.   disk_file_selection = v99_file_selection_new (title);
  1375. //  gtk_object_set_data (GTK_OBJECT (disk_file_selection), "disk_file_selection", disk_file_selection);
  1376.   gtk_container_set_border_width (GTK_CONTAINER (disk_file_selection), 10);
  1377.  
  1378.   ok_button2 = V99_FILE_SELECTION (disk_file_selection)->ok_button;
  1379.   gtk_object_set_data (GTK_OBJECT (disk_file_selection), "ok_button2", ok_button2);
  1380.   gtk_widget_show (ok_button2);
  1381.   GTK_WIDGET_SET_FLAGS (ok_button2, GTK_CAN_DEFAULT);
  1382.  
  1383.   cancel_button2 = V99_FILE_SELECTION (disk_file_selection)->cancel_button;
  1384.   gtk_object_set_data (GTK_OBJECT (disk_file_selection), "cancel_button2", cancel_button2);
  1385.   gtk_widget_show (cancel_button2);
  1386.   GTK_WIDGET_SET_FLAGS (cancel_button2, GTK_CAN_DEFAULT);
  1387.  
  1388.   return disk_file_selection;
  1389. }
  1390.  
  1391. #if 0
  1392. #pragma mark -
  1393. #endif
  1394.  
  1395. /*
  1396.  *    Choose a disk or directory for the disk in user_data (1..x)
  1397.  */
  1398.  
  1399. V99FileSelection *disk_file_dialog;        // V99FileDialog
  1400.  
  1401. static void 
  1402. GTK_info_logger(u32 srcflags, const char *format, ...)
  1403. {
  1404.     va_list va;
  1405.     if (srcflags & (LOG_ERROR|LOG_WARN))
  1406.         return;
  1407.     if (srcflags & LOG_VERBOSE_MASK)
  1408.         return;
  1409.     
  1410.     va_start(va, format);
  1411.     vlogger(srcflags, format, va);
  1412.     va_end(va);
  1413. }
  1414.  
  1415.  
  1416. /*
  1417.  *    Given a filename, append a row to the clist with info
  1418.  *    about the V9t9 file (if it is one)
  1419.  */
  1420. static const char *
  1421. emu_disk_clist_titles[] =
  1422. { "Name", "Size", "Type", "P", "Host filename" };
  1423.  
  1424. #if __MWERKS__
  1425. // Support for the runtime initialization of local arrays
  1426. #pragma gcc_extensions on
  1427. #endif
  1428.  
  1429. static int
  1430. on_v99_file_selection_file_append(V99FileSelection *filesel, 
  1431.                                   GtkCList *clist, 
  1432.                                   const gchar *path, 
  1433.                                   const gchar *filename)
  1434. {
  1435.     char tiname[11];
  1436.     char size[8];
  1437.     char type[12];
  1438.     char protect[2];
  1439.     gchar *cols[6] = { tiname, size, type, protect, (gchar *)filename, NULL };
  1440.     int charwidth = gdk_string_width(filesel->file_list->style->font, "M");
  1441.     int widths[5]= { charwidth*10, charwidth*3, charwidth*10, charwidth*1, charwidth*16 };
  1442.     int col;
  1443.     fiad_tifile tf;
  1444.     OSSpec spec;
  1445.     fiad_logger_func old;
  1446.  
  1447.     /* Try to make a tifile from the entry */
  1448.     if (OS_MakeSpec2(path, filename, &spec) != OS_NOERR) {
  1449.         /* oops, not even a good file (maybe broken softlink) */
  1450.         return 0;
  1451.     }
  1452.  
  1453.     /* Don't log errors found in likely-non-V9t9 files,
  1454.         but log renames */
  1455.     old = fiad_set_logger(GTK_info_logger);
  1456.  
  1457.     if (fiad_tifile_setup_spec_with_spec(&tf, &spec) == OS_NOERR &&
  1458.         fiad_tifile_get_info(&tf))
  1459.     {
  1460.         /* it might have just been renamed */
  1461.         cols[4] = OS_NameSpecToString1(&tf.spec.name);
  1462.  
  1463.         memcpy(tiname, tf.fdr.filenam, 10);
  1464.         tiname[10] = 0;
  1465.         sprintf(size, "%d", tf.fdr.secsused + 1);
  1466.         strcpy(type, fiad_catalog_get_file_type_string(&tf.fdr));
  1467.         protect[0] = (tf.fdr.flags & ff_protected) ? 'Y' : ' ';
  1468.         protect[1] = 0;
  1469.  
  1470.     } 
  1471.     else     /* not a V9t9 file */
  1472.     {
  1473.         *tiname = 0;
  1474.         *size = 0;
  1475.         *protect = 0;
  1476.         *type = 0;
  1477.     }
  1478.  
  1479.     /* figure widths for each column */
  1480.     for (col = 0; col < 5; col++) {
  1481.         int width = gdk_string_width(filesel->file_list->style->font, cols[col]);
  1482.         if (width > widths[col]) {
  1483.             widths[col] = width;
  1484.         }
  1485.         gtk_clist_set_column_width(clist, col, widths[col]);
  1486.     }
  1487.  
  1488.     return gtk_clist_append(clist, cols);
  1489. }
  1490.  
  1491. #if __MWERKS__
  1492. #pragma gcc_extensions reset
  1493. #endif
  1494.  
  1495. static void
  1496. on_v99_file_selection_file_click_column(GtkCList *clist,
  1497.                                         gint column,
  1498.                                         gpointer user_data)
  1499. {
  1500.     gboolean swap = (clist->sort_column == column);
  1501.     GtkSortType sort = swap 
  1502.         ? (clist->sort_type == GTK_SORT_ASCENDING ? 
  1503.            GTK_SORT_DESCENDING : 
  1504.            GTK_SORT_ASCENDING)
  1505.         : GTK_SORT_ASCENDING;
  1506.  
  1507.     gtk_clist_set_sort_column(clist, column);
  1508.     gtk_clist_set_sort_type(clist, sort);
  1509.     gtk_clist_sort(clist);
  1510. }
  1511.  
  1512. /*
  1513.  *    user_data is the disk number
  1514.  */
  1515. void
  1516. on_disk_file_ok_button_clicked         (GtkButton       *button,
  1517.                                         gpointer         user_data)
  1518. {
  1519.     gint disk = (gint)user_data;
  1520.     gboolean dir = dsr_is_emu_disk(disk);
  1521.     const char *path;
  1522.     gchar *copy;
  1523.     OSSpec spec;
  1524.  
  1525.     g_return_if_fail(disk >= 1 && disk <= 5);
  1526.  
  1527.     path = v99_file_selection_get_filename(disk_file_dialog);
  1528.     copy = disk_file_canonicalize(&diskimagepath, 0L,
  1529.                                   dir, path, &spec, true /*add_dir*/);
  1530.  
  1531.     if (dsr_set_disk_info(disk, copy)) {
  1532.         GtkWidget *entry = table_get_widget(disk_dialog_table, disk-1, ddt_combo_history);
  1533.  
  1534.         gtk_entry_set_text(GTK_ENTRY(entry), copy);
  1535.         gtk_widget_hide((GtkWidget *)disk_file_dialog);
  1536. //        disk_file_dialog = 0L;
  1537.  
  1538.         GTK_RESTORE_FOCUS;
  1539.     }
  1540.  
  1541.     g_free(copy);
  1542.     //g_free(path);
  1543. }
  1544.  
  1545.  
  1546. void
  1547. on_disk_file_cancel_button_clicked     (GtkButton       *button,
  1548.                                         gpointer         user_data)
  1549. {
  1550.     gtk_widget_hide((GtkWidget *)disk_file_dialog);
  1551.     GTK_RESTORE_FOCUS;
  1552. }
  1553.  
  1554. /*
  1555.  *    Main disk/file chooser dialog.
  1556.  *    
  1557.  */
  1558. void
  1559. on_disk_choose_button_clicked          (GtkButton       *button,
  1560.                                         gpointer         user_data)
  1561. {
  1562.     gint disk = (gint)user_data;
  1563.  
  1564.     g_return_if_fail(disk >= 1 && disk <= 5);
  1565.  
  1566.     if (!VALID_WINDOW(disk_file_dialog)) {
  1567.         disk_file_dialog = V99_FILE_SELECTION(create_disk_file_selection("Select Path"));
  1568.         if (dsr_is_real_disk(disk)) {
  1569.             // normal file selection
  1570.             v99_file_selection_set_file_list_active(disk_file_dialog, 
  1571.                                                     TRUE);
  1572.         } else {
  1573.             // v9t9 directory selection
  1574.             v99_file_selection_set_file_list_columns(disk_file_dialog, 
  1575.                                                      5,
  1576.                                                      (gchar **)emu_disk_clist_titles,
  1577.                                                      on_v99_file_selection_file_append,
  1578.                                                      NULL);
  1579.             gtk_signal_connect(GTK_OBJECT(disk_file_dialog->file_list),
  1580.                                "click_column",
  1581.                                on_v99_file_selection_file_click_column,
  1582.                                NULL);
  1583.  
  1584.             // no, we can't select files as directories
  1585.             v99_file_selection_set_file_list_active(disk_file_dialog, 
  1586.                                                     FALSE);
  1587.             disk_file_dialog->user_data = (gpointer)(disk - 1);
  1588.         }
  1589.     }
  1590.  
  1591.     gtk_widget_show(GTK_WIDGET(disk_file_dialog));
  1592.  
  1593.     if (dsr_is_real_disk(disk)) {
  1594. //        OSError err;
  1595.         OSSpec spec;
  1596.         const char *filename;
  1597.         gchar *copy;
  1598.  
  1599.         // Set the full path if we can
  1600.         filename = dsr_get_disk_info(disk);
  1601.         copy = disk_file_canonicalize(&diskimagepath, 0L,
  1602.                                       false /*directory*/, filename, &spec,
  1603.                                       false /*add_dir*/);
  1604.  
  1605.         v99_file_selection_set_filename(disk_file_dialog, 
  1606.                                         OS_SpecToString1(&spec));
  1607.         v99_file_selection_complete(disk_file_dialog,
  1608.                                     "*.dsk");
  1609.  
  1610.         g_free(copy);
  1611.     } else {
  1612.         // it's already a full path
  1613.         char path[OS_PATHSIZE];
  1614.         strcpy(path, dsr_get_disk_info(disk));
  1615. #if !defined(UNDER_MACOS)
  1616.         // force a directory selection so ppl don't think they can
  1617.         // type a filename
  1618.         strcat(path, ".");    
  1619. #endif
  1620.         v99_file_selection_set_filename(disk_file_dialog, 
  1621.                                         path);
  1622.  
  1623.     }
  1624.  
  1625.     // wire up buttons here (so we can pass known disk number)
  1626.     gtk_signal_connect(GTK_OBJECT(disk_file_dialog->ok_button), 
  1627.                        "clicked", 
  1628.                        GTK_SIGNAL_FUNC(on_disk_file_ok_button_clicked),
  1629.                        (gpointer)disk);
  1630.     gtk_signal_connect(GTK_OBJECT(disk_file_dialog->cancel_button), 
  1631.                        "clicked", 
  1632.                        GTK_SIGNAL_FUNC(on_disk_file_cancel_button_clicked),
  1633.                        (gpointer)disk);
  1634. }
  1635.  
  1636. /*
  1637.  *    Toggle use of realdisk DSR
  1638.  */
  1639.  
  1640. void
  1641. on_real_disk_cb_toggled                (GtkToggleButton *togglebutton,
  1642.                                         gpointer         user_data)
  1643. {
  1644.     char cmd[64];
  1645.     sprintf(cmd, "ToggleV9t9 dsrRealDisk %s", 
  1646.             gtk_toggle_button_get_active(togglebutton) ? "on" : "off");
  1647.     GTK_send_command(cmd);
  1648.     gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize");
  1649. }
  1650.  
  1651.  
  1652. void
  1653. on_real_disk_cb_realize                (GtkWidget       *widget,
  1654.                                         gpointer         user_data)
  1655. {
  1656.     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
  1657.                            !!(realDiskDSR.runtimeflags & vmRTInUse));
  1658.     gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize");
  1659. }
  1660.  
  1661. /*
  1662.  *    Toggle use of emulated disk DSR
  1663.  */
  1664.  
  1665. void
  1666. on_emu_disk_cb_toggled                 (GtkToggleButton *togglebutton,
  1667.                                         gpointer         user_data)
  1668. {
  1669.     char cmd[64];
  1670.     sprintf(cmd, "ToggleV9t9 dsrEmuDisk %s",
  1671.             gtk_toggle_button_get_active(togglebutton) ? "on" : "off");
  1672.     GTK_send_command(cmd);
  1673.     gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize");
  1674. }
  1675.  
  1676.  
  1677. void
  1678. on_emu_disk_cb_realize                 (GtkWidget       *widget,
  1679.                                         gpointer         user_data)
  1680. {
  1681.     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
  1682.                            !!(emuDiskDSR.runtimeflags & vmRTInUse));
  1683.     gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize");
  1684. }
  1685.  
  1686. #if 0
  1687. #pragma mark -
  1688. #endif
  1689.  
  1690. static GtkWidget *debugger_window;
  1691. GtkWidget *debugger_registers_table,
  1692.     *debugger_instruction_box,
  1693.     *debugger_status_bar,
  1694.     *debugger_pc_entry,
  1695.     *debugger_wp_entry,
  1696.     *debugger_st_entry;
  1697.  
  1698. // flag indicating we want to display all the time-wasting
  1699. // updates (turned on/off during intermittent mode, etc)
  1700. static bool debugger_verbose_updates;
  1701.  
  1702. #define DBG_COLOR_NORMAL(s)        (&(s)->fg[0])
  1703. #define DBG_COLOR_VIEW(s)        (&(s)->fg[0])
  1704. #define DBG_COLOR_READ(s)        (&(s)->mid[0])
  1705. #define DBG_COLOR_WRITTEN(s)    (&(s)->dark[0])
  1706.  
  1707. static GdkColor *
  1708. debugger_status_color_fg(status_item item, GtkStyle *style)
  1709. {
  1710.     switch (item)
  1711.     {
  1712.     case STATUS_CPU_PC:                return DBG_COLOR_NORMAL(style);
  1713.     case STATUS_CPU_STATUS:            return DBG_COLOR_NORMAL(style);
  1714.     case STATUS_CPU_WP:                return DBG_COLOR_NORMAL(style);
  1715.     case STATUS_CPU_REGISTER_VIEW:    return DBG_COLOR_VIEW(style);
  1716.     case STATUS_CPU_REGISTER_READ:    return DBG_COLOR_READ(style);
  1717.     case STATUS_CPU_REGISTER_WRITE:    return DBG_COLOR_WRITTEN(style);
  1718.     case STATUS_CPU_INSTRUCTION:    return DBG_COLOR_NORMAL(style);
  1719.     case STATUS_CPU_INSTRUCTION_LAST: return DBG_COLOR_WRITTEN(style);
  1720.     case STATUS_MEMORY_VIEW:        return DBG_COLOR_VIEW(style);
  1721.     case STATUS_MEMORY_READ:        return DBG_COLOR_READ(style);
  1722.     case STATUS_MEMORY_WRITE:        return DBG_COLOR_WRITTEN(style);
  1723.     }
  1724.     return DBG_COLOR_NORMAL(style);
  1725. }
  1726.  
  1727. static GdkColor*
  1728. debugger_status_color_bg(status_item item, GtkStyle *style)
  1729. {
  1730. //    return &style->bg[0];
  1731.     return 0L;
  1732. }
  1733.  
  1734. /*
  1735.  *    Set up registers table for the first time
  1736.  */
  1737. static void
  1738. setup_debugger_registers_table(void)
  1739. {
  1740.     int reg;
  1741.     GtkWidget *w;
  1742.     GtkTable *t;
  1743.     GtkStyle *s;
  1744.     int width, height;
  1745.  
  1746.     g_return_if_fail(debugger_registers_table);
  1747.  
  1748.     t = GTK_TABLE(debugger_registers_table);
  1749.  
  1750.     s = gtk_widget_get_style(debugger_registers_table);
  1751.  
  1752.     // setup base size of text box
  1753.     width = gdk_string_width(s->font, "_>FFFF_");
  1754.     height = gdk_string_height(s->font, "!")*2;
  1755.  
  1756. //    gtk_style_unref(s);
  1757.  
  1758.     // fix the items below the register table here...
  1759.     gtk_widget_set_usize(debugger_pc_entry, width, height);
  1760.     gtk_widget_set_usize(debugger_wp_entry, width, height);
  1761.     gtk_widget_set_usize(debugger_st_entry, width, height);
  1762.  
  1763.     // resize
  1764.     gtk_table_resize(t, 16 /*rows*/, 2 /*columns*/);
  1765.  
  1766.     // set up each register row
  1767.     for (reg = 0; reg < 16; reg++) {
  1768.         // assign label...
  1769.         char tmp[32];
  1770.         sprintf(tmp, "R%d", reg);
  1771.         w = gtk_label_new(tmp);
  1772.         gtk_widget_ref(w);
  1773.         gtk_object_set_data_full(GTK_OBJECT(debugger_window), 
  1774.                                  widget_tag("register_label_", reg, 1),
  1775.                                  w, (GtkDestroyNotify) gtk_widget_unref);
  1776.         gtk_widget_show(w);
  1777.         gtk_table_attach(t, w, 0, 1, reg, reg+1,
  1778.                          (GtkAttachOptions) (0),
  1779.                          (GtkAttachOptions) (0), 2, 0);
  1780.  
  1781.         // assign text entry to register
  1782.  
  1783.         w = gtk_text_new (NULL, NULL);
  1784.         gtk_widget_ref(w);
  1785.         gtk_text_set_editable (GTK_TEXT(w), false);
  1786.  
  1787.         // force size
  1788.         gtk_widget_set_usize(w, width, height);
  1789.  
  1790.         gtk_object_set_data_full(GTK_OBJECT(debugger_window),
  1791.                                  widget_tag("reg_value_", reg, 1),
  1792.                                  w, (GtkDestroyNotify) gtk_widget_unref);
  1793.         gtk_table_attach(t, w, 1, 2, reg, reg+1,
  1794.                          (GtkAttachOptions) (0),
  1795.                          (GtkAttachOptions) (0), 2, 0);
  1796.  
  1797.         gtk_widget_show(w);
  1798.     }
  1799. }
  1800.  
  1801. static void
  1802. update_debugger_register(status_item item, int reg, int val)
  1803. {
  1804.     GtkTable *t = GTK_TABLE(debugger_registers_table);
  1805.     GtkText *tb;
  1806.     GtkWidget *w;
  1807.     GtkStyle *style;
  1808.     char buffer[8];
  1809.  
  1810.     // get value widget
  1811.     w = table_get_widget(t, reg, 1);
  1812.  
  1813.     if (!VALID_WINDOW(w))
  1814.         return;
  1815.  
  1816.     // get style
  1817.     style = gtk_widget_get_style(w);
  1818.  
  1819.     // freeze entry
  1820.     tb = GTK_TEXT(w);
  1821.     gtk_text_freeze(tb);
  1822.     
  1823.     // remove old text
  1824.     gtk_editable_delete_text(GTK_EDITABLE(tb), 0, -1);
  1825.  
  1826.     // insert new text
  1827.     sprintf(buffer, ">%04X", val);
  1828.     gtk_text_insert(tb, 
  1829.                     style->font,
  1830.                     debugger_status_color_fg(item, style),
  1831.                     debugger_status_color_bg(item, style),
  1832.                     buffer,
  1833.                     5);
  1834.                     
  1835.     // update
  1836.     gtk_text_thaw(tb);
  1837. }
  1838.  
  1839. /*
  1840.  *    Setup memory windows for the first time.
  1841.  *
  1842.  *    Each entry in the vbox contains a frame with a scrolled window inside.
  1843.  */
  1844.  
  1845. #define MEMORY_BYTES_PER_ROW    16
  1846.  
  1847. static char *memory_frame_names[MEMORY_VIEW_COUNT] =
  1848. {
  1849.     "cpu_1_memory_frame",
  1850.     "cpu_2_memory_frame",
  1851.     "video_memory_frame",
  1852.     "graphics_memory_frame",
  1853.     "speech_memory_frame"
  1854. };
  1855.  
  1856. static char *memory_view_names[MEMORY_VIEW_COUNT] =
  1857. {
  1858.     "cpu_view_1",
  1859.     "cpu_view_2",
  1860.     "video_view",
  1861.     "graphics_view",
  1862.     "speech_view"
  1863. };
  1864.  
  1865. static void
  1866. on_debugger_memory_window_size_request_event (GtkWidget       *widget,
  1867.                                         GtkRequisition  *requisition,
  1868.                                         gpointer         user_data)
  1869. {
  1870.     GtkWidget *tb;
  1871.     GtkStyle *s;
  1872.     int width, height;
  1873.  
  1874.     tb = widget;
  1875.  
  1876.     s = gtk_widget_get_style(tb);
  1877.  
  1878.     height = gdk_string_height(s->font, "!\n") * 3 / 2;
  1879.     width = gdk_string_width(s->font, "F");
  1880.  
  1881.     if (requisition->width < width) {
  1882.         requisition->width = width;
  1883.         gtk_widget_set_usize(widget, width, -2);
  1884.     }
  1885.     if (requisition->height < height) {
  1886.         requisition->height = height;
  1887.         gtk_widget_set_usize(widget, -2, height);
  1888.     }
  1889.  
  1890. //    requisition->width = 80;
  1891. //    requisition->height = 80;
  1892.  
  1893. //    g_print("requesting %d x %d\n", requisition->width, requisition->height);
  1894.  
  1895. }
  1896.  
  1897. static gboolean
  1898. on_debugger_memory_window_size_allocate_event  (GtkWidget       *widget,
  1899.                                         GtkAllocation     *allocation,
  1900.                                         gpointer         user_data)
  1901. {
  1902.     GtkWidget *tb;
  1903.     GtkStyle *s;
  1904.     int width, height, which;
  1905.  
  1906.     tb = widget;
  1907.  
  1908. //    g_print("allocated %d x %d\n", allocation->width, allocation->height);
  1909.  
  1910.     s = gtk_widget_get_style(tb);
  1911.     height = allocation->height / (gdk_string_height(s->font, "!\n") * 3 / 2);
  1912.     width = debugger_hex_dump_chars_to_bytes(allocation->width / (gdk_string_width(s->font, "F")) - 1);
  1913.     width &= ~1;    // display whole words
  1914.  
  1915.     // in case the window was sized really small...
  1916.     if (height <= 0) height = 1;
  1917.     if (width <= 0) width = 1;
  1918.  
  1919. //    gtk_style_unref(s);
  1920.  
  1921.     gtk_object_set_data(GTK_OBJECT(widget), "view_width", (gpointer)width);
  1922.     gtk_object_set_data(GTK_OBJECT(widget), "view_height", (gpointer)height);
  1923.  
  1924.     which = (int)gtk_object_get_data(GTK_OBJECT(widget), "which");
  1925.     debugger_memory_view_size[which] = width * height;
  1926.  
  1927.     return FALSE;
  1928. }
  1929.  
  1930. static void
  1931. setup_debugger_memory_views(void)
  1932. {
  1933. //    GtkWidget *win;
  1934.     GtkWidget *w; 
  1935.     GtkText *tb;
  1936.     GtkStyle *s;
  1937.     int width, height;
  1938.     int idx;
  1939.  
  1940.     int default_tab_width;
  1941.  
  1942.     // get a feel for width of window
  1943.     // by trying a test line
  1944.     default_tab_width = 1;
  1945.  
  1946.     // setup base size of text box
  1947.     s = gtk_widget_get_style(debugger_window);
  1948.     width = gdk_string_width(s->font, "^") * 80;
  1949.     height = gdk_string_height(s->font, "!") * 2;
  1950. //    gtk_style_unref(s);
  1951.  
  1952.     idx = MEMORY_VIEW_CPU_1;
  1953.     while (idx < MEMORY_VIEW_COUNT) {
  1954.         w = gtk_object_get_data(GTK_OBJECT(debugger_window), 
  1955.                                   memory_frame_names[idx]);
  1956.  
  1957.         g_return_if_fail(w);
  1958.         g_return_if_fail(GTK_IS_BIN(w));
  1959.         
  1960.         w = GTK_BIN(w)->child;
  1961.         g_return_if_fail(GTK_IS_TEXT(w));
  1962.         tb = (GtkText *)w;
  1963.  
  1964.         // add a text box to the window
  1965. /*        w = gtk_text_new (NULL, NULL);
  1966.         tb = GTK_TEXT(w);
  1967.         gtk_widget_ref(w);*/
  1968.         gtk_text_set_editable (tb, false);
  1969.  
  1970.         // force size
  1971.         //gtk_widget_set_usize(w, width, height);
  1972.  
  1973.         // don't wrap lines!
  1974.         gtk_text_set_line_wrap(tb, false);
  1975.         gtk_text_set_adjustments(tb, NULL, NULL);
  1976.  
  1977.         // set tab width
  1978.         tb->default_tab_width = default_tab_width;
  1979.  
  1980.         gtk_object_set_data_full(GTK_OBJECT(debugger_window), 
  1981.                                  memory_view_names[idx],
  1982.                                  w,    
  1983.                                  (GtkDestroyNotify) gtk_widget_unref);
  1984.  
  1985.         gtk_object_set_data(GTK_OBJECT(tb), 
  1986.                             "which",
  1987.                             (gpointer)idx);
  1988.  
  1989.         debugger_memory_view_size[idx] = MEMORY_BYTES_PER_ROW * 4;
  1990.  
  1991.         // watch for resizes so we can fill the memory view
  1992.         gtk_signal_connect (GTK_OBJECT (tb), "size_allocate",
  1993.                       GTK_SIGNAL_FUNC (on_debugger_memory_window_size_allocate_event),
  1994.                       (gpointer)tb);
  1995.  
  1996.         gtk_signal_connect (GTK_OBJECT (tb), "size_request",
  1997.                       GTK_SIGNAL_FUNC (on_debugger_memory_window_size_request_event),
  1998.                       (gpointer)tb);
  1999.  
  2000.         //gtk_widget_show(w);
  2001.         //gtk_container_add(GTK_CONTAINER(win), w);
  2002.  
  2003.         idx++;
  2004.     }
  2005. }
  2006.  
  2007. static void
  2008. update_memory_window(status_item item, Memory *mem)
  2009. {
  2010.     GtkText *tb;
  2011.     GtkWidget *w;
  2012.     GtkStyle *style;
  2013.     char buffer[256];
  2014.     char *start, *end, *astart, *aend;
  2015.     int len;
  2016.     int offs;
  2017.  
  2018.     int width, height, which;
  2019.  
  2020.     // get our view
  2021.     w = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2022.                             memory_view_names[mem->which]);
  2023.  
  2024.     if (!VALID_WINDOW(w))
  2025.         return;
  2026.  
  2027.     width = (int)gtk_object_get_data(GTK_OBJECT(w), "view_width");
  2028.     height = (int)gtk_object_get_data(GTK_OBJECT(w), "view_height");
  2029.     which = (int)gtk_object_get_data(GTK_OBJECT(w), "which");
  2030.  
  2031.     // get style
  2032.     style = gtk_widget_get_style(w);
  2033.  
  2034.     // freeze entry
  2035.     tb = GTK_TEXT(w);
  2036.     gtk_text_freeze(tb);
  2037.     
  2038.     // remove old text
  2039.     gtk_editable_delete_text(GTK_EDITABLE(tb), 0, -1);
  2040.  
  2041.     offs = 0;
  2042.  
  2043.     while (offs < debugger_memory_view_size[which]) {
  2044.         // create new text
  2045.         debugger_hex_dump_line(mem, offs, width,
  2046.                                ' ', ' ', ' ', 
  2047.                                offs + width < debugger_memory_view_size[which]
  2048.                                ? '\n' : 0, 
  2049.                                buffer, sizeof(buffer),
  2050.                                &start, &end, &astart, &aend);
  2051.         len = strlen(buffer);
  2052.  
  2053.         if (!start) {
  2054.             start = end = buffer + len;
  2055.             astart = aend = buffer + len;
  2056.         }
  2057.  
  2058.         // insert normal text
  2059.         gtk_text_insert(tb, 
  2060.                         style->font,
  2061.                         debugger_status_color_fg(STATUS_MEMORY_VIEW, style),
  2062.                         debugger_status_color_bg(STATUS_MEMORY_VIEW, style),
  2063.                         buffer,
  2064.                         start - buffer);
  2065.     
  2066.         // insert hex byte update text
  2067.         if (start < end) {
  2068.             gtk_text_insert(tb, 
  2069.                             style->font,
  2070.                             debugger_status_color_fg(item, style),
  2071.                             debugger_status_color_bg(item, style),
  2072.                             start,
  2073.                             end - start);
  2074.         }
  2075.  
  2076.         // insert normal text
  2077.         if (end < astart) {
  2078.             gtk_text_insert(tb, 
  2079.                             style->font,
  2080.                             debugger_status_color_fg(STATUS_MEMORY_VIEW, style),
  2081.                             debugger_status_color_bg(STATUS_MEMORY_VIEW, style),
  2082.                             end,
  2083.                             astart - end);
  2084.         }
  2085.  
  2086.         // insert ascii changed text
  2087.         if (astart < aend) {
  2088.             gtk_text_insert(tb, 
  2089.                             style->font,
  2090.                             debugger_status_color_fg(item, style),
  2091.                             debugger_status_color_bg(item, style),
  2092.                             astart,
  2093.                             aend - astart);
  2094.         }
  2095.  
  2096.         // insert normal ascii text
  2097.         if (aend < buffer + len) {
  2098.             gtk_text_insert(tb, 
  2099.                             style->font,
  2100.                             debugger_status_color_fg(STATUS_MEMORY_VIEW, style),
  2101.                             debugger_status_color_bg(STATUS_MEMORY_VIEW, style),
  2102.                             aend,
  2103.                             buffer + len - aend);
  2104.         }
  2105.  
  2106.         offs += width;
  2107.     }
  2108.  
  2109.     // update
  2110.     gtk_text_thaw(tb);
  2111. }
  2112.  
  2113. #define INSTRUCTION_BOX_MAX_LENGTH (256*1024)
  2114.  
  2115. static void
  2116. setup_debugger_instruction_box(void)
  2117. {
  2118.     GtkText *tb;
  2119.     GtkStyle *s;
  2120.     int width, height;
  2121.  
  2122.     g_return_if_fail(debugger_instruction_box);
  2123.  
  2124.     tb = GTK_TEXT(debugger_instruction_box);
  2125.  
  2126.     // set tab width
  2127.     tb->default_tab_width = 4;
  2128.  
  2129.     // setup base size of text box
  2130.     s = gtk_widget_get_style(debugger_instruction_box);
  2131.     width = gdk_string_width(s->font, "^") * 40;
  2132.     height = gdk_string_height(s->font, "!") * 16;
  2133. //    gtk_style_unref(s);
  2134.  
  2135. //    width = 64;
  2136. //    height = 16;
  2137.     // force size
  2138.     gtk_widget_set_usize(debugger_instruction_box, width, height);
  2139. //    memset((void *)&req, 0, sizeof(req));
  2140. //    req.width = width;
  2141. //    req.height = height;
  2142. //    gtk_widget_size_request(debugger_instruction_box, &req);
  2143.  
  2144.     // don't wrap lines!
  2145.     gtk_text_set_line_wrap(tb, false);
  2146. }
  2147.  
  2148. static void
  2149. update_debugger_instruction(status_item item, bool show_verbose,
  2150.                             Instruction *inst,
  2151.                             char *hex, char *disasm,    // may be NULL
  2152.                             char *op1, char *op2)
  2153. {
  2154.     char buffer[256];
  2155.     GtkStyle *style;
  2156.     GtkText *tb;
  2157.     int len, point;
  2158.  
  2159.     if (!VALID_WINDOW(debugger_instruction_box))
  2160.         return;
  2161.  
  2162.     // only deal with single instructions, ignore their effects
  2163.     if (item == STATUS_CPU_INSTRUCTION)
  2164.     {
  2165.         tb = GTK_TEXT(debugger_instruction_box);
  2166.  
  2167.         // delete old text
  2168.         len = gtk_text_get_length(tb);
  2169.         if (len > INSTRUCTION_BOX_MAX_LENGTH * 2) {
  2170.             gtk_text_freeze(tb);
  2171.             point = gtk_text_get_point(tb);
  2172.             gtk_text_set_point(tb, 0);
  2173.             gtk_text_forward_delete(tb, len - INSTRUCTION_BOX_MAX_LENGTH);
  2174.             gtk_text_set_point(tb, INSTRUCTION_BOX_MAX_LENGTH);
  2175.             gtk_text_thaw(tb);
  2176.         }
  2177.  
  2178.         len = sprintf(buffer, "%s %s %s\n",
  2179.                       hex, inst->name, disasm);
  2180.  
  2181.         style = gtk_widget_get_style(debugger_instruction_box);
  2182.         gtk_text_insert(tb,
  2183.                         style->font,
  2184.                         debugger_status_color_fg(item, style),
  2185.                         debugger_status_color_bg(item, style),
  2186.                         buffer,
  2187.                         len);
  2188.         gtk_text_set_point(tb, gtk_text_get_length(tb));
  2189.     }
  2190. }
  2191.  
  2192. static void
  2193. ping_debugger_instruction_box(void)
  2194. {
  2195. /*
  2196.     GtkText *tb;
  2197.     g_return_if_fail(GTK_IS_TEXT(debugger_instruction_box));
  2198.     tb = GTK_TEXT(debugger_instruction_box);
  2199.     gtk_text_set_point(tb, gtk_text_get_length(tb));
  2200.     if (debugger_verbose_updates) {
  2201.         if (tb->freeze_count) gtk_text_thaw(tb);
  2202.     } else {
  2203.         gtk_text_insert(tb, NULL, NULL, NULL, "\n", 1);
  2204.         if (!tb->freeze_count) gtk_text_freeze(tb);
  2205.     }
  2206. */
  2207. }
  2208.  
  2209. static void
  2210. update_debugger_entry(GtkWidget *entry, status_item item, u16 val)
  2211. {
  2212.     char buffer[32];
  2213.  
  2214.     if (!VALID_WINDOW(entry))
  2215.         return;
  2216.  
  2217.     sprintf(buffer, ">%04X", val);
  2218.     gtk_entry_set_text(GTK_ENTRY(entry), buffer);
  2219. }
  2220.  
  2221. /***************/
  2222.  
  2223. static int debugger_verbose_update_count;
  2224.  
  2225. void
  2226. debugger_report_status(status_item item, va_list va)
  2227. {
  2228.     bool show_verbose = execution_paused() || debugger_verbose_updates ||
  2229.         debugger_verbose_update_count != 0;
  2230.  
  2231.     if (!VALID_WINDOW(debugger_window))
  2232.         return;
  2233.  
  2234.     switch (item)
  2235.     {
  2236.     case STATUS_DEBUG_REFRESH:
  2237.         if (debugger_verbose_update_count) {
  2238.             debugger_register_clear_view();
  2239.             debugger_memory_clear_views();
  2240.             debugger_instruction_clear_view();
  2241.             debugger_verbose_update_count--;
  2242.         }
  2243.  
  2244.         break;
  2245.     case STATUS_CPU_PC:
  2246.         if (show_verbose) {
  2247.             update_debugger_entry(debugger_pc_entry, item, va_arg(va, int));
  2248.         }
  2249.         break;
  2250.  
  2251.     case STATUS_CPU_STATUS:
  2252.         if (show_verbose) {
  2253.             update_debugger_entry(debugger_st_entry, item, va_arg(va, int));
  2254.         }
  2255.         break;
  2256.  
  2257.     case STATUS_CPU_WP:
  2258.         if (show_verbose) {
  2259.             update_debugger_entry(debugger_wp_entry, item, va_arg(va, int));
  2260.         }
  2261.         break;
  2262.  
  2263.     case STATUS_CPU_REGISTER_READ:
  2264.     case STATUS_CPU_REGISTER_WRITE:
  2265.     {
  2266.         if (show_verbose) {
  2267.             int reg, val;
  2268.             reg = va_arg(va, int);
  2269.             val = va_arg(va, int);
  2270.             update_debugger_register(item, reg, val);
  2271.         }
  2272.         break;
  2273.     }
  2274.  
  2275.     case STATUS_CPU_REGISTER_VIEW:
  2276.     {
  2277.         if (show_verbose) {
  2278.             int wp;
  2279.             u16 *regs;
  2280.             int reg;
  2281.             wp = va_arg(va, int);
  2282.             regs = va_arg(va, u16 *);
  2283.             for (reg = 0; reg < 16; reg++) {
  2284.                 update_debugger_register(item, reg, regs[reg]);
  2285.             }
  2286.         }
  2287.         break;
  2288.     }
  2289.  
  2290.     case STATUS_CPU_INSTRUCTION:
  2291.     {
  2292.         if (show_verbose) {
  2293.         Instruction *inst;
  2294.         char *hex, *disasm, *op1, *op2;
  2295.         inst = va_arg(va, Instruction *);
  2296.         hex = va_arg(va, char *);
  2297.         disasm = va_arg(va, char *);
  2298.         op1 = va_arg(va, char *);
  2299.         op2 = va_arg(va, char *);
  2300.  
  2301.         update_debugger_instruction(item, show_verbose,
  2302.                                     inst, hex, disasm, op1, op2);
  2303.         }
  2304.         break;
  2305.     }
  2306.  
  2307.     case STATUS_CPU_INSTRUCTION_LAST:
  2308.     {
  2309.         if (show_verbose) {
  2310.         Instruction *inst;
  2311.         char *op1, *op2;
  2312.         inst = va_arg(va, Instruction *);
  2313.         op1 = va_arg(va, char *);
  2314.         op2 = va_arg(va, char *);
  2315.  
  2316.         update_debugger_instruction(item, show_verbose,
  2317.                                     inst, 0L, 0L, op1, op2);
  2318.         }
  2319.         break;
  2320.     }
  2321.  
  2322.     case STATUS_MEMORY_READ:
  2323.     case STATUS_MEMORY_WRITE:
  2324.     case STATUS_MEMORY_VIEW:
  2325.         if (show_verbose) {
  2326.             Memory *mem = va_arg(va, Memory *);
  2327.             update_memory_window(item, mem);
  2328.         }
  2329.         break;
  2330.     }
  2331. }
  2332.  
  2333. /***************/
  2334.  
  2335. static void
  2336. debugger_run_event(void)
  2337. {
  2338.     debugger_verbose_update_count = 2;
  2339.     debugger_refresh();
  2340. }
  2341.  
  2342. static void
  2343. debugger_change_verbosity(bool verbose)
  2344. {
  2345.     static int debugger_run_tag;
  2346.  
  2347.     if (debugger_verbose_updates != verbose) {
  2348.         debugger_verbose_updates = verbose;
  2349.         ping_debugger_instruction_box();
  2350.         if (!verbose) {
  2351.             if (!debugger_run_tag) {
  2352.                 debugger_run_tag = TM_UniqueTag();
  2353.             }
  2354.             TM_SetEvent(debugger_run_tag, TM_HZ*100, 0, 
  2355.                         TM_FUNC|TM_REPEAT, TM_EVENT_FUNC(debugger_run_event));
  2356.         } else {
  2357.             if (debugger_run_tag) {
  2358.                 TM_ResetEvent(debugger_run_tag);
  2359.             }
  2360.         }
  2361.     }
  2362. }
  2363.  
  2364. void
  2365. on_v9t9_debug_button_clicked           (GtkButton       *button,
  2366.                                         gpointer         user_data)
  2367. {
  2368. /*
  2369.     GtkWidget *label = GTK_BIN(button)->child;
  2370.  
  2371.     debugger_enable(!debugger_enabled());
  2372.  
  2373.     if (debugger_enabled()) {
  2374.         gtk_label_set_text(GTK_LABEL(label), "Stop Tracing");
  2375.     } else {
  2376.         gtk_label_set_text(GTK_LABEL(label), "Trace");
  2377.     }
  2378. */
  2379.  
  2380.     execution_pause(true);
  2381.     debugger_enable(true);
  2382.     debugger_change_verbosity(true);
  2383. }
  2384.  
  2385. void
  2386. on_debugger_close_button_clicked       (GtkButton       *button,
  2387.                                         gpointer         user_data)
  2388. {
  2389.     debugger_enable(false);
  2390.     execution_pause(false);
  2391. }
  2392.  
  2393. void
  2394. on_debugger_run_button_clicked         (GtkButton       *button,
  2395.                                         gpointer         user_data)
  2396. {
  2397.     debugger_change_verbosity(false);
  2398.     ping_debugger_instruction_box();
  2399.     execution_pause(false);
  2400. }
  2401.  
  2402.  
  2403. void
  2404. on_debugger_walk_button_clicked        (GtkButton       *button,
  2405.                                         gpointer         user_data)
  2406. {
  2407.     debugger_change_verbosity(true);
  2408.     ping_debugger_instruction_box();
  2409.     execution_pause(false);
  2410. }
  2411.  
  2412.  
  2413. void
  2414. on_debugger_stop_button_clicked        (GtkButton       *button,
  2415.                                         gpointer         user_data)
  2416. {
  2417.     debugger_change_verbosity(true);
  2418.     execution_pause(true);
  2419.     debugger_refresh();
  2420.     if (!(stateflag & ST_PAUSE))
  2421.         stateflag |= ST_SINGLESTEP;
  2422.     ping_debugger_instruction_box();
  2423. }
  2424.  
  2425. void
  2426. on_debugger_next_button_clicked        (GtkButton       *button,
  2427.                                         gpointer         user_data)
  2428. {
  2429.     debugger_change_verbosity(true);
  2430. //    execution_pause(true);
  2431. //    execution_pause(false);
  2432.     stateflag |= ST_SINGLESTEP;
  2433.     ping_debugger_instruction_box();
  2434. }
  2435.  
  2436. void
  2437. GTK_system_debugger_enabled(bool enabled)
  2438. {
  2439.     if (enabled) {
  2440.         if (!VALID_WINDOW(debugger_window)) {
  2441.             debugger_window = create_debugger_window();
  2442.             gtk_widget_set_name(debugger_window, "v9t9.debugger");
  2443.  
  2444.             debugger_registers_table = gtk_object_get_data(GTK_OBJECT(debugger_window), 
  2445.                                                            "debugger_registers_table");
  2446.             debugger_instruction_box = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2447.                                                            "debugger_instruction_box");
  2448.             debugger_status_bar = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2449.                                                            "debugger_status_bar");
  2450.             debugger_pc_entry = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2451.                                                     "debugger_pc_entry");
  2452.             debugger_wp_entry = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2453.                                                     "debugger_wp_entry");
  2454.             debugger_st_entry = gtk_object_get_data(GTK_OBJECT(debugger_window),
  2455.                                                     "debugger_st_entry");
  2456.  
  2457.             setup_debugger_registers_table();
  2458.             setup_debugger_memory_views();
  2459.             setup_debugger_instruction_box();
  2460.         }
  2461. //        debugger_verbose_updates = true;
  2462. //        ping_debugger_instruction_box();
  2463.         gtk_widget_show(debugger_window);
  2464.     } else {
  2465.         if (debugger_window) {
  2466.             execution_pause(false);
  2467.             gtk_widget_hide(debugger_window);
  2468.             GTK_RESTORE_FOCUS;
  2469.         }
  2470.     }
  2471. }
  2472.  
  2473. void
  2474. GTK_system_execution_paused(bool paused)
  2475. {
  2476.     if (v9t9_window_pause_button) {
  2477.         GtkWidget *label = GTK_BIN(v9t9_window_pause_button)->child;
  2478.         if (!GTK_IS_LABEL(label))
  2479.             return;
  2480.  
  2481.         if (debugger_enabled()) {
  2482.             debugger_register_clear_view();
  2483.             debugger_memory_clear_views();
  2484.             debugger_instruction_clear_view();
  2485.         }
  2486.  
  2487.         if (paused) {
  2488.             gtk_label_set_text(GTK_LABEL(label), "Resume");
  2489.         } else {
  2490.             gtk_label_set_text(GTK_LABEL(label), "Pause");
  2491.         }
  2492.     }
  2493. }
  2494.  
  2495. #if 0
  2496. #pragma mark -
  2497. #endif
  2498.  
  2499. /*
  2500.  *    Generic routine that enables or disables a widget in user_data
  2501.  *    based on the state of the toggle button.
  2502.  */
  2503. void
  2504. on_v9t9_togglebutton_realize_widget_enable (GtkWidget           *widget,
  2505.                                          gpointer         user_data)
  2506. {
  2507.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget));
  2508.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2509.     gtk_widget_set_sensitive(GTK_WIDGET(user_data), 
  2510.          gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
  2511. }
  2512.  
  2513. void
  2514. on_v9t9_togglebutton_toggled_widget_enable (GtkToggleButton *togglebutton,
  2515.                                         gpointer         user_data)
  2516. {
  2517.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2518.     gtk_widget_set_sensitive(GTK_WIDGET(user_data), 
  2519.                              gtk_toggle_button_get_active(togglebutton));
  2520. }
  2521.  
  2522. void
  2523. on_v9t9_togglebutton_realize_widget_enable_not (GtkWidget           *widget,
  2524.                                          gpointer         user_data)
  2525. {
  2526.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget));
  2527.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2528.     gtk_widget_set_sensitive(GTK_WIDGET(user_data), 
  2529.          !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
  2530. }
  2531.  
  2532. void
  2533. on_v9t9_togglebutton_toggled_widget_enable_not (GtkToggleButton *togglebutton,
  2534.                                         gpointer         user_data)
  2535. {
  2536.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2537.     gtk_widget_set_sensitive(GTK_WIDGET(user_data), 
  2538.                              !gtk_toggle_button_get_active(togglebutton));
  2539. }
  2540.  
  2541. /*
  2542.  *    Generic routine that toggles the value of the command variable
  2543.  *    name in user_data depending on the value of togglebutton.
  2544.  */
  2545. static void
  2546. togglebutton_toggled_command_toggle
  2547.                                         (GtkToggleButton *togglebutton,
  2548.                                          gpointer         user_data,
  2549.                                          gboolean         if_active)
  2550. {
  2551.     gchar *var = (gchar *)user_data;
  2552.     gboolean enabled = gtk_toggle_button_get_active(togglebutton);
  2553.     char command[256];
  2554.  
  2555.     snprintf(command, sizeof(command), "%s %s\n", var, 
  2556.              if_active == enabled ? "on" : "off");
  2557.     GTK_send_command(command);
  2558. }
  2559.  
  2560. /*
  2561.  *    Generic routine that toggles the value of the command variable
  2562.  *    name in user_data depending on the value of togglebutton.
  2563.  */
  2564. void
  2565. on_v9t9_togglebutton_toggled_command_toggle
  2566.                                         (GtkToggleButton *togglebutton,
  2567.                                         gpointer         user_data)
  2568. {
  2569.     togglebutton_toggled_command_toggle(togglebutton, user_data, true);
  2570. }
  2571.  
  2572. /*
  2573.  *    Generic routine that toggles the value of the command variable
  2574.  *    name in user_data depending on the inverted value of togglebutton.
  2575.  */
  2576. void
  2577. on_v9t9_togglebutton_toggled_command_toggle_not
  2578.                                         (GtkToggleButton *togglebutton,
  2579.                                         gpointer         user_data)
  2580. {
  2581.     togglebutton_toggled_command_toggle(togglebutton, user_data, false);
  2582. }
  2583.  
  2584.  
  2585. /*
  2586.  *    Generic routine that sets the value of the togglebutton
  2587.  *    based on the value of the command variable name in user_data.
  2588.  */
  2589. static void
  2590. togglebutton_realize_active (GtkWidget       *widget,
  2591.                                    gpointer         user_data,
  2592.                                    gboolean            if_active)
  2593. {
  2594.     GtkToggleButton *tb;
  2595.     char *var = (char *)user_data;
  2596.     command_symbol *sym;
  2597.     int toggle;
  2598.  
  2599.     g_return_if_fail(var);
  2600.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget));
  2601.     tb = GTK_TOGGLE_BUTTON(widget);
  2602.  
  2603.     /* Look up the symbol and set its value */
  2604.     if (command_match_symbol(universe, var, &sym) &&
  2605.         command_arg_get_num(sym->args, &toggle)) 
  2606.     {
  2607.         // don't call this, or else it triggers the other
  2608.         // callback and executes a command...
  2609.         //gtk_toggle_button_set_active(tb, if_active == toggle);
  2610.         tb->active = (if_active == !!toggle);
  2611.     }
  2612.     else
  2613.     {
  2614.         logger(LOG_USER|LOG_FATAL, "Button mapped to missing option '%s'\n",
  2615.                var);
  2616.     }
  2617. }
  2618.  
  2619. /*
  2620.  *    Generic routine that sets the value of the togglebutton
  2621.  *    based on the true value of the command variable name in user_data.
  2622.  */
  2623. void
  2624. on_v9t9_togglebutton_realize_active  (GtkWidget       *widget,
  2625.                                      gpointer         user_data)
  2626. {
  2627.     togglebutton_realize_active(widget, user_data, true);
  2628. }
  2629.  
  2630. /*
  2631.  *    Generic routine that sets the value of the togglebutton
  2632.  *    based on the false value of the command variable name in user_data.
  2633.  */
  2634. void
  2635. on_v9t9_togglebutton_realize_inactive (GtkWidget       *widget,
  2636.                                      gpointer         user_data)
  2637. {
  2638.     togglebutton_realize_active(widget, user_data, false);
  2639. }
  2640.  
  2641. /*
  2642.  *    Generic callback to execute a command if a toggle button
  2643.  *    has been clicked and thusly enabled.
  2644.  */
  2645. void
  2646. on_v9t9_togglebutton_clicked            (GtkButton       *button,
  2647.                                         gpointer         user_data)
  2648. {
  2649.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button));
  2650.     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
  2651.     {
  2652.         GTK_send_command((const gchar *)user_data);
  2653.     }
  2654. }
  2655.  
  2656. static char *
  2657. _v9t9_dsr_entry_get_filename(gpointer user_data)
  2658. {
  2659.     char *var, *filename;
  2660.     command_symbol *sym;
  2661.  
  2662.     var = (char *)user_data;
  2663.  
  2664.     /* Look up the symbol and set its value */
  2665.     if (command_match_symbol(universe, var, &sym) &&
  2666.         command_arg_get_string(sym->args, &filename)) 
  2667.     {
  2668.         return filename;
  2669.     }
  2670.     else
  2671.     {
  2672.         logger(LOG_USER|LOG_FATAL, "Text entry mapped to missing option '%s'\n",
  2673.                var);
  2674.         return 0L;
  2675.     }
  2676. }
  2677.  
  2678. static void
  2679. _v9t9_dsr_entry_set_filename(gpointer user_data, char *filename)
  2680. {
  2681.     char msg[256];
  2682.  
  2683.     snprintf(msg, sizeof(msg), "%s \"%s\"\n",
  2684.              (gchar *)user_data, filename);
  2685.     GTK_send_command(msg);
  2686. }
  2687.  
  2688. /*
  2689.  *    Generic DSR entry activation callback
  2690.  */
  2691. void
  2692. on_v9t9_dsr_entry_activate             (GtkEditable     *editable,
  2693.                                         gpointer         user_data)
  2694. {
  2695.     char *path;
  2696.     gchar *copy;
  2697.     OSSpec spec;
  2698.  
  2699.     if (GTK_WIDGET(editable)->state != GTK_STATE_INSENSITIVE)
  2700.     {
  2701.         path = gtk_editable_get_chars(editable, 0, -1);
  2702.  
  2703.         copy = disk_file_canonicalize(&romspath, systemromspath,
  2704.                                       false /*directory*/, path, &spec,
  2705.                                       true /*add_dir*/);
  2706.         _v9t9_dsr_entry_set_filename(user_data, copy);
  2707.  
  2708.         g_free(path);
  2709.         g_free(copy);
  2710.     }
  2711. }
  2712.  
  2713. /*
  2714.  *    Setup the text entry
  2715.  */
  2716. void
  2717. on_v9t9_dsr_entry_realize              (GtkWidget       *widget,
  2718.                                         gpointer         user_data)
  2719. {
  2720.     char *filename;
  2721.  
  2722.     g_return_if_fail(GTK_IS_ENTRY(widget));
  2723.  
  2724.     filename = _v9t9_dsr_entry_get_filename(user_data);
  2725.     gtk_entry_set_text(GTK_ENTRY(widget), filename ? filename : "");
  2726. }
  2727.  
  2728. static GtkFileSelection *dsr_file_dialog;
  2729.  
  2730. static GtkFileSelection *
  2731. create_dsr_file_selection (void)
  2732. {
  2733.   GtkWidget *dsr_file_selection;
  2734.   GtkWidget *ok_button2;
  2735.   GtkWidget *cancel_button2;
  2736.  
  2737.   dsr_file_selection = gtk_file_selection_new ("Select ROM Filename");
  2738.   gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "dsr_file_selection", dsr_file_selection);
  2739.   gtk_container_set_border_width (GTK_CONTAINER (dsr_file_selection), 10);
  2740.  
  2741.   ok_button2 = GTK_FILE_SELECTION (dsr_file_selection)->ok_button;
  2742.   gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "ok_button2", ok_button2);
  2743.   gtk_widget_show (ok_button2);
  2744.   GTK_WIDGET_SET_FLAGS (ok_button2, GTK_CAN_DEFAULT);
  2745.  
  2746.   cancel_button2 = GTK_FILE_SELECTION (dsr_file_selection)->cancel_button;
  2747.   gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "cancel_button2", cancel_button2);
  2748.   gtk_widget_show (cancel_button2);
  2749.   GTK_WIDGET_SET_FLAGS (cancel_button2, GTK_CAN_DEFAULT);
  2750.  
  2751.   return GTK_FILE_SELECTION(dsr_file_selection);
  2752. }
  2753.  
  2754. /*
  2755.  *    user_data is the text entry widget
  2756.  */
  2757. static void
  2758. on_dsr_file_ok_button_clicked         (GtkButton       *button,
  2759.                                         gpointer         user_data)
  2760. {
  2761.     gchar *path;
  2762.     gchar *copy;
  2763.     GtkEntry *entry;
  2764.     OSSpec spec;
  2765.  
  2766.     g_return_if_fail(GTK_IS_ENTRY(user_data));
  2767.  
  2768.     entry = GTK_ENTRY(user_data);
  2769.  
  2770.     path = gtk_file_selection_get_filename(dsr_file_dialog);
  2771.     copy = disk_file_canonicalize(&romspath, systemromspath,
  2772.                                   false /*directory*/, path, &spec,
  2773.                                   true /*add_dir*/);
  2774.  
  2775.     gtk_entry_set_text(entry, copy);
  2776.     gtk_signal_emit_by_name(GTK_OBJECT(entry), "activate");
  2777.  
  2778.     gtk_widget_unref((GtkWidget *)dsr_file_dialog);
  2779.     dsr_file_dialog = 0L;
  2780.  
  2781.     g_free(copy);
  2782. }
  2783.  
  2784. /*
  2785.  *    user_data is the DSR filename variable
  2786.  */
  2787. static void
  2788. on_dsr_file_cancel_button_clicked     (GtkButton       *button,
  2789.                                         gpointer         user_data)
  2790. {
  2791.     gtk_widget_unref((GtkWidget *)dsr_file_dialog);
  2792.     dsr_file_dialog = 0L;
  2793. }
  2794.  
  2795. /*
  2796.  *    Choose a new entry for the filename.
  2797.  *
  2798.  *    user_data is the text entry widget
  2799.  */
  2800. void
  2801. on_v9t9_dsr_button_clicked             (GtkButton       *button,
  2802.                                         gpointer         user_data)
  2803. {
  2804.     OSSpec spec;
  2805.     const char *filename;
  2806.     GtkEntry *entry;
  2807.     gchar *copy;
  2808.  
  2809.     g_return_if_fail(GTK_IS_ENTRY(user_data));
  2810.  
  2811.     entry = GTK_ENTRY(user_data);
  2812.  
  2813.     if (VALID_WINDOW(dsr_file_dialog)) {
  2814.         return;
  2815.     }
  2816.  
  2817.     dsr_file_dialog = create_dsr_file_selection();
  2818.  
  2819.     gtk_widget_show(GTK_WIDGET(dsr_file_dialog));
  2820.     filename = gtk_entry_get_text(entry);
  2821.  
  2822.     copy = disk_file_canonicalize(&romspath, systemromspath,
  2823.                                    false /*directory*/, filename, &spec,
  2824.                                   false /*add_dir*/);
  2825.  
  2826.     gtk_file_selection_set_filename(dsr_file_dialog, OS_SpecToString1(&spec));
  2827.     gtk_file_selection_complete(dsr_file_dialog, "*.bin");
  2828.  
  2829.     g_free(copy);
  2830.  
  2831.     // wire up buttons here (so we can pass known disk number)
  2832.     gtk_signal_connect(GTK_OBJECT(dsr_file_dialog->ok_button), 
  2833.                        "clicked", 
  2834.                        GTK_SIGNAL_FUNC(on_dsr_file_ok_button_clicked),
  2835.                        (gpointer)entry);
  2836.     gtk_signal_connect(GTK_OBJECT(dsr_file_dialog->cancel_button), 
  2837.                        "clicked", 
  2838.                        GTK_SIGNAL_FUNC(on_dsr_file_cancel_button_clicked),
  2839.                        (gpointer)0L);
  2840. }
  2841.  
  2842. /***********************************************/
  2843. #if 0
  2844. #pragma mark -
  2845. #endif
  2846.  
  2847. static GtkWidget *memory_dialog;
  2848.  
  2849. void
  2850. on_v9t9_window_memory_button_clicked   (GtkButton       *button,
  2851.                                         gpointer         user_data)
  2852. {
  2853.     if (!VALID_WINDOW(memory_dialog)) {
  2854.         memory_dialog = create_memory_dialog();
  2855.     } else {
  2856.         gtk_widget_hide(memory_dialog);
  2857.     }
  2858.     gtk_widget_show(memory_dialog);
  2859.  
  2860.     execution_pause(true);
  2861. }
  2862.  
  2863.  
  2864. void
  2865. on_memory_dialog_close_button_clicked  (GtkButton       *button,
  2866.                                         gpointer         user_data)
  2867. {
  2868.     gtk_widget_hide(memory_dialog);
  2869.     execution_pause(false);
  2870.     GTK_RESTORE_FOCUS;
  2871. }
  2872.  
  2873. /*
  2874.  *    Lookup and execute the first iteration of a dynamic command
  2875.  */
  2876. static int 
  2877. _v9t9_dynamic_command(const char *name, command_symbol **sym)
  2878. {
  2879.     if (!command_match_symbol(universe, name, sym))
  2880.         logger(_L|LOG_FATAL, "Unknown command '%s'\n", name);
  2881.  
  2882.     if (!((*sym)->flags & c_DYNAMIC))
  2883.         logger(_L|LOG_FATAL, "'%s' is not c_DYNAMIC\n", name);
  2884.  
  2885.     return (*sym)->action(*sym, csa_READ, 0);
  2886. }
  2887.  
  2888. /*
  2889.  *    Activate or deactivate a button that optionally loads
  2890.  *    a module ROM.  These conflict with the "LoadModule"
  2891.  *    command and the commands that load them won't be saved
  2892.  *    to the config file if they are empty.  We use this
  2893.  *    to tell whether they are being used.
  2894.  */
  2895. void
  2896. on_memory_config_module_rom_button_realize
  2897.                                         (GtkWidget       *widget,
  2898.                                         gpointer         user_data)
  2899. {
  2900.     GtkToggleButton *tb;
  2901.     command_symbol *sym;
  2902.  
  2903. #if 0
  2904.     // old style: one button per ROM
  2905.     g_return_if_fail(user_data);
  2906.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget));
  2907.     tb = GTK_TOGGLE_BUTTON(widget);
  2908.  
  2909.     /*
  2910.      *    If the entry is loaded, activate the button.
  2911.      */
  2912.     tb->active = (_v9t9_dynamic_command((char *)user_data, &sym));
  2913. #endif
  2914.  
  2915.     g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget));
  2916.     tb = GTK_TOGGLE_BUTTON(widget);
  2917.  
  2918.     /*
  2919.      *    If the module entry is not loaded, activate the button.
  2920.      */
  2921.     tb->active = (!_v9t9_dynamic_command("ReplaceModule", &sym));
  2922. }
  2923.  
  2924. /*
  2925.  *    User opted to set a custom module ROM file,
  2926.  *    this means we have to unload the module entry so
  2927.  *    this will have precedence.
  2928.  */
  2929. void
  2930. on_memory_config_module_rom_button_clicked
  2931.                                         (GtkToggleButton *togglebutton,
  2932.                                         gpointer         user_data)
  2933. {
  2934.     gpointer ptr;
  2935.  
  2936.     if (gtk_toggle_button_get_active(togglebutton))
  2937.     {
  2938.         /* Activate all the children */
  2939.         ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom_entry");
  2940.         if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate");
  2941.         ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_grom_entry");
  2942.         if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate");
  2943.         ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom1_entry");
  2944.         if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate");
  2945.         ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom2_entry");
  2946.         if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate");
  2947.     }
  2948.  
  2949. #if 0
  2950.     // old style: one button per rom
  2951.     g_return_if_fail(GTK_IS_ENTRY(user_data));
  2952.  
  2953.     if (gtk_toggle_button_get_active(togglebutton))
  2954.     {
  2955.         if (_v9t9_dynamic_command("ReplaceModule", &sym))
  2956.         {
  2957.             GTK_send_command("UnloadModuleOnly\n");
  2958.         }
  2959.         gtk_signal_emit_by_name(GTK_OBJECT(user_data), "activate");
  2960.     }
  2961. #endif
  2962. }
  2963.  
  2964. /*
  2965.  *    Activated the ROM entry, disable the banked ROM entries
  2966.  */
  2967. void
  2968. on_memory_config_banked_module_deactivate
  2969.                                         (GtkEditable     *editable,
  2970.                                         gpointer         user_data)
  2971. {
  2972.     gchar *str;
  2973.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2974.     
  2975.     str = gtk_entry_get_text(GTK_ENTRY(editable));
  2976.     if (str && *str)
  2977.         gtk_widget_set_sensitive(GTK_WIDGET(user_data), false);
  2978.     else
  2979.         gtk_widget_set_sensitive(GTK_WIDGET(user_data), true);
  2980.  
  2981.     /* v9t9 handles the memory map stuff */
  2982. }
  2983.  
  2984. /*
  2985.  *    Banked module entry activated
  2986.  */
  2987. void
  2988. on_module_config_banked_module_activate
  2989.                                         (GtkEditable     *editable,
  2990.                                         gpointer         user_data)
  2991. {
  2992.     gchar *str;
  2993.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  2994.     
  2995.     str = gtk_entry_get_text(GTK_ENTRY(editable));
  2996.     if (str && *str)
  2997.         gtk_widget_set_sensitive(GTK_WIDGET(user_data), false);
  2998.     else
  2999.         gtk_widget_set_sensitive(GTK_WIDGET(user_data), true);
  3000.  
  3001.     /* v9t9 handles the memory map stuff */
  3002. }
  3003.  
  3004. #if 0
  3005. #pragma mark -
  3006. #endif
  3007.  
  3008. /*
  3009.  *    OPTIONS WINDOW
  3010.  */
  3011.  
  3012. static GtkWidget *options_dialog;
  3013.  
  3014. void
  3015. on_v9t9_window_options_button_clicked  (GtkButton       *button,
  3016.                                         gpointer         user_data)
  3017. {
  3018.     if (!VALID_WINDOW(options_dialog)) {
  3019.         options_dialog = create_options_dialog();
  3020.     } else {
  3021.         gtk_widget_hide(options_dialog);
  3022.     }
  3023.     gtk_widget_show(options_dialog);
  3024. }
  3025.  
  3026. void
  3027. on_option_dialog_close_button_clicked  (GtkButton       *button,
  3028.                                         gpointer         user_data)
  3029. {
  3030.     gtk_widget_hide(options_dialog);
  3031.  
  3032.     GTK_RESTORE_FOCUS;
  3033. }
  3034.  
  3035. /*
  3036.  *    Set the value of a spin button from a command.
  3037.  */
  3038. void
  3039. on_v9t9_spin_button_realize_value      (GtkWidget       *widget,
  3040.                                         gpointer         user_data)
  3041. {
  3042.     GtkSpinButton *s;
  3043.     command_symbol *sym;
  3044.     int val;
  3045.  
  3046.     g_return_if_fail(user_data != 0L);
  3047.     g_return_if_fail(GTK_IS_SPIN_BUTTON(widget));
  3048.     s = GTK_SPIN_BUTTON(widget);
  3049.  
  3050.     /* Look up the symbol and set its value */
  3051.     if (command_match_symbol(universe, (char *)user_data, &sym) &&
  3052.         command_arg_get_num(sym->args, &val)) 
  3053.     {
  3054.         gtk_spin_button_set_value(s, (gfloat)val);
  3055.     }
  3056.     else
  3057.     {
  3058.         logger(LOG_USER|LOG_FATAL, "Button mapped to missing option '%s'\n",
  3059.                user_data);
  3060.     }
  3061. }
  3062.  
  3063. /*
  3064.  *    User changed value of a spin button.
  3065.  *    user_data is the name of the command to set.
  3066.  */
  3067. void
  3068. on_v9t9_spin_button_changed_value      (GtkEditable     *editable,
  3069.                                         gpointer         user_data)
  3070. {
  3071.     char command[256];
  3072.     GtkSpinButton *s;
  3073.  
  3074.     g_return_if_fail(user_data != 0L);
  3075.     g_return_if_fail(GTK_IS_SPIN_BUTTON(editable));
  3076.     s = GTK_SPIN_BUTTON(editable);
  3077.  
  3078.     snprintf(command, sizeof(command), "%s %d\n", (char *)user_data, 
  3079.              gtk_spin_button_get_value_as_int(s));
  3080.  
  3081.     GTK_send_command(command);
  3082. }
  3083.  
  3084. /*
  3085.  *    Clicked a button that affects the value of another widget.
  3086.  */
  3087. void
  3088. on_v9t9_button_clicked_realize_widget  (GtkButton       *button,
  3089.                                         gpointer         user_data)
  3090. {
  3091.     GtkWidget *w;
  3092.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  3093.  
  3094.     w = GTK_WIDGET(user_data);
  3095.  
  3096.     // why can't we realize the widget again?
  3097.     gtk_widget_hide(w);
  3098.     gtk_widget_show(w);
  3099. }
  3100.  
  3101. #if 0
  3102. #pragma mark -
  3103. #endif
  3104.  
  3105. V99FileSelection *config_file_dialog;
  3106.  
  3107. /*
  3108.  *    user_data is 0 for saving, != 0 for loading
  3109.  */
  3110. static void
  3111. on_config_file_ok_button_clicked         (GtkButton       *button,
  3112.                                         gpointer         user_data)
  3113. {
  3114.     const char *path;
  3115.     OSSpec spec;
  3116.     OSError err;
  3117.  
  3118.     path = v99_file_selection_get_filename(config_file_dialog);
  3119.     err = OS_MakeFileSpec(path, &spec);
  3120.     if (err != OS_NOERR) {
  3121.         logger(_L|LOG_ERROR|LOG_USER, "Could not resolve filename '%s' (%s)\n", 
  3122.                path, OS_GetErrText(err));
  3123.         return;
  3124.     }
  3125.     
  3126.     if ((gint)user_data == GTK_QUICK_LOAD ? 
  3127.         config_load_spec(&spec, true /*session*/) :
  3128.         config_save_spec(&spec, true /*session*/)) 
  3129.     {    
  3130.         gtk_widget_hide((GtkWidget *)config_file_dialog);
  3131.         GTK_RESTORE_FOCUS;
  3132.     }
  3133. }
  3134.  
  3135.  
  3136. static void
  3137. on_config_file_cancel_button_clicked     (GtkButton       *button,
  3138.                                         gpointer         user_data)
  3139. {
  3140.     gtk_widget_hide((GtkWidget *)config_file_dialog);
  3141.     GTK_RESTORE_FOCUS;
  3142. }
  3143.  
  3144. /*
  3145.  *    Change directory by selecting an entry in the pathlist
  3146.  */
  3147. static void 
  3148. on_config_file_path_list_select_row    (GtkWidget      *clist,
  3149.                                      gint            row,
  3150.                                      gint            column,
  3151.                                      GdkEventButton *event,
  3152.                                      gpointer        data )
  3153. {
  3154.     gchar *text;
  3155.     gchar *wild;
  3156.     gchar sep[] = { G_DIR_SEPARATOR, 0 };
  3157.  
  3158.     /* Get the directory selected */
  3159.     gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
  3160.  
  3161.     if (strcmp(text, ".") == 0) {
  3162.         text = OS_PathSpecToString1(&v9t9_homedir);
  3163.     }
  3164.     wild = g_strconcat(text, sep, "*.cnf", 0L);
  3165.     v99_file_selection_complete(V99_FILE_SELECTION(config_file_dialog), wild);
  3166.     g_free(wild);
  3167. }
  3168.  
  3169. /*
  3170.  *    user_data is 0 for saving, != 0 for loading
  3171.  */
  3172. void
  3173. on_v9t9_quick_load_save_button_clicked      (GtkButton       *button,
  3174.                                              gpointer         user_data)
  3175. {
  3176.     GtkCList *clist;
  3177.     int paused = execution_paused();
  3178.     if ((int)user_data == 0) execution_pause(1);
  3179.  
  3180.     if (VALID_WINDOW(config_file_dialog)) {
  3181.         gtk_widget_destroy((GtkWidget *)config_file_dialog);
  3182.     }
  3183.  
  3184.     config_file_dialog = V99_FILE_SELECTION(create_disk_file_selection(
  3185.         (gint)user_data == GTK_QUICK_SAVE 
  3186.         ? "Save Session File" 
  3187.         : "Load Session File"));
  3188.  
  3189.     v99_file_selection_set_file_list_active(config_file_dialog, TRUE);
  3190.  
  3191.     // wire up buttons here
  3192.     gtk_signal_connect(GTK_OBJECT(config_file_dialog->ok_button), 
  3193.                        "clicked", 
  3194.                        GTK_SIGNAL_FUNC(on_config_file_ok_button_clicked),
  3195.                        user_data);
  3196.     gtk_signal_connect(GTK_OBJECT(config_file_dialog->cancel_button), 
  3197.                        "clicked", 
  3198.                        GTK_SIGNAL_FUNC(on_config_file_cancel_button_clicked),
  3199.                        (gpointer)0L);
  3200.     
  3201.     gtk_widget_show(GTK_WIDGET(config_file_dialog));
  3202.  
  3203.     // FIXME:  add tooltips
  3204.     clist = v99_file_selection_add_path_list(config_file_dialog, 
  3205.                                              "Sessions",
  3206.                                              sessionspath);
  3207.  
  3208.     /* wire up callback to change directory */
  3209.     gtk_signal_connect(GTK_OBJECT(clist), 
  3210.                        "select_row", 
  3211.                        GTK_SIGNAL_FUNC(on_config_file_path_list_select_row),
  3212.                        (gpointer)0L);
  3213.  
  3214.     clist = v99_file_selection_add_path_list(config_file_dialog, 
  3215.                                              "Configurations",
  3216.                                              configspath);
  3217.  
  3218.     /* wire up callback to change directory */
  3219.     gtk_signal_connect(GTK_OBJECT(clist), 
  3220.                        "select_row", 
  3221.                        GTK_SIGNAL_FUNC(on_config_file_path_list_select_row),
  3222.                        (gpointer)0L);
  3223.  
  3224.     if ((gint)user_data == GTK_QUICK_LOAD)
  3225.         v99_file_selection_complete(config_file_dialog, "*.cnf");
  3226.     else
  3227.         v99_file_selection_complete(config_file_dialog, "quicksave.cnf");
  3228.  
  3229.     v99_file_selection_set_filename(config_file_dialog, "quicksave.cnf");
  3230.  
  3231. }
  3232.  
  3233. /*********************************************/
  3234.  
  3235. /*
  3236.  *    Logging Configuration dialog.
  3237.  *
  3238.  *    The meat of the dialog is automatically generated.
  3239.  */
  3240. static GtkWidget *log_dialog;
  3241. static GtkTable *log_table;
  3242.  
  3243. void
  3244. on_v9t9_window_logging_button_clicked  (GtkButton       *button,
  3245.                                         gpointer         user_data)
  3246. {
  3247.     if (!VALID_WINDOW(log_dialog)) {
  3248.         log_dialog = create_logging_dialog();
  3249.     } else {
  3250.         gtk_widget_hide(log_dialog);
  3251.     }
  3252.     gtk_widget_show(log_dialog);
  3253. }
  3254.  
  3255. void
  3256. on_logging_reset_all_clicked           (GtkButton       *button,
  3257.                                         gpointer         user_data)
  3258. {
  3259.     GTK_send_command("Log All 0\n");
  3260.  
  3261.     /* force a realize */
  3262.     gtk_signal_emit_by_name(GTK_OBJECT(log_table), "realize");
  3263. }
  3264.  
  3265. void
  3266. on_logging_dialog_close_button_clicked (GtkButton       *button,
  3267.                                         gpointer         user_data)
  3268. {
  3269.     gtk_widget_hide(log_dialog);
  3270. }
  3271.  
  3272. /*
  3273.  *    Logging spin button needs to be realized.
  3274.  *    user_data is the logging subsystem.
  3275.  */
  3276. void
  3277. on_log_spin_button_realize_value      (GtkWidget       *widget,
  3278.                                         gpointer         user_data)
  3279. {
  3280.     GtkSpinButton *s;
  3281.     int val;
  3282.  
  3283.     g_return_if_fail(GTK_IS_SPIN_BUTTON(widget));
  3284.     s = GTK_SPIN_BUTTON(widget);
  3285.  
  3286.     /* Look up the symbol and set its value */
  3287.     val = log_level((int)user_data);
  3288.     gtk_spin_button_set_value(s, (gfloat)val);
  3289. }
  3290.  
  3291. /*
  3292.  *    Logging spin button changes.
  3293.  *    user_data is the log subsystem.
  3294.  */
  3295. static void
  3296. on_log_spin_button_changed_value      (GtkEditable     *editable,
  3297.                                        gpointer         user_data)
  3298. {
  3299.     char command[256];
  3300.     GtkSpinButton *s;
  3301.  
  3302.     g_return_if_fail(GTK_IS_SPIN_BUTTON(editable));
  3303.     s = GTK_SPIN_BUTTON(editable);
  3304.  
  3305.     snprintf(command, sizeof(command), "Log %s %d\n", 
  3306.              log_name((int)user_data), 
  3307.              gtk_spin_button_get_value_as_int(s));
  3308.  
  3309.     GTK_send_command(command);
  3310. }
  3311.  
  3312.  
  3313. /*
  3314.  *    Clicked a button that affects the value
  3315.  */
  3316. static void
  3317. on_log_button_clicked_realize_widget  (GtkButton       *button,
  3318.                                         gpointer         user_data)
  3319. {
  3320.     GtkWidget *w;
  3321.     g_return_if_fail(GTK_IS_WIDGET(user_data));
  3322.  
  3323.     w = GTK_WIDGET(user_data);
  3324.  
  3325.     // why can't we realize the widget again?
  3326.     gtk_widget_hide(w);
  3327.     gtk_widget_show(w);
  3328. }
  3329.  
  3330. /*
  3331.  *    This action sets up the log_dialog's log_table item 
  3332.  *    to include a dial and label for each log subsystem.
  3333.  */
  3334. void
  3335. on_logging_log_table_realize           (GtkWidget       *widget,
  3336.                                         gpointer         user_data)
  3337. {
  3338.     int rows = LOG_NUM_SRC / 3;
  3339.     int cols = 3;
  3340.     int row, col, sys;
  3341.  
  3342.     /* Get the table */
  3343.     log_table = GTK_TABLE(gtk_object_get_data((GtkObject *)log_dialog, "log_table"));
  3344.     if (!log_table)
  3345.         logger(_L|LOG_FATAL, "Cannot get log_table from dialog\n");
  3346.  
  3347.     /* Resize from 1x1 to an interesting size */
  3348.     gtk_table_resize(log_table, rows, cols);
  3349.  
  3350.     /* Add an entry for each subsystem */
  3351.     row = col = 0;
  3352.     for (sys = 0; sys < LOG_NUM_SRC; sys++) {
  3353.         /* make the widgets */
  3354.         GtkObject *spin_adj = gtk_adjustment_new(
  3355.             log_level(sys), 
  3356.             L_0,
  3357.             L_4,
  3358.             1,
  3359.             1,
  3360.             1);
  3361.         GtkWidget *spin = gtk_spin_button_new(GTK_ADJUSTMENT(spin_adj), 1, 1);
  3362.         GtkWidget *label = gtk_label_new(log_name(sys));
  3363.         GtkWidget *hbox = gtk_hbox_new(false /*homogenous*/, 4 /*spacing*/);
  3364.  
  3365.         /* standard stuff */
  3366.         gtk_widget_ref(spin);
  3367.         gtk_widget_ref(label);
  3368.         gtk_widget_ref(hbox);
  3369.  
  3370.         gtk_object_set_data_full (GTK_OBJECT (log_table), "log_spin_button", 
  3371.                                   spin,(GtkDestroyNotify) gtk_widget_unref);
  3372.         gtk_object_set_data_full (GTK_OBJECT (log_table), "log_label", 
  3373.                                   label,(GtkDestroyNotify) gtk_widget_unref);
  3374.         gtk_object_set_data_full (GTK_OBJECT (log_table), "log_hbox", 
  3375.                                   hbox,(GtkDestroyNotify) gtk_widget_unref);
  3376.  
  3377.         /* associate subsystem with spin button */
  3378.         gtk_signal_connect_after (GTK_OBJECT (spin), "activate",
  3379.                                   GTK_SIGNAL_FUNC (on_log_spin_button_changed_value),
  3380.                                   (gpointer)sys);
  3381.         gtk_signal_connect (GTK_OBJECT (spin), "changed",
  3382.                             GTK_SIGNAL_FUNC (on_log_spin_button_changed_value),
  3383.                               (gpointer)sys);
  3384.         gtk_signal_connect (GTK_OBJECT (spin), "realize",
  3385.                             GTK_SIGNAL_FUNC (on_log_spin_button_realize_value),
  3386.                             (gpointer)sys);
  3387.         gtk_signal_connect (GTK_OBJECT (spin), "show",
  3388.                             GTK_SIGNAL_FUNC (on_log_spin_button_realize_value),
  3389.                             (gpointer)sys);
  3390.  
  3391.         gtk_box_pack_start(GTK_BOX(hbox), label, 
  3392.                            TRUE /*expand*/, FALSE /*fill*/, 0 /*padding*/);
  3393.         gtk_box_pack_start(GTK_BOX(hbox), spin, 
  3394.                            FALSE /*expand*/, TRUE /*fill*/, 0 /*padding*/);
  3395.  
  3396.         gtk_widget_show(spin);
  3397.         gtk_widget_show(label);
  3398.         gtk_widget_show(hbox);
  3399.  
  3400.         /* add hbox to table */
  3401.         gtk_table_attach_defaults (GTK_TABLE (log_table), 
  3402.                                    hbox, col, col+1, row, row+1);
  3403.  
  3404.         if (++col >= cols) {
  3405.             col = 0;
  3406.             ++row;
  3407.         }
  3408.     }
  3409. }
  3410.  
  3411.