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 } |