9d9c3deb1d38d1569fee597624be93287232ac51
[vlc.git] / modules / gui / gtk / gtk_callbacks.c
1 /*****************************************************************************
2  * gtk_callbacks.c : Callbacks for the Gtk+ plugin.
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: gtk_callbacks.c,v 1.12 2003/02/05 22:11:52 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          St├ęphane Borel <stef@via.ecp.fr>
9  *          Julien BLACHE <jb@technologeek.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <sys/types.h>                                              /* off_t */
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34 #include <vlc/vout.h>
35 #include <vlc/aout.h>
36
37 #include <unistd.h>
38
39 #include <gtk/gtk.h>
40
41 #include <string.h>
42
43 #include "gtk_callbacks.h"
44 #include "gtk_interface.h"
45 #include "gtk_support.h"
46
47 #include "common.h"
48
49 #include "netutils.h"
50
51 /*****************************************************************************
52  * Useful function to retrieve p_intf
53  ****************************************************************************/
54 void * E_(__GtkGetIntf)( GtkWidget * widget )
55 {
56     void *p_data;
57
58     if( GTK_IS_MENU_ITEM( widget ) )
59     {
60         /* Look for a GTK_MENU */
61         while( widget->parent && !GTK_IS_MENU( widget ) )
62         {
63             widget = widget->parent;
64         }
65
66         /* Maybe this one has the data */
67         p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" );
68         if( p_data )
69         {
70             return p_data;
71         }
72
73         /* Otherwise, the parent widget has it */
74         widget = gtk_menu_get_attach_widget( GTK_MENU( widget ) );
75         p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" );
76         if( p_data )
77         {
78             return p_data;
79         }
80     }
81
82     /* We look for the top widget */
83     widget = gtk_widget_get_toplevel( GTK_WIDGET( widget ) );
84     p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" );
85
86     return p_data;
87 }
88
89 /*****************************************************************************
90  * Callbacks
91  *****************************************************************************/
92
93 /*
94  * Main interface callbacks
95  */
96
97 #ifdef MODULE_NAME_IS_gtk
98 #   define GTKEXIT GtkExit
99 #else
100 #   define GTKEXIT GnomeExit
101 #endif
102
103 gboolean GTKEXIT( GtkWidget       *widget,
104                   gpointer         user_data )
105 {
106     intf_thread_t *p_intf = GtkGetIntf( widget );
107
108     vlc_mutex_lock( &p_intf->change_lock );
109     p_intf->p_vlc->b_die = VLC_TRUE;
110     vlc_mutex_unlock( &p_intf->change_lock );
111
112     return TRUE;
113 }
114
115 void GtkClose( GtkMenuItem     *menuitem,
116                gpointer         user_data )
117 {
118     intf_thread_t *p_intf = GtkGetIntf( menuitem );
119     p_intf->b_die = VLC_TRUE;
120 }
121
122 gboolean GtkWindowDelete( GtkWidget       *widget,
123                           GdkEvent        *event,
124                           gpointer         user_data )
125 {
126     GTKEXIT( GTK_WIDGET( widget ), user_data );
127
128     return TRUE;
129 }
130
131
132 gboolean GtkWindowToggle( GtkWidget       *widget,
133                           gpointer         user_data )
134 {
135     intf_thread_t *p_intf = GtkGetIntf( widget );
136
137     if( GTK_WIDGET_VISIBLE(p_intf->p_sys->p_window) )
138     {
139         gtk_widget_hide( p_intf->p_sys->p_window);
140     }
141     else
142     {
143         gtk_widget_show( p_intf->p_sys->p_window );
144     }
145
146     return TRUE;
147 }
148
149 gboolean GtkFullscreen( GtkWidget       *widget,
150                         gpointer         user_data)
151 {
152     intf_thread_t *p_intf = GtkGetIntf( widget );
153     vout_thread_t *p_vout;
154
155     if( p_intf->p_sys->p_input == NULL )
156     {
157         return FALSE;
158     }
159
160     p_vout = vlc_object_find( p_intf->p_sys->p_input,
161                               VLC_OBJECT_VOUT, FIND_CHILD );
162     if( p_vout == NULL )
163     {
164         return FALSE;
165     }
166
167     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
168     vlc_object_release( p_vout );
169     return TRUE;
170 }
171
172 void GtkWindowDrag( GtkWidget       *widget,
173                     GdkDragContext  *drag_context,
174                     gint             x,
175                     gint             y,
176                     GtkSelectionData *data,
177                     guint            info,
178                     guint            time,
179                     gpointer         user_data)
180 {
181     intf_thread_t * p_intf = GtkGetIntf( widget );
182     GtkDropDataReceived( p_intf, data, info, PLAYLIST_END );
183 }
184
185
186 /****************************************************************************
187  * Slider management
188  ****************************************************************************/
189
190 gboolean GtkSliderRelease( GtkWidget       *widget,
191                            GdkEventButton  *event,
192                            gpointer         user_data )
193 {
194     intf_thread_t *p_intf = GtkGetIntf( widget );
195
196     vlc_mutex_lock( &p_intf->change_lock );
197     p_intf->p_sys->b_slider_free = VLC_TRUE;
198     vlc_mutex_unlock( &p_intf->change_lock );
199
200     return FALSE;
201 }
202
203
204 gboolean GtkSliderPress( GtkWidget       *widget,
205                          GdkEventButton  *event,
206                          gpointer         user_data)
207 {
208     intf_thread_t *p_intf = GtkGetIntf( widget );
209
210     vlc_mutex_lock( &p_intf->change_lock );
211     p_intf->p_sys->b_slider_free = VLC_FALSE;
212     vlc_mutex_unlock( &p_intf->change_lock );
213
214     return FALSE;
215 }
216
217
218 /****************************************************************************
219  * DVD specific items
220  ****************************************************************************/
221
222 void GtkTitlePrev( GtkButton * button, gpointer user_data )
223 {
224     intf_thread_t *  p_intf;
225     input_area_t *   p_area;
226     int              i_id;
227
228     p_intf = GtkGetIntf( button );
229     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
230     i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1;
231
232     if( i_id > 0 )
233     {
234         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
235         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
236
237         input_ChangeArea( p_intf->p_sys->p_input, p_area );
238         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
239
240         p_intf->p_sys->b_title_update = VLC_TRUE;
241         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
242         GtkSetupMenus( p_intf );
243     }
244
245     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
246 }
247
248
249 void GtkTitleNext( GtkButton * button, gpointer user_data )
250 {
251     intf_thread_t * p_intf;
252     input_area_t *  p_area;
253     unsigned int    i_id;
254
255     p_intf = GtkGetIntf( button );
256     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
257     i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1;
258
259     if( i_id < p_intf->p_sys->p_input->stream.i_area_nb )
260     {
261         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
262         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
263
264         input_ChangeArea( p_intf->p_sys->p_input, p_area );
265         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
266
267         p_intf->p_sys->b_title_update = VLC_TRUE;
268         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
269         GtkSetupMenus( p_intf );
270     }
271
272     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
273 }
274
275
276 void GtkChapterPrev( GtkButton * button, gpointer user_data )
277 {
278     intf_thread_t * p_intf;
279     input_area_t *  p_area;
280
281     p_intf = GtkGetIntf( button );
282     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
283     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
284
285     if( p_area->i_part - 1 > 0 )
286     {
287         p_area->i_part--;
288         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
289
290         input_ChangeArea( p_intf->p_sys->p_input, p_area );
291         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
292
293         p_intf->p_sys->b_chapter_update = VLC_TRUE;
294         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
295         GtkSetupMenus( p_intf );
296     }
297
298     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
299 }
300
301
302 void GtkChapterNext( GtkButton * button, gpointer user_data )
303 {
304     intf_thread_t * p_intf;
305     input_area_t *  p_area;
306
307     p_intf = GtkGetIntf( button );
308     vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
309     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
310
311     if( p_area->i_part + 1 < p_area->i_part_nb )
312     {
313         p_area->i_part++;
314         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
315
316         input_ChangeArea( p_intf->p_sys->p_input, p_area );
317         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
318
319         p_intf->p_sys->b_chapter_update = VLC_TRUE;
320         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
321         GtkSetupMenus( p_intf );
322     }
323
324     vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
325 }
326
327 /****************************************************************************
328  * Network specific items
329  ****************************************************************************/
330 void GtkNetworkJoin( GtkEditable * editable, gpointer user_data )
331 {
332     int     i_channel;
333
334     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( editable ) );
335 #if 0
336     msg_Dbg( "intf info: joining channel %d", i_channel );
337
338     network_ChannelJoin( i_channel );
339 #endif
340 }
341
342 void GtkChannelGo( GtkButton * button, gpointer user_data )
343 {
344     GtkWidget *     window;
345     GtkWidget *     spin;
346     int             i_channel;
347
348     intf_thread_t *p_intf = GtkGetIntf( button );
349
350     window = gtk_widget_get_toplevel( GTK_WIDGET (button) );
351     spin = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( window ),
352                        "network_channel_spinbutton" ) );
353
354     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin ) );
355     msg_Dbg( p_intf, "joining channel %d", i_channel );
356
357     vlc_mutex_lock( &p_intf->change_lock );
358     network_ChannelJoin( p_intf, i_channel );
359     vlc_mutex_unlock( &p_intf->change_lock );
360
361 /*    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); */
362 }
363
364
365 /****************************************************************************
366  * About box
367  ****************************************************************************/
368
369 gboolean GtkAboutShow( GtkWidget       *widget,
370                        gpointer         user_data)
371 {
372     intf_thread_t *p_intf = GtkGetIntf( widget );
373
374     if( !GTK_IS_WIDGET( p_intf->p_sys->p_about ) )
375     {
376         p_intf->p_sys->p_about = create_intf_about();
377         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_about ),
378                              "p_intf", p_intf );
379     }
380     gtk_widget_show( p_intf->p_sys->p_about );
381     gdk_window_raise( p_intf->p_sys->p_about->window );
382
383     return TRUE;
384 }
385
386 void GtkAboutOk( GtkButton * button, gpointer user_data)
387 {
388     intf_thread_t *p_intf = GtkGetIntf( button );
389
390     gtk_widget_hide( p_intf->p_sys->p_about );
391 }
392
393
394 /****************************************************************************
395  * Jump box
396  ****************************************************************************/
397
398 gboolean GtkJumpShow( GtkWidget       *widget,
399                       gpointer         user_data)
400 {
401     intf_thread_t *p_intf = GtkGetIntf( widget );
402
403     if( !GTK_IS_WIDGET( p_intf->p_sys->p_jump ) )
404     {
405         p_intf->p_sys->p_jump = create_intf_jump();
406         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_jump ),
407                              "p_intf", p_intf );
408     }
409
410     gtk_widget_show( p_intf->p_sys->p_jump );
411     gdk_window_raise( p_intf->p_sys->p_jump->window );
412
413     return FALSE;
414 }
415
416
417 void GtkJumpOk( GtkButton       *button,
418                 gpointer         user_data)
419 {
420     intf_thread_t * p_intf = GtkGetIntf( button );
421     int i_hours, i_minutes, i_seconds;
422
423     if( p_intf->p_sys->p_input == NULL )
424     {
425         return;
426     }
427
428 #define GET_VALUE( name )                                                   \
429     gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( gtk_object_get_data( \
430         GTK_OBJECT( p_intf->p_sys->p_jump ), name ) ) )
431     i_hours   = GET_VALUE( "jump_hour_spinbutton" );
432     i_minutes = GET_VALUE( "jump_minute_spinbutton" );
433     i_seconds = GET_VALUE( "jump_second_spinbutton" );
434 #undef GET_VALUE
435
436     input_Seek( p_intf->p_sys->p_input,
437                 i_seconds + 60 * i_minutes + 3600 * i_hours,
438                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
439
440     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
441 }
442
443
444 void GtkJumpCancel( GtkButton       *button,
445                     gpointer         user_data)
446 {
447     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
448 }
449
450 /****************************************************************************
451  * Callbacks for disc ejection
452  ****************************************************************************/
453 gboolean GtkDiscEject ( GtkWidget *widget, gpointer user_data )
454 {
455     char *psz_device = NULL;
456     char *psz_parser;
457     char *psz_current;
458
459     intf_thread_t *p_intf = GtkGetIntf( widget );
460     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
461                                                        FIND_ANYWHERE );
462     if( p_playlist == NULL )
463     {
464         return FALSE;
465     }
466
467     vlc_mutex_lock( &p_playlist->object_lock );
468
469     if( p_playlist->i_index < 0 )
470     {
471         vlc_mutex_unlock( &p_playlist->object_lock );
472         vlc_object_release( p_playlist );
473         return FALSE;
474     }
475
476     psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name;
477
478     /*
479      * Get the active input
480      * Determine whether we can eject a media, ie it's a VCD or DVD
481      * If it's neither a VCD nor a DVD, then return
482      */
483
484     /*
485      * Don't really know if I must lock the stuff here, we're using it read-only
486      */
487
488     if( psz_current != NULL )
489     {
490         if( !strncmp(psz_current, "dvd:", 4) )
491         {
492             switch( psz_current[4] )
493             {
494             case '\0':
495             case '@':
496                 psz_device = config_GetPsz( p_intf, "dvd" );
497                 break;
498             default:
499                 /* Omit the first 4 characters */
500                 psz_device = strdup( psz_current + 4 );
501                 break;
502             }
503         }
504         else if( !strncmp(psz_current, "vcd:", 4) )
505         {
506             switch( psz_current[4] )
507             {
508             case '\0':
509             case '@':
510                 psz_device = config_GetPsz( p_intf, "vcd" );
511                 break;
512             default:
513                 /* Omit the first 4 characters */
514                 psz_device = strdup( psz_current + 4 );
515                 break;
516             }
517         }
518         else
519         {
520             psz_device = strdup( psz_current );
521         }
522     }
523
524     vlc_mutex_unlock( &p_playlist->object_lock );
525     vlc_object_release( p_playlist );
526
527     if( psz_device == NULL )
528     {
529         return TRUE;
530     }
531
532     /* Remove what we have after @ */
533     psz_parser = psz_device;
534     for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
535     {
536         if( *psz_parser == '@' )
537         {
538             *psz_parser = '\0';
539             break;
540         }
541     }
542
543     /* If there's a stream playing, we aren't allowed to eject ! */
544     if( p_intf->p_sys->p_input == NULL )
545     {
546         msg_Dbg( p_intf, "ejecting %s", psz_device );
547
548         intf_Eject( p_intf, psz_device );
549     }
550
551     free(psz_device);
552
553     return TRUE;
554 }
555
556 /****************************************************************************
557  * Messages window
558  ****************************************************************************/
559
560 gboolean GtkMessagesShow( GtkWidget       *widget,
561                           gpointer         user_data)
562 {
563     static GdkColor black = { 0, 0x0000, 0x0000, 0x0000 };
564     static GdkColormap *colormap;
565     intf_thread_t *p_intf = GtkGetIntf( widget );
566
567     gtk_widget_show( p_intf->p_sys->p_messages );
568     colormap = gdk_colormap_get_system ();
569     gdk_color_alloc( colormap, &black );
570     gdk_window_set_background( p_intf->p_sys->p_messages_text->text_area,
571                                &black );
572
573     gdk_window_raise( p_intf->p_sys->p_messages->window );
574
575     gtk_text_set_point( p_intf->p_sys->p_messages_text,
576                     gtk_text_get_length( p_intf->p_sys->p_messages_text ) );
577
578     return TRUE;
579 }
580
581 void
582 GtkMessagesOk                          (GtkButton       *button,
583                                         gpointer         user_data)
584 {
585     intf_thread_t *p_intf = GtkGetIntf( button );
586     gtk_widget_hide( p_intf->p_sys->p_messages );
587 }
588
589
590 gboolean
591 GtkMessagesDelete                      (GtkWidget       *widget,
592                                         GdkEvent        *event,
593                                         gpointer         user_data)
594 {
595     intf_thread_t *p_intf = GtkGetIntf( widget );
596     gtk_widget_hide( p_intf->p_sys->p_messages );
597     return TRUE;
598 }
599
600
601 void
602 GtkOpenNotebookChanged                 (GtkNotebook     *notebook,
603                                         GtkNotebookPage *page,
604                                         gint             page_num,
605                                         gpointer         user_data)
606 {
607     GtkOpenChanged( GTK_WIDGET( notebook ), user_data );
608 }
609
610 /****************************************************************************
611  * Audio management
612  ****************************************************************************/
613 void GtkVolumeUp                      ( GtkMenuItem     *menuitem,
614                                         gpointer         user_data )
615 {
616     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
617     aout_instance_t *p_aout;
618
619     p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
620     if( p_aout != NULL )
621     {
622         if( p_intf->p_sys->b_mute )
623         {
624             audio_volume_t i_volume;
625
626             aout_VolumeMute( p_aout, &i_volume );
627             p_intf->p_sys->b_mute = ( i_volume == 0 ) ? 1 : 0;
628
629         }
630         aout_VolumeUp( p_aout, 1, NULL );
631         vlc_object_release( (vlc_object_t *)p_aout );
632     }
633 }
634
635
636 void GtkVolumeDown                    ( GtkMenuItem     *menuitem,
637                                         gpointer         user_data )
638 {
639     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
640     aout_instance_t *p_aout;
641
642     p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
643     if( p_aout != NULL )
644     {
645         if( p_intf->p_sys->b_mute )
646         {
647             audio_volume_t i_volume;
648
649             aout_VolumeMute( p_aout, &i_volume );
650             p_intf->p_sys->b_mute = ( i_volume == 0 ) ? 1 : 0;
651         }
652         aout_VolumeDown( p_aout, 1, NULL );
653         vlc_object_release( (vlc_object_t *)p_aout );
654     }
655 }
656
657
658 void GtkVolumeMute                    ( GtkMenuItem     *menuitem,
659                                         gpointer         user_data )
660 {
661     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
662     aout_instance_t *p_aout;
663     audio_volume_t i_volume;
664
665     p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT, FIND_ANYWHERE );
666
667     if( p_aout != NULL )
668     {
669         aout_VolumeMute( p_aout, &i_volume );
670
671         p_intf->p_sys->b_mute = ( i_volume == 0 ) ? 1 : 0;
672
673         vlc_object_release( (vlc_object_t *)p_aout );
674     }
675 }
676
677 void
678 GtkMenubarDeinterlace                  ( GtkMenuItem     *menuitem,
679                                         gpointer         user_data)
680 {
681     intf_thread_t   *p_intf = GtkGetIntf( menuitem );
682
683     if( p_intf )
684         msg_Dbg( p_intf, "GtkMenubarDeinterlace" );
685
686     
687 }
688
689
690 void
691 GtkPopupDeinterlace                    (GtkRadioMenuItem *radiomenuitem,
692                                         gpointer         user_data)
693 {
694     intf_thread_t   *p_intf = GtkGetIntf( radiomenuitem );
695
696     if( p_intf )
697         msg_Dbg( p_intf, "GtkPopupDeinterlace" );
698 }
699
700
701