1 /*****************************************************************************
2 * controller.cpp : Controller for the main interface
3 ****************************************************************************
4 * Copyright (C) 2006-2009 the VideoLAN team
5 * $Id: 04368a73fc141a20649d0a94fa115f2771f358de $
6 *
7 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
8 * Ilkka Ollakka <ileoo@videolan.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * ( at your option ) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_vout.h> /* vout_thread_t for FSC */
30
31 /* Widgets */
32 #include "components/controller.hpp"
33 #include "components/controller_widget.hpp"
34 #include "components/interface_widgets.hpp"
35 #include "util/buttons/DeckButtonsLayout.hpp"
36 #include "util/buttons/BrowseButton.hpp"
37 #include "util/buttons/RoundButton.hpp"
38
39 #include "dialogs_provider.hpp" /* Opening Dialogs */
40 #include "actions_manager.hpp" /* *_ACTION */
41
42 #include "util/input_slider.hpp" /* SeekSlider */
43 #include "util/customwidgets.hpp" /* qEventToKey */
44
45 #include "adapters/seekpoints.hpp"
46
47 #include <QToolButton>
48 #include <QHBoxLayout>
49 #include <QRegion>
50 #include <QSignalMapper>
51 #include <QTimer>
52 #include <QApplication>
53 #include <QWindow>
54 #include <QScreen>
55
56 //#define DEBUG_LAYOUT 1
57
58 /**********************************************************************
59 * TEH controls
60 **********************************************************************/
61
62 /******
63 * This is an abstract Toolbar/Controller
64 * This has helper to create any toolbar, any buttons and to manage the actions
65 *
66 *****/
AbstractController(intf_thread_t * _p_i,QWidget * _parent)67 AbstractController::AbstractController( intf_thread_t * _p_i, QWidget *_parent )
68 : QFrame( _parent )
69 {
70 p_intf = _p_i;
71 advControls = NULL;
72 buttonGroupLayout = NULL;
73
74 /* Main action provider */
75 toolbarActionsMapper = new QSignalMapper( this );
76 CONNECT( toolbarActionsMapper, mapped( int ),
77 ActionsManager::getInstance( p_intf ), doAction( int ) );
78 CONNECT( THEMIM->getIM(), playingStatusChanged( int ), this, setStatus( int ) );
79
80 setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
81 }
82
83 /* Reemit some signals on status Change to activate some buttons */
setStatus(int status)84 void AbstractController::setStatus( int status )
85 {
86 bool b_hasInput = THEMIM->getIM()->hasInput();
87 /* Activate the interface buttons according to the presence of the input */
88 emit inputExists( b_hasInput );
89
90 emit inputPlaying( status == PLAYING_S );
91
92 emit inputIsRecordable( b_hasInput &&
93 var_GetBool( THEMIM->getInput(), "can-record" ) );
94
95 emit inputIsTrickPlayable( b_hasInput &&
96 var_GetBool( THEMIM->getInput(), "can-rewind" ) );
97 }
98
99 /* Generic button setup */
setupButton(QAbstractButton * aButton)100 void AbstractController::setupButton( QAbstractButton *aButton )
101 {
102 static QSizePolicy sizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
103 sizePolicy.setHorizontalStretch( 0 );
104 sizePolicy.setVerticalStretch( 0 );
105
106 aButton->setSizePolicy( sizePolicy );
107 aButton->setFixedSize( QSize( 26, 26 ) );
108 aButton->setIconSize( QSize( 20, 20 ) );
109 aButton->setFocusPolicy( Qt::NoFocus );
110 }
111
112 /* Open the generic config line for the toolbar, parse it
113 * and create the widgets accordingly */
parseAndCreate(const QString & config,QBoxLayout * newControlLayout)114 void AbstractController::parseAndCreate( const QString& config,
115 QBoxLayout *newControlLayout )
116 {
117 QStringList list = config.split( ";", QString::SkipEmptyParts ) ;
118 for( int i = 0; i < list.count(); i++ )
119 {
120 QStringList list2 = list.at( i ).split( "-" );
121 if( list2.count() < 1 )
122 {
123 msg_Warn( p_intf, "Parsing error 1. Please, report this." );
124 continue;
125 }
126
127 bool ok;
128 int i_option = WIDGET_NORMAL;
129 buttonType_e i_type = (buttonType_e)list2.at( 0 ).toInt( &ok );
130 if( !ok )
131 {
132 msg_Warn( p_intf, "Parsing error 2. Please, report this." );
133 continue;
134 }
135
136 if( list2.count() > 1 )
137 {
138 i_option = list2.at( 1 ).toInt( &ok );
139 if( !ok )
140 {
141 msg_Warn( p_intf, "Parsing error 3. Please, report this." );
142 continue;
143 }
144 }
145
146 createAndAddWidget( newControlLayout, -1, i_type, i_option );
147 }
148
149 if( buttonGroupLayout )
150 {
151 newControlLayout->addLayout( buttonGroupLayout );
152 buttonGroupLayout = NULL;
153 }
154 }
155
createAndAddWidget(QBoxLayout * controlLayout_,int i_index,buttonType_e i_type,int i_option)156 void AbstractController::createAndAddWidget( QBoxLayout *controlLayout_,
157 int i_index,
158 buttonType_e i_type,
159 int i_option )
160 {
161 VLC_UNUSED( i_index ); // i_index should only be required for edition
162
163 /* Close the current buttonGroup if we have a special widget or a spacer */
164 if( buttonGroupLayout && i_type > BUTTON_MAX )
165 {
166 controlLayout_->addLayout( buttonGroupLayout );
167 buttonGroupLayout = NULL;
168 }
169
170 /* Special case for SPACERS, who aren't QWidgets */
171 if( i_type == WIDGET_SPACER )
172 {
173 controlLayout_->addSpacing( 12 );
174 }
175 else if( i_type == WIDGET_SPACER_EXTEND )
176 {
177 controlLayout_->addStretch( 12 );
178 }
179 else
180 {
181 /* Create the widget */
182 QWidget *widg = createWidget( i_type, i_option );
183 if( !widg ) return;
184
185 /* Buttons */
186 if( i_type < BUTTON_MAX )
187 {
188 if( !buttonGroupLayout )
189 {
190 buttonGroupLayout = new QHBoxLayout;
191
192 }
193 buttonGroupLayout->addWidget( widg );
194 }
195 else /* Special widgets */
196 {
197 controlLayout_->addWidget( widg );
198 }
199 }
200 }
201
202
203 #define CONNECT_MAP( a ) CONNECT( a, clicked(), toolbarActionsMapper, map() )
204 #define SET_MAPPING( a, b ) toolbarActionsMapper->setMapping( a , b )
205 #define CONNECT_MAP_SET( a, b ) \
206 CONNECT_MAP( a ); \
207 SET_MAPPING( a, b );
208 #define BUTTON_SET_BAR( a_button ) \
209 a_button->setToolTip( qtr( tooltipL[button] ) ); \
210 a_button->setIcon( QIcon( iconL[button] ) );
211 #define BUTTON_SET_BAR2( button, image, tooltip ) \
212 button->setToolTip( tooltip ); \
213 button->setIcon( QIcon( ":/"#image ".svg" ) );
214
215 #define ENABLE_ON_VIDEO( a ) \
216 CONNECT( THEMIM->getIM(), voutChanged( bool ), a, setEnabled( bool ) ); \
217 a->setEnabled( THEMIM->getIM()->hasVideo() ); /* TODO: is this necessary? when input is started before the interface? */
218
219 #define ENABLE_ON_INPUT( a ) \
220 CONNECT( this, inputExists( bool ), a, setEnabled( bool ) ); \
221 a->setEnabled( THEMIM->getIM()->hasInput() ); /* TODO: is this necessary? when input is started before the interface? */
222
223 #define NORMAL_BUTTON( name ) \
224 QToolButton * name ## Button = new QToolButton; \
225 setupButton( name ## Button ); \
226 CONNECT_MAP_SET( name ## Button, name ## _ACTION ); \
227 BUTTON_SET_BAR( name ## Button ); \
228 widget = name ## Button;
229
createWidget(buttonType_e button,int options)230 QWidget *AbstractController::createWidget( buttonType_e button, int options )
231 {
232 bool b_flat = options & WIDGET_FLAT;
233 bool b_big = options & WIDGET_BIG;
234 bool b_shiny = options & WIDGET_SHINY;
235 bool b_special = false;
236
237 QWidget *widget = NULL;
238 switch( button )
239 {
240 case PLAY_BUTTON: {
241 PlayButton *playButton = new PlayButton;
242 setupButton( playButton );
243 BUTTON_SET_BAR( playButton );
244 CONNECT_MAP_SET( playButton, PLAY_ACTION );
245 CONNECT( this, inputPlaying( bool ),
246 playButton, updateButtonIcons( bool ));
247 playButton->updateButtonIcons( THEMIM->getIM()->playingStatus() == PLAYING_S );
248 widget = playButton;
249 }
250 break;
251 case STOP_BUTTON:{
252 NORMAL_BUTTON( STOP );
253 }
254 break;
255 case OPEN_BUTTON:{
256 NORMAL_BUTTON( OPEN );
257 }
258 break;
259 case OPEN_SUB_BUTTON:{
260 NORMAL_BUTTON( OPEN_SUB );
261 }
262 break;
263 case PREVIOUS_BUTTON:{
264 NORMAL_BUTTON( PREVIOUS );
265 }
266 break;
267 case NEXT_BUTTON: {
268 NORMAL_BUTTON( NEXT );
269 }
270 break;
271 case SLOWER_BUTTON:{
272 NORMAL_BUTTON( SLOWER );
273 ENABLE_ON_INPUT( SLOWERButton );
274 }
275 break;
276 case FASTER_BUTTON:{
277 NORMAL_BUTTON( FASTER );
278 ENABLE_ON_INPUT( FASTERButton );
279 }
280 break;
281 case PREV_SLOW_BUTTON:{
282 QToolButtonExt *but = new QToolButtonExt;
283 setupButton( but );
284 BUTTON_SET_BAR( but );
285 CONNECT( but, shortClicked(), THEMIM, prev() );
286 CONNECT( but, longClicked(), THEAM, skipBackward() );
287 widget = but;
288 }
289 break;
290 case NEXT_FAST_BUTTON:{
291 QToolButtonExt *but = new QToolButtonExt;
292 setupButton( but );
293 BUTTON_SET_BAR( but );
294 CONNECT( but, shortClicked(), THEMIM, next() );
295 CONNECT( but, longClicked(), THEAM, skipForward() );
296 widget = but;
297 }
298 break;
299 case FRAME_BUTTON: {
300 NORMAL_BUTTON( FRAME );
301 ENABLE_ON_VIDEO( FRAMEButton );
302 }
303 break;
304 case FULLSCREEN_BUTTON:
305 case DEFULLSCREEN_BUTTON:
306 {
307 NORMAL_BUTTON( FULLSCREEN );
308 ENABLE_ON_VIDEO( FULLSCREENButton );
309 }
310 break;
311 case FULLWIDTH_BUTTON: {
312 NORMAL_BUTTON( FULLWIDTH );
313 }
314 break;
315 case EXTENDED_BUTTON:{
316 NORMAL_BUTTON( EXTENDED );
317 }
318 break;
319 case PLAYLIST_BUTTON:{
320 NORMAL_BUTTON( PLAYLIST );
321 }
322 break;
323 case SNAPSHOT_BUTTON:{
324 NORMAL_BUTTON( SNAPSHOT );
325 ENABLE_ON_VIDEO( SNAPSHOTButton );
326 }
327 break;
328 case RECORD_BUTTON:{
329 QToolButton *recordButton = new QToolButton;
330 setupButton( recordButton );
331 CONNECT_MAP_SET( recordButton, RECORD_ACTION );
332 BUTTON_SET_BAR( recordButton );
333 ENABLE_ON_INPUT( recordButton );
334 recordButton->setCheckable( true );
335 CONNECT( THEMIM->getIM(), recordingStateChanged( bool ),
336 recordButton, setChecked( bool ) );
337 widget = recordButton;
338 }
339 break;
340 case ATOB_BUTTON: {
341 AtoB_Button *ABButton = new AtoB_Button;
342 setupButton( ABButton );
343 ABButton->setShortcut( qtr("Shift+L") );
344 BUTTON_SET_BAR( ABButton );
345 ENABLE_ON_INPUT( ABButton );
346 CONNECT_MAP_SET( ABButton, ATOB_ACTION );
347 CONNECT( THEMIM->getIM(), AtoBchanged( bool, bool),
348 ABButton, updateButtonIcons( bool, bool ) );
349 widget = ABButton;
350 }
351 break;
352 case INPUT_SLIDER: {
353 SeekSlider *slider = new SeekSlider( p_intf, Qt::Horizontal, NULL, !b_shiny );
354 SeekPoints *chapters = new SeekPoints( this, p_intf );
355 CONNECT( THEMIM->getIM(), chapterChanged( bool ), chapters, update() );
356 slider->setChapters( chapters );
357
358 /* Update the position when the IM has changed */
359 CONNECT( THEMIM->getIM(), positionUpdated( float, int64_t, int ),
360 slider, setPosition( float, int64_t, int ) );
361 /* And update the IM, when the position has changed */
362 CONNECT( slider, sliderDragged( float ),
363 THEMIM->getIM(), sliderUpdate( float ) );
364 CONNECT( THEMIM->getIM(), cachingChanged( float ),
365 slider, updateBuffering( float ) );
366 /* Give hint to disable slider's interactivity when useless */
367 CONNECT( THEMIM->getIM(), inputCanSeek( bool ),
368 slider, setSeekable( bool ) );
369 widget = slider;
370 }
371 break;
372 case MENU_BUTTONS:
373 widget = discFrame();
374 break;
375 case TELETEXT_BUTTONS:
376 widget = telexFrame();
377 widget->hide();
378 break;
379 case VOLUME_SPECIAL:
380 b_special = true;
381 case VOLUME:
382 {
383 SoundWidget *snd = new SoundWidget( this, p_intf, b_shiny, b_special );
384 widget = snd;
385 }
386 break;
387 case TIME_LABEL:
388 {
389 TimeLabel *timeLabel = new TimeLabel( p_intf );
390 widget = timeLabel;
391 }
392 break;
393 case SPLITTER:
394 {
395 QFrame *line = new QFrame;
396 line->setFrameShape( QFrame::VLine );
397 line->setFrameShadow( QFrame::Raised );
398 line->setLineWidth( 0 );
399 line->setMidLineWidth( 1 );
400 widget = line;
401 }
402 break;
403 case ADVANCED_CONTROLLER:
404 if( qobject_cast<AdvControlsWidget *>(this) == NULL )
405 {
406 advControls = new AdvControlsWidget( p_intf, this );
407 widget = advControls;
408 }
409 break;
410 case REVERSE_BUTTON:{
411 QToolButton *reverseButton = new QToolButton;
412 setupButton( reverseButton );
413 CONNECT_MAP_SET( reverseButton, REVERSE_ACTION );
414 BUTTON_SET_BAR( reverseButton );
415 reverseButton->setCheckable( true );
416 /* You should, of COURSE change this to the correct event,
417 when/if we have one, that tells us if trickplay is possible . */
418 CONNECT( this, inputIsTrickPlayable( bool ), reverseButton, setVisible( bool ) );
419 reverseButton->setVisible( false );
420 widget = reverseButton;
421 }
422 break;
423 case SKIP_BACK_BUTTON: {
424 NORMAL_BUTTON( SKIP_BACK );
425 ENABLE_ON_INPUT( SKIP_BACKButton );
426 }
427 break;
428 case SKIP_FW_BUTTON: {
429 NORMAL_BUTTON( SKIP_FW );
430 ENABLE_ON_INPUT( SKIP_FWButton );
431 }
432 break;
433 case QUIT_BUTTON: {
434 NORMAL_BUTTON( QUIT );
435 }
436 break;
437 case RANDOM_BUTTON: {
438 NORMAL_BUTTON( RANDOM );
439 RANDOMButton->setCheckable( true );
440 RANDOMButton->setChecked( var_GetBool( THEPL, "random" ) );
441 CONNECT( THEMIM, randomChanged( bool ),
442 RANDOMButton, setChecked( bool ) );
443 }
444 break;
445 case LOOP_BUTTON:{
446 LoopButton *loopButton = new LoopButton;
447 setupButton( loopButton );
448 loopButton->setToolTip( qtr( "Click to toggle between loop all, loop one and no loop") );
449 loopButton->setCheckable( true );
450 {
451 int i_state = NORMAL;
452 if( var_GetBool( THEPL, "loop" ) ) i_state = REPEAT_ALL;
453 if( var_GetBool( THEPL, "repeat" ) ) i_state = REPEAT_ONE;
454 loopButton->updateButtonIcons( i_state );
455 }
456
457 CONNECT( THEMIM, repeatLoopChanged( int ), loopButton, updateButtonIcons( int ) );
458 CONNECT( loopButton, clicked(), THEMIM, loopRepeatLoopStatus() );
459 widget = loopButton;
460 }
461 break;
462 case INFO_BUTTON: {
463 NORMAL_BUTTON( INFO );
464 }
465 break;
466 case PLAYBACK_BUTTONS:{
467 widget = new QWidget;
468 DeckButtonsLayout *layout = new DeckButtonsLayout( widget );
469 BrowseButton *prev = new BrowseButton( widget, BrowseButton::Backward );
470 BrowseButton *next = new BrowseButton( widget );
471 RoundButton *play = new RoundButton( widget );
472 layout->setBackwardButton( prev );
473 layout->setForwardButton( next );
474 layout->setRoundButton( play );
475 CONNECT_MAP_SET( prev, PREVIOUS_ACTION );
476 CONNECT_MAP_SET( next, NEXT_ACTION );
477 CONNECT_MAP_SET( play, PLAY_ACTION );
478 }
479 break;
480 case ASPECT_RATIO_COMBOBOX:
481 widget = new AspectRatioComboBox( p_intf );
482 widget->setMinimumHeight( 26 );
483 break;
484 case SPEED_LABEL:
485 widget = new SpeedLabel( p_intf, this );
486 break;
487 case TIME_LABEL_ELAPSED:
488 widget = new TimeLabel( p_intf, TimeLabel::Elapsed );
489 break;
490 case TIME_LABEL_REMAINING:
491 widget = new TimeLabel( p_intf, TimeLabel::Remaining );
492 break;
493 default:
494 msg_Warn( p_intf, "This should not happen %i", button );
495 break;
496 }
497
498 /* Customize Buttons */
499 if( b_flat || b_big )
500 {
501 QFrame *frame = qobject_cast<QFrame *>(widget);
502 if( frame )
503 {
504 QList<QToolButton *> allTButtons = frame->findChildren<QToolButton *>();
505 for( int i = 0; i < allTButtons.count(); i++ )
506 applyAttributes( allTButtons[i], b_flat, b_big );
507 }
508 else
509 {
510 QToolButton *tmpButton = qobject_cast<QToolButton *>(widget);
511 if( tmpButton )
512 applyAttributes( tmpButton, b_flat, b_big );
513 }
514 }
515 return widget;
516 }
517 #undef NORMAL_BUTTON
518
applyAttributes(QToolButton * tmpButton,bool b_flat,bool b_big)519 void AbstractController::applyAttributes( QToolButton *tmpButton, bool b_flat, bool b_big )
520 {
521 if( tmpButton )
522 {
523 if( b_flat )
524 tmpButton->setAutoRaise( b_flat );
525 if( b_big )
526 {
527 tmpButton->setFixedSize( QSize( 32, 32 ) );
528 tmpButton->setIconSize( QSize( 26, 26 ) );
529 }
530 }
531 }
532
discFrame()533 QFrame *AbstractController::discFrame()
534 {
535 /** Disc and Menus handling */
536 QFrame *discFrame = new QFrame( this );
537
538 QHBoxLayout *discLayout = new QHBoxLayout( discFrame );
539 discLayout->setSpacing( 0 ); discLayout->setMargin( 0 );
540
541
542 QFrame *chapFrame = new QFrame( discFrame );
543 QHBoxLayout *chapLayout = new QHBoxLayout( chapFrame );
544 chapLayout->setSpacing( 0 ); chapLayout->setMargin( 0 );
545
546 QToolButton *prevSectionButton = new QToolButton( chapFrame );
547 setupButton( prevSectionButton );
548 BUTTON_SET_BAR2( prevSectionButton, toolbar/dvd_prev,
549 qtr("Previous Chapter/Title" ) );
550 chapLayout->addWidget( prevSectionButton );
551
552 QToolButton *nextSectionButton = new QToolButton( chapFrame );
553 setupButton( nextSectionButton );
554 BUTTON_SET_BAR2( nextSectionButton, toolbar/dvd_next,
555 qtr("Next Chapter/Title" ) );
556 chapLayout->addWidget( nextSectionButton );
557
558 discLayout->addWidget( chapFrame );
559 chapFrame->hide();
560
561 QFrame *menuFrame = new QFrame( discFrame );
562 QHBoxLayout *menuLayout = new QHBoxLayout( menuFrame );
563 menuLayout->setSpacing( 0 ); menuLayout->setMargin( 0 );
564
565 QToolButton *menuButton = new QToolButton( menuFrame );
566 setupButton( menuButton );
567 menuLayout->addWidget( menuButton );
568 BUTTON_SET_BAR2( menuButton, toolbar/dvd_menu, qtr( "Menu" ) );
569
570 discLayout->addWidget( menuFrame );
571 menuFrame->hide();
572
573 /* Change the navigation button display when the IM
574 navigation changes */
575 CONNECT( THEMIM->getIM(), chapterChanged( bool ),
576 chapFrame, setVisible( bool ) );
577 CONNECT( THEMIM->getIM(), titleChanged( bool ),
578 menuFrame, setVisible( bool ) );
579 /* Changes the IM navigation when triggered on the nav buttons */
580 CONNECT( prevSectionButton, clicked(), THEMIM->getIM(),
581 sectionPrev() );
582 CONNECT( nextSectionButton, clicked(), THEMIM->getIM(),
583 sectionNext() );
584 CONNECT( menuButton, clicked(), THEMIM->getIM(),
585 sectionMenu() );
586
587 return discFrame;
588 }
589
telexFrame()590 QFrame *AbstractController::telexFrame()
591 {
592 /**
593 * Telextext QFrame
594 **/
595 QFrame *telexFrame = new QFrame( this );
596 QHBoxLayout *telexLayout = new QHBoxLayout( telexFrame );
597 telexLayout->setSpacing( 0 ); telexLayout->setMargin( 0 );
598 CONNECT( THEMIM->getIM(), teletextPossible( bool ),
599 telexFrame, setVisible( bool ) );
600
601 /* On/Off button */
602 QToolButton *telexOn = new QToolButton;
603 setupButton( telexOn );
604 BUTTON_SET_BAR2( telexOn, toolbar/tv, qtr( "Teletext Activation" ) );
605 telexOn->setEnabled( false );
606 telexOn->setCheckable( true );
607
608 telexLayout->addWidget( telexOn );
609
610 /* Teletext Activation and set */
611 CONNECT( telexOn, clicked( bool ),
612 THEMIM->getIM(), activateTeletext( bool ) );
613 CONNECT( THEMIM->getIM(), teletextPossible( bool ),
614 telexOn, setEnabled( bool ) );
615
616 /* Transparency button */
617 QToolButton *telexTransparent = new QToolButton;
618 setupButton( telexTransparent );
619 BUTTON_SET_BAR2( telexTransparent, toolbar/tvtelx,
620 qtr( "Toggle Transparency" ) );
621 telexTransparent->setEnabled( false );
622 telexTransparent->setCheckable( true );
623 telexLayout->addWidget( telexTransparent );
624
625 /* Transparency change and set */
626 CONNECT( telexTransparent, clicked( bool ),
627 THEMIM->getIM(), telexSetTransparency( bool ) );
628 CONNECT( THEMIM->getIM(), teletextTransparencyActivated( bool ),
629 telexTransparent, setChecked( bool ) );
630
631
632 /* Page setting */
633 QSpinBox *telexPage = new QSpinBox( telexFrame );
634 telexPage->setRange( 100, 899 );
635 telexPage->setValue( 100 );
636 telexPage->setAccelerated( true );
637 telexPage->setWrapping( true );
638 telexPage->setAlignment( Qt::AlignRight );
639 telexPage->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
640 telexPage->setEnabled( false );
641 telexLayout->addWidget( telexPage );
642
643 /* Contextual & Index Buttons */
644 QSignalMapper *contextButtonMapper = new QSignalMapper( this );
645 QToolButton *contextButton = NULL;
646 int i_iconminsize = __MAX( 16, telexOn->minimumHeight() );
647
648 #if HAS_QT56
649 qreal f_ratio = QApplication::primaryScreen()->devicePixelRatio();
650 QPixmap iconPixmap( i_iconminsize * f_ratio, i_iconminsize * f_ratio );
651 #else
652 QPixmap iconPixmap( i_iconminsize, i_iconminsize );
653 #endif
654
655 iconPixmap.fill( Qt::transparent );
656 QPainter iconPixmapPainter( &iconPixmap );
657 QLinearGradient iconPixmapPainterGradient( iconPixmap.rect().center() / 2,
658 iconPixmap.rect().center() );
659
660 #define CREATE_CONTEXT_BUTTON(color, key) \
661 iconPixmapPainterGradient.setColorAt( 0, QColor( color ).lighter(150) );\
662 iconPixmapPainterGradient.setColorAt( 1.0, QColor( color ) );\
663 iconPixmapPainter.setBrush( iconPixmapPainterGradient );\
664 iconPixmapPainter.drawEllipse( iconPixmap.rect().adjusted( 4, 4, -5, -5 ) );\
665 contextButton = new QToolButton();\
666 setupButton( contextButton );\
667 contextButton->setIcon( iconPixmap );\
668 contextButton->setEnabled( false );\
669 contextButtonMapper->setMapping( contextButton, key << 16 );\
670 CONNECT( contextButton, clicked(), contextButtonMapper, map() );\
671 CONNECT( contextButtonMapper, mapped( int ),\
672 THEMIM->getIM(), telexSetPage( int ) );\
673 CONNECT( THEMIM->getIM(), teletextActivated( bool ), contextButton, setEnabled( bool ) );\
674 telexLayout->addWidget( contextButton )
675
676 CREATE_CONTEXT_BUTTON("grey", 'i'); /* index */
677 CREATE_CONTEXT_BUTTON("red", 'r');
678 CREATE_CONTEXT_BUTTON("green", 'g');
679 CREATE_CONTEXT_BUTTON("yellow", 'y');
680 CREATE_CONTEXT_BUTTON("blue", 'b');
681
682 #undef CREATE_CONTEXT_BUTTON
683
684 /* Page change and set */
685 CONNECT( telexPage, valueChanged( int ),
686 THEMIM->getIM(), telexSetPage( int ) );
687 CONNECT( THEMIM->getIM(), newTelexPageSet( int ),
688 telexPage, setValue( int ) );
689
690 CONNECT( THEMIM->getIM(), teletextActivated( bool ), telexPage, setEnabled( bool ) );
691 CONNECT( THEMIM->getIM(), teletextActivated( bool ), telexTransparent, setEnabled( bool ) );
692 CONNECT( THEMIM->getIM(), teletextActivated( bool ), telexOn, setChecked( bool ) );
693 return telexFrame;
694 }
695 #undef CONNECT_MAP
696 #undef SET_MAPPING
697 #undef CONNECT_MAP_SET
698 #undef BUTTON_SET_BAR
699 #undef BUTTON_SET_BAR2
700 #undef ENABLE_ON_VIDEO
701 #undef ENABLE_ON_INPUT
702
703 #include <QHBoxLayout>
704 /*****************************
705 * DA Control Widget !
706 *****************************/
ControlsWidget(intf_thread_t * _p_i,bool b_advControls,QWidget * _parent)707 ControlsWidget::ControlsWidget( intf_thread_t *_p_i,
708 bool b_advControls,
709 QWidget *_parent ) :
710 AbstractController( _p_i, _parent )
711 {
712 RTL_UNAFFECTED_WIDGET
713 /* advanced Controls handling */
714 b_advancedVisible = b_advControls;
715 #ifdef DEBUG_LAYOUT
716 setStyleSheet( "background: red ");
717 #endif
718 setAttribute( Qt::WA_MacBrushedMetal);
719 controlLayout = new QVBoxLayout( this );
720 controlLayout->setContentsMargins( 3, 1, 0, 1 );
721 controlLayout->setSpacing( 0 );
722 QHBoxLayout *controlLayout1 = new QHBoxLayout;
723 controlLayout1->setSpacing( 0 ); controlLayout1->setMargin( 0 );
724
725 QString line1 = getSettings()->value( "MainWindow/MainToolbar1", MAIN_TB1_DEFAULT )
726 .toString();
727 parseAndCreate( line1, controlLayout1 );
728
729 QHBoxLayout *controlLayout2 = new QHBoxLayout;
730 controlLayout2->setSpacing( 0 ); controlLayout2->setMargin( 0 );
731 QString line2 = getSettings()->value( "MainWindow/MainToolbar2", MAIN_TB2_DEFAULT )
732 .toString();
733 parseAndCreate( line2, controlLayout2 );
734
735 grip = new QSizeGrip( this );
736 controlLayout2->addWidget( grip, 0, Qt::AlignBottom|Qt::AlignRight );
737
738 if( !b_advancedVisible && advControls ) advControls->hide();
739
740 controlLayout->addLayout( controlLayout1 );
741 controlLayout->addLayout( controlLayout2 );
742 }
743
toggleAdvanced()744 void ControlsWidget::toggleAdvanced()
745 {
746 if( !advControls ) return;
747
748 advControls->setVisible( !b_advancedVisible );
749 b_advancedVisible = !b_advancedVisible;
750 emit advancedControlsToggled( b_advancedVisible );
751 }
752
AdvControlsWidget(intf_thread_t * _p_i,QWidget * _parent)753 AdvControlsWidget::AdvControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
754 AbstractController( _p_i, _parent )
755 {
756 RTL_UNAFFECTED_WIDGET
757 controlLayout = new QHBoxLayout( this );
758 controlLayout->setMargin( 0 );
759 controlLayout->setSpacing( 0 );
760 #ifdef DEBUG_LAYOUT
761 setStyleSheet( "background: orange ");
762 #endif
763
764
765 QString line = getSettings()->value( "MainWindow/AdvToolbar", ADV_TB_DEFAULT )
766 .toString();
767 parseAndCreate( line, controlLayout );
768 }
769
InputControlsWidget(intf_thread_t * _p_i,QWidget * _parent)770 InputControlsWidget::InputControlsWidget( intf_thread_t *_p_i, QWidget *_parent ) :
771 AbstractController( _p_i, _parent )
772 {
773 RTL_UNAFFECTED_WIDGET
774 controlLayout = new QHBoxLayout( this );
775 controlLayout->setMargin( 0 );
776 controlLayout->setSpacing( 0 );
777 #ifdef DEBUG_LAYOUT
778 setStyleSheet( "background: green ");
779 #endif
780
781 QString line = getSettings()->value( "MainWindow/InputToolbar", INPT_TB_DEFAULT ).toString();
782 parseAndCreate( line, controlLayout );
783 }
784 /**********************************************************************
785 * Fullscrenn control widget
786 **********************************************************************/
FullscreenControllerWidget(intf_thread_t * _p_i,QWidget * _parent)787 FullscreenControllerWidget::FullscreenControllerWidget( intf_thread_t *_p_i, QWidget *_parent )
788 : AbstractController( _p_i, _parent )
789 {
790 RTL_UNAFFECTED_WIDGET
791 i_mouse_last_x = -1;
792 i_mouse_last_y = -1;
793 b_mouse_over = false;
794 i_mouse_last_move_x = -1;
795 i_mouse_last_move_y = -1;
796 #if HAVE_TRANSPARENCY
797 b_slow_hide_begin = false;
798 i_slow_hide_timeout = 1;
799 #endif
800 b_fullscreen = false;
801 i_hide_timeout = 1;
802 i_screennumber = -1;
803 #ifdef QT5_HAS_WAYLAND
804 b_hasWayland = QGuiApplication::platformName()
805 .startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
806 #endif
807
808 vout.clear();
809
810 setWindowFlags( Qt::Tool | Qt::FramelessWindowHint );
811 setAttribute( Qt::WA_ShowWithoutActivating );
812 setMinimumWidth( FSC_WIDTH );
813 isWideFSC = false;
814
815 setFrameShape( QFrame::StyledPanel );
816 setFrameStyle( QFrame::Sunken );
817 setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
818
819 QVBoxLayout *controlLayout2 = new QVBoxLayout( this );
820 controlLayout2->setContentsMargins( 4, 6, 4, 2 );
821
822 /* First line */
823 InputControlsWidget *inputC = new InputControlsWidget( p_intf, this );
824 controlLayout2->addWidget( inputC );
825
826 controlLayout = new QHBoxLayout;
827 QString line = getSettings()->value( "MainWindow/FSCtoolbar", FSC_TB_DEFAULT ).toString();
828 parseAndCreate( line, controlLayout );
829 controlLayout2->addLayout( controlLayout );
830
831 /* hiding timer */
832 p_hideTimer = new QTimer( this );
833 p_hideTimer->setSingleShot( true );
834 CONNECT( p_hideTimer, timeout(), this, hideFSC() );
835
836 /* slow hiding timer */
837 #if HAVE_TRANSPARENCY
838 p_slowHideTimer = new QTimer( this );
839 CONNECT( p_slowHideTimer, timeout(), this, slowHideFSC() );
840 f_opacity = var_InheritFloat( p_intf, "qt-fs-opacity" );
841 #endif
842
843 i_sensitivity = var_InheritInteger( p_intf, "qt-fs-sensitivity" );
844
845 vlc_mutex_init_recursive( &lock );
846
847 DCONNECT( THEMIM->getIM(), voutListChanged( vout_thread_t **, int ),
848 this, setVoutList( vout_thread_t **, int ) );
849
850 /* First Move */
851 previousPosition = getSettings()->value( "FullScreen/pos" ).toPoint();
852 screenRes = getSettings()->value( "FullScreen/screen" ).toRect();
853 isWideFSC = getSettings()->value( "FullScreen/wide" ).toBool();
854
855 CONNECT( this, fullscreenChanged( bool ), THEMIM, changeFullscreen( bool ) );
856 }
857
~FullscreenControllerWidget()858 FullscreenControllerWidget::~FullscreenControllerWidget()
859 {
860 getSettings()->setValue( "FullScreen/pos", previousPosition );
861 getSettings()->setValue( "FullScreen/screen", screenRes );
862 getSettings()->setValue( "FullScreen/wide", isWideFSC );
863
864 setVoutList( NULL, 0 );
865 vlc_mutex_destroy( &lock );
866 }
867
restoreFSC()868 void FullscreenControllerWidget::restoreFSC()
869 {
870 if( !isWideFSC )
871 {
872 /* Restore half-bar and re-centre if needed */
873 setMinimumWidth( FSC_WIDTH );
874 adjustSize();
875
876 if ( targetScreen() < 0 )
877 return;
878
879 QRect currentRes = QApplication::desktop()->screenGeometry( targetScreen() );
880 QWindow *wh = windowHandle();
881 if ( wh != Q_NULLPTR )
882 {
883 #ifdef QT5_HAS_WAYLAND
884 if ( !b_hasWayland )
885 wh->setScreen(QGuiApplication::screens()[targetScreen()]);
886 #else
887 wh->setScreen(QGuiApplication::screens()[targetScreen()]);
888 #endif
889 }
890
891 if( currentRes == screenRes &&
892 currentRes.contains( previousPosition, true ) )
893 {
894 /* Restore to the last known position */
895 move( previousPosition );
896 }
897 else
898 {
899 /* FSC is out of screen or screen resolution changed */
900 msg_Dbg( p_intf, "Recentering the Fullscreen Controller" );
901 centerFSC( targetScreen() );
902 screenRes = currentRes;
903 previousPosition = pos();
904 }
905 }
906 else
907 {
908 /* Dock at the bottom of the screen */
909 updateFullwidthGeometry( targetScreen() );
910 }
911 }
912
centerFSC(int number)913 void FullscreenControllerWidget::centerFSC( int number )
914 {
915 QRect currentRes = QApplication::desktop()->screenGeometry( number );
916
917 /* screen has changed, calculate new position */
918 QPoint pos = QPoint( currentRes.x() + (currentRes.width() / 2) - (width() / 2),
919 currentRes.y() + currentRes.height() - height());
920 move( pos );
921 }
922
923 /**
924 * Show fullscreen controller
925 */
showFSC()926 void FullscreenControllerWidget::showFSC()
927 {
928 restoreFSC();
929
930 #if HAVE_TRANSPARENCY
931 setWindowOpacity( f_opacity );
932 #endif
933
934 show();
935 }
936
937 /**
938 * Plane to hide fullscreen controller
939 */
planHideFSC()940 void FullscreenControllerWidget::planHideFSC()
941 {
942 vlc_mutex_lock( &lock );
943 int i_timeout = i_hide_timeout;
944 vlc_mutex_unlock( &lock );
945
946 p_hideTimer->start( i_timeout );
947
948 #if HAVE_TRANSPARENCY
949 b_slow_hide_begin = true;
950 i_slow_hide_timeout = i_timeout;
951 p_slowHideTimer->start( i_slow_hide_timeout / 2 );
952 #endif
953 }
954
955 /**
956 * Hidding fullscreen controller slowly
957 * Linux: need composite manager
958 * Windows: it is blinking, so it can be enabled by define TRASPARENCY
959 */
slowHideFSC()960 void FullscreenControllerWidget::slowHideFSC()
961 {
962 #if HAVE_TRANSPARENCY
963 if( b_slow_hide_begin )
964 {
965 b_slow_hide_begin = false;
966
967 p_slowHideTimer->stop();
968 /* the last part of time divided to 100 pieces */
969 p_slowHideTimer->start( (int)( i_slow_hide_timeout / 2 / ( windowOpacity() * 100 ) ) );
970
971 }
972 else
973 {
974 if ( windowOpacity() > 0.0 )
975 {
976 /* we should use 0.01 because of 100 pieces ^^^
977 but than it cannt be done in time */
978 setWindowOpacity( windowOpacity() - 0.02 );
979 }
980
981 if ( windowOpacity() <= 0.0 )
982 p_slowHideTimer->stop();
983 }
984 #endif
985 }
986
updateFullwidthGeometry(int number)987 void FullscreenControllerWidget::updateFullwidthGeometry( int number )
988 {
989 QRect screenGeometry = QApplication::desktop()->screenGeometry( number );
990 setMinimumWidth( screenGeometry.width() );
991 setGeometry( screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - height(), screenGeometry.width(), height() );
992 adjustSize();
993 }
994
toggleFullwidth()995 void FullscreenControllerWidget::toggleFullwidth()
996 {
997 /* Toggle isWideFSC switch */
998 isWideFSC = !isWideFSC;
999
1000 restoreFSC();
1001 }
1002
1003
setTargetScreen(int screennumber)1004 void FullscreenControllerWidget::setTargetScreen(int screennumber)
1005 {
1006 i_screennumber = screennumber;
1007 }
1008
1009
targetScreen()1010 int FullscreenControllerWidget::targetScreen()
1011 {
1012 if( i_screennumber < 0 || i_screennumber >= QApplication::desktop()->screenCount() )
1013 return QApplication::desktop()->screenNumber( p_intf->p_sys->p_mi );
1014 return i_screennumber;
1015 }
1016
1017 /**
1018 * event handling
1019 * events: show, hide, start timer for hiding
1020 */
customEvent(QEvent * event)1021 void FullscreenControllerWidget::customEvent( QEvent *event )
1022 {
1023 bool b_fs;
1024
1025 switch( (int)event->type() )
1026 {
1027 /* This is used when the 'i' hotkey is used, to force quick toggle */
1028 case IMEvent::FullscreenControlToggle:
1029 vlc_mutex_lock( &lock );
1030 b_fs = b_fullscreen;
1031 vlc_mutex_unlock( &lock );
1032
1033 if( b_fs )
1034 {
1035 if( isHidden() )
1036 {
1037 p_hideTimer->stop();
1038 showFSC();
1039 }
1040 else
1041 hideFSC();
1042 }
1043 break;
1044 /* Event called to Show the FSC on mouseChanged() */
1045 case IMEvent::FullscreenControlShow:
1046 vlc_mutex_lock( &lock );
1047 b_fs = b_fullscreen;
1048 vlc_mutex_unlock( &lock );
1049
1050 if( b_fs && ( isHidden()
1051 #if HAVE_TRANSPARENCY
1052 || p_slowHideTimer->isActive()
1053 #endif
1054 ) )
1055 showFSC();
1056
1057 break;
1058 /* Start the timer to hide later, called usually with above case */
1059 case IMEvent::FullscreenControlPlanHide:
1060 if( !b_mouse_over ) // Only if the mouse is not over FSC
1061 planHideFSC();
1062 break;
1063 /* Hide */
1064 case IMEvent::FullscreenControlHide:
1065 hideFSC();
1066 break;
1067 default:
1068 break;
1069 }
1070 }
1071
1072 /**
1073 * On mouse move
1074 * moving with FSC
1075 */
mouseMoveEvent(QMouseEvent * event)1076 void FullscreenControllerWidget::mouseMoveEvent( QMouseEvent *event )
1077 {
1078 if( event->buttons() == Qt::LeftButton )
1079 {
1080 if( i_mouse_last_x == -1 || i_mouse_last_y == -1 )
1081 return;
1082
1083 int i_moveX = event->globalX() - i_mouse_last_x;
1084 int i_moveY = event->globalY() - i_mouse_last_y;
1085
1086 move( x() + i_moveX, y() + i_moveY );
1087
1088 i_mouse_last_x = event->globalX();
1089 i_mouse_last_y = event->globalY();
1090 }
1091 }
1092
1093 /**
1094 * On mouse press
1095 * store position of cursor
1096 */
mousePressEvent(QMouseEvent * event)1097 void FullscreenControllerWidget::mousePressEvent( QMouseEvent *event )
1098 {
1099 if( isWideFSC ) return;
1100 i_mouse_last_x = event->globalX();
1101 i_mouse_last_y = event->globalY();
1102 event->accept();
1103 }
1104
mouseReleaseEvent(QMouseEvent * event)1105 void FullscreenControllerWidget::mouseReleaseEvent( QMouseEvent *event )
1106 {
1107 if( isWideFSC ) return;
1108 i_mouse_last_x = -1;
1109 i_mouse_last_y = -1;
1110 event->accept();
1111
1112 // Save the new FSC position
1113 previousPosition = pos();
1114 }
1115
1116 /**
1117 * On mouse go above FSC
1118 */
enterEvent(QEvent * event)1119 void FullscreenControllerWidget::enterEvent( QEvent *event )
1120 {
1121 b_mouse_over = true;
1122
1123 p_hideTimer->stop();
1124 #if HAVE_TRANSPARENCY
1125 p_slowHideTimer->stop();
1126 setWindowOpacity( f_opacity );
1127 #endif
1128 event->accept();
1129 }
1130
1131 /**
1132 * On mouse go out from FSC
1133 */
leaveEvent(QEvent * event)1134 void FullscreenControllerWidget::leaveEvent( QEvent *event )
1135 {
1136 planHideFSC();
1137
1138 b_mouse_over = false;
1139 event->accept();
1140 }
1141
1142 /**
1143 * When you get pressed key, send it to video output
1144 */
keyPressEvent(QKeyEvent * event)1145 void FullscreenControllerWidget::keyPressEvent( QKeyEvent *event )
1146 {
1147 emit keyPressed( event );
1148 }
1149
1150 /* */
FullscreenChanged(vlc_object_t * obj,const char *,vlc_value_t,vlc_value_t new_val,void * data)1151 int FullscreenControllerWidget::FullscreenChanged( vlc_object_t *obj,
1152 const char *, vlc_value_t, vlc_value_t new_val, void *data )
1153 {
1154 vout_thread_t *p_vout = (vout_thread_t *) obj;
1155
1156 msg_Dbg( p_vout, "Qt: Fullscreen state changed" );
1157 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1158
1159 p_fs->fullscreenChanged( p_vout, new_val.b_bool, var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1160 p_fs->emit fullscreenChanged( new_val.b_bool );
1161
1162 return VLC_SUCCESS;
1163 }
1164 /* */
FullscreenControllerWidgetMouseMoved(vlc_object_t * obj,const char *,vlc_value_t,vlc_value_t new_val,void * data)1165 static int FullscreenControllerWidgetMouseMoved( vlc_object_t *obj,
1166 const char *, vlc_value_t, vlc_value_t new_val, void *data )
1167 {
1168 vout_thread_t *p_vout = (vout_thread_t *) obj;
1169 FullscreenControllerWidget *p_fs = (FullscreenControllerWidget *)data;
1170
1171 /* Get the value from the Vout - Trust the vout more than Qt */
1172 p_fs->mouseChanged( p_vout, new_val.coords.x, new_val.coords.y );
1173
1174 return VLC_SUCCESS;
1175 }
1176
1177 /**
1178 * It is call to update the list of vout handled by the fullscreen controller
1179 */
setVoutList(vout_thread_t ** pp_vout,int i_vout)1180 void FullscreenControllerWidget::setVoutList( vout_thread_t **pp_vout, int i_vout )
1181 {
1182 QList<vout_thread_t*> del;
1183 QList<vout_thread_t*> add;
1184
1185 QList<vout_thread_t*> set;
1186
1187 /* */
1188 for( int i = 0; i < i_vout; i++ )
1189 set += pp_vout[i];
1190
1191 /* Vout to remove */
1192 vlc_mutex_lock( &lock );
1193 foreach( vout_thread_t *p_vout, vout )
1194 {
1195 if( !set.contains( p_vout ) )
1196 del += p_vout;
1197 }
1198 vlc_mutex_unlock( &lock );
1199
1200 foreach( vout_thread_t *p_vout, del )
1201 {
1202 var_DelCallback( p_vout, "fullscreen",
1203 FullscreenControllerWidget::FullscreenChanged, this );
1204 vlc_mutex_lock( &lock );
1205 fullscreenChanged( p_vout, false, 0 );
1206 vout.removeAll( p_vout );
1207 vlc_mutex_unlock( &lock );
1208
1209 vlc_object_release( VLC_OBJECT(p_vout) );
1210 }
1211
1212 /* Vout to track */
1213 vlc_mutex_lock( &lock );
1214 foreach( vout_thread_t *p_vout, set )
1215 {
1216 if( !vout.contains( p_vout ) )
1217 add += p_vout;
1218 }
1219 vlc_mutex_unlock( &lock );
1220
1221 foreach( vout_thread_t *p_vout, add )
1222 {
1223 vlc_object_hold( VLC_OBJECT(p_vout) );
1224
1225 vlc_mutex_lock( &lock );
1226 vout.append( p_vout );
1227 var_AddCallback( p_vout, "fullscreen",
1228 FullscreenControllerWidget::FullscreenChanged, this );
1229 /* I miss a add and fire */
1230 emit fullscreenChanged( p_vout, var_InheritBool( p_vout, "fullscreen" ),
1231 var_GetInteger( p_vout, "mouse-hide-timeout" ) );
1232 vlc_mutex_unlock( &lock );
1233 }
1234 }
1235 /**
1236 * Register and unregister callback for mouse moving
1237 */
fullscreenChanged(vout_thread_t * p_vout,bool b_fs,int i_timeout)1238 void FullscreenControllerWidget::fullscreenChanged( vout_thread_t *p_vout,
1239 bool b_fs, int i_timeout )
1240 {
1241 /* FIXME - multiple vout (ie multiple mouse position ?) and thread safety if multiple vout ? */
1242
1243 vlc_mutex_lock( &lock );
1244 /* Entering fullscreen, register callback */
1245 if( b_fs && !b_fullscreen )
1246 {
1247 msg_Dbg( p_vout, "Qt: Entering Fullscreen" );
1248 b_fullscreen = true;
1249 i_hide_timeout = i_timeout;
1250 var_AddCallback( p_vout, "mouse-moved",
1251 FullscreenControllerWidgetMouseMoved, this );
1252 }
1253 /* Quitting fullscreen, unregistering callback */
1254 else if( !b_fs && b_fullscreen )
1255 {
1256 msg_Dbg( p_vout, "Qt: Quitting Fullscreen" );
1257 b_fullscreen = false;
1258 i_hide_timeout = i_timeout;
1259 var_DelCallback( p_vout, "mouse-moved",
1260 FullscreenControllerWidgetMouseMoved, this );
1261
1262 /* Force fs hiding */
1263 IMEvent *eHide = new IMEvent( IMEvent::FullscreenControlHide, 0 );
1264 QApplication::postEvent( this, eHide );
1265 }
1266 vlc_mutex_unlock( &lock );
1267 }
1268
1269 /**
1270 * Mouse change callback (show/hide the controller on mouse movement)
1271 */
mouseChanged(vout_thread_t *,int i_mousex,int i_mousey)1272 void FullscreenControllerWidget::mouseChanged( vout_thread_t *, int i_mousex, int i_mousey )
1273 {
1274 bool b_toShow;
1275
1276 /* FIXME - multiple vout (ie multiple mouse position ?) and thread safety if multiple vout ? */
1277
1278 b_toShow = false;
1279 if( ( i_mouse_last_move_x == -1 || i_mouse_last_move_y == -1 ) ||
1280 ( abs( i_mouse_last_move_x - i_mousex ) > i_sensitivity ||
1281 abs( i_mouse_last_move_y - i_mousey ) > i_sensitivity ) )
1282 {
1283 i_mouse_last_move_x = i_mousex;
1284 i_mouse_last_move_y = i_mousey;
1285 b_toShow = true;
1286 }
1287
1288 if( b_toShow )
1289 {
1290 /* Show event */
1291 IMEvent *eShow = new IMEvent( IMEvent::FullscreenControlShow, 0 );
1292 QApplication::postEvent( this, eShow );
1293
1294 /* Plan hide event */
1295 IMEvent *eHide = new IMEvent( IMEvent::FullscreenControlPlanHide, 0 );
1296 QApplication::postEvent( this, eHide );
1297 }
1298 }
1299
1300