skin_main.cpp 15.9 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 = vlc_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
    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 );
111
    p_intf->p_sys->b_error = false;
112
113
114
115
116
117
    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 );
118

119
120
121
122
123
124
125
126
127
128
        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 );

129
130
131
132
133
134
135
136
137
138
139
    if( p_intf->p_sys->b_error )
    {
        vlc_join( p_intf->p_sys->thread, NULL );

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

        free( p_intf->p_sys );
        return VLC_EGENERIC;
    }

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    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" );

156
157
158
    /* Terminate input to ensure that our window provider is released. */
    playlist_Deactivate( p_intf->p_sys->p_playlist );

159
160
161
162
    vlc_mutex_lock( &skin_load.mutex );
    skin_load.intf = NULL;
    vlc_mutex_unlock( &skin_load.mutex);

163
164
165
166
167
168
169
170
171
172
173
174
    AsyncQueue *pQueue = p_intf->p_sys->p_queue;
    if( pQueue )
    {
        CmdGeneric *pCmd = new CmdExitLoop( p_intf );
        if( pCmd )
            pQueue->push( CmdGenericPtr( pCmd ) );
    }
    else
    {
        msg_Err( p_intf, "thread found already stopped (weird!)" );
    }

175
176
    vlc_join( p_intf->p_sys->thread, NULL );

177
178
179
    vlc_mutex_destroy( &p_intf->p_sys->init_lock );
    vlc_cond_destroy( &p_intf->p_sys->init_wait );

180
181
    // Unsubscribe from messages bank
#if 0
182
    vlc_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
183
184
185
186
187
188
189
190
191
192
#endif

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


//---------------------------------------------------------------------------
// Run: main loop
//---------------------------------------------------------------------------
193
static void *Run( void * p_obj )
194
195
196
{
    int canc = vlc_savecancel();

197
198
    intf_thread_t *p_intf = (intf_thread_t *)p_obj;

199
200
201
202
203
    bool b_error = false;
    char *skin_last = NULL;
    ThemeLoader *pLoader = NULL;
    OSLoop *loop = NULL;

204
205
    vlc_mutex_lock( &p_intf->p_sys->init_lock );

206
    // Initialize singletons
207
208
    if( OSFactory::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
209
        msg_Err( p_intf, "cannot initialize OSFactory" );
210
211
        b_error = true;
        goto end;
212
    }
213
214
    if( AsyncQueue::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
215
        msg_Err( p_intf, "cannot initialize AsyncQueue" );
216
217
        b_error = true;
        goto end;
218
    }
Cyril Deguet's avatar
Cyril Deguet committed
219
220
    if( Interpreter::instance( p_intf ) == NULL )
    {
221
        msg_Err( p_intf, "cannot instantiate Interpreter" );
222
223
        b_error = true;
        goto end;
Cyril Deguet's avatar
Cyril Deguet committed
224
    }
225
226
    if( VarManager::instance( p_intf ) == NULL )
    {
227
        msg_Err( p_intf, "cannot instantiate VarManager" );
228
229
        b_error = true;
        goto end;
230
231
232
    }
    if( VlcProc::instance( p_intf ) == NULL )
    {
zorglub's avatar
zorglub committed
233
        msg_Err( p_intf, "cannot initialize VLCProc" );
234
235
        b_error = true;
        goto end;
236
    }
Erwan Tulou's avatar
Erwan Tulou committed
237
238
    if( VoutManager::instance( p_intf ) == NULL )
    {
239
240
241
242
243
244
245
        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" );
246
247
248
249
250
        b_error = true;
        goto end;
    }
    if( ThemeRepository::instance( p_intf ) == NULL )
    {
251
        msg_Err( p_intf, "cannot instantiate ThemeRepository" );
252
253
254
255
256
        b_error = true;
        goto end;
    }
    if( Dialogs::instance( p_intf ) == NULL )
    {
257
        msg_Err( p_intf, "cannot instantiate qt4 dialogs provider" );
258
259
        b_error = true;
        goto end;
Erwan Tulou's avatar
Erwan Tulou committed
260
    }
261

262
    // Load a theme
Erwan Tulou's avatar
Erwan Tulou committed
263
    skin_last = config_GetPsz( p_intf, "skins2-last" );
264
    pLoader = new ThemeLoader( p_intf );
265

266
    if( !skin_last || !pLoader->load( skin_last ) )
267
    {
268
269
270
271
272
        // 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");
273
274
    }

275
    delete pLoader;
276
277
    free( skin_last );

278
279
    // Get the instance of OSLoop
    loop = OSFactory::instance( p_intf )->getOSLoop();
280

281
    // Signal the main thread this thread is now ready
282
    p_intf->p_sys->b_error = false;
283
284
285
286
    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 );

287
288
    // Enter the main event loop
    loop->run();
289

290
291
    // Destroy OSLoop
    OSFactory::instance( p_intf )->destroyOSLoop();
Erwan Tulou's avatar
Erwan Tulou committed
292

293
    // save and delete the theme
Erwan Tulou's avatar
Erwan Tulou committed
294
295
    if( p_intf->p_sys->p_theme )
    {
296
297
        p_intf->p_sys->p_theme->saveConfig();

Erwan Tulou's avatar
Erwan Tulou committed
298
299
        delete p_intf->p_sys->p_theme;
        p_intf->p_sys->p_theme = NULL;
300

Erwan Tulou's avatar
Erwan Tulou committed
301
302
303
        msg_Dbg( p_intf, "current theme deleted" );
    }

Erwan Tulou's avatar
Erwan Tulou committed
304
    // save config file
305
    config_SaveConfigFile( p_intf );
Erwan Tulou's avatar
Erwan Tulou committed
306

307
end:
308
    // Destroy "singleton" objects
309
    Dialogs::destroy( p_intf );
310
    ThemeRepository::destroy( p_intf );
311
    ArtManager::destroy( p_intf );
Erwan Tulou's avatar
Erwan Tulou committed
312
    VoutManager::destroy( p_intf );
313
314
    VlcProc::destroy( p_intf );
    VarManager::destroy( p_intf );
Cyril Deguet's avatar
Cyril Deguet committed
315
    Interpreter::destroy( p_intf );
316
    AsyncQueue::destroy( p_intf );
317
    OSFactory::destroy( p_intf );
318

319
    if( b_error )
320
    {
321
        p_intf->p_sys->b_error = true;
322
323
324
325
        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 );
    }
326

327
    vlc_restorecancel(canc);
328
    return NULL;
329
330
}

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
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 );
}
354

355
static int WindowOpen( vout_window_t *pWnd, const vout_window_cfg_t *cfg )
356
{
357
358
    vout_window_sys_t* sys;

359
360
361
362
363
    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 );
364

365
    if( pIntf == NULL )
366
367
        return VLC_EGENERIC;

368
    if( !var_InheritBool( pIntf, "skinned-video") ||
369
        cfg->is_standalone )
370
371
372
373
374
    {
        vlc_object_release( pIntf );
        return VLC_EGENERIC;
    }

375
376
377
378
379
380
    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
381

382
383
384
385
    pWnd->sys = sys;
    pWnd->sys->cfg = *cfg;
    pWnd->sys->pIntf = pIntf;
    pWnd->control = WindowControl;
Erwan Tulou's avatar
Erwan Tulou committed
386

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

392
393
394
395
396
#ifdef X11_SKINS
    if( !pWnd->handle.xid )
#else
    if( !pWnd->handle.hwnd )
#endif
397
    {
398
        free( sys );
399
        vlc_object_release( pIntf );
400
401
        return VLC_EGENERIC;
    }
402
403

    return VLC_SUCCESS;
404
405
}

406
static void WindowClose( vout_window_t *pWnd )
407
{
408
409
    vout_window_sys_t* sys = pWnd->sys;
    intf_thread_t *pIntf = sys->pIntf;
410

411
412
413
414
    // force execution in the skins2 thread context
    CmdExecuteBlock* cmd = new CmdExecuteBlock( pIntf, VLC_OBJECT( pWnd ),
                                                WindowCloseLocal );
    CmdExecuteBlock::executeWait( CmdGenericPtr( cmd ) );
415

416
417
    vlc_object_release( sys->pIntf );
    free( sys );
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
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
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;
    }
}
472

473
474
475
//---------------------------------------------------------------------------
// Module descriptor
//---------------------------------------------------------------------------
zorglub's avatar
zorglub committed
476
477
#define SKINS2_LAST      N_("Skin to use")
#define SKINS2_LAST_LONG N_("Path to the skin to use.")
478
#define SKINS2_CONFIG      N_("Config of last used skin")
479
480
481
482
#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")
483
484
#define SKINS2_TASKBAR      N_("Show VLC on the taskbar")
#define SKINS2_TASKBAR_LONG N_("Show VLC on the taskbar")
485
#define SKINS2_TRANSPARENCY      N_("Enable transparency effects")
486
#define SKINS2_TRANSPARENCY_LONG N_("You can disable all transparency effects"\
487
488
    " if you want. This is mainly useful when moving windows does not behave" \
    " correctly.")
dionoea's avatar
dionoea committed
489
490
#define SKINS2_PLAYLIST N_("Use a skinned playlist")
#define SKINS2_PLAYLIST_LONG N_("Use a skinned playlist")
491
492
493
494
#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")
495

496
497
498
vlc_module_begin ()
    set_category( CAT_INTERFACE )
    set_subcategory( SUBCAT_INTERFACE_MAIN )
499
    add_loadfile( "skins2-last", "", SKINS2_LAST, SKINS2_LAST_LONG,
500
                  true )
501
    add_string( "skins2-config", "", SKINS2_CONFIG, SKINS2_CONFIG_LONG,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
502
                true )
503
        change_private ()
504
#ifdef WIN32
Erwan Tulou's avatar
Erwan Tulou committed
505
    add_bool( "skins2-systray", true, SKINS2_SYSTRAY,
506
              SKINS2_SYSTRAY_LONG, false );
Erwan Tulou's avatar
Erwan Tulou committed
507
    add_bool( "skins2-taskbar", true, SKINS2_TASKBAR,
508
              SKINS2_TASKBAR_LONG, false );
509
#endif
510
    add_bool( "skins2-transparency", false, SKINS2_TRANSPARENCY,
511
              SKINS2_TRANSPARENCY_LONG, false );
512

513
    add_bool( "skinned-playlist", true, SKINS2_PLAYLIST,
514
              SKINS2_PLAYLIST_LONG, false );
515
    add_bool( "skinned-video", true, SKINS2_VIDEO,
516
              SKINS2_VIDEO_LONG, false );
517
518
519
520
521
522
523
    set_shortname( N_("Skins"))
    set_description( N_("Skinnable Interface") )
    set_capability( "interface", 30 )
    set_callbacks( Open, Close )
    add_shortcut( "skins" )

    add_submodule ()
524
525
526
527
528
#ifdef WIN32
        set_capability( "vout window hwnd", 51 )
#else
        set_capability( "vout window xid", 51 )
#endif
529
530
531
        set_callbacks( WindowOpen, WindowClose )

vlc_module_end ()