]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/skin_main.cpp
skins2: rework skins2 as a vout_window provider
[vlc] / modules / gui / skins2 / src / skin_main.cpp
1 /*****************************************************************************
2  * skin_main.cpp
3  *****************************************************************************
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  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_input.h>
32 #include <vlc_playlist.h>
33 #include <vlc_threads.h>
34 #include <vlc_vout_window.h>
35 #include <vlc_vout_display.h>
36
37 #include "dialogs.hpp"
38 #include "os_factory.hpp"
39 #include "os_loop.hpp"
40 #include "var_manager.hpp"
41 #include "vlcproc.hpp"
42 #include "theme_loader.hpp"
43 #include "theme.hpp"
44 #include "theme_repository.hpp"
45 #include "vout_window.hpp"
46 #include "vout_manager.hpp"
47 #include "art_manager.hpp"
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 #include "../commands/cmd_callbacks.hpp"
55 #include "../commands/cmd_show_window.hpp"
56 #include "../commands/cmd_resize.hpp"
57 #include "../commands/cmd_on_top.hpp"
58
59 //---------------------------------------------------------------------------
60 // Exported interface functions.
61 //---------------------------------------------------------------------------
62 #ifdef WIN32_SKINS
63 extern "C" __declspec( dllexport )
64     int __VLC_SYMBOL( vlc_entry ) ( module_t *p_module );
65 #endif
66
67
68 //---------------------------------------------------------------------------
69 // Local prototypes
70 //---------------------------------------------------------------------------
71 static int  Open  ( vlc_object_t * );
72 static void Close ( vlc_object_t * );
73 static void *Run  ( void * );
74
75 static struct
76 {
77     intf_thread_t *intf;
78     vlc_mutex_t mutex;
79 } skin_load = { NULL, VLC_STATIC_MUTEX };
80
81 //---------------------------------------------------------------------------
82 // Open: initialize interface
83 //---------------------------------------------------------------------------
84 static int Open( vlc_object_t *p_this )
85 {
86     intf_thread_t *p_intf = (intf_thread_t *)p_this;
87
88     // Allocate instance and initialize some members
89     p_intf->p_sys = (intf_sys_t *) calloc( 1, sizeof( intf_sys_t ) );
90     if( p_intf->p_sys == NULL )
91         return VLC_ENOMEM;
92
93     // Suscribe to messages bank
94 #if 0
95     p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
96 #endif
97
98     p_intf->p_sys->p_input = NULL;
99     p_intf->p_sys->p_playlist = pl_Get( p_intf );
100
101     // Initialize "singleton" objects
102     p_intf->p_sys->p_logger = NULL;
103     p_intf->p_sys->p_queue = NULL;
104     p_intf->p_sys->p_dialogs = NULL;
105     p_intf->p_sys->p_interpreter = NULL;
106     p_intf->p_sys->p_osFactory = NULL;
107     p_intf->p_sys->p_osLoop = NULL;
108     p_intf->p_sys->p_varManager = NULL;
109     p_intf->p_sys->p_voutManager = NULL;
110     p_intf->p_sys->p_vlcProc = NULL;
111     p_intf->p_sys->p_repository = NULL;
112
113     // No theme yet
114     p_intf->p_sys->p_theme = NULL;
115
116     vlc_mutex_init( &p_intf->p_sys->init_lock );
117     vlc_cond_init( &p_intf->p_sys->init_wait );
118
119     vlc_mutex_lock( &p_intf->p_sys->init_lock );
120     p_intf->p_sys->b_ready = false;
121
122     if( vlc_clone( &p_intf->p_sys->thread, Run, p_intf,
123                                VLC_THREAD_PRIORITY_LOW ) )
124     {
125         vlc_mutex_unlock( &p_intf->p_sys->init_lock );
126
127         vlc_cond_destroy( &p_intf->p_sys->init_wait );
128         vlc_mutex_destroy( &p_intf->p_sys->init_lock );
129         free( p_intf->p_sys );
130         return VLC_EGENERIC;
131     }
132
133     while( !p_intf->p_sys->b_ready )
134         vlc_cond_wait( &p_intf->p_sys->init_wait, &p_intf->p_sys->init_lock );
135     vlc_mutex_unlock( &p_intf->p_sys->init_lock );
136
137     vlc_mutex_lock( &skin_load.mutex );
138     skin_load.intf = p_intf;
139     vlc_mutex_unlock( &skin_load.mutex );
140
141     return VLC_SUCCESS;
142 }
143
144 //---------------------------------------------------------------------------
145 // Close: destroy interface
146 //---------------------------------------------------------------------------
147 static void Close( vlc_object_t *p_this )
148 {
149     intf_thread_t *p_intf = (intf_thread_t *)p_this;
150
151     msg_Dbg( p_intf, "closing skins2 module" );
152
153     vlc_mutex_lock( &skin_load.mutex );
154     skin_load.intf = NULL;
155     vlc_mutex_unlock( &skin_load.mutex);
156
157     vlc_join( p_intf->p_sys->thread, NULL );
158
159     vlc_mutex_destroy( &p_intf->p_sys->init_lock );
160     vlc_cond_destroy( &p_intf->p_sys->init_wait );
161
162     // Unsubscribe from messages bank
163 #if 0
164     msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
165 #endif
166
167     // Destroy structure
168     free( p_intf->p_sys );
169 }
170
171
172 //---------------------------------------------------------------------------
173 // Run: main loop
174 //---------------------------------------------------------------------------
175 static void *Run( void * p_obj )
176 {
177     int canc = vlc_savecancel();
178
179     intf_thread_t *p_intf = (intf_thread_t *)p_obj;
180
181     bool b_error = false;
182     char *skin_last = NULL;
183     ThemeLoader *pLoader = NULL;
184     OSLoop *loop = NULL;
185
186     vlc_mutex_lock( &p_intf->p_sys->init_lock );
187
188     // Initialize singletons
189     if( OSFactory::instance( p_intf ) == NULL )
190     {
191         msg_Err( p_intf, "cannot initialize OSFactory" );
192         b_error = true;
193         goto end;
194     }
195     if( AsyncQueue::instance( p_intf ) == NULL )
196     {
197         msg_Err( p_intf, "cannot initialize AsyncQueue" );
198         b_error = true;
199         goto end;
200     }
201     if( Interpreter::instance( p_intf ) == NULL )
202     {
203         msg_Err( p_intf, "cannot instantiate Interpreter" );
204         b_error = true;
205         goto end;
206     }
207     if( VarManager::instance( p_intf ) == NULL )
208     {
209         msg_Err( p_intf, "cannot instantiate VarManager" );
210         b_error = true;
211         goto end;
212     }
213     if( VlcProc::instance( p_intf ) == NULL )
214     {
215         msg_Err( p_intf, "cannot initialize VLCProc" );
216         b_error = true;
217         goto end;
218     }
219     if( VoutManager::instance( p_intf ) == NULL )
220     {
221         msg_Err( p_intf, "cannot instantiate VoutManager" );
222         b_error = true;
223         goto end;
224     }
225     if( ArtManager::instance( p_intf ) == NULL )
226     {
227         msg_Err( p_intf, "cannot instantiate ArtManager" );
228         b_error = true;
229         goto end;
230     }
231     if( ThemeRepository::instance( p_intf ) == NULL )
232     {
233         msg_Err( p_intf, "cannot instantiate ThemeRepository" );
234         b_error = true;
235         goto end;
236     }
237     if( Dialogs::instance( p_intf ) == NULL )
238     {
239         msg_Err( p_intf, "cannot instantiate qt4 dialogs provider" );
240         b_error = true;
241         goto end;
242     }
243
244     // Load a theme
245     skin_last = config_GetPsz( p_intf, "skins2-last" );
246     pLoader = new ThemeLoader( p_intf );
247
248     if( !skin_last || !pLoader->load( skin_last ) )
249     {
250         // No skins (not even the default one). let's quit
251         CmdQuit *pCmd = new CmdQuit( p_intf );
252         AsyncQueue *pQueue = AsyncQueue::instance( p_intf );
253         pQueue->push( CmdGenericPtr( pCmd ) );
254         msg_Err( p_intf, "no skins found : exiting");
255     }
256
257     delete pLoader;
258     free( skin_last );
259
260     // Get the instance of OSLoop
261     loop = OSFactory::instance( p_intf )->getOSLoop();
262
263     // Signal the main thread this thread is now ready
264     p_intf->p_sys->b_ready = true;
265     vlc_cond_signal( &p_intf->p_sys->init_wait );
266     vlc_mutex_unlock( &p_intf->p_sys->init_lock );
267
268     // Enter the main event loop
269     loop->run();
270
271     // Destroy OSLoop
272     OSFactory::instance( p_intf )->destroyOSLoop();
273
274     // save and delete the theme
275     if( p_intf->p_sys->p_theme )
276     {
277         p_intf->p_sys->p_theme->saveConfig();
278
279         delete p_intf->p_sys->p_theme;
280         p_intf->p_sys->p_theme = NULL;
281
282         msg_Dbg( p_intf, "current theme deleted" );
283     }
284
285     // save config file
286     config_SaveConfigFile( p_intf, NULL );
287
288 end:
289     // Destroy "singleton" objects
290     Dialogs::destroy( p_intf );
291     ThemeRepository::destroy( p_intf );
292     ArtManager::destroy( p_intf );
293     VoutManager::destroy( p_intf );
294     VlcProc::destroy( p_intf );
295     VarManager::destroy( p_intf );
296     Interpreter::destroy( p_intf );
297     AsyncQueue::destroy( p_intf );
298     OSFactory::destroy( p_intf );
299
300     if( b_error )
301     {
302         p_intf->p_sys->b_ready = true;
303         vlc_cond_signal( &p_intf->p_sys->init_wait );
304         vlc_mutex_unlock( &p_intf->p_sys->init_lock );
305
306         libvlc_Quit( p_intf->p_libvlc );
307     }
308
309     vlc_restorecancel(canc);
310     return NULL;
311 }
312
313 static int  WindowOpen( vout_window_t *, const vout_window_cfg_t * );
314 static void WindowClose( vout_window_t * );
315 static int  WindowControl( vout_window_t *, int, va_list );
316
317 struct vout_window_sys_t
318 {
319     intf_thread_t*     pIntf;
320     vout_window_cfg_t  cfg;
321 };
322
323 static void WindowOpenLocal( intf_thread_t* pIntf, vlc_object_t *pObj )
324 {
325     vout_window_t* pWnd = (vout_window_t*)pObj;
326     int width = (int)pWnd->sys->cfg.width;
327     int height = (int)pWnd->sys->cfg.height;
328     VoutManager::instance( pIntf )->acceptWnd( pWnd, width, height );
329 }
330
331 static void WindowCloseLocal( intf_thread_t* pIntf, vlc_object_t *pObj )
332 {
333     vout_window_t* pWnd = (vout_window_t*)pObj;
334     VoutManager::instance( pIntf )->releaseWnd( pWnd );
335 }
336
337 static int WindowOpen( vout_window_t *pWnd, const vout_window_cfg_t *cfg )
338 {
339     vout_window_sys_t* sys;
340
341     vlc_mutex_lock( &skin_load.mutex );
342     intf_thread_t *pIntf = skin_load.intf;
343     if( pIntf )
344         vlc_object_hold( pIntf );
345     vlc_mutex_unlock( &skin_load.mutex );
346
347     if( pIntf == NULL )
348         return VLC_EGENERIC;
349
350     if( !vlc_object_alive( pIntf ) ||
351         !var_InheritBool( pIntf, "skinned-video") ||
352         cfg->is_standalone )
353     {
354         vlc_object_release( pIntf );
355         return VLC_EGENERIC;
356     }
357
358     sys = (vout_window_sys_t*)calloc( 1, sizeof( *sys ) );
359     if( !sys )
360     {
361         vlc_object_release( pIntf );
362         return VLC_ENOMEM;
363     }
364
365     pWnd->sys = sys;
366     pWnd->sys->cfg = *cfg;
367     pWnd->sys->pIntf = pIntf;
368     pWnd->control = WindowControl;
369
370     // force execution in the skins2 thread context
371     CmdExecuteBlock* cmd = new CmdExecuteBlock( pIntf, VLC_OBJECT( pWnd ),
372                                                 WindowOpenLocal );
373     CmdExecuteBlock::executeWait( CmdGenericPtr( cmd ) );
374
375 #ifdef X11_SKINS
376     if( !pWnd->handle.xid )
377 #else
378     if( !pWnd->handle.hwnd )
379 #endif
380     {
381         free( sys );
382         vlc_object_release( pIntf );
383         return VLC_EGENERIC;
384     }
385
386     return VLC_SUCCESS;
387 }
388
389 static void WindowClose( vout_window_t *pWnd )
390 {
391     vout_window_sys_t* sys = pWnd->sys;
392     intf_thread_t *pIntf = sys->pIntf;
393
394     // force execution in the skins2 thread context
395     CmdExecuteBlock* cmd = new CmdExecuteBlock( pIntf, VLC_OBJECT( pWnd ),
396                                                 WindowCloseLocal );
397     CmdExecuteBlock::executeWait( CmdGenericPtr( cmd ) );
398
399     vlc_object_release( sys->pIntf );
400     free( sys );
401 }
402
403 static int WindowControl( vout_window_t *pWnd, int query, va_list args )
404 {
405     vout_window_sys_t* sys = pWnd->sys;
406     intf_thread_t *pIntf = sys->pIntf;
407     VoutManager *pVoutManager = VoutManager::instance( pIntf );
408     AsyncQueue *pQueue = AsyncQueue::instance( pIntf );
409
410     switch( query )
411     {
412         case VOUT_WINDOW_SET_SIZE:
413         {
414             unsigned int i_width  = va_arg( args, unsigned int );
415             unsigned int i_height = va_arg( args, unsigned int );
416
417             if( i_width && i_height )
418             {
419                 // Post a vout resize command
420                 CmdResizeVout *pCmd =
421                     new CmdResizeVout( pIntf, pWnd,
422                                        (int)i_width, (int)i_height );
423                 pQueue->push( CmdGenericPtr( pCmd ) );
424             }
425             return VLC_EGENERIC;
426         }
427
428         case VOUT_WINDOW_SET_FULLSCREEN:
429         {
430             bool b_fullscreen = va_arg( args, int );
431
432             // Post a set fullscreen command
433             CmdSetFullscreen* pCmd =
434                 new CmdSetFullscreen( pIntf, pWnd, b_fullscreen );
435             pQueue->push( CmdGenericPtr( pCmd ) );
436             return VLC_SUCCESS;
437         }
438
439         case VOUT_WINDOW_SET_STATE:
440         {
441             unsigned i_arg = va_arg( args, unsigned );
442             unsigned on_top = i_arg & VOUT_WINDOW_STATE_ABOVE;
443
444             // Post a SetOnTop command
445             CmdSetOnTop* pCmd =
446                 new CmdSetOnTop( pIntf, on_top );
447             pQueue->push( CmdGenericPtr( pCmd ) );
448             return VLC_SUCCESS;
449         }
450
451         default:
452             msg_Dbg( pIntf, "control query not supported" );
453             return VLC_EGENERIC;
454     }
455 }
456
457 //---------------------------------------------------------------------------
458 // Module descriptor
459 //---------------------------------------------------------------------------
460 #define SKINS2_LAST      N_("Skin to use")
461 #define SKINS2_LAST_LONG N_("Path to the skin to use.")
462 #define SKINS2_CONFIG      N_("Config of last used skin")
463 #define SKINS2_CONFIG_LONG N_("Windows configuration of the last skin used. " \
464         "This option is updated automatically, do not touch it." )
465 #define SKINS2_SYSTRAY      N_("Systray icon")
466 #define SKINS2_SYSTRAY_LONG N_("Show a systray icon for VLC")
467 #define SKINS2_TASKBAR      N_("Show VLC on the taskbar")
468 #define SKINS2_TASKBAR_LONG N_("Show VLC on the taskbar")
469 #define SKINS2_TRANSPARENCY      N_("Enable transparency effects")
470 #define SKINS2_TRANSPARENCY_LONG N_("You can disable all transparency effects"\
471     " if you want. This is mainly useful when moving windows does not behave" \
472     " correctly.")
473 #define SKINS2_PLAYLIST N_("Use a skinned playlist")
474 #define SKINS2_PLAYLIST_LONG N_("Use a skinned playlist")
475 #define SKINS2_VIDEO N_("Display video in a skinned window if any")
476 #define SKINS2_VIDEO_LONG N_( \
477     "When set to 'no', this parameter is intended to give old skins a chance" \
478     " to play back video even though no video tag is implemented")
479
480 vlc_module_begin ()
481     set_category( CAT_INTERFACE )
482     set_subcategory( SUBCAT_INTERFACE_MAIN )
483     add_loadfile( "skins2-last", "", SKINS2_LAST, SKINS2_LAST_LONG,
484                   true )
485         change_autosave ()
486     add_string( "skins2-config", "", SKINS2_CONFIG, SKINS2_CONFIG_LONG,
487                 true )
488         change_autosave ()
489         change_private ()
490 #ifdef WIN32
491     add_bool( "skins2-systray", true, SKINS2_SYSTRAY,
492               SKINS2_SYSTRAY_LONG, false );
493     add_bool( "skins2-taskbar", true, SKINS2_TASKBAR,
494               SKINS2_TASKBAR_LONG, false );
495 #endif
496     add_bool( "skins2-transparency", false, SKINS2_TRANSPARENCY,
497               SKINS2_TRANSPARENCY_LONG, false );
498
499     add_bool( "skinned-playlist", true, SKINS2_PLAYLIST,
500               SKINS2_PLAYLIST_LONG, false );
501     add_bool( "skinned-video", true, SKINS2_VIDEO,
502               SKINS2_VIDEO_LONG, false );
503     set_shortname( N_("Skins"))
504     set_description( N_("Skinnable Interface") )
505     set_capability( "interface", 30 )
506     set_callbacks( Open, Close )
507     add_shortcut( "skins" )
508
509     add_submodule ()
510 #ifdef WIN32
511         set_capability( "vout window hwnd", 51 )
512 #else
513         set_capability( "vout window xid", 51 )
514 #endif
515         set_callbacks( WindowOpen, WindowClose )
516
517 vlc_module_end ()