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