/* -*-c-*- ---------------- mixgtk_device.c : * actual types for mixgtk devices * ------------------------------------------------------------------ * $Id: mixgtk_device.c,v 1.21 2004/06/23 10:50:10 jao Exp $ * ------------------------------------------------------------------ * Copyright (C) 2001, 2002, 2004 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 #include #include #include "mixgtk.h" #include "mixgtk_gen_handlers.h" #include "mixgtk_widgets.h" #include "mixgtk_config.h" #include "mixgtk_cmd_dispatcher.h" #include "mixgtk_device.h" #define BIN_DEV_COL_ 5 static const gchar *DEV_FORMAT_KEY_ = "Device.format"; /* device container */ static GtkNotebook *container_ = NULL; /* devdir dialog */ static GtkWidget *devdir_dlg_ = NULL; static GtkEntry *devdir_entry_ = NULL; /* terminal input dialog */ static GtkWidget *input_dlg_ = NULL; static GtkEntry *input_dlg_entry_ = NULL; /** configuration stuff */ #define LAST_BIN_DEV_ mix_dev_DISK_7 static GtkWidget *devdlg_ = NULL; static GtkWidget *dtoggle_ = NULL; static GtkWidget *wtoggle_ = NULL; static GtkWidget *combo_ = NULL; /* virtual machine */ static mix_vm_t *vm_ = NULL; /* dec settings */ static gint32 decs_ = 0; static gint32 new_decs_ = 0; /* macros manipulating dec settings */ #define IS_DEC(flags,type) (((flags) >> (type)) & 1) #define SET_DEC(flags,type) ((flags) |= (1<<(type))) #define CLEAR_DEC(flags,type) ((flags) &= ~(1<<(type))) /* a mixgtk device */ struct mixgtk_device_t { mix_device_t device; GtkWidget *widget; GtkWidget *scroll; }; struct mixgtk_bin_device_t { struct mixgtk_device_t gtk_device; guint last_insert; GtkListStore *store; gboolean dec; }; /* callbacks for output devices */ static void write_char_ (struct mixgtk_device_t *dev, const mix_word_t *block) { enum {MAX_BLOCK = 16, BUFF_SIZE = MAX_BLOCK * 5 + 2}; static gchar BUFFER[BUFF_SIZE]; guint k, j; for (k = 0; k < SIZES_[dev->device.type]; k++) for (j = 1; j < 6; j++) { mix_char_t ch = mix_word_get_byte (block[k], j); BUFFER[5 * k + j - 1] = mix_char_to_ascii (ch); } BUFFER[5 * k] = '\n'; BUFFER[5 * k + 1] = '\0'; gtk_text_buffer_insert_at_cursor (gtk_text_view_get_buffer (GTK_TEXT_VIEW (dev->widget)), BUFFER, -1); } static const gchar * get_word_string_ (mix_word_t w, gboolean dec) { enum {BUFF_SIZE = 17}; static gchar BUFFER[BUFF_SIZE] = { 0 }; if (dec) g_snprintf (BUFFER, BUFF_SIZE, "%s%011ld", mix_word_is_negative (w)? "-" : "+", mix_word_magnitude (w)); else mix_word_print_to_buffer (w, BUFFER); return BUFFER; } static void write_bin_ (struct mixgtk_bin_device_t *dev, const mix_word_t *block) { guint k, col; gboolean dec = FALSE; size_t len; GtkTreeView *view = GTK_TREE_VIEW (dev->gtk_device.widget); GtkListStore *store = dev->store; GtkTreeIter iter; g_assert (view); g_assert (store); dec = IS_DEC(decs_, dev->gtk_device.device.type); for (k = 0, len = SIZES_[dev->gtk_device.device.type]; k < len; k += 5) { gtk_list_store_append (store, &iter); for (col = 0; col < 5; ++col) gtk_list_store_set (store, &iter, col, get_word_string_ (block[k + col], dec), -1); dev->last_insert++; } } static gboolean write_ (mix_device_t *dev, const mix_word_t *block) { struct mixgtk_device_t *gtkdev = (struct mixgtk_device_t *) dev; if (dev->type != mix_dev_CONSOLE && !(DEF_DEV_VTABLE_->write)(dev, block)) return FALSE; if (MODES_[dev->type] == mix_dev_CHAR) write_char_ (gtkdev, block); else write_bin_ ((struct mixgtk_bin_device_t *)gtkdev, block); gtk_notebook_set_current_page (container_, gtk_notebook_page_num (container_, gtkdev->scroll)); return TRUE; } static gboolean read_cons_ (mix_word_t *block) { gchar *text; size_t i, j; if (input_dlg_ == NULL) { input_dlg_ = mixgtk_widget_factory_get_dialog (MIXGTK_INPUT_DIALOG); g_assert (input_dlg_); input_dlg_entry_ = GTK_ENTRY (mixgtk_widget_factory_get_child_by_name (MIXGTK_INPUT_DIALOG, "input_entry")); g_assert (input_dlg_entry_); } gtk_widget_show (input_dlg_); gtk_main (); /* wait until dialog closes */ text = g_strdup_printf ("%-70s", gtk_entry_get_text (input_dlg_entry_)); for (i = 0; i < 70; ++i) for (j = 0; j < 5; ++j) mix_word_set_byte (block + i, j + 1, mix_char_to_byte (mix_ascii_to_char (text[5 * i + j]))); g_free (text); return TRUE; } static gboolean read_ (mix_device_t *dev, mix_word_t *block) { struct mixgtk_device_t *gtkdev = (struct mixgtk_device_t *) dev; if (dev->type == mix_dev_CONSOLE && !read_cons_ (block)) return FALSE; if (dev->type != mix_dev_CONSOLE && !(DEF_DEV_VTABLE_->read)(dev, block)) return FALSE; if (MODES_[dev->type] == mix_dev_CHAR) write_char_ (gtkdev, block); else write_bin_ ((struct mixgtk_bin_device_t *)gtkdev, block); gtk_notebook_set_current_page (container_, gtk_notebook_page_num (container_, gtkdev->scroll)); return TRUE; } static gboolean ioc_ (mix_device_t *dev, mix_short_t cmd) { return (DEF_DEV_VTABLE_->ioc)(dev, cmd); } static gboolean busy_ (const mix_device_t *dev) { return (DEF_DEV_VTABLE_->busy)(dev); } static void destroy_ (mix_device_t *dev) { struct mixgtk_device_t *gtkdev = (struct mixgtk_device_t *)dev; if (MODES_[dev->type] == mix_dev_BIN) { struct mixgtk_bin_device_t * bdev = (struct mixgtk_bin_device_t *)dev; gtk_list_store_clear (bdev->store); g_object_unref ((gpointer)bdev->store); } (DEF_DEV_VTABLE_->destroy) (dev); gtk_notebook_remove_page (container_, gtk_notebook_page_num (container_, gtkdev->scroll)); } static mix_device_vtable_t MIXGTK_VTABLE_ = { write_, read_, ioc_, busy_, destroy_ }; /* create the gui part of the device */ static void mixgtk_device_construct_gui_ (struct mixgtk_device_t *dev) { GtkWidget *label = gtk_label_new (DEF_NAMES_[dev->device.type]); g_assert (label); dev->scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dev->scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); if (MODES_[dev->device.type] == mix_dev_CHAR) { dev->widget = gtk_text_view_new (); gtk_text_view_set_editable (GTK_TEXT_VIEW (dev->widget), FALSE); } else { gint k; struct mixgtk_bin_device_t *bindev = (struct mixgtk_bin_device_t *)dev; GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); bindev->store = gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); dev->widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (bindev->store)); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dev->widget), FALSE); for (k = 0; k < BIN_DEV_COL_; ++k) { gtk_tree_view_append_column (GTK_TREE_VIEW (dev->widget), gtk_tree_view_column_new_with_attributes ("", renderer, "text", k, NULL)); } } g_assert (dev->widget); gtk_container_add (GTK_CONTAINER (dev->scroll), dev->widget); gtk_notebook_append_page (container_, dev->scroll, label); gtk_widget_set_style (dev->widget, gtk_widget_get_style (GTK_WIDGET (container_))); gtk_widget_show (label); gtk_widget_show (dev->scroll); gtk_widget_show (dev->widget); } /* create a new mixgtk device */ static mix_device_t * mixgtk_device_new_ (mix_device_type_t type) { struct mixgtk_device_t *dev = NULL; g_return_val_if_fail (type < mix_dev_INVALID, NULL); if (MODES_[type] == mix_dev_CHAR) { dev = g_new (struct mixgtk_device_t, 1); } else { dev = (struct mixgtk_device_t *) g_new (struct mixgtk_bin_device_t, 1); ((struct mixgtk_bin_device_t *)dev)->last_insert = 0; } construct_device_ (&dev->device, type); dev->device.vtable = &MIXGTK_VTABLE_; mixgtk_device_construct_gui_ (dev); return (mix_device_t *)dev; } static mix_device_t * mixgtk_device_copy_ (const struct mixgtk_device_t *from) { struct mixgtk_device_t *result = (struct mixgtk_device_t *)mixgtk_device_new_ (from->device.type); g_return_val_if_fail (result != NULL, NULL); if (MODES_[from->device.type] == mix_dev_CHAR) { gchar *text = gtk_editable_get_chars (GTK_EDITABLE (from->widget), 0, -1); gtk_text_buffer_insert_at_cursor (gtk_text_view_get_buffer (GTK_TEXT_VIEW (result->widget)), text, -1); g_free (text); } else { struct mixgtk_bin_device_t *to = (struct mixgtk_bin_device_t *) result; struct mixgtk_bin_device_t *fr = (struct mixgtk_bin_device_t *) from; to->last_insert = fr->last_insert; to->dec = fr->dec; gtk_tree_view_set_model (GTK_TREE_VIEW (result->widget), GTK_TREE_MODEL (fr->store)); to->store = fr->store; } return (mix_device_t *)result; } /* init default devices */ gboolean mixgtk_device_init (GtkNotebook *container, mix_vm_t *vm) { gint k = 0; g_return_val_if_fail (container != NULL, FALSE); g_return_val_if_fail (vm != NULL, FALSE); container_ = container; vm_ = vm; devdlg_ = NULL; devdir_dlg_ = NULL; devdir_entry_ = NULL; input_dlg_ = NULL; dtoggle_ = NULL; wtoggle_ = NULL; combo_ = NULL; /* remove dummy page from container */ gtk_notebook_remove_page (container_, 0); mix_vm_set_device_factory (vm, mixgtk_device_new_); /* read format configuration */ if (mixgtk_config_get (DEV_FORMAT_KEY_)) decs_ = atoi (mixgtk_config_get (DEV_FORMAT_KEY_)); /* re-create existing devices */ for (k = 0; k < mix_dev_INVALID; ++k) { mix_device_t *dev = mix_vm_get_device (vm, k); if (dev != NULL) { mix_device_t *newdev = mixgtk_device_copy_ ((struct mixgtk_device_t *)dev); mix_vm_connect_device (vm, newdev); } } return TRUE; } void mixgtk_device_set_format (mix_device_type_t dev, gboolean dec) { gboolean changed; g_return_if_fail (dev < mix_dev_INVALID); changed = (dec && !IS_DEC (decs_, dev)) || (!dec && IS_DEC (decs_, dev)); if (changed && (MODES_[dev] == mix_dev_BIN)) { if (dec) SET_DEC (decs_, dev); else CLEAR_DEC (decs_, dev); /* redraw_bin_device_ ((struct mixgtk_bin_device_t *) */ /* mix_vm_get_device (vm_, dev)); */ } } static mix_device_type_t get_device_idx_ (void) { /* const gchar *name = gtk_entry_get_text */ /* (GTK_ENTRY (GTK_COMBO (combo_)->entry)); */ /* /\* inefficient, but the list is short *\/ */ /* int k; */ /* for (k = 0; k <= LAST_BIN_DEV_; ++k) */ /* if (!strcmp (name, DEF_NAMES_[k])) return k; */ /* g_assert_not_reached (); */ return 0; } static void init_devform_ (void) { GList *names = NULL; int k; devdlg_ = mixgtk_widget_factory_get_dialog (MIXGTK_DEVFORM_DIALOG); g_assert (devdlg_); dtoggle_ = mixgtk_widget_factory_get_child_by_name (MIXGTK_DEVFORM_DIALOG, "decradio"); g_assert (dtoggle_); wtoggle_ = mixgtk_widget_factory_get_child_by_name (MIXGTK_DEVFORM_DIALOG, "wordradio"); g_assert (wtoggle_); combo_ = mixgtk_widget_factory_get_child_by_name (MIXGTK_DEVFORM_DIALOG, "dev_combo"); g_assert (combo_); for (k = 0; k <= LAST_BIN_DEV_; ++k) names = g_list_append (names, (gchar *)DEF_NAMES_[k]); /* gtk_combo_set_popdown_strings (GTK_COMBO (combo_), names); */ } void on_deventry_changed () { mix_device_type_t dev = get_device_idx_ (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dtoggle_), IS_DEC (new_decs_, dev)); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle_), !IS_DEC (new_decs_, dev)); } void on_devform_activate () { if (!devdlg_) init_devform_ (); new_decs_ = decs_; gtk_widget_show (devdlg_); on_deventry_changed (); } void on_decradio_toggled (GtkToggleButton *button) { if (gtk_toggle_button_get_active (button)) SET_DEC (new_decs_, get_device_idx_ ()); else CLEAR_DEC (new_decs_, get_device_idx_ ()); } void on_devapp_button_clicked () { int k; gchar value[20]; for (k = 0; k <= LAST_BIN_DEV_; ++k) mixgtk_device_set_format (k, IS_DEC (new_decs_, k)); decs_ = new_decs_; g_snprintf (value, 20, "%d", decs_); mixgtk_config_update (DEV_FORMAT_KEY_, value); } void on_devok_button_clicked () { on_devapp_button_clicked (); gtk_widget_hide (devdlg_); } void on_devcancel_button_clicked () { gtk_widget_hide (devdlg_); } void on_devset_button_clicked () { static gint32 ON = 0xffff, OFF = 0; new_decs_ = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dtoggle_)))? ON : OFF; } void on_devdir_activate () { static const gchar *DEVDIR_ENTRY_NAME = "devdir_entry"; if (devdir_dlg_ == NULL) { devdir_dlg_ = mixgtk_widget_factory_get_dialog (MIXGTK_DEVDIR_DIALOG); g_assert (devdir_dlg_); devdir_entry_ = GTK_ENTRY (mixgtk_widget_factory_get_child_by_name (MIXGTK_DEVDIR_DIALOG, DEVDIR_ENTRY_NAME)); g_assert (devdir_entry_); } gtk_entry_set_text (devdir_entry_, mix_device_get_dir ()); gtk_widget_show (devdir_dlg_); } void on_devdir_browse_clicked () { GtkWidget *dialog; const gchar *current = gtk_entry_get_text (devdir_entry_); dialog = gtk_file_chooser_dialog_new (_("Devices folder"), GTK_WINDOW (devdir_dlg_), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (current != NULL) gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), current); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gtk_entry_set_text (devdir_entry_, filename); g_free (filename); } gtk_widget_destroy (dialog); } void on_devdir_cancel_clicked () { gtk_widget_hide (devdir_dlg_); } void on_devdir_ok_clicked () { const gchar *dirname = gtk_entry_get_text (devdir_entry_); gchar *cmd = g_strconcat (mix_vm_command_to_string (MIX_CMD_SDDIR), " ", dirname, NULL); gtk_widget_hide (devdir_dlg_); mixgtk_cmd_dispatcher_dispatch (cmd); g_free (cmd); } void on_input_ok_clicked () { gtk_widget_hide (input_dlg_); gtk_main_quit (); } void on_input_clear_clicked () { gtk_entry_set_text (input_dlg_entry_, ""); } void on_input_entry_activate () { on_input_ok_clicked (); }