03887104a4e4444b56913798bda190dbad1aa90b
[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.49 2002/07/15 20:09:31 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
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     /* Disallow area 0 since it is used for video_ts.vob */
216     if( i_id > 0 )
217     {
218         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
219         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
220
221         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
222
223         p_intf->p_sys->b_title_update = 1;
224         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
225         GtkSetupMenus( p_intf );
226         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
227     }
228 }
229
230
231 void GtkTitleNext( GtkButton * button, gpointer user_data )
232 {
233     intf_thread_t * p_intf;
234     input_area_t *  p_area;
235     int             i_id;
236
237     p_intf = GtkGetIntf( button );
238     i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1;
239
240     if( i_id < p_intf->p_sys->p_input->stream.i_area_nb )
241     {
242         p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];   
243         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
244
245         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
246
247         p_intf->p_sys->b_title_update = 1;
248         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
249         GtkSetupMenus( p_intf );
250         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
251     }
252 }
253
254
255 void GtkChapterPrev( GtkButton * button, gpointer user_data )
256 {
257     intf_thread_t * p_intf;
258     input_area_t *  p_area;
259
260     p_intf = GtkGetIntf( button );
261     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
262
263     if( p_area->i_part > 0 )
264     {
265         p_area->i_part--;
266         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
267
268         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
269
270         p_intf->p_sys->b_chapter_update = 1;
271         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
272         GtkSetupMenus( p_intf );
273         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
274     }
275 }
276
277
278 void GtkChapterNext( GtkButton * button, gpointer user_data )
279 {
280     intf_thread_t * p_intf;
281     input_area_t *  p_area;
282
283     p_intf = GtkGetIntf( button );
284     p_area = p_intf->p_sys->p_input->stream.p_selected_area;
285
286     if( p_area->i_part < p_area->i_part_nb )
287     {
288         p_area->i_part++;
289         input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
290
291         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
292
293         p_intf->p_sys->b_chapter_update = 1;
294         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
295         GtkSetupMenus( p_intf );
296         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
297     }
298 }
299
300 /****************************************************************************
301  * Network specific items
302  ****************************************************************************/
303 void GtkNetworkJoin( GtkEditable * editable, gpointer user_data )
304 {
305     int     i_channel;
306
307     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( editable ) );
308 //    msg_Dbg( "intf info: joining channel %d", i_channel );
309
310 //    network_ChannelJoin( i_channel );
311 }
312
313 void GtkChannelGo( GtkButton * button, gpointer user_data )
314 {
315     GtkWidget *     window;
316     GtkWidget *     spin;
317     int             i_channel;
318
319     intf_thread_t *p_intf = GtkGetIntf( button );
320
321     window = gtk_widget_get_toplevel( GTK_WIDGET (button) );
322     spin = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( window ),
323                        "network_channel_spinbutton" ) );
324
325     i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin ) );
326     msg_Dbg( p_intf, "joining channel %d", i_channel );
327
328     vlc_mutex_lock( &p_intf->change_lock );
329     network_ChannelJoin( p_intf, i_channel );
330     vlc_mutex_unlock( &p_intf->change_lock );
331
332 //    input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
333 }
334
335
336 /****************************************************************************
337  * About box
338  ****************************************************************************/
339
340 gboolean GtkAboutShow( GtkWidget       *widget,
341                        gpointer         user_data)
342 {
343     intf_thread_t *p_intf = GtkGetIntf( widget );
344
345     if( !GTK_IS_WIDGET( p_intf->p_sys->p_about ) )
346     {
347         p_intf->p_sys->p_about = create_intf_about();
348         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_about ),
349                              "p_intf", p_intf );
350     }
351     gtk_widget_show( p_intf->p_sys->p_about );
352     gdk_window_raise( p_intf->p_sys->p_about->window );
353
354     return TRUE;
355 }
356
357 void GtkAboutOk( GtkButton * button, gpointer user_data)
358 {
359     intf_thread_t *p_intf = GtkGetIntf( button );
360
361     gtk_widget_hide( p_intf->p_sys->p_about );
362 }
363
364
365 /****************************************************************************
366  * Jump box
367  ****************************************************************************/
368
369 gboolean GtkJumpShow( 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_jump ) )
375     {
376         p_intf->p_sys->p_jump = create_intf_jump();
377         gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_jump ),
378                              "p_intf", p_intf );
379     }
380
381     gtk_widget_show( p_intf->p_sys->p_jump );
382     gdk_window_raise( p_intf->p_sys->p_jump->window );
383
384     return FALSE;
385 }
386
387
388 void GtkJumpOk( GtkButton       *button,
389                 gpointer         user_data)
390 {
391     intf_thread_t * p_intf = GtkGetIntf( button );
392     int i_hours, i_minutes, i_seconds;
393
394     if( p_intf->p_sys->p_input == NULL )
395     {
396         return;
397     }
398
399 #define GET_VALUE( name )                                                   \
400     gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( gtk_object_get_data( \
401         GTK_OBJECT( p_intf->p_sys->p_jump ), name ) ) )
402     i_hours   = GET_VALUE( "jump_hour_spinbutton" );
403     i_minutes = GET_VALUE( "jump_minute_spinbutton" );
404     i_seconds = GET_VALUE( "jump_second_spinbutton" );
405 #undef GET_VALUE
406
407     input_Seek( p_intf->p_sys->p_input,
408                 i_seconds + 60 * i_minutes + 3600 * i_hours,
409                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
410
411     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
412 }
413
414
415 void GtkJumpCancel( GtkButton       *button,
416                     gpointer         user_data)
417 {
418     gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) );
419 }
420
421 /****************************************************************************
422  * Callbacks for disc ejection
423  ****************************************************************************/
424 gboolean GtkDiscEject ( GtkWidget *widget, gpointer user_data )
425 {
426     char *psz_device = NULL;
427     char *psz_parser;
428     char *psz_current;
429
430     intf_thread_t *p_intf = GtkGetIntf( widget );
431     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
432                                                        FIND_ANYWHERE );
433     if( p_playlist == NULL )
434     {
435         return FALSE;
436     }
437
438     vlc_mutex_lock( &p_playlist->object_lock );
439
440     if( p_playlist->i_index < 0 )
441     {
442         vlc_mutex_unlock( &p_playlist->object_lock );
443         vlc_object_release( p_playlist );
444         return FALSE;
445     }
446
447     psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name;
448
449     /*
450      * Get the active input
451      * Determine whether we can eject a media, ie it's a VCD or DVD
452      * If it's neither a VCD nor a DVD, then return
453      */
454
455     /*
456      * Don't really know if I must lock the stuff here, we're using it read-only
457      */
458
459     if( psz_current != NULL )
460     {
461         if( !strncmp(psz_current, "dvd:", 4) )
462         {
463             switch( psz_current[4] )
464             {
465             case '\0':
466             case '@':
467                 psz_device = config_GetPsz( p_intf, "dvd" );
468                 break;
469             default:
470                 /* Omit the first 4 characters */
471                 psz_device = strdup( psz_current + 4 );
472                 break;
473             }
474         }
475         else if( !strncmp(psz_current, "vcd:", 4) )
476         {
477             switch( psz_current[4] )
478             {
479             case '\0':
480             case '@':
481                 psz_device = config_GetPsz( p_intf, "vcd" );
482                 break;
483             default:
484                 /* Omit the first 4 characters */
485                 psz_device = strdup( psz_current + 4 );
486                 break;
487             }
488         }
489         else
490         {
491             psz_device = strdup( psz_current );
492         }
493     }
494
495     vlc_mutex_unlock( &p_playlist->object_lock );
496     vlc_object_release( p_playlist );
497
498     if( psz_device == NULL )
499     {
500         return TRUE;
501     }
502
503     /* Remove what we have after @ */
504     psz_parser = psz_device;
505     for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
506     {
507         if( *psz_parser == '@' )
508         {
509             *psz_parser = '\0';
510             break;
511         }
512     }
513
514     /* If there's a stream playing, we aren't allowed to eject ! */
515     if( p_intf->p_sys->p_input == NULL )
516     {
517         msg_Dbg( p_intf, "ejecting %s", psz_device );
518
519         intf_Eject( p_intf, psz_device );
520     }
521
522     free(psz_device);
523
524     return TRUE;
525 }
526
527 /****************************************************************************
528  * Messages window
529  ****************************************************************************/
530
531 gboolean GtkMessagesShow( GtkWidget       *widget,
532                           gpointer         user_data)
533 {
534     static GdkColor black = { 0, 0x0000, 0x0000, 0x0000 };
535     static GdkColormap *colormap;
536     intf_thread_t *p_intf = GtkGetIntf( widget );
537
538     gtk_widget_show( p_intf->p_sys->p_messages );
539     colormap = gdk_colormap_get_system ();
540     gdk_color_alloc( colormap, &black );
541     gdk_window_set_background( p_intf->p_sys->p_messages_text->text_area,
542                                &black );
543
544     gdk_window_raise( p_intf->p_sys->p_messages->window );
545
546     gtk_text_set_point( p_intf->p_sys->p_messages_text,
547                     gtk_text_get_length( p_intf->p_sys->p_messages_text ) );
548
549     return TRUE;
550 }
551
552
553 void
554 GtkMessagesOk                          (GtkButton       *button,
555                                         gpointer         user_data)
556 {
557     intf_thread_t *p_intf = GtkGetIntf( button );
558     gtk_widget_hide( p_intf->p_sys->p_messages );
559 }
560
561
562 gboolean
563 GtkMessagesDelete                      (GtkWidget       *widget,
564                                         GdkEvent        *event,
565                                         gpointer         user_data)
566 {
567     intf_thread_t *p_intf = GtkGetIntf( widget );
568     gtk_widget_hide( p_intf->p_sys->p_messages );
569     return TRUE;
570 }
571
572
573 void
574 GtkOpenNotebookChanged                 (GtkNotebook     *notebook,
575                                         GtkNotebookPage *page,
576                                         gint             page_num,
577                                         gpointer         user_data)
578 {
579     GtkOpenChanged( GTK_WIDGET( notebook ), user_data );
580 }
581