/* -*-c-*- -------------- mixgtk_mixal.c : * Implementation of the functions declared in mixgtk_mixal.h * ------------------------------------------------------------------ * $Id: mixgtk_mixal.c,v 1.16 2002/04/10 23:39:40 jao Exp $ * ------------------------------------------------------------------ * Copyright (C) 2001, 2002 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include "mixgtk_widgets.h" #include "mixgtk_config.h" #include "mixgtk_mixal.h" #define MIXAL_TAB_POS_ 2 static mix_vm_t *vm_ = NULL; static GtkCList *clist_; static gulong lineno_; static const gchar *LOCAL_STATUS_BAR_ = "mixal_statusbar"; static GtkStatusbar *status_; static gint status_context_; static GPtrArray *tips_text_ = NULL; static GtkWidget *symbols_dlg_ = NULL; static GtkWidget *symbols_clist_ = NULL; static const gchar *SYMBOLS_CLIST_NAME_ = "symbols_clist"; static void init_symbols_ (void) { symbols_dlg_ = mixgtk_widget_factory_get_dialog (MIXGTK_SYMBOLS_DIALOG); g_assert (symbols_dlg_); symbols_clist_ = mixgtk_widget_factory_get_child_by_name (MIXGTK_SYMBOLS_DIALOG, SYMBOLS_CLIST_NAME_); g_assert (symbols_clist_); gtk_clist_set_sort_type (GTK_CLIST (symbols_clist_), GTK_SORT_ASCENDING); gtk_clist_set_auto_sort (GTK_CLIST (symbols_clist_), TRUE); } static void insert_symbol_ (gpointer symbol, gpointer value, gpointer list) { enum {DEC_SIZE = 25, WORD_SIZE = 20}; static gchar DEC[DEC_SIZE], WORD[WORD_SIZE]; gchar *text[] = {(gchar *)symbol, DEC, WORD}; mix_word_t w = (mix_word_t)GPOINTER_TO_INT (value); g_snprintf (DEC, DEC_SIZE, "%s%ld", mix_word_is_negative (w)? "-" : "+", mix_word_magnitude (w)); mix_word_print_to_buffer (w, WORD); gtk_clist_append ((GtkCList *)list, text); } static void fill_symbols_ (const mix_symbol_table_t *table) { if (symbols_clist_) gtk_clist_clear (GTK_CLIST (symbols_clist_)); else init_symbols_ (); mix_symbol_table_foreach (((mix_symbol_table_t *)table), insert_symbol_, (gpointer)symbols_clist_); } static GdkColor colors_[3][2]; static GdkColormap *colormap_ = NULL; static const char* default_colors_[3][2] = { {"red", "black"}, {"lightgrey", "black"}, {"white", "black"} }; static const char* keys_[3][2] = { {"MIXAL.bp.color.bg", "MIXAL.bp.color.fg"}, {"MIXAL.lc.color.bg", "MIXAL.lc.color.fg"}, {"MIXAL.pl.color.bg", "MIXAL.pl.color.fg"} }; static const GdkColor * parse_color_ (const gchar *str) { static GdkColor color; if (sscanf (str, "%hd%hd%hd", &(color.red), &(color.green), &(color.blue)) < 3) { g_warning (_("Wrong color spec: %s\n"), str); return NULL; } return &color; } static const gchar * color_to_string_ (const GdkColor *color) { enum {LEN = 100}; static gchar buffer[LEN]; g_snprintf (buffer, LEN, "%hd %hd %hd", color->red, color->green, color->blue); return buffer; } static gboolean init_color_ (GdkColor *c, const gchar *name) { return (gdk_color_parse (name, c) && gdk_colormap_alloc_color (colormap_, c, FALSE, TRUE)); } /* initialise the mixal widgets */ gboolean mixgtk_mixal_init (mix_vm_t *vm, mixgtk_dialog_id_t top) { static gboolean restart = FALSE; int i,j; g_return_val_if_fail (vm != NULL, FALSE); vm_ = vm; clist_ = GTK_CLIST (mixgtk_widget_factory_get (top, MIXGTK_WIDGET_MIXAL)); g_return_val_if_fail (clist_ != NULL, FALSE); if (!mixgtk_config_is_split ()) status_ = GTK_STATUSBAR (mixgtk_widget_factory_get (MIXGTK_MAIN, MIXGTK_WIDGET_STATUSBAR)); else status_ = GTK_STATUSBAR (mixgtk_widget_factory_get_child_by_name (top, LOCAL_STATUS_BAR_)); g_return_val_if_fail (status_ != NULL, FALSE); status_context_ = gtk_statusbar_get_context_id (status_, "MIXAL status"); symbols_dlg_ = symbols_clist_ = NULL; /* allocate colors */ colormap_ = gtk_widget_get_colormap (GTK_WIDGET (clist_)); for (i = 0; i < 3; ++i) for (j = 0; j < 2; ++j) { const gchar *ccol = mixgtk_config_get (keys_[i][j]); const GdkColor *color = NULL; if (ccol && (color = parse_color_ (ccol))) { mixgtk_mixal_set_color (i, j, color); } else { g_return_val_if_fail (init_color_ (&colors_[i][j], default_colors_[i][j]), FALSE); } } if (restart) mixgtk_mixal_load_file (); else restart = TRUE; return TRUE; } /* set the plain, location pointer and break colors */ void mixgtk_mixal_set_color (mixal_line_t line, mixal_line_zone_t zone, const GdkColor *color) { g_return_if_fail (color != NULL); g_return_if_fail (line <= MIXAL_LINE_PLAIN); g_return_if_fail (zone <= MIXAL_LINE_FG); colors_[line][zone].red = color->red; colors_[line][zone].green = color->green; colors_[line][zone].blue = color->blue; gdk_colormap_alloc_color (colormap_, &colors_[line][zone], FALSE, TRUE); mixgtk_mixal_update_bp_all (); mixgtk_config_update (keys_[line][zone], color_to_string_(&colors_[line][zone])); } const GdkColor * mixgtk_mixal_get_color (mixal_line_t line, mixal_line_zone_t zone) { g_return_val_if_fail (line <= MIXAL_LINE_PLAIN, FALSE); g_return_val_if_fail (zone <= MIXAL_LINE_FG, FALSE); return &colors_[line][zone]; } /* load the corresponding mixal file */ static void update_tips_ (const mix_symbol_table_t *table, const gchar *line) { enum {SIZE = 256}; static gchar BUFFER[256]; static const gchar *DELIMITERS = " /+*=-()\t,:\n"; if (line) { guint k = 0; gchar *tip = g_strdup (""); gchar *new_tip; gchar **tokens; gchar *text = g_strdup (line); text = g_strdelimit (text, DELIMITERS, ' '); tokens = g_strsplit (g_strstrip (text), " ", -1); while (tokens[k]) { if (mix_symbol_table_is_defined (table, tokens[k])) { mix_word_t val = mix_symbol_table_value (table, tokens[k]); g_snprintf (BUFFER, SIZE, "[ %s = %s%ld ]", tokens[k], mix_word_is_negative (val)? "-" : "+", mix_word_magnitude (val)); new_tip = g_strconcat (tip, " ", BUFFER, NULL); g_free (tip); tip = new_tip; } ++k; } g_ptr_array_add (tips_text_, (gpointer)tip); g_strfreev (tokens); g_free (text); } } void mixgtk_mixal_load_file (void) { enum {ADDR_SIZE = 20, CONT_SIZE = 200}; static gchar ADDR[ADDR_SIZE], CONT[CONT_SIZE]; static gchar *TEXT[] = {ADDR, CONT}; static gchar *NULL_TEXT[] = {NULL, NULL}; const mix_src_file_t *file; g_assert (vm_); g_assert (clist_); gtk_clist_clear (clist_); file = mix_vm_get_src_file (vm_); if (file != NULL) { gint k; mix_address_t addr; const mix_symbol_table_t *table = mix_vm_get_symbol_table (vm_); lineno_ = mix_src_file_get_line_no (file); if (tips_text_) g_ptr_array_free (tips_text_, TRUE); tips_text_ = g_ptr_array_new (); gtk_clist_freeze (clist_); for (k = 0; k < lineno_; ++k) { const gchar *line = mix_src_file_get_line (file, k + 1); g_snprintf (CONT, CONT_SIZE, "%03d: %s", k + 1, line); addr = mix_vm_get_lineno_address (vm_, k + 1); if (addr != MIX_VM_CELL_NO) { g_snprintf (ADDR, ADDR_SIZE, "%04d: ", mix_short_magnitude (addr)); mix_word_print_to_buffer (mix_vm_get_addr_contents (vm_, addr), ADDR + strlen (ADDR)); } else ADDR[0] = '\0'; gtk_clist_append (clist_, TEXT); gtk_clist_set_row_data (clist_, k, GINT_TO_POINTER (mix_short_magnitude (addr))); if (table) update_tips_ (table, line); } if (table) fill_symbols_ (table); gtk_clist_append (clist_, NULL_TEXT); gtk_clist_set_row_data (clist_, k, GINT_TO_POINTER (MIX_VM_CELL_NO)); gtk_clist_unselect_row (clist_, 0, 0); gtk_clist_thaw (clist_); } else lineno_ = 0; } /* update the widgets */ static void reset_bg_ (gint row) { gint addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, row)); gboolean isset = mix_vm_has_breakpoint_at_address (vm_, addr); gtk_clist_set_background (clist_, row, isset ? &colors_[MIXAL_LINE_BREAK][MIXAL_LINE_BG]: &colors_[MIXAL_LINE_PLAIN][MIXAL_LINE_BG]); gtk_clist_set_foreground (clist_, row, isset ? &colors_[MIXAL_LINE_BREAK][MIXAL_LINE_FG]: &colors_[MIXAL_LINE_PLAIN][MIXAL_LINE_FG]); } static void select_row_ (gint row) { static gint last = -1; gtk_clist_set_background (clist_, row, &colors_[MIXAL_LINE_LOC][MIXAL_LINE_BG]); gtk_clist_set_foreground (clist_, row, &colors_[MIXAL_LINE_LOC][MIXAL_LINE_FG]); if (gtk_clist_row_is_visible (clist_, row) != GTK_VISIBILITY_FULL) gtk_clist_moveto (clist_, row, 0, 0.25, 0); if (last != -1 && last != row) reset_bg_ (last); last = row; } void mixgtk_mixal_update (void) { gint addr = 0; gint k = 0; g_assert (vm_); g_assert (clist_); addr = mix_short_magnitude (mix_vm_get_prog_count (vm_)); k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); select_row_ (k); } /* breakpoints */ void mixgtk_mixal_update_bp_at_address (guint addr) { gint k; g_assert (vm_); g_assert (clist_); k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); reset_bg_ (k); } void mixgtk_mixal_update_bp_at_line (guint line) { if ( line < 1 ) return; while (line < lineno_) { gint addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, line - 1)); if (addr != MIX_VM_CELL_NO) break; ++line; } reset_bg_ (line - 1); } void mixgtk_mixal_update_bp_all () { gint k, addr; for (k = 0; k < lineno_; ++k) reset_bg_ (k); addr = mix_vm_get_prog_count (vm_); k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); select_row_ (k); } /* callbacks */ void on_mixal_select_row (GtkWidget *w, gint row, gint col, GdkEventButton *e, gpointer data) { gboolean isset; gint addr, pc; gtk_clist_unselect_row (clist_, row, col); addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, row)); pc = mix_vm_get_prog_count (vm_); if (addr < MIX_VM_CELL_NO) { isset = mix_vm_has_breakpoint_at_address (vm_, addr); if (isset) mix_vm_clear_breakpoint_address (vm_, addr); else mix_vm_set_breakpoint_address (vm_, addr); reset_bg_ (row); } } gint on_mixal_motion_notify_event (GtkWidget *list, GdkEventMotion *event, gpointer data) { static gint last_row = 0; static guint last_message = 0; gint row = last_row, col = 0; if (gtk_clist_get_selection_info (clist_, event->x, event->y, &row, &col) && row != last_row && tips_text_) { const gchar *msg = NULL; last_row = row; if (last_message) gtk_statusbar_remove (status_, status_context_, last_message); msg = (const gchar *)g_ptr_array_index (tips_text_, row); if (msg) last_message = gtk_statusbar_push (status_, status_context_, msg); else last_message = 0; } return FALSE; } void on_symbol_ok_clicked () { gtk_widget_hide (symbols_dlg_); } void on_symbols_activate () { if (!symbols_dlg_) init_symbols_ (); gtk_widget_show (symbols_dlg_); } void on_notebook_switch_page (GtkNotebook *notebook) { gint p = gtk_notebook_get_current_page (notebook); if (p != MIXAL_TAB_POS_) gtk_statusbar_pop (status_, status_context_); if (p == MIXAL_TAB_POS_) mixgtk_mixal_update (); } void on_mixal_leave_notify_event () { gtk_statusbar_pop (status_, status_context_); }