]> git.sesse.net Git - vlc/blob - plugins/qt/intf_qt.cpp
ffcf4f87e236b0a3d74529fb8c94f0d16c200b82
[vlc] / plugins / qt / intf_qt.cpp
1 /*****************************************************************************
2  * intf_qt.cpp: Qt interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  * $Id: intf_qt.cpp,v 1.6 2001/05/07 03:14:09 stef Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 extern "C"
25 {
26
27 #define MODULE_NAME qt
28 #include "modules_inner.h"
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include "defs.h"
34
35 #include <errno.h>                                                 /* ENOMEM */
36 #include <stdlib.h>                                                /* free() */
37 #include <string.h>                                            /* strerror() */
38 #include <stdio.h>
39
40 #include "config.h"
41 #include "common.h"
42 #include "threads.h"
43 #include "mtime.h"
44 #include "tests.h"
45 #include "modules.h"
46
47 #include "stream_control.h"
48 #include "input_ext-intf.h"
49
50 #include "intf_msg.h"
51 #include "intf_playlist.h"
52 #include "interface.h"
53
54 #include "main.h"
55
56 } /* extern "C" */
57
58 #include <qapplication.h>
59 #include <qmainwindow.h>
60 #include <qtoolbar.h>
61 #include <qtoolbutton.h>
62 #include <qwhatsthis.h>
63 #include <qpushbutton.h>
64 #include <qfiledialog.h>
65 #include <qslider.h>
66 #include <qlcdnumber.h>
67 #include <qmenubar.h>
68 #include <qstatusbar.h>
69 #include <qmessagebox.h>
70 #include <qlabel.h> 
71 #include <qtimer.h> 
72 #include <qiconset.h> 
73
74 #include <qvbox.h>
75 #include <qhbox.h>
76
77 /*****************************************************************************
78  * Local Qt slider class
79  *****************************************************************************/
80 class IntfSlider : public QSlider
81 {
82     Q_OBJECT
83
84 public:
85     IntfSlider( intf_thread_t *, QWidget * );  /* Constructor and destructor */
86     ~IntfSlider();
87
88     bool b_free;                                     /* Is the slider free ? */
89
90     int  oldvalue   ( void ) { return i_oldvalue; };
91     void setOldValue( int i_value ) { i_oldvalue = i_value; };
92
93 private slots:
94     void SlideStart ( void ) { b_free = FALSE; };
95     void SlideStop  ( void ) { b_free = TRUE; };
96
97 private:
98     intf_thread_t *p_intf;
99     int  i_oldvalue;
100 };
101
102 /*****************************************************************************
103  * Local Qt interface window class
104  *****************************************************************************/
105 class IntfWindow : public QMainWindow
106 {
107     Q_OBJECT
108
109 public:
110     IntfWindow( intf_thread_t * );
111     ~IntfWindow();
112
113 private slots:
114     void Manage( void );
115
116     void FileOpen  ( void );
117     void FileQuit  ( void ) { p_intf->b_die = 1; };
118
119     void PlaybackPlay  ( void );
120     void PlaybackPause ( void );
121     void PlaybackSlow  ( void );
122     void PlaybackFast  ( void );
123
124     void PlaylistPrev  ( void );
125     void PlaylistNext  ( void );
126
127     void DateDisplay  ( int );
128     void About ( void );
129
130     void Unimplemented( void ) { intf_WarnMsg( 1, "intf warning: "
131                                  "unimplemented function" ); };
132
133 private:
134     intf_thread_t *p_intf;
135
136     IntfSlider *p_slider;
137
138     QToolBar   *p_toolbar;
139     QPopupMenu *p_popup;
140     QLabel     *p_date;
141 };
142
143 #ifdef BUILTIN
144 #   include "BUILTIN_intf_qt.moc"
145 #else
146 #   include "intf_qt.moc"
147 #endif
148
149 #define SLIDER_MIN    0x00000
150 #define SLIDER_MAX    0x10000
151 #define SLIDER_STEP   (SLIDER_MAX >> 4)
152
153 /*****************************************************************************
154  * intf_sys_t: description and status of Qt interface
155  *****************************************************************************/
156 typedef struct intf_sys_s
157 {
158     QApplication *p_app;
159     IntfWindow   *p_window;
160
161 } intf_sys_t;
162
163 /*****************************************************************************
164  * Local prototypes.
165  *****************************************************************************/
166 static int  intf_Probe     ( probedata_t *p_data );
167 static int  intf_Open      ( intf_thread_t *p_intf );
168 static void intf_Close     ( intf_thread_t *p_intf );
169 static void intf_Run       ( intf_thread_t *p_intf );
170
171 /*****************************************************************************
172  * Functions exported as capabilities. They are declared as static so that
173  * we don't pollute the namespace too much.
174  *****************************************************************************/
175 extern "C"
176 {
177
178 void _M( intf_getfunctions )( function_list_t * p_function_list )
179 {
180     p_function_list->pf_probe = intf_Probe;
181     p_function_list->functions.intf.pf_open  = intf_Open;
182     p_function_list->functions.intf.pf_close = intf_Close;
183     p_function_list->functions.intf.pf_run   = intf_Run;
184 }
185
186 }
187
188 /*****************************************************************************
189  * intf_Probe: probe the interface and return a score
190  *****************************************************************************
191  * This function tries to initialize Qt and returns a score to the
192  * plugin manager so that it can select the best plugin.
193  *****************************************************************************/
194 static int intf_Probe( probedata_t *p_data )
195 {
196     if( TestMethod( INTF_METHOD_VAR, "qt" ) )
197     {
198         return( 999 );
199     }
200
201     if( TestProgram( "qvlc" ) )
202     {
203         return( 180 );
204     }
205
206     return( 80 );
207 }
208
209 /*****************************************************************************
210  * intf_Open: initialize and create window
211  *****************************************************************************/
212 static int intf_Open( intf_thread_t *p_intf )
213 {
214     char *pp_argv[] = { "" };
215     int   i_argc    = 1;
216
217     /* Allocate instance and initialize some members */
218     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
219     if( p_intf->p_sys == NULL )
220     {
221         intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
222         return( 1 );
223     }
224
225     /* Create the C++ objects */
226     p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
227     p_intf->p_sys->p_window = new IntfWindow( p_intf );
228
229     /* Tell the world we are here */
230     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
231
232     return( 0 );
233 }
234
235 /*****************************************************************************
236  * intf_Close: destroy interface window
237  *****************************************************************************/
238 static void intf_Close( intf_thread_t *p_intf )
239 {
240     /* Get rid of the C++ objects */
241     delete p_intf->p_sys->p_window;
242     delete p_intf->p_sys->p_app;
243
244     /* Destroy structure */
245     free( p_intf->p_sys );
246 }
247
248 /*****************************************************************************
249  * intf_Run: Qt thread
250  *****************************************************************************
251  * This part of the interface is in a separate thread so that we can call
252  * exec() from within it without annoying the rest of the program.
253  *****************************************************************************/
254 static void intf_Run( intf_thread_t *p_intf )
255 {
256     p_intf->p_sys->p_window->show();
257
258     p_intf->p_sys->p_app->exec();
259 }
260
261 /* following functions are local */
262
263 /*****************************************************************************
264  * IntfWindow: interface window creator
265  *****************************************************************************
266  * This function creates the interface window, and populates it with a
267  * menu bar, a toolbar and a slider.
268  *****************************************************************************/
269 IntfWindow::IntfWindow( intf_thread_t *p_intf )
270            :QMainWindow( 0 )
271 {
272     setUsesTextLabel( TRUE );
273
274     this->p_intf = p_intf;
275
276     /*
277      * Create the toolbar
278      */
279
280     p_toolbar = new QToolBar( this, "toolbar" );
281     p_toolbar->setHorizontalStretchable( TRUE );
282
283     QIconSet * set = new QIconSet();
284     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
285
286 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
287     addbut( "Open", "Open a File", SLOT(FileOpen()) );
288     addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
289     addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
290     p_toolbar->addSeparator();
291     addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
292     addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
293     addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
294     addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
295     addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
296     addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
297     p_toolbar->addSeparator();
298     addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
299     addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
300     addbut( "Next", "Next File", SLOT(PlaylistNext()) );
301 #undef addbut
302
303     /* 
304      * Create the menubar
305      */
306
307     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
308
309 #define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y )
310     menuBar()->insertItem( "&File", p_tmpmenu );
311     instmp( "&Open File...", SLOT(FileOpen()), Key_F3 );
312     instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
313     instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
314     p_tmpmenu->insertSeparator();
315     instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
316
317     p_tmpmenu = new QPopupMenu( this );
318     menuBar()->insertItem( "&View", p_tmpmenu );
319     instmp( "&Playlist...", SLOT(Unimplemented()) );
320     instmp( "&Modules...", SLOT(Unimplemented()) );
321
322     p_tmpmenu = new QPopupMenu( this );
323     menuBar()->insertItem( "&Settings", p_tmpmenu );
324     instmp( "&Preferences...", SLOT(Unimplemented()) );
325
326     p_tmpmenu = new QPopupMenu( this );
327     menuBar()->insertItem( "&Help", p_tmpmenu );
328     instmp( "&About...", SLOT(About()) );
329 #undef instmp
330
331     /*
332      * Create the popup menu
333      */
334
335     p_popup = new QPopupMenu( /* floating menu */ );
336
337 #define inspop( x, y... ) p_popup->insertItem( x, this, ## y )
338     inspop( "&Play", SLOT(PlaybackPlay()) );
339     inspop( "Pause", SLOT(PlaybackPause()) );
340     inspop( "&Slow", SLOT(PlaybackSlow()) );
341     inspop( "&Fast", SLOT(PlaybackFast()) );
342     p_popup->insertSeparator();
343     inspop( "&Open File...", SLOT(FileOpen()), Key_F3 );
344     inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
345     inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
346     p_popup->insertSeparator();
347     inspop( "&About...", SLOT(About()) );
348     inspop( "&Exit", SLOT(FileQuit()) );
349 #undef inspop
350
351     /* Activate the statusbar */
352     statusBar();
353
354     /* Add the vertical box */
355     QVBox * p_vbox = new QVBox( this );
356     setCentralWidget( p_vbox );
357
358         /* The horizontal box */
359         QHBox * p_hbox = new QHBox( p_vbox );
360
361             /* The date label */
362             p_date  = new QLabel( p_hbox );
363             p_date->setAlignment( AlignHCenter | AlignVCenter );
364             p_date->setText( "-:--:--" );
365
366             /* The status label */
367             QLabel *p_label  = new QLabel( p_hbox );
368             p_label->setAlignment( AlignHCenter | AlignVCenter );
369             p_label->setText( "Status: foo" );
370
371             /* The bar label */
372             p_label  = new QLabel( p_hbox );
373             p_label->setAlignment( AlignHCenter | AlignVCenter );
374             p_label->setText( "Bar: baz quux" );
375
376         /* Create the slider and connect it to the date label */
377         p_slider = new IntfSlider( p_intf, p_vbox );
378
379         connect( p_slider, SIGNAL(valueChanged(int)),
380                  this, SLOT(DateDisplay(int)) );
381
382     /* The timer */
383     QTimer *p_timer = new QTimer( this );
384     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
385     p_timer->start( INTF_IDLE_SLEEP / 1000 );
386
387     /* Everything worked fine */
388     resize( 620, 30 );
389 }
390
391 /*****************************************************************************
392  * ~IntfWindow: interface window destructor
393  *****************************************************************************
394  * This function is called when the interface window is destroyed.
395  *****************************************************************************/
396 IntfWindow::~IntfWindow( void )
397 {
398     /* FIXME: remove everything cleanly */
399 }
400
401 /*****************************************************************************
402  * DateDisplay: display date
403  *****************************************************************************
404  * This function displays the current date in the date label.
405  *****************************************************************************/
406 void IntfWindow::DateDisplay( int i_range )
407 {
408     if( p_intf->p_input != NULL )
409     {
410         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
411
412         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
413         p_date->setText( input_OffsetToTime( p_intf->p_input, psz_time,
414                ( p_intf->p_input->stream.p_selected_area->i_size * i_range )
415                    / SLIDER_MAX ) );
416         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
417     }
418 }
419
420 /*****************************************************************************
421  * FileOpen: open a file
422  *****************************************************************************
423  * This function opens a file requester and adds the selected file to
424  * the playlist.
425  *****************************************************************************/
426 void IntfWindow::FileOpen( void )
427 {
428     QString file = QFileDialog::getOpenFileName( QString::null,
429                                                  QString::null, this );
430
431     if( file.isEmpty() )
432     {
433         statusBar()->message( "No file loaded", 2000 );
434     }
435     else
436     {
437         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, file.latin1() );
438     }
439 }
440
441 /*****************************************************************************
442  * About: display the "about" box
443  *****************************************************************************
444  * This function displays a simple "about" box with copyright information.
445  *****************************************************************************/
446 void IntfWindow::About( void )
447 {
448     QMessageBox::about( this, "About",
449         "VideoLAN Client\n"
450         "(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team\n"
451         "\n"
452         "This is the VideoLAN client, a DVD and MPEG player.\n"
453         "It can play MPEG and MPEG 2 files from a file "
454             "or from a network source.\n"
455         "\n"
456         "More information: http://www.videolan.org/" );
457 }
458
459 /*****************************************************************************
460  * Manage: manage main thread messages
461  *****************************************************************************
462  * In this function, called approx. 10 times a second, we check what the
463  * main program wanted to tell us.
464  *****************************************************************************/
465 void IntfWindow::Manage( void )
466 {
467     /* Manage the slider */
468     if( p_intf->p_input != NULL && p_intf->p_input->stream.b_seekable )
469     {
470         int i_value = p_slider->value();
471
472 #define p_area p_intf->p_input->stream.p_selected_area
473         /* If the user hasn't touched the slider since the last time,
474          * then the input can safely change it */
475         if( i_value == p_slider->oldvalue() )
476         {
477             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
478
479             p_slider->setValue( i_value );
480             p_slider->setOldValue( i_value );
481         }
482         /* Otherwise, send message to the input if the user has
483          * finished dragging the slider */
484         else if( p_slider->b_free )
485         {
486             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
487
488             input_Seek( p_intf->p_input, i_seek );
489
490             /* Update the old value */
491             p_slider->setOldValue( i_value );
492         }
493 #undef p_area
494     }
495
496     /* If the "display popup" flag has changed, popup the context menu */
497     if( p_intf->b_menu_change )
498     {
499         p_popup->popup( QCursor::pos() );
500         p_intf->b_menu_change = 0;
501     }
502
503     /* Manage core vlc functions through the callback */
504     p_intf->pf_manage( p_intf );
505
506     if( p_intf->b_die )
507     {
508         /* Prepare to die, young Skywalker */
509         qApp->quit();
510
511         /* Just in case */
512         return;
513     }
514 }
515
516 /*****************************************************************************
517  * PlaybackPlay: play
518  *****************************************************************************/
519 void IntfWindow::PlaybackPlay( void )
520 {
521     if( p_intf->p_input != NULL )
522     {
523         input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
524     }
525 }
526
527 /*****************************************************************************
528  * PlaybackPause: pause
529  *****************************************************************************/
530 void IntfWindow::PlaybackPause( void )
531 {
532     if( p_intf->p_input != NULL )
533     {
534         input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
535     }
536 }
537
538 /*****************************************************************************
539  * PlaybackSlow: slow
540  *****************************************************************************/
541 void IntfWindow::PlaybackSlow( void )
542 {
543     if( p_intf->p_input != NULL )
544     {
545         input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
546     }
547 }
548
549 /*****************************************************************************
550  * PlaybackFast: fast
551  *****************************************************************************/
552 void IntfWindow::PlaybackFast( void )
553 {
554     if( p_intf->p_input != NULL )
555     {
556         input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
557     }
558 }
559
560 /*****************************************************************************
561  * PlaylistPrev: previous playlist entry
562  *****************************************************************************/
563 void IntfWindow::PlaylistPrev( void )
564 {
565     if( p_intf->p_input != NULL )
566     {
567         /* FIXME: temporary hack */
568         intf_PlaylistPrev( p_main->p_playlist );
569         intf_PlaylistPrev( p_main->p_playlist );
570         p_intf->p_input->b_eof = 1;
571     }
572 }
573
574 /*****************************************************************************
575  * PlaylistNext: next playlist entry
576  *****************************************************************************/
577 void IntfWindow::PlaylistNext( void )
578 {
579     if( p_intf->p_input != NULL )
580     {
581         /* FIXME: temporary hack */
582         p_intf->p_input->b_eof = 1;
583     }
584 }
585
586 /*****************************************************************************
587  * IntfSlider: slider creator
588  *****************************************************************************
589  * This function creates the slider, sets its default values, and connects
590  * the interesting signals.
591  *****************************************************************************/
592 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
593            :QSlider( Horizontal, p_parent )
594 {
595     this->p_intf = p_intf;
596
597     setRange( SLIDER_MIN, SLIDER_MAX );
598     setPageStep( SLIDER_STEP );
599
600     setValue( SLIDER_MIN );
601     setOldValue( SLIDER_MIN );
602
603     setTracking( TRUE );
604     b_free = TRUE;
605
606     connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
607     connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
608     connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
609 }
610
611 /*****************************************************************************
612  * ~IntfSlider: slider destructor
613  *****************************************************************************
614  * This function is called when the interface slider is destroyed.
615  *****************************************************************************/
616 IntfSlider::~IntfSlider( void )
617 {
618     /* We don't need to remove anything */
619 }
620
621