]> git.sesse.net Git - vlc/blob - plugins/gnome/intf_gnome.c
First serie of changes in DVD module for the forthcoming interface menus
[vlc] / plugins / gnome / intf_gnome.c
1 /*****************************************************************************
2  * intf_gnome.c: Gnome interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: intf_gnome.c,v 1.14 2001/02/20 02:53:13 stef Exp $
6  *
7  * Authors:
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "defs.h"
28
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <stdlib.h>                                                /* free() */
31 #include <string.h>                                            /* strerror() */
32 #include <stdio.h>
33
34 #include <gnome.h>
35
36 #include "config.h"
37 #include "common.h"
38 #include "threads.h"
39 #include "mtime.h"
40 #include "tests.h"
41 #include "modules.h"
42
43 #include "stream_control.h"
44 #include "input_ext-intf.h"
45
46 #include "intf_msg.h"
47 #include "interface.h"
48
49 #include "gnome_sys.h"
50 #include "gnome_interface.h"
51 #include "gnome_support.h"
52
53 #include "main.h"
54
55 /*****************************************************************************
56  * Local prototypes.
57  *****************************************************************************/
58 static int  intf_Probe     ( probedata_t *p_data );
59 static int  intf_Open      ( intf_thread_t *p_intf );
60 static void intf_Close     ( intf_thread_t *p_intf );
61 static void intf_Run       ( intf_thread_t *p_intf );
62
63 static gint GnomeManage    ( gpointer p_data );
64
65 /*****************************************************************************
66  * g_atexit: kludge to avoid the Gnome thread to segfault at exit
67  *****************************************************************************
68  * gtk_init() makes several calls to g_atexit() which calls atexit() to
69  * register tidying callbacks to be called at program exit. Since the Gnome
70  * plugin is likely to be unloaded at program exit, we have to export this
71  * symbol to intercept the g_atexit() calls. Talk about crude hack.
72  *****************************************************************************/
73 void g_atexit( GVoidFunc func )
74 {
75     intf_thread_t *p_intf = p_main->p_intf;
76
77     if( p_intf->p_sys->pf_gdk_callback == NULL )
78     {
79         p_intf->p_sys->pf_gdk_callback = func;
80     }
81     else if( p_intf->p_sys->pf_gtk_callback == NULL )
82     {
83         p_intf->p_sys->pf_gtk_callback = func;
84     }
85     /* else nothing, but we could do something here */
86     return;
87 }
88
89 /*****************************************************************************
90  * Functions exported as capabilities. They are declared as static so that
91  * we don't pollute the namespace too much.
92  *****************************************************************************/
93 void intf_getfunctions( function_list_t * p_function_list )
94 {
95     p_function_list->pf_probe = intf_Probe;
96     p_function_list->functions.intf.pf_open  = intf_Open;
97     p_function_list->functions.intf.pf_close = intf_Close;
98     p_function_list->functions.intf.pf_run   = intf_Run;
99 }
100
101 /*****************************************************************************
102  * intf_Probe: probe the interface and return a score
103  *****************************************************************************
104  * This function tries to initialize Gnome and returns a score to the
105  * plugin manager so that it can select the best plugin.
106  *****************************************************************************/
107 static int intf_Probe( probedata_t *p_data )
108 {
109     if( TestMethod( INTF_METHOD_VAR, "gnome" ) )
110     {
111         return( 999 );
112     }
113
114     return( 100 );
115 }
116
117 /*****************************************************************************
118  * intf_Open: initialize and create window
119  *****************************************************************************/
120 static int intf_Open( intf_thread_t *p_intf )
121 {
122     /* Allocate instance and initialize some members */
123     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
124     if( p_intf->p_sys == NULL )
125     {
126         intf_ErrMsg("error: %s", strerror(ENOMEM));
127         return( 1 );
128     }
129
130     /* Initialize Gnome thread */
131     p_intf->p_sys->b_popup_changed = 0;
132     p_intf->p_sys->b_window_changed = 0;
133     p_intf->p_sys->b_playlist_changed = 0;
134
135     p_intf->p_sys->b_scale_isfree = 1;
136
137     p_intf->p_sys->pf_gtk_callback = NULL;
138     p_intf->p_sys->pf_gdk_callback = NULL;
139
140     return( 0 );
141 }
142
143 /*****************************************************************************
144  * intf_Close: destroy interface window
145  *****************************************************************************/
146 static void intf_Close( intf_thread_t *p_intf )
147 {
148     /* Destroy structure */
149     free( p_intf->p_sys );
150 }
151
152 /*****************************************************************************
153  * intf_Run: Gnome thread
154  *****************************************************************************
155  * this part of the interface is in a separate thread so that we can call
156  * gtk_main() from within it without annoying the rest of the program.
157  * XXX: the approach may look kludgy, and probably is, but I could not find
158  * a better way to dynamically load a Gnome interface at runtime.
159  *****************************************************************************/
160 static void intf_Run( intf_thread_t *p_intf )
161 {
162     /* gnome_init needs to know the command line. We don't care, so we
163      * give it an empty one */
164     char *p_args[] = { };
165
166     /* The data types we are allowed to receive */
167     static GtkTargetEntry target_table[] =
168     {
169         { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST },
170         { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN }
171     };
172
173     /* Initialize Gnome */
174     gnome_init( p_main->psz_arg0, VERSION, 1, p_args );
175
176     /* create some useful widgets that will certainly be used */
177     p_intf->p_sys->p_window = create_intf_window( );
178     p_intf->p_sys->p_popup = create_intf_popup( );
179
180     /* accept file drops on the main window */
181     gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ),
182                        GTK_DEST_DEFAULT_ALL, target_table,
183                        1, GDK_ACTION_COPY );
184
185     /* we don't create these ones yet because we perhaps won't need them */
186     p_intf->p_sys->p_about = NULL;
187     p_intf->p_sys->p_playlist = NULL;
188     p_intf->p_sys->p_modules = NULL;
189     p_intf->p_sys->p_fileopen = NULL;
190
191     /* store p_sys to keep an eye on it */
192     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
193                          "p_intf", p_intf );
194
195     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup),
196                          "p_intf", p_intf );
197
198     /* show the control window */
199     gtk_widget_show( p_intf->p_sys->p_window );
200
201     /* Sleep to avoid using all CPU - since some interfaces needs to access
202      * keyboard events, a 100ms delay is a good compromise */
203     p_intf->p_sys->i_timeout = gtk_timeout_add( INTF_IDLE_SLEEP / 1000,
204                                                 GnomeManage, p_intf );
205  
206
207     /* enter gnome mode */
208     gtk_main();
209
210     /* launch stored callbacks */
211     if( p_intf->p_sys->pf_gtk_callback != NULL )
212     {
213         p_intf->p_sys->pf_gtk_callback();
214
215         if( p_intf->p_sys->pf_gdk_callback != NULL )
216         {
217             p_intf->p_sys->pf_gdk_callback();
218         }
219     }
220 }
221
222 /* following functions are local */
223
224 /*****************************************************************************
225  * GnomeManage: manage main thread messages
226  *****************************************************************************
227  * In this function, called approx. 10 times a second, we check what the
228  * main program wanted to tell us.
229  *****************************************************************************/
230 static gint GnomeManage( gpointer p_data )
231 {
232     intf_thread_t *p_intf = (void *)p_data;
233
234     vlc_mutex_lock( &p_intf->p_sys->change_lock );
235
236     /* If the "display popup" flag has changed */
237     if( p_intf->b_menu_change )
238     {
239         gnome_popup_menu_do_popup( p_intf->p_sys->p_popup,
240                                    NULL, NULL, NULL, NULL );
241         p_intf->b_menu_change = 0;
242     }
243
244     /* Manage the slider */
245     if( p_intf->p_input != NULL && p_intf->p_sys->p_window != NULL
246          && p_intf->p_sys->b_scale_isfree )
247     {
248         GtkWidget *p_scale;
249         GtkAdjustment *p_adj;
250    
251         p_scale = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
252                                   p_intf->p_sys->p_window ), "hscale" ) );
253         p_adj = gtk_range_get_adjustment ( GTK_RANGE( p_scale ) );
254
255         /* Update the value */
256         p_adj->value = ( 100. * p_intf->p_input->stream.pp_areas[0]->i_tell )
257                            / p_intf->p_input->stream.pp_areas[0]->i_size;
258
259         /* Gtv does it this way. Why not. */
260         gtk_range_set_adjustment ( GTK_RANGE( p_scale ), p_adj );
261         gtk_range_slider_update ( GTK_RANGE( p_scale ) );
262         gtk_range_clear_background ( GTK_RANGE( p_scale ) );
263         gtk_range_draw_background ( GTK_RANGE( p_scale ) );
264     }
265
266     /* Manage core vlc functions through the callback */
267     p_intf->pf_manage( p_intf );
268
269     if( p_intf->b_die )
270     {
271         /* Make sure we won't be called again */
272         gtk_timeout_remove( p_intf->p_sys->i_timeout );
273
274         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
275
276         /* Prepare to die, young Skywalker */
277         gtk_main_quit();
278         return( FALSE );
279     }
280
281     vlc_mutex_unlock( &p_intf->p_sys->change_lock );
282
283     return( TRUE );
284 }
285