1 /*****************************************************************************
2 * familiar.c : familiar plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: familiar.c,v 1.8.2.8 2002/10/13 20:20:46 jpsaman Exp $
7 * Authors: Jean-Paul Saman <jpsaman@wxs.nl>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <errno.h> /* ENOMEM */
29 #include <string.h> /* strerror() */
32 #include <videolan/vlc.h>
36 #include "stream_control.h"
37 #include "input_ext-intf.h"
39 #include "interface.h"
40 #include "intf_playlist.h"
43 #include "video_output.h"
45 #include "familiar_callbacks.h"
46 #include "familiar_interface.h"
47 #include "familiar_support.h"
50 /*****************************************************************************
52 *****************************************************************************/
53 static void intf_getfunctions ( function_list_t * p_function_list );
54 static int Open ( intf_thread_t *p_intf );
55 static void Close ( intf_thread_t *p_intf );
56 static void Run ( intf_thread_t * );
58 static gint GtkManage ( gpointer p_data );
59 void GtkAutoPlayFile( void );
61 /*****************************************************************************
63 *****************************************************************************/
64 #define AUTOPLAYFILE_TEXT N_("autoplay selected file")
65 #define AUTOPLAYFILE_LONGTEXT N_("automatically play a file when selected in the "\
66 "file selection list")
69 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
70 ADD_BOOL( "familiar-autoplayfile", 1, GtkAutoPlayFile, AUTOPLAYFILE_TEXT, AUTOPLAYFILE_LONGTEXT)
74 SET_DESCRIPTION( _("Familiar Linux Gtk+ interface module") )
76 if( getenv( "DISPLAY" ) == NULL )
78 ADD_CAPABILITY( INTF, 10 )
83 ADD_CAPABILITY( INTF, 70 )
88 intf_getfunctions( &p_module->p_functions->intf );
91 MODULE_DEACTIVATE_START
92 MODULE_DEACTIVATE_STOP
94 /*****************************************************************************
95 * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit
96 *****************************************************************************
97 * gtk_init() makes several calls to g_atexit() which calls atexit() to
98 * register tidying callbacks to be called at program exit. Since the Gtk+
99 * plugin is likely to be unloaded at program exit, we have to export this
100 * symbol to intercept the g_atexit() calls. Talk about crude hack.
101 *****************************************************************************/
102 void g_atexit( GVoidFunc func )
104 intf_thread_t *p_intf = p_main->p_intf;
108 i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
114 if( i_dummy >= MAX_ATEXIT - 1 )
116 intf_ErrMsg( "too many atexit() callbacks to register" );
120 p_intf->p_sys->pf_callback[i_dummy] = func;
121 p_intf->p_sys->pf_callback[i_dummy + 1] = NULL;
124 /*****************************************************************************
125 * Functions exported as capabilities. They are declared as static so that
126 * we don't pollute the namespace too much.
127 *****************************************************************************/
128 static void intf_getfunctions( function_list_t * p_function_list )
130 p_function_list->functions.intf.pf_open = Open;
131 p_function_list->functions.intf.pf_close = Close;
132 p_function_list->functions.intf.pf_run = Run;
135 /*****************************************************************************
136 * Open: initialize and create window
137 *****************************************************************************/
138 static int Open( intf_thread_t *p_intf )
140 /* Allocate instance and initialize some members */
141 p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
142 if( p_intf->p_sys == NULL )
144 intf_ErrMsg("error: %s", strerror(ENOMEM));
148 /* Initialize Gtk+ thread */
149 p_intf->p_sys->b_autoplayfile = 1;
150 p_intf->p_sys->pf_callback[0] = NULL;
152 p_intf->pf_run = Run;
157 /*****************************************************************************
158 * Close: destroy interface window
159 *****************************************************************************/
160 static void Close( intf_thread_t *p_intf )
162 /* Destroy structure */
163 free( p_intf->p_sys );
166 /*****************************************************************************
168 *****************************************************************************
169 * this part of the interface is in a separate thread so that we can call
170 * gtk_main() from within it without annoying the rest of the program.
171 *****************************************************************************/
172 static void Run( intf_thread_t *p_intf )
174 /* gtk_init needs to know the command line. We don't care, so we
175 * give it an empty one */
176 char *p_args[] = { "" };
177 char **pp_args = p_args;
181 /* Initialize Gtk+ */
184 /* gtk_init will register stuff with g_atexit, so we need to take
185 * the global lock if we want to be able to intercept the calls */
186 gtk_init( &i_args, &pp_args );
188 /* Create some useful widgets that will certainly be used */
190 add_pixmap_directory("share");
191 add_pixmap_directory("/usr/share/videolan");
193 p_intf->p_sys->p_window = create_familiar();
194 if (p_intf->p_sys->p_window == NULL)
196 intf_ErrMsg( "unable to create familiar interface" );
199 /* Set the title of the main window */
200 gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
201 VOUT_TITLE " (Familiar Linux interface)");
203 p_intf->p_sys->p_notebook = GTK_NOTEBOOK( gtk_object_get_data(
204 GTK_OBJECT( p_intf->p_sys->p_window ), "notebook" ) );
206 p_intf->p_sys->p_clist = GTK_CLIST( gtk_object_get_data(
207 GTK_OBJECT( p_intf->p_sys->p_window ), "clistmedia" ) );
208 gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 2, FALSE);
209 gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 3, FALSE);
210 gtk_clist_set_column_visibility (GTK_CLIST (p_intf->p_sys->p_clist), 4, FALSE);
211 gtk_clist_column_titles_show (GTK_CLIST (p_intf->p_sys->p_clist));
213 /* Store p_intf to keep an eye on it */
214 gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
216 /* Show the control window */
217 gtk_widget_show( p_intf->p_sys->p_window );
218 ReadDirectory(p_intf->p_sys->p_clist, ".");
220 /* Sleep to avoid using all CPU - since some interfaces needs to access
221 * keyboard events, a 100ms delay is a good compromise */
222 i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, GtkManage, p_intf );
227 /* Remove the timeout */
228 gtk_timeout_remove( i_dummy );
230 /* Launch stored callbacks */
232 i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
235 p_intf->p_sys->pf_callback[i_dummy]();
239 /* following functions are local */
241 /*****************************************************************************
242 * GtkManage: manage main thread messages
243 *****************************************************************************
244 * In this function, called approx. 10 times a second, we check what the
245 * main program wanted to tell us.
246 *****************************************************************************/
247 static gint GtkManage( gpointer p_data )
249 #define p_intf ((intf_thread_t *)p_data)
250 vlc_mutex_lock( &p_intf->change_lock );
252 /* Manage core vlc functions through the callback */
253 p_intf->pf_manage( p_intf );
257 vlc_mutex_unlock( &p_intf->change_lock );
259 /* Prepare to die, young Skywalker */
266 vlc_mutex_unlock( &p_intf->change_lock );
273 /*****************************************************************************
274 * GtkAutoplayFile: Autoplay file depending on configuration settings
275 *****************************************************************************
276 * FIXME: we should get the intf as parameter
277 *****************************************************************************/
278 void GtkAutoPlayFile( void )
280 GtkWidget *cbautoplay;
282 cbautoplay = GTK_WIDGET( gtk_object_get_data(
283 GTK_OBJECT( p_main->p_intf->p_sys->p_window ), "cbautoplay" ) );
284 if( !config_GetIntVariable( "familiar-autoplayfile" ) )
285 p_main->p_intf->p_sys->b_autoplayfile=0;
287 p_main->p_intf->p_sys->b_autoplayfile=1;
289 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(cbautoplay),p_main->p_intf->p_sys->b_autoplayfile);