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