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