Index: app/widgets/gimpcontrollereditor.c =================================================================== RCS file: /cvs/gnome/gimp/app/widgets/gimpcontrollereditor.c,v retrieving revision 1.4 diff -u -p -r1.4 gimpcontrollereditor.c --- app/widgets/gimpcontrollereditor.c 24 Nov 2004 02:17:12 -0000 1.4 +++ app/widgets/gimpcontrollereditor.c 7 Dec 2004 22:02:04 -0000 @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include "libgimpwidgets/gimpwidgets.h" @@ -273,9 +275,36 @@ gimp_controller_editor_constructor (GTyp { if (prop_spec->flags & G_PARAM_WRITABLE) { - widget = gimp_prop_spin_button_new (G_OBJECT (controller), - prop_spec->name, - 1, 8, 0); + GimpIntStore *model = NULL; + gchar *model_name = g_strdup_printf ("%s-values", + prop_spec->name); + + if (((i + 1) < n_property_specs) && + ! strcmp (model_name, property_specs[i + 1]->name) && + G_IS_PARAM_SPEC_OBJECT (property_specs[i + 1]) && + g_type_is_a (property_specs[i + 1]->value_type, + GIMP_TYPE_INT_STORE)) + { + g_object_get (controller, + property_specs[i + 1]->name, &model, + NULL); + } + + g_free (model_name); + + if (model) + { + widget = gimp_prop_int_combo_box_new (G_OBJECT (controller), + prop_spec->name, + model); + g_object_unref (model); + } + else + { + widget = gimp_prop_spin_button_new (G_OBJECT (controller), + prop_spec->name, + 1, 8, 0); + } gimp_table_attach_aligned (GTK_TABLE (table), 0, row++, g_param_spec_get_nick (prop_spec), Index: app/widgets/gimppropwidgets.c =================================================================== RCS file: /cvs/gnome/gimp/app/widgets/gimppropwidgets.c,v retrieving revision 1.62 diff -u -p -r1.62 gimppropwidgets.c --- app/widgets/gimppropwidgets.c 21 Nov 2004 14:22:44 -0000 1.62 +++ app/widgets/gimppropwidgets.c 7 Dec 2004 22:02:04 -0000 @@ -289,15 +289,65 @@ gimp_prop_enum_check_button_notify (GObj } -/*********************/ -/* enum combo box */ -/*********************/ - -static void gimp_prop_enum_combo_box_callback (GtkWidget *widget, - GObject *config); -static void gimp_prop_enum_combo_box_notify (GObject *config, - GParamSpec *param_spec, - GtkWidget *widget); +/*************************/ +/* int/enum combo box */ +/*************************/ + +static void gimp_prop_int_combo_box_callback (GtkWidget *widget, + GObject *config); +static void gimp_prop_int_combo_box_notify (GObject *config, + GParamSpec *param_spec, + GtkWidget *widget); + +GtkWidget * +gimp_prop_int_combo_box_new (GObject *config, + const gchar *property_name, + GimpIntStore *store) +{ + GParamSpec *param_spec; + GtkWidget *combo_box; + GtkWidget *widget; + gint value; + + param_spec = check_param_spec (config, property_name, + G_TYPE_PARAM_INT, G_STRFUNC); + if (! param_spec) + return NULL; + + g_object_get (config, + property_name, &value, + NULL); + + combo_box = g_object_new (GIMP_TYPE_INT_COMBO_BOX, + "model", store, + NULL); + + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo_box), value); + + g_signal_connect (combo_box, "changed", + G_CALLBACK (gimp_prop_int_combo_box_callback), + config); + + /* can't set a tooltip on a combo_box */ + if (g_param_spec_get_blurb (param_spec)) + { + widget = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER (widget), combo_box); + gtk_widget_show (combo_box); + } + else + { + widget = combo_box; + } + + set_param_spec (G_OBJECT (combo_box), widget, param_spec); + + connect_notify (config, property_name, + G_CALLBACK (gimp_prop_int_combo_box_notify), + combo_box); + + return widget; +} GtkWidget * gimp_prop_enum_combo_box_new (GObject *config, @@ -340,7 +390,7 @@ gimp_prop_enum_combo_box_new (GObject gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo_box), value); g_signal_connect (combo_box, "changed", - G_CALLBACK (gimp_prop_enum_combo_box_callback), + G_CALLBACK (gimp_prop_int_combo_box_callback), config); /* can't set a tooltip on a combo_box */ @@ -358,15 +408,15 @@ gimp_prop_enum_combo_box_new (GObject set_param_spec (G_OBJECT (combo_box), widget, param_spec); connect_notify (config, property_name, - G_CALLBACK (gimp_prop_enum_combo_box_notify), + G_CALLBACK (gimp_prop_int_combo_box_notify), combo_box); return widget; } static void -gimp_prop_enum_combo_box_callback (GtkWidget *widget, - GObject *config) +gimp_prop_int_combo_box_callback (GtkWidget *widget, + GObject *config) { GParamSpec *param_spec; gint value; @@ -384,9 +434,9 @@ gimp_prop_enum_combo_box_callback (GtkWi } static void -gimp_prop_enum_combo_box_notify (GObject *config, - GParamSpec *param_spec, - GtkWidget *combo_box) +gimp_prop_int_combo_box_notify (GObject *config, + GParamSpec *param_spec, + GtkWidget *combo_box) { gint value; @@ -395,13 +445,13 @@ gimp_prop_enum_combo_box_notify (GObject NULL); g_signal_handlers_block_by_func (combo_box, - gimp_prop_enum_combo_box_callback, + gimp_prop_int_combo_box_callback, config); gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo_box), value); g_signal_handlers_unblock_by_func (combo_box, - gimp_prop_enum_combo_box_callback, + gimp_prop_int_combo_box_callback, config); } Index: app/widgets/gimppropwidgets.h =================================================================== RCS file: /cvs/gnome/gimp/app/widgets/gimppropwidgets.h,v retrieving revision 1.22 diff -u -p -r1.22 gimppropwidgets.h --- app/widgets/gimppropwidgets.h 24 Jun 2004 22:23:05 -0000 1.22 +++ app/widgets/gimppropwidgets.h 7 Dec 2004 22:02:04 -0000 @@ -39,6 +39,13 @@ GtkWidget * gimp_prop_boolean_radio_ const gchar *false_text); +/* GParamInt, GParamEnum */ + +GtkWidget * gimp_prop_int_combo_box_new (GObject *config, + const gchar *property_name, + GimpIntStore *int_store); + + /* GParamEnum */ GtkWidget * gimp_prop_enum_combo_box_new (GObject *config, Index: modules/controller_midi.c =================================================================== RCS file: /cvs/gnome/gimp/modules/controller_midi.c,v retrieving revision 1.16 diff -u -p -r1.16 controller_midi.c --- modules/controller_midi.c 25 Nov 2004 12:57:17 -0000 1.16 +++ modules/controller_midi.c 7 Dec 2004 22:02:04 -0000 @@ -54,6 +54,8 @@ enum { PROP_0, PROP_DEVICE, + PROP_PORT, + PROP_PORT_VALUES, PROP_CHANNEL }; @@ -81,6 +83,9 @@ struct _ControllerMidi #ifdef HAVE_ALSA snd_seq_t *sequencer; guint seq_id; + + gint port; + GtkListStore *port_values; #endif /* midi status */ @@ -123,6 +128,7 @@ static const gchar * midi_get_event_blur static gboolean midi_set_device (ControllerMidi *controller, const gchar *device); static void midi_event (ControllerMidi *midi, + gint port, gint channel, gint event_id, gdouble value); @@ -246,6 +252,23 @@ midi_class_init (ControllerMidiClass *kl g_free (blurb); +#ifdef HAVE_ALSA + g_object_class_install_property (object_class, PROP_PORT, + g_param_spec_int ("port", + _("ALSA Port:"), + _("The ALSA port to read events from."), + -1, G_MAXINT, -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_PORT_VALUES, + g_param_spec_object ("port-values", + "Port Values", + "The ALSA ports available for 'port'.", + GIMP_TYPE_INT_STORE, + G_PARAM_READABLE)); +#endif /* HAVE ALSA */ + g_object_class_install_property (object_class, PROP_CHANNEL, g_param_spec_int ("channel", _("Channel:"), @@ -270,9 +293,23 @@ midi_init (ControllerMidi *midi) midi->midi_channel = -1; midi->io = NULL; midi->io_id = 0; + #ifdef HAVE_ALSA midi->sequencer = NULL; midi->seq_id = 0; + + midi->port = -1; + midi->port_values = gimp_int_store_new (); + + { + GtkTreeIter iter; + + gtk_list_store_append (GTK_LIST_STORE (midi->port_values), &iter); + gtk_list_store_set (GTK_LIST_STORE (midi->port_values), &iter, + GIMP_INT_STORE_VALUE, -1, + GIMP_INT_STORE_LABEL, _("All subscribed ports"), + -1); + } #endif midi->swallow = TRUE; /* get rid of data bytes at start of stream */ @@ -291,6 +328,14 @@ midi_dispose (GObject *object) midi_set_device (midi, NULL); +#ifdef HAVE_ALSA + if (midi->port_values) + { + g_object_unref (midi->port_values); + midi->port_values = NULL; + } +#endif + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -307,6 +352,11 @@ midi_set_property (GObject *object, case PROP_DEVICE: midi_set_device (midi, g_value_get_string (value)); break; +#ifdef HAVE_ALSA + case PROP_PORT: + midi->port = g_value_get_int (value); + break; +#endif case PROP_CHANNEL: midi->midi_channel = g_value_get_int (value); break; @@ -329,6 +379,14 @@ midi_get_property (GObject *object, case PROP_DEVICE: g_value_set_string (value, midi->device); break; +#ifdef HAVE_ALSA + case PROP_PORT: + g_value_set_int (value, midi->port); + break; + case PROP_PORT_VALUES: + g_value_set_object (value, midi->port_values); + break; +#endif case PROP_CHANNEL: g_value_set_int (value, midi->midi_channel); break; @@ -441,7 +499,6 @@ midi_set_device (ControllerMidi *midi, if (! g_ascii_strcasecmp (midi->device, "alsa")) { GAlsaSource *event_source; - gchar *alsa; gchar *state; gint ret; @@ -449,12 +506,13 @@ midi_set_device (ControllerMidi *midi, SND_SEQ_OPEN_INPUT, 0); if (ret >= 0) { - snd_seq_set_client_name (midi->sequencer, "The GIMP"); + snd_seq_set_client_name (midi->sequencer, + "The GIMP"); ret = snd_seq_create_simple_port (midi->sequencer, - "The GIMP midi controller", + "The GIMP input", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_APPLICATION); + SND_SEQ_PORT_TYPE_MIDI_GENERIC); } if (ret < 0) @@ -473,13 +531,11 @@ midi_set_device (ControllerMidi *midi, return FALSE; } - /* hack to avoid new message to translate */ - alsa = g_strdup_printf ("ALSA (%d:%d)", - snd_seq_client_id (midi->sequencer), - ret); - state = g_strdup_printf (_("Reading from %s"), alsa); - g_free (alsa); - + state = g_strdup_printf ("Reading on ALSA port %d:%d (%s/%s)", + snd_seq_client_id (midi->sequencer), + ret, + "The GIMP", + "The GIMP input"); g_object_set (midi, "state", state, NULL); g_free (state); @@ -533,10 +589,18 @@ midi_set_device (ControllerMidi *midi, static void midi_event (ControllerMidi *midi, + gint port, gint channel, gint event_id, gdouble value) { +#ifdef HAVE_ALSA + if (port != -1 && + midi->port != -1 && + port != midi->port) + return; +#endif + if (channel == -1 || midi->midi_channel == -1 || channel == midi->midi_channel) @@ -736,7 +800,7 @@ midi_read_event (GIOChannel *io, midi->channel, midi->key, midi->velocity)); - midi_event (midi, midi->channel, midi->key, + midi_event (midi, -1, midi->channel, midi->key, (gdouble) midi->velocity / 127.0); } else if (midi->command == 0x8) @@ -744,7 +808,7 @@ midi_read_event (GIOChannel *io, D (g_print ("MIDI (ch %02d): note off (%02x vel %02x)\n", midi->channel, midi->key, midi->velocity)); - midi_event (midi, midi->channel, midi->key + 128, + midi_event (midi, -1, midi->channel, midi->key + 128, (gdouble) midi->velocity / 127.0); } else @@ -771,7 +835,7 @@ midi_read_event (GIOChannel *io, D (g_print ("MIDI (ch %02d): controller %d (value %d)\n", midi->channel, midi->key, midi->velocity)); - midi_event (midi, midi->channel, midi->key + 128 + 128, + midi_event (midi, -1, midi->channel, midi->key + 128 + 128, (gdouble) midi->velocity / 127.0); midi->key = -1; @@ -849,12 +913,11 @@ midi_alsa_dispatch (GSource *source, gpointer user_data) { ControllerMidi *midi = CONTROLLER_MIDI (((GAlsaSource *) source)->controller); - snd_seq_event_t *event; - snd_seq_client_info_t *client_info; - snd_seq_port_info_t *port_info; if (snd_seq_event_input_pending (midi->sequencer, 1) > 0) { + snd_seq_event_t *event; + snd_seq_event_input (midi->sequencer, &event); if (event->type == SND_SEQ_EVENT_NOTEON && @@ -864,40 +927,76 @@ midi_alsa_dispatch (GSource *source, switch (event->type) { case SND_SEQ_EVENT_NOTEON: - midi_event (midi, midi->channel, event->data.note.note, + midi_event (midi, + (event->source.client << 8) + event->source.port, + event->data.note.channel, + event->data.note.note, (gdouble) event->data.note.velocity / 127.0); break; case SND_SEQ_EVENT_NOTEOFF: - midi_event (midi, midi->channel, event->data.note.note + 128, + midi_event (midi, + (event->source.client << 8) + event->source.port, + event->data.note.channel, + event->data.note.note + 128, (gdouble) event->data.note.velocity / 127.0); break; case SND_SEQ_EVENT_CONTROLLER: - midi_event (midi, midi->channel, event->data.control.param + 256, + midi_event (midi, + (event->source.client << 8) + event->source.port, + event->data.control.channel, + event->data.control.param + 256, (gdouble) event->data.control.value / 127.0); break; case SND_SEQ_EVENT_PORT_SUBSCRIBED: - snd_seq_client_info_alloca (&client_info); - snd_seq_port_info_alloca (&port_info); - snd_seq_get_any_client_info (midi->sequencer, + { + snd_seq_client_info_t *client_info; + snd_seq_port_info_t *port_info; + gchar *port_name; + GtkTreeIter iter; + + snd_seq_client_info_alloca (&client_info); + snd_seq_port_info_alloca (&port_info); + snd_seq_get_any_client_info (midi->sequencer, + event->data.connect.sender.client, + client_info); + snd_seq_get_any_port_info (midi->sequencer, event->data.connect.sender.client, - client_info); - snd_seq_get_any_port_info (midi->sequencer, - event->data.connect.sender.client, - event->data.connect.sender.port, - port_info); - /* - * g_printerr ("subscribed to \"%s:%s\"\n", - * snd_seq_client_info_get_name (client_info), - * snd_seq_port_info_get_name (port_info)); - */ + event->data.connect.sender.port, + port_info); + + port_name = g_strdup_printf ("%d:%d (%s/%s)", + snd_seq_client_info_get_client (client_info), + snd_seq_port_info_get_port (port_info), + snd_seq_client_info_get_name (client_info), + snd_seq_port_info_get_name (port_info)); + + gtk_list_store_append (GTK_LIST_STORE (midi->port_values), &iter); + gtk_list_store_set (GTK_LIST_STORE (midi->port_values), &iter, + GIMP_INT_STORE_VALUE, + (event->data.connect.sender.client << 8) + + event->data.connect.sender.port, + GIMP_INT_STORE_LABEL, port_name, + -1); + g_free (port_name); + } break; case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: - /* g_printerr ("unsubscribed\n"); - */ + { + GtkTreeIter iter; + + if (gimp_int_store_lookup_by_value (GTK_TREE_MODEL (midi->port_values), + (event->data.connect.sender.client << 8) + + event->data.connect.sender.port, + &iter)) + { + gtk_list_store_remove (GTK_LIST_STORE (midi->port_values), + &iter); + } + } break; default: