Mercurial > audlegacy-plugins
comparison src/evdev-plug/ed_ui.c @ 422:5e46b57d1eda trunk
[svn] - added evdev-plug, written-from-scratch plugin that allows to control the player via event devices on linux systems
| author | giacomo |
|---|---|
| date | Sun, 14 Jan 2007 17:55:24 -0800 |
| parents | |
| children | f5ed9a6ad3f1 |
comparison
equal
deleted
inserted
replaced
| 421:1a82af4f13cf | 422:5e46b57d1eda |
|---|---|
| 1 /* | |
| 2 * | |
| 3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007 | |
| 4 * | |
| 5 * This program is free software; you can redistribute it and/or modify it | |
| 6 * under the terms of the GNU General Public License as published by the | |
| 7 * Free Software Foundation; either version 2 of the License, or (at your | |
| 8 * option) any later version. | |
| 9 * | |
| 10 * This program is distributed in the hope that it will be useful, but | |
| 11 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU General Public License along | |
| 16 * with this program; if not, write to the Free Software Foundation, Inc., | |
| 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 18 * | |
| 19 */ | |
| 20 | |
| 21 #include "ed_ui.h" | |
| 22 #include "ed_types.h" | |
| 23 #include "ed_internals.h" | |
| 24 #include "ed_actions.h" | |
| 25 #include "ed_bindings_store.h" | |
| 26 #include "ed_common.h" | |
| 27 #include <stdlib.h> | |
| 28 #include <linux/input.h> | |
| 29 | |
| 30 #include <glib/gi18n.h> | |
| 31 #include <gtk/gtk.h> | |
| 32 | |
| 33 | |
| 34 static void cfg_ui_bindings_show ( ed_device_t * , GtkTreeRowReference * ); | |
| 35 | |
| 36 extern ed_action_t player_actions[]; | |
| 37 extern gboolean plugin_is_active; | |
| 38 | |
| 39 static GtkWidget *cfg_win = NULL; | |
| 40 | |
| 41 enum | |
| 42 { | |
| 43 DEVLIST_COL_ISACTIVE = 0, | |
| 44 DEVLIST_COL_NAME, | |
| 45 DEVLIST_COL_FILENAME, | |
| 46 DEVLIST_COL_PHYS, | |
| 47 DEVLIST_COL_ISAVAILABLE, | |
| 48 DEVLIST_COL_BINDINGS, | |
| 49 DEVLIST_NUMCOLS | |
| 50 }; | |
| 51 | |
| 52 enum | |
| 53 { | |
| 54 DEVLIST_ISAVAILABLE_NOTDET = 0, | |
| 55 DEVLIST_ISAVAILABLE_DET, | |
| 56 DEVLIST_ISAVAILABLE_CUSTOM | |
| 57 }; | |
| 58 | |
| 59 | |
| 60 | |
| 61 static void | |
| 62 cfg_device_lv_populate( GtkListStore * store ) | |
| 63 { | |
| 64 /* store is logically divided in three families of devices, | |
| 65 depending on the ISAVAILABLE value; | |
| 66 DEVLIST_ISAVAILABLE_NOTDET -> not detected devices: these are not-custom | |
| 67 devices that are present in configuration file but they do not seem | |
| 68 to be plugged at the moment, cause they're not in system_devices_list; | |
| 69 DEVLIST_ISAVAILABLE_DET -> detected devices: these are not-custom devices that | |
| 70 are currently plugged, no matter whether they are in configuration or not; | |
| 71 DEVLIST_ISAVAILABLE_CUSTOM -> custom devices: defined by user in configuration | |
| 72 file, these are not checked against system_devices_list; | |
| 73 */ | |
| 74 | |
| 75 GList *system_devices_list = NULL; | |
| 76 GList *config_devices_list = NULL; | |
| 77 GList *list_iter = NULL; | |
| 78 | |
| 79 system_devices_list = ed_device_get_list_from_system(); | |
| 80 config_devices_list = ed_device_get_list_from_config(); | |
| 81 | |
| 82 /* first, for each not-custom device in config_devices_list, | |
| 83 perform a search in system_devices_list */ | |
| 84 list_iter = config_devices_list; | |
| 85 while ( list_iter != NULL ) | |
| 86 { | |
| 87 ed_device_info_t *info_from_cfg = list_iter->data; | |
| 88 if ( info_from_cfg->is_custom == 0 ) /* only try to detect not-custom devices */ | |
| 89 { | |
| 90 /* note: if device is found, filename and phys in info_from_cfg could be updated by the | |
| 91 check; the found device will be marked as "found" in system_devices_list too */ | |
| 92 if ( ed_device_check( system_devices_list , | |
| 93 info_from_cfg->name , &(info_from_cfg->filename) , &(info_from_cfg->phys) ) == ED_DEVCHECK_OK ) | |
| 94 { | |
| 95 info_from_cfg->reg = 1; /* mark our device from config as "found" */ | |
| 96 } | |
| 97 } | |
| 98 list_iter = g_list_next( list_iter ); | |
| 99 } | |
| 100 | |
| 101 /* at this point, we have three logical groups: | |
| 102 #1 - not-custom devices in config_devices_list, marked as "found" -> DEVLIST_ISAVAILABLE_DET | |
| 103 #2 - not-custom devices in config_devices_list, not-marked -> DEVLIST_ISAVAILABLE_NOTDET | |
| 104 #3 - custom devices in config_devices_list -> DEVLIST_ISAVAILABLE_CUSTOM | |
| 105 #1bis - plus, we pick not-marked devices from system_devices_list, which | |
| 106 are plugged devices that are not present in config_devices_list -> DEVLIST_ISAVAILABLE_DET | |
| 107 */ | |
| 108 | |
| 109 /* let's start to fill the store with items from group #1 (DEVLIST_ISAVAILABLE_DET) */ | |
| 110 list_iter = config_devices_list; | |
| 111 while ( list_iter != NULL ) | |
| 112 { | |
| 113 ed_device_info_t *info_from_cfg = list_iter->data; | |
| 114 if (( info_from_cfg->reg == 1 ) && ( info_from_cfg->is_custom == 0 )) | |
| 115 { | |
| 116 GtkTreeIter iter; | |
| 117 gtk_list_store_append( store , &iter ); | |
| 118 gtk_list_store_set( store , &iter , | |
| 119 DEVLIST_COL_ISACTIVE , info_from_cfg->is_active , | |
| 120 DEVLIST_COL_NAME , info_from_cfg->name , | |
| 121 DEVLIST_COL_FILENAME , info_from_cfg->filename , | |
| 122 DEVLIST_COL_PHYS , info_from_cfg->phys , | |
| 123 DEVLIST_COL_ISAVAILABLE , DEVLIST_ISAVAILABLE_DET , | |
| 124 DEVLIST_COL_BINDINGS , info_from_cfg->bindings , | |
| 125 -1 ); | |
| 126 } | |
| 127 list_iter = g_list_next( list_iter ); | |
| 128 } | |
| 129 | |
| 130 /* add items from group #1bis (DEVLIST_ISAVAILABLE_DET) */ | |
| 131 list_iter = system_devices_list; | |
| 132 while ( list_iter != NULL ) | |
| 133 { | |
| 134 ed_device_info_t *info_from_sys = list_iter->data; | |
| 135 if ( info_from_sys->reg == 0 ) | |
| 136 { | |
| 137 GtkTreeIter iter; | |
| 138 gtk_list_store_append( store , &iter ); | |
| 139 gtk_list_store_set( store , &iter , | |
| 140 DEVLIST_COL_ISACTIVE , info_from_sys->is_active , | |
| 141 DEVLIST_COL_NAME , info_from_sys->name , | |
| 142 DEVLIST_COL_FILENAME , info_from_sys->filename , | |
| 143 DEVLIST_COL_PHYS , info_from_sys->phys , | |
| 144 DEVLIST_COL_ISAVAILABLE , DEVLIST_ISAVAILABLE_DET , | |
| 145 DEVLIST_COL_BINDINGS , info_from_sys->bindings , | |
| 146 -1 ); | |
| 147 } | |
| 148 list_iter = g_list_next( list_iter ); | |
| 149 } | |
| 150 | |
| 151 /* add items from group #2 (DEVLIST_ISAVAILABLE_NOTDET) */ | |
| 152 list_iter = config_devices_list; | |
| 153 while ( list_iter != NULL ) | |
| 154 { | |
| 155 ed_device_info_t *info_from_cfg = list_iter->data; | |
| 156 if (( info_from_cfg->reg == 0 ) && ( info_from_cfg->is_custom == 0 )) | |
| 157 { | |
| 158 GtkTreeIter iter; | |
| 159 gtk_list_store_append( store , &iter ); | |
| 160 gtk_list_store_set( store , &iter , | |
| 161 DEVLIST_COL_ISACTIVE , info_from_cfg->is_active , | |
| 162 DEVLIST_COL_NAME , info_from_cfg->name , | |
| 163 DEVLIST_COL_FILENAME , info_from_cfg->filename , | |
| 164 DEVLIST_COL_PHYS , info_from_cfg->phys , | |
| 165 DEVLIST_COL_ISAVAILABLE , DEVLIST_ISAVAILABLE_NOTDET , | |
| 166 DEVLIST_COL_BINDINGS , info_from_cfg->bindings , | |
| 167 -1 ); | |
| 168 } | |
| 169 list_iter = g_list_next( list_iter ); | |
| 170 } | |
| 171 | |
| 172 /* add items from group #3 (DEVLIST_ISAVAILABLE_CUSTOM) */ | |
| 173 list_iter = config_devices_list; | |
| 174 while ( list_iter != NULL ) | |
| 175 { | |
| 176 ed_device_info_t *info_from_cfg = list_iter->data; | |
| 177 if ( info_from_cfg->is_custom == 1 ) | |
| 178 { | |
| 179 GtkTreeIter iter; | |
| 180 gtk_list_store_append( store , &iter ); | |
| 181 gtk_list_store_set( store , &iter , | |
| 182 DEVLIST_COL_ISACTIVE , info_from_cfg->is_active , | |
| 183 DEVLIST_COL_NAME , info_from_cfg->name , | |
| 184 DEVLIST_COL_FILENAME , info_from_cfg->filename , | |
| 185 DEVLIST_COL_PHYS , info_from_cfg->phys , | |
| 186 DEVLIST_COL_ISAVAILABLE , DEVLIST_ISAVAILABLE_CUSTOM , | |
| 187 DEVLIST_COL_BINDINGS , info_from_cfg->bindings , | |
| 188 -1 ); | |
| 189 } | |
| 190 list_iter = g_list_next( list_iter ); | |
| 191 } | |
| 192 | |
| 193 /* delete lists; bindings objects are not deleted, | |
| 194 they must be accessible from liststore for customization | |
| 195 and they'll be deleted when the config win is destroyed */ | |
| 196 ed_device_free_list( config_devices_list ); | |
| 197 ed_device_free_list( system_devices_list ); | |
| 198 return; | |
| 199 } | |
| 200 | |
| 201 | |
| 202 static void | |
| 203 cfg_device_lv_celldatafunc_isavailable( GtkTreeViewColumn * col , GtkCellRenderer * renderer , | |
| 204 GtkTreeModel * model , GtkTreeIter * iter , gpointer data ) | |
| 205 { | |
| 206 guint is_available = 0; | |
| 207 gtk_tree_model_get( model , iter , DEVLIST_COL_ISAVAILABLE , &is_available , -1 ); | |
| 208 switch (is_available) | |
| 209 { | |
| 210 case DEVLIST_ISAVAILABLE_DET: | |
| 211 g_object_set( renderer , "text" , "Detected" , | |
| 212 "foreground" , "Green" , "foreground-set" , TRUE , | |
| 213 "background" , "Black" , "background-set" , TRUE , NULL ); | |
| 214 break; | |
| 215 case DEVLIST_ISAVAILABLE_CUSTOM: | |
| 216 g_object_set( renderer , "text" , "Custom" , | |
| 217 "foreground" , "Yellow" , "foreground-set" , TRUE , | |
| 218 "background" , "Black" , "background-set" , TRUE , NULL ); | |
| 219 break; | |
| 220 case DEVLIST_ISAVAILABLE_NOTDET: | |
| 221 default: | |
| 222 g_object_set( renderer , "text" , "Not Detected" , | |
| 223 "foreground" , "Orange" , "foreground-set" , TRUE , | |
| 224 "background" , "Black" , "background-set" , TRUE , NULL ); | |
| 225 break; | |
| 226 } | |
| 227 return; | |
| 228 } | |
| 229 | |
| 230 | |
| 231 static void | |
| 232 cfg_device_lv_changetoggle ( GtkCellRendererToggle * toggle , | |
| 233 gchar * path_str , gpointer cfg_device_lv ) | |
| 234 { | |
| 235 GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 236 GtkTreeIter iter; | |
| 237 GtkTreePath *path = gtk_tree_path_new_from_string( path_str ); | |
| 238 gboolean toggled; | |
| 239 | |
| 240 gtk_tree_model_get_iter( model , &iter , path ); | |
| 241 gtk_tree_model_get( model , &iter , DEVLIST_COL_ISACTIVE , &toggled , -1 ); | |
| 242 | |
| 243 toggled ^= 1; | |
| 244 gtk_list_store_set( GTK_LIST_STORE(model), &iter , DEVLIST_COL_ISACTIVE , toggled , -1 ); | |
| 245 | |
| 246 gtk_tree_path_free( path ); | |
| 247 return; | |
| 248 } | |
| 249 | |
| 250 | |
| 251 static void | |
| 252 cfg_config_cb_bindings_show ( gpointer cfg_device_lv ) | |
| 253 { | |
| 254 GtkTreeSelection *sel; | |
| 255 GtkTreeModel *model; | |
| 256 GtkTreeIter iter; | |
| 257 | |
| 258 /* check if a row is selected */ | |
| 259 sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 260 if ( gtk_tree_selection_get_selected( sel , &model , &iter ) == TRUE ) | |
| 261 { | |
| 262 /* check availability and active status */ | |
| 263 guint is_available = 0; | |
| 264 gboolean is_active = FALSE; | |
| 265 | |
| 266 gtk_tree_model_get( model , &iter , | |
| 267 DEVLIST_COL_ISACTIVE , &is_active , | |
| 268 DEVLIST_COL_ISAVAILABLE , &is_available , | |
| 269 -1 ); | |
| 270 | |
| 271 if ( is_available == DEVLIST_ISAVAILABLE_NOTDET ) | |
| 272 { | |
| 273 /* do not open bindings window for a not-detected device */ | |
| 274 ed_ui_message_show( _("Information") , | |
| 275 _("Cannot open bindings window for a not-detected device.\n" | |
| 276 "Ensure that the device has been correctly plugged in.") , | |
| 277 cfg_win ); | |
| 278 return; | |
| 279 } | |
| 280 else | |
| 281 { | |
| 282 /* ok, create a ed_device_t item from selected row information */ | |
| 283 ed_device_t *dev; | |
| 284 gchar *device_name = NULL, *device_file = NULL, *device_phys = NULL; | |
| 285 gpointer bindings = NULL; | |
| 286 | |
| 287 gtk_tree_model_get( model , &iter , | |
| 288 DEVLIST_COL_NAME , &device_name , | |
| 289 DEVLIST_COL_FILENAME , &device_file , | |
| 290 DEVLIST_COL_PHYS , &device_phys , | |
| 291 DEVLIST_COL_BINDINGS , &bindings , | |
| 292 -1 ); | |
| 293 | |
| 294 dev = ed_device_new( | |
| 295 device_name , device_file , device_phys , | |
| 296 ( is_available == DEVLIST_ISAVAILABLE_CUSTOM ? 1 : 0 ) ); | |
| 297 g_free( device_name ); g_free( device_file ); g_free( device_phys ); | |
| 298 | |
| 299 if ( dev != NULL ) | |
| 300 { | |
| 301 GtkTreePath *path; | |
| 302 GtkTreeRowReference *rowref; | |
| 303 | |
| 304 dev->info->bindings = bindings; | |
| 305 | |
| 306 path = gtk_tree_model_get_path( model , &iter ); | |
| 307 rowref = gtk_tree_row_reference_new( model , path ); | |
| 308 gtk_tree_path_free( path ); | |
| 309 /* show bindings window for device "dev"; also pass to the bindings window | |
| 310 the GtkTreeRowReference (it keeps track of the model too) for selected row; | |
| 311 if changes are committed in the bindings window, the row reference will be | |
| 312 needed to update the treemodel with the new bindings information */ | |
| 313 cfg_ui_bindings_show( dev , rowref ); | |
| 314 } | |
| 315 else | |
| 316 { | |
| 317 /* something went wrong */ | |
| 318 ed_ui_message_show( _("Error") , | |
| 319 _("Unable to open selected device.\n" | |
| 320 "Please check read permissions on device file.") , | |
| 321 cfg_win ); | |
| 322 } | |
| 323 } | |
| 324 } | |
| 325 } | |
| 326 | |
| 327 | |
| 328 static void | |
| 329 cfg_config_cb_addcustom_show ( gpointer cfg_device_lv ) | |
| 330 { | |
| 331 GtkWidget *addc_dlg; | |
| 332 GtkWidget *addc_data_frame, *addc_data_vbox; | |
| 333 GtkWidget *addc_data_label; | |
| 334 GtkWidget *addc_data_table; | |
| 335 GtkWidget *addc_data_name_label, *addc_data_name_entry; | |
| 336 GtkWidget *addc_data_file_label, *addc_data_file_entry; | |
| 337 gint result; | |
| 338 gboolean task_done = FALSE; | |
| 339 | |
| 340 addc_dlg = gtk_dialog_new_with_buttons( _("EvDev-Plug - Add custom device") , | |
| 341 GTK_WINDOW(cfg_win) , GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , | |
| 342 GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL ); | |
| 343 | |
| 344 addc_data_frame = gtk_frame_new( NULL ); | |
| 345 gtk_container_add( GTK_CONTAINER(GTK_DIALOG(addc_dlg)->vbox) , addc_data_frame ); | |
| 346 addc_data_vbox = gtk_vbox_new( FALSE , 5 ); | |
| 347 gtk_container_set_border_width( GTK_CONTAINER(addc_data_vbox) , 5 ); | |
| 348 gtk_container_add( GTK_CONTAINER(addc_data_frame) , addc_data_vbox ); | |
| 349 | |
| 350 addc_data_label = gtk_label_new( "" ); | |
| 351 gtk_label_set_text( GTK_LABEL(addc_data_label) , | |
| 352 _("EvDev-Plug tries to automatically detect and update information about\n" | |
| 353 "event devices available on the system.\n" | |
| 354 "However, if auto-detect doesn't work for your system, or you have event\n" | |
| 355 "devices in a non-standard location (currently they're only searched in\n" | |
| 356 "/dev/input/ ), you may want to add a custom device, explicitly specifying\n" | |
| 357 "name and device file.") ); | |
| 358 gtk_box_pack_start( GTK_BOX(addc_data_vbox) , addc_data_label , FALSE , FALSE , 0 ); | |
| 359 | |
| 360 addc_data_name_label = gtk_label_new( _("Device name:") ); | |
| 361 gtk_misc_set_alignment( GTK_MISC(addc_data_name_label) , 0 , 0.5 ); | |
| 362 addc_data_name_entry = gtk_entry_new(); | |
| 363 | |
| 364 addc_data_file_label = gtk_label_new( _("Device file:") ); | |
| 365 gtk_misc_set_alignment( GTK_MISC(addc_data_file_label) , 0 , 0.5 ); | |
| 366 addc_data_file_entry = gtk_entry_new(); | |
| 367 | |
| 368 addc_data_table = gtk_table_new( 2 , 2 , FALSE ); | |
| 369 gtk_table_set_col_spacings( GTK_TABLE(addc_data_table) , 2 ); | |
| 370 gtk_table_set_row_spacings( GTK_TABLE(addc_data_table) , 2 ); | |
| 371 gtk_table_attach( GTK_TABLE(addc_data_table) , addc_data_name_label , 0 , 1 , 0 , 1 , | |
| 372 GTK_FILL , GTK_EXPAND | GTK_FILL , 0 , 0 ); | |
| 373 gtk_table_attach( GTK_TABLE(addc_data_table) , addc_data_name_entry , 1 , 2 , 0 , 1 , | |
| 374 GTK_EXPAND | GTK_FILL , GTK_EXPAND | GTK_FILL , 0 , 0 ); | |
| 375 gtk_table_attach( GTK_TABLE(addc_data_table) , addc_data_file_label , 0 , 1 , 1 , 2 , | |
| 376 GTK_FILL , GTK_EXPAND | GTK_FILL , 0 , 0 ); | |
| 377 gtk_table_attach( GTK_TABLE(addc_data_table) , addc_data_file_entry , 1 , 2 , 1 , 2 , | |
| 378 GTK_EXPAND | GTK_FILL , GTK_EXPAND | GTK_FILL , 0 , 0 ); | |
| 379 gtk_box_pack_start( GTK_BOX(addc_data_vbox) , addc_data_table , TRUE , TRUE , 0 ); | |
| 380 | |
| 381 gtk_widget_show_all( addc_dlg ); | |
| 382 | |
| 383 while ( task_done == FALSE ) | |
| 384 { | |
| 385 result = gtk_dialog_run( GTK_DIALOG(addc_dlg) ); | |
| 386 if ( result == GTK_RESPONSE_ACCEPT ) | |
| 387 { | |
| 388 const gchar *name = gtk_entry_get_text( GTK_ENTRY(addc_data_name_entry) ); | |
| 389 const gchar *file = gtk_entry_get_text( GTK_ENTRY(addc_data_file_entry) ); | |
| 390 if ( ( strcmp( name , "" ) != 0 ) && | |
| 391 ( strcmp( name , "___plugin___" ) != 0 ) && | |
| 392 ( strcmp( file , "" ) != 0 ) && | |
| 393 ( file[0] == '/' ) ) | |
| 394 { | |
| 395 GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 396 GtkTreeIter iter; | |
| 397 | |
| 398 gtk_list_store_append( GTK_LIST_STORE(model) , &iter ); | |
| 399 gtk_list_store_set( GTK_LIST_STORE(model) , &iter , | |
| 400 DEVLIST_COL_ISACTIVE , FALSE , | |
| 401 DEVLIST_COL_NAME , name , | |
| 402 DEVLIST_COL_FILENAME , file , | |
| 403 DEVLIST_COL_PHYS , "(custom)" , | |
| 404 DEVLIST_COL_ISAVAILABLE , DEVLIST_ISAVAILABLE_CUSTOM , | |
| 405 DEVLIST_COL_BINDINGS , NULL , -1 ); | |
| 406 task_done = TRUE; | |
| 407 } | |
| 408 else | |
| 409 { | |
| 410 ed_ui_message_show( _("Information") , | |
| 411 _("Please specify both name and filename.\n" | |
| 412 "Filename must be specified with absolute path.") , | |
| 413 addc_dlg ); | |
| 414 } | |
| 415 } | |
| 416 else | |
| 417 task_done = TRUE; | |
| 418 } | |
| 419 | |
| 420 gtk_widget_destroy( addc_dlg ); | |
| 421 } | |
| 422 | |
| 423 | |
| 424 static void | |
| 425 cfg_config_cb_remove ( gpointer cfg_device_lv ) | |
| 426 { | |
| 427 GtkTreeSelection *sel; | |
| 428 GtkTreeModel *model; | |
| 429 GtkTreeIter iter; | |
| 430 | |
| 431 /* check if a row is selected */ | |
| 432 sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 433 if ( gtk_tree_selection_get_selected( sel , &model , &iter ) == TRUE ) | |
| 434 { | |
| 435 guint is_available = 0; | |
| 436 gtk_tree_model_get( model , &iter , DEVLIST_COL_ISAVAILABLE , &is_available , -1 ); | |
| 437 switch ( is_available ) | |
| 438 { | |
| 439 case DEVLIST_ISAVAILABLE_NOTDET: | |
| 440 { | |
| 441 /* if remove is called on a not-detected device, | |
| 442 it allows to remove existing configuration for it */ | |
| 443 GtkWidget *yesno_dlg = gtk_message_dialog_new( GTK_WINDOW(cfg_win) , | |
| 444 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , GTK_MESSAGE_QUESTION , | |
| 445 GTK_BUTTONS_YES_NO , | |
| 446 _("Do you want to remove the existing configuration for selected device?\n") ); | |
| 447 if ( gtk_dialog_run( GTK_DIALOG(yesno_dlg) ) == GTK_RESPONSE_YES ) | |
| 448 { | |
| 449 gpointer bindings = NULL; | |
| 450 gtk_tree_model_get( model , &iter , DEVLIST_COL_BINDINGS , &bindings , -1 ); | |
| 451 if ( bindings != NULL ) ed_bindings_store_delete( bindings ); | |
| 452 gtk_list_store_remove( GTK_LIST_STORE(model) , &iter ); | |
| 453 } | |
| 454 gtk_widget_destroy( yesno_dlg ); | |
| 455 break; | |
| 456 } | |
| 457 | |
| 458 case DEVLIST_ISAVAILABLE_CUSTOM: | |
| 459 { | |
| 460 /* if remove is called on a custom device, | |
| 461 it allows to remove it along with its configuration */ | |
| 462 GtkWidget *yesno_dlg = gtk_message_dialog_new( GTK_WINDOW(cfg_win) , | |
| 463 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , GTK_MESSAGE_QUESTION , | |
| 464 GTK_BUTTONS_YES_NO , | |
| 465 _("Do you want to remove the selected custom device?\n") ); | |
| 466 if ( gtk_dialog_run( GTK_DIALOG(yesno_dlg) ) == GTK_RESPONSE_YES ) | |
| 467 { | |
| 468 gpointer bindings = NULL; | |
| 469 gtk_tree_model_get( model , &iter , DEVLIST_COL_BINDINGS , &bindings , -1 ); | |
| 470 if ( bindings != NULL ) ed_bindings_store_delete( bindings ); | |
| 471 gtk_list_store_remove( GTK_LIST_STORE(model) , &iter ); | |
| 472 } | |
| 473 gtk_widget_destroy( yesno_dlg ); | |
| 474 break; | |
| 475 } | |
| 476 | |
| 477 case DEVLIST_ISAVAILABLE_DET: | |
| 478 default: | |
| 479 { | |
| 480 /* do nothing for detected devices */ | |
| 481 break; | |
| 482 } | |
| 483 } | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 | |
| 488 static gboolean | |
| 489 cfg_config_cb_bindings_commit_foreach ( GtkTreeModel * model , | |
| 490 GtkTreePath * path , | |
| 491 GtkTreeIter * iter , | |
| 492 gpointer config_device_list_p ) | |
| 493 { | |
| 494 gchar *device_name = NULL; | |
| 495 gchar *device_file = NULL; | |
| 496 gchar *device_phys = NULL; | |
| 497 gboolean is_active = FALSE; | |
| 498 guint is_available = 0; | |
| 499 gpointer bindings = NULL; | |
| 500 ed_device_info_t *info; | |
| 501 GList **config_device_list = config_device_list_p; | |
| 502 | |
| 503 gtk_tree_model_get( model , iter , | |
| 504 DEVLIST_COL_ISACTIVE , &is_active , | |
| 505 DEVLIST_COL_NAME , &device_name , | |
| 506 DEVLIST_COL_FILENAME , &device_file , | |
| 507 DEVLIST_COL_PHYS , &device_phys , | |
| 508 DEVLIST_COL_ISAVAILABLE , &is_available , | |
| 509 DEVLIST_COL_BINDINGS , &bindings , -1 ); | |
| 510 | |
| 511 info = ed_device_info_new( device_name , device_file , device_phys , | |
| 512 ( is_available == DEVLIST_ISAVAILABLE_CUSTOM ? 1 : 0 ) ); | |
| 513 info->bindings = bindings; | |
| 514 info->is_active = is_active; | |
| 515 | |
| 516 *config_device_list = g_list_append( *config_device_list , info ); | |
| 517 return FALSE; | |
| 518 } | |
| 519 | |
| 520 | |
| 521 static gboolean | |
| 522 cfg_config_cb_bindings_delbindings_foreach ( GtkTreeModel * model , | |
| 523 GtkTreePath * path , | |
| 524 GtkTreeIter * iter , | |
| 525 gpointer data ) | |
| 526 { | |
| 527 gpointer bindings = NULL; | |
| 528 gtk_tree_model_get( model , iter , DEVLIST_COL_BINDINGS , &bindings , -1 ); | |
| 529 if ( bindings != NULL ) | |
| 530 ed_bindings_store_delete( bindings ); | |
| 531 return FALSE; | |
| 532 } | |
| 533 | |
| 534 | |
| 535 static void | |
| 536 cfg_config_cb_commit ( gpointer cfg_device_lv ) | |
| 537 { | |
| 538 GList *config_device_list = NULL; | |
| 539 GList *list_iter; | |
| 540 GtkTreeModel *model; | |
| 541 | |
| 542 model = gtk_tree_view_get_model( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 543 /* fill config_device_list with information from the treeview */ | |
| 544 gtk_tree_model_foreach( model , cfg_config_cb_bindings_commit_foreach , &config_device_list ); | |
| 545 /* ok, now we have a list of ed_device_info_t objects */ | |
| 546 | |
| 547 /* commit changes in configuration file */ | |
| 548 ed_config_save_from_list( config_device_list ); | |
| 549 | |
| 550 /* not needed anymore */ | |
| 551 ed_device_free_list( config_device_list ); | |
| 552 | |
| 553 /* free bindings stored in the liststore */ | |
| 554 gtk_tree_model_foreach( model , cfg_config_cb_bindings_delbindings_foreach , NULL ); | |
| 555 | |
| 556 if ( plugin_is_active == TRUE ) | |
| 557 { | |
| 558 /* restart device listening according to the (possibly changed) config file */ | |
| 559 ed_device_start_listening_from_config(); | |
| 560 } | |
| 561 | |
| 562 gtk_widget_destroy( cfg_win ); | |
| 563 } | |
| 564 | |
| 565 | |
| 566 static void | |
| 567 cfg_config_cb_cancel ( gpointer cfg_device_lv ) | |
| 568 { | |
| 569 GtkTreeModel *model; | |
| 570 model = gtk_tree_view_get_model( GTK_TREE_VIEW(cfg_device_lv) ); | |
| 571 | |
| 572 /* free bindings stored in the liststore */ | |
| 573 gtk_tree_model_foreach( model , cfg_config_cb_bindings_delbindings_foreach , NULL ); | |
| 574 | |
| 575 if ( plugin_is_active == TRUE ) | |
| 576 { | |
| 577 /* restart device listening according to the (unchanged) config file */ | |
| 578 ed_device_start_listening_from_config(); | |
| 579 } | |
| 580 | |
| 581 gtk_widget_destroy( cfg_win ); | |
| 582 } | |
| 583 | |
| 584 | |
| 585 void | |
| 586 ed_ui_config_show( void ) | |
| 587 { | |
| 588 GtkWidget *cfg_vbox; | |
| 589 GtkWidget *cfg_device_lv, *cfg_device_lv_frame, *cfg_device_lv_sw; | |
| 590 GtkTreeViewColumn *cfg_device_lv_col_name, *cfg_device_lv_col_filename, *cfg_device_lv_col_phys; | |
| 591 GtkTreeViewColumn *cfg_device_lv_col_isactive, *cfg_device_lv_col_isavailable; | |
| 592 GtkCellRenderer *cfg_device_lv_rndr_text, *cfg_device_lv_rndr_toggle; | |
| 593 GtkCellRenderer *cfg_device_lv_rndr_textphys, *cfg_device_lv_rndr_isavailable; | |
| 594 GtkListStore *device_store; | |
| 595 GtkWidget *cfg_bbar_hbbox; | |
| 596 GtkWidget *cfg_bbar_bt_bind, *cfg_bbar_bt_addc, *cfg_bbar_bt_remc; | |
| 597 GtkWidget *cfg_bbar_bt_cancel, *cfg_bbar_bt_ok; | |
| 598 GdkGeometry cfg_win_hints; | |
| 599 | |
| 600 if ( cfg_win != NULL ) | |
| 601 { | |
| 602 gtk_window_present( GTK_WINDOW(cfg_win) ); | |
| 603 return; | |
| 604 } | |
| 605 | |
| 606 /* IMPORTANT: stop listening for all devices when config window is opened */ | |
| 607 ed_device_stop_listening_all( TRUE ); | |
| 608 | |
| 609 cfg_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); | |
| 610 gtk_window_set_type_hint( GTK_WINDOW(cfg_win), GDK_WINDOW_TYPE_HINT_DIALOG ); | |
| 611 gtk_window_set_position( GTK_WINDOW(cfg_win), GTK_WIN_POS_CENTER ); | |
| 612 gtk_window_set_title( GTK_WINDOW(cfg_win), _("EvDev-Plug - Configuration") ); | |
| 613 gtk_container_set_border_width( GTK_CONTAINER(cfg_win), 10 ); | |
| 614 g_signal_connect( G_OBJECT(cfg_win) , "destroy" , | |
| 615 G_CALLBACK(gtk_widget_destroyed) , &cfg_win ); | |
| 616 cfg_win_hints.min_width = -1; | |
| 617 cfg_win_hints.min_height = 300; | |
| 618 gtk_window_set_geometry_hints( GTK_WINDOW(cfg_win) , GTK_WIDGET(cfg_win) , | |
| 619 &cfg_win_hints , GDK_HINT_MIN_SIZE ); | |
| 620 | |
| 621 cfg_vbox = gtk_vbox_new( FALSE , 0 ); | |
| 622 gtk_container_add( GTK_CONTAINER(cfg_win) , cfg_vbox ); | |
| 623 | |
| 624 /* current liststore model | |
| 625 ---------------------------------------------- | |
| 626 G_TYPE_BOOLEAN -> device listening on/off | |
| 627 G_TYPE_STRING -> device name | |
| 628 G_TYPE_STRING -> device filename | |
| 629 G_TYPE_STRING -> device physical port | |
| 630 G_TYPE_UINT -> device is available | |
| 631 G_TYPE_POINTER -> device bindings | |
| 632 ---------------------------------------------- | |
| 633 */ | |
| 634 device_store = gtk_list_store_new( | |
| 635 DEVLIST_NUMCOLS , G_TYPE_BOOLEAN , G_TYPE_STRING , | |
| 636 G_TYPE_STRING , G_TYPE_STRING , G_TYPE_UINT , G_TYPE_POINTER ); | |
| 637 cfg_device_lv_populate( device_store ); | |
| 638 | |
| 639 cfg_device_lv_frame = gtk_frame_new( NULL ); | |
| 640 cfg_device_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(device_store) ); | |
| 641 g_object_unref( device_store ); | |
| 642 | |
| 643 cfg_device_lv_rndr_text = gtk_cell_renderer_text_new(); | |
| 644 cfg_device_lv_rndr_toggle = gtk_cell_renderer_toggle_new(); | |
| 645 cfg_device_lv_rndr_isavailable = gtk_cell_renderer_text_new(); | |
| 646 cfg_device_lv_rndr_textphys = gtk_cell_renderer_text_new(); | |
| 647 g_object_set( G_OBJECT(cfg_device_lv_rndr_textphys) , | |
| 648 "ellipsize-set" , TRUE , "ellipsize" , PANGO_ELLIPSIZE_END , NULL ); | |
| 649 | |
| 650 cfg_device_lv_col_isactive = gtk_tree_view_column_new_with_attributes( | |
| 651 _("Active") , cfg_device_lv_rndr_toggle , "active" , DEVLIST_COL_ISACTIVE , NULL ); | |
| 652 gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_isactive) , FALSE ); | |
| 653 gtk_tree_view_append_column( GTK_TREE_VIEW(cfg_device_lv), cfg_device_lv_col_isactive ); | |
| 654 cfg_device_lv_col_isavailable = gtk_tree_view_column_new(); | |
| 655 gtk_tree_view_column_set_title( cfg_device_lv_col_isavailable , _("Status") ); | |
| 656 gtk_tree_view_column_pack_start( cfg_device_lv_col_isavailable , cfg_device_lv_rndr_isavailable , TRUE ); | |
| 657 gtk_tree_view_column_set_cell_data_func( | |
| 658 cfg_device_lv_col_isavailable , cfg_device_lv_rndr_isavailable , | |
| 659 (GtkTreeCellDataFunc)cfg_device_lv_celldatafunc_isavailable , | |
| 660 NULL , NULL ); | |
| 661 gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_isavailable) , FALSE ); | |
| 662 gtk_tree_view_append_column( GTK_TREE_VIEW(cfg_device_lv), cfg_device_lv_col_isavailable ); | |
| 663 cfg_device_lv_col_name = gtk_tree_view_column_new_with_attributes( | |
| 664 _("Device Name") , cfg_device_lv_rndr_text , "text" , DEVLIST_COL_NAME , NULL ); | |
| 665 gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_name) , FALSE ); | |
| 666 gtk_tree_view_append_column( GTK_TREE_VIEW(cfg_device_lv), cfg_device_lv_col_name ); | |
| 667 cfg_device_lv_col_filename = gtk_tree_view_column_new_with_attributes( | |
| 668 _("Device File") , cfg_device_lv_rndr_text , "text" , DEVLIST_COL_FILENAME , NULL ); | |
| 669 gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_filename) , FALSE ); | |
| 670 gtk_tree_view_append_column( GTK_TREE_VIEW(cfg_device_lv), cfg_device_lv_col_filename ); | |
| 671 cfg_device_lv_col_phys = gtk_tree_view_column_new_with_attributes( | |
| 672 _("Device Address") , cfg_device_lv_rndr_textphys , "text" , DEVLIST_COL_PHYS , NULL ); | |
| 673 gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_phys) , TRUE ); | |
| 674 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(cfg_device_lv_col_phys) , TRUE ); | |
| 675 gtk_tree_view_append_column( GTK_TREE_VIEW(cfg_device_lv), cfg_device_lv_col_phys ); | |
| 676 cfg_device_lv_sw = gtk_scrolled_window_new( NULL , NULL ); | |
| 677 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(cfg_device_lv_sw) , | |
| 678 GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); | |
| 679 | |
| 680 gtk_container_add( GTK_CONTAINER(cfg_device_lv_sw) , cfg_device_lv ); | |
| 681 gtk_container_add( GTK_CONTAINER(cfg_device_lv_frame) , cfg_device_lv_sw ); | |
| 682 gtk_box_pack_start( GTK_BOX(cfg_vbox) , cfg_device_lv_frame , TRUE , TRUE , 0 ); | |
| 683 | |
| 684 gtk_box_pack_start( GTK_BOX(cfg_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); | |
| 685 | |
| 686 /* button bar */ | |
| 687 cfg_bbar_hbbox = gtk_hbutton_box_new(); | |
| 688 gtk_button_box_set_layout( GTK_BUTTON_BOX(cfg_bbar_hbbox) , GTK_BUTTONBOX_START ); | |
| 689 cfg_bbar_bt_bind = gtk_button_new_with_mnemonic( _("_Bindings") ); | |
| 690 gtk_button_set_image( GTK_BUTTON(cfg_bbar_bt_bind) , | |
| 691 gtk_image_new_from_stock( GTK_STOCK_PREFERENCES , GTK_ICON_SIZE_BUTTON ) ); | |
| 692 cfg_bbar_bt_addc = gtk_button_new_from_stock( GTK_STOCK_ADD ); | |
| 693 cfg_bbar_bt_remc = gtk_button_new_from_stock( GTK_STOCK_REMOVE ); | |
| 694 /*cfg_bbar_bt_refresh = gtk_button_new_from_stock( GTK_STOCK_REFRESH );*/ | |
| 695 cfg_bbar_bt_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL ); | |
| 696 cfg_bbar_bt_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); | |
| 697 gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_bind ); | |
| 698 gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_addc ); | |
| 699 gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_remc ); | |
| 700 /*gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_refresh );*/ | |
| 701 gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_cancel ); | |
| 702 gtk_container_add( GTK_CONTAINER(cfg_bbar_hbbox) , cfg_bbar_bt_ok ); | |
| 703 gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(cfg_bbar_hbbox) , cfg_bbar_bt_cancel , TRUE ); | |
| 704 gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(cfg_bbar_hbbox) , cfg_bbar_bt_ok , TRUE ); | |
| 705 gtk_box_pack_start( GTK_BOX(cfg_vbox) , cfg_bbar_hbbox , FALSE , FALSE , 0 ); | |
| 706 | |
| 707 g_signal_connect( cfg_device_lv_rndr_toggle , "toggled" , | |
| 708 G_CALLBACK(cfg_device_lv_changetoggle) , cfg_device_lv ); | |
| 709 g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_bind) , "clicked" , | |
| 710 G_CALLBACK(cfg_config_cb_bindings_show) , cfg_device_lv ); | |
| 711 g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_addc) , "clicked" , | |
| 712 G_CALLBACK(cfg_config_cb_addcustom_show) , cfg_device_lv ); | |
| 713 g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_remc) , "clicked" , | |
| 714 G_CALLBACK(cfg_config_cb_remove) , cfg_device_lv ); | |
| 715 g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_cancel) , "clicked" , | |
| 716 G_CALLBACK(cfg_config_cb_cancel) , cfg_device_lv ); | |
| 717 g_signal_connect_swapped( G_OBJECT(cfg_bbar_bt_ok) , "clicked" , | |
| 718 G_CALLBACK(cfg_config_cb_commit) , cfg_device_lv ); | |
| 719 | |
| 720 gtk_widget_show_all( cfg_win ); | |
| 721 } | |
| 722 | |
| 723 | |
| 724 | |
| 725 /* bindings window */ | |
| 726 | |
| 727 static void cfg_bindbox_new_empty_row( GtkTable * , GtkWidget * , gboolean ); | |
| 728 | |
| 729 enum | |
| 730 { | |
| 731 BINDLIST_COL_COMBO_ACTION = 0, | |
| 732 BINDLIST_COL_BT_ASSIGN, | |
| 733 BINDLIST_COL_LABEL_EVCODE, | |
| 734 BINDLIST_COL_BT_DELETE, | |
| 735 BINDLIST_NUMCOLS | |
| 736 }; | |
| 737 | |
| 738 | |
| 739 static gboolean | |
| 740 cfg_bindbox_assign_binding_timeout_func ( gpointer bindings_win ) | |
| 741 { | |
| 742 GtkWidget *trigger_dlg = g_object_get_data( G_OBJECT(bindings_win) , "trigger-win" ); | |
| 743 if ( trigger_dlg != NULL ) | |
| 744 gtk_dialog_response( GTK_DIALOG(trigger_dlg) , GTK_RESPONSE_CANCEL ); | |
| 745 | |
| 746 return FALSE; | |
| 747 } | |
| 748 | |
| 749 | |
| 750 static gboolean | |
| 751 cfg_bindbox_assign_binding_input_func ( GIOChannel * iochan , | |
| 752 GIOCondition cond , | |
| 753 gpointer bindings_win ) | |
| 754 { | |
| 755 switch ( cond ) | |
| 756 { | |
| 757 case G_IO_IN: | |
| 758 { | |
| 759 gsize rb = 0; | |
| 760 GError *gerr = NULL; | |
| 761 struct input_event inputev; | |
| 762 g_io_channel_read_chars( iochan , (gchar*)&inputev , | |
| 763 sizeof(struct input_event) , &rb , NULL ); | |
| 764 if ( rb == sizeof(struct input_event) ) | |
| 765 { | |
| 766 GtkWidget *trigger_dlg = g_object_get_data( G_OBJECT(bindings_win) , "trigger-win" ); | |
| 767 if ( trigger_dlg == NULL ) | |
| 768 { | |
| 769 /* the trigger-dialog window is not open; ignore input */ | |
| 770 return TRUE; | |
| 771 } | |
| 772 else | |
| 773 { | |
| 774 /* the trigger-dialog window is open; record input and | |
| 775 store it in a container managed by the trigger-dialog itself */ | |
| 776 ed_inputevent_t *dinputev = g_malloc(sizeof(ed_inputevent_t*)); | |
| 777 dinputev->type = inputev.type; | |
| 778 dinputev->code = inputev.code; | |
| 779 dinputev->value = inputev.value; | |
| 780 g_object_set_data( G_OBJECT(trigger_dlg) , "trigger-data" , dinputev ); | |
| 781 gtk_dialog_response( GTK_DIALOG(trigger_dlg) , GTK_RESPONSE_OK ); | |
| 782 } | |
| 783 } | |
| 784 } | |
| 785 } | |
| 786 return TRUE; | |
| 787 } | |
| 788 | |
| 789 | |
| 790 static gboolean | |
| 791 cfg_bindbox_assign_binding_checkdups( GtkWidget * table , ed_inputevent_t * inputev ) | |
| 792 { | |
| 793 /* check if inputev is already assigned in table */ | |
| 794 GList *children = GTK_TABLE(table)->children; | |
| 795 for ( children ; children != NULL ; children = g_list_next(children) ) | |
| 796 { | |
| 797 GtkTableChild *child = children->data; | |
| 798 | |
| 799 if ( child->top_attach + 1 == GTK_TABLE(table)->nrows ) | |
| 800 continue; /* skip last empty row */ | |
| 801 | |
| 802 if ( child->left_attach == BINDLIST_COL_LABEL_EVCODE ) | |
| 803 { | |
| 804 /* it's a label, pick its inputevent */ | |
| 805 ed_inputevent_t * iev = g_object_get_data( G_OBJECT(child->widget) , "inputevent" ); | |
| 806 if ( ( iev != NULL ) && ( ed_inputevent_check_equality( inputev , iev ) == TRUE ) ) | |
| 807 return TRUE; /* a duplicate was found */ | |
| 808 } | |
| 809 } | |
| 810 return FALSE; | |
| 811 } | |
| 812 | |
| 813 | |
| 814 static void | |
| 815 cfg_bindbox_assign_binding ( GtkButton * assign_button , gpointer bindings_win ) | |
| 816 { | |
| 817 GtkWidget *trigger_dlg; | |
| 818 GtkWidget *trigger_dlg_frame; | |
| 819 GtkWidget *trigger_dlg_label; | |
| 820 guint timeout_sid = 0; | |
| 821 gint res = 0; | |
| 822 | |
| 823 /* create a not-decorated window to inform the user about what's going on */ | |
| 824 trigger_dlg = gtk_dialog_new(); | |
| 825 gtk_widget_set_name( trigger_dlg , "trigger_dlg" ); | |
| 826 trigger_dlg_label = gtk_label_new( _("Press a key of your device to bind it;\n" | |
| 827 "if no key is pressed in five seconds, this window\n" | |
| 828 "will close without binding changes.") ); | |
| 829 gtk_widget_hide( GTK_WIDGET(GTK_DIALOG(trigger_dlg)->action_area) ); | |
| 830 gtk_misc_set_padding( GTK_MISC(trigger_dlg_label) , 10 , 10 ); | |
| 831 trigger_dlg_frame = gtk_frame_new( NULL ); | |
| 832 gtk_container_add( GTK_CONTAINER(trigger_dlg_frame) , trigger_dlg_label ); | |
| 833 gtk_container_add( GTK_CONTAINER(GTK_DIALOG(trigger_dlg)->vbox) , trigger_dlg_frame ); | |
| 834 gtk_window_set_position( GTK_WINDOW(trigger_dlg) , GTK_WIN_POS_CENTER ); | |
| 835 gtk_window_set_decorated( GTK_WINDOW(trigger_dlg) , FALSE ); | |
| 836 gtk_window_set_transient_for( GTK_WINDOW(trigger_dlg) , | |
| 837 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(assign_button))) ); | |
| 838 gtk_dialog_set_has_separator( GTK_DIALOG(trigger_dlg) , FALSE ); | |
| 839 gtk_widget_show_all( trigger_dlg ); | |
| 840 | |
| 841 /* close the trigger-window if no input is received in 5 seconds */ | |
| 842 timeout_sid = g_timeout_add( 5000 , cfg_bindbox_assign_binding_timeout_func , bindings_win ); | |
| 843 | |
| 844 g_object_set_data( G_OBJECT(bindings_win) , "trigger-win" , trigger_dlg ); /* enable trigger-listening */ | |
| 845 res = gtk_dialog_run( GTK_DIALOG(trigger_dlg) ); | |
| 846 g_object_set_data( G_OBJECT(bindings_win) , "trigger-win" , NULL ); /* stop trigger-listening */ | |
| 847 switch ( res ) | |
| 848 { | |
| 849 case GTK_RESPONSE_OK: | |
| 850 { | |
| 851 ed_inputevent_t *dinputev = g_object_get_data( G_OBJECT(trigger_dlg) , "trigger-data" ); | |
| 852 GtkWidget *label = g_object_get_data( G_OBJECT(assign_button) , "label" ); | |
| 853 GtkWidget *table = g_object_get_data( G_OBJECT(bindings_win) , "table" ); | |
| 854 gchar *input_str; | |
| 855 | |
| 856 /* we got a new input event; ensure that this has not been assigned to an action already */ | |
| 857 if ( cfg_bindbox_assign_binding_checkdups( table , dinputev ) == TRUE ) | |
| 858 { | |
| 859 /* this input event has been already used */ | |
| 860 g_free( dinputev ); | |
| 861 g_source_remove( timeout_sid ); | |
| 862 ed_ui_message_show( _("Information") , | |
| 863 _("This input event has been already assigned.\n\n" | |
| 864 "It's not possible to assign multiple actions to the same input event " | |
| 865 "(although it's possible to assign the same action to multiple events).") , | |
| 866 bindings_win ); | |
| 867 } | |
| 868 else | |
| 869 { | |
| 870 /* if this is the last row ("Assign" button) , create a new empty row */ | |
| 871 if ( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(assign_button),"last")) == 1 ) | |
| 872 { | |
| 873 cfg_bindbox_new_empty_row( GTK_TABLE(table) , bindings_win , TRUE ); | |
| 874 /* so, the current row is not the last one anymore; | |
| 875 remove its "last" mark and enable its delete button */ | |
| 876 g_object_set_data( G_OBJECT(assign_button) , "last" , GINT_TO_POINTER(0) ); | |
| 877 gtk_widget_set_sensitive( GTK_WIDGET(g_object_get_data(G_OBJECT(assign_button),"delbt")) , TRUE ); | |
| 878 } | |
| 879 | |
| 880 g_object_set_data_full( G_OBJECT(label) , "inputevent" , dinputev , g_free ); | |
| 881 input_str = g_strdup_printf( "%i:%i:%i" , dinputev->type , dinputev->code , dinputev->value ); | |
| 882 gtk_label_set_text( GTK_LABEL(label) , input_str ); | |
| 883 g_free( input_str ); | |
| 884 g_source_remove( timeout_sid ); | |
| 885 } | |
| 886 | |
| 887 break; | |
| 888 } | |
| 889 | |
| 890 default: | |
| 891 { | |
| 892 break; /* nothing should be changed */ | |
| 893 } | |
| 894 } | |
| 895 | |
| 896 gtk_widget_destroy( trigger_dlg ); | |
| 897 } | |
| 898 | |
| 899 | |
| 900 static void | |
| 901 cfg_bindbox_delete_row( GtkButton * delete_button , gpointer bindings_win ) | |
| 902 { | |
| 903 GtkTable *oldtable, *newtable; | |
| 904 GtkWidget *table_sw, *table_vp; | |
| 905 GList *children = NULL; | |
| 906 gint drow = 0; | |
| 907 | |
| 908 /* here comes the drawback of using GtkTable to display | |
| 909 a list-like set of widgets :) deletion can be a complex task */ | |
| 910 | |
| 911 /* first, get the row number of the row that should be deleted | |
| 912 (this can't be the last one cause it has the delete button disabled) */ | |
| 913 oldtable = g_object_get_data( G_OBJECT(bindings_win) , "table" ); | |
| 914 children = oldtable->children; | |
| 915 while ( children != NULL ) | |
| 916 { | |
| 917 GtkTableChild *child = children->data; | |
| 918 if ( child->widget == (GtkWidget*)delete_button ) | |
| 919 drow = child->top_attach; | |
| 920 children = g_list_next( children ); | |
| 921 } | |
| 922 | |
| 923 /* now, a simple trick: create a new GtkTable and move all | |
| 924 of the widgets there, excepting those positioned in row "drow" */ | |
| 925 newtable = (GtkTable*)gtk_table_new( oldtable->nrows - 1 , oldtable->ncols , FALSE ); | |
| 926 | |
| 927 children = oldtable->children; | |
| 928 while ( children != NULL ) | |
| 929 { | |
| 930 GtkTableChild *child = children->data; | |
| 931 if ( child->top_attach < drow ) | |
| 932 { | |
| 933 GtkWidget *widget = child->widget; | |
| 934 guint widget_row = child->top_attach; | |
| 935 guint widget_col = child->left_attach; | |
| 936 g_object_ref( widget ); | |
| 937 gtk_container_remove( GTK_CONTAINER(oldtable) , widget ); | |
| 938 gtk_table_attach( GTK_TABLE(newtable) , widget , | |
| 939 widget_col , widget_col + 1 , widget_row , widget_row + 1 , | |
| 940 (widget_col == BINDLIST_COL_LABEL_EVCODE ? GTK_EXPAND | GTK_FILL : GTK_FILL ) , GTK_FILL , 0 , 0 ); | |
| 941 /* gtk_container_remove() changed the structure used to iterate; restart */ | |
| 942 children = oldtable->children; | |
| 943 } | |
| 944 else if ( child->top_attach > drow ) | |
| 945 { | |
| 946 GtkWidget *widget = child->widget; | |
| 947 guint widget_row = child->top_attach; | |
| 948 guint widget_col = child->left_attach; | |
| 949 g_object_ref( widget ); | |
| 950 gtk_container_remove( GTK_CONTAINER(oldtable) , widget ); | |
| 951 gtk_table_attach( GTK_TABLE(newtable) , widget , | |
| 952 widget_col , widget_col + 1 , widget_row - 1 , widget_row , | |
| 953 (widget_col == BINDLIST_COL_LABEL_EVCODE ? GTK_EXPAND | GTK_FILL : GTK_FILL ) , GTK_FILL , 0 , 0 ); | |
| 954 /* gtk_container_remove() changed the structure used to iterate; restart */ | |
| 955 children = oldtable->children; | |
| 956 } | |
| 957 else | |
| 958 children = g_list_next(children); | |
| 959 } | |
| 960 | |
| 961 /* now, replace the old GtkTable with the new one */ | |
| 962 table_sw = g_object_get_data( G_OBJECT(bindings_win) , "tablesw" ); | |
| 963 table_vp = gtk_bin_get_child( GTK_BIN(table_sw) ); /* get the viewport */ | |
| 964 gtk_widget_destroy( GTK_WIDGET(oldtable) ); /* destroy old GtkTable */ | |
| 965 gtk_container_add( GTK_CONTAINER(table_vp) , GTK_WIDGET(newtable) ); | |
| 966 g_object_set_data( G_OBJECT(bindings_win) , "table" , newtable ); /* update table in bindings_win */ | |
| 967 gtk_widget_show_all( GTK_WIDGET(newtable) ); | |
| 968 return; | |
| 969 } | |
| 970 | |
| 971 | |
| 972 /* the three structure types defined below | |
| 973 are only used in cfg_bindbox_populate process */ | |
| 974 typedef struct | |
| 975 { | |
| 976 GtkWidget *combobox; | |
| 977 gint action_code; | |
| 978 } | |
| 979 combosas_helper_t; | |
| 980 | |
| 981 typedef struct | |
| 982 { | |
| 983 gint action_code; | |
| 984 ed_inputevent_t * inputev; | |
| 985 } | |
| 986 popul_binding_t; | |
| 987 | |
| 988 typedef struct | |
| 989 { | |
| 990 gint id; | |
| 991 popul_binding_t *bindings; | |
| 992 } | |
| 993 popul_container_binding_t; | |
| 994 | |
| 995 static gboolean | |
| 996 cfg_bindbox_populate_foreach_combosas ( GtkTreeModel * model , | |
| 997 GtkTreePath * path , | |
| 998 GtkTreeIter * iter , | |
| 999 gpointer combosas_helper_gp ) | |
| 1000 { | |
| 1001 gint action_code = 0; | |
| 1002 combosas_helper_t *combosas_helper = combosas_helper_gp; | |
| 1003 gtk_tree_model_get( model , iter , 1 , &action_code , -1 ); | |
| 1004 if ( action_code == combosas_helper->action_code ) | |
| 1005 { | |
| 1006 gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combosas_helper->combobox) , iter ); | |
| 1007 return TRUE; | |
| 1008 } | |
| 1009 return FALSE; | |
| 1010 } | |
| 1011 | |
| 1012 static void | |
| 1013 cfg_bindbox_populate_foreach ( ed_inputevent_t * sinputev , | |
| 1014 gint action_code , | |
| 1015 gpointer popul_container_gp , | |
| 1016 gpointer none ) | |
| 1017 { | |
| 1018 ed_inputevent_t *inputev; | |
| 1019 popul_container_binding_t *popul_container = popul_container_gp; | |
| 1020 | |
| 1021 /* make a copy of the ed_inputevent_t object "sinputev" */ | |
| 1022 inputev = g_malloc(sizeof(ed_inputevent_t)); | |
| 1023 inputev->type = sinputev->type; | |
| 1024 inputev->code = sinputev->code; | |
| 1025 inputev->value = sinputev->value; | |
| 1026 | |
| 1027 popul_container->bindings[popul_container->id].inputev = inputev; | |
| 1028 popul_container->bindings[popul_container->id].action_code = action_code; | |
| 1029 | |
| 1030 popul_container->id++; | |
| 1031 return; | |
| 1032 } | |
| 1033 | |
| 1034 static int | |
| 1035 cfg_bindbox_populate_qsortfunc( const void * p_binding_a , const void * p_binding_b ) | |
| 1036 { | |
| 1037 return ((popul_binding_t*)p_binding_a)->action_code - ((popul_binding_t*)p_binding_b)->action_code; | |
| 1038 } | |
| 1039 | |
| 1040 static void | |
| 1041 cfg_bindbox_populate( GtkWidget * bind_table , GtkWidget * bindings_win , gpointer bindings ) | |
| 1042 { | |
| 1043 if ( bindings != NULL ) | |
| 1044 { | |
| 1045 guint bindings_num = ed_bindings_store_size( bindings ); | |
| 1046 popul_binding_t *popul_binding = (popul_binding_t*)calloc( bindings_num , sizeof(popul_binding_t) ); | |
| 1047 popul_container_binding_t *popul_container = g_malloc(sizeof(popul_container_binding_t)); | |
| 1048 gint i = 0; | |
| 1049 | |
| 1050 popul_container->bindings = popul_binding; | |
| 1051 popul_container->id = 0; | |
| 1052 | |
| 1053 ed_bindings_store_foreach( bindings , | |
| 1054 (ed_bindings_store_foreach_func)cfg_bindbox_populate_foreach , popul_container , NULL ); | |
| 1055 | |
| 1056 /* ok, now we have a popul_binding array, reorder it using action_codes */ | |
| 1057 qsort( popul_binding , bindings_num , sizeof(popul_binding_t) , cfg_bindbox_populate_qsortfunc ); | |
| 1058 | |
| 1059 /* attach to table each popul_binding */ | |
| 1060 for ( i = 0 ; i < bindings_num ; i++ ) | |
| 1061 { | |
| 1062 GList *children = GTK_TABLE(bind_table)->children; | |
| 1063 for ( children ; children != NULL ; children = g_list_next(children) ) | |
| 1064 { | |
| 1065 GtkTableChild *child = children->data; | |
| 1066 if ( ( (child->top_attach + 1) == GTK_TABLE(bind_table)->nrows ) && | |
| 1067 ( child->left_attach == BINDLIST_COL_BT_ASSIGN ) && | |
| 1068 ( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(child->widget),"last")) == 1 ) ) | |
| 1069 { | |
| 1070 /* ok, this child->widget is the last assign button */ | |
| 1071 GtkWidget *combobox = g_object_get_data(G_OBJECT(child->widget),"combobox"); | |
| 1072 GtkWidget *label = g_object_get_data(G_OBJECT(child->widget),"label"); | |
| 1073 GtkWidget *delbt = g_object_get_data(G_OBJECT(child->widget),"delbt"); | |
| 1074 GtkTreeModel *combomodel; | |
| 1075 GtkTreeIter comboiter; | |
| 1076 combosas_helper_t *combosas_helper; | |
| 1077 gchar *input_str; | |
| 1078 | |
| 1079 combomodel = gtk_combo_box_get_model( GTK_COMBO_BOX(combobox) ); | |
| 1080 combosas_helper = g_malloc(sizeof(combosas_helper_t)); | |
| 1081 combosas_helper->combobox = combobox; | |
| 1082 combosas_helper->action_code = popul_binding[i].action_code; | |
| 1083 gtk_tree_model_foreach( combomodel , cfg_bindbox_populate_foreach_combosas , combosas_helper ); | |
| 1084 g_free( combosas_helper ); | |
| 1085 | |
| 1086 g_object_set_data_full( G_OBJECT(label) , "inputevent" , popul_binding[i].inputev , g_free ); | |
| 1087 input_str = g_strdup_printf( "%i:%i:%i" , | |
| 1088 popul_binding[i].inputev->type , | |
| 1089 popul_binding[i].inputev->code , | |
| 1090 popul_binding[i].inputev->value ); | |
| 1091 gtk_label_set_text( GTK_LABEL(label) , input_str ); | |
| 1092 g_free( input_str ); | |
| 1093 | |
| 1094 /* so, the current row wont' be the last one anymore; | |
| 1095 remove its "last" mark and enable its delete button */ | |
| 1096 g_object_set_data( G_OBJECT(child->widget) , "last" , GINT_TO_POINTER(0) ); | |
| 1097 gtk_widget_set_sensitive( delbt , TRUE ); | |
| 1098 cfg_bindbox_new_empty_row( GTK_TABLE(bind_table) , bindings_win , TRUE ); | |
| 1099 | |
| 1100 } | |
| 1101 } | |
| 1102 DEBUGMSG( "populating bindings window: code %i -> event %d:%d:%d\n" , | |
| 1103 popul_binding[i].action_code , popul_binding[i].inputev->type, | |
| 1104 popul_binding[i].inputev->code, popul_binding[i].inputev->value ); | |
| 1105 } | |
| 1106 g_free( popul_binding ); | |
| 1107 g_free( popul_container ); | |
| 1108 } | |
| 1109 return; | |
| 1110 } | |
| 1111 | |
| 1112 | |
| 1113 static void | |
| 1114 cfg_bindbox_new_empty_row( GtkTable * bind_table , GtkWidget * bindings_win , gboolean resize_table ) | |
| 1115 { | |
| 1116 GtkWidget *action_combobox; | |
| 1117 GtkCellRenderer *action_combobox_rndr; | |
| 1118 GtkWidget *assign_button; | |
| 1119 GtkWidget *assign_label; | |
| 1120 GtkWidget *delete_button; | |
| 1121 | |
| 1122 /* add one row to the table */ | |
| 1123 if ( resize_table == TRUE ) | |
| 1124 gtk_table_resize( bind_table , bind_table->nrows + 1 , bind_table->ncols ); | |
| 1125 | |
| 1126 /* action combobox */ | |
| 1127 action_combobox = gtk_combo_box_new_with_model( | |
| 1128 GTK_TREE_MODEL(g_object_get_data(G_OBJECT(bindings_win),"action_store")) ); | |
| 1129 action_combobox_rndr = gtk_cell_renderer_text_new(); | |
| 1130 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(action_combobox) , action_combobox_rndr , TRUE ); | |
| 1131 gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT(action_combobox) , | |
| 1132 action_combobox_rndr , "text" , 0 , NULL ); | |
| 1133 gtk_combo_box_set_active( GTK_COMBO_BOX(action_combobox) , 0 ); | |
| 1134 | |
| 1135 gtk_table_attach( bind_table , action_combobox , | |
| 1136 BINDLIST_COL_COMBO_ACTION , BINDLIST_COL_COMBO_ACTION + 1 , | |
| 1137 bind_table->nrows - 1 , bind_table->nrows , | |
| 1138 GTK_FILL , GTK_FILL , 0 , 0 ); | |
| 1139 | |
| 1140 /* assign button */ | |
| 1141 assign_button = gtk_button_new(); | |
| 1142 gtk_button_set_image( GTK_BUTTON(assign_button) , | |
| 1143 gtk_image_new_from_stock( GTK_STOCK_EXECUTE , GTK_ICON_SIZE_BUTTON ) ); | |
| 1144 g_object_set_data( G_OBJECT(assign_button) , "last" , GINT_TO_POINTER(1) ); | |
| 1145 g_signal_connect( G_OBJECT(assign_button) , "clicked" , | |
| 1146 G_CALLBACK(cfg_bindbox_assign_binding) , bindings_win ); | |
| 1147 | |
| 1148 gtk_table_attach( bind_table , assign_button , | |
| 1149 BINDLIST_COL_BT_ASSIGN , BINDLIST_COL_BT_ASSIGN + 1 , | |
| 1150 bind_table->nrows - 1 , bind_table->nrows , | |
| 1151 GTK_FILL , GTK_FILL , 0 , 0 ); | |
| 1152 | |
| 1153 /* assigned-code label */ | |
| 1154 assign_label = gtk_label_new( "" ); | |
| 1155 gtk_misc_set_alignment( GTK_MISC(assign_label) , 0 , 0.5 ); | |
| 1156 gtk_misc_set_padding( GTK_MISC(assign_label) , 10 , 0 ); | |
| 1157 g_object_set_data_full( G_OBJECT(assign_label) , "inputevent" , NULL , g_free ); | |
| 1158 | |
| 1159 gtk_table_attach( bind_table , assign_label , | |
| 1160 BINDLIST_COL_LABEL_EVCODE , BINDLIST_COL_LABEL_EVCODE +1 , | |
| 1161 bind_table->nrows - 1 , bind_table->nrows , | |
| 1162 GTK_EXPAND | GTK_FILL , GTK_FILL , 0 , 0 ); | |
| 1163 | |
| 1164 /* delete button */ | |
| 1165 delete_button = gtk_button_new(); | |
| 1166 gtk_button_set_image( GTK_BUTTON(delete_button) , | |
| 1167 gtk_image_new_from_stock( GTK_STOCK_DELETE , GTK_ICON_SIZE_BUTTON ) ); | |
| 1168 g_signal_connect( G_OBJECT(delete_button) , "clicked" , | |
| 1169 G_CALLBACK(cfg_bindbox_delete_row) , bindings_win ); | |
| 1170 gtk_widget_set_sensitive( delete_button , FALSE ); | |
| 1171 | |
| 1172 gtk_table_attach( bind_table , delete_button , | |
| 1173 BINDLIST_COL_BT_DELETE , BINDLIST_COL_BT_DELETE + 1 , | |
| 1174 bind_table->nrows - 1 , bind_table->nrows , | |
| 1175 GTK_FILL , GTK_FILL , 0 , 0 ); | |
| 1176 | |
| 1177 /* data for assign button */ | |
| 1178 g_object_set_data( G_OBJECT(assign_button) , "combobox" , action_combobox ); | |
| 1179 g_object_set_data( G_OBJECT(assign_button) , "label" , assign_label ); | |
| 1180 g_object_set_data( G_OBJECT(assign_button) , "delbt" , delete_button ); | |
| 1181 | |
| 1182 gtk_widget_show_all( GTK_WIDGET(bind_table) ); | |
| 1183 return; | |
| 1184 } | |
| 1185 | |
| 1186 | |
| 1187 static void | |
| 1188 cfg_bindings_cb_destroy ( GtkObject * bindings_win , gpointer dev_gp ) | |
| 1189 { | |
| 1190 ed_device_t *dev = dev_gp; | |
| 1191 /* bindings window is going to be destroyed; | |
| 1192 deactivate device listening and free the ed_device_t object */ | |
| 1193 g_source_remove( dev->iochan_sid ); | |
| 1194 ed_device_delete( dev ); | |
| 1195 | |
| 1196 /* the rowreference is no longer needed as well */ | |
| 1197 gtk_tree_row_reference_free( | |
| 1198 (GtkTreeRowReference*)g_object_get_data(G_OBJECT(bindings_win),"rowref") ); | |
| 1199 return; | |
| 1200 } | |
| 1201 | |
| 1202 | |
| 1203 static void | |
| 1204 cfg_bindings_cb_commit ( gpointer bindings_win ) | |
| 1205 { | |
| 1206 GtkTreeRowReference *rowref = g_object_get_data(G_OBJECT(bindings_win),"rowref"); | |
| 1207 if ( gtk_tree_row_reference_valid( rowref ) == TRUE ) | |
| 1208 { | |
| 1209 GtkTreeModel *model = gtk_tree_row_reference_get_model( rowref ); | |
| 1210 GtkTreePath *path = gtk_tree_row_reference_get_path( rowref ); | |
| 1211 GtkTreeIter iter; | |
| 1212 GtkTable *table; | |
| 1213 gpointer new_bindings = NULL, old_bindings = NULL; | |
| 1214 | |
| 1215 /****************************************************************************/ | |
| 1216 table = g_object_get_data( G_OBJECT(bindings_win) , "table" ); | |
| 1217 if ( table->nrows > 1 ) | |
| 1218 { | |
| 1219 /* bindings defined */ | |
| 1220 GList *children = table->children; | |
| 1221 gint *array_actioncode; | |
| 1222 ed_inputevent_t **array_inputevent; | |
| 1223 gint i = 0; | |
| 1224 | |
| 1225 array_actioncode = calloc( table->nrows - 1 , sizeof(gint) ); | |
| 1226 array_inputevent = calloc( table->nrows - 1 , sizeof(ed_inputevent_t*) ); | |
| 1227 | |
| 1228 for ( children ; children != NULL ; children = g_list_next( children ) ) | |
| 1229 { | |
| 1230 /* pick information from relevant table cells and put them in arrays */ | |
| 1231 GtkTableChild *child = children->data; | |
| 1232 | |
| 1233 if ( ( child->top_attach + 1 ) == table->nrows ) | |
| 1234 continue; /* skip last empty row */ | |
| 1235 | |
| 1236 if ( child->left_attach == BINDLIST_COL_COMBO_ACTION ) | |
| 1237 { | |
| 1238 GtkTreeModel *combomodel = gtk_combo_box_get_model( GTK_COMBO_BOX(child->widget) ); | |
| 1239 GtkTreeIter comboiter; | |
| 1240 gint actioncode = 0; | |
| 1241 | |
| 1242 gtk_combo_box_get_active_iter( GTK_COMBO_BOX(child->widget) , &comboiter ); | |
| 1243 gtk_tree_model_get( combomodel , &comboiter , 1 , &actioncode , -1 ); /* pick the action code */ | |
| 1244 array_actioncode[child->top_attach] = actioncode; | |
| 1245 } | |
| 1246 else if ( child->left_attach == BINDLIST_COL_LABEL_EVCODE ) | |
| 1247 { | |
| 1248 ed_inputevent_t *inputevent = g_object_get_data( G_OBJECT(child->widget) , "inputevent" ); | |
| 1249 array_inputevent[child->top_attach] = inputevent; | |
| 1250 } | |
| 1251 } | |
| 1252 | |
| 1253 /* ok, now copy data from arrays to the bindings store */ | |
| 1254 new_bindings = ed_bindings_store_new(); /* new bindings store object */ | |
| 1255 | |
| 1256 for ( i = 0 ; i < ( table->nrows - 1 ) ; i++ ) | |
| 1257 ed_bindings_store_insert( new_bindings , array_inputevent[i] , array_actioncode[i] ); | |
| 1258 | |
| 1259 g_free( array_actioncode ); g_free( array_inputevent ); /* not needed anymore */ | |
| 1260 } | |
| 1261 else | |
| 1262 { | |
| 1263 /* no bindings defined */ | |
| 1264 new_bindings = NULL; | |
| 1265 } | |
| 1266 /****************************************************************************/ | |
| 1267 | |
| 1268 /* pick old bindings store and delete it */ | |
| 1269 gtk_tree_model_get_iter( model , &iter , path ); | |
| 1270 gtk_tree_model_get( model , &iter, DEVLIST_COL_BINDINGS , &old_bindings , -1 ); | |
| 1271 if ( old_bindings != NULL ) | |
| 1272 ed_bindings_store_delete( old_bindings ); | |
| 1273 /* replace it with new one */ | |
| 1274 gtk_list_store_set( GTK_LIST_STORE(model) , &iter , DEVLIST_COL_BINDINGS , new_bindings , -1 ); | |
| 1275 /* everything done! */ | |
| 1276 } | |
| 1277 gtk_widget_destroy( GTK_WIDGET(bindings_win) ); | |
| 1278 } | |
| 1279 | |
| 1280 | |
| 1281 #define action_store_add(x) { gtk_list_store_append(action_store,&iter); gtk_list_store_set(action_store,&iter,0,player_actions[x].desc,1,x,-1); } | |
| 1282 | |
| 1283 static void | |
| 1284 cfg_ui_bindings_show ( ed_device_t * dev , GtkTreeRowReference * rowref ) | |
| 1285 { | |
| 1286 GtkWidget *bindings_win; | |
| 1287 GdkGeometry bindings_win_hints; | |
| 1288 GtkWidget *bindings_vbox; | |
| 1289 GtkWidget *bindings_info_table, *bindings_info_frame; | |
| 1290 GtkWidget *bindings_info_label_name_p, *bindings_info_label_name_c; | |
| 1291 GtkWidget *bindings_info_label_file_p, *bindings_info_label_file_c; | |
| 1292 GtkWidget *bindings_info_label_phys_p, *bindings_info_label_phys_c; | |
| 1293 GtkWidget *bindings_bind_frame, *bindings_bind_table, *bindings_bind_table_sw; | |
| 1294 GtkWidget *bindings_bbar_hbbox, *bindings_bbar_bt_cancel, *bindings_bbar_bt_ok; | |
| 1295 GtkListStore *action_store; | |
| 1296 GtkTreeIter iter; | |
| 1297 static gboolean style_added = FALSE; | |
| 1298 | |
| 1299 if ( !style_added ) | |
| 1300 { | |
| 1301 /* this is used by trigger dialogs, calling it once is enough */ | |
| 1302 gtk_rc_parse_string( "style \"noaaborder\" { GtkDialog::action-area-border = 0 }\n" | |
| 1303 "widget \"trigger_dlg\" style \"noaaborder\"\n" ); | |
| 1304 style_added = TRUE; | |
| 1305 } | |
| 1306 | |
| 1307 bindings_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); | |
| 1308 gtk_window_set_type_hint( GTK_WINDOW(bindings_win), GDK_WINDOW_TYPE_HINT_DIALOG ); | |
| 1309 gtk_window_set_position( GTK_WINDOW(bindings_win), GTK_WIN_POS_CENTER ); | |
| 1310 gtk_window_set_transient_for( GTK_WINDOW(bindings_win), GTK_WINDOW(cfg_win) ); | |
| 1311 gtk_window_set_modal( GTK_WINDOW(bindings_win) , TRUE ); | |
| 1312 gtk_window_set_title( GTK_WINDOW(bindings_win), _("EvDev-Plug - Bindings Configuration") ); | |
| 1313 gtk_container_set_border_width( GTK_CONTAINER(bindings_win), 10 ); | |
| 1314 bindings_win_hints.min_width = 400; | |
| 1315 bindings_win_hints.min_height = 400; | |
| 1316 gtk_window_set_geometry_hints( GTK_WINDOW(bindings_win) , GTK_WIDGET(bindings_win) , | |
| 1317 &bindings_win_hints , GDK_HINT_MIN_SIZE ); | |
| 1318 | |
| 1319 g_object_set_data( G_OBJECT(bindings_win) , "rowref" , rowref ); | |
| 1320 g_object_set_data( G_OBJECT(bindings_win) , "trigger-win" , NULL ); | |
| 1321 | |
| 1322 bindings_vbox = gtk_vbox_new( FALSE , 4 ); | |
| 1323 gtk_container_add( GTK_CONTAINER(bindings_win) , bindings_vbox ); | |
| 1324 | |
| 1325 /* action combobox model | |
| 1326 column 0 -> action desc | |
| 1327 column 1 -> action code */ | |
| 1328 action_store = gtk_list_store_new( 2 , G_TYPE_STRING , G_TYPE_INT ); | |
| 1329 action_store_add( ED_ACTION_PB_PLAY ); | |
| 1330 action_store_add( ED_ACTION_PB_STOP ); | |
| 1331 action_store_add( ED_ACTION_PB_PAUSE ); | |
| 1332 action_store_add( ED_ACTION_PB_PREV ); | |
| 1333 action_store_add( ED_ACTION_PB_NEXT ); | |
| 1334 action_store_add( ED_ACTION_PB_EJECT ); | |
| 1335 action_store_add( ED_ACTION_PL_REPEAT ); | |
| 1336 action_store_add( ED_ACTION_PL_SHUFFLE ); | |
| 1337 action_store_add( ED_ACTION_VOL_UP5 ); | |
| 1338 action_store_add( ED_ACTION_VOL_DOWN5 ); | |
| 1339 action_store_add( ED_ACTION_VOL_UP10 ); | |
| 1340 action_store_add( ED_ACTION_VOL_DOWN10 ); | |
| 1341 action_store_add( ED_ACTION_VOL_UP5 ); | |
| 1342 action_store_add( ED_ACTION_WIN_MAIN ); | |
| 1343 action_store_add( ED_ACTION_WIN_PLAYLIST ); | |
| 1344 action_store_add( ED_ACTION_WIN_EQUALIZER ); | |
| 1345 g_object_set_data_full( G_OBJECT(bindings_win) , "action_store" , action_store , g_object_unref ); | |
| 1346 | |
| 1347 /* info table */ | |
| 1348 bindings_info_table = gtk_table_new( 3 , 2 , FALSE ); | |
| 1349 gtk_container_set_border_width( GTK_CONTAINER(bindings_info_table), 4 ); | |
| 1350 bindings_info_label_name_p = gtk_label_new( "" ); | |
| 1351 gtk_label_set_markup( GTK_LABEL(bindings_info_label_name_p) , _("<b>Name: </b>") ); | |
| 1352 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_name_p) , 0 , 0.5 ); | |
| 1353 bindings_info_label_name_c = gtk_label_new( dev->info->name ); | |
| 1354 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_name_c) , 0 , 0.5 ); | |
| 1355 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_name_p , 0 , 1 , 0 , 1 , | |
| 1356 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1357 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_name_c , 1 , 2 , 0 , 1 , | |
| 1358 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1359 bindings_info_label_file_p = gtk_label_new( "" ); | |
| 1360 gtk_label_set_markup( GTK_LABEL(bindings_info_label_file_p) , _("<b>Filename: </b>") ); | |
| 1361 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_file_p) , 0 , 0.5 ); | |
| 1362 bindings_info_label_file_c = gtk_label_new( dev->info->filename ); | |
| 1363 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_file_c) , 0 , 0.5 ); | |
| 1364 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_file_p , 0 , 1 , 1 , 2 , | |
| 1365 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1366 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_file_c , 1 , 2 , 1 , 2 , | |
| 1367 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1368 bindings_info_label_phys_p = gtk_label_new( "" ); | |
| 1369 gtk_label_set_markup( GTK_LABEL(bindings_info_label_phys_p) , _("<b>Phys.Address: </b>") ); | |
| 1370 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_phys_p) , 0 , 0.5 ); | |
| 1371 bindings_info_label_phys_c = gtk_label_new( dev->info->phys ); | |
| 1372 gtk_misc_set_alignment( GTK_MISC(bindings_info_label_phys_c) , 0 , 0.5 ); | |
| 1373 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_phys_p , 0 , 1 , 2 , 3 , | |
| 1374 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1375 gtk_table_attach( GTK_TABLE(bindings_info_table) , bindings_info_label_phys_c , 1 , 2 , 2 , 3 , | |
| 1376 GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 0 ); | |
| 1377 bindings_info_frame = gtk_frame_new( NULL ); | |
| 1378 gtk_container_add( GTK_CONTAINER(bindings_info_frame) , bindings_info_table ); | |
| 1379 gtk_box_pack_start( GTK_BOX(bindings_vbox) , bindings_info_frame , FALSE , FALSE , 0 ); | |
| 1380 | |
| 1381 /* bindings boxlist */ | |
| 1382 bindings_bind_table = gtk_table_new( 1 , BINDLIST_NUMCOLS , FALSE ); | |
| 1383 cfg_bindbox_new_empty_row( GTK_TABLE(bindings_bind_table) , bindings_win , FALSE ); | |
| 1384 cfg_bindbox_populate( bindings_bind_table , bindings_win , dev->info->bindings ); | |
| 1385 bindings_bind_table_sw = gtk_scrolled_window_new( NULL , NULL ); | |
| 1386 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(bindings_bind_table_sw) , | |
| 1387 GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); | |
| 1388 bindings_bind_frame = gtk_frame_new( NULL ); | |
| 1389 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(bindings_bind_table_sw) , | |
| 1390 bindings_bind_table ); | |
| 1391 gtk_container_add( GTK_CONTAINER(bindings_bind_frame) , bindings_bind_table_sw ); | |
| 1392 gtk_box_pack_start( GTK_BOX(bindings_vbox) , bindings_bind_frame , TRUE , TRUE , 0 ); | |
| 1393 g_object_set_data( G_OBJECT(bindings_win) , "table" , bindings_bind_table ); | |
| 1394 g_object_set_data( G_OBJECT(bindings_win) , "tablesw" , bindings_bind_table_sw ); | |
| 1395 | |
| 1396 gtk_box_pack_start( GTK_BOX(bindings_vbox) , gtk_hseparator_new() , FALSE , FALSE , 0 ); | |
| 1397 | |
| 1398 /* button bar */ | |
| 1399 bindings_bbar_hbbox = gtk_hbutton_box_new(); | |
| 1400 gtk_button_box_set_layout( GTK_BUTTON_BOX(bindings_bbar_hbbox) , GTK_BUTTONBOX_START ); | |
| 1401 bindings_bbar_bt_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL ); | |
| 1402 bindings_bbar_bt_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); | |
| 1403 gtk_container_add( GTK_CONTAINER(bindings_bbar_hbbox) , bindings_bbar_bt_cancel ); | |
| 1404 gtk_container_add( GTK_CONTAINER(bindings_bbar_hbbox) , bindings_bbar_bt_ok ); | |
| 1405 gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(bindings_bbar_hbbox) , bindings_bbar_bt_cancel , TRUE ); | |
| 1406 gtk_button_box_set_child_secondary( GTK_BUTTON_BOX(bindings_bbar_hbbox) , bindings_bbar_bt_ok , TRUE ); | |
| 1407 gtk_box_pack_start( GTK_BOX(bindings_vbox) , bindings_bbar_hbbox , FALSE , FALSE , 0 ); | |
| 1408 | |
| 1409 /* activate device listening */ | |
| 1410 dev->iochan_sid = g_io_add_watch( dev->iochan , G_IO_IN , | |
| 1411 (GIOFunc)cfg_bindbox_assign_binding_input_func , bindings_win ); | |
| 1412 | |
| 1413 /* signals */ | |
| 1414 g_signal_connect( G_OBJECT(bindings_win) , "destroy" , | |
| 1415 G_CALLBACK(cfg_bindings_cb_destroy) , dev ); | |
| 1416 g_signal_connect_swapped( G_OBJECT(bindings_bbar_bt_cancel) , "clicked" , | |
| 1417 G_CALLBACK(gtk_widget_destroy) , bindings_win ); | |
| 1418 g_signal_connect_swapped( G_OBJECT(bindings_bbar_bt_ok) , "clicked" , | |
| 1419 G_CALLBACK(cfg_bindings_cb_commit) , bindings_win ); | |
| 1420 | |
| 1421 gtk_widget_show_all( bindings_win ); | |
| 1422 } | |
| 1423 | |
| 1424 | |
| 1425 | |
| 1426 /* about box */ | |
| 1427 void | |
| 1428 ed_ui_about_show( void ) | |
| 1429 { | |
| 1430 static GtkWidget *about_win = NULL; | |
| 1431 GtkWidget *about_vbox; | |
| 1432 GtkWidget *logoandinfo_vbox; | |
| 1433 GtkWidget *info_tv, *info_tv_sw, *info_tv_frame; | |
| 1434 GtkWidget *bbar_bbox, *bbar_bt_ok; | |
| 1435 GtkTextBuffer *info_tb; | |
| 1436 GdkGeometry abount_win_hints; | |
| 1437 | |
| 1438 if ( about_win != NULL ) | |
| 1439 { | |
| 1440 gtk_window_present( GTK_WINDOW(about_win) ); | |
| 1441 return; | |
| 1442 } | |
| 1443 | |
| 1444 about_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); | |
| 1445 gtk_window_set_type_hint( GTK_WINDOW(about_win), GDK_WINDOW_TYPE_HINT_DIALOG ); | |
| 1446 gtk_window_set_position( GTK_WINDOW(about_win), GTK_WIN_POS_CENTER ); | |
| 1447 gtk_window_set_title( GTK_WINDOW(about_win), _("EvDev-Plug - about") ); | |
| 1448 abount_win_hints.min_width = 420; | |
| 1449 abount_win_hints.min_height = 200; | |
| 1450 gtk_window_set_geometry_hints( GTK_WINDOW(about_win) , GTK_WIDGET(about_win) , | |
| 1451 &abount_win_hints , GDK_HINT_MIN_SIZE ); | |
| 1452 /* gtk_window_set_resizable( GTK_WINDOW(about_win) , FALSE ); */ | |
| 1453 gtk_container_set_border_width( GTK_CONTAINER(about_win) , 10 ); | |
| 1454 g_signal_connect( G_OBJECT(about_win) , "destroy" , G_CALLBACK(gtk_widget_destroyed) , &about_win ); | |
| 1455 | |
| 1456 about_vbox = gtk_vbox_new( FALSE , 0 ); | |
| 1457 gtk_container_add( GTK_CONTAINER(about_win) , about_vbox ); | |
| 1458 | |
| 1459 logoandinfo_vbox = gtk_vbox_new( TRUE , 2 ); | |
| 1460 | |
| 1461 /* TODO make a logo or make someone do it! :) | |
| 1462 logo_pixbuf = gdk_pixbuf_new_from_xpm_data( (const gchar **)evdev_plug_logo_xpm ); | |
| 1463 logo_image = gtk_image_new_from_pixbuf( logo_pixbuf ); | |
| 1464 g_object_unref( logo_pixbuf ); | |
| 1465 | |
| 1466 logo_frame = gtk_frame_new( NULL ); | |
| 1467 gtk_container_add( GTK_CONTAINER(logo_frame) , logo_image ); | |
| 1468 gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , logo_frame , TRUE , TRUE , 0 ); */ | |
| 1469 | |
| 1470 info_tv = gtk_text_view_new(); | |
| 1471 info_tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(info_tv) ); | |
| 1472 gtk_text_view_set_editable( GTK_TEXT_VIEW(info_tv) , FALSE ); | |
| 1473 gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(info_tv) , FALSE ); | |
| 1474 gtk_text_view_set_justification( GTK_TEXT_VIEW(info_tv) , GTK_JUSTIFY_LEFT ); | |
| 1475 gtk_text_view_set_left_margin( GTK_TEXT_VIEW(info_tv) , 10 ); | |
| 1476 | |
| 1477 gtk_text_buffer_set_text( info_tb , | |
| 1478 _("\nEvDev-Plug " ED_VERSION_PLUGIN | |
| 1479 "\nplayer remote control via event devices\n" | |
| 1480 "http://www.develia.org/projects.php?p=evdevplug\n\n" | |
| 1481 "written by Giacomo Lozito\n" | |
| 1482 "< james@develia.org >\n\n") , -1 ); | |
| 1483 | |
| 1484 info_tv_sw = gtk_scrolled_window_new( NULL , NULL ); | |
| 1485 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(info_tv_sw) , | |
| 1486 GTK_POLICY_NEVER , GTK_POLICY_ALWAYS ); | |
| 1487 gtk_container_add( GTK_CONTAINER(info_tv_sw) , info_tv ); | |
| 1488 info_tv_frame = gtk_frame_new( NULL ); | |
| 1489 gtk_container_add( GTK_CONTAINER(info_tv_frame) , info_tv_sw ); | |
| 1490 gtk_box_pack_start( GTK_BOX(logoandinfo_vbox) , info_tv_frame , TRUE , TRUE , 0 ); | |
| 1491 | |
| 1492 gtk_box_pack_start( GTK_BOX(about_vbox) , logoandinfo_vbox , TRUE , TRUE , 0 ); | |
| 1493 | |
| 1494 /* horizontal separator and buttons */ | |
| 1495 gtk_box_pack_start( GTK_BOX(about_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); | |
| 1496 bbar_bbox = gtk_hbutton_box_new(); | |
| 1497 gtk_button_box_set_layout( GTK_BUTTON_BOX(bbar_bbox) , GTK_BUTTONBOX_END ); | |
| 1498 bbar_bt_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); | |
| 1499 g_signal_connect_swapped( G_OBJECT(bbar_bt_ok) , "clicked" , | |
| 1500 G_CALLBACK(gtk_widget_destroy) , about_win ); | |
| 1501 gtk_container_add( GTK_CONTAINER(bbar_bbox) , bbar_bt_ok ); | |
| 1502 gtk_box_pack_start( GTK_BOX(about_vbox) , bbar_bbox , FALSE , FALSE , 0 ); | |
| 1503 | |
| 1504 gtk_widget_show_all( about_win ); | |
| 1505 } | |
| 1506 | |
| 1507 | |
| 1508 | |
| 1509 /* message box */ | |
| 1510 void | |
| 1511 ed_ui_message_show ( gchar * title , gchar * message , gpointer parent_win_gp ) | |
| 1512 { | |
| 1513 GtkWidget *message_win; | |
| 1514 GtkWindow *parent_win = NULL; | |
| 1515 | |
| 1516 if (( parent_win_gp != NULL ) && ( GTK_WIDGET_TOPLEVEL(GTK_WIDGET(parent_win_gp)) )) | |
| 1517 parent_win = GTK_WINDOW(parent_win_gp); | |
| 1518 | |
| 1519 message_win = gtk_message_dialog_new( | |
| 1520 parent_win , | |
| 1521 ( parent_win != NULL ? GTK_DIALOG_DESTROY_WITH_PARENT : 0 ) , | |
| 1522 GTK_MESSAGE_INFO , GTK_BUTTONS_CLOSE , message ); | |
| 1523 gtk_window_set_title( GTK_WINDOW(message_win) , title ); | |
| 1524 | |
| 1525 gtk_dialog_run( GTK_DIALOG(message_win) ); | |
| 1526 gtk_widget_destroy( message_win ); | |
| 1527 } |
