Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

interface.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * interface.c: interface access for other threads
00003  * This library provides basic functions for threads to interact with user
00004  * interface, such as command line.
00005  *****************************************************************************
00006  * Copyright (C) 1998-2004 the VideoLAN team
00007  * $Id: interface.c 12065 2005-08-07 20:22:33Z zorglub $
00008  *
00009  * Authors: Vincent Seguin <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00032 /*****************************************************************************
00033  * Preamble
00034  *****************************************************************************/
00035 #include <stdlib.h>                                      /* free(), strtol() */
00036 #include <stdio.h>                                                   /* FILE */
00037 #include <string.h>                                            /* strerror() */
00038 
00039 #include <vlc/vlc.h>
00040 #include <vlc/input.h>
00041 
00042 #include "audio_output.h"
00043 
00044 #include "vlc_interface.h"
00045 #include "vlc_video.h"
00046 #include "video_output.h"
00047 
00048 #ifdef SYS_DARWIN
00049 #    include "Cocoa/Cocoa.h"
00050 #endif /* SYS_DARWIN */
00051 
00052 /*****************************************************************************
00053  * Local prototypes
00054  *****************************************************************************/
00055 static void Manager( intf_thread_t *p_intf );
00056 static void RunInterface( intf_thread_t *p_intf );
00057 
00058 static int SwitchIntfCallback( vlc_object_t *, char const *,
00059                                vlc_value_t , vlc_value_t , void * );
00060 static int AddIntfCallback( vlc_object_t *, char const *,
00061                             vlc_value_t , vlc_value_t , void * );
00062 
00063 #ifdef SYS_DARWIN
00064 /*****************************************************************************
00065  * VLCApplication interface
00066  *****************************************************************************/
00067 @interface VLCApplication : NSApplication
00068 {
00069 }
00070 
00071 @end
00072 #endif
00073 
00074 /*****************************************************************************
00075  * intf_Create: prepare interface before main loop
00076  *****************************************************************************
00077  * This function opens output devices and creates specific interfaces. It sends
00078  * its own error messages.
00079  *****************************************************************************/
00087 intf_thread_t* __intf_Create( vlc_object_t *p_this, const char *psz_module )
00088 {
00089     intf_thread_t * p_intf;
00090 
00091     /* Allocate structure */
00092     p_intf = vlc_object_create( p_this, VLC_OBJECT_INTF );
00093     if( !p_intf )
00094     {
00095         msg_Err( p_this, "out of memory" );
00096         return NULL;
00097     }
00098     p_intf->pf_request_window = NULL;
00099     p_intf->pf_release_window = NULL;
00100     p_intf->pf_control_window = NULL;
00101     p_intf->b_play = VLC_FALSE;
00102 
00103     /* Choose the best module */
00104     p_intf->p_module = module_Need( p_intf, "interface", psz_module, 0 );
00105 
00106     if( p_intf->p_module == NULL )
00107     {
00108         msg_Err( p_intf, "no suitable intf module" );
00109         vlc_object_destroy( p_intf );
00110         return NULL;
00111     }
00112 
00113     /* Initialize structure */
00114     p_intf->b_menu        = VLC_FALSE;
00115     p_intf->b_menu_change = VLC_FALSE;
00116 
00117     /* Initialize mutexes */
00118     vlc_mutex_init( p_intf, &p_intf->change_lock );
00119 
00120     msg_Dbg( p_intf, "interface initialized" );
00121 
00122     /* Attach interface to its parent object */
00123     vlc_object_attach( p_intf, p_this );
00124 
00125     return p_intf;
00126 }
00127 
00128 /*****************************************************************************
00129  * intf_RunThread: launch the interface thread
00130  *****************************************************************************
00131  * This function either creates a new thread and runs the interface in it,
00132  * or runs the interface in the current thread, depending on b_block.
00133  *****************************************************************************/
00142 int intf_RunThread( intf_thread_t *p_intf )
00143 {
00144 #ifdef SYS_DARWIN
00145     NSAutoreleasePool * o_pool;
00146 
00147     if( p_intf->b_block )
00148     {
00149         /* This is the primary intf */
00150         /* Run a manager thread, launch the interface, kill the manager */
00151         if( vlc_thread_create( p_intf, "manager", Manager,
00152                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
00153         {
00154             msg_Err( p_intf, "cannot spawn manager thread" );
00155             return VLC_EGENERIC;
00156         }
00157     }
00158 
00159     if( p_intf->b_block && strncmp( p_intf->p_module->psz_object_name,
00160                                     "clivlc", 6) )
00161     {
00162         o_pool = [[NSAutoreleasePool alloc] init];
00163         [VLCApplication sharedApplication];
00164     }
00165 
00166     if( p_intf->b_block &&
00167         ( !strncmp( p_intf->p_module->psz_object_name, "macosx" , 6 ) ||
00168           !strncmp( p_intf->p_vlc->psz_object_name, "clivlc", 6 ) ) )
00169     {
00170         /* VLC in normal primary interface mode */
00171         RunInterface( p_intf );
00172         p_intf->b_die = VLC_TRUE;
00173     }
00174     else
00175     {
00176         /* Run the interface in a separate thread */
00177         if( vlc_thread_create( p_intf, "interface", RunInterface,
00178                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
00179         {
00180             msg_Err( p_intf, "cannot spawn interface thread" );
00181             return VLC_EGENERIC;
00182         }
00183 
00184         if( p_intf->b_block )
00185         {
00186             /* VLC in primary interface mode with a working macosx vout */
00187             [NSApp run];
00188             p_intf->b_die = VLC_TRUE;
00189         }
00190     }
00191 #else
00192     if( p_intf->b_block )
00193     {
00194         /* Run a manager thread, launch the interface, kill the manager */
00195         if( vlc_thread_create( p_intf, "manager", Manager,
00196                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
00197         {
00198             msg_Err( p_intf, "cannot spawn manager thread" );
00199             return VLC_EGENERIC;
00200         }
00201 
00202         RunInterface( p_intf );
00203 
00204         p_intf->b_die = VLC_TRUE;
00205         /* Do not join the thread... intf_StopThread will do it for us */
00206     }
00207     else
00208     {
00209         /* Run the interface in a separate thread */
00210         if( vlc_thread_create( p_intf, "interface", RunInterface,
00211                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
00212         {
00213             msg_Err( p_intf, "cannot spawn interface thread" );
00214             return VLC_EGENERIC;
00215         }
00216     }
00217 #endif
00218 
00219     return VLC_SUCCESS;
00220 }
00221 
00229 void intf_StopThread( intf_thread_t *p_intf )
00230 {
00231     /* Tell the interface to die */
00232     if( !p_intf->b_block )
00233     {
00234         p_intf->b_die = VLC_TRUE;
00235     }
00236 
00237     /* Wait for the thread to exit */
00238     vlc_thread_join( p_intf );
00239 }
00240 
00248 void intf_Destroy( intf_thread_t *p_intf )
00249 {
00250     /* Unlock module if present (a switch may have failed) */
00251     if( p_intf->p_module )
00252     {
00253         module_Unneed( p_intf, p_intf->p_module );
00254     }
00255 
00256     vlc_mutex_destroy( &p_intf->change_lock );
00257 
00258     /* Free structure */
00259     vlc_object_destroy( p_intf );
00260 }
00261 
00262 
00263 /* Following functions are local */
00264 
00265 /*****************************************************************************
00266  * Manager: helper thread for blocking interfaces
00267  *****************************************************************************
00268  * If the interface is launched in the main thread, it will not listen to
00269  * p_vlc->b_die events because it is only supposed to listen to p_intf->b_die.
00270  * This thread takes care of the matter.
00271  *****************************************************************************/
00284 static void Manager( intf_thread_t *p_intf )
00285 {
00286     while( !p_intf->b_die )
00287     {
00288         msleep( INTF_IDLE_SLEEP );
00289 
00290         if( p_intf->p_vlc->b_die )
00291         {
00292             p_intf->b_die = VLC_TRUE;
00293 #ifdef SYS_DARWIN
00294     if( strncmp( p_intf->p_vlc->psz_object_name, "clivlc", 6 ) )
00295     {
00296         [NSApp stop: NULL];
00297     }
00298 #endif
00299             return;
00300         }
00301     }
00302 }
00303 
00304 /*****************************************************************************
00305  * RunInterface: setups necessary data and give control to the interface
00306  *****************************************************************************/
00307 static void RunInterface( intf_thread_t *p_intf )
00308 {
00309     static char *ppsz_interfaces[] =
00310     {
00311         "skins2", "Skins 2",
00312         "wxwidgets", "wxWidgets",
00313         NULL, NULL
00314     };
00315     char **ppsz_parser;
00316 
00317     vlc_list_t *p_list;
00318     int i;
00319     vlc_value_t val, text;
00320     char *psz_intf;
00321 
00322     /* Variable used for interface switching */
00323     p_intf->psz_switch_intf = NULL;
00324     var_Create( p_intf, "intf-switch", VLC_VAR_STRING |
00325                 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
00326     text.psz_string = _("Switch interface");
00327     var_Change( p_intf, "intf-switch", VLC_VAR_SETTEXT, &text, NULL );
00328 
00329     /* Only fill the list with available modules */
00330     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
00331     for( ppsz_parser = ppsz_interfaces; *ppsz_parser; ppsz_parser += 2 )
00332     {
00333         for( i = 0; i < p_list->i_count; i++ )
00334         {
00335             module_t *p_module = (module_t *)p_list->p_values[i].p_object;
00336             if( !strcmp( p_module->psz_object_name, ppsz_parser[0] ) )
00337             {
00338                 val.psz_string = ppsz_parser[0];
00339                 text.psz_string = ppsz_parser[1];
00340                 var_Change( p_intf, "intf-switch", VLC_VAR_ADDCHOICE,
00341                             &val, &text );
00342                 break;
00343             }
00344         }
00345     }
00346     vlc_list_release( p_list );
00347 
00348     var_AddCallback( p_intf, "intf-switch", SwitchIntfCallback, NULL );
00349 
00350     /* Variable used for interface spawning */
00351     var_Create( p_intf, "intf-add", VLC_VAR_STRING |
00352                 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
00353     text.psz_string = _("Add Interface");
00354     var_Change( p_intf, "intf-add", VLC_VAR_SETTEXT, &text, NULL );
00355 
00356     val.psz_string = "rc"; text.psz_string = "Console";
00357     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
00358     val.psz_string = "telnet"; text.psz_string = "Telnet Interface";
00359     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
00360     val.psz_string = "http"; text.psz_string = "Web Interface";
00361     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
00362     val.psz_string = "logger"; text.psz_string = "Debug logging";
00363     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
00364     val.psz_string = "gestures"; text.psz_string = "Mouse Gestures";
00365     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
00366 
00367     var_AddCallback( p_intf, "intf-add", AddIntfCallback, NULL );
00368 
00369     do
00370     {
00371         /* Give control to the interface */
00372         p_intf->pf_run( p_intf );
00373 
00374         /* Reset play on start status */
00375         p_intf->b_play = VLC_FALSE;
00376 
00377         if( !p_intf->psz_switch_intf )
00378         {
00379             break;
00380         }
00381 
00382         /* Make sure the old interface is completely uninitialized */
00383         module_Unneed( p_intf, p_intf->p_module );
00384 
00385         /* Provide ability to switch the main interface on the fly */
00386         psz_intf = p_intf->psz_switch_intf;
00387         p_intf->psz_switch_intf = NULL;
00388 
00389         vlc_mutex_lock( &p_intf->object_lock );
00390         p_intf->b_die = VLC_FALSE;
00391         p_intf->b_dead = VLC_FALSE;
00392         vlc_mutex_unlock( &p_intf->object_lock );
00393 
00394         p_intf->p_module = module_Need( p_intf, "interface", psz_intf, 0 );
00395         free( psz_intf );
00396     }
00397     while( p_intf->p_module );
00398 }
00399 
00400 static int SwitchIntfCallback( vlc_object_t *p_this, char const *psz_cmd,
00401                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00402 {
00403     intf_thread_t *p_intf = (intf_thread_t *)p_this;
00404 
00405     p_intf->psz_switch_intf =
00406         malloc( strlen(newval.psz_string) + sizeof(",none") );
00407     sprintf( p_intf->psz_switch_intf, "%s,none", newval.psz_string );
00408     p_intf->b_die = VLC_TRUE;
00409 
00410     return VLC_SUCCESS;
00411 }
00412 
00413 static int AddIntfCallback( vlc_object_t *p_this, char const *psz_cmd,
00414                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00415 {
00416     intf_thread_t *p_intf;
00417     char *psz_intf = malloc( strlen(newval.psz_string) + sizeof(",none") );
00418 
00419     /* Try to create the interface */
00420     sprintf( psz_intf, "%s,none", newval.psz_string );
00421     p_intf = intf_Create( p_this->p_vlc, psz_intf );
00422     free( psz_intf );
00423     if( p_intf == NULL )
00424     {
00425         msg_Err( p_this, "interface \"%s\" initialization failed",
00426                  newval.psz_string );
00427         return VLC_EGENERIC;
00428     }
00429 
00430     /* Try to run the interface */
00431     p_intf->b_block = VLC_FALSE;
00432     if( intf_RunThread( p_intf ) != VLC_SUCCESS )
00433     {
00434         vlc_object_detach( p_intf );
00435         intf_Destroy( p_intf );
00436         return VLC_EGENERIC;
00437     }
00438 
00439     return VLC_SUCCESS;
00440 }
00441 
00442 #ifdef SYS_DARWIN
00443 /*****************************************************************************
00444  * VLCApplication implementation 
00445  *****************************************************************************/
00446 @implementation VLCApplication 
00447 
00448 - (void)stop: (id)sender
00449 {
00450     NSEvent *o_event;
00451     NSAutoreleasePool *o_pool;
00452     [super stop:sender];
00453 
00454     o_pool = [[NSAutoreleasePool alloc] init];
00455     /* send a dummy event to break out of the event loop */
00456     o_event = [NSEvent mouseEventWithType: NSLeftMouseDown
00457                 location: NSMakePoint( 1, 1 ) modifierFlags: 0
00458                 timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber]
00459                 context: [NSGraphicsContext currentContext] eventNumber: 1
00460                 clickCount: 1 pressure: 0.0];
00461     [NSApp postEvent: o_event atStart: YES];
00462     [o_pool release];
00463 }
00464 
00465 - (void)terminate: (id)sender
00466 {
00467     if( [NSApp isRunning] )
00468         [NSApp stop:sender];
00469     [super terminate: sender];
00470 }
00471 
00472 @end
00473 #endif
00474 

Generated on Tue Dec 20 10:14:48 2005 for vlc-0.8.4a by  doxygen 1.4.2