nkeynes@447: /** nkeynes@561: * $Id$ nkeynes@447: * nkeynes@447: * Define the main (emu) GTK window, along with its menubars, nkeynes@447: * toolbars, etc. nkeynes@447: * nkeynes@447: * Copyright (c) 2005 Nathan Keynes. nkeynes@447: * nkeynes@447: * This program is free software; you can redistribute it and/or modify nkeynes@447: * it under the terms of the GNU General Public License as published by nkeynes@447: * the Free Software Foundation; either version 2 of the License, or nkeynes@447: * (at your option) any later version. nkeynes@447: * nkeynes@447: * This program is distributed in the hope that it will be useful, nkeynes@447: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@447: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@447: * GNU General Public License for more details. nkeynes@447: */ nkeynes@447: nkeynes@447: #include nkeynes@669: #include nkeynes@447: #include nkeynes@460: #include nkeynes@447: nkeynes@614: #include "lxdream.h" nkeynes@614: #include "display.h" nkeynes@537: #include "gtkui/gtkui.h" nkeynes@447: #include "maple/maple.h" nkeynes@447: nkeynes@447: #define MAX_DEVICES 4 nkeynes@447: nkeynes@455: static void controller_device_configure(maple_device_t device); nkeynes@455: nkeynes@455: struct maple_config_class { nkeynes@455: const char *name; nkeynes@455: void (*config_func)(maple_device_t device); nkeynes@455: }; nkeynes@455: nkeynes@447: typedef struct maple_slot_data { nkeynes@447: maple_device_t old_device; nkeynes@447: maple_device_t new_device; nkeynes@447: GtkWidget *button; nkeynes@447: GtkWidget *combo; nkeynes@447: } *maple_slot_data_t; nkeynes@447: nkeynes@455: static struct maple_config_class maple_device_config[] = { nkeynes@736: { "Sega Controller", controller_device_configure }, nkeynes@852: { "Sega Lightgun", controller_device_configure }, nkeynes@736: { NULL, NULL } }; nkeynes@455: nkeynes@447: static struct maple_slot_data maple_data[MAX_DEVICES]; nkeynes@447: nkeynes@614: static void config_keysym_hook( void *data, const gchar *keysym ) nkeynes@614: { nkeynes@614: GtkWidget *widget = (GtkWidget *)data; nkeynes@614: gtk_entry_set_text( GTK_ENTRY(widget), keysym ); nkeynes@614: g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) ); nkeynes@614: input_set_keysym_hook(NULL, NULL); nkeynes@614: } nkeynes@614: nkeynes@460: static gboolean config_key_buttonpress( GtkWidget *widget, GdkEventButton *event, gpointer user_data ) nkeynes@460: { nkeynes@460: gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode")); nkeynes@849: if( keypress_mode ) { nkeynes@849: gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, event->button); nkeynes@849: if( keysym != NULL ) { nkeynes@849: config_keysym_hook( widget, keysym ); nkeynes@849: g_free(keysym); nkeynes@849: } nkeynes@849: return TRUE; nkeynes@849: } else { nkeynes@736: gtk_entry_set_text( GTK_ENTRY(widget), _("") ); nkeynes@736: g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) ); nkeynes@736: input_set_keysym_hook(config_keysym_hook, widget); nkeynes@460: } nkeynes@460: return FALSE; nkeynes@460: } nkeynes@460: nkeynes@455: static gboolean config_key_keypress( GtkWidget *widget, GdkEventKey *event, gpointer user_data ) nkeynes@455: { nkeynes@460: gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode")); nkeynes@460: if( keypress_mode ) { nkeynes@736: if( event->keyval == GDK_Escape ) { nkeynes@736: gtk_entry_set_text( GTK_ENTRY(widget), "" ); nkeynes@736: g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) ); nkeynes@736: return TRUE; nkeynes@736: } nkeynes@736: GdkKeymap *keymap = gdk_keymap_get_default(); nkeynes@736: guint keyval; nkeynes@736: nkeynes@736: gdk_keymap_translate_keyboard_state( keymap, event->hardware_keycode, 0, 0, &keyval, nkeynes@736: NULL, NULL, NULL ); nkeynes@736: gtk_entry_set_text( GTK_ENTRY(widget), gdk_keyval_name(keyval) ); nkeynes@736: g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) ); nkeynes@736: input_set_keysym_hook(NULL, NULL); nkeynes@736: return TRUE; nkeynes@460: } else { nkeynes@736: switch( event->keyval ) { nkeynes@736: case GDK_Return: nkeynes@736: case GDK_KP_Enter: nkeynes@736: gtk_entry_set_text( GTK_ENTRY(widget), _("") ); nkeynes@736: g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) ); nkeynes@736: input_set_keysym_hook(config_keysym_hook, widget); nkeynes@736: return TRUE; nkeynes@736: case GDK_BackSpace: nkeynes@736: case GDK_Delete: nkeynes@736: gtk_entry_set_text( GTK_ENTRY(widget), "" ); nkeynes@736: return TRUE; nkeynes@736: } nkeynes@736: return FALSE; nkeynes@460: } nkeynes@736: nkeynes@455: } nkeynes@447: nkeynes@455: static void controller_config_done( GtkWidget *panel, gboolean isOK ) nkeynes@455: { nkeynes@460: if( isOK ) { nkeynes@736: maple_device_t device = (maple_device_t)gtk_object_get_data( GTK_OBJECT(panel), "maple_device" ); nkeynes@736: lxdream_config_entry_t conf = device->get_config(device); nkeynes@736: int i; nkeynes@736: for( i=0; conf[i].key != NULL; i++ ) { nkeynes@736: char buf[64]; nkeynes@736: GtkWidget *entry1, *entry2; nkeynes@736: const gchar *key1, *key2; nkeynes@736: snprintf( buf, sizeof(buf), "%s.1", conf[i].key ); nkeynes@736: entry1 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf))); nkeynes@736: key1 = gtk_entry_get_text(GTK_ENTRY(entry1)); nkeynes@736: snprintf( buf, sizeof(buf), "%s.2", conf[i].key ); nkeynes@736: entry2 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf))); nkeynes@736: key2 = gtk_entry_get_text(GTK_ENTRY(entry2)); nkeynes@736: if( key1 == NULL || key1[0] == '\0') { nkeynes@736: lxdream_set_config_value( &conf[i], key2 ); nkeynes@736: } else if( key2 == NULL || key2[0] == '\0') { nkeynes@736: lxdream_set_config_value( &conf[i], key1 ); nkeynes@736: } else { nkeynes@736: char buf[64]; nkeynes@736: snprintf( buf, sizeof(buf), "%s, %s", key1, key2 ); nkeynes@736: lxdream_set_config_value( &conf[i], buf ); nkeynes@736: } nkeynes@736: } nkeynes@460: } nkeynes@614: input_set_keysym_hook(NULL, NULL); nkeynes@455: } nkeynes@455: nkeynes@455: static void controller_device_configure( maple_device_t device ) nkeynes@455: { nkeynes@770: lxdream_config_entry_t conf = maple_get_device_config(device); nkeynes@455: int count, i; nkeynes@455: for( count=0; conf[count].key != NULL; count++ ); nkeynes@455: nkeynes@455: GtkWidget *table = gtk_table_new( (count+1)>>1, 6, FALSE ); nkeynes@460: GList *focus_chain = NULL; nkeynes@460: gtk_object_set_data( GTK_OBJECT(table), "maple_device", device ); nkeynes@455: for( i=0; i= (count+1)>>1 ) { nkeynes@736: x = 3; nkeynes@736: y -= (count+1)>>1; nkeynes@736: } nkeynes@770: gtk_table_attach( GTK_TABLE(table), gtk_label_new(gettext(conf[i].label)), x, x+1, y, y+1, nkeynes@736: GTK_SHRINK, GTK_SHRINK, 0, 0 ); nkeynes@736: text = gtk_entry_new(); nkeynes@736: gtk_entry_set_width_chars( GTK_ENTRY(text), 11 ); nkeynes@736: gtk_entry_set_editable( GTK_ENTRY(text), FALSE ); nkeynes@736: g_signal_connect( text, "key_press_event", nkeynes@736: G_CALLBACK(config_key_keypress), NULL ); nkeynes@736: g_signal_connect( text, "button_press_event", nkeynes@736: G_CALLBACK(config_key_buttonpress), NULL ); nkeynes@736: snprintf( buf, sizeof(buf), "%s.1", conf[i].key ); nkeynes@736: g_object_set_data( G_OBJECT(text), "keypress_mode", GINT_TO_POINTER(FALSE) ); nkeynes@736: g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text ); nkeynes@736: gtk_table_attach_defaults( GTK_TABLE(table), text, x+1, x+2, y, y+1); nkeynes@736: focus_chain = g_list_append( focus_chain, text ); nkeynes@736: text2 = gtk_entry_new(); nkeynes@736: gtk_entry_set_width_chars( GTK_ENTRY(text2), 11 ); nkeynes@736: gtk_entry_set_editable( GTK_ENTRY(text2), FALSE ); nkeynes@736: g_signal_connect( text2, "key_press_event", nkeynes@736: G_CALLBACK(config_key_keypress), NULL ); nkeynes@736: g_signal_connect( text2, "button_press_event", nkeynes@736: G_CALLBACK(config_key_buttonpress), NULL ); nkeynes@736: snprintf( buf, sizeof(buf), "%s.2", conf[i].key ); nkeynes@736: g_object_set_data( G_OBJECT(text2), "keypress_mode", GINT_TO_POINTER(FALSE) ); nkeynes@736: g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text2 ); nkeynes@736: gtk_table_attach_defaults( GTK_TABLE(table), text2, x+2, x+3, y, y+1); nkeynes@736: focus_chain = g_list_append( focus_chain, text2 ); nkeynes@736: if( conf[i].value != NULL ) { nkeynes@736: gchar **parts = g_strsplit(conf[i].value,",",3); nkeynes@736: if( parts[0] != NULL ) { nkeynes@736: gtk_entry_set_text( GTK_ENTRY(text), g_strstrip(parts[0]) ); nkeynes@736: if( parts[1] != NULL ) { nkeynes@736: gtk_entry_set_text( GTK_ENTRY(text2), g_strstrip(parts[1]) ); nkeynes@736: } nkeynes@736: } nkeynes@736: g_strfreev(parts); nkeynes@736: } nkeynes@455: } nkeynes@460: gtk_container_set_focus_chain( GTK_CONTAINER(table), focus_chain ); nkeynes@508: gtk_gui_run_property_dialog( _("Controller Configuration"), table, controller_config_done ); nkeynes@455: } nkeynes@455: nkeynes@455: gboolean maple_properties_activated( GtkButton *button, gpointer user_data ) nkeynes@447: { nkeynes@447: maple_slot_data_t data = (maple_slot_data_t)user_data; nkeynes@455: if( data->new_device != NULL ) { nkeynes@736: int i; nkeynes@736: for( i=0; maple_device_config[i].name != NULL; i++ ) { nkeynes@736: if( strcmp(data->new_device->device_class->name, maple_device_config[i].name) == 0 ) { nkeynes@736: if( data->new_device == data->old_device ) { nkeynes@736: // Make a copy at this point if we haven't already nkeynes@736: data->new_device = data->old_device->clone(data->old_device); nkeynes@736: } nkeynes@736: maple_device_config[i].config_func(data->new_device); nkeynes@736: break; nkeynes@736: } nkeynes@736: } nkeynes@736: if( maple_device_config[i].name == NULL ) { nkeynes@736: gui_error_dialog( _("No configuration page available for device type") ); nkeynes@736: } nkeynes@455: } nkeynes@455: return TRUE; nkeynes@447: } nkeynes@447: nkeynes@455: gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data ) nkeynes@447: { nkeynes@447: maple_slot_data_t data = (maple_slot_data_t)user_data; nkeynes@447: int active = gtk_combo_box_get_active(combo); nkeynes@608: gboolean has_config = FALSE; nkeynes@447: if( active != 0 ) { nkeynes@736: gchar *devname = gtk_combo_box_get_active_text(combo); nkeynes@736: const maple_device_class_t devclz = maple_get_device_class(devname); nkeynes@736: assert(devclz != NULL); nkeynes@736: if( data->new_device != NULL ) { nkeynes@736: if( data->new_device->device_class != devclz ) { nkeynes@736: if( data->new_device != data->old_device ) { nkeynes@736: data->new_device->destroy(data->new_device); nkeynes@736: } nkeynes@736: data->new_device = maple_new_device(devname); nkeynes@736: } nkeynes@736: } else { nkeynes@736: data->new_device = maple_new_device(devname); nkeynes@736: } nkeynes@736: has_config = data->new_device != NULL && data->new_device->get_config != NULL; nkeynes@447: } else { nkeynes@736: if( data->new_device != NULL && data->new_device != data->old_device ) { nkeynes@736: data->new_device->destroy(data->new_device); nkeynes@736: } nkeynes@736: data->new_device = NULL; nkeynes@447: } nkeynes@608: gtk_widget_set_sensitive(data->button, has_config); nkeynes@455: return TRUE; nkeynes@447: } nkeynes@447: nkeynes@460: void maple_dialog_done( GtkWidget *panel, gboolean isOK ) nkeynes@447: { nkeynes@460: if( isOK ) { nkeynes@736: int i; nkeynes@736: for( i=0; idestroy(maple_data[i].new_device); nkeynes@736: } nkeynes@736: } nkeynes@447: } nkeynes@447: nkeynes@447: } nkeynes@447: nkeynes@455: GtkWidget *maple_panel_new() nkeynes@447: { nkeynes@447: GtkWidget *table = gtk_table_new(4, 3, TRUE); nkeynes@447: int i,j; nkeynes@447: const struct maple_device_class **devices = maple_get_device_classes(); nkeynes@447: nkeynes@447: for( i=0; i< MAX_DEVICES; i++ ) { nkeynes@764: char buf[16]; nkeynes@736: GtkWidget *combo, *button; nkeynes@736: int active = 0; nkeynes@736: maple_device_t device = maple_get_device(i,0); nkeynes@764: snprintf( buf, sizeof(buf), _("Slot %d."), i ); nkeynes@736: gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, i, i+1 ); nkeynes@736: combo = gtk_combo_box_new_text(); nkeynes@736: gtk_combo_box_append_text( GTK_COMBO_BOX(combo), _("") ); nkeynes@736: for( j=0; devices[j] != NULL; j++ ) { nkeynes@736: gtk_combo_box_append_text(GTK_COMBO_BOX(combo), devices[j]->name); nkeynes@736: if( device != NULL && device->device_class == devices[j] ) { nkeynes@736: active = j+1; nkeynes@736: } nkeynes@736: } nkeynes@736: gtk_combo_box_set_active(GTK_COMBO_BOX(combo), active); nkeynes@736: gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, i, i+1 ); nkeynes@736: button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES ); nkeynes@736: gtk_widget_set_sensitive(button, active != 0 && device->get_config != NULL); nkeynes@736: gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, i, i+1 ); nkeynes@447: nkeynes@736: maple_data[i].old_device = device; nkeynes@736: maple_data[i].new_device = device; nkeynes@736: maple_data[i].combo = combo; nkeynes@736: maple_data[i].button = button; nkeynes@736: g_signal_connect( button, "clicked", nkeynes@736: G_CALLBACK( maple_properties_activated ), &maple_data[i] ); nkeynes@736: g_signal_connect( combo, "changed", nkeynes@736: G_CALLBACK( maple_device_changed ), &maple_data[i] ); nkeynes@447: nkeynes@447: } nkeynes@447: return table; nkeynes@447: } nkeynes@447: nkeynes@460: void maple_dialog_run( ) nkeynes@447: { nkeynes@508: gtk_gui_run_property_dialog( _("Controller Settings"), maple_panel_new(), maple_dialog_done ); nkeynes@447: }