]> git.sesse.net Git - vlc/blob - modules/gui/wxwidgets/wxwidgets.cpp
Include vlc_plugin.h as needed
[vlc] / modules / gui / wxwidgets / wxwidgets.cpp
1 /*****************************************************************************
2  * wxwidgets.cpp : wxWidgets plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_plugin.h>
35 #include <vlc_interface.h>
36
37 #ifdef HAVE_LOCALE_H
38 #   include <locale.h>
39 #endif
40
41 #include "interface.hpp"
42
43 /* Temporary hack */
44 #if defined(WIN32) && defined(_WX_INIT_H_)
45 #if (wxMAJOR_VERSION <= 2) && (wxMINOR_VERSION <= 5) && (wxRELEASE_NUMBER < 3)
46 /* Hack to detect wxWidgets 2.5 which has a different wxEntry() prototype */
47 extern int wxEntry( HINSTANCE hInstance, HINSTANCE hPrevInstance = NULL,
48                     char *pCmdLine = NULL, int nCmdShow = SW_NORMAL );
49 #endif
50 #endif
51
52 /*****************************************************************************
53  * Local prototypes.
54  *****************************************************************************/
55 static int  Open         ( vlc_object_t * );
56 static void Close        ( vlc_object_t * );
57 static int  OpenDialogs  ( vlc_object_t * );
58
59 static void Run          ( intf_thread_t * );
60 static void Init         ( intf_thread_t * );
61
62 static void ShowDialog   ( intf_thread_t *, int, int, intf_dialog_args_t * );
63
64 #if (wxCHECK_VERSION(2,5,0))
65 void *wxClassInfo_sm_classTable_BUGGY = 0;
66 #endif
67
68 /*****************************************************************************
69  * Local classes declarations.
70  *****************************************************************************/
71 class Instance: public wxApp
72 {
73 public:
74     Instance();
75     Instance( intf_thread_t *_p_intf );
76
77     bool OnInit();
78     int  OnExit();
79
80 private:
81     intf_thread_t *p_intf;
82     wxLocale locale;                                /* locale we'll be using */
83 };
84
85 /*****************************************************************************
86  * Module descriptor
87  *****************************************************************************/
88 #define EMBED_TEXT N_("Embed video in interface")
89 #define EMBED_LONGTEXT N_("Embed the video inside the interface instead " \
90     "of having it in a separate window.")
91 #define BOOKMARKS_TEXT N_("Bookmarks dialog")
92 #define BOOKMARKS_LONGTEXT N_("Show bookmarks dialog at startup" )
93 #define EXTENDED_TEXT N_("Extended GUI")
94 #define EXTENDED_LONGTEXT N_("Show extended GUI (equalizer, image adjust, "  \
95               "video filters...) at startup"  )
96 #define TASKBAR_TEXT N_("Taskbar")
97 #define TASKBAR_LONGTEXT N_("Show VLC on the taskbar")
98 #define MINIMAL_TEXT N_("Minimal interface")
99 #define MINIMAL_LONGTEXT N_("Use minimal interface, with no toolbar and " \
100                 "fewer menus.")
101 #define SIZE_TO_VIDEO_TEXT N_("Size to video")
102 #define SIZE_TO_VIDEO_LONGTEXT N_("Resize VLC to match the video resolution.")
103 #define SYSTRAY_TEXT N_("Systray icon")
104 #define SYSTRAY_LONGTEXT N_("Show a systray icon for VLC")
105 #define LABEL_TEXT N_("Show labels in toolbar")
106 #define LABEL_LONGTEXT N_("Show labels below the icons in the toolbar.")
107
108 #define PLAYLIST_TEXT N_("Playlist view" )
109 #define PLAYLIST_LONGTEXT N_("There are two possible playlist views in the " \
110                 "interface : the normal playlist (separate window), or an " \
111                 "embedded playlist (within the main interface, but with " \
112                 "less features). You can select which one will be available " \
113                 "on the toolbar (or both)." )
114
115 static int pi_playlist_views[] = { 0,1,2 };
116 static const char *psz_playlist_views[] = { N_("Normal" ), N_("Embedded" ) ,
117                                             N_("Both") };
118
119 vlc_module_begin();
120     int i_score = 150;
121     set_shortname( (char*) "wxWidgets" );
122     set_description( (char *) _("wxWidgets interface module") );
123     set_category( CAT_INTERFACE );
124     set_subcategory( SUBCAT_INTERFACE_MAIN );
125     set_capability( "interface", i_score );
126     set_callbacks( Open, Close );
127     add_shortcut( "wxwindows" );
128     add_shortcut( "wxwin" );
129     add_shortcut( "wx" );
130     add_shortcut( "wxwidgets" );
131
132     add_bool( "wx-embed", 1, NULL,
133               EMBED_TEXT, EMBED_LONGTEXT, false );
134         add_deprecated_alias( "wxwin-enbed" ); /*Deprecated since 0.8.4*/
135     add_bool( "wx-bookmarks", 0, NULL,
136               BOOKMARKS_TEXT, BOOKMARKS_LONGTEXT, false );
137         add_deprecated_alias( "wxwin-bookmarks" ); /*Deprecated since 0.8.4*/
138     add_bool( "wx-taskbar", 1, NULL,
139               TASKBAR_TEXT, TASKBAR_LONGTEXT, false );
140         add_deprecated_alias( "wxwin-taskbar" ); /*Deprecated since 0.8.4*/
141     add_bool( "wx-extended", 0, NULL,
142               EXTENDED_TEXT, EXTENDED_LONGTEXT, false );
143     add_bool( "wx-minimal", 0, NULL,
144               MINIMAL_TEXT, MINIMAL_LONGTEXT, true );
145         add_deprecated_alias( "wxwin-minimal" ); /*Deprecated since 0.8.4*/
146     add_bool( "wx-autosize", 1, NULL,
147               SIZE_TO_VIDEO_TEXT, SIZE_TO_VIDEO_LONGTEXT, true );
148         add_deprecated_alias( "wxwin-autosize" ); /*Deprecated since 0.8.4*/
149     add_integer( "wx-playlist-view", 0, NULL, PLAYLIST_TEXT, PLAYLIST_LONGTEXT,
150              false );
151         change_integer_list( pi_playlist_views, psz_playlist_views, 0 );
152 /* wxCocoa pretends to support this, but at least 2.6.x doesn't */
153 #ifndef __APPLE__
154 #ifdef wxHAS_TASK_BAR_ICON
155     add_bool( "wx-systray", 0, NULL,
156               SYSTRAY_TEXT, SYSTRAY_LONGTEXT, false );
157         add_deprecated_alias( "wxwin-systray" ); /*Deprecated since 0.8.4*/
158 #endif
159 #endif
160     add_bool( "wx-labels", 0, NULL, LABEL_TEXT, LABEL_LONGTEXT, true);
161     add_string( "wx-config-last", NULL, NULL,
162                 N_("last config"), N_("last config"), true );
163         change_autosave();
164         change_internal();
165         add_deprecated_alias( "wxwin-config-last" ); /*Deprecated since 0.8.4*/
166
167     add_submodule();
168     set_description( _("wxWidgets dialogs provider") );
169     set_capability( "dialogs provider", 50 );
170     set_callbacks( OpenDialogs, Close );
171
172 #if !defined(WIN32)
173     linked_with_a_crap_library_which_uses_atexit();
174 #endif
175 vlc_module_end();
176
177 /*****************************************************************************
178  * Open: initialize and create window
179  *****************************************************************************/
180 static int Open( vlc_object_t *p_this )
181 {
182     intf_thread_t *p_intf = (intf_thread_t *)p_this;
183     /* Test in we have an X*/
184 #if defined HAVE_GETENV && (defined __WXGTK__ || defined __WXX11)
185     if( !getenv( "DISPLAY" ) )
186     {
187         msg_Err( p_intf, "no X server");
188         return VLC_EGENERIC;
189     }
190 #endif
191     /* Allocate instance and initialize some members */
192     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
193     if( p_intf->p_sys == NULL )
194     {
195         msg_Err( p_intf, "out of memory" );
196         return VLC_ENOMEM;
197     }
198     memset( p_intf->p_sys, 0, sizeof( intf_sys_t ) );
199
200     p_intf->pf_run = Run;
201
202     p_intf->p_sys->p_sub = msg_Subscribe( p_intf, MSG_QUEUE_NORMAL );
203
204     /* Initialize wxWidgets thread */
205     p_intf->p_sys->b_playing = 0;
206
207     p_intf->p_sys->p_input = NULL;
208     p_intf->p_sys->i_playing = -1;
209
210     p_intf->p_sys->p_popup_menu = NULL;
211     p_intf->p_sys->p_video_window = NULL;
212
213     p_intf->pf_show_dialog = NULL;
214
215     /* We support play on start */
216     p_intf->b_play = true;
217
218     p_intf->p_sys->b_video_autosize =
219         config_GetInt( p_intf, "wx-autosize" );
220
221     return VLC_SUCCESS;
222 }
223
224 static int OpenDialogs( vlc_object_t *p_this )
225 {
226     intf_thread_t *p_intf = (intf_thread_t *)p_this;
227     int i_ret = Open( p_this );
228
229     p_intf->pf_show_dialog = ShowDialog;
230
231     return i_ret;
232 }
233
234 /*****************************************************************************
235  * Close: destroy interface window
236  *****************************************************************************/
237 static void Close( vlc_object_t *p_this )
238 {
239     intf_thread_t *p_intf = (intf_thread_t *)p_this;
240
241     vlc_mutex_lock( &p_intf->object_lock );
242     p_intf->b_dead = true;
243     vlc_mutex_unlock( &p_intf->object_lock );
244
245     if( p_intf->pf_show_dialog )
246     {
247         /* We must destroy the dialogs thread */
248         wxCommandEvent event( wxEVT_DIALOG, INTF_DIALOG_EXIT );
249         p_intf->p_sys->p_wxwindow->AddPendingEvent( event );
250         vlc_thread_join( p_intf );
251     }
252
253     msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
254
255     /* */
256     delete p_intf->p_sys->p_window_settings;
257
258 #if (wxCHECK_VERSION(2,5,0))
259     wxClassInfo::sm_classTable = (wxHashTable*)wxClassInfo_sm_classTable_BUGGY;
260 #endif
261
262     /* Destroy structure */
263     free( p_intf->p_sys );
264 }
265
266 /*****************************************************************************
267  * Run: wxWidgets thread
268  *****************************************************************************/
269
270 //when is this called?
271 #if !defined(__BUILTIN__) && defined( WIN32 )
272 HINSTANCE hInstance = 0;
273 extern "C" BOOL WINAPI
274 DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
275 {
276     hInstance = (HINSTANCE)hModule;
277     return TRUE;
278 }
279 #endif
280
281 static void Run( intf_thread_t *p_intf )
282 {
283     if( p_intf->pf_show_dialog )
284     {
285         /* The module is used in dialog provider mode */
286
287         /* Create a new thread for wxWidgets */
288         if( vlc_thread_create( p_intf, "Skins Dialogs Thread",
289                                Init, 0, true ) )
290         {
291             msg_Err( p_intf, "cannot create Skins Dialogs Thread" );
292             p_intf->pf_show_dialog = NULL;
293         }
294     }
295     else
296     {
297         /* The module is used in interface mode */
298         Init( p_intf );
299     }
300 }
301
302 static void Init( intf_thread_t *p_intf )
303 {
304 #if !defined( WIN32 )
305     static char  *p_args[] = { "" };
306     int i_args = 1;
307 #endif
308
309     /* Hack to pass the p_intf pointer to the new wxWidgets Instance object */
310 #ifdef wxTheApp
311     wxApp::SetInstance( new Instance( p_intf ) );
312 #else
313     wxTheApp = new Instance( p_intf );
314 #endif
315
316 #if defined( WIN32 )
317 #if !defined(__BUILTIN__)
318
319     //because no one knows when DllMain is called
320     if (hInstance == NULL)
321       hInstance = GetModuleHandle(NULL);
322
323     wxEntry( hInstance/*GetModuleHandle(NULL)*/, NULL, NULL, SW_SHOW );
324 #else
325     wxEntry( GetModuleHandle(NULL), NULL, NULL, SW_SHOW );
326 #endif
327 #else
328     wxEntry( i_args, p_args );
329 #endif
330 }
331
332 /* following functions are local */
333
334 /*****************************************************************************
335  * Constructors.
336  *****************************************************************************/
337 Instance::Instance( )
338 {
339 }
340
341 Instance::Instance( intf_thread_t *_p_intf )
342 {
343     /* Initialization */
344     p_intf = _p_intf;
345 }
346
347 IMPLEMENT_APP_NO_MAIN(Instance)
348
349 /*****************************************************************************
350  * Instance::OnInit: the parent interface execution starts here
351  *****************************************************************************
352  * This is the "main program" equivalent, the program execution will
353  * start here.
354  *****************************************************************************/
355 bool Instance::OnInit()
356 {
357     /* Initialization of i18n stuff.
358      * Usefull for things we don't have any control over, like wxWidgets
359      * provided facilities (eg. open file dialog) */
360     locale.Init( wxLANGUAGE_DEFAULT, wxLOCALE_LOAD_DEFAULT );
361
362     /* Load saved window settings */
363     p_intf->p_sys->p_window_settings = new WindowSettings( p_intf );
364
365     /* Make an instance of your derived frame. Passing NULL (the default value
366      * of Frame's constructor is NULL) as the frame doesn't have a parent
367      * since it is the first window */
368
369     if( !p_intf->pf_show_dialog )
370     {
371         /* The module is used in interface mode */
372         long style = wxDEFAULT_FRAME_STYLE;
373         if ( ! config_GetInt( p_intf, "wx-taskbar" ) )
374         {
375             style = wxDEFAULT_FRAME_STYLE|wxFRAME_NO_TASKBAR;
376         }
377
378         Interface *MainInterface = new Interface( p_intf, style );
379         p_intf->p_sys->p_wxwindow = MainInterface;
380
381         /* Show the interface */
382         MainInterface->Show( TRUE );
383         SetTopWindow( MainInterface );
384         MainInterface->Raise();
385     }
386
387     /* Creates the dialogs provider */
388     p_intf->p_sys->p_wxwindow =
389         CreateDialogsProvider( p_intf, p_intf->pf_show_dialog ?
390                                NULL : p_intf->p_sys->p_wxwindow );
391
392     p_intf->p_sys->pf_show_dialog = ShowDialog;
393
394     /* OK, initialization is over */
395     vlc_thread_ready( p_intf );
396
397     /* Check if we need to start playing */
398     if( !p_intf->pf_show_dialog && p_intf->b_play )
399     {
400         playlist_t *p_playlist =
401             (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
402                                            FIND_ANYWHERE );
403         if( p_playlist )
404         {
405             playlist_Control( p_playlist, PLAYLIST_PLAY, false );
406             vlc_object_release( p_playlist );
407         }
408     }
409
410     /* Return TRUE to tell program to continue (FALSE would terminate) */
411     return TRUE;
412 }
413
414 /*****************************************************************************
415  * Instance::OnExit: called when the interface execution stops
416  *****************************************************************************/
417 int Instance::OnExit()
418 {
419     if( p_intf->pf_show_dialog )
420     {
421          /* We need to manually clean up the dialogs class */
422          delete p_intf->p_sys->p_wxwindow;
423     }
424
425 #if (wxCHECK_VERSION(2,5,0))
426     wxClassInfo_sm_classTable_BUGGY = wxClassInfo::sm_classTable;
427     wxClassInfo::sm_classTable = 0;
428 #endif
429
430     return 0;
431 }
432
433 static void ShowDialog( intf_thread_t *p_intf, int i_dialog_event, int i_arg,
434                         intf_dialog_args_t *p_arg )
435 {
436     wxCommandEvent event( wxEVT_DIALOG, i_dialog_event );
437     event.SetInt( i_arg );
438     event.SetClientData( p_arg );
439
440 #ifdef WIN32
441     SendMessage( (HWND)p_intf->p_sys->p_wxwindow->GetHandle(),
442                  WM_CANCELMODE, 0, 0 );
443 #endif
444     if( i_dialog_event == INTF_DIALOG_POPUPMENU && i_arg == 0 ) return;
445
446     /* Hack to prevent popup events to be enqueued when
447      * one is already active */
448     if( i_dialog_event != INTF_DIALOG_POPUPMENU ||
449         !p_intf->p_sys->p_popup_menu )
450     {
451         p_intf->p_sys->p_wxwindow->AddPendingEvent( event );
452     }
453 }
454
455 /*****************************************************************************
456  * WindowSettings utility class
457  *****************************************************************************/
458 WindowSettings::WindowSettings( intf_thread_t *_p_intf )
459 {
460     char *psz_org = NULL;
461     char *psz;
462     int i;
463
464     /* */
465     p_intf = _p_intf;
466
467     /* */
468     for( i = 0; i < ID_MAX; i++ )
469     {
470         b_valid[i] = false;
471         b_shown[i] = false;
472         position[i] = wxDefaultPosition;
473         size[i] = wxDefaultSize;
474     }
475     b_shown[ID_MAIN] = true;
476
477     if( p_intf->pf_show_dialog ) return;
478
479     /* Parse the configuration */
480     psz_org = psz = config_GetPsz( p_intf, "wx-config-last" );
481     if( !psz || *psz == '\0' ) return;
482
483     msg_Dbg( p_intf, "Using last windows config '%s'", psz );
484
485     i_screen_w = 0;
486     i_screen_h = 0;
487     while( psz && *psz )
488     {
489         int id, v[4];
490
491         psz = strchr( psz, '(' );
492
493         if( !psz )
494             break;
495         psz++;
496
497         id = strtol( psz, &psz, 0 );
498         if( *psz != ',' ) /* broken cfg */
499         {
500             goto invalid;
501         }
502         psz++;
503
504         for( i = 0; i < 4; i++ )
505         {
506             v[i] = strtol( psz, &psz, 0 );
507
508             if( i < 3 )
509             {
510                 if( *psz != ',' )
511                 {
512                     goto invalid;
513                 }
514                 psz++;
515             }
516             else
517             {
518                 if( *psz != ')' )
519                 {
520                     goto invalid;
521                 }
522             }
523         }
524         if( id == ID_SCREEN )
525         {
526             i_screen_w = v[2];
527             i_screen_h = v[3];
528         }
529         else if( id >= 0 && id < ID_MAX )
530         {
531             b_valid[id] = true;
532             b_shown[id] = true;
533             position[id] = wxPoint( v[0], v[1] );
534             size[id] = wxSize( v[2], v[3] );
535
536             msg_Dbg( p_intf, "id=%d p=(%d,%d) s=(%d,%d)",
537                      id, position[id].x, position[id].y,
538                          size[id].x, size[id].y );
539         }
540
541         psz = strchr( psz, ')' );
542         if( psz ) psz++;
543     }
544
545     if( i_screen_w <= 0 || i_screen_h <= 0 )
546     {
547         goto invalid;
548     }
549
550     for( i = 0; i < ID_MAX; i++ )
551     {
552         if( !b_valid[i] )
553             continue;
554         if( position[i].x < 0 || position[i].y < 0 )
555         {
556             goto invalid;
557         }
558         if( i != ID_SMALL_PLAYLIST && (size[i].x <= 0 || size[i].y <= 0)  )
559         {
560             goto invalid;
561         }
562     }
563
564     free( psz_org );
565     return;
566
567 invalid:
568     msg_Dbg( p_intf, "last windows config is invalid (ignored)" );
569     for( i = 0; i < ID_MAX; i++ )
570     {
571         b_valid[i] = false;
572         b_shown[i] = false;
573         position[i] = wxDefaultPosition;
574         size[i] = wxDefaultSize;
575     }
576     free( psz_org );
577 }
578
579
580 WindowSettings::~WindowSettings( )
581 {
582     wxString sCfg;
583
584     if( p_intf->pf_show_dialog ) return;
585
586     sCfg = wxString::Format( wxT("(%d,0,0,%d,%d)"), ID_SCREEN,
587                              wxSystemSettings::GetMetric( wxSYS_SCREEN_X ),
588                              wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ) );
589     for( int i = 0; i < ID_MAX; i++ )
590     {
591         if( !b_valid[i] || !b_shown[i] )
592             continue;
593
594         sCfg += wxString::Format( wxT("(%d,%d,%d,%d,%d)"),
595                                   i, position[i].x, position[i].y,
596                                      size[i].x, size[i].y );
597     }
598
599     config_PutPsz( p_intf, "wx-config-last", sCfg.mb_str(wxConvUTF8) );
600 }
601
602 void WindowSettings::SetScreen( int i_screen_w, int i_screen_h )
603 {
604     int i;
605
606     for( i = 0; i < ID_MAX; i++ )
607     {
608         if( !b_valid[i] )
609             continue;
610         if( position[i].x >= i_screen_w || position[i].y >= i_screen_h )
611             goto invalid;
612     }
613     return;
614
615 invalid:
616     for( i = 0; i < ID_MAX; i++ )
617     {
618         b_valid[i] = false;
619         b_shown[i] = false;
620         position[i] = wxDefaultPosition;
621         size[i] = wxDefaultSize;
622     }
623 }
624
625 void WindowSettings::SetSettings( int id, bool _b_shown, wxPoint p, wxSize s )
626 {
627     if( id < 0 || id >= ID_MAX )
628         return;
629
630     b_valid[id] = true;
631     b_shown[id] = _b_shown;
632
633     position[id] = p;
634     size[id] = s;
635 }
636
637 bool WindowSettings::GetSettings( int id, bool& _b_shown, wxPoint& p, wxSize& s)
638 {
639     if( id < 0 || id >= ID_MAX )
640         return false;
641
642     if( !b_valid[id] )
643         return false;
644
645     _b_shown = b_shown[id];
646     p = position[id];
647     s = size[id];
648
649     return true;
650 }