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