vlc/modules/gui/qt/maininterface/mainctx.cpp

908 lines
27 KiB
C++
Raw Normal View History

2006-05-27 13:09:56 +02:00
/*****************************************************************************
2006-12-23 11:36:47 +01:00
* main_interface.cpp : Main interface
2006-05-27 13:09:56 +02:00
****************************************************************************
* Copyright (C) 2006-2011 VideoLAN and AUTHORS
2006-05-27 13:09:56 +02:00
*
* Authors: Clément Stenac <zorglub@videolan.org>
* Jean-Baptiste Kempf <jb@videolan.org>
* Ilkka Ollakka <ileoo@videolan.org>
2006-05-27 13:09:56 +02:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
2007-04-28 02:26:29 +02:00
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
2006-05-27 13:09:56 +02:00
2016-02-27 17:36:04 +01:00
#include "qt.hpp"
#include "maininterface/mainctx.hpp"
#include "compositor.hpp"
#include "util/renderer_manager.hpp"
#include "widgets/native/customwidgets.hpp" // qtEventToVLCKey, QVLCStackedWidget
2010-03-11 15:49:08 +01:00
#include "util/qt_dirs.hpp" // toNativeSeparators
#include "widgets/native/interface_widgets.hpp" // bgWidget, videoWidget
#include "playlist/playlist_controller.hpp"
#include "dialogs/dialogs_provider.hpp"
#include "videosurface.hpp"
#include "menus/menus.hpp" // Menu creation
#include "dialogs/toolbar/controlbar_profile_model.hpp"
#include <QKeyEvent>
2006-10-14 18:44:55 +02:00
#include <QUrl>
#include <QDate>
2012-07-04 15:47:40 +02:00
#include <QMimeData>
#include <QQmlProperty>
#include <QQmlContext>
#include <QWindow>
#include <QScreen>
#ifdef _WIN32
#include <QFileInfo>
#endif
#define VLC_REFERENCE_SCALE_FACTOR 96.
using namespace vlc::playlist;
2010-03-19 17:24:27 +01:00
// #define DEBUG_INTF
/* Callback prototypes */
static int PopupMenuCB( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfShowCB( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfBossCB( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param );
static int IntfRaiseMainCB( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val,
void *param );
const QEvent::Type MainCtx::ToolbarsNeedRebuild =
(QEvent::Type)QEvent::registerEventType();
namespace
{
template <typename T>
T loadVLCOption(vlc_object_t *obj, const char *name);
template <>
int loadVLCOption<int>(vlc_object_t *obj, const char *name)
{
return var_InheritInteger(obj, name);
}
template <>
bool loadVLCOption<bool>(vlc_object_t *obj, const char *name)
{
return var_InheritBool(obj, name);
}
}
MainCtx::MainCtx(qt_intf_t *_p_intf)
: p_intf(_p_intf)
2006-05-27 13:09:56 +02:00
{
/**
* Configuration and settings
* Pre-building of interface
**/
settings = getSettings();
m_colorScheme = new ColorSchemeModel(this);
loadPrefs(false);
loadFromSettingsImpl(false);
/* Get the available interfaces */
m_extraInterfaces = new VLCVarChoiceModel(VLC_OBJECT(p_intf->intf), "intf-add", this);
vlc_medialibrary_t* ml = vlc_ml_instance_get( p_intf );
b_hasMedialibrary = (ml != NULL);
if (b_hasMedialibrary) {
qt: provide runOnMLThread function this function allows to run lambdas on the ML thread, this should be used to perform operation that requires to call vlc_ml_xxx functions as vlc_ml_xxx should *not* be called from the UI thread obj: this is the instance of the calling QObject, we ensure that this object is still live when calling the ui callback, if this object gets destroyed the task is canceled mlCb: this callback is executed in a background thread (thread pool), it takes as arguments the instance of the medialibrary, and a context, the context can be modified to pass data to the UI callback uiCB: this callback is executed on the Qt thread, it takes as first argument the id of the tasks, and as second argument the context that was created for the ML callback queue: this allow the task to be ran on a specific thread, when this parameter isn't provided, the task can be scheduled on any thread. Ctx is the type of context, this context is created by the runner and passed sequentially to the ML callback then to UI callback, the ML callback may modify its properties as a way to pass data to the UI callback :warning: the ml callback **SHOULD NOT** capture the obj object or point to its properties by reference, as the obj object may potentially be destroyed when the function is called the ui callback **MAY** capture the object obj as we will ensure that the object still exists before calling the callback the uiCb **MAY NOT** be called if the object obj is released earlier anything stored int the context Ctx **MUST** auto release when the context is destroyed sample usage: ``` //structure used to pass data from the ML thread to the UI thread struct Ctx { bool success; }; m_mediaLib->runOnMLThread<Ctx>( //reference to the object making the call, this is used to ensure that //the caller still exists before calling the UI callback this, //ML thread, data needed from the caller are passed in the capture of the lambda //capturing this or any of its member is not allowed here //the callback have in parametters the ml instance and a context that will be shared with //the UI callback [url, indexed](vlc_medialibrary_t* ml, Ctx& ctx) { int res; if ( indexed ) res = vlc_ml_add_folder( ml, qtu( url ) ); else res = vlc_ml_remove_folder( ml, qtu( url ) ); ctx.success = (res == VLC_SUCCESS); }, //UI callback, capturing this is allowed, (runOnMLThread will ensure that `this` //still exists at this point //the callback has as parametters the request id and the shared context [this, indexed](quint64, Ctx& ctx){ if (ctx.success) { m_indexed = indexed; emit isIndexedChanged(); } }, //allow to specify if the task should be run on a specific thread, null (default) will run on any thread "ML_FOLDER_ADD_QUEUE"); ```
2021-11-22 10:05:25 +01:00
m_medialib = new MediaLib(p_intf);
}
/* Controlbar Profile Model Creation */
m_controlbarProfileModel = new ControlbarProfileModel(p_intf, this);
m_dialogFilepath = getSettings()->value( "filedialog-path", QVLCUserDir( VLC_HOME_DIR ) ).toString();
QString platformName = QGuiApplication::platformName();
#ifdef QT5_HAS_WAYLAND
b_hasWayland = platformName.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive);
#endif
2011-09-26 01:38:31 +02:00
/*********************************
* Create the Systray Management *
*********************************/
//postpone systray initialisation to speedup starting time
QMetaObject::invokeMethod(this, &MainCtx::initSystray, Qt::QueuedConnection);
2011-09-26 01:38:31 +02:00
/*************************************************************
* Connect the input manager to the GUI elements it manages *
* Beware initSystray did some connects on input manager too *
*************************************************************/
/**
* Connects on nameChanged()
* Those connects are different because options can impeach them to trigger.
**/
/* Main Interface statusbar */
/* and title of the Main Interface*/
connect( THEMIM, &PlayerController::inputChanged, this, &MainCtx::onInputChanged );
/* END CONNECTS ON IM */
/* VideoWidget connects for asynchronous calls */
connect( this, &MainCtx::askToQuit, THEDP, &DialogsProvider::quit, Qt::QueuedConnection );
2022-02-02 11:35:36 +01:00
QMetaObject::invokeMethod(this, [this]()
{
// *** HACKY ***
assert(p_intf->p_compositor->interfaceMainWindow());
connect(p_intf->p_compositor->interfaceMainWindow(), &QWindow::screenChanged,
this, &MainCtx::screenChanged);
}, Qt::QueuedConnection);
/** END of CONNECTS**/
/************
* Callbacks
************/
libvlc_int_t* libvlc = vlc_object_instance(p_intf);
var_AddCallback( libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
var_AddCallback( libvlc, "intf-boss", IntfBossCB, p_intf );
var_AddCallback( libvlc, "intf-show", IntfRaiseMainCB, p_intf );
/* Register callback for the intf-popupmenu variable */
var_AddCallback( libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
if( config_GetInt("qt-privacy-ask") )
{
//postpone dialog call, as composition might not be ready yet
QMetaObject::invokeMethod(this, [this](){
THEDP->firstRunDialog();
}, Qt::QueuedConnection);
}
}
MainCtx::~MainCtx()
{
RendererManager::killInstance();
2009-02-27 22:14:13 +01:00
/* Save states */
settings->beginGroup("MainWindow");
settings->setValue( "pl-dock-status", b_playlistDocked );
settings->setValue( "ShowRemainingTime", m_showRemainingTime );
settings->setValue( "interface-scale", m_intfUserScaleFactor );
settings->setValue( "pin-video-controls", m_pinVideoControls );
/* Save playlist state */
settings->setValue( "playlist-visible", playlistVisible );
settings->setValue( "playlist-width-factor", playlistWidthFactor);
settings->setValue( "grid-view", m_gridView );
settings->setValue( "grouping", m_grouping );
settings->setValue( "color-scheme", m_colorScheme->currentScheme() );
/* Save the stackCentralW sizes */
settings->endGroup();
if( var_InheritBool( p_intf, "save-recentplay" ) )
getSettings()->setValue( "filedialog-path", m_dialogFilepath );
else
getSettings()->remove( "filedialog-path" );
2009-02-27 22:14:13 +01:00
/* Unregister callbacks */
libvlc_int_t* libvlc = vlc_object_instance(p_intf);
var_DelCallback( libvlc, "intf-boss", IntfBossCB, p_intf );
var_DelCallback( libvlc, "intf-show", IntfRaiseMainCB, p_intf );
var_DelCallback( libvlc, "intf-toggle-fscontrol", IntfShowCB, p_intf );
var_DelCallback( libvlc, "intf-popupmenu", PopupMenuCB, p_intf );
qt: provide runOnMLThread function this function allows to run lambdas on the ML thread, this should be used to perform operation that requires to call vlc_ml_xxx functions as vlc_ml_xxx should *not* be called from the UI thread obj: this is the instance of the calling QObject, we ensure that this object is still live when calling the ui callback, if this object gets destroyed the task is canceled mlCb: this callback is executed in a background thread (thread pool), it takes as arguments the instance of the medialibrary, and a context, the context can be modified to pass data to the UI callback uiCB: this callback is executed on the Qt thread, it takes as first argument the id of the tasks, and as second argument the context that was created for the ML callback queue: this allow the task to be ran on a specific thread, when this parameter isn't provided, the task can be scheduled on any thread. Ctx is the type of context, this context is created by the runner and passed sequentially to the ML callback then to UI callback, the ML callback may modify its properties as a way to pass data to the UI callback :warning: the ml callback **SHOULD NOT** capture the obj object or point to its properties by reference, as the obj object may potentially be destroyed when the function is called the ui callback **MAY** capture the object obj as we will ensure that the object still exists before calling the callback the uiCb **MAY NOT** be called if the object obj is released earlier anything stored int the context Ctx **MUST** auto release when the context is destroyed sample usage: ``` //structure used to pass data from the ML thread to the UI thread struct Ctx { bool success; }; m_mediaLib->runOnMLThread<Ctx>( //reference to the object making the call, this is used to ensure that //the caller still exists before calling the UI callback this, //ML thread, data needed from the caller are passed in the capture of the lambda //capturing this or any of its member is not allowed here //the callback have in parametters the ml instance and a context that will be shared with //the UI callback [url, indexed](vlc_medialibrary_t* ml, Ctx& ctx) { int res; if ( indexed ) res = vlc_ml_add_folder( ml, qtu( url ) ); else res = vlc_ml_remove_folder( ml, qtu( url ) ); ctx.success = (res == VLC_SUCCESS); }, //UI callback, capturing this is allowed, (runOnMLThread will ensure that `this` //still exists at this point //the callback has as parametters the request id and the shared context [this, indexed](quint64, Ctx& ctx){ if (ctx.success) { m_indexed = indexed; emit isIndexedChanged(); } }, //allow to specify if the task should be run on a specific thread, null (default) will run on any thread "ML_FOLDER_ADD_QUEUE"); ```
2021-11-22 10:05:25 +01:00
if (m_medialib)
m_medialib->destroy();
p_intf->p_mi = NULL;
}
bool MainCtx::hasVLM() const {
#ifdef ENABLE_VLM
return true;
#else
return false;
#endif
}
bool MainCtx::useClientSideDecoration() const
{
//don't show CSD when interface is fullscreen
return !m_windowTitlebar;
}
bool MainCtx::hasFirstrun() const {
return config_GetInt( "qt-privacy-ask" );
}
void MainCtx::setUseGlobalShortcuts( bool useShortcuts )
{
if (m_useGlobalShortcuts == useShortcuts)
return;
m_useGlobalShortcuts = useShortcuts;
emit useGlobalShortcutsChanged(m_useGlobalShortcuts);
}
/*****************************
* Main UI handling *
*****************************/
void MainCtx::loadPrefs(const bool callSignals)
{
const auto loadFromVLCOption = [this, callSignals](auto &variable, const char *name
, const std::function<void(MainCtx *)> signal)
{
using variableType = std::remove_reference_t<decltype(variable)>;
const auto value = loadVLCOption<variableType>(VLC_OBJECT(p_intf), name);
if (value == variable)
return;
variable = value;
if (callSignals && signal)
signal(this);
};
/* Are we in the enhanced always-video mode or not ? */
loadFromVLCOption(b_minimalView, "qt-minimal-view", nullptr);
/* Do we want annoying popups or not */
loadFromVLCOption(i_notificationSetting, "qt-notification", nullptr);
/* Should the UI stays on top of other windows */
loadFromVLCOption(b_interfaceOnTop, "video-on-top", [this](MainCtx *)
{
emit interfaceAlwaysOnTopChanged(b_interfaceOnTop);
});
loadFromVLCOption(m_hasToolbarMenu, "qt-menubar", &MainCtx::hasToolbarMenuChanged);
#if QT_CLIENT_SIDE_DECORATION_AVAILABLE
loadFromVLCOption(m_windowTitlebar, "qt-titlebar" , &MainCtx::useClientSideDecorationChanged);
#endif
2021-12-06 18:10:17 +01:00
loadFromVLCOption(m_smoothScroll, "qt-smooth-scrolling", &MainCtx::smoothScrollChanged);
2022-04-26 16:21:56 +02:00
loadFromVLCOption(m_maxVolume, "qt-max-volume", &MainCtx::maxVolumeChanged);
}
void MainCtx::loadFromSettingsImpl(const bool callSignals)
{
const auto loadFromSettings = [this, callSignals](auto &variable, const char *name
, const auto defaultValue, auto signal)
{
using variableType = std::remove_reference_t<decltype(variable)>;
const auto value = getSettings()->value(name, defaultValue).template value<variableType>();
if (value == variable)
return;
variable = value;
if (callSignals && signal)
(this->*signal)(variable);
};
loadFromSettings(b_playlistDocked, "MainWindow/pl-dock-status", true, &MainCtx::playlistDockedChanged);
loadFromSettings(playlistVisible, "MainWindow/playlist-visible", false, &MainCtx::playlistVisibleChanged);
loadFromSettings(playlistWidthFactor, "MainWindow/playlist-width-factor", 4.0 , &MainCtx::playlistWidthFactorChanged);
loadFromSettings(m_gridView, "MainWindow/grid-view", true, &MainCtx::gridViewChanged);
loadFromSettings(m_grouping, "MainWindow/grouping", GROUPING_NONE, &MainCtx::groupingChanged);
loadFromSettings(m_showRemainingTime, "MainWindow/ShowRemainingTime", false, &MainCtx::showRemainingTimeChanged);
loadFromSettings(m_pinVideoControls, "MainWindow/pin-video-controls", false, &MainCtx::pinVideoControlsChanged);
const auto colorScheme = static_cast<ColorSchemeModel::ColorScheme>(getSettings()->value( "MainWindow/color-scheme", ColorSchemeModel::System ).toInt());
if (m_colorScheme->currentScheme() != colorScheme)
m_colorScheme->setCurrentScheme(colorScheme);
/* user interface scale factor */
auto userIntfScaleFactor = var_InheritFloat(p_intf, "qt-interface-scale");
if (userIntfScaleFactor == -1)
userIntfScaleFactor = getSettings()->value( "MainWindow/interface-scale", 1.0).toDouble();
if (m_intfUserScaleFactor != userIntfScaleFactor)
{
m_intfUserScaleFactor = userIntfScaleFactor;
updateIntfScaleFactor();
}
}
void MainCtx::reloadPrefs()
{
loadPrefs(true);
}
void MainCtx::onInputChanged( bool hasInput )
{
if( hasInput == false )
return;
int autoRaise = var_InheritInteger( p_intf, "qt-auto-raise" );
if ( autoRaise == MainCtx::RAISE_NEVER )
return;
if( THEMIM->hasVideoOutput() == true )
{
if( ( autoRaise & MainCtx::RAISE_VIDEO ) == 0 )
return;
}
else if ( ( autoRaise & MainCtx::RAISE_AUDIO ) == 0 )
return;
emit askRaise();
}
#ifdef KeyPress
#undef KeyPress
#endif
void MainCtx::sendHotkey(Qt::Key key , Qt::KeyboardModifiers modifiers)
{
QKeyEvent event(QEvent::KeyPress, key, modifiers );
int vlckey = qtEventToVLCKey(&event);
var_SetInteger(vlc_object_instance(p_intf), "key-pressed", vlckey);
}
void MainCtx::updateIntfScaleFactor()
{
m_intfScaleFactor = m_intfUserScaleFactor;
if (QWindow* window = p_intf->p_compositor ? p_intf->p_compositor->interfaceMainWindow() : nullptr)
{
QScreen* screen = window->screen();
if (screen)
{
qreal dpi = screen->logicalDotsPerInch();
m_intfScaleFactor = m_intfUserScaleFactor * dpi / VLC_REFERENCE_SCALE_FACTOR;
}
}
emit intfScaleFactorChanged();
}
void MainCtx::onWindowVisibilityChanged(QWindow::Visibility visibility)
{
m_windowVisibility = visibility;
}
void MainCtx::setHasAcrylicSurface(const bool v)
{
if (m_hasAcrylicSurface == v)
return;
m_hasAcrylicSurface = v;
emit hasAcrylicSurfaceChanged();
}
void MainCtx::incrementIntfUserScaleFactor(bool increment)
{
if (increment)
setIntfUserScaleFactor(m_intfUserScaleFactor + 0.1);
else
setIntfUserScaleFactor(m_intfUserScaleFactor - 0.1);
}
void MainCtx::setIntfUserScaleFactor(double newValue)
{
m_intfUserScaleFactor = qBound(getMinIntfUserScaleFactor(), newValue, getMaxIntfUserScaleFactor());
updateIntfScaleFactor();
}
void MainCtx::setPinVideoControls(bool pinVideoControls)
{
if (m_pinVideoControls == pinVideoControls)
return;
m_pinVideoControls = pinVideoControls;
emit pinVideoControlsChanged(m_pinVideoControls);
}
inline void MainCtx::initSystray()
{
bool b_systrayAvailable = QSystemTrayIcon::isSystemTrayAvailable();
2010-01-23 18:53:57 +01:00
bool b_systrayWanted = var_InheritBool( p_intf, "qt-system-tray" );
2010-01-23 18:53:57 +01:00
if( var_InheritBool( p_intf, "qt-start-minimized") )
{
if( b_systrayAvailable )
{
b_systrayWanted = true;
b_hideAfterCreation = true;
}
else
msg_Err( p_intf, "cannot start minimized without system tray bar" );
}
if( b_systrayAvailable && b_systrayWanted )
createSystray();
}
2010-02-28 15:00:23 +01:00
void MainCtx::setPlaylistDocked( bool docked )
{
b_playlistDocked = docked;
emit playlistDockedChanged(docked);
}
void MainCtx::setPlaylistVisible( bool visible )
{
playlistVisible = visible;
emit playlistVisibleChanged(visible);
}
void MainCtx::setPlaylistWidthFactor( double factor )
{
if (factor > 0.0)
{
playlistWidthFactor = factor;
emit playlistWidthFactorChanged(factor);
}
}
void MainCtx::setShowRemainingTime( bool show )
{
m_showRemainingTime = show;
emit showRemainingTimeChanged(show);
}
void MainCtx::setGridView(bool asGrid)
{
m_gridView = asGrid;
emit gridViewChanged( asGrid );
}
void MainCtx::setGrouping(Grouping grouping)
{
m_grouping = grouping;
emit groupingChanged(grouping);
}
void MainCtx::setInterfaceAlwaysOnTop( bool on_top )
{
b_interfaceOnTop = on_top;
emit interfaceAlwaysOnTopChanged(on_top);
}
bool MainCtx::hasEmbededVideo() const
{
return m_videoSurfaceProvider && m_videoSurfaceProvider->hasVideoEmbed();
}
void MainCtx::setVideoSurfaceProvider(VideoSurfaceProvider* videoSurfaceProvider)
{
if (m_videoSurfaceProvider)
disconnect(m_videoSurfaceProvider, &VideoSurfaceProvider::hasVideoEmbedChanged, this, &MainCtx::hasEmbededVideoChanged);
m_videoSurfaceProvider = videoSurfaceProvider;
if (m_videoSurfaceProvider)
connect(m_videoSurfaceProvider, &VideoSurfaceProvider::hasVideoEmbedChanged,
this, &MainCtx::hasEmbededVideoChanged,
Qt::QueuedConnection);
emit hasEmbededVideoChanged(m_videoSurfaceProvider && m_videoSurfaceProvider->hasVideoEmbed());
}
VideoSurfaceProvider* MainCtx::getVideoSurfaceProvider() const
{
return m_videoSurfaceProvider;
}
/*****************************************************************************
* Systray Icon and Systray Menu
*****************************************************************************/
/**
* Create a SystemTray icon and a menu that would go with it.
* Connects to a click handler on the icon.
**/
void MainCtx::createSystray()
{
QIcon iconVLC;
if( QDate::currentDate().dayOfYear() >= QT_XMAS_JOKE_DAY && var_InheritBool( p_intf, "qt-icon-change" ) )
iconVLC = QIcon::fromTheme( "vlc-xmas", QIcon( ":/logo/vlc128-xmas.png" ) );
else
iconVLC = QIcon::fromTheme( "vlc", QIcon( ":/logo/vlc256.png" ) );
sysTray = new QSystemTrayIcon( iconVLC, this );
sysTray->setToolTip( qtr( "VLC media player" ));
systrayMenu.reset(new QMenu( qtr( "VLC media player") ));
systrayMenu->setIcon( iconVLC );
VLCMenuBar::updateSystrayMenu( this, p_intf, true );
sysTray->show();
connect( sysTray, &QSystemTrayIcon::activated,
this, &MainCtx::handleSystrayClick );
/* Connects on nameChanged() */
connect( THEMIM, &PlayerController::nameChanged,
this, &MainCtx::updateSystrayTooltipName );
/* Connect PLAY_STATUS on the systray */
connect( THEMIM, &PlayerController::playingStateChanged,
this, &MainCtx::updateSystrayTooltipStatus );
}
/**
* Updates the Systray Icon's menu and toggle the main interface
*/
void MainCtx::toggleUpdateSystrayMenu()
{
emit toggleWindowVisibility();
if( sysTray )
VLCMenuBar::updateSystrayMenu( this, p_intf );
2006-09-22 18:10:16 +02:00
}
/* First Item of the systray menu */
void MainCtx::showUpdateSystrayMenu()
{
emit setInterfaceVisibible(true);
VLCMenuBar::updateSystrayMenu( this, p_intf );
}
/* First Item of the systray menu */
void MainCtx::hideUpdateSystrayMenu()
{
emit setInterfaceVisibible(false);
VLCMenuBar::updateSystrayMenu( this, p_intf );
}
/* Click on systray Icon */
void MainCtx::handleSystrayClick(
QSystemTrayIcon::ActivationReason reason )
{
switch( reason )
{
case QSystemTrayIcon::Trigger:
2009-01-14 00:00:22 +01:00
case QSystemTrayIcon::DoubleClick:
#ifdef Q_OS_MAC
VLCMenuBar::updateSystrayMenu( this, p_intf );
#else
toggleUpdateSystrayMenu();
#endif
break;
case QSystemTrayIcon::MiddleClick:
sysTray->showMessage( qtr( "VLC media player" ),
qtr( "Control menu for the player" ),
QSystemTrayIcon::Information, 3000 );
break;
2009-01-14 00:00:22 +01:00
default:
break;
}
}
/**
* Updates the name of the systray Icon tooltip.
* Doesn't check if the systray exists, check before you call it.
**/
void MainCtx::updateSystrayTooltipName( const QString& name )
{
if( name.isEmpty() )
{
sysTray->setToolTip( qtr( "VLC media player" ) );
}
else
{
sysTray->setToolTip( name );
if( ( i_notificationSetting == NOTIFICATION_ALWAYS ) ||
( i_notificationSetting == NOTIFICATION_MINIMIZED && (m_windowVisibility == QWindow::Hidden || m_windowVisibility == QWindow::Minimized)))
{
sysTray->showMessage( qtr( "VLC media player" ), name,
QSystemTrayIcon::NoIcon, 3000 );
}
}
VLCMenuBar::updateSystrayMenu( this, p_intf );
}
/**
* Updates the status of the systray Icon tooltip.
* Doesn't check if the systray exists, check before you call it.
**/
void MainCtx::updateSystrayTooltipStatus( PlayerController::PlayingState )
{
VLCMenuBar::updateSystrayMenu( this, p_intf );
}
/************************************************************************
* D&D Events
************************************************************************/
/**
* dropEventPlay
*
* Event called if something is dropped onto a VLC window
* \param event the event in question
* \param b_play whether to play the file immediately
* \return nothing
*/
void MainCtx::dropEventPlay( QDropEvent *event, bool b_play )
{
if( event->possibleActions() & ( Qt::CopyAction | Qt::MoveAction | Qt::LinkAction ) )
event->setDropAction( Qt::CopyAction );
else
return;
const QMimeData *mimeData = event->mimeData();
/* D&D of a subtitles file, add it on the fly */
if( mimeData->urls().count() == 1 && THEMIM->hasInput() )
{
if( !THEMIM->AddAssociatedMedia(SPU_ES, mimeData->urls()[0].toString(), true, true, true) )
{
event->accept();
return;
}
}
QVector<vlc::playlist::Media> medias;
for( const QUrl &url: mimeData->urls() )
{
if( url.isValid() )
{
2010-11-10 17:27:33 +01:00
QString mrl = toURI( url.toEncoded().constData() );
#ifdef _WIN32
QFileInfo info( url.toLocalFile() );
if( info.exists() && info.isSymLink() )
{
QString target = info.symLinkTarget();
QUrl url;
if( QFile::exists( target ) )
{
url = QUrl::fromLocalFile( target );
}
else
{
url.setUrl( target );
}
mrl = toURI( url.toEncoded().constData() );
}
#endif
if( mrl.length() > 0 )
medias.push_back( vlc::playlist::Media{ mrl, QString {} });
}
}
/* Browsers give content as text if you dnd the addressbar,
so check if mimedata has valid url in text and use it
if we didn't get any normal Urls()*/
if( !mimeData->hasUrls() && mimeData->hasText() &&
QUrl(mimeData->text()).isValid() )
{
2010-11-10 17:27:33 +01:00
QString mrl = toURI( mimeData->text() );
medias.push_back( vlc::playlist::Media{ mrl, QString {} });
}
if (!medias.empty())
THEMPL->append(medias, b_play);
event->accept();
}
/************************************************************************
* Events stuff
************************************************************************/
bool MainCtx::onWindowClose( QWindow* )
{
PlaylistControllerModel* playlistController = p_intf->p_mainPlaylistController;
PlayerController* playerController = p_intf->p_mainPlayerController;
if (m_videoSurfaceProvider)
m_videoSurfaceProvider->onWindowClosed();
//We need to make sure that noting is playing anymore otherwise the vout will be closed
//after the main interface, and it requires (at least with OpenGL) that the OpenGL context
//from the main window is still valid.
//vlc_window_ReportClose is currently stubbed
if (playerController && playerController->hasVideoOutput()) {
connect(playerController, &PlayerController::playingStateChanged, [this](PlayerController::PlayingState state){
if (state == PlayerController::PLAYING_STATE_STOPPED) {
emit askToQuit();
}
});
playlistController->stop();
return false;
}
else
{
emit askToQuit(); /* ask THEDP to quit, so we have a unique method */
return true;
}
}
void MainCtx::toggleInterfaceFullScreen()
{
emit setInterfaceFullScreen( m_windowVisibility != QWindow::FullScreen );
}
void MainCtx::emitBoss()
{
emit askBoss();
}
void MainCtx::emitShow()
{
emit askShow();
}
void MainCtx::emitRaise()
{
emit askRaise();
}
VLCVarChoiceModel* MainCtx::getExtraInterfaces()
{
return m_extraInterfaces;
}
/*****************************************************************************
* PopupMenuCB: callback triggered by the intf-popupmenu playlist variable.
* We don't show the menu directly here because we don't want the
* caller to block for a too long time.
*****************************************************************************/
static int PopupMenuCB( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t new_val, void *param )
{
qt_intf_t *p_intf = (qt_intf_t *)param;
if( p_intf->pf_show_dialog )
{
p_intf->pf_show_dialog( p_intf->intf, INTF_DIALOG_POPUPMENU,
new_val.b_bool, NULL );
}
return VLC_SUCCESS;
}
/*****************************************************************************
* IntfShowCB: callback triggered by the intf-toggle-fscontrol libvlc variable.
*****************************************************************************/
static int IntfShowCB( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *param )
{
qt_intf_t *p_intf = (qt_intf_t *)param;
p_intf->p_mi->emitShow();
return VLC_SUCCESS;
}
/*****************************************************************************
* IntfRaiseMainCB: callback triggered by the intf-show-main libvlc variable.
*****************************************************************************/
static int IntfRaiseMainCB( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *param )
{
qt_intf_t *p_intf = (qt_intf_t *)param;
p_intf->p_mi->emitRaise();
return VLC_SUCCESS;
}
/*****************************************************************************
* IntfBossCB: callback triggered by the intf-boss libvlc variable.
*****************************************************************************/
static int IntfBossCB( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void *param )
{
qt_intf_t *p_intf = (qt_intf_t *)param;
p_intf->p_mi->emitBoss();
return VLC_SUCCESS;
}
2021-11-19 17:09:42 +01:00
bool MainCtx::acrylicActive() const
2021-11-19 17:09:42 +01:00
{
return m_acrylicActive;
}
void MainCtx::setAcrylicActive(bool newAcrylicActive)
2021-11-19 17:09:42 +01:00
{
if (m_acrylicActive == newAcrylicActive)
return;
m_acrylicActive = newAcrylicActive;
emit acrylicActiveChanged();
}
bool MainCtx::preferHotkeys() const
{
return m_preferHotkeys;
}
void MainCtx::setPreferHotkeys(bool enable)
{
if (m_preferHotkeys == enable)
return;
m_preferHotkeys = enable;
emit preferHotkeysChanged();
}
QWindow *MainCtx::intfMainWindow() const
{
if (p_intf->p_compositor)
return p_intf->p_compositor->interfaceMainWindow();
else
return nullptr;
}
QVariant MainCtx::settingValue(const QString &key, const QVariant &defaultValue) const
{
return settings->value(key, defaultValue);
}
void MainCtx::setSettingValue(const QString &key, const QVariant &value)
{
settings->setValue(key, value);
}
void MainCtx::setAttachedToolTip(QObject *toolTip)
{
// See QQuickToolTipAttachedPrivate::instance(bool create)
assert(toolTip);
// Prevent possible invalid down-casting:
assert(toolTip->inherits("QQuickToolTip"));
QQmlEngine* const engine = qmlEngine(toolTip);
assert(engine);
assert(engine->objectOwnership(toolTip) == QQmlEngine::ObjectOwnership::JavaScriptOwnership);
// Dynamic internal property:
static const char* const name = "_q_QQuickToolTip";
if (const auto obj = engine->property(name).value<QObject *>())
{
if (engine->objectOwnership(obj) == QQmlEngine::ObjectOwnership::CppOwnership)
obj->deleteLater();
}
// setProperty() will return false, so there is no
// need to check the return value:
engine->setProperty(name, QVariant::fromValue(toolTip));
// Check if the attached tooltip is actually the
// one that is set
#ifndef NDEBUG
QQmlComponent component(engine);
component.setData(QByteArrayLiteral("import QtQuick 2.11; import QtQuick.Controls 2.4; Item { }"), {});
QObject* const obj = component.create();
assert(obj);
// Consider disabling setting of custom attached
// tooltip if the following assertion fails:
assert(QQmlProperty::read(obj, QStringLiteral("ToolTip.toolTip"), qmlContext(obj)).value<QObject*>() == toolTip);
obj->deleteLater();
#endif
}