801ae90095a8c55d8f18b841f2514a843ce7f038
[rugen] / src / dv1394app.c
1 /*
2 * dv1394app.c -- GTK+ 2 dv1394d client demo
3 * Copyright (C) 2002-2003 Charles Yates <charles.yates@pandora.be>
4 * Copyright (C) 2010 Dan Dennedy <dan@dennedy.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #include "interface.h"
32 #include "support.h"
33 #include "dv1394app.h"
34 #include "page.h"
35 #include "gtkenhancedscale.h"
36 #include <mvcp/mvcp_remote.h>
37 #include <melted/melted_local.h>
38
39
40 /** Window close event.
41 */
42
43 static gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data )
44 {
45 gtk_exit( 0 );
46 return TRUE;
47 }
48
49 static gboolean instance_connect( dv1394app this, char *server, char *port )
50 {
51 if ( this->parser == NULL )
52 {
53 if ( strstr( server, ".conf" ) == NULL )
54 this->parser = mvcp_parser_init_remote( server, atoi( port ) );
55 else
56 this->parser = melted_parser_init_local( );
57
58 this->command = mvcp_init( this->parser );
59
60 if ( strstr( server, ".conf" ) != NULL )
61 mvcp_run( this->command, server );
62
63 if ( mvcp_connect( this->command ) == mvcp_ok )
64 {
65 struct timespec t = { 1, 0 };
66 nanosleep( &t, NULL );
67 //gdk_threads_leave( );
68 dv1394app_connect( this );
69 //gdk_threads_enter( );
70 }
71 else
72 {
73 mvcp_close( this->command );
74 mvcp_parser_close( this->parser );
75 this->parser = NULL;
76 // beep( );
77 }
78 }
79
80 return this->parser != NULL;
81 }
82
83 /** Connection window - Connect button pressed.
84 */
85
86 static gboolean on_connect_pressed( GtkWidget *button, gpointer user_data )
87 {
88 dv1394app this = user_data;
89 GtkWidget *widget;
90 char *server;
91 char *port;
92
93 if ( this->parser == NULL )
94 {
95 widget = lookup_widget( this->connect, "entry_server" );
96 server = ( char * )gtk_entry_get_text( GTK_ENTRY( widget ) );
97 widget = lookup_widget( this->connect, "entry_port" );
98 port = ( char * )gtk_entry_get_text( GTK_ENTRY( widget ) );
99 instance_connect( this, server, port );
100 }
101 gtk_widget_destroy( this->connect );
102 this->guard = 1;
103 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_connect" ) ), TRUE );
104 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_disconnect" ) ), FALSE );
105 this->guard = 0;
106
107 return FALSE;
108 }
109
110 /** Connection window - Cancel button pressed.
111 */
112
113 static gboolean on_cancel_pressed( GtkWidget *button, gpointer user_data )
114 {
115 dv1394app this = user_data;
116 if ( this->guard ) return FALSE;
117 gtk_widget_destroy( this->connect );
118 return FALSE;
119 }
120
121 /** Main window - connect menu item selected.
122 */
123
124 void on_item_connect_activate( GtkMenuItem *menuitem, gpointer user_data )
125 {
126 dv1394app this = user_data;
127 GtkWidget *widget;
128
129 if ( this->guard ) return;
130 this->connect = create_window_connection( );
131
132 /* Connection set up handling */
133 widget = lookup_widget( this->connect, "button_connect" );
134 gtk_signal_connect( GTK_OBJECT( widget ), "clicked", GTK_SIGNAL_FUNC( on_connect_pressed ), this );
135 widget = lookup_widget( this->connect, "button_cancel" );
136 gtk_signal_connect( GTK_OBJECT( widget ), "clicked", GTK_SIGNAL_FUNC( on_cancel_pressed ), this );
137
138 gtk_widget_show( this->connect );
139 }
140
141 /** Main window - disconnect menu item selected.
142 */
143
144 void on_item_disconnect_activate( GtkMenuItem *menuitem, gpointer user_data )
145 {
146 dv1394app this = user_data;
147
148 if ( this->guard ) return;
149 dv1394app_disconnect( this );
150
151 this->guard = 1;
152 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_connect" ) ), FALSE );
153 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_disconnect" ) ), TRUE );
154 this->guard = 0;
155 }
156
157 /** Main window - quit menu item selected.
158 */
159
160 void on_item_quit_activate( GtkMenuItem *menuitem, gpointer user_data )
161 {
162 gtk_main_quit( );
163 }
164
165 static gboolean on_page_switch_pressed( GtkWidget *button, gpointer user_data )
166 {
167 dv1394app this = user_data;
168 int index = 0;
169 GtkWidget *notebook = lookup_widget( button, "notebook1" );
170
171 if ( this->guard ) return TRUE;
172 this->guard = 1;
173 for ( index = 0; index < this->page_count; index ++ )
174 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( this->page_buttons[ index ] ), FALSE );
175 for ( index = 0; index < this->page_count; index ++ )
176 {
177 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( this->page_buttons[ index ] ), FALSE );
178 if ( this->page_buttons[ index ] == button )
179 break;
180 }
181 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( this->page_buttons[ index ] ), TRUE );
182 gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook ), index );
183 this->guard = 0;
184
185 return TRUE;
186 }
187
188 static gboolean on_transport_pressed( GtkWidget *button, gpointer data )
189 {
190 int index = 0;
191 dv1394app this = ( dv1394app )data;
192 mvcp dv = dv1394app_get_command( this );
193 int unit = dv1394app_get_selected_unit( this );
194
195 for ( index = 0; index < 11; index ++ )
196 if ( this->buttons[ index ] == button )
197 break;
198
199 switch( index )
200 {
201 case 0:
202 mvcp_unit_clip_goto( dv, unit, mvcp_absolute, 0, 0 );
203 break;
204
205 case 1:
206 mvcp_unit_goto( dv, unit, 0 );
207 break;
208
209 case 2:
210 mvcp_unit_rewind( dv, unit );
211 break;
212
213 case 3:
214 mvcp_unit_step( dv, unit, -1 );
215 break;
216
217 case 4:
218 mvcp_unit_pause( dv, unit );
219 break;
220
221 case 5:
222 mvcp_unit_play( dv, unit );
223 break;
224
225 case 6:
226 mvcp_unit_stop( dv, unit );
227 break;
228
229 case 7:
230 mvcp_unit_step( dv, unit, 1 );
231 break;
232
233 case 8:
234 mvcp_unit_fast_forward( dv, unit );
235 break;
236
237 case 9:
238 mvcp_unit_clip_goto( dv, unit, mvcp_relative, 1, 0 );
239 break;
240
241 case 10:
242 mvcp_unit_clip_goto( dv, unit, mvcp_absolute, 9999, -1 );
243 break;
244
245 default:
246 break;
247 }
248
249 return TRUE;
250 }
251
252 static void dv1394app_register_page( dv1394app this, page item )
253 {
254 GtkWidget *toolbar = lookup_widget( this->window, "toolbar1" );
255 GtkIconSize size = gtk_toolbar_get_icon_size( GTK_TOOLBAR( toolbar ) );
256 GtkWidget *widget = lookup_widget( this->window, "notebook1" );
257 GtkWidget *bin = gtk_frame_new( NULL );
258 char *label = NULL;
259
260 this->pages[ this->page_count ] = item;
261 gtk_widget_reparent( GTK_BIN( page_get_widget( item ) )->child, bin );
262 gtk_container_add(GTK_CONTAINER( widget ), bin );
263 gtk_frame_set_label_align( GTK_FRAME( bin ), 0, 0 );
264 gtk_frame_set_shadow_type( GTK_FRAME( bin ), GTK_SHADOW_NONE );
265 gtk_widget_show( bin );
266
267 page_get_toolbar_info( item, size, &widget, &label );
268 this->page_buttons[ this->page_count ] = gtk_toolbar_append_element( GTK_TOOLBAR ( toolbar ), GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NULL, label, NULL, NULL, widget, NULL, NULL);
269 gtk_label_set_use_underline( GTK_LABEL(((GtkToolbarChild*)(g_list_last( GTK_TOOLBAR( toolbar )->children)->data))->label), TRUE);
270 gtk_widget_show( widget );
271 gtk_signal_connect( GTK_OBJECT( this->page_buttons[ this->page_count ] ), "clicked", GTK_SIGNAL_FUNC( on_page_switch_pressed ), this );
272 gtk_signal_connect( GTK_OBJECT( this->page_buttons[ this->page_count ] ), "activate", GTK_SIGNAL_FUNC( on_page_switch_pressed ), this );
273
274 this->page_count ++;
275 }
276
277 static GtkAdjustment *trim_adj[3];
278 #define TRIM_ADJ_POS 0
279 #define TRIM_ADJ_IN 1
280 #define TRIM_ADJ_OUT 2
281
282 void dv1394app_show_status( dv1394app this, mvcp_status status )
283 {
284 int index = 0;
285 for ( index = 0; index < this->page_count; index ++ )
286 page_show_status( this->pages[ index ], status );
287
288 if ( status->seek_flag != this->seek_flag )
289 {
290 gtk_widget_set_sensitive( lookup_widget( dv1394app_get_widget( this ), "transport_2" ), status->seek_flag );
291 gtk_widget_set_sensitive( lookup_widget( dv1394app_get_widget( this ), "transport_3" ), status->seek_flag );
292 gtk_widget_set_sensitive( lookup_widget( dv1394app_get_widget( this ), "transport_7" ), status->seek_flag );
293 gtk_widget_set_sensitive( lookup_widget( dv1394app_get_widget( this ), "transport_8" ), status->seek_flag );
294 this->seek_flag = status->seek_flag;
295 }
296
297 if ( !this->trim_in_use )
298 {
299 int upper = status->length > 0 ? status->length - 1 : 0;
300 trim_adj[TRIM_ADJ_IN]->upper = upper;
301 trim_adj[TRIM_ADJ_IN]->value = status->in;
302 trim_adj[TRIM_ADJ_OUT]->upper = upper;
303 trim_adj[TRIM_ADJ_OUT]->value = status->out;
304 trim_adj[TRIM_ADJ_POS]->upper = upper;
305 trim_adj[TRIM_ADJ_POS]->value = status->position;
306 gtk_signal_emit_by_name( GTK_OBJECT(trim_adj[TRIM_ADJ_POS]), "value_changed" );
307 }
308 }
309
310 static gboolean trim_pressed( GtkWidget *button, GdkEventButton *event, gpointer user_data )
311 {
312 dv1394app this = (dv1394app)user_data;
313 mvcp_unit_pause( dv1394app_get_command( this ), this->selected_unit );
314 this->trim_in = -1;
315 this->trim_out = -1;
316 this->trim_in_use = 1;
317 return FALSE;
318 }
319
320 static gboolean trim_released( GtkWidget *button, GdkEventButton *event, gpointer user_data )
321 {
322 dv1394app this = (dv1394app)user_data;
323 this->trim_in_use = 0;
324 if ( this->trim_in != -1 )
325 mvcp_unit_set_in( dv1394app_get_command( this ), this->selected_unit, this->trim_in );
326 if ( this->trim_out != -1 )
327 mvcp_unit_set_out( dv1394app_get_command( this ), this->selected_unit, this->trim_out );
328 return TRUE;
329 }
330
331 static gboolean on_trim_value_changed_event( GtkWidget *button, gpointer user_data )
332 {
333 dv1394app this = (dv1394app)user_data;
334 if ( this->trim_in_use )
335 {
336 char *value;
337 g_object_get( G_OBJECT( button ), "user_data", &value, NULL );
338
339 if ( !strcmp( value, "position" ) )
340 {
341 mvcp_unit_goto( dv1394app_get_command( this ), this->selected_unit, trim_adj[TRIM_ADJ_POS]->value );
342 }
343 else if ( !strcmp( value, "in" ) )
344 {
345 this->trim_in = trim_adj[TRIM_ADJ_IN]->value;
346 mvcp_unit_goto( dv1394app_get_command( this ), this->selected_unit, trim_adj[TRIM_ADJ_IN]->value );
347 }
348 else if ( !strcmp( value, "out" ) )
349 {
350 this->trim_out = trim_adj[TRIM_ADJ_OUT]->value;
351 mvcp_unit_goto( dv1394app_get_command( this ), this->selected_unit, trim_adj[TRIM_ADJ_OUT]->value );
352 }
353
354 gtk_widget_queue_draw (lookup_widget(this->window, "vbox_trim") );
355 return TRUE;
356 }
357 return FALSE;
358 }
359
360 /** Initialiser for application state.
361 */
362
363 dv1394app dv1394app_init( GtkWidget *window, char *instance )
364 {
365 dv1394app this = calloc( 1, sizeof( dv1394app_t ) );
366
367 if ( this != NULL )
368 {
369 GtkWidget *widget;
370
371 this->window = window;
372
373 /* Window destroy event */
374 gtk_signal_connect( GTK_OBJECT( this->window ), "destroy", GTK_SIGNAL_FUNC( on_main_window_delete_event ), this );
375
376 /* Menu item signal handling */
377 // widget = lookup_widget( this->window, "item_connect" );
378 // gtk_signal_connect( GTK_OBJECT( widget ), "activate", GTK_SIGNAL_FUNC( on_item_connect_activate ), this );
379 widget = lookup_widget( this->window, "button_connect" );
380 gtk_signal_connect( GTK_OBJECT( widget ), "clicked", GTK_SIGNAL_FUNC( on_item_connect_activate ), this );
381 // widget = lookup_widget( this->window, "item_disconnect" );
382 // gtk_signal_connect( GTK_OBJECT( widget ), "activate", GTK_SIGNAL_FUNC( on_item_disconnect_activate ), this );
383 widget = lookup_widget( this->window, "button_disconnect" );
384 gtk_signal_connect( GTK_OBJECT( widget ), "clicked", GTK_SIGNAL_FUNC( on_item_disconnect_activate ), this );
385 // widget = lookup_widget( this->window, "item_quit" );
386 // gtk_signal_connect( GTK_OBJECT( widget ), "activate", GTK_SIGNAL_FUNC( on_item_quit_activate ), this );
387 // widget = lookup_widget( this->window, "button_quit" );
388 // gtk_signal_connect( GTK_OBJECT( widget ), "clicked", GTK_SIGNAL_FUNC( on_item_quit_activate ), this );
389
390 /* Initialise the pages. */
391 dv1394app_register_page( this, page_status_init( this ) );
392 dv1394app_register_page( this, page_clips_init( this ) );
393 dv1394app_register_page( this, page_command_init( this ) );
394 this->guard = 1;
395 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( this->page_buttons[ 0 ] ), TRUE );
396 this->guard = 0;
397
398 /* Remove the empty page */
399 widget = lookup_widget( this->window, "notebook1" );
400 gtk_notebook_remove_page( GTK_NOTEBOOK( widget ), 0 );
401
402 guint keys[ ] = { GDK_0, GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_A };
403 int index;
404 GtkAccelGroup *accel_group = gtk_accel_group_new( );
405
406 for ( index = 0; index < 11; index ++ )
407 {
408 char name[ 256 ];
409 sprintf( name, "transport_%d", index );
410 this->buttons[ index ] = lookup_widget( dv1394app_get_widget( this ), name );
411 gtk_signal_connect( GTK_OBJECT( this->buttons[ index ] ), "clicked", GTK_SIGNAL_FUNC( on_transport_pressed ), this );
412 gtk_widget_add_accelerator( this->buttons[ index ], "clicked", accel_group, keys[ index ], GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE );
413 }
414
415 gtk_window_add_accel_group( GTK_WINDOW( dv1394app_get_widget( this ) ), accel_group);
416
417 trim_adj[TRIM_ADJ_POS] = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 1000, 1, 10, 0 ) );
418 g_object_set( G_OBJECT( trim_adj[TRIM_ADJ_POS] ), "user_data", "position", NULL );
419 trim_adj[TRIM_ADJ_IN] = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 1000, 1, 10, 0 ) );
420 g_object_set( G_OBJECT( trim_adj[TRIM_ADJ_IN] ), "user_data", "in", NULL );
421 trim_adj[TRIM_ADJ_OUT] = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 1000, 1, 10, 0 ) );
422 g_object_set( G_OBJECT( trim_adj[TRIM_ADJ_OUT] ), "user_data", "out", NULL );
423
424 int i;
425 for (i = 0; i < 3; i++)
426 gtk_signal_connect (GTK_OBJECT (trim_adj[i]), "value_changed", GTK_SIGNAL_FUNC (on_trim_value_changed_event), this );
427
428 GtkWidget *trim = gtk_enhanced_scale_new( (GtkObject**) trim_adj, 3);
429 if ( trim != NULL )
430 {
431 gtk_widget_set_name (trim, "trim");
432 GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( trim ), GTK_CAN_FOCUS );
433 gtk_widget_ref(trim);
434 gtk_object_set_data_full (GTK_OBJECT( this->window ), "trim", trim, (GtkDestroyNotify) gtk_widget_unref);
435 GtkWidget *vbox_trim = lookup_widget(this->window, "vbox_trim");
436 gtk_widget_show(trim);
437 gtk_box_pack_start(GTK_BOX (vbox_trim), trim, TRUE, TRUE, 0);
438 gtk_signal_connect( GTK_OBJECT( trim ), "button_press_event", GTK_SIGNAL_FUNC (trim_pressed), this );
439 gtk_signal_connect( GTK_OBJECT( trim ), "button_release_event", GTK_SIGNAL_FUNC (trim_released), this );
440 }
441 this->seek_flag = 1;
442 }
443
444 if ( instance != NULL )
445 {
446 char *server = strdup( instance );
447 char *port = strchr( server, ':' );
448 if ( port != NULL )
449 *port ++ = '\0';
450 else
451 port = "5250";
452 this->guard = 1;
453 if ( instance_connect( this, server, port ) )
454 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_connect" ) ), TRUE );
455 else
456 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( lookup_widget( this->window, "button_disconnect" ) ), TRUE );
457 this->guard = 0;
458 free( server );
459 }
460
461
462 return this;
463 }
464
465 /** Get the app window widget.
466 */
467
468 GtkWidget *dv1394app_get_widget( dv1394app this )
469 {
470 return this->window;
471 }
472
473 /** Get the applications parser.
474 */
475
476 mvcp_parser dv1394app_get_parser( dv1394app this )
477 {
478 return this->parser;
479 }
480
481 /** Return the command parser.
482 */
483
484 mvcp dv1394app_get_command( dv1394app this )
485 {
486 return this->command;
487 }
488
489 /** Issue a connect to all pages.
490 */
491
492 void dv1394app_connect( dv1394app this )
493 {
494 int index = 0;
495 for ( index = 0; index < this->page_count; index ++ )
496 page_on_connect( this->pages[ index ] );
497 }
498
499 /** Inform all pages that the unit has changed.
500 */
501
502 void dv1394app_on_unit_change( dv1394app this, int unit )
503 {
504 int index = 0;
505 this->selected_unit = unit;
506 for ( index = 0; index < this->page_count; index ++ )
507 page_on_unit_change( this->pages[ index ], unit );
508 }
509
510 /** Return the selected unit.
511 */
512
513 int dv1394app_get_selected_unit( dv1394app this )
514 {
515 return this->selected_unit;
516 }
517
518 /** Issue a disconnect to all pages.
519 */
520
521 void dv1394app_disconnect( dv1394app this )
522 {
523 int index = 0;
524 if ( this->parser != NULL )
525 {
526 for ( index = 0; index < this->page_count; index ++ )
527 page_on_disconnect( this->pages[ index ] );
528 mvcp_close( this->command );
529 this->command = NULL;
530 mvcp_parser_close( this->parser );
531 this->parser = NULL;
532 }
533 }
534
535 /** Close application.
536 */
537
538 void dv1394app_close( dv1394app this )
539 {
540 dv1394app_disconnect( this );
541 while ( this->page_count > 0 )
542 page_close( this->pages[ -- this->page_count ] );
543 free( this );
544 }