#ifdef HAVE_CONFIG_H # include #endif #include #include #if 0 && defined(UNDER_WIN32) #define WIN32_LEAN_AND_MEAN #include #endif #include "gtkcallbacks.h" #include "gtkinterface.h" #include "gtksupport.h" #include "gtk_v99filesel.h" #include "gtkloop.h" #include "v9t9_common.h" #include "v9t9.h" #include "moduleconfig.h" #include "moduledb.h" #include "debugger.h" #include "dsr.h" #include "vdp.h" #include "fiad.h" #include "roms.h" #include "timer.h" #include "config.h" #define _L LOG_VIDEO #include "log.h" /* * Initial window size configured? */ int GTK_size_configured; /* * Size of TI screen */ int GTK_x_size, GTK_y_size; /* * Size of drawing area (as of last configure_event) * and multiple of x_size and y_size this is */ int GTK_x_pixels, GTK_y_pixels, GTK_x_mult, GTK_y_mult; int GTK_user_size_configured; /* * "Pause" button */ GtkButton *v9t9_window_pause_button; /* * Make a tag for a widget used in setting unique names * for repeated members of an object */ static char * widget_tag(const char *base, int number, int mag) { static char widget_tag_buf[32]; int len = strlen(base); unsigned int nyb = mag; memcpy(widget_tag_buf, base, len); while (nyb) { widget_tag_buf[len++] = "0123456789ABCDEF"[number & nyb]; nyb >>= 4; } widget_tag_buf[len] = 0; return widget_tag_buf; } void on_v9t9_window_destroy (GtkObject *object, gpointer user_data) { gtk_main_quit(); v9t9_sigterm(1); } gboolean on_v9t9_draw_area_configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { /* g_print("configure_event, ev =%d,%d req=%d,%d alloc=%d,%d\n", event->width, event->height, widget->requisition.width, widget->requisition.height, widget->allocation.width, widget->allocation.height);*/ #if defined(UNDER_WIN32) if (gtkVideo.runtimeflags & vmRTUnselected) { if (v9t9_drawing_area) { gtk_widget_destroy(v9t9_drawing_area); v9t9_drawing_area = NULL; } } #endif #if 0 && defined(UNDER_WIN32) // an attempt to make an actual window be reparented // inside the v9t9_drawing_area... doesn't seem to work { GdkWindow *window; GtkWidget *parent; GtkWidget *area; extern HWND hWndWindow; parent = v9t9_drawing_area->parent; window = gdk_window_foreign_new ((guint32) hWndWindow); gtk_widget_destroy(v9t9_drawing_area); v9t9_drawing_area = gtk_drawing_area_new(); v9t9_drawing_area->window = window; gtk_widget_show(v9t9_drawing_area); // area = gtk_widget_new(); // area->window = window; gtk_container_add(GTK_CONTAINER(parent), v9t9_drawing_area); } #endif GTK_x_mult = (widget->requisition.width) / GTK_x_size; GTK_y_mult = (widget->requisition.height) / GTK_y_size; if (!GTK_x_mult) GTK_x_mult = 1; if (!GTK_y_mult) GTK_y_mult = 1; if (GTK_x_size * GTK_x_mult != GTK_x_pixels || GTK_y_size * GTK_y_mult != GTK_y_pixels) { GTK_x_pixels = GTK_x_size * GTK_x_mult; GTK_y_pixels = GTK_y_size * GTK_y_mult; vdpcompleteredraw(); } return TRUE; } /* * Make sure the size of the widget is a multiple of 256 and 192 */ void on_v9t9_draw_area_size_request (GtkWidget *widget, GtkRequisition *requisition, gpointer user_data) { int psx, psy; GtkWidget *main; /* g_print("size_request, Req=%d,%d, req=%d,%d alloc=%d,%d\n", requisition->width, requisition->height, widget->requisition.width, widget->requisition.height, widget->allocation.width, widget->allocation.height); g_print("\tparent's parent's size is %d,%d\n", widget->parent->parent->allocation.width, widget->parent->parent->allocation.height);*/ // base our size on main window size main = widget->parent; while (main && !GTK_IS_WINDOW(main)) { main = main->parent; } g_assert(main); if (!GTK_x_size) GTK_x_size = 256; if (!GTK_y_size) GTK_y_size = 192; if (GTK_size_configured || GTK_user_size_configured) { // did user specify the size? if (GTK_user_size_configured) { psx = GTK_x_mult * 256; psy = GTK_y_mult * 192; GTK_user_size_configured = 0; } else { // else, use parent's size psx = widget->allocation.width; psy = widget->allocation.height; // ignore smaller window size and keep existing size if (psx < 256 || psy < 192) { psx = main->allocation.width; psy = main->allocation.height; } if (psx < 256 || psy < 192) { psx = 256; psy = 192; } } } else { // if sizes not set up yet (say, by v9t9 reading -geometry), // take up 1/2 of the screen psx = gdk_screen_width() / 2 / GTK_x_size; psy = gdk_screen_height() / 2 / GTK_y_size; // fix to an aspected multiple of 256x192 if (psx < 1) psx = 1; if (psy < 1) psy = 1; if (psx < psy) psx = psy; psx *= GTK_x_size; psy *= GTK_y_size; } GTK_size_configured = 1; if (psx > 16384) { psx = 16384; } if (psy > 16384) { psy = 16384; } // don't resize to 240 for text mode, since when the mode switches // back to graphics, the window will shrink to 1/2 size requisition->width = (psx / 256 /*GTK_x_size*/) * 256 /*GTK_x_size*/; if (requisition->width < 256 /*GTK_x_size*/) requisition->width = 256 /*GTK_x_size*/; requisition->height = (psy / GTK_y_size) * GTK_y_size; if (requisition->height < GTK_y_size) requisition->height = GTK_y_size; } #if 0 && defined(UNDER_WIN32) extern HWND hWndWindow; extern LRESULT CALLBACK WindowWndProc( HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam ); void gtk_window_paint(RECT *updaterect); #endif gboolean on_v9t9_draw_area_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { gint x,y,sx,sy; int xoffs; xoffs = (256 - GTK_x_size) * GTK_x_mult / 2; x = (event->area.x - xoffs); y = (event->area.y); sx = (event->area.width); sy = (event->area.height); // we can get expose events for stuff outside window if (x < 0) { sx += x; x = 0; } if (x >= GTK_x_pixels) return FALSE; if (y < 0) { sy += y; y = 0; } if (y >= GTK_y_pixels) return FALSE; if (sx + x > GTK_x_pixels) sx = GTK_x_pixels - x; if (sy + y > GTK_y_pixels) sy = GTK_y_pixels - y; sx = (sx + (x % GTK_x_mult) + GTK_x_mult - 1) / GTK_x_mult; sy = (sy + (y % GTK_y_mult) + GTK_y_mult - 1) / GTK_y_mult; x /= GTK_x_mult; y /= GTK_y_mult; logger(_L|L_2, "for expose %d,%d, dirtying (%d,%d) to (%d,%d)\n", GTK_x_mult, GTK_y_mult, x,y,x+sx,y+sy); #if 0 && defined(UNDER_WIN32) { RECT updaterect; #define AREA(x) event->area.x updaterect.left = AREA(x); updaterect.right = AREA(x) + AREA(width); updaterect.top = AREA(y); updaterect.bottom = AREA(y) + AREA(height); vdp_dirty_screen(x, y, sx, sy); //gtk_window_paint(&updaterect); //ValidateRect(hWndWindow, NULL); return TRUE; } #else GTK_clear_sides(256, GTK_x_size); vdp_dirty_screen(x, y, sx, sy); #endif return TRUE; } gboolean on_v9t9_draw_area_draw (GtkWidget *widget, GdkRectangle *area, gpointer user_data) { return FALSE; } /* * bring up command dialog on right click */ gboolean on_v9t9_drawing_area_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { // bring up v9t9 window if (event->button == 1) { gdk_window_raise(v9t9_window->window); } // raise command dialog to center on cursor else if (event->button > 1) { gdk_window_raise(command_center->window); gtk_widget_activate(command_center); gtk_widget_set_uposition(command_center, event->x_root - command_center->allocation.width / 2, event->y_root - command_center->allocation.height / 2); } return TRUE; } gboolean on_v9t9_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { GTK_keyboard_set_key(event->keyval, 1); return TRUE; } gboolean on_v9t9_key_release_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { GTK_keyboard_set_key(event->keyval, 0); return TRUE; } /* gboolean on_v9t9_draw_area_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) { g_print("focused out!\n"); // gtk_window_set_focus(widget->parent->parent, widget); return TRUE; } */ #define GTK_RESTORE_FOCUS \ gtk_widget_grab_focus(v9t9_window);\ gtk_window_set_focus(GTK_WINDOW(v9t9_window), v9t9_drawing_area) gboolean on_v9t9_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { // g_print("v9t9_window_enter\n"); GTK_RESTORE_FOCUS; return FALSE; } gboolean on_v9t9_draw_area_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { // g_print("v9t9_drawing_area_enter\n"); GTK_RESTORE_FOCUS; return FALSE; } #if 0 #pragma mark - #endif /* * This is a callback for a generic button that has a fixed * command string in user_data. */ void on_v9t9_button_clicked (GtkButton *button, gpointer user_data) { GTK_send_command((const gchar *)user_data); } /* * This is for a generic cancel button which will unpause the * computer. */ void on_v9t9_button_cancel (GtkButton *button, gpointer user_data) { if (!debugger_enabled()) execution_pause(false); gtk_widget_destroy(GTK_WIDGET(user_data)); } void on_v9t9_pause_button_clicked (GtkButton *button, gpointer user_data) { v9t9_window_pause_button = button; execution_pause(!execution_paused()); } void on_quit_button_clicked (GtkButton *button, gpointer user_data) { GtkWidget *dialog = create_quit_dialog(); gtk_widget_show(dialog); if (!debugger_enabled()) execution_pause(true); } gboolean on_v9t9_window_configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { // gtk_window_set_focus(GTK_WINDOW(widget), v9t9_drawing_area); return FALSE; } /***********************************/ #if 0 #pragma mark - #endif typedef struct { GList *lines; int index; } History; static GtkWidget *command_text_entry; static History *command_text_history; static History *history_get(History **where) { if (!*where) { *where = (History *)g_malloc(sizeof(History)); (*where)->lines = g_list_alloc(); (*where)->index = 0; } return *where; } static void history_append(History *history, gpointer data) { g_list_append(history->lines, data); history->index = g_list_length(history->lines); } static void history_update(History *history, gpointer data) { if (history->index == g_list_length(history->lines)) { } } static void history_remove(History *history) { int length = g_list_length(history->lines); if (length) { g_list_free(g_list_last(history->lines)); history->index = MIN(history->index, length); } } static gpointer *history_prev(History *history) { if (history->index > 0) { history->index--; } return g_list_nth_data(history->lines, history->index); } static gpointer *history_next(History *history) { if (history->index + 1 < g_list_length(history->lines)) { history->index++; } return g_list_nth_data(history->lines, history->index); } /* * Someone has entered text in the window. * Need to turn on interactive mode temporarily, or * make the entry insensitive. * * user_data is the text box */ void on_command_text_entry_activate (GtkEditable *editable, gpointer user_data) { History *history = history_get(&command_text_history); // get line of text gchar *text = gtk_editable_get_chars(editable, 0, -1); // execute text GTK_send_command(text); // append it history_append(history, text); // g_free(text); // select text so it can be cleared gtk_editable_select_region(editable, 0, -1); } gboolean on_command_text_entry_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { gchar *text; History *history = history_get(&command_text_history); gint pos; GtkEditable *editable = GTK_EDITABLE(widget); // handle up and down arrow for history switch (event->keyval) { case GDK_Up: case GDK_Page_Up: text = gtk_editable_get_chars(editable, 0, -1); history_update(history, text); text = (gchar *)history_prev(history); if (text) { gtk_editable_delete_text(editable, 0, -1); pos = 0; gtk_editable_insert_text(editable, text, strlen(text), &pos); } else { // history_remove(history); } break; case GDK_Down: case GDK_Page_Down: text = gtk_editable_get_chars(editable, 0, -1); history_update(history, text); text = (gchar *)history_next(history); if (text) { gtk_editable_delete_text(editable, 0, -1); pos = 0; gtk_editable_insert_text(editable, text, strlen(text), &pos); } else { // history_remove(history); } break; // notice these keys case GDK_End: case GDK_Left: if (editable->has_selection) { text = gtk_editable_get_chars(editable, 0, -1); gtk_editable_select_region(editable, 0, 0); gtk_editable_set_position(editable, strlen(text)); g_free(text); } break; case GDK_Home: case GDK_Right: if (editable->has_selection) { gtk_editable_select_region(editable, 0, 0); gtk_editable_set_position(editable, 0); } break; default: return TRUE; } return TRUE; } void on_log_text_box_realize_event (GtkWidget *widget, gpointer user_data) { v9t9_command_log = widget; } /* * Flush text in command log */ void on_flush_item_activate (GtkMenuItem *menuitem, gpointer user_data) { GTK_flush_log(); } #if 0 #pragma mark - #endif /* * Select text font */ static GtkWidget *font_selector; static gchar *last_font_selected; void on_font_item_activate (GtkMenuItem *menuitem, gpointer user_data) { if (!VALID_WINDOW(font_selector)) { font_selector = create_command_log_font_selector(); } else { gtk_widget_hide(font_selector); } if (last_font_selected) { gtk_font_selection_dialog_set_font_name( GTK_FONT_SELECTION_DIALOG(font_selector), last_font_selected); } gtk_widget_show(font_selector); } void on_command_log_font_selector_ok_button1_clicked (GtkButton *button, gpointer user_data) { char *fontname; fontname = gtk_font_selection_dialog_get_font_name( GTK_FONT_SELECTION_DIALOG(font_selector)); GTK_change_log_font(fontname); if (last_font_selected) g_free(last_font_selected); last_font_selected = fontname; gtk_widget_hide(font_selector); } void on_command_log_font_selector_apply_button1_clicked (GtkButton *button, gpointer user_data) { gchar *fontname; fontname = gtk_font_selection_dialog_get_font_name( GTK_FONT_SELECTION_DIALOG(font_selector)); GTK_change_log_font(fontname); g_free(fontname); } void on_command_log_font_cancel1_button_clicked (GtkButton *button, gpointer user_data) { GTK_change_log_font(last_font_selected); gtk_widget_hide(font_selector); } gboolean on_command_text_entry_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { return FALSE; } gboolean on_command_dialog_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { /* if (event->keyval == GDK_Up || event->keyval == GDK_Down) { gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); gtk_signal_emit_by_name(GTK_OBJECT(user_data), "key_press_event", event); } */ return FALSE; } void on_command_dialog_destroy (GtkObject *object, gpointer user_data) { gtk_main_quit(); v9t9_sigterm(1); } /***********************************************************************/ #if 0 #pragma mark - #endif /* * Module selection dialog */ static GtkWidget *module_dialog; static GtkToggleButton *module_reset_toggle; /* These must correspond with columns in dialog */ enum { mc_text_name, mc_tag_name, mc_setup_commands }; static void module_clist_prefix_clear(GtkWidget *widget); void on_v9t9_window_module_button_clicked (GtkButton *button, gpointer user_data) { GtkWidget *clist; if (!VALID_WINDOW(module_dialog)) { module_dialog = create_modules_dialog(); module_reset_toggle = 0L; } else { gtk_widget_hide(module_dialog); } clist = gtk_object_get_data((GtkObject *)module_dialog, "module_clist"); if (clist) module_clist_prefix_clear(clist); gtk_widget_show(module_dialog); } void on_module_clist_load_button_clicked (GtkButton *button, gpointer user_data) { GtkCList *clist; GList *list; g_return_if_fail(GTK_IS_CLIST(clist = user_data)); // Step through list of selected modules // and load them up list = clist->selection; while (list) { gint row = (gint)(list->data); ModuleEntry *ent = (ModuleEntry *)gtk_clist_get_row_data(clist, row); if (ent) module_load(ent); list = list->next; } if (clist->selection && (!module_reset_toggle || gtk_toggle_button_get_active(module_reset_toggle))) { GTK_send_command("ResetComputer\n"); } // Unselect items gtk_clist_unselect_all(clist); GTK_RESTORE_FOCUS; } void on_module_clist_close_button_clicked (GtkButton *button, gpointer user_data) { GtkCList *clist; g_return_if_fail(GTK_IS_CLIST(clist = user_data)); // Unselect items gtk_clist_unselect_all(clist); gtk_widget_hide(module_dialog); // module_reset_toggle = 0L; // module_dialog = 0L; GTK_RESTORE_FOCUS; } #define ALT_KEY(x) \ ((x) == GDK_Meta_L ||\ (x) == GDK_Meta_R ||\ (x) == GDK_Alt_L ||\ (x) == GDK_Alt_R) /* * Don't intercept ALT-key shortcuts */ gboolean on_clist_key_release_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { if (ALT_KEY(event->keyval)) { gtk_object_set_data(GTK_OBJECT(widget), "alt_down", (gpointer)0); } return FALSE; } /* * Key was pressed in (module) clist. * * Create a prefix string from the keys pressed and find * a suitable match in the given column in (int)user_data. */ gboolean on_clist_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { GtkCList *clist; gchar *old; char *prefix_name; gchar *prefix; int row; int col = (int)user_data; GList *list; int current; gboolean matched; g_return_val_if_fail(GTK_IS_CLIST(widget), false); clist = GTK_CLIST(widget); prefix_name = widget_tag("prefix_string_", col, 1); old = gtk_object_get_data(GTK_OBJECT(widget), prefix_name); /* * Don't intercept ALT keys */ if (ALT_KEY(event->keyval)) { gtk_object_set_data(GTK_OBJECT(widget), "alt_down", (gpointer)1); return false; } if ((int)gtk_object_get_data(GTK_OBJECT(widget), "alt_down")) { return false; } /* * Ignore accelerator keys */ if (event->keyval == GDK_Escape) { return false; } /* * Start off with some old prefix value to compare against */ if (!old) old = g_strdup(""); /* * Don't append non-printable characters, which we assume * are control characters intended to clear the prefix. */ if (event->string && *event->string && isprint(*event->string)) { prefix = g_strconcat(old, event->string, 0L); } else { gtk_clist_unselect_all(clist); prefix = g_strdup(""); } /* find current selection */ list = clist->selection; /* find item with this prefix */ current = (list ? (gint)list->data : -1); matched = false; // g_print("prefix='%s', current=%d\n", prefix, current); if (*prefix) for (row = 0; row < clist->rows; row++) { gchar *text; if (gtk_clist_get_text(clist, row, col, &text) && strncasecmp(text, prefix, strlen(prefix)) == 0) { current = row; matched = true; break; } } // g_print("old='%s', event='%s'\n", old, event->string); /* if we couldn't find one with new prefix, and this new key is a suffix of the last prefix, look for another one matching... */ if (!matched && event->string && *event->string && strcasecmp(old + strlen(old) - strlen(event->string), event->string) == 0) { if (list) { current = (gint)list->data; if (current < 0 || current >= clist->rows) current = 0; } else current = 0; // g_print("current=%d, list->data=%d\n", current, list->data); g_free(prefix); prefix = g_strdup(old); for (row = current + 1; row != current; row = (row + 1 >= clist->rows ? 0 : row + 1)) { gchar *text; if (gtk_clist_get_text(clist, row, col, &text) && strncasecmp(text, prefix, strlen(prefix)) == 0) { current = row; matched = true; break; } } } gtk_object_set_data(GTK_OBJECT(widget), prefix_name, prefix); if (matched && current != -1) { gtk_clist_undo_selection(clist); clist->focus_row = current; gtk_clist_select_row(clist, current, 0 /*col*/); gtk_clist_moveto(clist, current, 0 /*col*/, 0.5, 0.5); } else if (!matched) { gtk_clist_undo_selection(clist); } g_free(old); return TRUE; } static void module_clist_prefix_clear(GtkWidget *widget) { gchar *prefix; int i; for (i=0; i < 2; i++) { char *name = widget_tag("prefix_string_", i, 1); prefix = (gchar *)gtk_object_get_data(GTK_OBJECT(widget), name); if (prefix) g_free(prefix); gtk_object_set_data(GTK_OBJECT(widget), name, 0L); } } gboolean on_module_clist_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { if ((event->type == GDK_KEY_PRESS && event->key.keyval == GDK_Return) || event->type == GDK_2BUTTON_PRESS) { on_module_clist_load_button_clicked(NULL, user_data); gtk_widget_hide(module_dialog); GTK_RESTORE_FOCUS; } return FALSE; } /* Create clist from module database */ void on_module_clist_realize (GtkWidget *widget, gpointer user_data) { ModuleEntry *ent; GtkCList *clist = GTK_CLIST(widget); int old_selection; old_selection = (clist->selection ? (gint)clist->selection->data : 0); // Clear clist gtk_clist_clear(clist); // Freeze display gtk_clist_freeze(clist); // Add an entry for each item ent = moddb; while (ent) { gchar *items[3]; gint row; items[0] = ent->name; items[1] = ent->tag; items[2] = ent->commands; // add row row = gtk_clist_append(clist, items); // associate row with ModuleEntry gtk_clist_set_row_data(clist, row, ent); ent = ent->next; } // Unfreeze gtk_clist_thaw(clist); // Reselect old selection gtk_clist_select_row(clist, old_selection, 0 /*col*/); gtk_clist_moveto(clist, old_selection, 0 /*col*/, 0.5, 0.5); gtk_clist_set_column_max_width(clist, mc_tag_name, 50); } void on_module_clist_click_column (GtkCList *clist, gint column, gpointer user_data) { gboolean swap = (clist->sort_column == column); GtkSortType sort = swap ? (clist->sort_type == GTK_SORT_ASCENDING ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING) : GTK_SORT_ASCENDING; gtk_clist_set_sort_column(clist, column); gtk_clist_set_sort_type(clist, sort); gtk_clist_sort(clist); module_clist_prefix_clear(GTK_WIDGET(clist)); } /* * Toggled "show setup commands" button */ void on_show_commands_cb_toggled (GtkToggleButton *togglebutton, gpointer user_data) { GtkCList *clist; g_return_if_fail(GTK_IS_CLIST(clist = user_data)); gtk_clist_set_column_visibility(clist, mc_setup_commands, gtk_toggle_button_get_active(togglebutton)); gtk_clist_set_column_max_width(clist, mc_tag_name, 50); } /* * Toggled "reset computer after load" button */ void on_reset_computer_cb_toggled (GtkToggleButton *togglebutton, gpointer user_data) { module_reset_toggle = togglebutton; } void on_modules_refresh_button_clicked (GtkButton *button, gpointer user_data) { g_return_if_fail(GTK_IS_CLIST(user_data)); GTK_send_command("InitModuleDatabase\n" "LoadConfigFile \"modules.inf\"\n"); module_clist_prefix_clear(GTK_WIDGET(user_data)); on_module_clist_realize(GTK_WIDGET(user_data), 0L); } void on_unload_current_button_clicked (GtkButton *button, gpointer user_data) { GTK_send_command("UnloadModuleOnly\n"); } /******************************************************************/ #if 0 #pragma mark - #endif /* * Disk selection dialog */ static GtkWidget *disk_dialog; static GtkTable *disk_dialog_table; enum { ddt_disk_name, ddt_combo_history, ddt_choose_button }; void on_v9t9_window_disks_button_clicked (GtkButton *button, gpointer user_data) { if (!VALID_WINDOW(disk_dialog)) { disk_dialog = create_disks_dialog(); } else { gtk_widget_hide(disk_dialog); } gtk_widget_show(disk_dialog); } /* * Clicked 'apply' button on dialog */ void on_disk_dialog_apply_button_clicked (GtkButton *button, gpointer user_data) { GTK_RESTORE_FOCUS; } /* * Clicked 'close' button on dialog */ void on_disk_dialog_close_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide(disk_dialog); // disk_dialog = 0L; // disk_dialog_table = 0L; GTK_RESTORE_FOCUS; } /* * Setup disk table. Format is: * column 0: label DSKx * column 1: combo box, history of names used [not implemented] * column 2: 'choose' button, which triggers on_disk_choose_button_clicked(row) */ /* * Icky! No accessor functions. */ static GtkWidget *table_get_widget(GtkTable *table, gint row, gint column) { GList *list; for (list = table->children; list; list = list->next) { GtkTableChild *child; child = (GtkTableChild *)list->data; if (child->top_attach == row && child->left_attach == column) return child->widget; } return 0L; } void on_disk_info_table_realize (GtkWidget *widget, gpointer user_data) { gint row; GtkTable *table; GtkWidget *kid; g_return_if_fail(GTK_IS_TABLE(table = GTK_TABLE(widget))); disk_dialog_table = table; for (row = 0; row < dsr_get_disk_count(); row++) { GtkWidget *label, *combo, *choose; const char *path; label = table_get_widget(table, row, ddt_disk_name); combo = table_get_widget(table, row, ddt_combo_history); choose = table_get_widget(table, row, ddt_choose_button); // enable widgets for disks we can use gtk_widget_set_sensitive(label, TRUE); gtk_widget_set_sensitive(combo, TRUE); gtk_widget_set_sensitive(choose, TRUE); path = dsr_get_disk_info(row + 1); // gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), path ? path : ""); gtk_entry_set_text(GTK_ENTRY(combo), path ? path : ""); } // Disable inaccessible kids for (; row < 5; row++) { int col; for (col = 0; col < 3; col++) { kid = table_get_widget(table, row, col); gtk_widget_set_sensitive(kid, FALSE); } } } /* * Canonicalize a path to either a directory or a filename */ static gchar *disk_file_canonicalize(gchar **searchpath, gchar *syssearchpath, gboolean dir, const char *path, OSSpec *spec, gboolean add_dir) { char *fptr; gchar *copy; fptr = (char *)OS_GetFileNamePtr(path); if (dir) { // don't accept a file as a directory if (OS_MakeFileSpec(path, spec) == OS_NOERR && OS_Status(spec) == OS_NOERR) { *fptr = 0; } if (OS_MakeSpec(path, spec, NULL) == OS_NOERR) { copy = g_strdup(OS_PathSpecToString1(&spec->path)); } else { copy = g_strdup(path); } } else { // find file in the path, or add it. if (!findbinary(*searchpath, syssearchpath, fptr, spec)) { if (add_dir && *fptr) { char *list = (char *)xmalloc((*searchpath ? strlen(*searchpath) : 0) + (fptr - path) + 1 + 1); sprintf(list, "%s%c%.*s", *searchpath ? *searchpath : "", OS_ENVSEP, fptr - path, path); xfree(*searchpath); *searchpath = list; } copy = g_strdup(fptr); } else { copy = g_strdup(OS_NameSpecToString1(&spec->name)); } } return copy; } #if 0 // um, this combo crap really doesn't make sense... /* * Text in combo box changed for disk in user_data (1..x) */ void on_disk_combo_entry_activate (GtkEditable *editable, gpointer user_data) { char msg[256]; GtkCombo *combo; gint disk; gchar *path; gchar *canon; g_return_if_fail(GTK_IS_COMBO(combo = GTK_COMBO(GTK_WIDGET(editable)->parent))); disk = (gint)user_data; path = gtk_editable_get_chars(editable, 0, -1); snprintf(msg, sizeof(msg), "Changing DSK%d to '%s'\n", disk, path); GTK_append_log(msg, NULL, NULL); // if not an error, add to history if (dsr_set_disk_info(disk, path) && (canon = dsr_get_disk_info(disk))) { GtkList *strings = GTK_LIST(combo->list); GList *items; GtkWidget *item; gint pos; gtk_editable_delete_text(editable, 0, -1); pos = 0; gtk_editable_insert_text(editable, canon, strlen(canon), &pos); items = g_list_alloc(); g_list_append(items, (gpointer)editable); gtk_list_prepend_items(strings, items); // ??? // gtk_combo_set_popdown_strings(combo, strings); // combo->list = strings; } g_free(path); } #endif /* * Text in combo box changed for disk in user_data (1..x) */ void on_disk_combo_entry_activate (GtkEditable *editable, gpointer user_data) { char msg[256]; gint disk; char *path; gchar *copy; OSSpec spec; disk = (gint)user_data; path = gtk_editable_get_chars(editable, 0, -1); copy = disk_file_canonicalize(&diskimagepath, 0L, dsr_is_emu_disk(disk), path, &spec, true /*add_dir*/); snprintf(msg, sizeof(msg), "Changing DSK%d to '%s'\n", disk, copy); GTK_append_log(msg, NULL, NULL); dsr_set_disk_info(disk, copy); g_free(path); g_free(copy); } static GtkWidget* create_disk_file_selection (gchar *title) { GtkWidget *disk_file_selection; GtkWidget *ok_button2; GtkWidget *cancel_button2; disk_file_selection = v99_file_selection_new (title); // gtk_object_set_data (GTK_OBJECT (disk_file_selection), "disk_file_selection", disk_file_selection); gtk_container_set_border_width (GTK_CONTAINER (disk_file_selection), 10); ok_button2 = V99_FILE_SELECTION (disk_file_selection)->ok_button; gtk_object_set_data (GTK_OBJECT (disk_file_selection), "ok_button2", ok_button2); gtk_widget_show (ok_button2); GTK_WIDGET_SET_FLAGS (ok_button2, GTK_CAN_DEFAULT); cancel_button2 = V99_FILE_SELECTION (disk_file_selection)->cancel_button; gtk_object_set_data (GTK_OBJECT (disk_file_selection), "cancel_button2", cancel_button2); gtk_widget_show (cancel_button2); GTK_WIDGET_SET_FLAGS (cancel_button2, GTK_CAN_DEFAULT); return disk_file_selection; } #if 0 #pragma mark - #endif /* * Choose a disk or directory for the disk in user_data (1..x) */ V99FileSelection *disk_file_dialog; // V99FileDialog static void GTK_info_logger(u32 srcflags, const char *format, ...) { va_list va; if (srcflags & (LOG_ERROR|LOG_WARN)) return; if (srcflags & LOG_VERBOSE_MASK) return; va_start(va, format); vlogger(srcflags, format, va); va_end(va); } /* * Given a filename, append a row to the clist with info * about the V9t9 file (if it is one) */ static const char * emu_disk_clist_titles[] = { "Name", "Size", "Type", "P", "Host filename" }; #if __MWERKS__ // Support for the runtime initialization of local arrays #pragma gcc_extensions on #endif static int on_v99_file_selection_file_append(V99FileSelection *filesel, GtkCList *clist, const gchar *path, const gchar *filename) { char tiname[11]; char size[8]; char type[12]; char protect[2]; gchar *cols[6] = { tiname, size, type, protect, (gchar *)filename, NULL }; int charwidth = gdk_string_width(filesel->file_list->style->font, "M"); int widths[5]= { charwidth*10, charwidth*3, charwidth*10, charwidth*1, charwidth*16 }; int col; fiad_tifile tf; OSSpec spec; fiad_logger_func old; /* Try to make a tifile from the entry */ if (OS_MakeSpec2(path, filename, &spec) != OS_NOERR) { /* oops, not even a good file (maybe broken softlink) */ return 0; } /* Don't log errors found in likely-non-V9t9 files, but log renames */ old = fiad_set_logger(GTK_info_logger); if (fiad_tifile_setup_spec_with_spec(&tf, &spec) == OS_NOERR && fiad_tifile_get_info(&tf)) { /* it might have just been renamed */ cols[4] = OS_NameSpecToString1(&tf.spec.name); memcpy(tiname, tf.fdr.filenam, 10); tiname[10] = 0; sprintf(size, "%d", tf.fdr.secsused + 1); strcpy(type, fiad_catalog_get_file_type_string(&tf.fdr)); protect[0] = (tf.fdr.flags & ff_protected) ? 'Y' : ' '; protect[1] = 0; } else /* not a V9t9 file */ { *tiname = 0; *size = 0; *protect = 0; *type = 0; } /* figure widths for each column */ for (col = 0; col < 5; col++) { int width = gdk_string_width(filesel->file_list->style->font, cols[col]); if (width > widths[col]) { widths[col] = width; } gtk_clist_set_column_width(clist, col, widths[col]); } return gtk_clist_append(clist, cols); } #if __MWERKS__ #pragma gcc_extensions reset #endif static void on_v99_file_selection_file_click_column(GtkCList *clist, gint column, gpointer user_data) { gboolean swap = (clist->sort_column == column); GtkSortType sort = swap ? (clist->sort_type == GTK_SORT_ASCENDING ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING) : GTK_SORT_ASCENDING; gtk_clist_set_sort_column(clist, column); gtk_clist_set_sort_type(clist, sort); gtk_clist_sort(clist); } /* * user_data is the disk number */ void on_disk_file_ok_button_clicked (GtkButton *button, gpointer user_data) { gint disk = (gint)user_data; gboolean dir = dsr_is_emu_disk(disk); const char *path; gchar *copy; OSSpec spec; g_return_if_fail(disk >= 1 && disk <= 5); path = v99_file_selection_get_filename(disk_file_dialog); copy = disk_file_canonicalize(&diskimagepath, 0L, dir, path, &spec, true /*add_dir*/); if (dsr_set_disk_info(disk, copy)) { GtkWidget *entry = table_get_widget(disk_dialog_table, disk-1, ddt_combo_history); gtk_entry_set_text(GTK_ENTRY(entry), copy); gtk_widget_hide((GtkWidget *)disk_file_dialog); // disk_file_dialog = 0L; GTK_RESTORE_FOCUS; } g_free(copy); //g_free(path); } void on_disk_file_cancel_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide((GtkWidget *)disk_file_dialog); GTK_RESTORE_FOCUS; } /* * Main disk/file chooser dialog. * */ void on_disk_choose_button_clicked (GtkButton *button, gpointer user_data) { gint disk = (gint)user_data; g_return_if_fail(disk >= 1 && disk <= 5); if (!VALID_WINDOW(disk_file_dialog)) { disk_file_dialog = V99_FILE_SELECTION(create_disk_file_selection("Select Path")); if (dsr_is_real_disk(disk)) { // normal file selection v99_file_selection_set_file_list_active(disk_file_dialog, TRUE); } else { // v9t9 directory selection v99_file_selection_set_file_list_columns(disk_file_dialog, 5, (gchar **)emu_disk_clist_titles, on_v99_file_selection_file_append, NULL); gtk_signal_connect(GTK_OBJECT(disk_file_dialog->file_list), "click_column", on_v99_file_selection_file_click_column, NULL); // no, we can't select files as directories v99_file_selection_set_file_list_active(disk_file_dialog, FALSE); disk_file_dialog->user_data = (gpointer)(disk - 1); } } gtk_widget_show(GTK_WIDGET(disk_file_dialog)); if (dsr_is_real_disk(disk)) { // OSError err; OSSpec spec; const char *filename; gchar *copy; // Set the full path if we can filename = dsr_get_disk_info(disk); copy = disk_file_canonicalize(&diskimagepath, 0L, false /*directory*/, filename, &spec, false /*add_dir*/); v99_file_selection_set_filename(disk_file_dialog, OS_SpecToString1(&spec)); v99_file_selection_complete(disk_file_dialog, "*.dsk"); g_free(copy); } else { // it's already a full path char path[OS_PATHSIZE]; strcpy(path, dsr_get_disk_info(disk)); #if !defined(UNDER_MACOS) // force a directory selection so ppl don't think they can // type a filename strcat(path, "."); #endif v99_file_selection_set_filename(disk_file_dialog, path); } // wire up buttons here (so we can pass known disk number) gtk_signal_connect(GTK_OBJECT(disk_file_dialog->ok_button), "clicked", GTK_SIGNAL_FUNC(on_disk_file_ok_button_clicked), (gpointer)disk); gtk_signal_connect(GTK_OBJECT(disk_file_dialog->cancel_button), "clicked", GTK_SIGNAL_FUNC(on_disk_file_cancel_button_clicked), (gpointer)disk); } /* * Toggle use of realdisk DSR */ void on_real_disk_cb_toggled (GtkToggleButton *togglebutton, gpointer user_data) { char cmd[64]; sprintf(cmd, "ToggleV9t9 dsrRealDisk %s", gtk_toggle_button_get_active(togglebutton) ? "on" : "off"); GTK_send_command(cmd); gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize"); } void on_real_disk_cb_realize (GtkWidget *widget, gpointer user_data) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), !!(realDiskDSR.runtimeflags & vmRTInUse)); gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize"); } /* * Toggle use of emulated disk DSR */ void on_emu_disk_cb_toggled (GtkToggleButton *togglebutton, gpointer user_data) { char cmd[64]; sprintf(cmd, "ToggleV9t9 dsrEmuDisk %s", gtk_toggle_button_get_active(togglebutton) ? "on" : "off"); GTK_send_command(cmd); gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize"); } void on_emu_disk_cb_realize (GtkWidget *widget, gpointer user_data) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), !!(emuDiskDSR.runtimeflags & vmRTInUse)); gtk_signal_emit_by_name(GTK_OBJECT(user_data), "realize"); } #if 0 #pragma mark - #endif static GtkWidget *debugger_window; GtkWidget *debugger_registers_table, *debugger_instruction_box, *debugger_status_bar, *debugger_pc_entry, *debugger_wp_entry, *debugger_st_entry; // flag indicating we want to display all the time-wasting // updates (turned on/off during intermittent mode, etc) static bool debugger_verbose_updates; #define DBG_COLOR_NORMAL(s) (&(s)->fg[0]) #define DBG_COLOR_VIEW(s) (&(s)->fg[0]) #define DBG_COLOR_READ(s) (&(s)->mid[0]) #define DBG_COLOR_WRITTEN(s) (&(s)->dark[0]) static GdkColor * debugger_status_color_fg(status_item item, GtkStyle *style) { switch (item) { case STATUS_CPU_PC: return DBG_COLOR_NORMAL(style); case STATUS_CPU_STATUS: return DBG_COLOR_NORMAL(style); case STATUS_CPU_WP: return DBG_COLOR_NORMAL(style); case STATUS_CPU_REGISTER_VIEW: return DBG_COLOR_VIEW(style); case STATUS_CPU_REGISTER_READ: return DBG_COLOR_READ(style); case STATUS_CPU_REGISTER_WRITE: return DBG_COLOR_WRITTEN(style); case STATUS_CPU_INSTRUCTION: return DBG_COLOR_NORMAL(style); case STATUS_CPU_INSTRUCTION_LAST: return DBG_COLOR_WRITTEN(style); case STATUS_MEMORY_VIEW: return DBG_COLOR_VIEW(style); case STATUS_MEMORY_READ: return DBG_COLOR_READ(style); case STATUS_MEMORY_WRITE: return DBG_COLOR_WRITTEN(style); } return DBG_COLOR_NORMAL(style); } static GdkColor* debugger_status_color_bg(status_item item, GtkStyle *style) { // return &style->bg[0]; return 0L; } /* * Set up registers table for the first time */ static void setup_debugger_registers_table(void) { int reg; GtkWidget *w; GtkTable *t; GtkStyle *s; int width, height; g_return_if_fail(debugger_registers_table); t = GTK_TABLE(debugger_registers_table); s = gtk_widget_get_style(debugger_registers_table); // setup base size of text box width = gdk_string_width(s->font, "_>FFFF_"); height = gdk_string_height(s->font, "!")*2; // gtk_style_unref(s); // fix the items below the register table here... gtk_widget_set_usize(debugger_pc_entry, width, height); gtk_widget_set_usize(debugger_wp_entry, width, height); gtk_widget_set_usize(debugger_st_entry, width, height); // resize gtk_table_resize(t, 16 /*rows*/, 2 /*columns*/); // set up each register row for (reg = 0; reg < 16; reg++) { // assign label... char tmp[32]; sprintf(tmp, "R%d", reg); w = gtk_label_new(tmp); gtk_widget_ref(w); gtk_object_set_data_full(GTK_OBJECT(debugger_window), widget_tag("register_label_", reg, 1), w, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show(w); gtk_table_attach(t, w, 0, 1, reg, reg+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 2, 0); // assign text entry to register w = gtk_text_new (NULL, NULL); gtk_widget_ref(w); gtk_text_set_editable (GTK_TEXT(w), false); // force size gtk_widget_set_usize(w, width, height); gtk_object_set_data_full(GTK_OBJECT(debugger_window), widget_tag("reg_value_", reg, 1), w, (GtkDestroyNotify) gtk_widget_unref); gtk_table_attach(t, w, 1, 2, reg, reg+1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 2, 0); gtk_widget_show(w); } } static void update_debugger_register(status_item item, int reg, int val) { GtkTable *t = GTK_TABLE(debugger_registers_table); GtkText *tb; GtkWidget *w; GtkStyle *style; char buffer[8]; // get value widget w = table_get_widget(t, reg, 1); if (!VALID_WINDOW(w)) return; // get style style = gtk_widget_get_style(w); // freeze entry tb = GTK_TEXT(w); gtk_text_freeze(tb); // remove old text gtk_editable_delete_text(GTK_EDITABLE(tb), 0, -1); // insert new text sprintf(buffer, ">%04X", val); gtk_text_insert(tb, style->font, debugger_status_color_fg(item, style), debugger_status_color_bg(item, style), buffer, 5); // update gtk_text_thaw(tb); } /* * Setup memory windows for the first time. * * Each entry in the vbox contains a frame with a scrolled window inside. */ #define MEMORY_BYTES_PER_ROW 16 static char *memory_frame_names[MEMORY_VIEW_COUNT] = { "cpu_1_memory_frame", "cpu_2_memory_frame", "video_memory_frame", "graphics_memory_frame", "speech_memory_frame" }; static char *memory_view_names[MEMORY_VIEW_COUNT] = { "cpu_view_1", "cpu_view_2", "video_view", "graphics_view", "speech_view" }; static void on_debugger_memory_window_size_request_event (GtkWidget *widget, GtkRequisition *requisition, gpointer user_data) { GtkWidget *tb; GtkStyle *s; int width, height; tb = widget; s = gtk_widget_get_style(tb); height = gdk_string_height(s->font, "!\n") * 3 / 2; width = gdk_string_width(s->font, "F"); if (requisition->width < width) { requisition->width = width; gtk_widget_set_usize(widget, width, -2); } if (requisition->height < height) { requisition->height = height; gtk_widget_set_usize(widget, -2, height); } // requisition->width = 80; // requisition->height = 80; // g_print("requesting %d x %d\n", requisition->width, requisition->height); } static gboolean on_debugger_memory_window_size_allocate_event (GtkWidget *widget, GtkAllocation *allocation, gpointer user_data) { GtkWidget *tb; GtkStyle *s; int width, height, which; tb = widget; // g_print("allocated %d x %d\n", allocation->width, allocation->height); s = gtk_widget_get_style(tb); height = allocation->height / (gdk_string_height(s->font, "!\n") * 3 / 2); width = debugger_hex_dump_chars_to_bytes(allocation->width / (gdk_string_width(s->font, "F")) - 1); width &= ~1; // display whole words // in case the window was sized really small... if (height <= 0) height = 1; if (width <= 0) width = 1; // gtk_style_unref(s); gtk_object_set_data(GTK_OBJECT(widget), "view_width", (gpointer)width); gtk_object_set_data(GTK_OBJECT(widget), "view_height", (gpointer)height); which = (int)gtk_object_get_data(GTK_OBJECT(widget), "which"); debugger_memory_view_size[which] = width * height; return FALSE; } static void setup_debugger_memory_views(void) { // GtkWidget *win; GtkWidget *w; GtkText *tb; GtkStyle *s; int width, height; int idx; int default_tab_width; // get a feel for width of window // by trying a test line default_tab_width = 1; // setup base size of text box s = gtk_widget_get_style(debugger_window); width = gdk_string_width(s->font, "^") * 80; height = gdk_string_height(s->font, "!") * 2; // gtk_style_unref(s); idx = MEMORY_VIEW_CPU_1; while (idx < MEMORY_VIEW_COUNT) { w = gtk_object_get_data(GTK_OBJECT(debugger_window), memory_frame_names[idx]); g_return_if_fail(w); g_return_if_fail(GTK_IS_BIN(w)); w = GTK_BIN(w)->child; g_return_if_fail(GTK_IS_TEXT(w)); tb = (GtkText *)w; // add a text box to the window /* w = gtk_text_new (NULL, NULL); tb = GTK_TEXT(w); gtk_widget_ref(w);*/ gtk_text_set_editable (tb, false); // force size //gtk_widget_set_usize(w, width, height); // don't wrap lines! gtk_text_set_line_wrap(tb, false); gtk_text_set_adjustments(tb, NULL, NULL); // set tab width tb->default_tab_width = default_tab_width; gtk_object_set_data_full(GTK_OBJECT(debugger_window), memory_view_names[idx], w, (GtkDestroyNotify) gtk_widget_unref); gtk_object_set_data(GTK_OBJECT(tb), "which", (gpointer)idx); debugger_memory_view_size[idx] = MEMORY_BYTES_PER_ROW * 4; // watch for resizes so we can fill the memory view gtk_signal_connect (GTK_OBJECT (tb), "size_allocate", GTK_SIGNAL_FUNC (on_debugger_memory_window_size_allocate_event), (gpointer)tb); gtk_signal_connect (GTK_OBJECT (tb), "size_request", GTK_SIGNAL_FUNC (on_debugger_memory_window_size_request_event), (gpointer)tb); //gtk_widget_show(w); //gtk_container_add(GTK_CONTAINER(win), w); idx++; } } static void update_memory_window(status_item item, Memory *mem) { GtkText *tb; GtkWidget *w; GtkStyle *style; char buffer[256]; char *start, *end, *astart, *aend; int len; int offs; int width, height, which; // get our view w = gtk_object_get_data(GTK_OBJECT(debugger_window), memory_view_names[mem->which]); if (!VALID_WINDOW(w)) return; width = (int)gtk_object_get_data(GTK_OBJECT(w), "view_width"); height = (int)gtk_object_get_data(GTK_OBJECT(w), "view_height"); which = (int)gtk_object_get_data(GTK_OBJECT(w), "which"); // get style style = gtk_widget_get_style(w); // freeze entry tb = GTK_TEXT(w); gtk_text_freeze(tb); // remove old text gtk_editable_delete_text(GTK_EDITABLE(tb), 0, -1); offs = 0; while (offs < debugger_memory_view_size[which]) { // create new text debugger_hex_dump_line(mem, offs, width, ' ', ' ', ' ', offs + width < debugger_memory_view_size[which] ? '\n' : 0, buffer, sizeof(buffer), &start, &end, &astart, &aend); len = strlen(buffer); if (!start) { start = end = buffer + len; astart = aend = buffer + len; } // insert normal text gtk_text_insert(tb, style->font, debugger_status_color_fg(STATUS_MEMORY_VIEW, style), debugger_status_color_bg(STATUS_MEMORY_VIEW, style), buffer, start - buffer); // insert hex byte update text if (start < end) { gtk_text_insert(tb, style->font, debugger_status_color_fg(item, style), debugger_status_color_bg(item, style), start, end - start); } // insert normal text if (end < astart) { gtk_text_insert(tb, style->font, debugger_status_color_fg(STATUS_MEMORY_VIEW, style), debugger_status_color_bg(STATUS_MEMORY_VIEW, style), end, astart - end); } // insert ascii changed text if (astart < aend) { gtk_text_insert(tb, style->font, debugger_status_color_fg(item, style), debugger_status_color_bg(item, style), astart, aend - astart); } // insert normal ascii text if (aend < buffer + len) { gtk_text_insert(tb, style->font, debugger_status_color_fg(STATUS_MEMORY_VIEW, style), debugger_status_color_bg(STATUS_MEMORY_VIEW, style), aend, buffer + len - aend); } offs += width; } // update gtk_text_thaw(tb); } #define INSTRUCTION_BOX_MAX_LENGTH (256*1024) static void setup_debugger_instruction_box(void) { GtkText *tb; GtkStyle *s; int width, height; g_return_if_fail(debugger_instruction_box); tb = GTK_TEXT(debugger_instruction_box); // set tab width tb->default_tab_width = 4; // setup base size of text box s = gtk_widget_get_style(debugger_instruction_box); width = gdk_string_width(s->font, "^") * 40; height = gdk_string_height(s->font, "!") * 16; // gtk_style_unref(s); // width = 64; // height = 16; // force size gtk_widget_set_usize(debugger_instruction_box, width, height); // memset((void *)&req, 0, sizeof(req)); // req.width = width; // req.height = height; // gtk_widget_size_request(debugger_instruction_box, &req); // don't wrap lines! gtk_text_set_line_wrap(tb, false); } static void update_debugger_instruction(status_item item, bool show_verbose, Instruction *inst, char *hex, char *disasm, // may be NULL char *op1, char *op2) { char buffer[256]; GtkStyle *style; GtkText *tb; int len, point; if (!VALID_WINDOW(debugger_instruction_box)) return; // only deal with single instructions, ignore their effects if (item == STATUS_CPU_INSTRUCTION) { tb = GTK_TEXT(debugger_instruction_box); // delete old text len = gtk_text_get_length(tb); if (len > INSTRUCTION_BOX_MAX_LENGTH * 2) { gtk_text_freeze(tb); point = gtk_text_get_point(tb); gtk_text_set_point(tb, 0); gtk_text_forward_delete(tb, len - INSTRUCTION_BOX_MAX_LENGTH); gtk_text_set_point(tb, INSTRUCTION_BOX_MAX_LENGTH); gtk_text_thaw(tb); } len = sprintf(buffer, "%s %s %s\n", hex, inst->name, disasm); style = gtk_widget_get_style(debugger_instruction_box); gtk_text_insert(tb, style->font, debugger_status_color_fg(item, style), debugger_status_color_bg(item, style), buffer, len); gtk_text_set_point(tb, gtk_text_get_length(tb)); } } static void ping_debugger_instruction_box(void) { /* GtkText *tb; g_return_if_fail(GTK_IS_TEXT(debugger_instruction_box)); tb = GTK_TEXT(debugger_instruction_box); gtk_text_set_point(tb, gtk_text_get_length(tb)); if (debugger_verbose_updates) { if (tb->freeze_count) gtk_text_thaw(tb); } else { gtk_text_insert(tb, NULL, NULL, NULL, "\n", 1); if (!tb->freeze_count) gtk_text_freeze(tb); } */ } static void update_debugger_entry(GtkWidget *entry, status_item item, u16 val) { char buffer[32]; if (!VALID_WINDOW(entry)) return; sprintf(buffer, ">%04X", val); gtk_entry_set_text(GTK_ENTRY(entry), buffer); } /***************/ static int debugger_verbose_update_count; void debugger_report_status(status_item item, va_list va) { bool show_verbose = execution_paused() || debugger_verbose_updates || debugger_verbose_update_count != 0; if (!VALID_WINDOW(debugger_window)) return; switch (item) { case STATUS_DEBUG_REFRESH: if (debugger_verbose_update_count) { debugger_register_clear_view(); debugger_memory_clear_views(); debugger_instruction_clear_view(); debugger_verbose_update_count--; } break; case STATUS_CPU_PC: if (show_verbose) { update_debugger_entry(debugger_pc_entry, item, va_arg(va, int)); } break; case STATUS_CPU_STATUS: if (show_verbose) { update_debugger_entry(debugger_st_entry, item, va_arg(va, int)); } break; case STATUS_CPU_WP: if (show_verbose) { update_debugger_entry(debugger_wp_entry, item, va_arg(va, int)); } break; case STATUS_CPU_REGISTER_READ: case STATUS_CPU_REGISTER_WRITE: { if (show_verbose) { int reg, val; reg = va_arg(va, int); val = va_arg(va, int); update_debugger_register(item, reg, val); } break; } case STATUS_CPU_REGISTER_VIEW: { if (show_verbose) { int wp; u16 *regs; int reg; wp = va_arg(va, int); regs = va_arg(va, u16 *); for (reg = 0; reg < 16; reg++) { update_debugger_register(item, reg, regs[reg]); } } break; } case STATUS_CPU_INSTRUCTION: { if (show_verbose) { Instruction *inst; char *hex, *disasm, *op1, *op2; inst = va_arg(va, Instruction *); hex = va_arg(va, char *); disasm = va_arg(va, char *); op1 = va_arg(va, char *); op2 = va_arg(va, char *); update_debugger_instruction(item, show_verbose, inst, hex, disasm, op1, op2); } break; } case STATUS_CPU_INSTRUCTION_LAST: { if (show_verbose) { Instruction *inst; char *op1, *op2; inst = va_arg(va, Instruction *); op1 = va_arg(va, char *); op2 = va_arg(va, char *); update_debugger_instruction(item, show_verbose, inst, 0L, 0L, op1, op2); } break; } case STATUS_MEMORY_READ: case STATUS_MEMORY_WRITE: case STATUS_MEMORY_VIEW: if (show_verbose) { Memory *mem = va_arg(va, Memory *); update_memory_window(item, mem); } break; } } /***************/ static void debugger_run_event(void) { debugger_verbose_update_count = 2; debugger_refresh(); } static void debugger_change_verbosity(bool verbose) { static int debugger_run_tag; if (debugger_verbose_updates != verbose) { debugger_verbose_updates = verbose; ping_debugger_instruction_box(); if (!verbose) { if (!debugger_run_tag) { debugger_run_tag = TM_UniqueTag(); } TM_SetEvent(debugger_run_tag, TM_HZ*100, 0, TM_FUNC|TM_REPEAT, TM_EVENT_FUNC(debugger_run_event)); } else { if (debugger_run_tag) { TM_ResetEvent(debugger_run_tag); } } } } void on_v9t9_debug_button_clicked (GtkButton *button, gpointer user_data) { /* GtkWidget *label = GTK_BIN(button)->child; debugger_enable(!debugger_enabled()); if (debugger_enabled()) { gtk_label_set_text(GTK_LABEL(label), "Stop Tracing"); } else { gtk_label_set_text(GTK_LABEL(label), "Trace"); } */ execution_pause(true); debugger_enable(true); debugger_change_verbosity(true); } void on_debugger_close_button_clicked (GtkButton *button, gpointer user_data) { debugger_enable(false); execution_pause(false); } void on_debugger_run_button_clicked (GtkButton *button, gpointer user_data) { debugger_change_verbosity(false); ping_debugger_instruction_box(); execution_pause(false); } void on_debugger_walk_button_clicked (GtkButton *button, gpointer user_data) { debugger_change_verbosity(true); ping_debugger_instruction_box(); execution_pause(false); } void on_debugger_stop_button_clicked (GtkButton *button, gpointer user_data) { debugger_change_verbosity(true); execution_pause(true); debugger_refresh(); if (!(stateflag & ST_PAUSE)) stateflag |= ST_SINGLESTEP; ping_debugger_instruction_box(); } void on_debugger_next_button_clicked (GtkButton *button, gpointer user_data) { debugger_change_verbosity(true); // execution_pause(true); // execution_pause(false); stateflag |= ST_SINGLESTEP; ping_debugger_instruction_box(); } void GTK_system_debugger_enabled(bool enabled) { if (enabled) { if (!VALID_WINDOW(debugger_window)) { debugger_window = create_debugger_window(); gtk_widget_set_name(debugger_window, "v9t9.debugger"); debugger_registers_table = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_registers_table"); debugger_instruction_box = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_instruction_box"); debugger_status_bar = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_status_bar"); debugger_pc_entry = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_pc_entry"); debugger_wp_entry = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_wp_entry"); debugger_st_entry = gtk_object_get_data(GTK_OBJECT(debugger_window), "debugger_st_entry"); setup_debugger_registers_table(); setup_debugger_memory_views(); setup_debugger_instruction_box(); } // debugger_verbose_updates = true; // ping_debugger_instruction_box(); gtk_widget_show(debugger_window); } else { if (debugger_window) { execution_pause(false); gtk_widget_hide(debugger_window); GTK_RESTORE_FOCUS; } } } void GTK_system_execution_paused(bool paused) { if (v9t9_window_pause_button) { GtkWidget *label = GTK_BIN(v9t9_window_pause_button)->child; if (!GTK_IS_LABEL(label)) return; if (debugger_enabled()) { debugger_register_clear_view(); debugger_memory_clear_views(); debugger_instruction_clear_view(); } if (paused) { gtk_label_set_text(GTK_LABEL(label), "Resume"); } else { gtk_label_set_text(GTK_LABEL(label), "Pause"); } } } #if 0 #pragma mark - #endif /* * Generic routine that enables or disables a widget in user_data * based on the state of the toggle button. */ void on_v9t9_togglebutton_realize_widget_enable (GtkWidget *widget, gpointer user_data) { g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget)); g_return_if_fail(GTK_IS_WIDGET(user_data)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); } void on_v9t9_togglebutton_toggled_widget_enable (GtkToggleButton *togglebutton, gpointer user_data) { g_return_if_fail(GTK_IS_WIDGET(user_data)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), gtk_toggle_button_get_active(togglebutton)); } void on_v9t9_togglebutton_realize_widget_enable_not (GtkWidget *widget, gpointer user_data) { g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget)); g_return_if_fail(GTK_IS_WIDGET(user_data)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); } void on_v9t9_togglebutton_toggled_widget_enable_not (GtkToggleButton *togglebutton, gpointer user_data) { g_return_if_fail(GTK_IS_WIDGET(user_data)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), !gtk_toggle_button_get_active(togglebutton)); } /* * Generic routine that toggles the value of the command variable * name in user_data depending on the value of togglebutton. */ static void togglebutton_toggled_command_toggle (GtkToggleButton *togglebutton, gpointer user_data, gboolean if_active) { gchar *var = (gchar *)user_data; gboolean enabled = gtk_toggle_button_get_active(togglebutton); char command[256]; snprintf(command, sizeof(command), "%s %s\n", var, if_active == enabled ? "on" : "off"); GTK_send_command(command); } /* * Generic routine that toggles the value of the command variable * name in user_data depending on the value of togglebutton. */ void on_v9t9_togglebutton_toggled_command_toggle (GtkToggleButton *togglebutton, gpointer user_data) { togglebutton_toggled_command_toggle(togglebutton, user_data, true); } /* * Generic routine that toggles the value of the command variable * name in user_data depending on the inverted value of togglebutton. */ void on_v9t9_togglebutton_toggled_command_toggle_not (GtkToggleButton *togglebutton, gpointer user_data) { togglebutton_toggled_command_toggle(togglebutton, user_data, false); } /* * Generic routine that sets the value of the togglebutton * based on the value of the command variable name in user_data. */ static void togglebutton_realize_active (GtkWidget *widget, gpointer user_data, gboolean if_active) { GtkToggleButton *tb; char *var = (char *)user_data; command_symbol *sym; int toggle; g_return_if_fail(var); g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget)); tb = GTK_TOGGLE_BUTTON(widget); /* Look up the symbol and set its value */ if (command_match_symbol(universe, var, &sym) && command_arg_get_num(sym->args, &toggle)) { // don't call this, or else it triggers the other // callback and executes a command... //gtk_toggle_button_set_active(tb, if_active == toggle); tb->active = (if_active == !!toggle); } else { logger(LOG_USER|LOG_FATAL, "Button mapped to missing option '%s'\n", var); } } /* * Generic routine that sets the value of the togglebutton * based on the true value of the command variable name in user_data. */ void on_v9t9_togglebutton_realize_active (GtkWidget *widget, gpointer user_data) { togglebutton_realize_active(widget, user_data, true); } /* * Generic routine that sets the value of the togglebutton * based on the false value of the command variable name in user_data. */ void on_v9t9_togglebutton_realize_inactive (GtkWidget *widget, gpointer user_data) { togglebutton_realize_active(widget, user_data, false); } /* * Generic callback to execute a command if a toggle button * has been clicked and thusly enabled. */ void on_v9t9_togglebutton_clicked (GtkButton *button, gpointer user_data) { g_return_if_fail(GTK_IS_TOGGLE_BUTTON(button)); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { GTK_send_command((const gchar *)user_data); } } static char * _v9t9_dsr_entry_get_filename(gpointer user_data) { char *var, *filename; command_symbol *sym; var = (char *)user_data; /* Look up the symbol and set its value */ if (command_match_symbol(universe, var, &sym) && command_arg_get_string(sym->args, &filename)) { return filename; } else { logger(LOG_USER|LOG_FATAL, "Text entry mapped to missing option '%s'\n", var); return 0L; } } static void _v9t9_dsr_entry_set_filename(gpointer user_data, char *filename) { char msg[256]; snprintf(msg, sizeof(msg), "%s \"%s\"\n", (gchar *)user_data, filename); GTK_send_command(msg); } /* * Generic DSR entry activation callback */ void on_v9t9_dsr_entry_activate (GtkEditable *editable, gpointer user_data) { char *path; gchar *copy; OSSpec spec; if (GTK_WIDGET(editable)->state != GTK_STATE_INSENSITIVE) { path = gtk_editable_get_chars(editable, 0, -1); copy = disk_file_canonicalize(&romspath, systemromspath, false /*directory*/, path, &spec, true /*add_dir*/); _v9t9_dsr_entry_set_filename(user_data, copy); g_free(path); g_free(copy); } } /* * Setup the text entry */ void on_v9t9_dsr_entry_realize (GtkWidget *widget, gpointer user_data) { char *filename; g_return_if_fail(GTK_IS_ENTRY(widget)); filename = _v9t9_dsr_entry_get_filename(user_data); gtk_entry_set_text(GTK_ENTRY(widget), filename ? filename : ""); } static GtkFileSelection *dsr_file_dialog; static GtkFileSelection * create_dsr_file_selection (void) { GtkWidget *dsr_file_selection; GtkWidget *ok_button2; GtkWidget *cancel_button2; dsr_file_selection = gtk_file_selection_new ("Select ROM Filename"); gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "dsr_file_selection", dsr_file_selection); gtk_container_set_border_width (GTK_CONTAINER (dsr_file_selection), 10); ok_button2 = GTK_FILE_SELECTION (dsr_file_selection)->ok_button; gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "ok_button2", ok_button2); gtk_widget_show (ok_button2); GTK_WIDGET_SET_FLAGS (ok_button2, GTK_CAN_DEFAULT); cancel_button2 = GTK_FILE_SELECTION (dsr_file_selection)->cancel_button; gtk_object_set_data (GTK_OBJECT (dsr_file_selection), "cancel_button2", cancel_button2); gtk_widget_show (cancel_button2); GTK_WIDGET_SET_FLAGS (cancel_button2, GTK_CAN_DEFAULT); return GTK_FILE_SELECTION(dsr_file_selection); } /* * user_data is the text entry widget */ static void on_dsr_file_ok_button_clicked (GtkButton *button, gpointer user_data) { gchar *path; gchar *copy; GtkEntry *entry; OSSpec spec; g_return_if_fail(GTK_IS_ENTRY(user_data)); entry = GTK_ENTRY(user_data); path = gtk_file_selection_get_filename(dsr_file_dialog); copy = disk_file_canonicalize(&romspath, systemromspath, false /*directory*/, path, &spec, true /*add_dir*/); gtk_entry_set_text(entry, copy); gtk_signal_emit_by_name(GTK_OBJECT(entry), "activate"); gtk_widget_unref((GtkWidget *)dsr_file_dialog); dsr_file_dialog = 0L; g_free(copy); } /* * user_data is the DSR filename variable */ static void on_dsr_file_cancel_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_unref((GtkWidget *)dsr_file_dialog); dsr_file_dialog = 0L; } /* * Choose a new entry for the filename. * * user_data is the text entry widget */ void on_v9t9_dsr_button_clicked (GtkButton *button, gpointer user_data) { OSSpec spec; const char *filename; GtkEntry *entry; gchar *copy; g_return_if_fail(GTK_IS_ENTRY(user_data)); entry = GTK_ENTRY(user_data); if (VALID_WINDOW(dsr_file_dialog)) { return; } dsr_file_dialog = create_dsr_file_selection(); gtk_widget_show(GTK_WIDGET(dsr_file_dialog)); filename = gtk_entry_get_text(entry); copy = disk_file_canonicalize(&romspath, systemromspath, false /*directory*/, filename, &spec, false /*add_dir*/); gtk_file_selection_set_filename(dsr_file_dialog, OS_SpecToString1(&spec)); gtk_file_selection_complete(dsr_file_dialog, "*.bin"); g_free(copy); // wire up buttons here (so we can pass known disk number) gtk_signal_connect(GTK_OBJECT(dsr_file_dialog->ok_button), "clicked", GTK_SIGNAL_FUNC(on_dsr_file_ok_button_clicked), (gpointer)entry); gtk_signal_connect(GTK_OBJECT(dsr_file_dialog->cancel_button), "clicked", GTK_SIGNAL_FUNC(on_dsr_file_cancel_button_clicked), (gpointer)0L); } /***********************************************/ #if 0 #pragma mark - #endif static GtkWidget *memory_dialog; void on_v9t9_window_memory_button_clicked (GtkButton *button, gpointer user_data) { if (!VALID_WINDOW(memory_dialog)) { memory_dialog = create_memory_dialog(); } else { gtk_widget_hide(memory_dialog); } gtk_widget_show(memory_dialog); execution_pause(true); } void on_memory_dialog_close_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide(memory_dialog); execution_pause(false); GTK_RESTORE_FOCUS; } /* * Lookup and execute the first iteration of a dynamic command */ static int _v9t9_dynamic_command(const char *name, command_symbol **sym) { if (!command_match_symbol(universe, name, sym)) logger(_L|LOG_FATAL, "Unknown command '%s'\n", name); if (!((*sym)->flags & c_DYNAMIC)) logger(_L|LOG_FATAL, "'%s' is not c_DYNAMIC\n", name); return (*sym)->action(*sym, csa_READ, 0); } /* * Activate or deactivate a button that optionally loads * a module ROM. These conflict with the "LoadModule" * command and the commands that load them won't be saved * to the config file if they are empty. We use this * to tell whether they are being used. */ void on_memory_config_module_rom_button_realize (GtkWidget *widget, gpointer user_data) { GtkToggleButton *tb; command_symbol *sym; #if 0 // old style: one button per ROM g_return_if_fail(user_data); g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget)); tb = GTK_TOGGLE_BUTTON(widget); /* * If the entry is loaded, activate the button. */ tb->active = (_v9t9_dynamic_command((char *)user_data, &sym)); #endif g_return_if_fail(GTK_IS_TOGGLE_BUTTON(widget)); tb = GTK_TOGGLE_BUTTON(widget); /* * If the module entry is not loaded, activate the button. */ tb->active = (!_v9t9_dynamic_command("ReplaceModule", &sym)); } /* * User opted to set a custom module ROM file, * this means we have to unload the module entry so * this will have precedence. */ void on_memory_config_module_rom_button_clicked (GtkToggleButton *togglebutton, gpointer user_data) { gpointer ptr; if (gtk_toggle_button_get_active(togglebutton)) { /* Activate all the children */ ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom_entry"); if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate"); ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_grom_entry"); if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate"); ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom1_entry"); if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate"); ptr = gtk_object_get_data((GtkObject *)memory_dialog, "module_rom2_entry"); if (ptr) gtk_signal_emit_by_name(GTK_OBJECT(ptr), "activate"); } #if 0 // old style: one button per rom g_return_if_fail(GTK_IS_ENTRY(user_data)); if (gtk_toggle_button_get_active(togglebutton)) { if (_v9t9_dynamic_command("ReplaceModule", &sym)) { GTK_send_command("UnloadModuleOnly\n"); } gtk_signal_emit_by_name(GTK_OBJECT(user_data), "activate"); } #endif } /* * Activated the ROM entry, disable the banked ROM entries */ void on_memory_config_banked_module_deactivate (GtkEditable *editable, gpointer user_data) { gchar *str; g_return_if_fail(GTK_IS_WIDGET(user_data)); str = gtk_entry_get_text(GTK_ENTRY(editable)); if (str && *str) gtk_widget_set_sensitive(GTK_WIDGET(user_data), false); else gtk_widget_set_sensitive(GTK_WIDGET(user_data), true); /* v9t9 handles the memory map stuff */ } /* * Banked module entry activated */ void on_module_config_banked_module_activate (GtkEditable *editable, gpointer user_data) { gchar *str; g_return_if_fail(GTK_IS_WIDGET(user_data)); str = gtk_entry_get_text(GTK_ENTRY(editable)); if (str && *str) gtk_widget_set_sensitive(GTK_WIDGET(user_data), false); else gtk_widget_set_sensitive(GTK_WIDGET(user_data), true); /* v9t9 handles the memory map stuff */ } #if 0 #pragma mark - #endif /* * OPTIONS WINDOW */ static GtkWidget *options_dialog; void on_v9t9_window_options_button_clicked (GtkButton *button, gpointer user_data) { if (!VALID_WINDOW(options_dialog)) { options_dialog = create_options_dialog(); } else { gtk_widget_hide(options_dialog); } gtk_widget_show(options_dialog); } void on_option_dialog_close_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide(options_dialog); GTK_RESTORE_FOCUS; } /* * Set the value of a spin button from a command. */ void on_v9t9_spin_button_realize_value (GtkWidget *widget, gpointer user_data) { GtkSpinButton *s; command_symbol *sym; int val; g_return_if_fail(user_data != 0L); g_return_if_fail(GTK_IS_SPIN_BUTTON(widget)); s = GTK_SPIN_BUTTON(widget); /* Look up the symbol and set its value */ if (command_match_symbol(universe, (char *)user_data, &sym) && command_arg_get_num(sym->args, &val)) { gtk_spin_button_set_value(s, (gfloat)val); } else { logger(LOG_USER|LOG_FATAL, "Button mapped to missing option '%s'\n", user_data); } } /* * User changed value of a spin button. * user_data is the name of the command to set. */ void on_v9t9_spin_button_changed_value (GtkEditable *editable, gpointer user_data) { char command[256]; GtkSpinButton *s; g_return_if_fail(user_data != 0L); g_return_if_fail(GTK_IS_SPIN_BUTTON(editable)); s = GTK_SPIN_BUTTON(editable); snprintf(command, sizeof(command), "%s %d\n", (char *)user_data, gtk_spin_button_get_value_as_int(s)); GTK_send_command(command); } /* * Clicked a button that affects the value of another widget. */ void on_v9t9_button_clicked_realize_widget (GtkButton *button, gpointer user_data) { GtkWidget *w; g_return_if_fail(GTK_IS_WIDGET(user_data)); w = GTK_WIDGET(user_data); // why can't we realize the widget again? gtk_widget_hide(w); gtk_widget_show(w); } #if 0 #pragma mark - #endif V99FileSelection *config_file_dialog; /* * user_data is 0 for saving, != 0 for loading */ static void on_config_file_ok_button_clicked (GtkButton *button, gpointer user_data) { const char *path; OSSpec spec; OSError err; path = v99_file_selection_get_filename(config_file_dialog); err = OS_MakeFileSpec(path, &spec); if (err != OS_NOERR) { logger(_L|LOG_ERROR|LOG_USER, "Could not resolve filename '%s' (%s)\n", path, OS_GetErrText(err)); return; } if ((gint)user_data == GTK_QUICK_LOAD ? config_load_spec(&spec, true /*session*/) : config_save_spec(&spec, true /*session*/)) { gtk_widget_hide((GtkWidget *)config_file_dialog); GTK_RESTORE_FOCUS; } } static void on_config_file_cancel_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide((GtkWidget *)config_file_dialog); GTK_RESTORE_FOCUS; } /* * Change directory by selecting an entry in the pathlist */ static void on_config_file_path_list_select_row (GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data ) { gchar *text; gchar *wild; gchar sep[] = { G_DIR_SEPARATOR, 0 }; /* Get the directory selected */ gtk_clist_get_text(GTK_CLIST(clist), row, column, &text); if (strcmp(text, ".") == 0) { text = OS_PathSpecToString1(&v9t9_homedir); } wild = g_strconcat(text, sep, "*.cnf", 0L); v99_file_selection_complete(V99_FILE_SELECTION(config_file_dialog), wild); g_free(wild); } /* * user_data is 0 for saving, != 0 for loading */ void on_v9t9_quick_load_save_button_clicked (GtkButton *button, gpointer user_data) { GtkCList *clist; int paused = execution_paused(); if ((int)user_data == 0) execution_pause(1); if (VALID_WINDOW(config_file_dialog)) { gtk_widget_destroy((GtkWidget *)config_file_dialog); } config_file_dialog = V99_FILE_SELECTION(create_disk_file_selection( (gint)user_data == GTK_QUICK_SAVE ? "Save Session File" : "Load Session File")); v99_file_selection_set_file_list_active(config_file_dialog, TRUE); // wire up buttons here gtk_signal_connect(GTK_OBJECT(config_file_dialog->ok_button), "clicked", GTK_SIGNAL_FUNC(on_config_file_ok_button_clicked), user_data); gtk_signal_connect(GTK_OBJECT(config_file_dialog->cancel_button), "clicked", GTK_SIGNAL_FUNC(on_config_file_cancel_button_clicked), (gpointer)0L); gtk_widget_show(GTK_WIDGET(config_file_dialog)); // FIXME: add tooltips clist = v99_file_selection_add_path_list(config_file_dialog, "Sessions", sessionspath); /* wire up callback to change directory */ gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(on_config_file_path_list_select_row), (gpointer)0L); clist = v99_file_selection_add_path_list(config_file_dialog, "Configurations", configspath); /* wire up callback to change directory */ gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(on_config_file_path_list_select_row), (gpointer)0L); if ((gint)user_data == GTK_QUICK_LOAD) v99_file_selection_complete(config_file_dialog, "*.cnf"); else v99_file_selection_complete(config_file_dialog, "quicksave.cnf"); v99_file_selection_set_filename(config_file_dialog, "quicksave.cnf"); } /*********************************************/ /* * Logging Configuration dialog. * * The meat of the dialog is automatically generated. */ static GtkWidget *log_dialog; static GtkTable *log_table; void on_v9t9_window_logging_button_clicked (GtkButton *button, gpointer user_data) { if (!VALID_WINDOW(log_dialog)) { log_dialog = create_logging_dialog(); } else { gtk_widget_hide(log_dialog); } gtk_widget_show(log_dialog); } void on_logging_reset_all_clicked (GtkButton *button, gpointer user_data) { GTK_send_command("Log All 0\n"); /* force a realize */ gtk_signal_emit_by_name(GTK_OBJECT(log_table), "realize"); } void on_logging_dialog_close_button_clicked (GtkButton *button, gpointer user_data) { gtk_widget_hide(log_dialog); } /* * Logging spin button needs to be realized. * user_data is the logging subsystem. */ void on_log_spin_button_realize_value (GtkWidget *widget, gpointer user_data) { GtkSpinButton *s; int val; g_return_if_fail(GTK_IS_SPIN_BUTTON(widget)); s = GTK_SPIN_BUTTON(widget); /* Look up the symbol and set its value */ val = log_level((int)user_data); gtk_spin_button_set_value(s, (gfloat)val); } /* * Logging spin button changes. * user_data is the log subsystem. */ static void on_log_spin_button_changed_value (GtkEditable *editable, gpointer user_data) { char command[256]; GtkSpinButton *s; g_return_if_fail(GTK_IS_SPIN_BUTTON(editable)); s = GTK_SPIN_BUTTON(editable); snprintf(command, sizeof(command), "Log %s %d\n", log_name((int)user_data), gtk_spin_button_get_value_as_int(s)); GTK_send_command(command); } /* * Clicked a button that affects the value */ static void on_log_button_clicked_realize_widget (GtkButton *button, gpointer user_data) { GtkWidget *w; g_return_if_fail(GTK_IS_WIDGET(user_data)); w = GTK_WIDGET(user_data); // why can't we realize the widget again? gtk_widget_hide(w); gtk_widget_show(w); } /* * This action sets up the log_dialog's log_table item * to include a dial and label for each log subsystem. */ void on_logging_log_table_realize (GtkWidget *widget, gpointer user_data) { int rows = LOG_NUM_SRC / 3; int cols = 3; int row, col, sys; /* Get the table */ log_table = GTK_TABLE(gtk_object_get_data((GtkObject *)log_dialog, "log_table")); if (!log_table) logger(_L|LOG_FATAL, "Cannot get log_table from dialog\n"); /* Resize from 1x1 to an interesting size */ gtk_table_resize(log_table, rows, cols); /* Add an entry for each subsystem */ row = col = 0; for (sys = 0; sys < LOG_NUM_SRC; sys++) { /* make the widgets */ GtkObject *spin_adj = gtk_adjustment_new( log_level(sys), L_0, L_4, 1, 1, 1); GtkWidget *spin = gtk_spin_button_new(GTK_ADJUSTMENT(spin_adj), 1, 1); GtkWidget *label = gtk_label_new(log_name(sys)); GtkWidget *hbox = gtk_hbox_new(false /*homogenous*/, 4 /*spacing*/); /* standard stuff */ gtk_widget_ref(spin); gtk_widget_ref(label); gtk_widget_ref(hbox); gtk_object_set_data_full (GTK_OBJECT (log_table), "log_spin_button", spin,(GtkDestroyNotify) gtk_widget_unref); gtk_object_set_data_full (GTK_OBJECT (log_table), "log_label", label,(GtkDestroyNotify) gtk_widget_unref); gtk_object_set_data_full (GTK_OBJECT (log_table), "log_hbox", hbox,(GtkDestroyNotify) gtk_widget_unref); /* associate subsystem with spin button */ gtk_signal_connect_after (GTK_OBJECT (spin), "activate", GTK_SIGNAL_FUNC (on_log_spin_button_changed_value), (gpointer)sys); gtk_signal_connect (GTK_OBJECT (spin), "changed", GTK_SIGNAL_FUNC (on_log_spin_button_changed_value), (gpointer)sys); gtk_signal_connect (GTK_OBJECT (spin), "realize", GTK_SIGNAL_FUNC (on_log_spin_button_realize_value), (gpointer)sys); gtk_signal_connect (GTK_OBJECT (spin), "show", GTK_SIGNAL_FUNC (on_log_spin_button_realize_value), (gpointer)sys); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE /*expand*/, FALSE /*fill*/, 0 /*padding*/); gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE /*expand*/, TRUE /*fill*/, 0 /*padding*/); gtk_widget_show(spin); gtk_widget_show(label); gtk_widget_show(hbox); /* add hbox to table */ gtk_table_attach_defaults (GTK_TABLE (log_table), hbox, col, col+1, row, row+1); if (++col >= cols) { col = 0; ++row; } } }