playlist_CreateNode(): add an argument to specify an input_item_t to be linked with...
[vlc.git] / modules / gui / wxwidgets / video.cpp
1 /*****************************************************************************
2  * video.cpp : wxWidgets plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004, 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
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 <vlc/vlc.h>
28 #include <vlc_vout.h>
29 #include <vlc_interface.h>
30
31 #include "video.hpp"
32 #include "interface.hpp"
33
34 static void *GetWindow( intf_thread_t *p_intf, vout_thread_t *,
35                         int *pi_x_hint, int *pi_y_hint,
36                         unsigned int *pi_width_hint,
37                         unsigned int *pi_height_hint );
38
39 static void ReleaseWindow( intf_thread_t *p_intf, void *p_window );
40
41 static int ControlWindow( intf_thread_t *p_intf, void *p_window,
42                           int i_query, va_list args );
43
44 /* IDs for the controls and the menu commands */
45 enum
46 {
47     UpdateSize_Event = wxID_HIGHEST + 1,
48     UpdateHide_Event,
49     SetStayOnTop_Event,
50     ID_HIDE_TIMER
51 };
52
53 DEFINE_LOCAL_EVENT_TYPE( wxEVT_VLC_VIDEO );
54
55 BEGIN_EVENT_TABLE(VideoWindow, wxWindow)
56     EVT_CUSTOM( wxEVT_SIZE, UpdateSize_Event, VideoWindow::UpdateSize )
57     EVT_CUSTOM( wxEVT_SIZE, UpdateHide_Event, VideoWindow::UpdateHide )
58     EVT_COMMAND( SetStayOnTop_Event, wxEVT_VLC_VIDEO,
59                  VideoWindow::OnControlEvent )
60     EVT_TIMER( ID_HIDE_TIMER, VideoWindow::OnHideTimer )
61 END_EVENT_TABLE()
62
63 /*****************************************************************************
64  * Public methods.
65  *****************************************************************************/
66 wxWindow *CreateVideoWindow( intf_thread_t *p_intf, wxWindow *p_parent )
67 {
68     return new VideoWindow( p_intf, p_parent );
69 }
70
71 void UpdateVideoWindow( intf_thread_t *p_intf, wxWindow *p_window )
72 {
73 #if wxCHECK_VERSION(2,5,3)
74     if( !p_intf->p_sys->b_video_autosize ) return;
75
76     if( p_window && mdate() - ((VideoWindow *)p_window)->i_creation_date < 2000000 )
77         return; /* Hack to prevent saving coordinates if window is not yet
78                  * properly created. Yuck :( */
79
80     if( p_window && p_intf->p_sys->p_video_sizer && p_window->IsShown() )
81         p_intf->p_sys->p_video_sizer->SetMinSize( p_window->GetSize() );
82 #endif
83 }
84
85 /*****************************************************************************
86  * Constructor.
87  *****************************************************************************/
88 VideoWindow::VideoWindow( intf_thread_t *_p_intf, wxWindow *_p_parent ):
89   wxWindow( _p_parent, -1, wxDefaultPosition, wxDefaultSize, wxCLIP_CHILDREN )
90 {
91     /* Initializations */
92     p_intf = _p_intf;
93     p_parent = _p_parent;
94     p_child_window = 0;
95
96     vlc_mutex_init( p_intf, &lock );
97
98     b_auto_size = p_intf->p_sys->b_video_autosize;
99
100     p_vout = NULL;
101     i_creation_date = 0;
102     m_hide_timer.SetOwner( this, ID_HIDE_TIMER );
103
104     p_intf->pf_request_window = ::GetWindow;
105     p_intf->pf_release_window = ::ReleaseWindow;
106     p_intf->pf_control_window = ::ControlWindow;
107
108     p_intf->p_sys->p_video_window = this;
109
110     wxSize child_size = wxSize(0,0);
111     if( !b_auto_size )
112     {
113         WindowSettings *ws = p_intf->p_sys->p_window_settings;
114         wxPoint p; bool b_shown;
115
116         // Maybe this size should be an option
117         child_size = wxSize( wxSystemSettings::GetMetric(wxSYS_SCREEN_X) / 2,
118                              wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) / 2 );
119
120         ws->GetSettings( WindowSettings::ID_VIDEO, b_shown, p, child_size );
121         SetSize( child_size );
122     }
123
124 #ifdef __WXGTK__
125     p_child_window = new wxWindow( this, -1, wxDefaultPosition, child_size,
126                                    wxCLIP_CHILDREN );
127 #endif
128
129     if( !b_auto_size )
130     {
131         SetBackgroundColour( *wxBLACK );
132         if( p_child_window ) p_child_window->SetBackgroundColour( *wxBLACK );
133     }
134
135     if( p_child_window ) p_child_window->Show();
136     Show();
137     b_shown = VLC_TRUE;
138
139     p_intf->p_sys->p_video_sizer = new wxBoxSizer( wxHORIZONTAL );
140 #if (wxCHECK_VERSION(2,5,3))
141     p_intf->p_sys->p_video_sizer->Add( this, 1, wxEXPAND|wxFIXED_MINSIZE );
142 #else
143     p_intf->p_sys->p_video_sizer->Add( this, 1, wxEXPAND );
144 #endif
145
146     ReleaseWindow( NULL );
147 }
148
149 VideoWindow::~VideoWindow()
150 {
151     vlc_mutex_lock( &lock );
152     if( p_vout )
153     {
154         if( !p_intf->psz_switch_intf )
155         {
156             if( vout_Control( p_vout, VOUT_CLOSE ) != VLC_SUCCESS )
157                 vout_Control( p_vout, VOUT_REPARENT, 0 );
158         }
159         else
160         {
161             if( vout_Control( p_vout, VOUT_REPARENT, 0 ) != VLC_SUCCESS )
162                 vout_Control( p_vout, VOUT_CLOSE );
163         }
164     }
165
166     p_intf->pf_request_window = NULL;
167     p_intf->pf_release_window = NULL;
168     p_intf->pf_control_window = NULL;
169     vlc_mutex_unlock( &lock );
170
171     if( !b_auto_size )
172     {
173         WindowSettings *ws = p_intf->p_sys->p_window_settings;
174         ws->SetSettings( WindowSettings::ID_VIDEO, true,
175                          GetPosition(), GetSize() );
176     }
177
178     vlc_mutex_destroy( &lock );
179 }
180
181 /*****************************************************************************
182  * Private methods.
183  *****************************************************************************/
184 static void *GetWindow( intf_thread_t *p_intf, vout_thread_t *p_vout,
185                         int *pi_x_hint, int *pi_y_hint,
186                         unsigned int *pi_width_hint,
187                         unsigned int *pi_height_hint )
188 {
189     return p_intf->p_sys->p_video_window->GetWindow( p_vout,
190                                                      pi_x_hint, pi_y_hint,
191                                                      pi_width_hint,
192                                                      pi_height_hint );
193 }
194
195 /* Part of the hack to get the X11 window handle from the GtkWidget */
196 #ifdef __WXGTK__
197 extern "C" {
198 #ifdef __WXGTK20__
199     int gdk_x11_drawable_get_xid( void * );
200 #endif
201     void *gtk_widget_get_parent_window( void * );
202 }
203 #endif
204
205 void *VideoWindow::GetWindow( vout_thread_t *_p_vout,
206                               int *pi_x_hint, int *pi_y_hint,
207                               unsigned int *pi_width_hint,
208                               unsigned int *pi_height_hint )
209 {
210 #if defined(__WXGTK__) || defined(WIN32)
211     vlc_mutex_lock( &lock );
212
213     if( p_vout )
214     {
215         vlc_mutex_unlock( &lock );
216         msg_Dbg( p_intf, "video window already in use" );
217         return NULL;
218     }
219
220     p_vout = _p_vout;
221
222     wxSizeEvent event( wxSize(*pi_width_hint, *pi_height_hint),
223                        UpdateSize_Event );
224     AddPendingEvent( event );
225     vlc_mutex_unlock( &lock );
226
227 #ifdef __WXGTK__
228     GtkWidget *p_widget = p_child_window->GetHandle();
229
230 #ifdef __WXGTK20__
231     return (void *)gdk_x11_drawable_get_xid(
232                gtk_widget_get_parent_window( p_widget ) );
233 #elif defined(__WXGTK__)
234     return (void *)*(int *)( (char *)gtk_widget_get_parent_window( p_widget )
235                + 2 * sizeof(void *) );
236 #endif
237
238 #elif defined(WIN32)
239     return (void*)GetHandle();
240
241 #endif
242
243 #else // defined(__WXGTK__) || defined(WIN32)
244     return NULL;
245
246 #endif
247 }
248
249 static void ReleaseWindow( intf_thread_t *p_intf, void *p_window )
250 {
251     return p_intf->p_sys->p_video_window->ReleaseWindow( p_window );
252 }
253
254 void VideoWindow::ReleaseWindow( void *p_window )
255 {
256     vlc_mutex_lock( &lock );
257     p_vout = NULL;
258     vlc_mutex_unlock( &lock );
259
260     if( !b_auto_size ) return;
261
262 #if defined(__WXGTK__) || defined(WIN32)
263     wxSizeEvent event( wxSize(0, 0), UpdateHide_Event );
264     AddPendingEvent( event );
265 #endif
266 }
267
268 void VideoWindow::UpdateSize( wxEvent &_event )
269 {
270     m_hide_timer.Stop();
271
272     if( !b_auto_size ) return;
273
274     wxSizeEvent * event = (wxSizeEvent*)(&_event);
275     if( !b_shown )
276     {
277         p_intf->p_sys->p_video_sizer->Show( this, TRUE );
278         p_intf->p_sys->p_video_sizer->Layout();
279         SetFocus();
280         b_shown = VLC_TRUE;
281     }
282
283     p_intf->p_sys->p_video_sizer->SetMinSize( event->GetSize() );
284
285     i_creation_date = mdate();
286     wxCommandEvent intf_event( wxEVT_INTF, 0 );
287     p_parent->AddPendingEvent( intf_event );
288 }
289
290 void VideoWindow::UpdateHide( wxEvent &_event )
291 {
292     if( b_auto_size ) m_hide_timer.Start( 200, wxTIMER_ONE_SHOT );
293 }
294
295 void VideoWindow::OnHideTimer( wxTimerEvent& WXUNUSED(event))
296 {
297     if( b_shown )
298     {
299         p_intf->p_sys->p_video_sizer->Show( this, FALSE );
300         SetSize( 0, 0 );
301         p_intf->p_sys->p_video_sizer->Layout();
302         b_shown = VLC_FALSE;
303     }
304     p_intf->p_sys->p_video_sizer->SetMinSize( wxSize(0,0) );
305
306     wxCommandEvent intf_event( wxEVT_INTF, 0 );
307     p_parent->AddPendingEvent( intf_event );
308 }
309
310 void VideoWindow::OnControlEvent( wxCommandEvent &event )
311 {
312     switch( event.GetId() )
313     {
314     case SetStayOnTop_Event:
315         wxCommandEvent intf_event( wxEVT_INTF, 1 );
316         intf_event.SetInt( event.GetInt() );
317         p_parent->AddPendingEvent( intf_event );
318         break;
319     }
320 }
321
322 static int ControlWindow( intf_thread_t *p_intf, void *p_window,
323                           int i_query, va_list args )
324 {
325     return p_intf->p_sys->p_video_window->ControlWindow( p_window, i_query,
326                                                          args );
327 }
328
329 int VideoWindow::ControlWindow( void *p_window, int i_query, va_list args )
330 {
331     int i_ret = VLC_EGENERIC;
332
333     vlc_mutex_lock( &lock );
334
335     switch( i_query )
336     {
337         case VOUT_GET_SIZE:
338         {
339             unsigned int *pi_width  = va_arg( args, unsigned int * );
340             unsigned int *pi_height = va_arg( args, unsigned int * );
341
342             *pi_width = GetSize().GetWidth();
343             *pi_height = GetSize().GetHeight();
344             i_ret = VLC_SUCCESS;
345         }
346         break;
347
348         case VOUT_SET_SIZE:
349         {
350             if( !b_auto_size ) break;
351
352             unsigned int i_width  = va_arg( args, unsigned int );
353             unsigned int i_height = va_arg( args, unsigned int );
354
355             if( !i_width && p_vout ) i_width = p_vout->i_window_width;
356             if( !i_height && p_vout ) i_height = p_vout->i_window_height;
357
358             /* Update dimensions */
359             wxSizeEvent event( wxSize( i_width, i_height ), UpdateSize_Event );
360
361             AddPendingEvent( event );
362
363             i_ret = VLC_SUCCESS;
364         }
365         break;
366
367         case VOUT_SET_STAY_ON_TOP:
368         {
369             int i_arg = va_arg( args, int );
370             wxCommandEvent event( wxEVT_VLC_VIDEO, SetStayOnTop_Event );
371             event.SetInt( i_arg );
372             AddPendingEvent( event );
373
374             i_ret = VLC_SUCCESS;
375         }
376         break;
377
378         default:
379             msg_Dbg( p_intf, "control query not supported" );
380             break;
381     }
382
383     vlc_mutex_unlock( &lock );
384
385     return i_ret;
386 }