1 /*****************************************************************************
\r
2 * mainframe.cpp: Win32 interface plugin for vlc
\r
3 *****************************************************************************
\r
4 * Copyright (C) 2002 VideoLAN
\r
6 * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
\r
8 * This program is free software; you can redistribute it and/or modify
\r
9 * it under the terms of the GNU General Public License as published by
\r
10 * the Free Software Foundation; either version 2 of the License, or
\r
11 * (at your option) any later version.
\r
13 * This program is distributed in the hope that it will be useful,
\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 * GNU General Public License for more details.
\r
18 * You should have received a copy of the GNU General Public License
\r
19 * along with this program; if not, write to the Free Software
\r
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
\r
21 *****************************************************************************/
\r
26 #include <vlc/vlc.h>
\r
27 #include <vlc/intf.h>
\r
28 #include <vlc/vout.h>
\r
30 #include "dragdrop.h"
\r
31 #include "mainframe.h"
\r
34 #include "network.h"
\r
36 #include "preferences.h"
\r
37 #include "messages.h"
\r
38 #include "playlist.h"
\r
40 #include "win32_common.h"
\r
42 #include "netutils.h"
\r
44 //---------------------------------------------------------------------------
\r
45 #pragma link "CSPIN"
\r
46 #pragma resource "*.dfm"
\r
48 extern int Win32Manage( intf_thread_t *p_intf );
\r
50 //---------------------------------------------------------------------------
\r
51 __fastcall TMainFrameDlg::TMainFrameDlg(
\r
52 TComponent* Owner, intf_thread_t *_p_intf ) : TForm( Owner )
\r
56 Application->ShowHint = true;
\r
57 Application->OnHint = DisplayHint;
\r
59 TimerManage->Interval = INTF_IDLE_SLEEP / 1000;
\r
61 TrackBar->Max = SLIDER_MAX_VALUE;
\r
63 /* default height and caption */
\r
64 ClientHeight = 37 + ToolBar->Height;
\r
65 Caption = VOUT_TITLE " (Win32 interface)";
\r
67 StringListPref = new TStringList();
\r
71 /* drag and drop stuff */
\r
73 /* initialize the OLE library */
\r
74 OleInitialize( NULL );
\r
75 /* TDropTarget will send the WM_OLEDROP message to the form */
\r
76 lpDropTarget = (LPDROPTARGET)new TDropTarget( this->Handle );
\r
77 CoLockObjectExternal( lpDropTarget, true, true );
\r
78 /* register the form as a drop target */
\r
79 RegisterDragDrop( this->Handle, lpDropTarget );
\r
81 //---------------------------------------------------------------------------
\r
82 __fastcall TMainFrameDlg::~TMainFrameDlg()
\r
84 delete StringListPref;
\r
86 //---------------------------------------------------------------------------
\r
89 /*****************************************************************************
\r
91 ****************************************************************************/
\r
92 void __fastcall TMainFrameDlg::TimerManageTimer( TObject *Sender )
\r
94 Win32Manage( p_intf );
\r
96 //---------------------------------------------------------------------------
\r
97 void __fastcall TMainFrameDlg::DisplayHint( TObject *Sender )
\r
99 StatusBar->SimpleText = GetLongHint( Application->Hint );
\r
101 //---------------------------------------------------------------------------
\r
102 void __fastcall TMainFrameDlg::TrackBarChange( TObject *Sender )
\r
104 /* This function displays the current date related to the position in
\r
105 * the stream. It is called whenever the slider changes its value.
\r
106 * The lock has to be taken before the function is called */
\r
108 if( p_intf->p_sys->p_input != NULL )
\r
110 #define p_area p_intf->p_sys->p_input->stream.p_selected_area
\r
111 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
\r
112 off_t Value = TrackBar->Position;
\r
114 GroupBoxSlider->Caption =
\r
115 input_OffsetToTime( p_intf->p_sys->p_input, psz_time,
\r
116 ( p_area->i_size * Value ) / (off_t)SLIDER_MAX_VALUE );
\r
120 //---------------------------------------------------------------------------
\r
121 void __fastcall TMainFrameDlg::FormClose( TObject *Sender,
\r
122 TCloseAction &Action )
\r
124 vlc_mutex_lock( &p_intf->change_lock );
\r
125 p_intf->p_vlc->b_die = VLC_TRUE;
\r
126 vlc_mutex_unlock( &p_intf->change_lock );
\r
128 /* remove the form from the list of drop targets */
\r
129 RevokeDragDrop( this->Handle );
\r
130 lpDropTarget->Release();
\r
131 CoLockObjectExternal( lpDropTarget, false, true );
\r
133 /* uninitialize the OLE library */
\r
136 /* we don't destroy the form immediatly */
\r
139 //---------------------------------------------------------------------------
\r
142 /*****************************************************************************
\r
144 ****************************************************************************/
\r
145 void __fastcall TMainFrameDlg::OpenFileActionExecute( TObject *Sender )
\r
147 if( OpenDialog1->Execute() )
\r
149 /* add the new file to the interface playlist */
\r
150 p_intf->p_sys->p_playwin->Add( OpenDialog1->FileName,
\r
151 PLAYLIST_APPEND | PLAYLIST_GO,
\r
155 //---------------------------------------------------------------------------
\r
156 void __fastcall TMainFrameDlg::OpenDiscActionExecute( TObject *Sender )
\r
158 TDiscDlg *p_disc = p_intf->p_sys->p_disc;
\r
159 if( p_disc == NULL )
\r
161 p_disc = new TDiscDlg( this, p_intf );
\r
162 p_intf->p_sys->p_disc = p_disc;
\r
166 //---------------------------------------------------------------------------
\r
167 void __fastcall TMainFrameDlg::NetworkStreamActionExecute( TObject *Sender )
\r
169 TNetworkDlg *p_network = p_intf->p_sys->p_network;
\r
170 if( p_network == NULL )
\r
172 p_network = new TNetworkDlg( this, p_intf );
\r
173 p_intf->p_sys->p_network = p_network;
\r
177 //---------------------------------------------------------------------------
\r
178 void __fastcall TMainFrameDlg::ExitActionExecute( TObject *Sender )
\r
182 //---------------------------------------------------------------------------
\r
183 void __fastcall TMainFrameDlg::FullscreenActionExecute( TObject *Sender )
\r
185 vout_thread_t *p_vout;
\r
187 p_vout = (vout_thread_t *)vlc_object_find( p_intf->p_sys->p_input,
\r
188 VLC_OBJECT_VOUT, FIND_CHILD );
\r
189 if( p_vout == NULL )
\r
194 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
\r
195 vlc_object_release( p_vout );
\r
197 //---------------------------------------------------------------------------
\r
198 void __fastcall TMainFrameDlg::PlaylistActionExecute( TObject *Sender )
\r
200 TPlaylistDlg *p_playwin = p_intf->p_sys->p_playwin;
\r
201 if( p_playwin->Visible )
\r
207 p_playwin->UpdateGrid();
\r
211 //---------------------------------------------------------------------------
\r
212 void __fastcall TMainFrameDlg::MessagesActionExecute( TObject *Sender )
\r
214 p_intf->p_sys->p_messages->Show();
\r
216 //---------------------------------------------------------------------------
\r
217 void __fastcall TMainFrameDlg::PreferencesActionExecute( TObject *Sender )
\r
219 CreatePreferences( "main" );
\r
221 //---------------------------------------------------------------------------
\r
222 void __fastcall TMainFrameDlg::AboutActionExecute( TObject *Sender )
\r
224 TAboutDlg *AboutDlg = new TAboutDlg( this, p_intf );
\r
225 AboutDlg->ShowModal();
\r
228 //---------------------------------------------------------------------------
\r
229 void __fastcall TMainFrameDlg::BackActionExecute( TObject *Sender )
\r
233 //---------------------------------------------------------------------------
\r
234 void __fastcall TMainFrameDlg::PlayActionExecute( TObject *Sender )
\r
236 p_intf->p_sys->p_playwin->Play();
\r
238 //---------------------------------------------------------------------------
\r
239 void __fastcall TMainFrameDlg::PauseActionExecute( TObject *Sender )
\r
241 p_intf->p_sys->p_playwin->Pause();
\r
243 //---------------------------------------------------------------------------
\r
244 void __fastcall TMainFrameDlg::StopActionExecute( TObject *Sender )
\r
246 p_intf->p_sys->p_playwin->Stop();
\r
248 //---------------------------------------------------------------------------
\r
249 void __fastcall TMainFrameDlg::SlowActionExecute( TObject *Sender )
\r
251 p_intf->p_sys->p_playwin->Slow();
\r
253 //---------------------------------------------------------------------------
\r
254 void __fastcall TMainFrameDlg::FastActionExecute( TObject *Sender )
\r
256 p_intf->p_sys->p_playwin->Fast();
\r
258 //---------------------------------------------------------------------------
\r
259 void __fastcall TMainFrameDlg::PreviousActionExecute(TObject *Sender)
\r
261 p_intf->p_sys->p_playwin->Previous();
\r
263 //---------------------------------------------------------------------------
\r
264 void __fastcall TMainFrameDlg::NextActionExecute(TObject *Sender)
\r
266 p_intf->p_sys->p_playwin->Next();
\r
268 //---------------------------------------------------------------------------
\r
269 void __fastcall TMainFrameDlg::EjectActionExecute( TObject *Sender )
\r
271 AnsiString Device = "";
\r
272 char * psz_current;
\r
273 playlist_t * p_playlist;
\r
275 p_playlist = (playlist_t *)vlc_object_find( p_intf,
\r
276 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
\r
277 if( p_playlist == NULL )
\r
283 * Get the active input
\r
284 * Determine whether we can eject a media, ie it's a VCD or DVD
\r
285 * If it's neither a VCD nor a DVD, then return
\r
288 vlc_mutex_lock( &p_playlist->object_lock );
\r
289 psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name;
\r
291 if( psz_current != NULL )
\r
293 if( strncmp( psz_current, "dvd", 3 )
\r
294 || strncmp( psz_current, "vcd", 3 ) )
\r
296 /* Determine the device name by omitting the first 4 characters
\r
297 * and keeping 3 characters */
\r
298 Device = strdup( ( psz_current + 4 ) );
\r
299 Device = Device.SubString( 1, 2 );
\r
303 vlc_mutex_unlock( &p_playlist->object_lock );
\r
304 vlc_object_release( p_playlist );
\r
311 /* If there's a stream playing, we aren't allowed to eject ! */
\r
312 if( p_intf->p_sys->p_input == NULL )
\r
314 msg_Dbg( p_intf, "ejecting %s", Device.c_str() );
\r
316 intf_Eject( p_intf, Device.c_str() );
\r
319 //--------------------------------------------------------------------------
\r
322 /*****************************************************************************
\r
323 * External drop handling
\r
324 *****************************************************************************/
\r
325 void __fastcall TMainFrameDlg::OnDrop( TMessage &Msg )
\r
327 /* find the number of files dropped */
\r
328 int num_files = DragQueryFile( (HDROP)Msg.WParam, 0xFFFFFFFF,
\r
329 (LPSTR)NULL, NULL );
\r
331 /* append each file to the playlist */
\r
332 for( int i = 0; i < num_files; i++ )
\r
334 /* find the length of the filename */
\r
335 int name_length = DragQueryFile( (HDROP)Msg.WParam, i, NULL, NULL ) + 1;
\r
337 /* get the filename */
\r
338 char *FileName = new char[name_length];
\r
339 DragQueryFile( (HDROP)Msg.WParam, i, FileName, name_length );
\r
341 /* add the new file to the playlist */
\r
342 p_intf->p_sys->p_playwin->Add( FileName, PLAYLIST_APPEND | PLAYLIST_GO,
\r
348 DragFinish( (HDROP)Msg.WParam );
\r
351 //--------------------------------------------------------------------------
\r
354 /*****************************************************************************
\r
355 * Menu and popup callbacks
\r
356 *****************************************************************************/
\r
357 void __fastcall TMainFrameDlg::MenuHideinterfaceClick( TObject *Sender )
\r
359 this->SendToBack();
\r
361 //---------------------------------------------------------------------------
\r
362 void __fastcall TMainFrameDlg::PopupToggleInterfaceClick( TObject *Sender )
\r
364 this->BringToFront();
\r
366 //---------------------------------------------------------------------------
\r
367 void __fastcall TMainFrameDlg::PopupCloseClick( TObject *Sender )
\r
369 /* We do nothing, we just need a click on a menu item
\r
370 * to close the popup. Don't ask me why... */
\r
373 //---------------------------------------------------------------------------
\r
374 void __fastcall TMainFrameDlg::PopupJumpClick( TObject *Sender )
\r
378 //---------------------------------------------------------------------------
\r
381 /*****************************************************************************
\r
382 * Callbacks for DVD/VCD navigation
\r
383 ****************************************************************************/
\r
384 void __fastcall TMainFrameDlg::PrevTitleActionExecute( TObject *Sender )
\r
386 input_area_t * p_area;
\r
389 i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1;
\r
391 /* Disallow area 0 since it is used for video_ts.vob */
\r
394 p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
\r
395 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
\r
397 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
\r
399 p_intf->p_sys->b_title_update = 1;
\r
400 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
401 p_intf->p_sys->p_menus->SetupMenus();
\r
402 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
405 //---------------------------------------------------------------------------
\r
406 void __fastcall TMainFrameDlg::NextTitleActionExecute( TObject *Sender )
\r
408 input_area_t * p_area;
\r
411 i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1;
\r
413 if( i_id < p_intf->p_sys->p_input->stream.i_area_nb )
\r
415 p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id];
\r
416 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
\r
418 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
\r
420 p_intf->p_sys->b_title_update = 1;
\r
421 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
422 p_intf->p_sys->p_menus->SetupMenus();
\r
423 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
426 //---------------------------------------------------------------------------
\r
427 void __fastcall TMainFrameDlg::PrevChapterActionExecute( TObject *Sender )
\r
429 input_area_t * p_area;
\r
431 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
\r
433 if( p_area->i_part > 0 )
\r
436 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
\r
438 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
\r
440 p_intf->p_sys->b_chapter_update = 1;
\r
441 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
442 p_intf->p_sys->p_menus->SetupMenus();
\r
443 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
446 //---------------------------------------------------------------------------
\r
447 void __fastcall TMainFrameDlg::NextChapterActionExecute( TObject *Sender )
\r
449 input_area_t * p_area;
\r
451 p_area = p_intf->p_sys->p_input->stream.p_selected_area;
\r
453 if( p_area->i_part < p_area->i_part_nb )
\r
456 input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area );
\r
458 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
\r
460 p_intf->p_sys->b_chapter_update = 1;
\r
461 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
462 p_intf->p_sys->p_menus->SetupMenus();
\r
463 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
\r
466 //---------------------------------------------------------------------------
\r
469 /*****************************************************************************
\r
470 * Callback for the 'go!' button
\r
471 ****************************************************************************/
\r
472 void __fastcall TMainFrameDlg::ButtonGoClick( TObject *Sender )
\r
476 i_channel = SpinEditChannel->Value;
\r
477 msg_Dbg( p_intf, "joining channel %d", i_channel );
\r
479 vlc_mutex_lock( &p_intf->change_lock );
\r
480 network_ChannelJoin( p_intf, i_channel );
\r
481 vlc_mutex_unlock( &p_intf->change_lock );
\r
483 // input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
\r
485 //---------------------------------------------------------------------------
\r
488 /*****************************************************************************
\r
489 * ModeManage: actualise the aspect of the interface whenever the input
\r
491 *****************************************************************************
\r
492 * The lock has to be taken before you call the function.
\r
493 *****************************************************************************/
\r
494 void __fastcall TMainFrameDlg::ModeManage()
\r
496 TGroupBox * ActiveGB;
\r
500 /* hide all boxes */
\r
501 GroupBoxFile->Visible = false;
\r
502 GroupBoxNetwork->Visible = false;
\r
503 GroupBoxDisc->Visible = false;
\r
506 GroupBoxSlider->Hide();
\r
508 /* controls unavailable */
\r
511 /* show the box related to current input mode */
\r
512 if( p_intf->p_sys->p_input != NULL )
\r
514 switch( p_intf->p_sys->p_input->stream.i_method & 0xf0 )
\r
516 case INPUT_METHOD_FILE:
\r
517 GroupBoxFile->Visible = true;
\r
518 ActiveGB = GroupBoxFile;
\r
519 LabelFileName->Caption = p_intf->p_sys->p_input->psz_source;
\r
521 case INPUT_METHOD_DISC:
\r
522 GroupBoxDisc->Visible = true;
\r
523 ActiveGB = GroupBoxDisc;
\r
525 case INPUT_METHOD_NETWORK:
\r
526 GroupBoxNetwork->Visible = true;
\r
527 ActiveGB = GroupBoxNetwork;
\r
528 LabelServer->Caption = p_intf->p_sys->p_input->psz_source;
\r
529 if( config_GetInt( p_intf, "network-channel" ) )
\r
531 LabelChannel->Visible = true;
\r
535 LabelChannel->Visible = false;
\r
539 msg_Warn( p_intf, "cannot determine input method" );
\r
540 GroupBoxFile->Visible = true;
\r
541 ActiveGB = GroupBoxFile;
\r
542 LabelFileName->Caption = p_intf->p_sys->p_input->psz_source;
\r
546 i_Height = StatusBar->Height + ActiveGB->Height + ToolBar->Height + 54;
\r
548 /* initialize and show slider for seekable streams */
\r
549 if( p_intf->p_sys->p_input->stream.b_seekable )
\r
551 TrackBar->Position = p_intf->p_sys->OldValue = 0;
\r
552 GroupBoxSlider->Show();
\r
553 i_Height += GroupBoxSlider->Height;
\r
556 /* control buttons for free pace streams */
\r
557 b_control = p_intf->p_sys->p_input->stream.b_pace_control;
\r
559 /* get ready for menu regeneration */
\r
560 p_intf->p_sys->b_program_update = 1;
\r
561 p_intf->p_sys->b_title_update = 1;
\r
562 p_intf->p_sys->b_chapter_update = 1;
\r
563 p_intf->p_sys->b_audio_update = 1;
\r
564 p_intf->p_sys->b_spu_update = 1;
\r
565 p_intf->p_sys->i_part = 0;
\r
567 p_intf->p_sys->p_input->stream.b_changed = 0;
\r
568 msg_Dbg( p_intf, "stream has changed, refreshing interface" );
\r
572 i_Height = StatusBar->Height + ToolBar->Height + 47;
\r
574 if( config_GetInt( p_intf, "network-channel" ) )
\r
576 GroupBoxNetwork->Visible = true;
\r
577 LabelChannel->Visible = true;
\r
578 i_Height += GroupBoxNetwork->Height + 7;
\r
582 /* add space between tolbar and statusbar when
\r
583 * nothing is displayed; isn't it nicer ? :) */
\r
587 /* unsensitize menus */
\r
588 MenuProgram->Enabled = false;
\r
589 MenuTitle->Enabled = false;
\r
590 MenuChapter->Enabled = false;
\r
591 MenuAudio->Enabled = false;
\r
592 MenuSubtitles->Enabled = false;
\r
593 PopupNavigation->Enabled = false;
\r
594 PopupAudio->Enabled = false;
\r
595 PopupSubtitles->Enabled = false;
\r
598 /* resize main window */
\r
599 this->Height = i_Height;
\r
601 /* set control items */
\r
602 ToolButtonBack->Enabled = false;
\r
603 ToolButtonEject->Enabled = !b_control;
\r
604 StopAction->Enabled = true;
\r
605 PauseAction->Enabled = b_control;
\r
606 SlowAction->Enabled = b_control;
\r
607 FastAction->Enabled = b_control;
\r
608 PopupBack->Enabled = false;
\r
610 //---------------------------------------------------------------------------
\r
613 /*****************************************************************************
\r
614 * CreateConfig: create a configuration dialog and save it for further use
\r
615 *****************************************************************************
\r
616 * Check if the dialog box is already opened, if so this will save us
\r
617 * quite a bit of work. (the interface will be destroyed when you actually
\r
618 * close the main window, but remember that it is only hidden if you
\r
619 * clicked on the action buttons). This trick also allows us not to
\r
620 * duplicate identical dialog windows.
\r
621 *****************************************************************************/
\r
622 void __fastcall TMainFrameDlg::CreatePreferences( AnsiString Name )
\r
624 TPreferencesDlg *Preferences;
\r
625 int i_index, i_pos;
\r
627 i_index = StringListPref->IndexOf( Name );
\r
628 if( i_index != -1 )
\r
630 /* config dialog already exists */
\r
631 Preferences = (TPreferencesDlg *)StringListPref->Objects[i_index];
\r
635 /* create the config dialog */
\r
636 Preferences = new TPreferencesDlg( this, p_intf );
\r
637 Preferences->CreateConfigDialog( Name.c_str() );
\r
640 i_pos = StringListPref->Add( Name );
\r
641 StringListPref->Objects[i_pos] = Preferences;
\r
644 /* display the dialog */
\r
645 Preferences->Show();
\r
647 //---------------------------------------------------------------------------
\r