]> git.sesse.net Git - vlc/blob - plugins/familiar/familiar.c
?
[vlc] / plugins / familiar / familiar.c
1 /*****************************************************************************
2  * familiar.c : familiar plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: familiar.c,v 1.8.2.9 2002/10/29 20:53:30 jpsaman Exp $
6  *
7  * Authors: Jean-Paul Saman <jpsaman@wxs.nl>
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 <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <videolan/vlc.h>
33
34 #include <gtk/gtk.h>
35
36 #ifdef HAVE_GPE_INIT_H
37 #include <gpe/init.h>
38 #endif 
39
40 #include "stream_control.h"
41 #include "input_ext-intf.h"
42
43 #include "interface.h"
44 #include "intf_playlist.h"
45
46 #include "video.h"
47 #include "video_output.h"
48
49 #include "familiar_callbacks.h"
50 #include "familiar_interface.h"
51 #include "familiar_support.h"
52 #include "familiar.h"
53
54 /*****************************************************************************
55  * Local prototypes.
56  *****************************************************************************/
57 static void intf_getfunctions ( function_list_t * p_function_list );
58 static int  Open         ( intf_thread_t *p_intf );
59 static void Close        ( intf_thread_t *p_intf );
60 static void Run          ( intf_thread_t * );
61
62 static gint GtkManage         ( gpointer p_data );
63 void GtkAutoPlayFile( void );
64
65 /*****************************************************************************
66  * Module descriptor
67  *****************************************************************************/
68 #define AUTOPLAYFILE_TEXT  N_("autoplay selected file")
69 #define AUTOPLAYFILE_LONGTEXT N_("automatically play a file when selected in the "\
70         "file selection list")
71
72 MODULE_CONFIG_START
73 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
74 ADD_BOOL( "familiar-autoplayfile", 1, GtkAutoPlayFile, AUTOPLAYFILE_TEXT, AUTOPLAYFILE_LONGTEXT)
75 MODULE_CONFIG_STOP
76
77 MODULE_INIT_START
78     SET_DESCRIPTION( _("Familiar Linux Gtk+ interface module") )
79 #ifndef WIN32
80     if( getenv( "DISPLAY" ) == NULL )
81     {
82         ADD_CAPABILITY( INTF, 10 )
83     }
84     else
85 #endif
86     {
87         ADD_CAPABILITY( INTF, 70 )
88     }
89 MODULE_INIT_STOP
90
91 MODULE_ACTIVATE_START
92     intf_getfunctions( &p_module->p_functions->intf );
93 MODULE_ACTIVATE_STOP
94
95 MODULE_DEACTIVATE_START
96 MODULE_DEACTIVATE_STOP
97
98 /*****************************************************************************
99  * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit
100  *****************************************************************************
101  * gtk_init() makes several calls to g_atexit() which calls atexit() to
102  * register tidying callbacks to be called at program exit. Since the Gtk+
103  * plugin is likely to be unloaded at program exit, we have to export this
104  * symbol to intercept the g_atexit() calls. Talk about crude hack.
105  *****************************************************************************/
106 void g_atexit( GVoidFunc func )
107 {
108     intf_thread_t *p_intf = p_main->p_intf;
109     int i_dummy;
110
111     for( i_dummy = 0;
112          i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
113          i_dummy++ )
114     {
115         ;
116     }
117
118     if( i_dummy >= MAX_ATEXIT - 1 )
119     {
120         intf_ErrMsg( "too many atexit() callbacks to register" );
121         return;
122     }
123
124     p_intf->p_sys->pf_callback[i_dummy]     = func;
125     p_intf->p_sys->pf_callback[i_dummy + 1] = NULL;
126 }
127
128 /*****************************************************************************
129  * Functions exported as capabilities. They are declared as static so that
130  * we don't pollute the namespace too much.
131  *****************************************************************************/
132 static void intf_getfunctions( function_list_t * p_function_list )
133 {
134     p_function_list->functions.intf.pf_open  = Open;
135     p_function_list->functions.intf.pf_close = Close;
136     p_function_list->functions.intf.pf_run   = Run;
137 }
138
139 /*****************************************************************************
140  * Open: initialize and create window
141  *****************************************************************************/
142 static int Open( intf_thread_t *p_intf )
143 {   
144     /* Allocate instance and initialize some members */
145     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
146     if( p_intf->p_sys == NULL )
147     {
148         intf_ErrMsg("error: %s", strerror(ENOMEM));
149         return (1);
150     }
151
152     /* Initialize Gtk+ thread */
153     p_intf->p_sys->b_autoplayfile = 1;
154     p_intf->p_sys->pf_callback[0] = NULL;
155
156     p_intf->pf_run = Run;
157
158     return (0);
159 }
160
161 /*****************************************************************************
162  * Close: destroy interface window
163  *****************************************************************************/
164 static void Close( intf_thread_t *p_intf )
165 {   
166     /* Destroy structure */
167     free( p_intf->p_sys );
168 }
169
170 /*****************************************************************************
171  * Run: Gtk+ thread
172  *****************************************************************************
173  * this part of the interface is in a separate thread so that we can call
174  * gtk_main() from within it without annoying the rest of the program.
175  *****************************************************************************/
176 static void Run( intf_thread_t *p_intf )
177 {
178     /* gtk_init needs to know the command line. We don't care, so we
179      * give it an empty one */
180     char  *p_args[] = { "" };
181     char **pp_args  = p_args;
182     int    i_args   = 1;
183     int    i_dummy  = 0;
184
185 #ifdef HAVE_GPE_INIT_H
186    /* Initialize GPE interface */
187    if (gpe_application_init(&i_args, &pp_args) == FALSE)
188         exit (1);       
189 #else
190    /* Initialize Gtk+ */
191    gtk_set_locale ();
192     
193    /* gtk_init will register stuff with g_atexit, so we need to take
194     * the global lock if we want to be able to intercept the calls */
195    gtk_init( &i_args, &pp_args );
196 #endif
197
198     /* Create some useful widgets that will certainly be used */
199 // FIXME: magic path
200     add_pixmap_directory("share");
201     add_pixmap_directory("/usr/share/videolan");
202
203     p_intf->p_sys->p_window = create_familiar();
204     if (p_intf->p_sys->p_window == NULL)
205     {
206         intf_ErrMsg( "unable to create familiar interface" );
207     }
208
209     /* Set the title of the main window */
210     gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
211                           VOUT_TITLE " (Familiar Linux interface)");
212
213     p_intf->p_sys->p_notebook = GTK_NOTEBOOK( gtk_object_get_data(
214         GTK_OBJECT( p_intf->p_sys->p_window ), "notebook" ) );
215
216     p_intf->p_sys->p_clist = GTK_CLIST( gtk_object_get_data(
217         GTK_OBJECT( p_intf->p_sys->p_window ), "clistmedia" ) );
218     gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 2, FALSE);
219     gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 3, FALSE);
220     gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 4, FALSE);
221     gtk_clist_column_titles_show (GTK_CLIST (p_intf->p_sys->p_clist));
222
223     /* Store p_intf to keep an eye on it */
224     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
225                          "p_intf", p_intf );
226     /* Show the control window */
227     gtk_widget_show( p_intf->p_sys->p_window );
228     ReadDirectory(p_intf->p_sys->p_clist, "/mnt"); 
229 //    OpenDirectory(p_intf->p_sys->p_clist, "/mnt");
230
231     /* Sleep to avoid using all CPU - since some interfaces needs to access
232      * keyboard events, a 100ms delay is a good compromise */
233     i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, GtkManage, p_intf );
234
235     /* Enter Gtk mode */
236     gtk_main();
237
238     /* Remove the timeout */
239     gtk_timeout_remove( i_dummy );
240
241     /* Launch stored callbacks */
242     for( i_dummy = 0;
243          i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
244          i_dummy++ )
245     {
246         p_intf->p_sys->pf_callback[i_dummy]();
247     }
248 }
249
250 /* following functions are local */
251
252 /*****************************************************************************
253  * GtkManage: manage main thread messages
254  *****************************************************************************
255  * In this function, called approx. 10 times a second, we check what the
256  * main program wanted to tell us.
257  *****************************************************************************/
258 static gint GtkManage( gpointer p_data )
259 {
260 #define p_intf ((intf_thread_t *)p_data)
261     vlc_mutex_lock( &p_intf->change_lock );
262
263     /* Manage core vlc functions through the callback */
264     p_intf->pf_manage( p_intf );
265
266     if( p_intf->b_die )
267     {
268         vlc_mutex_unlock( &p_intf->change_lock );
269
270         /* Prepare to die, young Skywalker */
271         gtk_main_quit();
272
273         /* Just in case */
274         return( FALSE );
275     }
276
277     vlc_mutex_unlock( &p_intf->change_lock );
278
279     return( TRUE );
280
281 #undef p_intf
282 }
283
284 /*****************************************************************************
285  * GtkAutoplayFile: Autoplay file depending on configuration settings
286  *****************************************************************************
287  * FIXME: we should get the intf as parameter
288  *****************************************************************************/
289 void GtkAutoPlayFile( void )
290 {
291     GtkWidget *cbautoplay;
292
293     cbautoplay = GTK_WIDGET( gtk_object_get_data(
294                    GTK_OBJECT( p_main->p_intf->p_sys->p_window ), "cbautoplay" ) );
295     if( !config_GetIntVariable( "familiar-autoplayfile" ) )
296        p_main->p_intf->p_sys->b_autoplayfile=0;
297     else
298        p_main->p_intf->p_sys->b_autoplayfile=1;
299
300     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(cbautoplay),p_main->p_intf->p_sys->b_autoplayfile);
301 }