>From dd49eb83f985c9318072f3b627a2ff4ee9aeb78c Mon Sep 17 00:00:00 2001 From: KO Myung-Hun Date: Sun, 11 Nov 2012 15:04:13 +0900 Subject: [PATCH] os2: implement one-instance feature --- src/libvlc-module.c | 6 +- src/libvlc.c | 2 +- src/libvlc.h | 4 +- src/os2/specific.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 242 insertions(+), 6 deletions(-) diff --git a/src/libvlc-module.c b/src/libvlc-module.c index 7dd880b..cb92202 100644 --- a/src/libvlc-module.c +++ b/src/libvlc-module.c @@ -1078,12 +1078,12 @@ static const char *const ppsz_prefres[] = { "Log all VLC messages to syslog (UNIX systems)." ) #define ONEINSTANCE_TEXT N_("Allow only one running instance") -#if defined( WIN32 ) +#if defined( WIN32 ) || defined( __OS2__ ) #define ONEINSTANCE_LONGTEXT N_( \ "Allowing only one running instance of VLC can sometimes be useful, " \ "for example if you associated VLC with some media types and you " \ "don't want a new instance of VLC to be opened each time you " \ - "double-click on a file in the explorer. This option will allow you " \ + "open a file in your file manager. This option will allow you " \ "to play the file with the already running instance or enqueue it.") #elif defined( HAVE_DBUS ) #define ONEINSTANCE_LONGTEXT N_( \ @@ -2044,7 +2044,7 @@ vlc_module_begin () add_bool( "playlist-autostart", true, AUTOSTART_TEXT, AUTOSTART_LONGTEXT, false ) add_bool( "playlist-cork", true, CORK_TEXT, CORK_LONGTEXT, false ) -#if defined(WIN32) || defined(HAVE_DBUS) +#if defined(WIN32) || defined(HAVE_DBUS) || defined(__OS2__) add_bool( "one-instance", 0, ONEINSTANCE_TEXT, ONEINSTANCE_LONGTEXT, true ) add_bool( "started-from-file", 0, STARTEDFROMFILE_TEXT, diff --git a/src/libvlc.c b/src/libvlc.c index 65e27fe..7dd511b 100644 --- a/src/libvlc.c +++ b/src/libvlc.c @@ -662,7 +662,7 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc ) module_EndBank (true); vlc_DeinitActions( p_libvlc, priv->actions ); -#ifdef WIN32 +#if defined(WIN32) || defined(__OS2__) system_End( ); #endif } diff --git a/src/libvlc.h b/src/libvlc.h index 5d557c8..4392f48 100644 --- a/src/libvlc.h +++ b/src/libvlc.h @@ -41,10 +41,12 @@ size_t vlc_towc (const char *str, uint32_t *restrict pwc); */ void system_Init ( void ); void system_Configure ( libvlc_int_t *, int, const char *const [] ); -#ifdef WIN32 +#if defined(WIN32) || defined(__OS2__) void system_End(void); +#ifndef __OS2__ size_t EnumClockSource( vlc_object_t *, const char *, char ***, char *** ); #endif +#endif void vlc_CPU_init(void); void vlc_CPU_dump(vlc_object_t *); diff --git a/src/os2/specific.c b/src/os2/specific.c index 9cc2e09..c76f52e 100644 --- a/src/os2/specific.c +++ b/src/os2/specific.c @@ -24,12 +24,99 @@ #include #include "../libvlc.h" +#include +#include #include #include +#define VLC_IPC_PIPE "\\PIPE\\VLC\\IPC\\"VERSION + +#define IPC_CMD_GO 0x00 +#define IPC_CMD_ENQUEUE 0x01 +#define IPC_CMD_QUIT 0xFF + extern int _fmode_bin; +static HPIPE hpipeIPC = NULLHANDLE; +static int tidIPCFirst = -1; +static int tidIPCHelper = -1; + +static void IPCHelperThread( void *arg ) +{ + vlc_object_t *p_this = arg; + + ULONG ulCmd; + int i_argc; + char **ppsz_argv; + size_t i_len; + ULONG cbActual; + int i_options; + + /* Add files to the playlist */ + playlist_t *p_playlist = pl_Get( p_this ); + + do + { + DosConnectNPipe( hpipeIPC ); + + /* Read command */ + DosRead( hpipeIPC, &ulCmd, sizeof( ulCmd ), &cbActual ); + if( ulCmd == IPC_CMD_QUIT ) + continue; + + /* Read a count of arguments */ + DosRead( hpipeIPC, &i_argc, sizeof( i_argc ), &cbActual ); + + ppsz_argv = malloc( i_argc * sizeof( *ppsz_argv )); + + for( int i_opt = 0; i_opt < i_argc; i_opt++ ) + { + /* Read a length of argv */ + DosRead( hpipeIPC, &i_len, sizeof( i_len ), &cbActual ); + + ppsz_argv[ i_opt ] = malloc( i_len ); + + /* Read argv */ + DosRead( hpipeIPC, ppsz_argv[ i_opt ], i_len, &cbActual ); + } + + for( int i_opt = 0; i_opt < i_argc;) + { + i_options = 0; + + /* Count the input options */ + while( i_opt + i_options + 1 < i_argc && + *ppsz_argv[ i_opt + i_options + 1 ] == ':' ) + i_options++; + + playlist_AddExt( p_playlist, ppsz_argv[ i_opt ], NULL, + PLAYLIST_APPEND | + (( i_opt || ulCmd == IPC_CMD_ENQUEUE ) ? + 0 : PLAYLIST_GO ), + PLAYLIST_END, -1, i_options, + ( char const ** ) + ( i_options ? &ppsz_argv[ i_opt + 1 ] : + NULL ), + VLC_INPUT_OPTION_TRUSTED, + true, pl_Unlocked ); + + for( ; i_options >= 0; i_options-- ) + free( ppsz_argv[ i_opt++ ]); + } + + free( ppsz_argv ); + } while( !DosDisConnectNPipe( hpipeIPC ) && ulCmd != IPC_CMD_QUIT ); + + vlc_object_release( p_this ); + + DosClose( hpipeIPC ); + hpipeIPC = NULLHANDLE; + + tidIPCFirst = -1; + tidIPCHelper = -1; +} + void system_Init( void ) { /* Set the default file-translation mode */ @@ -39,7 +126,6 @@ void system_Init( void ) void system_Configure( libvlc_int_t *p_this, int i_argc, const char *const ppsz_argv[] ) { - VLC_UNUSED( i_argc ); VLC_UNUSED( ppsz_argv ); if( var_InheritBool( p_this, "high-priority" ) ) { if( !DosSetPriority( PRTYS_PROCESS, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 ) ) @@ -51,4 +137,152 @@ void system_Configure( libvlc_int_t *p_this, int i_argc, const char *const ppsz_ msg_Dbg( p_this, "could not raise process priority" ); } } + + if( var_InheritBool( p_this, "one-instance" ) + || ( var_InheritBool( p_this, "one-instance-when-started-from-file" ) + && var_InheritBool( p_this, "started-from-file" ) ) ) + { + HPIPE hpipe; + ULONG ulAction; + ULONG rc; + + msg_Info( p_this, "one instance mode ENABLED"); + + /* Use a named pipe to check if another instance is already running */ + for(;;) + { + rc = DosOpen( VLC_IPC_PIPE, &hpipe, &ulAction, 0, 0, + OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | + OPEN_FLAGS_FAIL_ON_ERROR, + NULL ); + + if( rc == ERROR_PIPE_BUSY ) + DosWaitNPipe( VLC_IPC_PIPE, -1 ); + else + break; + } + + if( rc ) + { + rc = DosCreateNPipe( VLC_IPC_PIPE, &hpipeIPC, + NP_ACCESS_DUPLEX, + NP_WAIT | NP_TYPE_MESSAGE | + NP_READMODE_MESSAGE | 0x01, + 32768, 32768, 0 ); + if( rc ) + { + /* Failed to create a named pipe. Just ignore the option and + * go on as normal. */ + msg_Err( p_this, "one instance mode DISABLED " + "(a named pipe couldn't be created)" ); + return; + } + + /* We are the 1st instance. */ + vlc_object_t* p_helper = vlc_custom_create( p_this, + sizeof( *p_helper ), + "ipc helper" ); + + /* Save the tid of the first instance */ + tidIPCFirst = _gettid(); + + /* Run the helper thread */ + tidIPCHelper = _beginthread( IPCHelperThread, NULL, 1024 * 1024, + p_helper ); + if( tidIPCHelper == -1 ) + { + msg_Err( p_this, "one instance mode DISABLED " + "(IPC helper thread couldn't be created)"); + vlc_object_release( p_helper ); + + tidIPCFirst = -1; + } + } + else + { + /* Another instance is running */ + ULONG ulCmd = var_InheritBool( p_this, "playlist-enqueue") ? + IPC_CMD_ENQUEUE : IPC_CMD_GO; + ULONG cbActual; + + /* Write a command */ + DosWrite( hpipe, &ulCmd, sizeof( ulCmd ), &cbActual ); + + /* We assume that the remaining parameters are filenames + * and their input options */ + + /* Write a count of arguments */ + DosWrite( hpipe, &i_argc, sizeof( i_argc ), &cbActual ); + + for( int i_opt = 0; i_opt < i_argc; i_opt++ ) + { + /* We need to resolve relative paths in this instance */ + char *mrl; + if( strstr( ppsz_argv[ i_opt ], "://" )) + mrl = strdup( ppsz_argv[ i_opt ] ); + else + mrl = vlc_path2uri( ppsz_argv[ i_opt ], NULL ); + + if( !mrl ) + mrl = ( char * )ppsz_argv[ i_opt ]; + + size_t i_len = strlen( mrl ) + 1; + + /* Write a length of an argument */ + DosWrite( hpipe, &i_len, sizeof( i_len ), &cbActual ); + + /* Write an argument */ + DosWrite( hpipe, mrl, i_len, &cbActual ); + + if( mrl != ppsz_argv[ i_opt ]) + free( mrl ); + } + + /* Close a named pipe of a client side */ + DosClose( hpipe ); + + /* Bye bye */ + system_End(); + exit( 0 ); + } + } } + +/** + * Cleans up after system_Init() and system_Configure(). + */ +void system_End(void) +{ + if( tidIPCFirst == _gettid()) + { + HPIPE hpipe; + ULONG ulAction; + ULONG cbActual; + ULONG rc; + + do + { + rc = DosOpen( VLC_IPC_PIPE, &hpipe, &ulAction, 0, 0, + OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | + OPEN_FLAGS_FAIL_ON_ERROR, + NULL ); + + if( rc == ERROR_PIPE_BUSY ) + DosWaitNPipe( VLC_IPC_PIPE, -1 ); + else if( rc ) + DosSleep( 1 ); + } while( rc ); + + /* Ask for IPCHelper to quit */ + ULONG ulCmd = IPC_CMD_QUIT; + DosWrite( hpipe, &ulCmd, sizeof( ulCmd ), &cbActual ); + + DosClose( hpipe ); + + TID tid = tidIPCHelper; + DosWaitThread( &tid, DCWW_WAIT ); + } +} + -- 1.7.3.2