*Allow 0 for title selection as it is the area for first play pgc in DVDs
[vlc.git] / plugins / 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.50 2002/07/23 19:28:25 stef 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
36 #include <unistd.h>
37
38 #include <gtk/gtk.h>
39
40 #include <string.h>
41
42 #include "gtk_callbacks.h"
43 #include "gtk_interface.h"
44 #include "gtk_support.h"
45 #include "gtk_common.h"
46
47 #include "netutils.h"
48
49 /*****************************************************************************
50  * Useful function to retrieve p_intf
51  ****************************************************************************/
52 void * __GtkGetIntf( GtkWidget * widget )
53 {
54     void *p_data;
55
56     if( GTK_IS_MENU_ITEM( widget ) )
57     {
58         /* Look for a GTK_MENU */
59         while( widget->parent && !GTK_IS_MENU( widget ) )
60         {
61             widget = widget->parent;
62         }
63
64         /* Maybe this one has the data */
65         p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" );
66         if( p_data )
67         {
68             return p_data;
69         }
70
71         /* Otherwise, the parent widget has it */
72         widget = gtk_menu_get_attach_widget( GTK_MENU( widget ) );
73     }
74
75     /* We look for the top widget */
76     widget = gtk_widget_get_toplevel( GTK_WIDGET( widget ) );
77
78     p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" );
79
80     return p_data;
81 }
82
83 /*****************************************************************************
84  * Callbacks
85  *****************************************************************************/
86
87 /*
88  * Main interface callbacks
89  */
90
91 gboolean GtkExit( GtkWidget       *widget,
92                   gpointer         user_data )
93 {
94     intf_thread_t *p_intf = GtkGetIntf( widget );
95
96     vlc_mutex_lock( &p_intf->change_lock );
97     p_intf->p_vlc->b_die = VLC_TRUE;
98     vlc_mutex_unlock( &p_intf->change_lock );
99
100     return TRUE;
101 }
102
103 void GtkClose( GtkMenuItem     *menuitem,
104                gpointer         user_data )
105 {
106     intf_thread_t *p_intf = GtkGetIntf( menuitem );
107     p_intf->b_die = VLC_TRUE;
108 }
109
110 gboolean GtkWindowDelete( GtkWidget       *widget,
111                           GdkEvent        *event,
112                           gpointer         user_data )
113 {
114     GtkExit( GTK_WIDGET( widget ), user_data );
115
116     return TRUE;
117 }
118
119
120 gboolean GtkWindowToggle( GtkWidget       *widget,
121                           gpointer         user_data )
122 {
123     intf_thread_t *p_intf = GtkGetIntf( widget );
124     
125     if( GTK_WIDGET_VISIBLE(p_intf->p_sys->p_window) )
126     {
127         gtk_widget_hide( p_intf->p_sys->p_window);
128     } 
129     else 
130     {
131         gtk_widget_show( p_intf->p_sys->p_window );
132     }
133
134     return TRUE;
135 }
136
137 gboolean GtkFullscreen( GtkWidget       *widget,
138                         gpointer         user_data)
139 {
140     intf_thread_t *p_intf = GtkGetIntf( widget );
141     vout_thread_t *p_vout;
142
143     p_vout = vlc_object_find( p_intf->p_sys->p_input,
144                               VLC_OBJECT_VOUT, FIND_CHILD );
145     if( p_vout == NULL )
146     {
147         return FALSE;
148     }
149
150     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
151     vlc_object_release( p_vout );
152     return TRUE;
153 }
154
155 void GtkWindowDrag( GtkWidget       *widget,
156                     GdkDragContext  *drag_context,
157                     gint             x,
158                     gint             y,
159                     GtkSelectionData *data,
160                     guint            info,
161                     guint            time,
162                     gpointer         user_data)
163 {
164     intf_thread_t * p_intf = GtkGetIntf( widget );
165     GtkDropDataReceived( p_intf, data, info, PLAYLIST_END );
166 }
167
168
169 /****************************************************************************
170  * Slider management
171  ****************************************************************************/
172
173 gboolean GtkSliderRelease( GtkWidget       *widget,
174                            GdkEventButton  *event,
175                            gpointer         user_data )
176 {
177     intf_thread_t *p_intf = GtkGetIntf( widget );
178
179     vlc_mutex_lock( &p_intf->change_lock );
180     p_intf->p_sys->b_slider_free = 1;
181     vlc_mutex_unlock( &p_intf->change_lock );
182
183     return FALSE;
184 }
185
186
187 gboolean GtkSliderPress( GtkWidget       *widget,
188                          GdkEventButton  *event,
189                          gpointer         user_data)
190 {
191     intf_thread_t *p_intf = GtkGetIntf( widget );
192
193     vlc_mutex_lock( &p_intf->change_lock );
194     p_intf->p_sys->b_slider_free = 0;
195     vlc_mutex_unlock( &p_intf->change_lock );
196
197     return FALSE;
198 }
199
200
201 /****************************************************************************
202  * DVD specific items
203  ****************************************************************************/
204
205 void GtkTitlePrev( GtkButton * button, gpointer user_data )
206 {
207     intf_thread_t *  p_intf;
208     input_area_t *   p_area;
209     int              i_id;
210
211     p_intf = GtkGetIntf( button );
212
213     i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1;
214
215     if( i_id >= 0 )
216     {
217         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
218         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
219
220         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
221
222         p_intf->p_sys->b_title_update = 1;
223         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
224         GtkSetupMenus( p_intf );
225         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
226     }
227 }
228
229
230 void GtkTitleNext( GtkButton * button, gpointer user_data )
231 {
232     intf_thread_t * p_intf;
233     input_area_t *  p_area;
234     int             i_id;
235
236     p_intf = GtkGetIntf( button );
237     i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1;
238
239     if( i_id < p_intf->p_sys->p_input->stream.i_area_nb )
240     {
241         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];   
242         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
243
244         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
245
246         p_intf->p_sys->b_title_update = 1;
247         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
248         GtkSetupMenus( p_intf );
249         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
250     }
251 }
252
253
254 void GtkChapterPrev( GtkButton * button, gpointer user_data )
255 {
256     intf_thread_t * p_intf;
257     input_area_t *  p_area;
258
259     p_intf = GtkGetIntf( button );
260     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
261
262     if( p_area->i_part > 0 )
263     {
264         p_area->i_part--;
265         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
266
267         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
268
269         p_intf->p_sys->b_chapter_update = 1;
270         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
271         GtkSetupMenus( p_intf );
272         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
273     }
274 }
275
276
277 void GtkChapterNext( GtkButton * button, gpointer user_data )
278 {
279     intf_thread_t * p_intf;
280     input_area_t *  p_area;
281
282     p_intf = GtkGetIntf( button );
283     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
284
285     if( p_area->i_part < p_area->i_part_nb )
286     {
287         p_area->i_part++;
288         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
289
290         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
291
292         p_intf->p_sys->b_chapter_update = 1;
293         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
294         GtkSetupMenus( p_intf );
295         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
296     }
297 }
298
299 /****************************************************************************
300  * Network specific items
301  ****************************************************************************/
302 void GtkNetworkJoin( GtkEditable * editable, gpointer user_data )
303 {
304     int     i_channel;
305
306     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( editable ) );
307 //    msg_Dbg( "intf info: joining channel %d", i_channel );
308
309 //    network_ChannelJoin( i_channel );
310 }
311
312 void GtkChannelGo( GtkButton * button, gpointer user_data )
313 {
314     GtkWidget *     window;
315     GtkWidget *     spin;
316     int             i_channel;
317
318     intf_thread_t *p_intf = GtkGetIntf( button );
319
320     window = gtk_widget_get_toplevel( GTK_WIDGET (button) );
321     spin = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( window ),
322                        "network_channel_spinbutton" ) );
323
324     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin ) );
325     msg_Dbg( p_intf, "joining channel %d", i_channel );
326
327     vlc_mutex_lock( &p_intf->change_lock );
328     network_ChannelJoin( p_intf, i_channel );
329     vlc_mutex_unlock( &p_intf->change_lock );
330
331 //    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
332 }
333
334
335 /****************************************************************************
336  * About box
337  ****************************************************************************/
338
339 gboolean GtkAboutShow( GtkWidget       *widget,
340                        gpointer         user_data)
341 {
342     intf_thread_t *p_intf = GtkGetIntf( widget );
343
344     if( !GTK_IS_WIDGET( p_intf->p_sys->p_about ) )
345     {
346         p_intf->p_sys->p_about = create_intf_about();
347         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_about ),
348                              "p_intf", p_intf );
349     }
350     gtk_widget_show( p_intf->p_sys->p_about );
351     gdk_window_raise( p_intf->p_sys->p_about->window );
352
353     return TRUE;
354 }
355
356 void GtkAboutOk( GtkButton * button, gpointer user_data)
357 {
358     intf_thread_t *p_intf = GtkGetIntf( button );
359
360     gtk_widget_hide( p_intf->p_sys->p_about );
361 }
362
363
364 /****************************************************************************
365  * Jump box
366  ****************************************************************************/
367
368 gboolean GtkJumpShow( GtkWidget       *widget,
369                       gpointer         user_data)
370 {
371     intf_thread_t *p_intf = GtkGetIntf( widget );
372
373     if( !GTK_IS_WIDGET( p_intf->p_sys->p_jump ) )
374     {
375         p_intf->p_sys->p_jump = create_intf_jump();
376         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_jump ),
377                              "p_intf", p_intf );
378     }
379
380     gtk_widget_show( p_intf->p_sys->p_jump );
381     gdk_window_raise( p_intf->p_sys->p_jump->window );
382
383     return FALSE;
384 }
385
386
387 void GtkJumpOk( GtkButton       *button,
388                 gpointer         user_data)
389 {
390     intf_thread_t * p_intf = GtkGetIntf( button );
391     int i_hours, i_minutes, i_seconds;
392
393     if( p_intf->p_sys->p_input == NULL )
394     {
395         return;
396     }
397
398 #define GET_VALUE( name )                                                   \
399     gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( gtk_object_get_data( \
400         GTK_OBJECT( p_intf->p_sys->p_jump ), name ) ) )
401     i_hours   = GET_VALUE( "jump_hour_spinbutton" );
402     i_minutes = GET_VALUE( "jump_minute_spinbutton" );
403     i_seconds = GET_VALUE( "jump_second_spinbutton" );
404 #undef GET_VALUE
405
406     input_Seek( p_intf->p_sys->p_input,
407                 i_seconds + 60 * i_minutes + 3600 * i_hours,
408                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
409
410     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
411 }
412
413
414 void GtkJumpCancel( GtkButton       *button,
415                     gpointer         user_data)
416 {
417     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
418 }
419
420 /****************************************************************************
421  * Callbacks for disc ejection
422  ****************************************************************************/
423 gboolean GtkDiscEject ( GtkWidget *widget, gpointer user_data )
424 {
425     char *psz_device = NULL;
426     char *psz_parser;
427     char *psz_current;
428
429     intf_thread_t *p_intf = GtkGetIntf( widget );
430     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
431                                                        FIND_ANYWHERE );
432     if( p_playlist == NULL )
433     {
434         return FALSE;
435     }
436
437     vlc_mutex_lock( &p_playlist->object_lock );
438
439     if( p_playlist->i_index < 0 )
440     {
441         vlc_mutex_unlock( &p_playlist->object_lock );
442         vlc_object_release( p_playlist );
443         return FALSE;
444     }
445
446     psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name;
447
448     /*
449      * Get the active input
450      * Determine whether we can eject a media, ie it's a VCD or DVD
451      * If it's neither a VCD nor a DVD, then return
452      */
453
454     /*
455      * Don't really know if I must lock the stuff here, we're using it read-only
456      */
457
458     if( psz_current != NULL )
459     {
460         if( !strncmp(psz_current, "dvd:", 4) )
461         {
462             switch( psz_current[4] )
463             {
464             case '\0':
465             case '@':
466                 psz_device = config_GetPsz( p_intf, "dvd" );
467                 break;
468             default:
469                 /* Omit the first 4 characters */
470                 psz_device = strdup( psz_current + 4 );
471                 break;
472             }
473         }
474         else if( !strncmp(psz_current, "vcd:", 4) )
475         {
476             switch( psz_current[4] )
477             {
478             case '\0':
479             case '@':
480                 psz_device = config_GetPsz( p_intf, "vcd" );
481                 break;
482             default:
483                 /* Omit the first 4 characters */
484                 psz_device = strdup( psz_current + 4 );
485                 break;
486             }
487         }
488         else
489         {
490             psz_device = strdup( psz_current );
491         }
492     }
493
494     vlc_mutex_unlock( &p_playlist->object_lock );
495     vlc_object_release( p_playlist );
496
497     if( psz_device == NULL )
498     {
499         return TRUE;
500     }
501
502     /* Remove what we have after @ */
503     psz_parser = psz_device;
504     for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
505     {
506         if( *psz_parser == '@' )
507         {
508             *psz_parser = '\0';
509             break;
510         }
511     }
512
513     /* If there's a stream playing, we aren't allowed to eject ! */
514     if( p_intf->p_sys->p_input == NULL )
515     {
516         msg_Dbg( p_intf, "ejecting %s", psz_device );
517
518         intf_Eject( p_intf, psz_device );
519     }
520
521     free(psz_device);
522
523     return TRUE;
524 }
525
526 /****************************************************************************
527  * Messages window
528  ****************************************************************************/
529
530 gboolean GtkMessagesShow( GtkWidget       *widget,
531                           gpointer         user_data)
532 {
533     static GdkColor black = { 0, 0x0000, 0x0000, 0x0000 };
534     static GdkColormap *colormap;
535     intf_thread_t *p_intf = GtkGetIntf( widget );
536
537     gtk_widget_show( p_intf->p_sys->p_messages );
538     colormap = gdk_colormap_get_system ();
539     gdk_color_alloc( colormap, &black );
540     gdk_window_set_background( p_intf->p_sys->p_messages_text->text_area,
541                                &black );
542
543     gdk_window_raise( p_intf->p_sys->p_messages->window );
544
545     gtk_text_set_point( p_intf->p_sys->p_messages_text,
546                     gtk_text_get_length( p_intf->p_sys->p_messages_text ) );
547
548     return TRUE;
549 }
550
551
552 void
553 GtkMessagesOk                          (GtkButton       *button,
554                                         gpointer         user_data)
555 {
556     intf_thread_t *p_intf = GtkGetIntf( button );
557     gtk_widget_hide( p_intf->p_sys->p_messages );
558 }
559
560
561 gboolean
562 GtkMessagesDelete                      (GtkWidget       *widget,
563                                         GdkEvent        *event,
564                                         gpointer         user_data)
565 {
566     intf_thread_t *p_intf = GtkGetIntf( widget );
567     gtk_widget_hide( p_intf->p_sys->p_messages );
568     return TRUE;
569 }
570
571
572 void
573 GtkOpenNotebookChanged                 (GtkNotebook     *notebook,
574                                         GtkNotebookPage *page,
575                                         gint             page_num,
576                                         gpointer         user_data)
577 {
578     GtkOpenChanged( GTK_WIDGET( notebook ), user_data );
579 }
580