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 }