skin_main.cpp 15.2 KB
Newer Older
1
2
3
/*****************************************************************************
 * skin_main.cpp
 *****************************************************************************
4
 * Copyright (C) 2003 the VideoLAN team
5
 * $Id$
6
7
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8
 *          Olivier Teulière <ipkiss@via.ecp.fr>
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
zorglub's avatar
zorglub committed
24

25
26
27
28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <vlc_common.h>
30
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
31
32
#include <vlc_input.h>
#include <vlc_playlist.h>
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
33
#include <vlc_threads.h>
34
#include <vlc_vout_window.h>
35
#include <vlc_vout_display.h>
zorglub's avatar
zorglub committed
36

37
38
39
40
41
42
#include "dialogs.hpp"
#include "os_factory.hpp"
#include "os_loop.hpp"
#include "var_manager.hpp"
#include "vlcproc.hpp"
#include "theme_loader.hpp"
43
#include "theme.hpp"
44
#include "theme_repository.hpp"
Erwan Tulou's avatar
Erwan Tulou committed
45
46
#include "vout_window.hpp"
#include "vout_manager.hpp"
47
#include "art_manager.hpp"
Cyril Deguet's avatar
Cyril Deguet committed
48
#include "../parser/interpreter.hpp"
49
#include "../commands/async_queue.hpp"
50
#include "../commands/cmd_quit.hpp"
51
#include "../commands/cmd_dialogs.hpp"
52
#include "../commands/cmd_minimize.hpp"
53
#include "../commands/cmd_playlist.hpp"
54
55
56
57
#include "../commands/cmd_callbacks.hpp"
#include "../commands/cmd_show_window.hpp"
#include "../commands/cmd_resize.hpp"
#include "../commands/cmd_on_top.hpp"
58
59

//---------------------------------------------------------------------------
60
// Local prototypes
61
62
63
//---------------------------------------------------------------------------
static int  Open  ( vlc_object_t * );
static void Close ( vlc_object_t * );
64
static void *Run  ( void * );
65

66
67
68
69
static struct
{
    intf_thread_t *intf;
    vlc_mutex_t mutex;
Christophe Mutricy's avatar
Typo    
Christophe Mutricy committed
70
} skin_load = { NULL, VLC_STATIC_MUTEX };
71

72
73
74
75
76
77
78
79
//---------------------------------------------------------------------------
// Open: initialize interface
//---------------------------------------------------------------------------
static int Open( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;

    // Allocate instance and initialize some members
80
    p_intf->p_sys = (intf_sys_t *) calloc( 1, sizeof( intf_sys_t ) );
81
    if( p_intf->p_sys == NULL )
82
        return VLC_ENOMEM;
83
84

    // Suscribe to messages bank
85
#if 0
86
    p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
87
#endif
88
89

    p_intf->p_sys->p_input = NULL;
90
    p_intf->p_sys->p_playlist = pl_Get( p_intf );
91
92
93
94
95

    // Initialize "singleton" objects
    p_intf->p_sys->p_logger = NULL;
    p_intf->p_sys->p_queue = NULL;
    p_intf->p_sys->p_dialogs = NULL;
Cyril Deguet's avatar
Cyril Deguet committed
96
    p_intf->p_sys->p_interpreter = NULL;
97
98
99
    p_intf->p_sys->p_osFactory = NULL;
    p_intf->p_sys->p_osLoop = NULL;
    p_intf->p_sys->p_varManager = NULL;
Erwan Tulou's avatar
Erwan Tulou committed
100
    p_intf->p_sys->p_voutManager = NULL;
101
    p_intf->p_sys->p_vlcProc = NULL;
102
    p_intf->p_sys->p_repository = NULL;
103
104
105
106

    // No theme yet
    p_intf->p_sys->p_theme = NULL;

107
108
109
110
111
112
113
114
115
116
    vlc_mutex_init( &p_intf->p_sys->init_lock );
    vlc_cond_init( &p_intf->p_sys->init_wait );

    vlc_mutex_lock( &p_intf->p_sys->init_lock );
    p_intf->p_sys->b_ready = false;

    if( vlc_clone( &p_intf->p_sys->thread, Run, p_intf,
                               VLC_THREAD_PRIORITY_LOW ) )
    {
        vlc_mutex_unlock( &p_intf->p_sys->init_lock );
117

118
119
120
121
122
123
124
125
126
127
        vlc_cond_destroy( &p_intf->p_sys->init_wait );
        vlc_mutex_destroy( &p_intf->p_sys->init_lock );
        free( p_intf->p_sys );
        return VLC_EGENERIC;
    }

    while( !p_intf->p_sys->b_ready )
        vlc_cond_wait( &p_intf->p_sys->init_wait, &p_intf->p_sys->init_lock );
    vlc_mutex_unlock( &p_intf->p_sys->init_lock );

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    vlc_mutex_lock( &skin_load.mutex );
    skin_load.intf = p_intf;
    vlc_mutex_unlock( &skin_load.mutex );

    return VLC_SUCCESS;
}

//---------------------------------------------------------------------------
// Close: destroy interface
//---------------------------------------------------------------------------
static void Close( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t *)p_this;

    msg_Dbg( p_intf, "closing skins2 module" );

    vlc_mutex_lock( &skin_load.mutex );
    skin_load.intf = NULL;
    vlc_mutex_unlock( &skin_load.mutex);

148
149
    vlc_join( p_intf->p_sys->thread, NULL );

150
151
152
    vlc_mutex_destroy( &p_intf->p_sys->init_lock );
    vlc_cond_destroy( &p_intf->p_sys->init_wait );

153
154
155
156
157
158
159
160
161
162
163
164
165
    // Unsubscribe from messages bank
#if 0
    msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
#endif

    // Destroy structure
    free( p_intf->p_sys );
}


//---------------------------------------------------------------------------
// Run: main loop
//---------------------------------------------------------------------------
166
static void *Run( void * p_obj )
167
168
169
{
    int canc = vlc_savecancel();

170
171
    intf_thread_t *p_intf = (intf_thread_t *)p_obj;

172
173
174
175
176
    bool b_error = false;
    char *skin_last = NULL;
    ThemeLoader *pLoader = NULL;
    OSLoop *loop = NULL;

177
178
    vlc_mutex_lock( &p_intf->p_sys->init_lock );

179
    // Initialize singletons
180
181
    if( OSFactory::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
182
        msg_Err( p_intf, "cannot initialize OSFactory" );
183
184
        b_error = true;
        goto end;
185
    }
186
187
    if( AsyncQueue::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
188
        msg_Err( p_intf, "cannot initialize AsyncQueue" );
189
190
        b_error = true;
        goto end;
191
    }
Cyril Deguet's avatar
Cyril Deguet committed
192
193
    if( Interpreter::instance( p_intf ) == NULL )
    {
194
        msg_Err( p_intf, "cannot instantiate Interpreter" );
195
196
        b_error = true;
        goto end;
Cyril Deguet's avatar
Cyril Deguet committed
197
    }
198
199
    if( VarManager::instance( p_intf ) == NULL )
    {
200
        msg_Err( p_intf, "cannot instantiate VarManager" );
201
202
        b_error = true;
        goto end;
203
204
205
    }
    if( VlcProc::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
206
        msg_Err( p_intf, "cannot initialize VLCProc" );
207
208
        b_error = true;
        goto end;
209
    }
Erwan Tulou's avatar
Erwan Tulou committed
210
211
    if( VoutManager::instance( p_intf ) == NULL )
    {
212
213
214
215
216
217
218
        msg_Err( p_intf, "cannot instantiate VoutManager" );
        b_error = true;
        goto end;
    }
    if( ArtManager::instance( p_intf ) == NULL )
    {
        msg_Err( p_intf, "cannot instantiate ArtManager" );
219
220
221
222
223
        b_error = true;
        goto end;
    }
    if( ThemeRepository::instance( p_intf ) == NULL )
    {
224
        msg_Err( p_intf, "cannot instantiate ThemeRepository" );
225
226
227
228
229
        b_error = true;
        goto end;
    }
    if( Dialogs::instance( p_intf ) == NULL )
    {
230
        msg_Err( p_intf, "cannot instantiate qt4 dialogs provider" );
231
232
        b_error = true;
        goto end;
Erwan Tulou's avatar
Erwan Tulou committed
233
    }
234

235
    // Load a theme
Erwan Tulou's avatar
Erwan Tulou committed
236
    skin_last = config_GetPsz( p_intf, "skins2-last" );
237
    pLoader = new ThemeLoader( p_intf );
238

239
    if( !skin_last || !pLoader->load( skin_last ) )
240
    {
241
242
243
244
245
        // No skins (not even the default one). let's quit
        CmdQuit *pCmd = new CmdQuit( p_intf );
        AsyncQueue *pQueue = AsyncQueue::instance( p_intf );
        pQueue->push( CmdGenericPtr( pCmd ) );
        msg_Err( p_intf, "no skins found : exiting");
246
247
    }

248
    delete pLoader;
249
250
    free( skin_last );

251
252
    // Get the instance of OSLoop
    loop = OSFactory::instance( p_intf )->getOSLoop();
253

254
255
256
257
258
    // Signal the main thread this thread is now ready
    p_intf->p_sys->b_ready = true;
    vlc_cond_signal( &p_intf->p_sys->init_wait );
    vlc_mutex_unlock( &p_intf->p_sys->init_lock );

259
260
    // Enter the main event loop
    loop->run();
261

262
263
    // Destroy OSLoop
    OSFactory::instance( p_intf )->destroyOSLoop();
Erwan Tulou's avatar
Erwan Tulou committed
264

265
    // save and delete the theme
Erwan Tulou's avatar
Erwan Tulou committed
266
267
    if( p_intf->p_sys->p_theme )
    {
268
269
        p_intf->p_sys->p_theme->saveConfig();

Erwan Tulou's avatar
Erwan Tulou committed
270
271
        delete p_intf->p_sys->p_theme;
        p_intf->p_sys->p_theme = NULL;
272

Erwan Tulou's avatar
Erwan Tulou committed
273
274
275
        msg_Dbg( p_intf, "current theme deleted" );
    }

Erwan Tulou's avatar
Erwan Tulou committed
276
    // save config file
277
    config_SaveConfigFile( p_intf );
Erwan Tulou's avatar
Erwan Tulou committed
278

279
end:
280
    // Destroy "singleton" objects
281
    Dialogs::destroy( p_intf );
282
    ThemeRepository::destroy( p_intf );
283
    ArtManager::destroy( p_intf );
Erwan Tulou's avatar
Erwan Tulou committed
284
    VoutManager::destroy( p_intf );
285
286
    VlcProc::destroy( p_intf );
    VarManager::destroy( p_intf );
Cyril Deguet's avatar
Cyril Deguet committed
287
    Interpreter::destroy( p_intf );
288
    AsyncQueue::destroy( p_intf );
289
    OSFactory::destroy( p_intf );
290

291
    if( b_error )
292
293
294
295
296
    {
        p_intf->p_sys->b_ready = true;
        vlc_cond_signal( &p_intf->p_sys->init_wait );
        vlc_mutex_unlock( &p_intf->p_sys->init_lock );

297
        libvlc_Quit( p_intf->p_libvlc );
298
    }
299

300
    vlc_restorecancel(canc);
301
    return NULL;
302
303
}

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
static int  WindowOpen( vout_window_t *, const vout_window_cfg_t * );
static void WindowClose( vout_window_t * );
static int  WindowControl( vout_window_t *, int, va_list );

struct vout_window_sys_t
{
    intf_thread_t*     pIntf;
    vout_window_cfg_t  cfg;
};

static void WindowOpenLocal( intf_thread_t* pIntf, vlc_object_t *pObj )
{
    vout_window_t* pWnd = (vout_window_t*)pObj;
    int width = (int)pWnd->sys->cfg.width;
    int height = (int)pWnd->sys->cfg.height;
    VoutManager::instance( pIntf )->acceptWnd( pWnd, width, height );
}

static void WindowCloseLocal( intf_thread_t* pIntf, vlc_object_t *pObj )
{
    vout_window_t* pWnd = (vout_window_t*)pObj;
    VoutManager::instance( pIntf )->releaseWnd( pWnd );
}
327

328
static int WindowOpen( vout_window_t *pWnd, const vout_window_cfg_t *cfg )
329
{
330
331
    vout_window_sys_t* sys;

332
333
334
335
336
    vlc_mutex_lock( &skin_load.mutex );
    intf_thread_t *pIntf = skin_load.intf;
    if( pIntf )
        vlc_object_hold( pIntf );
    vlc_mutex_unlock( &skin_load.mutex );
337

338
    if( pIntf == NULL )
339
340
        return VLC_EGENERIC;

341
342
    if( !vlc_object_alive( pIntf ) ||
        !var_InheritBool( pIntf, "skinned-video") ||
343
        cfg->is_standalone )
344
345
346
347
348
    {
        vlc_object_release( pIntf );
        return VLC_EGENERIC;
    }

349
350
351
352
353
354
    sys = (vout_window_sys_t*)calloc( 1, sizeof( *sys ) );
    if( !sys )
    {
        vlc_object_release( pIntf );
        return VLC_ENOMEM;
    }
Erwan Tulou's avatar
Erwan Tulou committed
355

356
357
358
359
    pWnd->sys = sys;
    pWnd->sys->cfg = *cfg;
    pWnd->sys->pIntf = pIntf;
    pWnd->control = WindowControl;
Erwan Tulou's avatar
Erwan Tulou committed
360

361
362
363
364
    // force execution in the skins2 thread context
    CmdExecuteBlock* cmd = new CmdExecuteBlock( pIntf, VLC_OBJECT( pWnd ),
                                                WindowOpenLocal );
    CmdExecuteBlock::executeWait( CmdGenericPtr( cmd ) );
365

366
367
368
369
370
#ifdef X11_SKINS
    if( !pWnd->handle.xid )
#else
    if( !pWnd->handle.hwnd )
#endif
371
    {
372
        free( sys );
373
        vlc_object_release( pIntf );
374
375
        return VLC_EGENERIC;
    }
376
377

    return VLC_SUCCESS;
378
379
}

380
static void WindowClose( vout_window_t *pWnd )
381
{
382
383
    vout_window_sys_t* sys = pWnd->sys;
    intf_thread_t *pIntf = sys->pIntf;
384

385
386
387
388
    // force execution in the skins2 thread context
    CmdExecuteBlock* cmd = new CmdExecuteBlock( pIntf, VLC_OBJECT( pWnd ),
                                                WindowCloseLocal );
    CmdExecuteBlock::executeWait( CmdGenericPtr( cmd ) );
389

390
391
    vlc_object_release( sys->pIntf );
    free( sys );
392
393
}

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
static int WindowControl( vout_window_t *pWnd, int query, va_list args )
{
    vout_window_sys_t* sys = pWnd->sys;
    intf_thread_t *pIntf = sys->pIntf;
    AsyncQueue *pQueue = AsyncQueue::instance( pIntf );

    switch( query )
    {
        case VOUT_WINDOW_SET_SIZE:
        {
            unsigned int i_width  = va_arg( args, unsigned int );
            unsigned int i_height = va_arg( args, unsigned int );

            if( i_width && i_height )
            {
                // Post a vout resize command
                CmdResizeVout *pCmd =
                    new CmdResizeVout( pIntf, pWnd,
                                       (int)i_width, (int)i_height );
                pQueue->push( CmdGenericPtr( pCmd ) );
            }
            return VLC_EGENERIC;
        }

        case VOUT_WINDOW_SET_FULLSCREEN:
        {
            bool b_fullscreen = va_arg( args, int );

            // Post a set fullscreen command
            CmdSetFullscreen* pCmd =
                new CmdSetFullscreen( pIntf, pWnd, b_fullscreen );
            pQueue->push( CmdGenericPtr( pCmd ) );
            return VLC_SUCCESS;
        }

        case VOUT_WINDOW_SET_STATE:
        {
            unsigned i_arg = va_arg( args, unsigned );
            unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;

            // Post a SetOnTop command
            CmdSetOnTop* pCmd =
                new CmdSetOnTop( pIntf, on_top );
            pQueue->push( CmdGenericPtr( pCmd ) );
            return VLC_SUCCESS;
        }

        default:
            msg_Dbg( pIntf, "control query not supported" );
            return VLC_EGENERIC;
    }
}
446

447
448
449
//---------------------------------------------------------------------------
// Module descriptor
//---------------------------------------------------------------------------
zorglub's avatar
zorglub committed
450
451
#define SKINS2_LAST      N_("Skin to use")
#define SKINS2_LAST_LONG N_("Path to the skin to use.")
452
#define SKINS2_CONFIG      N_("Config of last used skin")
453
454
455
456
#define SKINS2_CONFIG_LONG N_("Windows configuration of the last skin used. " \
        "This option is updated automatically, do not touch it." )
#define SKINS2_SYSTRAY      N_("Systray icon")
#define SKINS2_SYSTRAY_LONG N_("Show a systray icon for VLC")
457
458
#define SKINS2_TASKBAR      N_("Show VLC on the taskbar")
#define SKINS2_TASKBAR_LONG N_("Show VLC on the taskbar")
459
#define SKINS2_TRANSPARENCY      N_("Enable transparency effects")
460
#define SKINS2_TRANSPARENCY_LONG N_("You can disable all transparency effects"\
461
462
    " if you want. This is mainly useful when moving windows does not behave" \
    " correctly.")
dionoea's avatar
dionoea committed
463
464
#define SKINS2_PLAYLIST N_("Use a skinned playlist")
#define SKINS2_PLAYLIST_LONG N_("Use a skinned playlist")
465
466
467
468
#define SKINS2_VIDEO N_("Display video in a skinned window if any")
#define SKINS2_VIDEO_LONG N_( \
    "When set to 'no', this parameter is intended to give old skins a chance" \
    " to play back video even though no video tag is implemented")
469

470
471
472
vlc_module_begin ()
    set_category( CAT_INTERFACE )
    set_subcategory( SUBCAT_INTERFACE_MAIN )
473
    add_loadfile( "skins2-last", "", SKINS2_LAST, SKINS2_LAST_LONG,
474
                  true )
475
    add_string( "skins2-config", "", SKINS2_CONFIG, SKINS2_CONFIG_LONG,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
476
                true )
477
        change_private ()
478
#ifdef WIN32
Erwan Tulou's avatar
Erwan Tulou committed
479
    add_bool( "skins2-systray", true, SKINS2_SYSTRAY,
480
              SKINS2_SYSTRAY_LONG, false );
Erwan Tulou's avatar
Erwan Tulou committed
481
    add_bool( "skins2-taskbar", true, SKINS2_TASKBAR,
482
              SKINS2_TASKBAR_LONG, false );
483
#endif
484
    add_bool( "skins2-transparency", false, SKINS2_TRANSPARENCY,
485
              SKINS2_TRANSPARENCY_LONG, false );
486

487
    add_bool( "skinned-playlist", true, SKINS2_PLAYLIST,
488
              SKINS2_PLAYLIST_LONG, false );
489
    add_bool( "skinned-video", true, SKINS2_VIDEO,
490
              SKINS2_VIDEO_LONG, false );
491
492
493
494
495
496
497
    set_shortname( N_("Skins"))
    set_description( N_("Skinnable Interface") )
    set_capability( "interface", 30 )
    set_callbacks( Open, Close )
    add_shortcut( "skins" )

    add_submodule ()
498
499
500
501
502
#ifdef WIN32
        set_capability( "vout window hwnd", 51 )
#else
        set_capability( "vout window xid", 51 )
#endif
503
504
505
        set_callbacks( WindowOpen, WindowClose )

vlc_module_end ()