/* -*-c-*- ---------------- mixgtk_device.c : * actual types for mixgtk devices * ------------------------------------------------------------------ * $Id: mixgtk_device.c,v 1.17 2002/03/29 16:30:49 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 #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; /** 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; static gint last_pos_ = 0; /* 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; gint pos; }; struct mixgtk_bin_device_t { struct mixgtk_device_t gtk_device; guint last_insert; GtkWidget *scroll; 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_insert (GTK_TEXT (dev->widget), NULL, NULL, NULL, 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) 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) { static gchar *DEFTEXT[BIN_DEV_COL_] = { "0", "0", "0", "0", "0" }; guint k, col, row; gboolean dec = FALSE; GtkCList *list = GTK_CLIST (dev->gtk_device.widget); dec = IS_DEC(decs_, dev->gtk_device.device.type); gtk_clist_freeze (list); for (k = 0; k < SIZES_[dev->gtk_device.device.type]; k++) { row = dev->last_insert / BIN_DEV_COL_; col = dev->last_insert % BIN_DEV_COL_; if (col == 0) { int j; mix_word_t *words = g_new (mix_word_t, 5); gtk_clist_append (list, DEFTEXT); for (j = 0; j < 5; ++j) words[j] = block[k + j]; gtk_clist_set_row_data_full (list, row, (gpointer)words, g_free); } gtk_clist_set_text (list, row, col, get_word_string_ (block[k], dec)); dev->last_insert++; } gtk_clist_thaw (list); } static void redraw_bin_device_ (struct mixgtk_bin_device_t *dev) { gint k, col, row; gboolean dec = FALSE; mix_word_t *words = NULL; GtkCList *list; if (!dev) return; list = GTK_CLIST (dev->gtk_device.widget); dec = IS_DEC(decs_, dev->gtk_device.device.type); gtk_clist_freeze (list); for (k = 0; k < dev->last_insert; ++k) { row = k / BIN_DEV_COL_; col = k % BIN_DEV_COL_; if (col == 0) words = gtk_clist_get_row_data (list, row); gtk_clist_set_text (list, row, col, get_word_string_ (words[col], dec)); } gtk_clist_thaw (list); } 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_page (container_, gtkdev->pos); 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 && !(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_page (container_, gtkdev->pos); 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) gtk_widget_destroy (((struct mixgtk_bin_device_t *)dev)->scroll); gtk_widget_destroy (gtkdev->widget); (DEF_DEV_VTABLE_->destroy) (dev); gtk_notebook_remove_page (GTK_NOTEBOOK (container_), gtkdev->pos); --last_pos_; } 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->pos = last_pos_++; if (MODES_[dev->device.type] == mix_dev_CHAR) { GtkWidget *box = gtk_hbox_new (0, 0); GtkWidget *scroll = NULL; GtkAdjustment *vadj = NULL; dev->widget = gtk_text_new (NULL, NULL); g_assert (box); g_assert (dev->widget); gtk_text_set_editable (GTK_TEXT (dev->widget), FALSE); vadj = GTK_TEXT (dev->widget)->vadj; scroll = gtk_vscrollbar_new (vadj); gtk_box_pack_start (GTK_BOX (box), dev->widget, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (box), scroll, FALSE, FALSE, 0); gtk_notebook_insert_page (container_, box, label, dev->pos); gtk_widget_show (box); gtk_widget_show (scroll); } else { gint k; struct mixgtk_bin_device_t *bindev = (struct mixgtk_bin_device_t *)dev; bindev->scroll = gtk_scrolled_window_new (NULL, NULL); g_assert (bindev->scroll); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (bindev->scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); dev->widget = gtk_clist_new (BIN_DEV_COL_); g_assert (dev->widget); for (k =0; k < BIN_DEV_COL_; ++k) { gtk_clist_set_column_width (GTK_CLIST (dev->widget), k, 120); gtk_clist_set_column_auto_resize (GTK_CLIST (dev->widget), k, TRUE); } gtk_container_add (GTK_CONTAINER (bindev->scroll), dev->widget); gtk_notebook_insert_page (container_, bindev->scroll, label, dev->pos); gtk_widget_show (bindev->scroll); } gtk_widget_show (label); gtk_widget_set_style (dev->widget, gtk_widget_get_style (GTK_WIDGET (container_))); gtk_widget_show (dev->widget); gtk_widget_draw (GTK_WIDGET (container_), NULL); } /* 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_insert (GTK_TEXT (result->widget), NULL, NULL, NULL, text, -1); g_free (text); } else { static gchar *VALS[BIN_DEV_COL_] = {""}; 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; if (to->last_insert > 0) { gint k, j, rows = to->last_insert / BIN_DEV_COL_; GtkCList *tl = GTK_CLIST (result->widget); GtkCList *fl = GTK_CLIST (from->widget); for (k = 0; k < rows; ++k) { mix_word_t *words = g_new (mix_word_t, BIN_DEV_COL_); mix_word_t *oldwords = (mix_word_t *) gtk_clist_get_row_data (fl, k); for (j = 0; j < BIN_DEV_COL_; ++j) words[j] = oldwords[j]; gtk_clist_append (tl, VALS); gtk_clist_set_row_data_full (tl, k, words, g_free); } redraw_bin_device_ (to); } } 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; last_pos_ = 0; devdlg_ = NULL; devdir_dlg_ = NULL; devdir_entry_ = 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); } } /* set to first page */ gtk_notebook_set_page (container_, 0); 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_; 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_); } static void devdir_callback (const gchar *file) { gtk_entry_set_text (devdir_entry_, file); } void on_devdir_browse_clicked () { mixgtk_get_file (devdir_callback, "Devices dir", mix_device_get_dir ()); } 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); }