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