]> git.sesse.net Git - vlc/blob - plugins/familiar/familiar.c
6db4bd59f31a627200f4ce8205bba32dcac4200e
[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.6 2002/07/24 20:46:08 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 <vlc/vlc.h>
33 #include <vlc/intf.h>
34
35 #include <gtk/gtk.h>
36
37 #include "familiar_callbacks.h"
38 #include "familiar_interface.h"
39 #include "familiar_support.h"
40 #include "familiar.h"
41
42 /*****************************************************************************
43  * Local variables (mutex-protected).
44  *****************************************************************************/
45 static void ** pp_global_data = NULL;
46
47 /*****************************************************************************
48  * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit
49  *****************************************************************************
50  * gtk_init() makes several calls to g_atexit() which calls atexit() to
51  * register tidying callbacks to be called at program exit. Since the Gtk+
52  * plugin is likely to be unloaded at program exit, we have to export this
53  * symbol to intercept the g_atexit() calls. Talk about crude hack.
54  *****************************************************************************/
55 void g_atexit( GVoidFunc func )
56 {
57     intf_thread_t *p_intf;
58
59     int i_dummy;
60
61     if( pp_global_data == NULL )
62     {
63         atexit( func );
64         return;
65     }
66
67     p_intf = (intf_thread_t *)*pp_global_data;
68     if( p_intf == NULL )
69     {
70         return;
71     }
72
73     for( i_dummy = 0;
74          i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL;
75          i_dummy++ )
76     {
77         ;
78     }
79
80     if( i_dummy >= MAX_ATEXIT - 1 )
81     {
82         msg_Err( p_intf, "too many atexit() callbacks to register" );
83         return;
84     }
85
86     p_intf->p_sys->pf_callback[i_dummy]     = func;
87     p_intf->p_sys->pf_callback[i_dummy + 1] = NULL;
88 }
89
90 /*****************************************************************************
91  * Local prototypes.
92  *****************************************************************************/
93 static void intf_getfunctions ( function_list_t * p_function_list );
94 static int  intf_Open         ( intf_thread_t *p_intf );
95 static void intf_Close        ( intf_thread_t *p_intf );
96 static void intf_Run          ( intf_thread_t *p_intf );
97
98 /*****************************************************************************
99  * Building configuration tree
100  *****************************************************************************/
101 MODULE_CONFIG_START
102    ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
103 MODULE_CONFIG_STOP
104
105 MODULE_INIT_START
106     SET_DESCRIPTION( _("Familiar Linux Gtk+ interface module") )
107     ADD_CAPABILITY( INTF, 70 )
108 MODULE_INIT_STOP
109
110 MODULE_ACTIVATE_START
111     _M( intf_getfunctions )( &p_module->p_functions->intf );
112 MODULE_ACTIVATE_STOP
113
114 MODULE_DEACTIVATE_START
115 MODULE_DEACTIVATE_STOP
116
117
118 /*****************************************************************************
119  * Functions exported as capabilities. They are declared as static so that
120  * we don't pollute the namespace too much.
121  *****************************************************************************/
122 static void intf_getfunctions( function_list_t * p_function_list )
123 {
124     p_function_list->functions.intf.pf_open  = intf_Open;
125     p_function_list->functions.intf.pf_close = intf_Close;
126     p_function_list->functions.intf.pf_run   = intf_Run;
127 }
128
129 /*****************************************************************************
130  * intf_Open: initialize and create window
131  *****************************************************************************/
132 static int intf_Open( intf_thread_t *p_intf )
133 {
134     /* Allocate instance and initialize some members */
135     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
136     if( p_intf->p_sys == NULL )
137     {
138         msg_Err( p_intf, "out of memory" );
139         return( 1 );
140     }
141
142     /* Initialize Gtk+ thread */
143     p_intf->p_sys->p_input = NULL;
144
145     return( 0 );
146 }
147
148 /*****************************************************************************
149  * intf_Close: destroy interface window
150  *****************************************************************************/
151 static void intf_Close( intf_thread_t *p_intf )
152 {
153     if( p_intf->p_sys->p_input )
154     {
155         vlc_object_release( p_intf->p_sys->p_input );
156     }
157
158     /* Destroy structure */
159     if (p_intf->p_sys) free( p_intf->p_sys );
160 }
161
162 /*****************************************************************************
163  * intf_Run: Gtk+ thread
164  *****************************************************************************
165  * this part of the interface is in a separate thread so that we can call
166  * gtk_main() from within it without annoying the rest of the program.
167  * XXX: the approach may look kludgy, and probably is, but I could not find
168  * a better way to dynamically load a Gtk+ interface at runtime.
169  *****************************************************************************/
170 static void intf_Run( intf_thread_t *p_intf )
171 {
172     /* gtk_init needs to know the command line. We don't care, so we
173      * give it an empty one */
174     char  *p_args[] = { "" };
175     char **pp_args  = p_args;
176     int    i_args   = 1;
177     int    i_dummy  = 0;
178
179     /* Initialize Gtk+ */
180     gtk_set_locale ();
181
182     /* gtk_init will register stuff with g_atexit, so we need to take
183      * the global lock if we want to be able to intercept the calls */
184     vlc_mutex_lock( p_intf->p_vlc->p_global_lock );
185     *p_intf->p_vlc->pp_global_data = p_intf;
186     gtk_init( &i_args, &pp_args );
187     vlc_mutex_unlock( p_intf->p_vlc->p_global_lock );
188
189     /* Create some useful widgets that will certainly be used */
190 // FIXME: magic path
191     add_pixmap_directory("share");
192     p_intf->p_sys->p_window = create_familiar();
193     if (p_intf->p_sys->p_window == NULL)
194     {
195         msg_Err( p_intf, "unable to create familiar interface" );
196     }
197
198     /* Set the title of the main window */
199     gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window),
200                           VOUT_TITLE " (Familiar Linux interface)");
201
202     /* Get the slider object */
203     p_intf->p_sys->p_notebook = GTK_NOTEBOOK( gtk_object_get_data(
204         GTK_OBJECT( p_intf->p_sys->p_window ), "notebook" ) );
205 //    gtk_widget_hide( GTK_WIDGET(p_intf->p_sys->p_notebook) );
206
207     /* Store p_intf to keep an eye on it */
208     gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window),
209                          "p_intf", p_intf );
210     /* Show the control window */
211     gtk_widget_show( p_intf->p_sys->p_window );
212
213     /* Enter Gtk mode */
214     gtk_main();
215
216     /* Remove the timeout */
217     gtk_timeout_remove( i_dummy );
218 }
219