]> git.sesse.net Git - vlc/blob - src/os2/specific.c
macosx: Update progress dialog on the main thread, make check thread safe
[vlc] / src / os2 / specific.c
1 /*****************************************************************************
2  * specific.c: OS/2 specific features
3  *****************************************************************************
4  * Copyright (C) 2010 KO Myung-Hun
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <vlc_common.h>
26 #include "../libvlc.h"
27 #include <vlc_playlist.h>
28 #include <vlc_input.h>
29 #include <vlc_interface.h>
30 #include <vlc_url.h>
31
32 #include <fcntl.h>
33 #include <io.h>
34
35 #define VLC_IPC_PIPE "\\PIPE\\VLC\\IPC\\"VERSION
36
37 #define IPC_CMD_GO      0x00
38 #define IPC_CMD_ENQUEUE 0x01
39 #define IPC_CMD_QUIT    0xFF
40
41 extern int _fmode_bin;
42
43 static HPIPE hpipeIPC     = NULLHANDLE;
44 static int   tidIPCFirst  = -1;
45 static int   tidIPCHelper = -1;
46
47 static void IPCHelperThread( void *arg )
48 {
49     libvlc_int_t *libvlc = arg;
50
51     ULONG  ulCmd;
52     int    i_argc;
53     char **ppsz_argv;
54     size_t i_len;
55     ULONG  cbActual;
56     int    i_options;
57
58     /* Add files to the playlist */
59     playlist_t *p_playlist;
60
61     do
62     {
63         DosConnectNPipe( hpipeIPC );
64
65         /* Read command */
66         DosRead( hpipeIPC, &ulCmd, sizeof( ulCmd ), &cbActual );
67         if( ulCmd == IPC_CMD_QUIT )
68             continue;
69
70         /* Read a count of arguments */
71         DosRead( hpipeIPC, &i_argc, sizeof( i_argc ), &cbActual );
72
73         ppsz_argv = malloc( i_argc * sizeof( *ppsz_argv ));
74
75         for( int i_opt = 0; i_opt < i_argc; i_opt++ )
76         {
77             /* Read a length of argv */
78             DosRead( hpipeIPC, &i_len, sizeof( i_len ), &cbActual );
79
80             ppsz_argv[ i_opt ] = malloc( i_len );
81
82             /* Read argv */
83             DosRead( hpipeIPC, ppsz_argv[ i_opt ], i_len, &cbActual );
84         }
85
86         p_playlist = libvlc_priv(libvlc)->playlist;
87
88         for( int i_opt = 0; i_opt < i_argc;)
89         {
90             i_options = 0;
91
92             /* Count the input options */
93             while( i_opt + i_options + 1 < i_argc &&
94                    *ppsz_argv[ i_opt + i_options + 1 ] == ':' )
95                 i_options++;
96
97
98             if( p_playlist )
99             {
100                 playlist_AddExt( p_playlist, ppsz_argv[ i_opt ], NULL,
101                                  PLAYLIST_APPEND |
102                                  (( i_opt || ulCmd == IPC_CMD_ENQUEUE ) ?
103                                      0 : PLAYLIST_GO ),
104                                  PLAYLIST_END, -1, i_options,
105                                  ( char const ** )
106                                      ( i_options ? &ppsz_argv[ i_opt + 1 ] :
107                                                    NULL ),
108                                  VLC_INPUT_OPTION_TRUSTED,
109                                  true, pl_Unlocked );
110             }
111
112             for( ; i_options >= 0; i_options-- )
113                 free( ppsz_argv[ i_opt++ ]);
114         }
115
116         free( ppsz_argv );
117     } while( !DosDisConnectNPipe( hpipeIPC ) && ulCmd != IPC_CMD_QUIT );
118
119     DosClose( hpipeIPC );
120     hpipeIPC = NULLHANDLE;
121
122     tidIPCFirst  = -1;
123     tidIPCHelper = -1;
124 }
125
126 void system_Init( void )
127 {
128     /* Set the default file-translation mode */
129     _fmode_bin = 1;
130     setmode( fileno( stdin ), O_BINARY ); /* Needed for pipes */
131 }
132
133 void system_Configure( libvlc_int_t *p_this, int i_argc, const char *const ppsz_argv[] )
134 {
135     if( var_InheritBool( p_this, "high-priority" ) )
136     {
137         if( !DosSetPriority( PRTYS_PROCESS, PRTYC_REGULAR, PRTYD_MAXIMUM, 0 ) )
138         {
139             msg_Dbg( p_this, "raised process priority" );
140         }
141         else
142         {
143             msg_Dbg( p_this, "could not raise process priority" );
144         }
145     }
146
147     if( var_InheritBool( p_this, "one-instance" )
148         || ( var_InheritBool( p_this, "one-instance-when-started-from-file" )
149              && var_InheritBool( p_this, "started-from-file" ) ) )
150     {
151         HPIPE hpipe;
152         ULONG ulAction;
153         ULONG rc;
154
155         msg_Info( p_this, "one instance mode ENABLED");
156
157         /* Use a named pipe to check if another instance is already running */
158         for(;;)
159         {
160             rc = DosOpen( VLC_IPC_PIPE, &hpipe, &ulAction, 0, 0,
161                           OPEN_ACTION_OPEN_IF_EXISTS,
162                           OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE |
163                           OPEN_FLAGS_FAIL_ON_ERROR,
164                           NULL );
165
166             if( rc == ERROR_PIPE_BUSY )
167                 DosWaitNPipe( VLC_IPC_PIPE, -1 );
168             else
169                 break;
170         }
171
172         if( rc )
173         {
174             rc = DosCreateNPipe( VLC_IPC_PIPE,  &hpipeIPC,
175                                  NP_ACCESS_DUPLEX,
176                                  NP_WAIT | NP_TYPE_MESSAGE |
177                                  NP_READMODE_MESSAGE | 0x01,
178                                  32768, 32768, 0 );
179             if( rc )
180             {
181                 /* Failed to create a named pipe. Just ignore the option and
182                  * go on as normal. */
183                 msg_Err( p_this, "one instance mode DISABLED "
184                          "(a named pipe couldn't be created)" );
185                 return;
186             }
187
188             /* We are the 1st instance. */
189
190             /* Save the tid of the first instance */
191             tidIPCFirst = _gettid();
192
193             /* Run the helper thread */
194             tidIPCHelper = _beginthread( IPCHelperThread, NULL, 1024 * 1024,
195                                          p_this );
196             if( tidIPCHelper == -1 )
197             {
198                 msg_Err( p_this, "one instance mode DISABLED "
199                          "(IPC helper thread couldn't be created)");
200
201                 tidIPCFirst = -1;
202             }
203         }
204         else
205         {
206             /* Another instance is running */
207             ULONG ulCmd = var_InheritBool( p_this, "playlist-enqueue") ?
208                               IPC_CMD_ENQUEUE : IPC_CMD_GO;
209             ULONG cbActual;
210
211             /* Write a command */
212             DosWrite( hpipe, &ulCmd, sizeof( ulCmd ), &cbActual );
213
214             /* We assume that the remaining parameters are filenames
215              * and their input options */
216
217             /* Write a count of arguments */
218             DosWrite( hpipe, &i_argc, sizeof( i_argc ), &cbActual );
219
220             for( int i_opt = 0; i_opt < i_argc; i_opt++ )
221             {
222                 /* We need to resolve relative paths in this instance */
223                 char *mrl;
224                 if( strstr( ppsz_argv[ i_opt ], "://" ))
225                     mrl = strdup( ppsz_argv[ i_opt ] );
226                 else
227                     mrl = vlc_path2uri( ppsz_argv[ i_opt ], NULL );
228
229                 if( !mrl )
230                     mrl = ( char * )ppsz_argv[ i_opt ];
231
232                 size_t i_len = strlen( mrl ) + 1;
233
234                 /* Write a length of an argument */
235                 DosWrite( hpipe, &i_len, sizeof( i_len ), &cbActual );
236
237                 /* Write an argument */
238                 DosWrite( hpipe, mrl, i_len, &cbActual );
239
240                 if( mrl != ppsz_argv[ i_opt ])
241                     free( mrl );
242             }
243
244             /* Close a named pipe of a client side */
245             DosClose( hpipe );
246
247             /* Bye bye */
248             system_End();
249             exit( 0 );
250         }
251     }
252 }
253
254 /**
255  * Cleans up after system_Init() and system_Configure().
256  */
257 void system_End(void)
258 {
259     if( tidIPCFirst == _gettid())
260     {
261         HPIPE hpipe;
262         ULONG ulAction;
263         ULONG cbActual;
264         ULONG rc;
265
266         do
267         {
268             rc = DosOpen( VLC_IPC_PIPE, &hpipe, &ulAction, 0, 0,
269                           OPEN_ACTION_OPEN_IF_EXISTS,
270                           OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE |
271                           OPEN_FLAGS_FAIL_ON_ERROR,
272                           NULL );
273
274             if( rc == ERROR_PIPE_BUSY )
275                 DosWaitNPipe( VLC_IPC_PIPE, -1 );
276             else if( rc )
277                 DosSleep( 1 );
278         } while( rc );
279
280         /* Ask for IPCHelper to quit */
281         ULONG ulCmd = IPC_CMD_QUIT;
282         DosWrite( hpipe, &ulCmd, sizeof( ulCmd ), &cbActual );
283
284         DosClose( hpipe );
285
286         TID tid = tidIPCHelper;
287         DosWaitThread( &tid, DCWW_WAIT );
288     }
289 }
290