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