1 /*
2  * gtv - a Gtk+ based SMPEG player
3  * (c) Michael Vance, 1999
4  *     briareos@lokigames.com
5  *
6  * TODO
7  * - SMPEG returns an incorrect current_frame after a
8  * call to SMPEG_renderFinal().
9  * - SMPEG loops audio incorrectly when audio stream is
10  * shorter than a video stream, etc.
11  */
12 
13 #include "gtv.h"
14 #include "SDL_syswm.h"
15 
16 #define TIMER_TIMEOUT 100
17 
18 static GtkWidget* create_gtv_window( void );
19 static void gtv_connect( gpointer, gchar*, gchar*, GtkSignalFunc );
20 static void gtv_set_frame( gpointer, int );
21 static void gtv_set_fps( gpointer, float );
22 static void gtv_set_trackbar( gpointer, int );
23 static void gtv_set_sensitive( gpointer, gchar*, gboolean );
24 static void gtv_clear_screen( gpointer );
25 static void gtv_fix_toggle_state( gpointer );
26 
27 static void gtv_double( GtkWidget*, gpointer );
28 static void gtv_loop( GtkWidget*, gpointer );
29 static void gtv_audio( GtkWidget*, gpointer );
30 static void gtv_filter( GtkWidget*, gpointer );
31 
32 static void gtv_open( GtkWidget*, gpointer );
33 static void gtv_open_file( gchar*, gpointer );
34 static void gtv_close( GtkWidget*, gpointer );
35 static void gtv_info( GtkWidget*, gpointer );
36 static void gtv_quit( GtkWidget*, gpointer );
37 static void gtv_about( GtkWidget*, gpointer );
38 
39 static void gtv_play( GtkWidget*, gpointer );
40 static void gtv_pause( GtkWidget*, gpointer );
41 static void gtv_stop( GtkWidget*, gpointer );
42 static void gtv_step( GtkWidget*, gpointer );
43 static void gtv_to_end( GtkWidget*, gpointer );
44 static void gtv_seek( GtkAdjustment*, gpointer );
45 static void gtv_drag_data_received(GtkWidget * widget,
46                                    GdkDragContext * context,
47                                    gint x, gint y,
48                                    GtkSelectionData * selection_data,
49                                    guint info, guint time);
50 
51 
52 static int gtv_trackbar_dragging;
53 static gchar * gtv_default_directory = 0;
54 
gtv_fix_toggle_state(gpointer raw)55 static void gtv_fix_toggle_state( gpointer raw )
56 {
57     SMPEG* mpeg = NULL;
58 
59     assert( raw );
60 
61     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
62 
63     /* If no mpeg is loaded, pop all the buttons. */
64     if( !mpeg ) {
65 	GtkWidget* twotimes = NULL;
66 	GtkWidget* loop = NULL;
67 	GtkWidget* audio = NULL;
68 	GtkWidget* filter = NULL;
69 
70 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
71 	loop = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "loop" ) );
72 	audio = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "audio" ) );
73 	filter = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "filter" ) );
74 
75 #if 1 /* Sam 5/31/2000 - Default to doubled video and audio on */
76 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), FALSE );
77 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( loop ), FALSE );
78 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( audio ), TRUE );
79 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( filter ), FALSE );
80 #else
81 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( twotimes ), FALSE );
82 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( loop ), FALSE );
83 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( audio ), FALSE );
84 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( filter ), FALSE );
85 #endif
86     }
87 
88 }
89 
gtv_set_sensitive(gpointer raw,gchar * name,gboolean sensitive)90 static void gtv_set_sensitive( gpointer raw, gchar* name, gboolean sensitive )
91 {
92     GtkWidget* item = NULL;
93 
94     assert( raw );
95     assert( name );
96 
97     item = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), name ) );
98     assert( item );
99     gtk_widget_set_sensitive( item, sensitive );
100 }
101 
gtv_set_buttons_sensitive(gpointer raw,gboolean sensitive)102 static void gtv_set_buttons_sensitive( gpointer raw, gboolean sensitive )
103 {
104     SMPEG_Info* info = NULL;
105 
106     /* HACK If no MPEG is loaded, info has been memset()'ed to 0. */
107     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
108 
109     gtv_set_sensitive( raw, "play", sensitive );
110     gtv_set_sensitive( raw, "pause", sensitive );
111     gtv_set_sensitive( raw, "stop", sensitive );
112     gtv_set_sensitive( raw, "step", sensitive && info->has_video );
113     gtv_set_sensitive( raw, "to_end", sensitive && info->has_video );
114     gtv_set_sensitive( raw, "loop", sensitive );
115     gtv_set_sensitive( raw, "close", sensitive );
116     gtv_set_sensitive( raw, "file_info", sensitive );
117 
118     gtv_set_sensitive( raw, "twotimes", sensitive && info->has_video );
119     gtv_set_sensitive( raw, "audio", sensitive && info->has_audio && info->has_video);
120     gtv_set_sensitive( raw, "filter", sensitive && info->has_video );
121 
122     gtv_fix_toggle_state( raw );
123 }
124 
gtv_dialog_cleanup(gpointer raw)125 static void gtv_dialog_cleanup( gpointer raw )
126 {
127     GtkWidget* dialog = NULL;
128 
129     dialog = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "dialog" ) );
130     gtk_grab_remove( dialog );
131     gtk_widget_destroy( dialog );
132     gtk_object_set_data( GTK_OBJECT( raw ), "dialog", NULL );
133 }
134 
gtv_dialog_cancel(GtkWidget * item,gpointer raw)135 static void gtv_dialog_cancel( GtkWidget* item, gpointer raw )
136 {
137     gtv_dialog_cleanup( raw );
138 }
139 
gtv_open_ok(GtkWidget * item,gpointer raw)140 static void gtv_open_ok( GtkWidget* item, gpointer raw )
141 {
142     GtkWidget* file_sel = NULL;
143     gchar* filename = NULL;
144 
145     /* HACK HACK HACK */
146     file_sel = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "dialog" ) );
147     filename = gtk_file_selection_get_filename( GTK_FILE_SELECTION( file_sel ) );
148 
149     if( filename ) {
150 	gtv_open_file( filename, raw );
151 	if( strrchr( filename, '/') )
152 	{
153 	  if( gtv_default_directory ) free( gtv_default_directory );
154 	  gtv_default_directory = (gchar *) malloc( (strlen(filename) + 1) * sizeof(gchar) );
155 	  strcpy( gtv_default_directory, filename);
156 	  *(strrchr( gtv_default_directory, '/' ) + 1) = 0;
157 	}
158     }
159 
160     gtv_dialog_cleanup( raw );
161 }
162 
gtv_open(GtkWidget * item,gpointer raw)163 static void gtv_open( GtkWidget* item, gpointer raw )
164 {
165     GtkWidget* file_sel = NULL;
166 
167     file_sel = gtk_file_selection_new( "Select an MPEG" );
168     gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->ok_button ), "clicked",
169 			GTK_SIGNAL_FUNC( gtv_open_ok ), raw );
170     gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION( file_sel )->cancel_button ), "clicked",
171 			GTK_SIGNAL_FUNC( gtv_dialog_cancel ), raw );
172     if( gtv_default_directory )
173       gtk_file_selection_complete( GTK_FILE_SELECTION( file_sel ), gtv_default_directory );
174     gtk_file_selection_hide_fileop_buttons( GTK_FILE_SELECTION( file_sel ) );
175 
176     /* HACK HACK HACK */
177     gtk_object_set_data( GTK_OBJECT( raw ), "dialog", file_sel );
178 
179     gtk_grab_add( file_sel );
180     gtk_widget_show( file_sel );
181 }
182 
gtv_center_window(SDL_Surface * screen)183 static void gtv_center_window(SDL_Surface *screen)
184 {
185     SDL_SysWMinfo info;
186 
187     SDL_VERSION(&info.version);
188     if ( SDL_GetWMInfo(&info) > 0 ) {
189         int x, y;
190         int w, h;
191 #ifdef unix
192         if ( info.subsystem == SDL_SYSWM_X11 ) {
193             info.info.x11.lock_func();
194             w = DisplayWidth(info.info.x11.display,
195                              DefaultScreen(info.info.x11.display));
196             h = DisplayHeight(info.info.x11.display,
197                              DefaultScreen(info.info.x11.display));
198             x = (w - screen->w)/2;
199             y = (h - screen->h)/2;
200             XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, x, y);
201             info.info.x11.unlock_func();
202         }
203 #else
204 #ifdef WIN32
205 	/* FIXME: implement centering code for Windows */
206 #else
207 #warning Need to implement these functions for other systems
208 #endif // WIN32
209 #endif // unix
210     }
211 }
212 
gtv_open_file(gchar * name,gpointer raw)213 static void gtv_open_file( gchar* name, gpointer raw )
214 {
215     SMPEG_Info* info = NULL;
216     SMPEG* mpeg = NULL;
217     gchar buffer[FILENAME_BUFFER_SIZE];
218 
219     assert( name );
220     assert( raw );
221 
222     gtv_close( NULL, raw );
223 
224     if( SDL_Init( SDL_INIT_AUDIO | SDL_INIT_VIDEO ) < 0 ) {
225 	fprintf( stderr, "gtv: couldn't initialize SDL: %s\n", SDL_GetError( ) );
226 	exit( 1 );
227     }
228 
229     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
230     assert( info );
231 
232     mpeg = SMPEG_new( name, info, 1 );
233 
234     if( SMPEG_error( mpeg ) ) {
235 	fprintf( stderr, "gtv: %s\n", SMPEG_error( mpeg ) );
236 	SMPEG_delete( mpeg );
237 	gtk_object_set_data( GTK_OBJECT( raw ), "mpeg", NULL );
238 	return;
239     }
240 
241     gtk_object_set_data( GTK_OBJECT( raw ), "mpeg", mpeg );
242     strncpy( (char*) gtk_object_get_data( GTK_OBJECT( raw ), "filename_buffer" ),
243 	     name,
244 	     FILENAME_BUFFER_SIZE );
245     gtv_set_frame( raw, 0 );
246     gtv_set_fps( raw, 0.0 );
247     g_snprintf( buffer, FILENAME_BUFFER_SIZE, "gtv - %s", name );
248     gtk_window_set_title( GTK_WINDOW( raw ), buffer );
249 
250     if( info->has_video ) {
251 	SDL_Surface* sdl_screen = NULL;
252         const SDL_VideoInfo *video_info;
253         int video_bpp;
254 
255         /* Get the "native" video mode */
256         video_info = SDL_GetVideoInfo();
257         switch (video_info->vfmt->BitsPerPixel) {
258             case 16:
259             case 32:
260                 video_bpp = video_info->vfmt->BitsPerPixel;
261                 break;
262             default:
263                 video_bpp = 16;
264                 break;
265         }
266 #ifdef linux
267 	putenv("SDL_VIDEO_CENTERED=1");
268 #endif
269 	sdl_screen = SDL_SetVideoMode( info->width , info->height , video_bpp, SDL_ASYNCBLIT);
270         SDL_WM_SetCaption(name, "gtv movie");
271         gtv_center_window(sdl_screen);
272 	SMPEG_setdisplay( mpeg, sdl_screen, NULL, NULL );
273 	gtk_object_set_data( GTK_OBJECT( raw ), "sdl_screen", sdl_screen );
274 	gtv_double( NULL, raw );
275     }
276 
277     gtv_loop( NULL, raw );
278     gtv_audio( NULL, raw );
279     gtv_filter( NULL, raw );
280     gtv_set_buttons_sensitive( raw, TRUE );
281 }
282 
gtv_close(GtkWidget * item,gpointer raw)283 static void gtv_close( GtkWidget* item, gpointer raw )
284 {
285     SMPEG* mpeg = NULL;
286     SMPEG_Info* info = NULL;
287 
288     assert( raw != NULL );
289 
290     gtv_stop( NULL, raw );
291     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
292 
293     if( mpeg ) {
294 	SDL_Surface* sdl_screen = NULL;
295 
296 	SMPEG_delete( mpeg );
297 	gtk_object_set_data( GTK_OBJECT( raw ), "mpeg", NULL );
298 	info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
299 	memset( info, 0, sizeof( SMPEG_Info ) );
300 
301 	sdl_screen = (SDL_Surface*) gtk_object_get_data( GTK_OBJECT( raw ), "sdl_screen" );
302 	SDL_FreeSurface( sdl_screen );
303 	gtk_object_set_data( GTK_OBJECT( raw ), "sdl_screen", NULL );
304 
305 	SDL_Quit( );
306     }
307 
308     /* Reset title. */
309     gtk_window_set_title( GTK_WINDOW( raw ), "gtv" );
310     gtv_set_frame( raw, 0 );
311     gtv_set_fps( raw, 0.0 );
312     gtv_set_buttons_sensitive( raw, FALSE );
313 }
314 
create_file_info_dialog(void)315 static GtkWidget* create_file_info_dialog( void )
316 {
317   GtkWidget *file_info_dialog;
318   GtkWidget *dialog_vbox1;
319   GtkWidget *vbox2;
320   GtkWidget *label5;
321   GtkWidget *scrolledwindow1;
322   GtkWidget *viewport1;
323   GtkWidget *text;
324   GtkWidget *dialog_action_area1;
325   GtkWidget *ok;
326 
327   file_info_dialog = gtk_dialog_new ();
328   gtk_object_set_data (GTK_OBJECT (file_info_dialog), "file_info_dialog", file_info_dialog);
329   gtk_window_set_title (GTK_WINDOW (file_info_dialog), "File Info");
330   gtk_window_set_default_size (GTK_WINDOW (file_info_dialog), 256, 192);
331 
332   dialog_vbox1 = GTK_DIALOG (file_info_dialog)->vbox;
333   gtk_object_set_data (GTK_OBJECT (file_info_dialog), "dialog_vbox1", dialog_vbox1);
334   gtk_widget_show (dialog_vbox1);
335 
336   vbox2 = gtk_vbox_new (FALSE, 5);
337   gtk_widget_ref (vbox2);
338   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "vbox2", vbox2,
339                             (GtkDestroyNotify) gtk_widget_unref);
340   gtk_widget_show (vbox2);
341   gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox2, TRUE, TRUE, 0);
342   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5);
343 
344   label5 = gtk_label_new ("File info:");
345   gtk_widget_ref (label5);
346   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "label5", label5,
347                             (GtkDestroyNotify) gtk_widget_unref);
348   gtk_widget_show (label5);
349   gtk_box_pack_start (GTK_BOX (vbox2), label5, FALSE, FALSE, 0);
350   gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5);
351 
352   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
353   gtk_widget_ref (scrolledwindow1);
354   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "scrolledwindow1", scrolledwindow1,
355                             (GtkDestroyNotify) gtk_widget_unref);
356   gtk_widget_show (scrolledwindow1);
357   gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow1, TRUE, TRUE, 0);
358   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
359 
360   viewport1 = gtk_viewport_new (NULL, NULL);
361   gtk_widget_ref (viewport1);
362   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "viewport1", viewport1,
363                             (GtkDestroyNotify) gtk_widget_unref);
364   gtk_widget_show (viewport1);
365   gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);
366 
367   text = gtk_text_new (NULL, NULL);
368   gtk_widget_ref (text);
369   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "text", text,
370                             (GtkDestroyNotify) gtk_widget_unref);
371   gtk_widget_show (text);
372   gtk_container_add (GTK_CONTAINER (viewport1), text);
373 
374   dialog_action_area1 = GTK_DIALOG (file_info_dialog)->action_area;
375   gtk_object_set_data (GTK_OBJECT (file_info_dialog), "dialog_action_area1", dialog_action_area1);
376   gtk_widget_show (dialog_action_area1);
377   gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 10);
378 
379   ok = gtk_button_new_with_label ("  OK  ");
380   gtk_widget_ref (ok);
381   gtk_object_set_data_full (GTK_OBJECT (file_info_dialog), "ok", ok,
382                             (GtkDestroyNotify) gtk_widget_unref);
383   gtk_widget_show (ok);
384   gtk_box_pack_start (GTK_BOX (dialog_action_area1), ok, FALSE, FALSE, 0);
385 
386   return file_info_dialog;
387 }
388 
gtv_info(GtkWidget * item,gpointer raw)389 static void gtv_info( GtkWidget* item, gpointer raw )
390 {
391     GtkWidget* dialog = NULL;
392     GtkWidget* ok = NULL;
393     gchar buffer[1024];
394     gint ignored = 0;
395     GtkWidget* text = NULL;
396     SMPEG_Info* info = NULL;
397     int hh,mm,ss;
398 
399     dialog = create_file_info_dialog( );
400     ok = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "ok" ) );
401     gtk_signal_connect( GTK_OBJECT( ok ), "clicked",
402 			GTK_SIGNAL_FUNC( gtv_dialog_cancel ), raw );
403     /* HACK HACK HACK */
404     gtk_object_set_data( GTK_OBJECT( raw ), "dialog", dialog );
405 
406     /* Actually stuff some data in there. */
407     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
408     hh = info->total_time / 3600;
409     mm = (info->total_time - hh * 3600)/60;
410     ss = ((int)info->total_time % 60);
411     g_snprintf( buffer, 1024, "Filename: %s\nStream: %s\nVideo: %dx%d resolution\nAudio: %s\nSize: %d\nTime %d:%02d:%02d\n",
412 		(gchar*) gtk_object_get_data( GTK_OBJECT( raw ), "filename_buffer" ),
413 		( info->has_audio && info->has_video ) ? "system" :
414 		( info->has_video ? "video" :
415 		( info->has_audio ? "audio" : "not MPEG" ) ),
416 		info->width, info->height,
417 		( info->has_audio ? info->audio_string : "none" ),
418 		info->total_size , hh,mm,ss);
419     text = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "text" ) );
420     gtk_editable_insert_text( GTK_EDITABLE( text ), buffer, strlen( buffer ), &ignored );
421 
422     gtk_grab_add( dialog );
423     gtk_widget_show( dialog );
424 }
425 
create_about_dialog(void)426 static GtkWidget* create_about_dialog( void )
427 {
428   GtkWidget *about_dialog;
429   GtkWidget *dialog_vbox2;
430   GtkWidget *scrolledwindow2;
431   GtkWidget *viewport2;
432   GtkWidget *text;
433   GtkWidget *dialog_action_area2;
434   GtkWidget *ok;
435 
436   about_dialog = gtk_dialog_new ();
437   gtk_object_set_data (GTK_OBJECT (about_dialog), "about_dialog", about_dialog);
438   gtk_window_set_title (GTK_WINDOW (about_dialog), "About gtv");
439   gtk_window_set_default_size (GTK_WINDOW (about_dialog), 384, 256);
440   gtk_window_set_policy (GTK_WINDOW (about_dialog), TRUE, TRUE, FALSE);
441 
442   dialog_vbox2 = GTK_DIALOG (about_dialog)->vbox;
443   gtk_object_set_data (GTK_OBJECT (about_dialog), "dialog_vbox2", dialog_vbox2);
444   gtk_widget_show (dialog_vbox2);
445 
446   scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
447   gtk_widget_ref (scrolledwindow2);
448   gtk_object_set_data_full (GTK_OBJECT (about_dialog), "scrolledwindow2", scrolledwindow2,
449                             (GtkDestroyNotify) gtk_widget_unref);
450   gtk_widget_show (scrolledwindow2);
451   gtk_box_pack_start (GTK_BOX (dialog_vbox2), scrolledwindow2, TRUE, TRUE, 0);
452   gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow2), 5);
453   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
454 
455   viewport2 = gtk_viewport_new (NULL, NULL);
456   gtk_widget_ref (viewport2);
457   gtk_object_set_data_full (GTK_OBJECT (about_dialog), "viewport2", viewport2,
458                             (GtkDestroyNotify) gtk_widget_unref);
459   gtk_widget_show (viewport2);
460   gtk_container_add (GTK_CONTAINER (scrolledwindow2), viewport2);
461 
462   text = gtk_text_new (NULL, NULL);
463   gtk_widget_ref (text);
464   gtk_object_set_data_full (GTK_OBJECT (about_dialog), "text", text,
465                             (GtkDestroyNotify) gtk_widget_unref);
466   gtk_widget_show (text);
467   gtk_container_add (GTK_CONTAINER (viewport2), text);
468 
469   dialog_action_area2 = GTK_DIALOG (about_dialog)->action_area;
470   gtk_object_set_data (GTK_OBJECT (about_dialog), "dialog_action_area2", dialog_action_area2);
471   gtk_widget_show (dialog_action_area2);
472   gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area2), 10);
473 
474   ok = gtk_button_new_with_label ("  OK  ");
475   gtk_widget_ref (ok);
476   gtk_object_set_data_full (GTK_OBJECT (about_dialog), "ok", ok,
477                             (GtkDestroyNotify) gtk_widget_unref);
478   gtk_widget_show (ok);
479   gtk_box_pack_start (GTK_BOX (dialog_action_area2), ok, FALSE, FALSE, 0);
480 
481   return about_dialog;
482 }
483 
gtv_about(GtkWidget * item,gpointer raw)484 static void gtv_about( GtkWidget* item, gpointer raw )
485 {
486     static const char* msg = "gtv - Gtk+ MPEG Player\n" \
487                              "(c) Michael Vance, 1999\n" \
488 	                     "    briareos@lokigames.com\n" \
489                              "\n" \
490                              "Built using:\n" \
491 	                     "SMPEG - http://www.lokigames.com/development\n" \
492 	                     "Gtk+ - http://www.gtk.org\n" \
493 	                     "Glade - http://glade.pn.org\n" \
494                              "\n" \
495                              "Distributed under the GPL.\n";
496     GtkWidget* dialog = NULL;
497     GtkWidget* ok = NULL;
498     GtkWidget* text = NULL;
499     gint ignored = 0;
500 
501     dialog = create_about_dialog( );
502     ok = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "ok" ) );
503     gtk_signal_connect( GTK_OBJECT( ok ), "clicked",
504 			GTK_SIGNAL_FUNC( gtv_dialog_cancel ), raw );
505     text = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( dialog ), "text" ) );
506     gtk_editable_insert_text( GTK_EDITABLE( text ), msg, strlen( msg ), &ignored );
507 
508     /* HACK HACK HACK */
509     gtk_object_set_data( GTK_OBJECT( raw ), "dialog", dialog );
510 
511     gtk_grab_add( dialog );
512     gtk_widget_show( dialog );
513 }
514 
gtv_rewind(gpointer raw)515 static void gtv_rewind( gpointer raw )
516 {
517     SMPEG* mpeg = NULL;
518 
519     assert( raw );
520 
521     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
522 
523     if( mpeg ) {
524 	SMPEG_Info* info = NULL;
525 
526 	SMPEG_rewind( mpeg );
527 	gtv_clear_screen( raw );
528 	info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
529 	SMPEG_getinfo( mpeg, info );
530 	gtv_set_frame( raw, info->current_frame );
531     }
532 
533 }
534 
gtv_double(GtkWidget * item,gpointer raw)535 static void gtv_double( GtkWidget* item, gpointer raw )
536 {
537     SMPEG* mpeg = NULL;
538     SDL_Surface* sdl_screen = NULL;
539     SMPEG_Info* info = NULL;
540     int stopped=0;
541     int width,height;
542 
543     assert( raw );
544 
545     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
546     sdl_screen = (SDL_Surface*) gtk_object_get_data( GTK_OBJECT( raw ), "sdl_screen" );
547 
548     if( mpeg && sdl_screen ) {
549 	GtkWidget* twotimes = NULL;
550 	gboolean active = FALSE;
551 
552 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
553 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( twotimes ) );
554 
555 	info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
556 	assert( info );
557         if (SMPEG_status(mpeg)==SMPEG_PLAYING) {
558 		SMPEG_pause(mpeg);
559 		stopped=1;
560 	}
561 	if( active ) {
562 	    width = info->width * 2;
563 	    height = info->height * 2;
564 	} else {
565 	    width = info->width;
566 	    height = info->height;
567 	}
568 	sdl_screen = SDL_SetVideoMode(width, height,
569 		sdl_screen->format->BitsPerPixel,sdl_screen->flags);
570         gtv_center_window(sdl_screen);
571 	SMPEG_setdisplay( mpeg, sdl_screen, NULL, NULL );
572 
573 	gtk_object_set_data( GTK_OBJECT( raw ), "sdl_screen", sdl_screen );
574 	SMPEG_scaleXY( mpeg, sdl_screen->w, sdl_screen->h );
575         gtv_center_window(sdl_screen);
576         if (stopped) SMPEG_pause(mpeg);
577     }
578 
579 }
580 
gtv_loop(GtkWidget * item,gpointer raw)581 static void gtv_loop( GtkWidget* item, gpointer raw )
582 {
583     SMPEG* mpeg = NULL;
584 
585     assert( raw );
586 
587     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
588 
589     if( mpeg ) {
590 	GtkWidget* loop = NULL;
591 	gboolean active = FALSE;
592 
593 	loop = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "loop" ) );
594 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( loop ) );
595 	SMPEG_loop( mpeg, active );
596     }
597 
598 }
599 
gtv_audio(GtkWidget * item,gpointer raw)600 static void gtv_audio( GtkWidget* item, gpointer raw )
601 {
602     SMPEG* mpeg = NULL;
603 
604     assert( raw );
605 
606     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
607 
608     if( mpeg ) {
609 	GtkWidget* audio = NULL;
610 	gboolean active = FALSE;
611 	SMPEG_Info* info = NULL;
612 
613 	audio = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "audio" ) );
614 	info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
615 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( audio ) );
616 	SMPEG_enableaudio( mpeg, active && info->has_audio );
617     }
618 
619 }
620 
gtv_filter(GtkWidget * item,gpointer raw)621 static void gtv_filter( GtkWidget* item, gpointer raw )
622 {
623     SMPEG* mpeg = NULL;
624     SMPEG_Info* info = NULL;
625 
626     assert( raw );
627 
628     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
629     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
630 
631     if( mpeg && info->has_video ) {
632 	GtkWidget* filter = NULL;
633 	gboolean active = FALSE;
634 
635 	filter = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "filter" ) );
636 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( filter ) );
637 
638 	if(active)
639 	{
640 	  SMPEG_Filter * filter;
641 
642 	  /* Activate the bilinear filter */
643        	  filter = SMPEGfilter_bilinear();
644 	  filter = SMPEG_filter( mpeg, filter );
645 	  filter->destroy(filter);
646 	}
647 	else
648 	{
649 	  SMPEG_Filter * filter;
650 
651 	  /* Reset to default (null) filter */
652 	  filter = SMPEGfilter_null();
653 	  filter = SMPEG_filter( mpeg, filter );
654 	  filter->destroy(filter);
655 	}
656     }
657 
658 }
659 
gtv_play(GtkWidget * item,gpointer raw)660 static void gtv_play( GtkWidget* item, gpointer raw )
661 {
662     SMPEG* mpeg = NULL;
663 
664     assert( raw );
665 
666     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
667 
668     if( mpeg ) {
669       //	gtv_rewind( raw );
670 	SMPEG_play( mpeg );
671     }
672 
673 }
674 
gtv_pause(GtkWidget * item,gpointer raw)675 static void gtv_pause( GtkWidget* item, gpointer raw )
676 {
677     SMPEG* mpeg = NULL;
678 
679     assert( raw );
680 
681     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
682 
683     if( mpeg ) {
684 	SMPEG_pause( mpeg );
685     }
686 
687 }
688 
gtv_stop(GtkWidget * item,gpointer raw)689 static void gtv_stop( GtkWidget* item, gpointer raw )
690 {
691     SMPEG* mpeg = NULL;
692     SMPEG_Info* info = NULL;
693 
694     assert( raw );
695 
696     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
697     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
698 
699     if( mpeg ) {
700 	SMPEG_stop( mpeg );
701 	gtv_rewind( raw );
702 	SMPEG_getinfo( mpeg, info );
703 	gtv_set_trackbar( raw, info->current_offset );
704     }
705 
706 }
707 
gtv_step(GtkWidget * item,gpointer raw)708 static void gtv_step( GtkWidget* item, gpointer raw )
709 {
710     SMPEG* mpeg = NULL;
711     SMPEG_Info* info = NULL;
712 
713     assert( raw );
714 
715     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
716     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
717 
718     if( mpeg && info && info->has_video && ( SMPEG_status( mpeg ) != SMPEG_PLAYING ) ) {
719 	int next_frame = 0;
720 	GtkWidget* twotimes = NULL;
721 	gboolean active = FALSE;
722 	SDL_Surface* sdl_screen = NULL;
723 
724 	SMPEG_getinfo( mpeg, info );
725 	next_frame = info->current_frame + 1;
726 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
727 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( twotimes ) );
728 	sdl_screen = (SDL_Surface*) gtk_object_get_data( GTK_OBJECT( raw ), "sdl_screen" );
729 
730 	SMPEG_renderFrame( mpeg, next_frame );
731 
732 	SMPEG_getinfo( mpeg, info );
733 
734 	if( info->current_frame != next_frame ) {
735             GtkWidget *looping;
736 
737             /* Sam 5/31/2000 - Only loop if the looping toggle is set */
738             looping = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(raw), "loop"));
739             if ( ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(looping)) ) {
740                 return;
741             }
742 	    gtv_rewind( raw );
743 	    gtv_step( NULL, raw );
744 	}
745 
746 	gtv_set_frame( raw, info->current_frame );
747     }
748 
749 }
750 
gtv_to_end(GtkWidget * item,gpointer raw)751 static void gtv_to_end( GtkWidget* item, gpointer raw )
752 {
753     SMPEG* mpeg = NULL;
754     SMPEG_Info* info = NULL;
755 
756     assert( raw );
757 
758     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
759     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
760 
761     if( mpeg && info->has_video ) {
762 	GtkWidget* twotimes = NULL;
763 	gboolean active = FALSE;
764 	SDL_Surface* sdl_screen = NULL;
765 
766 	SMPEG_stop( mpeg );
767 
768 	twotimes = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "twotimes" ) );
769 	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( twotimes ) );
770 	sdl_screen = (SDL_Surface*) gtk_object_get_data( GTK_OBJECT( raw ), "sdl_screen" );
771 
772 	if( active ) {
773 	    SMPEG_renderFinal( mpeg, sdl_screen, 0, 0 );
774 	} else {
775 	    SMPEG_renderFinal( mpeg, sdl_screen,
776 			       ( sdl_screen->w - info->width ) / 2,
777 			       ( sdl_screen->h - info->height ) / 2 );
778 	}
779 
780 	SMPEG_getinfo( mpeg, info );
781 	gtv_set_frame( raw, info->current_frame );
782     }
783 
784 }
785 
gtv_seek(GtkAdjustment * adjust,gpointer raw)786 static void gtv_seek( GtkAdjustment* adjust, gpointer raw )
787 {
788     SMPEG* mpeg = NULL;
789     SMPEG_Info* info = NULL;
790 
791     assert( raw );
792     if(gtv_trackbar_dragging) return;
793 
794     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
795     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
796 
797     if( mpeg && info && info->total_size ) {
798 
799       /* In case file is growing while we're playing */
800       SMPEG_getinfo( mpeg, info );
801 
802       SMPEG_seek(mpeg, (int)((info->total_size*adjust->value)/100));
803       SMPEG_getinfo( mpeg, info );
804       gtv_set_frame( raw, info->current_frame );
805     }
806 }
807 
gtv_trackbar_drag_on(GtkWidget * widget,gpointer raw)808 static void gtv_trackbar_drag_on(GtkWidget *widget, gpointer raw)
809 {
810     gtv_trackbar_dragging = 1;
811 }
812 
gtv_trackbar_drag_off(GtkWidget * widget,gpointer raw)813 static void gtv_trackbar_drag_off(GtkWidget *widget, gpointer raw)
814 {
815     gtv_trackbar_dragging = 0;
816 }
817 
gtv_set_frame(gpointer raw,int value)818 static void gtv_set_frame( gpointer raw, int value )
819 {
820     GtkWidget* frame = NULL;
821     gchar buffer[32];
822 
823     assert( raw );
824     assert( value >= 0 );
825 
826     frame = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "frame" ) );
827     g_snprintf( buffer, 32, "%d", value );
828     gtk_label_set_text( GTK_LABEL( frame ), buffer );
829 }
830 
gtv_set_fps(gpointer raw,float value)831 static void gtv_set_fps( gpointer raw, float value )
832 {
833     GtkWidget* fps = NULL;
834     gchar buffer[32];
835 
836     assert( raw );
837     assert( value >= 0.0 );
838 
839     fps = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "fps" ) );
840     g_snprintf( buffer, 32, "%2.2f", value );
841     gtk_label_set_text( GTK_LABEL( fps ), buffer );
842 }
843 
gtv_set_trackbar(gpointer raw,int value)844 static void gtv_set_trackbar( gpointer raw, int value )
845 {
846     SMPEG* mpeg = NULL;
847     SMPEG_Info* info = NULL;
848     GtkWidget* scale = NULL;
849     GtkAdjustment* seek = NULL;
850 
851     assert( raw );
852     assert( value >= 0 );
853     if(gtv_trackbar_dragging) return;
854 
855     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
856     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
857 
858     if( mpeg && info && info->total_size ) {
859             scale = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( raw ), "scale" ) );
860       seek  = gtk_range_get_adjustment ( GTK_RANGE( scale ) );
861       seek->value = 100. * value / info->total_size;
862       gtk_range_set_adjustment ( GTK_RANGE( scale ), seek );
863       gtk_range_slider_update ( GTK_RANGE( scale ) );
864       gtk_range_clear_background ( GTK_RANGE( scale ) );
865       gtk_range_draw_background ( GTK_RANGE( scale ) );
866     }
867 }
868 
869 /* Drag-N-Drop support, contributed by */
gtv_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time)870 static void gtv_drag_data_received(GtkWidget * widget,
871                                    GdkDragContext * context,
872                                    gint x,
873                                    gint y,
874                                    GtkSelectionData * selection_data,
875                                    guint info,
876                                    guint time)
877 {
878     gchar *temp, *string;
879 
880     string = (gchar *)selection_data->data;
881 
882     /* remove newline at end of line, and the file:// url header
883        at the begining, copied this code from the xmms source */
884     temp = strchr(string, '\n');
885     if (temp)
886     {
887         if (*(temp - 1) == '\r')
888             *(temp - 1) = '\0';
889         *temp = '\0';
890     }
891     if (!strncmp(string, "file:", 5))
892         string = string + 5;
893 
894     gtv_open_file(string, widget);
895     gtv_play(NULL, widget);
896 }
897 
gtv_timer(gpointer raw)898 static gint gtv_timer( gpointer raw )
899 {
900     SMPEG* mpeg = NULL;
901     SMPEG_Info* info = NULL;
902 
903     mpeg = (SMPEG*) gtk_object_get_data( GTK_OBJECT( raw ), "mpeg" );
904     info = (SMPEG_Info*) gtk_object_get_data( GTK_OBJECT( raw ), "info" );
905 
906     if( mpeg && info ) {
907 
908 	if( SMPEG_status( mpeg ) == SMPEG_PLAYING ) {
909 	    SMPEG_getinfo( mpeg, info );
910 	    gtv_set_frame( raw, info->current_frame );
911 	    gtv_set_fps( raw, info->current_fps );
912 	    gtv_set_trackbar( raw, info->current_offset );
913 	}
914 
915     }
916 
917     return 1;
918 }
919 
gtv_clear_screen(gpointer raw)920 static void gtv_clear_screen( gpointer raw )
921 {
922     SDL_Surface* sdl_screen = NULL;
923 
924     sdl_screen = (SDL_Surface*) gtk_object_get_data( GTK_OBJECT( raw ), "sdl_screen" );
925 
926     if( sdl_screen ) {
927 	SDL_FillRect( sdl_screen, NULL, SDL_MapRGB( sdl_screen->format, 0, 0, 0 ) );
928 	SDL_UpdateRect( sdl_screen, 0, 0, 0, 0 );
929     }
930 
931 }
932 
gtv_quit(GtkWidget * item,gpointer raw)933 static void gtv_quit( GtkWidget* item, gpointer raw )
934 {
935     gtv_close( NULL, raw );
936     gtk_exit( 0 );
937 }
938 
gtv_connect(gpointer raw,gchar * name,gchar * signal,GtkSignalFunc func)939 static void gtv_connect( gpointer raw, gchar* name, gchar* signal, GtkSignalFunc func )
940 {
941     GtkObject* item = NULL;
942 
943     assert( raw );
944 
945     item = GTK_OBJECT( gtk_object_get_data( GTK_OBJECT( raw ), name ) );
946     assert( item );
947     gtk_signal_connect(item, signal, func, raw );
948 }
949 
main(int argc,char * argv[])950 int main( int argc, char* argv[] )
951 {
952     static GtkTargetEntry drop_types[] =
953     {
954         { "text/plain", 0, 1 }
955     };
956     /* These are always on the stack until program exit. */
957     SMPEG_Info info;
958     gchar filename_buffer[FILENAME_BUFFER_SIZE];
959 
960     GtkWidget* window = NULL;
961 
962     memset( &info, 0, sizeof( info ) );
963     memset( &filename_buffer, 0, sizeof( gchar ) * FILENAME_BUFFER_SIZE );
964     gtk_set_locale();
965     gtk_init( &argc, &argv );
966     gtk_set_locale ();
967 
968     window = create_gtv_window( );
969     gtk_drag_dest_set(window, GTK_DEST_DEFAULT_ALL, drop_types, 1, GDK_ACTION_COPY);
970     gtk_signal_connect( GTK_OBJECT( window ), "drag_data_received",
971 			GTK_SIGNAL_FUNC( gtv_drag_data_received ), window );
972     gtk_signal_connect( GTK_OBJECT( window ), "destroy",
973 			GTK_SIGNAL_FUNC( gtv_quit ), window );
974     gtk_object_set_data( GTK_OBJECT( window ), "info", &info );
975     gtk_object_set_data( GTK_OBJECT( window ), "mpeg", NULL );
976     gtk_object_set_data( GTK_OBJECT( window ), "sdl_screen", NULL );
977     gtk_object_set_data( GTK_OBJECT( window ), "filename_buffer", filename_buffer );
978     gtk_widget_show( window );
979 
980     gtv_connect( window, "open", "activate", GTK_SIGNAL_FUNC( gtv_open ) );
981     gtv_connect( window, "close", "activate", GTK_SIGNAL_FUNC( gtv_close ) );
982     gtv_connect( window, "file_info", "activate", GTK_SIGNAL_FUNC( gtv_info ) );
983     gtv_connect( window, "quit", "activate", GTK_SIGNAL_FUNC( gtv_quit ) );
984     gtv_connect( window, "about", "activate", GTK_SIGNAL_FUNC( gtv_about ) );
985 
986     gtv_connect( window, "play", "clicked", GTK_SIGNAL_FUNC( gtv_play ) );
987     gtv_connect( window, "pause", "clicked", GTK_SIGNAL_FUNC( gtv_pause ) );
988     gtv_connect( window, "stop", "clicked", GTK_SIGNAL_FUNC( gtv_stop ) );
989     gtv_connect( window, "step", "clicked", GTK_SIGNAL_FUNC( gtv_step ) );
990     gtv_connect( window, "to_end", "clicked", GTK_SIGNAL_FUNC( gtv_to_end ) );
991 
992     gtv_connect( window, "twotimes", "toggled", GTK_SIGNAL_FUNC( gtv_double ) );
993     gtv_connect( window, "loop", "toggled", GTK_SIGNAL_FUNC( gtv_loop ) );
994     gtv_connect( window, "audio", "toggled", GTK_SIGNAL_FUNC( gtv_audio ) );
995     gtv_connect( window, "filter", "toggled", GTK_SIGNAL_FUNC( gtv_filter ) );
996 
997     gtv_connect( window, "seek", "value_changed", GTK_SIGNAL_FUNC( gtv_seek ) );
998 
999     gtv_connect( window, "scale", "button_press_event", GTK_SIGNAL_FUNC( gtv_trackbar_drag_on ) );
1000     gtv_connect( window, "scale", "button_release_event", GTK_SIGNAL_FUNC( gtv_trackbar_drag_off ) );
1001 
1002     /*    gtk_idle_add_priority( G_PRIORITY_LOW, gtv_timer, window );*/
1003     gtk_timeout_add( TIMER_TIMEOUT, gtv_timer, window );
1004 
1005     gtv_set_frame( window, 0 );
1006     gtv_set_fps( window, 0.0 );
1007     gtv_set_buttons_sensitive( window, FALSE );
1008 
1009     if( argc > 1 ) {
1010 	gtv_open_file( argv[1], window );
1011     }
1012 
1013     gtk_main( );
1014 
1015     return 0;
1016 }
1017 
create_gtv_window(void)1018 static GtkWidget* create_gtv_window( void )
1019 {
1020   GtkWidget *gtv_window;
1021   GtkWidget *vbox1;
1022   GtkWidget *menubar1;
1023   GtkWidget *file;
1024   GtkWidget *file_menu;
1025   GtkAccelGroup *file_menu_accels;
1026   GtkWidget *open;
1027   GtkWidget *close;
1028   GtkWidget *separator1;
1029   GtkWidget *file_info;
1030   GtkWidget *separator2;
1031   GtkWidget *quit;
1032   GtkWidget *help;
1033   GtkWidget *help_menu;
1034   GtkAccelGroup *help_menu_accels;
1035   GtkWidget *about;
1036   GtkWidget *table1;
1037   GtkObject *seek;
1038   GtkWidget *scale;
1039   GtkWidget *play;
1040   GtkWidget *pause;
1041   GtkWidget *stop;
1042   GtkWidget *step;
1043   GtkWidget *to_end;
1044   GtkWidget *twotimes;
1045   GtkWidget *loop;
1046   GtkWidget *audio;
1047   GtkWidget *filter;
1048   GtkWidget *label3;
1049   GtkWidget *fps;
1050   GtkWidget *label2;
1051   GtkWidget *frame;
1052   GtkAccelGroup *accel_group;
1053 
1054   accel_group = gtk_accel_group_new ();
1055 
1056   gtv_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1057   gtk_object_set_data (GTK_OBJECT (gtv_window), "gtv_window", gtv_window);
1058   gtk_window_set_title (GTK_WINDOW (gtv_window), "gtv");
1059   gtk_widget_set_uposition (GTK_WIDGET (gtv_window), 0, 0);
1060 
1061   vbox1 = gtk_vbox_new (FALSE, 0);
1062   gtk_widget_ref (vbox1);
1063   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "vbox1", vbox1,
1064                             (GtkDestroyNotify) gtk_widget_unref);
1065   gtk_widget_show (vbox1);
1066   gtk_container_add (GTK_CONTAINER (gtv_window), vbox1);
1067 
1068   menubar1 = gtk_menu_bar_new ();
1069   gtk_widget_ref (menubar1);
1070   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "menubar1", menubar1,
1071                             (GtkDestroyNotify) gtk_widget_unref);
1072   gtk_widget_show (menubar1);
1073   gtk_box_pack_start (GTK_BOX (vbox1), menubar1, FALSE, FALSE, 0);
1074 
1075   file = gtk_menu_item_new_with_label ("File");
1076   gtk_widget_ref (file);
1077   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "file", file,
1078                             (GtkDestroyNotify) gtk_widget_unref);
1079   gtk_widget_show (file);
1080   gtk_container_add (GTK_CONTAINER (menubar1), file);
1081 
1082   file_menu = gtk_menu_new ();
1083   gtk_widget_ref (file_menu);
1084   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "file_menu", file_menu,
1085                             (GtkDestroyNotify) gtk_widget_unref);
1086   gtk_menu_item_set_submenu (GTK_MENU_ITEM (file), file_menu);
1087   file_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (file_menu));
1088 
1089   open = gtk_menu_item_new_with_label ("Open");
1090   gtk_widget_ref (open);
1091   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "open", open,
1092                             (GtkDestroyNotify) gtk_widget_unref);
1093   gtk_widget_show (open);
1094   gtk_container_add (GTK_CONTAINER (file_menu), open);
1095   gtk_widget_add_accelerator (open, "activate", accel_group,
1096                               GDK_O, GDK_CONTROL_MASK,
1097                               GTK_ACCEL_VISIBLE);
1098 
1099   close = gtk_menu_item_new_with_label ("Close");
1100   gtk_widget_ref (close);
1101   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "close", close,
1102                             (GtkDestroyNotify) gtk_widget_unref);
1103   gtk_widget_show (close);
1104   gtk_container_add (GTK_CONTAINER (file_menu), close);
1105   gtk_widget_add_accelerator (close, "activate", accel_group,
1106                               GDK_W, GDK_CONTROL_MASK,
1107                               GTK_ACCEL_VISIBLE);
1108 
1109   separator1 = gtk_menu_item_new ();
1110   gtk_widget_ref (separator1);
1111   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "separator1", separator1,
1112                             (GtkDestroyNotify) gtk_widget_unref);
1113   gtk_widget_show (separator1);
1114   gtk_container_add (GTK_CONTAINER (file_menu), separator1);
1115   gtk_widget_set_sensitive (separator1, FALSE);
1116 
1117   file_info = gtk_menu_item_new_with_label ("Info");
1118   gtk_widget_ref (file_info);
1119   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "file_info", file_info,
1120                             (GtkDestroyNotify) gtk_widget_unref);
1121   gtk_widget_show (file_info);
1122   gtk_container_add (GTK_CONTAINER (file_menu), file_info);
1123   gtk_widget_add_accelerator (file_info, "activate", accel_group,
1124                               GDK_I, GDK_CONTROL_MASK,
1125                               GTK_ACCEL_VISIBLE);
1126 
1127   separator2 = gtk_menu_item_new ();
1128   gtk_widget_ref (separator2);
1129   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "separator2", separator2,
1130                             (GtkDestroyNotify) gtk_widget_unref);
1131   gtk_widget_show (separator2);
1132   gtk_container_add (GTK_CONTAINER (file_menu), separator2);
1133   gtk_widget_set_sensitive (separator2, FALSE);
1134 
1135   quit = gtk_menu_item_new_with_label ("Quit");
1136   gtk_widget_ref (quit);
1137   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "quit", quit,
1138                             (GtkDestroyNotify) gtk_widget_unref);
1139   gtk_widget_show (quit);
1140   gtk_container_add (GTK_CONTAINER (file_menu), quit);
1141   gtk_widget_add_accelerator (quit, "activate", accel_group,
1142                               GDK_Q, GDK_CONTROL_MASK,
1143                               GTK_ACCEL_VISIBLE);
1144 
1145   help = gtk_menu_item_new_with_label ("Help");
1146   gtk_widget_ref (help);
1147   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "help", help,
1148                             (GtkDestroyNotify) gtk_widget_unref);
1149   gtk_widget_show (help);
1150   gtk_container_add (GTK_CONTAINER (menubar1), help);
1151   gtk_menu_item_right_justify (GTK_MENU_ITEM (help));
1152 
1153   help_menu = gtk_menu_new ();
1154   gtk_widget_ref (help_menu);
1155   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "help_menu", help_menu,
1156                             (GtkDestroyNotify) gtk_widget_unref);
1157   gtk_menu_item_set_submenu (GTK_MENU_ITEM (help), help_menu);
1158   help_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (help_menu));
1159 
1160   about = gtk_menu_item_new_with_label ("About");
1161   gtk_widget_ref (about);
1162   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "about", about,
1163                             (GtkDestroyNotify) gtk_widget_unref);
1164   gtk_widget_show (about);
1165   gtk_container_add (GTK_CONTAINER (help_menu), about);
1166   gtk_widget_add_accelerator (about, "activate", accel_group,
1167                               GDK_F1, 0,
1168                               GTK_ACCEL_VISIBLE);
1169 
1170   table1 = gtk_table_new (4, 5, FALSE);
1171   gtk_widget_ref (table1);
1172   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "table1", table1,
1173                             (GtkDestroyNotify) gtk_widget_unref);
1174   gtk_widget_show (table1);
1175   gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0);
1176   gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
1177   gtk_table_set_row_spacings (GTK_TABLE (table1), 5);
1178   gtk_table_set_col_spacings (GTK_TABLE (table1), 5);
1179 
1180   seek = gtk_adjustment_new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0);
1181   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "seek", seek,
1182                             (GtkDestroyNotify) (0));
1183   scale = gtk_hscale_new(GTK_ADJUSTMENT(seek));
1184   gtv_trackbar_dragging = 0;
1185   gtk_widget_ref (scale);
1186   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "scale", scale,
1187                             (GtkDestroyNotify) gtk_widget_unref);
1188   gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
1189   gtk_widget_show (scale);
1190   gtk_table_attach (GTK_TABLE (table1), scale, 0, 5, 3, 4,
1191                     (GtkAttachOptions) (GTK_FILL),
1192                     (GtkAttachOptions) (0), 0, 0);
1193 
1194   play = gtk_button_new_with_label ("  Play  ");
1195   gtk_widget_ref (play);
1196   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "play", play,
1197                             (GtkDestroyNotify) gtk_widget_unref);
1198   gtk_widget_show (play);
1199   gtk_table_attach (GTK_TABLE (table1), play, 0, 1, 1, 2,
1200                     (GtkAttachOptions) (0),
1201                     (GtkAttachOptions) (0), 0, 0);
1202 
1203   pause = gtk_button_new_with_label ("  Pause  ");
1204   gtk_widget_ref (pause);
1205   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "pause", pause,
1206                             (GtkDestroyNotify) gtk_widget_unref);
1207   gtk_widget_show (pause);
1208   gtk_table_attach (GTK_TABLE (table1), pause, 1, 2, 1, 2,
1209                     (GtkAttachOptions) (0),
1210                     (GtkAttachOptions) (0), 0, 0);
1211 
1212   stop = gtk_button_new_with_label ("  Stop  ");
1213   gtk_widget_ref (stop);
1214   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "stop", stop,
1215                             (GtkDestroyNotify) gtk_widget_unref);
1216   gtk_widget_show (stop);
1217   gtk_table_attach (GTK_TABLE (table1), stop, 2, 3, 1, 2,
1218                     (GtkAttachOptions) (0),
1219                     (GtkAttachOptions) (0), 0, 0);
1220 
1221   step = gtk_button_new_with_label ("  Step  ");
1222   gtk_widget_ref (step);
1223   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "step", step,
1224                             (GtkDestroyNotify) gtk_widget_unref);
1225   gtk_widget_show (step);
1226   gtk_table_attach (GTK_TABLE (table1), step, 3, 4, 1, 2,
1227                     (GtkAttachOptions) (0),
1228                     (GtkAttachOptions) (0), 0, 0);
1229 
1230   to_end = gtk_button_new_with_label ("  To End  ");
1231   gtk_widget_ref (to_end);
1232   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "to_end", to_end,
1233                             (GtkDestroyNotify) gtk_widget_unref);
1234   gtk_widget_show (to_end);
1235   gtk_table_attach (GTK_TABLE (table1), to_end, 4, 5, 1, 2,
1236                     (GtkAttachOptions) (0),
1237                     (GtkAttachOptions) (0), 0, 0);
1238 
1239   twotimes = gtk_check_button_new_with_label ("Double");
1240   gtk_widget_ref (twotimes);
1241   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "twotimes", twotimes,
1242                             (GtkDestroyNotify) gtk_widget_unref);
1243   gtk_widget_show (twotimes);
1244   gtk_table_attach (GTK_TABLE (table1), twotimes, 0, 1, 2, 3,
1245                     (GtkAttachOptions) (0),
1246                     (GtkAttachOptions) (0), 0, 0);
1247 
1248   loop = gtk_check_button_new_with_label ("Loop");
1249   gtk_widget_ref (loop);
1250   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "loop", loop,
1251                             (GtkDestroyNotify) gtk_widget_unref);
1252   gtk_widget_show (loop);
1253   gtk_table_attach (GTK_TABLE (table1), loop, 1, 2, 2, 3,
1254                     (GtkAttachOptions) (0),
1255                     (GtkAttachOptions) (0), 0, 0);
1256 
1257   audio = gtk_check_button_new_with_label ("Audio");
1258   gtk_widget_ref (audio);
1259   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "audio", audio,
1260                             (GtkDestroyNotify) gtk_widget_unref);
1261   gtk_widget_show (audio);
1262   gtk_table_attach (GTK_TABLE (table1), audio, 2, 3, 2, 3,
1263                     (GtkAttachOptions) (0),
1264                     (GtkAttachOptions) (0), 0, 0);
1265 
1266   filter = gtk_check_button_new_with_label ("Filter");
1267   gtk_widget_ref (filter);
1268   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "filter", filter,
1269                             (GtkDestroyNotify) gtk_widget_unref);
1270   gtk_widget_show (filter);
1271   gtk_table_attach (GTK_TABLE (table1), filter, 3, 4, 2, 3,
1272                     (GtkAttachOptions) (0),
1273                     (GtkAttachOptions) (0), 0, 0);
1274 
1275   label3 = gtk_label_new ("Current frame:");
1276   gtk_widget_ref (label3);
1277   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "label3", label3,
1278                             (GtkDestroyNotify) gtk_widget_unref);
1279   gtk_widget_show (label3);
1280   gtk_table_attach (GTK_TABLE (table1), label3, 0, 2, 0, 1,
1281                     (GtkAttachOptions) (GTK_FILL),
1282                     (GtkAttachOptions) (0), 0, 0);
1283   gtk_misc_set_alignment (GTK_MISC (label3), 1, 0.5);
1284 
1285   fps = gtk_label_new ("<fps>");
1286   gtk_widget_ref (fps);
1287   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "fps", fps,
1288                             (GtkDestroyNotify) gtk_widget_unref);
1289   gtk_widget_show (fps);
1290   gtk_table_attach (GTK_TABLE (table1), fps, 3, 4, 0, 1,
1291                     (GtkAttachOptions) (GTK_FILL),
1292                     (GtkAttachOptions) (0), 0, 0);
1293   gtk_misc_set_alignment (GTK_MISC (fps), 1, 0.5);
1294 
1295   label2 = gtk_label_new ("fps");
1296   gtk_widget_ref (label2);
1297   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "label2", label2,
1298                             (GtkDestroyNotify) gtk_widget_unref);
1299   gtk_widget_show (label2);
1300   gtk_table_attach (GTK_TABLE (table1), label2, 4, 5, 0, 1,
1301                     (GtkAttachOptions) (GTK_FILL),
1302                     (GtkAttachOptions) (0), 0, 0);
1303   gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
1304 
1305   frame = gtk_label_new ("<frame>");
1306   gtk_widget_ref (frame);
1307   gtk_object_set_data_full (GTK_OBJECT (gtv_window), "frame", frame,
1308                             (GtkDestroyNotify) gtk_widget_unref);
1309   gtk_widget_show (frame);
1310   gtk_table_attach (GTK_TABLE (table1), frame, 2, 3, 0, 1,
1311                     (GtkAttachOptions) (GTK_FILL),
1312                     (GtkAttachOptions) (0), 0, 0);
1313   gtk_misc_set_alignment (GTK_MISC (frame), 0, 0.5);
1314 
1315   gtk_window_add_accel_group (GTK_WINDOW (gtv_window), accel_group);
1316 
1317   return gtv_window;
1318 }
1319