nkeynes@447 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
nkeynes@447 | 3 | *
|
nkeynes@447 | 4 | * Define the main (emu) GTK window, along with its menubars,
|
nkeynes@447 | 5 | * toolbars, etc.
|
nkeynes@447 | 6 | *
|
nkeynes@447 | 7 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@447 | 8 | *
|
nkeynes@447 | 9 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@447 | 10 | * it under the terms of the GNU General Public License as published by
|
nkeynes@447 | 11 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@447 | 12 | * (at your option) any later version.
|
nkeynes@447 | 13 | *
|
nkeynes@447 | 14 | * This program is distributed in the hope that it will be useful,
|
nkeynes@447 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@447 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@447 | 17 | * GNU General Public License for more details.
|
nkeynes@447 | 18 | */
|
nkeynes@447 | 19 |
|
nkeynes@447 | 20 | #include <assert.h>
|
nkeynes@669 | 21 | #include <string.h>
|
nkeynes@447 | 22 | #include <gtk/gtk.h>
|
nkeynes@460 | 23 | #include <gdk/gdkkeysyms.h>
|
nkeynes@447 | 24 |
|
nkeynes@614 | 25 | #include "lxdream.h"
|
nkeynes@614 | 26 | #include "display.h"
|
nkeynes@537 | 27 | #include "gtkui/gtkui.h"
|
nkeynes@447 | 28 | #include "maple/maple.h"
|
nkeynes@447 | 29 |
|
nkeynes@447 | 30 | #define MAX_DEVICES 4
|
nkeynes@447 | 31 |
|
nkeynes@455 | 32 | static void controller_device_configure(maple_device_t device);
|
nkeynes@455 | 33 |
|
nkeynes@455 | 34 | struct maple_config_class {
|
nkeynes@455 | 35 | const char *name;
|
nkeynes@455 | 36 | void (*config_func)(maple_device_t device);
|
nkeynes@455 | 37 | };
|
nkeynes@455 | 38 |
|
nkeynes@447 | 39 | typedef struct maple_slot_data {
|
nkeynes@447 | 40 | maple_device_t old_device;
|
nkeynes@447 | 41 | maple_device_t new_device;
|
nkeynes@447 | 42 | GtkWidget *button;
|
nkeynes@447 | 43 | GtkWidget *combo;
|
nkeynes@447 | 44 | } *maple_slot_data_t;
|
nkeynes@447 | 45 |
|
nkeynes@455 | 46 | static struct maple_config_class maple_device_config[] = {
|
nkeynes@736 | 47 | { "Sega Controller", controller_device_configure },
|
nkeynes@852 | 48 | { "Sega Lightgun", controller_device_configure },
|
nkeynes@736 | 49 | { NULL, NULL } };
|
nkeynes@455 | 50 |
|
nkeynes@447 | 51 | static struct maple_slot_data maple_data[MAX_DEVICES];
|
nkeynes@447 | 52 |
|
nkeynes@614 | 53 | static void config_keysym_hook( void *data, const gchar *keysym )
|
nkeynes@614 | 54 | {
|
nkeynes@614 | 55 | GtkWidget *widget = (GtkWidget *)data;
|
nkeynes@614 | 56 | gtk_entry_set_text( GTK_ENTRY(widget), keysym );
|
nkeynes@614 | 57 | g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
|
nkeynes@614 | 58 | input_set_keysym_hook(NULL, NULL);
|
nkeynes@614 | 59 | }
|
nkeynes@614 | 60 |
|
nkeynes@460 | 61 | static gboolean config_key_buttonpress( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
|
nkeynes@460 | 62 | {
|
nkeynes@460 | 63 | gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
|
nkeynes@849 | 64 | if( keypress_mode ) {
|
nkeynes@849 | 65 | gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, event->button);
|
nkeynes@849 | 66 | if( keysym != NULL ) {
|
nkeynes@849 | 67 | config_keysym_hook( widget, keysym );
|
nkeynes@849 | 68 | g_free(keysym);
|
nkeynes@849 | 69 | }
|
nkeynes@849 | 70 | return TRUE;
|
nkeynes@849 | 71 | } else {
|
nkeynes@736 | 72 | gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
|
nkeynes@736 | 73 | g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
|
nkeynes@736 | 74 | input_set_keysym_hook(config_keysym_hook, widget);
|
nkeynes@460 | 75 | }
|
nkeynes@460 | 76 | return FALSE;
|
nkeynes@460 | 77 | }
|
nkeynes@460 | 78 |
|
nkeynes@455 | 79 | static gboolean config_key_keypress( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
|
nkeynes@455 | 80 | {
|
nkeynes@460 | 81 | gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
|
nkeynes@460 | 82 | if( keypress_mode ) {
|
nkeynes@736 | 83 | if( event->keyval == GDK_Escape ) {
|
nkeynes@736 | 84 | gtk_entry_set_text( GTK_ENTRY(widget), "" );
|
nkeynes@736 | 85 | g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
|
nkeynes@736 | 86 | return TRUE;
|
nkeynes@736 | 87 | }
|
nkeynes@736 | 88 | GdkKeymap *keymap = gdk_keymap_get_default();
|
nkeynes@736 | 89 | guint keyval;
|
nkeynes@736 | 90 |
|
nkeynes@736 | 91 | gdk_keymap_translate_keyboard_state( keymap, event->hardware_keycode, 0, 0, &keyval,
|
nkeynes@736 | 92 | NULL, NULL, NULL );
|
nkeynes@736 | 93 | gtk_entry_set_text( GTK_ENTRY(widget), gdk_keyval_name(keyval) );
|
nkeynes@736 | 94 | g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
|
nkeynes@736 | 95 | input_set_keysym_hook(NULL, NULL);
|
nkeynes@736 | 96 | return TRUE;
|
nkeynes@460 | 97 | } else {
|
nkeynes@736 | 98 | switch( event->keyval ) {
|
nkeynes@736 | 99 | case GDK_Return:
|
nkeynes@736 | 100 | case GDK_KP_Enter:
|
nkeynes@736 | 101 | gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
|
nkeynes@736 | 102 | g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
|
nkeynes@736 | 103 | input_set_keysym_hook(config_keysym_hook, widget);
|
nkeynes@736 | 104 | return TRUE;
|
nkeynes@736 | 105 | case GDK_BackSpace:
|
nkeynes@736 | 106 | case GDK_Delete:
|
nkeynes@736 | 107 | gtk_entry_set_text( GTK_ENTRY(widget), "" );
|
nkeynes@736 | 108 | return TRUE;
|
nkeynes@736 | 109 | }
|
nkeynes@736 | 110 | return FALSE;
|
nkeynes@460 | 111 | }
|
nkeynes@736 | 112 |
|
nkeynes@455 | 113 | }
|
nkeynes@447 | 114 |
|
nkeynes@455 | 115 | static void controller_config_done( GtkWidget *panel, gboolean isOK )
|
nkeynes@455 | 116 | {
|
nkeynes@460 | 117 | if( isOK ) {
|
nkeynes@736 | 118 | maple_device_t device = (maple_device_t)gtk_object_get_data( GTK_OBJECT(panel), "maple_device" );
|
nkeynes@736 | 119 | lxdream_config_entry_t conf = device->get_config(device);
|
nkeynes@736 | 120 | int i;
|
nkeynes@736 | 121 | for( i=0; conf[i].key != NULL; i++ ) {
|
nkeynes@736 | 122 | char buf[64];
|
nkeynes@736 | 123 | GtkWidget *entry1, *entry2;
|
nkeynes@736 | 124 | const gchar *key1, *key2;
|
nkeynes@736 | 125 | snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
|
nkeynes@736 | 126 | entry1 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
|
nkeynes@736 | 127 | key1 = gtk_entry_get_text(GTK_ENTRY(entry1));
|
nkeynes@736 | 128 | snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
|
nkeynes@736 | 129 | entry2 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
|
nkeynes@736 | 130 | key2 = gtk_entry_get_text(GTK_ENTRY(entry2));
|
nkeynes@736 | 131 | if( key1 == NULL || key1[0] == '\0') {
|
nkeynes@736 | 132 | lxdream_set_config_value( &conf[i], key2 );
|
nkeynes@736 | 133 | } else if( key2 == NULL || key2[0] == '\0') {
|
nkeynes@736 | 134 | lxdream_set_config_value( &conf[i], key1 );
|
nkeynes@736 | 135 | } else {
|
nkeynes@736 | 136 | char buf[64];
|
nkeynes@736 | 137 | snprintf( buf, sizeof(buf), "%s, %s", key1, key2 );
|
nkeynes@736 | 138 | lxdream_set_config_value( &conf[i], buf );
|
nkeynes@736 | 139 | }
|
nkeynes@736 | 140 | }
|
nkeynes@460 | 141 | }
|
nkeynes@614 | 142 | input_set_keysym_hook(NULL, NULL);
|
nkeynes@455 | 143 | }
|
nkeynes@455 | 144 |
|
nkeynes@455 | 145 | static void controller_device_configure( maple_device_t device )
|
nkeynes@455 | 146 | {
|
nkeynes@770 | 147 | lxdream_config_entry_t conf = maple_get_device_config(device);
|
nkeynes@455 | 148 | int count, i;
|
nkeynes@455 | 149 | for( count=0; conf[count].key != NULL; count++ );
|
nkeynes@455 | 150 |
|
nkeynes@455 | 151 | GtkWidget *table = gtk_table_new( (count+1)>>1, 6, FALSE );
|
nkeynes@460 | 152 | GList *focus_chain = NULL;
|
nkeynes@460 | 153 | gtk_object_set_data( GTK_OBJECT(table), "maple_device", device );
|
nkeynes@455 | 154 | for( i=0; i<count; i++ ) {
|
nkeynes@736 | 155 | GtkWidget *text, *text2;
|
nkeynes@736 | 156 | char buf[64];
|
nkeynes@736 | 157 | int x=0;
|
nkeynes@736 | 158 | int y=i;
|
nkeynes@736 | 159 | if( i >= (count+1)>>1 ) {
|
nkeynes@736 | 160 | x = 3;
|
nkeynes@736 | 161 | y -= (count+1)>>1;
|
nkeynes@736 | 162 | }
|
nkeynes@770 | 163 | gtk_table_attach( GTK_TABLE(table), gtk_label_new(gettext(conf[i].label)), x, x+1, y, y+1,
|
nkeynes@736 | 164 | GTK_SHRINK, GTK_SHRINK, 0, 0 );
|
nkeynes@736 | 165 | text = gtk_entry_new();
|
nkeynes@736 | 166 | gtk_entry_set_width_chars( GTK_ENTRY(text), 11 );
|
nkeynes@736 | 167 | gtk_entry_set_editable( GTK_ENTRY(text), FALSE );
|
nkeynes@736 | 168 | g_signal_connect( text, "key_press_event",
|
nkeynes@736 | 169 | G_CALLBACK(config_key_keypress), NULL );
|
nkeynes@736 | 170 | g_signal_connect( text, "button_press_event",
|
nkeynes@736 | 171 | G_CALLBACK(config_key_buttonpress), NULL );
|
nkeynes@736 | 172 | snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
|
nkeynes@736 | 173 | g_object_set_data( G_OBJECT(text), "keypress_mode", GINT_TO_POINTER(FALSE) );
|
nkeynes@736 | 174 | g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text );
|
nkeynes@736 | 175 | gtk_table_attach_defaults( GTK_TABLE(table), text, x+1, x+2, y, y+1);
|
nkeynes@736 | 176 | focus_chain = g_list_append( focus_chain, text );
|
nkeynes@736 | 177 | text2 = gtk_entry_new();
|
nkeynes@736 | 178 | gtk_entry_set_width_chars( GTK_ENTRY(text2), 11 );
|
nkeynes@736 | 179 | gtk_entry_set_editable( GTK_ENTRY(text2), FALSE );
|
nkeynes@736 | 180 | g_signal_connect( text2, "key_press_event",
|
nkeynes@736 | 181 | G_CALLBACK(config_key_keypress), NULL );
|
nkeynes@736 | 182 | g_signal_connect( text2, "button_press_event",
|
nkeynes@736 | 183 | G_CALLBACK(config_key_buttonpress), NULL );
|
nkeynes@736 | 184 | snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
|
nkeynes@736 | 185 | g_object_set_data( G_OBJECT(text2), "keypress_mode", GINT_TO_POINTER(FALSE) );
|
nkeynes@736 | 186 | g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text2 );
|
nkeynes@736 | 187 | gtk_table_attach_defaults( GTK_TABLE(table), text2, x+2, x+3, y, y+1);
|
nkeynes@736 | 188 | focus_chain = g_list_append( focus_chain, text2 );
|
nkeynes@736 | 189 | if( conf[i].value != NULL ) {
|
nkeynes@736 | 190 | gchar **parts = g_strsplit(conf[i].value,",",3);
|
nkeynes@736 | 191 | if( parts[0] != NULL ) {
|
nkeynes@736 | 192 | gtk_entry_set_text( GTK_ENTRY(text), g_strstrip(parts[0]) );
|
nkeynes@736 | 193 | if( parts[1] != NULL ) {
|
nkeynes@736 | 194 | gtk_entry_set_text( GTK_ENTRY(text2), g_strstrip(parts[1]) );
|
nkeynes@736 | 195 | }
|
nkeynes@736 | 196 | }
|
nkeynes@736 | 197 | g_strfreev(parts);
|
nkeynes@736 | 198 | }
|
nkeynes@455 | 199 | }
|
nkeynes@460 | 200 | gtk_container_set_focus_chain( GTK_CONTAINER(table), focus_chain );
|
nkeynes@508 | 201 | gtk_gui_run_property_dialog( _("Controller Configuration"), table, controller_config_done );
|
nkeynes@455 | 202 | }
|
nkeynes@455 | 203 |
|
nkeynes@455 | 204 | gboolean maple_properties_activated( GtkButton *button, gpointer user_data )
|
nkeynes@447 | 205 | {
|
nkeynes@447 | 206 | maple_slot_data_t data = (maple_slot_data_t)user_data;
|
nkeynes@455 | 207 | if( data->new_device != NULL ) {
|
nkeynes@736 | 208 | int i;
|
nkeynes@736 | 209 | for( i=0; maple_device_config[i].name != NULL; i++ ) {
|
nkeynes@736 | 210 | if( strcmp(data->new_device->device_class->name, maple_device_config[i].name) == 0 ) {
|
nkeynes@736 | 211 | if( data->new_device == data->old_device ) {
|
nkeynes@736 | 212 | // Make a copy at this point if we haven't already
|
nkeynes@736 | 213 | data->new_device = data->old_device->clone(data->old_device);
|
nkeynes@736 | 214 | }
|
nkeynes@736 | 215 | maple_device_config[i].config_func(data->new_device);
|
nkeynes@736 | 216 | break;
|
nkeynes@736 | 217 | }
|
nkeynes@736 | 218 | }
|
nkeynes@736 | 219 | if( maple_device_config[i].name == NULL ) {
|
nkeynes@736 | 220 | gui_error_dialog( _("No configuration page available for device type") );
|
nkeynes@736 | 221 | }
|
nkeynes@455 | 222 | }
|
nkeynes@455 | 223 | return TRUE;
|
nkeynes@447 | 224 | }
|
nkeynes@447 | 225 |
|
nkeynes@455 | 226 | gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data )
|
nkeynes@447 | 227 | {
|
nkeynes@447 | 228 | maple_slot_data_t data = (maple_slot_data_t)user_data;
|
nkeynes@447 | 229 | int active = gtk_combo_box_get_active(combo);
|
nkeynes@608 | 230 | gboolean has_config = FALSE;
|
nkeynes@447 | 231 | if( active != 0 ) {
|
nkeynes@736 | 232 | gchar *devname = gtk_combo_box_get_active_text(combo);
|
nkeynes@736 | 233 | const maple_device_class_t devclz = maple_get_device_class(devname);
|
nkeynes@736 | 234 | assert(devclz != NULL);
|
nkeynes@736 | 235 | if( data->new_device != NULL ) {
|
nkeynes@736 | 236 | if( data->new_device->device_class != devclz ) {
|
nkeynes@736 | 237 | if( data->new_device != data->old_device ) {
|
nkeynes@736 | 238 | data->new_device->destroy(data->new_device);
|
nkeynes@736 | 239 | }
|
nkeynes@736 | 240 | data->new_device = maple_new_device(devname);
|
nkeynes@736 | 241 | }
|
nkeynes@736 | 242 | } else {
|
nkeynes@736 | 243 | data->new_device = maple_new_device(devname);
|
nkeynes@736 | 244 | }
|
nkeynes@736 | 245 | has_config = data->new_device != NULL && data->new_device->get_config != NULL;
|
nkeynes@447 | 246 | } else {
|
nkeynes@736 | 247 | if( data->new_device != NULL && data->new_device != data->old_device ) {
|
nkeynes@736 | 248 | data->new_device->destroy(data->new_device);
|
nkeynes@736 | 249 | }
|
nkeynes@736 | 250 | data->new_device = NULL;
|
nkeynes@447 | 251 | }
|
nkeynes@608 | 252 | gtk_widget_set_sensitive(data->button, has_config);
|
nkeynes@455 | 253 | return TRUE;
|
nkeynes@447 | 254 | }
|
nkeynes@447 | 255 |
|
nkeynes@460 | 256 | void maple_dialog_done( GtkWidget *panel, gboolean isOK )
|
nkeynes@447 | 257 | {
|
nkeynes@460 | 258 | if( isOK ) {
|
nkeynes@736 | 259 | int i;
|
nkeynes@736 | 260 | for( i=0; i<MAX_DEVICES; i++ ) {
|
nkeynes@736 | 261 | if( maple_data[i].new_device != maple_data[i].old_device ) {
|
nkeynes@736 | 262 | if( maple_data[i].old_device != NULL ) {
|
nkeynes@736 | 263 | maple_detach_device(i,0);
|
nkeynes@736 | 264 | }
|
nkeynes@736 | 265 | if( maple_data[i].new_device != NULL ) {
|
nkeynes@736 | 266 | maple_attach_device(maple_data[i].new_device, i, 0 );
|
nkeynes@736 | 267 | }
|
nkeynes@736 | 268 | }
|
nkeynes@736 | 269 | }
|
nkeynes@736 | 270 | lxdream_save_config();
|
nkeynes@460 | 271 | } else {
|
nkeynes@736 | 272 | int i;
|
nkeynes@736 | 273 | for( i=0; i<MAX_DEVICES; i++ ) {
|
nkeynes@736 | 274 | if( maple_data[i].new_device != NULL &&
|
nkeynes@736 | 275 | maple_data[i].new_device != maple_data[i].old_device ) {
|
nkeynes@736 | 276 | maple_data[i].new_device->destroy(maple_data[i].new_device);
|
nkeynes@736 | 277 | }
|
nkeynes@736 | 278 | }
|
nkeynes@447 | 279 | }
|
nkeynes@447 | 280 |
|
nkeynes@447 | 281 | }
|
nkeynes@447 | 282 |
|
nkeynes@455 | 283 | GtkWidget *maple_panel_new()
|
nkeynes@447 | 284 | {
|
nkeynes@447 | 285 | GtkWidget *table = gtk_table_new(4, 3, TRUE);
|
nkeynes@447 | 286 | int i,j;
|
nkeynes@447 | 287 | const struct maple_device_class **devices = maple_get_device_classes();
|
nkeynes@447 | 288 |
|
nkeynes@447 | 289 | for( i=0; i< MAX_DEVICES; i++ ) {
|
nkeynes@764 | 290 | char buf[16];
|
nkeynes@736 | 291 | GtkWidget *combo, *button;
|
nkeynes@736 | 292 | int active = 0;
|
nkeynes@736 | 293 | maple_device_t device = maple_get_device(i,0);
|
nkeynes@764 | 294 | snprintf( buf, sizeof(buf), _("Slot %d."), i );
|
nkeynes@736 | 295 | gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, i, i+1 );
|
nkeynes@736 | 296 | combo = gtk_combo_box_new_text();
|
nkeynes@736 | 297 | gtk_combo_box_append_text( GTK_COMBO_BOX(combo), _("<empty>") );
|
nkeynes@736 | 298 | for( j=0; devices[j] != NULL; j++ ) {
|
nkeynes@736 | 299 | gtk_combo_box_append_text(GTK_COMBO_BOX(combo), devices[j]->name);
|
nkeynes@736 | 300 | if( device != NULL && device->device_class == devices[j] ) {
|
nkeynes@736 | 301 | active = j+1;
|
nkeynes@736 | 302 | }
|
nkeynes@736 | 303 | }
|
nkeynes@736 | 304 | gtk_combo_box_set_active(GTK_COMBO_BOX(combo), active);
|
nkeynes@736 | 305 | gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, i, i+1 );
|
nkeynes@736 | 306 | button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES );
|
nkeynes@736 | 307 | gtk_widget_set_sensitive(button, active != 0 && device->get_config != NULL);
|
nkeynes@736 | 308 | gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, i, i+1 );
|
nkeynes@447 | 309 |
|
nkeynes@736 | 310 | maple_data[i].old_device = device;
|
nkeynes@736 | 311 | maple_data[i].new_device = device;
|
nkeynes@736 | 312 | maple_data[i].combo = combo;
|
nkeynes@736 | 313 | maple_data[i].button = button;
|
nkeynes@736 | 314 | g_signal_connect( button, "clicked",
|
nkeynes@736 | 315 | G_CALLBACK( maple_properties_activated ), &maple_data[i] );
|
nkeynes@736 | 316 | g_signal_connect( combo, "changed",
|
nkeynes@736 | 317 | G_CALLBACK( maple_device_changed ), &maple_data[i] );
|
nkeynes@447 | 318 |
|
nkeynes@447 | 319 | }
|
nkeynes@447 | 320 | return table;
|
nkeynes@447 | 321 | }
|
nkeynes@447 | 322 |
|
nkeynes@460 | 323 | void maple_dialog_run( )
|
nkeynes@447 | 324 | {
|
nkeynes@508 | 325 | gtk_gui_run_property_dialog( _("Controller Settings"), maple_panel_new(), maple_dialog_done );
|
nkeynes@447 | 326 | }
|