[Tidy] Tidyed up things, removed QML Reloading and Discord support.
This commit is contained in:
parent
5be24ac560
commit
b6d5547453
|
@ -4,21 +4,12 @@ project(KittehPlayer)
|
|||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
|
||||
option(DEVELOP "Enable runtime QML reloading for developing." OFF)
|
||||
option(DISCORD "Enable Discord SDK." OFF)
|
||||
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Gui REQUIRED)
|
||||
find_package(Qt5 CONFIG REQUIRED COMPONENTS Qml Quick Gui Widgets Core X11Extras)
|
||||
|
||||
find_package(Qt5QuickCompiler)
|
||||
if(DEVELOP)
|
||||
qt5_add_resources(QT_RESOURCES qml.qrc)
|
||||
else()
|
||||
qtquick_compiler_add_resources(qml_QRC src/qml/qml.qrc)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(MPV REQUIRED mpv)
|
||||
|
@ -29,7 +20,6 @@ if(X11_FOUND AND Xext_FOUND)
|
|||
add_definitions(-DENABLE_X11)
|
||||
endif(X11_FOUND AND Xext_FOUND)
|
||||
|
||||
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/DirectMpvPlayerBackend.cpp
|
||||
|
@ -37,14 +27,13 @@ set(SOURCES
|
|||
src/enums.hpp
|
||||
)
|
||||
|
||||
|
||||
if(MPV_VERSION VERSION_GREATER_EQUAL "1.28.0")
|
||||
set(SOURCES ${SOURCES} src/MpvPlayerBackend.cpp)
|
||||
else()
|
||||
add_definitions(-DDISABLE_MpvPlayerBackend)
|
||||
endif(MPV_VERSION VERSION_GREATER_EQUAL "1.28.0")
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
find_program(CCACHE_FOUND cache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
|
@ -52,7 +41,7 @@ endif(CCACHE_FOUND)
|
|||
|
||||
set(CMAKE_BUILD_TYPE RELEASE)
|
||||
|
||||
if(TESTING OR DEFINED ENV{TRAVIS})
|
||||
if(DEFINED ENV{TRAVIS})
|
||||
execute_process(
|
||||
COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
|
@ -61,37 +50,7 @@ execute_process(
|
|||
)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
||||
endif(TESTING OR DEFINED ENV{TRAVIS})
|
||||
|
||||
|
||||
|
||||
if(TESTING)
|
||||
SET(CMAKE_C_COMPILER "/usr/bin/clang")
|
||||
SET(CMAKE_CXX_COMPILER "/usr/bin/clang++")
|
||||
SET(CMAKE_AR "/usr/bin/llvm-ar")
|
||||
SET(CMAKE_LINKER "/usr/bin/llvm-link")
|
||||
SET(CMAKE_NM "/usr/bin/llvm-nm")
|
||||
SET(CMAKE_OBJDUMP "/usr/bin/llvm-objdump")
|
||||
SET(CMAKE_RANLIB "/usr/bin/llvm-ranlib")
|
||||
endif(TESTING)
|
||||
|
||||
|
||||
if(DEVELOP)
|
||||
set(SOURCES ${SOURCES} runtimeqml/runtimeqml.cpp)
|
||||
add_definitions(-DQRC_SOURCE_PATH="${PROJECT_SOURCE_DIR}/src/qml")
|
||||
add_definitions(-DQT_QML_DEBUG)
|
||||
endif(DEVELOP)
|
||||
|
||||
if(DISCORD)
|
||||
add_definitions(-DDISCORD)
|
||||
execute_process(
|
||||
COMMAND git clone --depth 1 https://github.com/discordapp/discord-rpc
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_subdirectory(discord-rpc)
|
||||
INCLUDE_DIRECTORIES(discord-rpc/include)
|
||||
target_link_libraries(KittehPlayer discord-rpc)
|
||||
endif(DISCORD)
|
||||
endif(DEFINED ENV{TRAVIS})
|
||||
|
||||
add_executable(KittehPlayer ${SOURCES} ${qml_QRC})
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
TARGET = KittehPlayer
|
||||
|
||||
TEMPLATE = app
|
||||
QT += qml quickcontrols2 widgets
|
||||
|
||||
SOURCES += src/main.cpp src/MpvPlayerBackend.cpp src/DirectMpvPlayerBackend.cpp src/utils.cpp
|
||||
|
||||
CONFIG += debug
|
||||
CONFIG-=qtquickcompiler
|
||||
QT_CONFIG -= no-pkg-config
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += mpv
|
||||
RESOURCES += src/qml/qml.qrc
|
||||
|
||||
unix {
|
||||
isEmpty {
|
||||
PREFIX = /usr
|
||||
}
|
||||
|
||||
target.path = $$PREFIX/bin
|
||||
|
||||
desktop.files = KittehPlayer.desktop
|
||||
desktop.path = $$PREFIX/share/applications/
|
||||
icon.files += KittehPlayer.png
|
||||
icon.path = $$PREFIX/share/icons/hicolor/256x256/apps/
|
||||
|
||||
INSTALLS += desktop
|
||||
INSTALLS += icon
|
||||
}
|
||||
|
||||
INSTALLS += target
|
||||
|
||||
HEADERS += src/MpvPlayerBackend.h src/DirectMpvPlayerBackend.h src/utils.hpp
|
||||
|
||||
|
||||
DISTFILES += KittehPlayer.desktop KittehPlayer.png README.md LICENSE.txt
|
|
@ -27,13 +27,12 @@ pacman -S git cmake qt5-svg qt5-declarative qt5-quickcontrols qt5-quickcontrols2
|
|||
```
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.11.1-xenial -y
|
||||
sudo apt update
|
||||
sudo apt install build-essential git nasm qt511-meta-minimal qt511quickcontrols qt511quickcontrols2 qt511imageformats qt511svg libgl1-mesa-dev
|
||||
sudo apt install build-essential git nasm qt511-meta-minimal qt511quickcontrols qt511quickcontrols2 qt511imageformats qt511svg libgl1-mesa-dev libmpv-dev
|
||||
sudo apt-get build-dep mpv libmpv* ffmpeg
|
||||
```
|
||||
#### Instructions
|
||||
- `git clone https://github.com/NamedKitten/KittehPlayer KittehPlayer`
|
||||
- `cd KittehPlayer`
|
||||
- If you are running Ubuntu you will need to run `sudo ./scripts/build-mpv.sh` because ubuntu's MPV version is way too old.
|
||||
- `mkdir build && cd build`
|
||||
- `cmake .. -DCMAKE_INSTALL_PREFIX=/usr`
|
||||
- `make`
|
||||
|
|
75
runtimeqml/.gitignore
vendored
75
runtimeqml/.gitignore
vendored
|
@ -1,75 +0,0 @@
|
|||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
# qtcreator builds of test project
|
||||
build-RuntimeQML-*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
Copyright (c) 2018, Benjamin Balga
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,87 +0,0 @@
|
|||
# Runtime QML for Qt
|
||||
|
||||
**Written by**: *Benjamin Balga.*
|
||||
**Copyright**: ***2018***, *Benjamin Balga*, released under BSD license.
|
||||
|
||||
|
||||
## About
|
||||
|
||||
This is a base project to get runtime QML reload in your Qt project.
|
||||
It allows you to reload all QML code at runtime, without recompiling or restarting your app, saving time.
|
||||
|
||||
With auto-reload, QML files are watched (based on the QRC file) and reloaded when you save them, or can trigger it manually.
|
||||
|
||||
On reload, all windows are closed, and the main window is reloaded. All "QML-only data" is lost, so use links to C++ models/properties as needed.
|
||||
|
||||
It only works with Window component as top object, or QQuickWindow subclasses.
|
||||
|
||||
### Examples
|
||||
Example project is located here: https://github.com/GIPdA/runtimeqml_examples
|
||||
|
||||
|
||||
## How to use it in your project
|
||||
|
||||
Clone the repo into your project (or copy-paste the ```runtimeqml``` folder) and import the ```.pri``` project file into your ```.pro``` file:
|
||||
|
||||
include(runtimeqml/runtimeqml.pri)
|
||||
|
||||
|
||||
### With Qbs
|
||||
The Qbs project file includes RuntimeQML as a static library. Check the example project to see how to include it in your project.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Include ```runtimeqml.h``` header file, and create the RuntimeQML object (after the QML engine) :
|
||||
|
||||
RuntimeQML *rt = new RuntimeQML(&engine, QRC_SOURCE_PATH"/qml.qrc");
|
||||
|
||||
The second argument is the path to your qrc file listing all your QML files, needed for the auto-reload feature only. You can omit it if you don't want auto-reload.
|
||||
```QRC_SOURCE_PATH``` is defined in the ```.pri/.qbs``` file to its parent path, just to not have to manually set an absolute path...
|
||||
|
||||
|
||||
Set the "options" you want, or not:
|
||||
|
||||
rt->noDebug(); // Removes debug prints
|
||||
rt->setAutoReload(true); // Enable auto-reload (begin to watch files)
|
||||
//rt->setCloseAllOnReload(false); // Don't close all windows on reload. Not advised!
|
||||
rt->setMainQmlFilename("main.qml"); // This is the file that loaded on reload, default is "main.qml"
|
||||
|
||||
For the auto-reload feature:
|
||||
|
||||
rt->addSuffix("conf"); // Adds a file suffix to the "white list" for watched files. "qml" is already in.
|
||||
rt->ignorePrefix("/test"); // Ignore a prefix in the QRC file.
|
||||
rt->ignoreFile("/Page2.qml"); // Ignore a file name with prefix (supports classic wildcard matching)
|
||||
|
||||
|
||||
Then load the main QML file :
|
||||
|
||||
rt->reload();
|
||||
|
||||
And you're all set!
|
||||
|
||||
|
||||
You can also check the test project. Beware, includes and defines differs a bit...
|
||||
|
||||
|
||||
## Manual reload
|
||||
|
||||
Add the RuntimeQML object to the QML context:
|
||||
|
||||
engine.rootContext()->setContextProperty("RuntimeQML", rt);
|
||||
|
||||
Trigger the reload when and where you want, like with a button:
|
||||
|
||||
Button {
|
||||
text: "Reload"
|
||||
onClicked: {
|
||||
RuntimeQML.reload();
|
||||
}
|
||||
}
|
||||
|
||||
You can do it in C++ too, of course.
|
||||
|
||||
|
||||
|
||||
## License
|
||||
See LICENSE file.
|
|
@ -1,398 +0,0 @@
|
|||
#include "runtimeqml.h"
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
#include <QTimer>
|
||||
|
||||
/*!
|
||||
* \brief Construct a RuntimeQML object with a path to the qrc file.
|
||||
* \param engine App engine to reload.
|
||||
* \param qrcFilename File name of the QRC file for auto reload.
|
||||
* \param parent Pointer to a parent object.
|
||||
*/
|
||||
RuntimeQML::RuntimeQML(QQmlApplicationEngine* engine, const QString &qrcFilename, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_engine(engine),
|
||||
m_qrcFilename(qrcFilename),
|
||||
m_mainQmlFilename("main.qml")
|
||||
{
|
||||
m_allowedSuffixList << "qml";
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Returns the absolute path for the given qml file.
|
||||
* \param qmlFile Qml filename
|
||||
*/
|
||||
QString RuntimeQML::adjustPath(QString qmlFile)
|
||||
{
|
||||
return m_selector.select(qrcAbsolutePath() + "/" + qmlFile);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the absolute path to the QRC file.
|
||||
*/
|
||||
QString RuntimeQML::qrcAbsolutePath() const
|
||||
{
|
||||
return QFileInfo(m_qrcFilename).absolutePath();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Filename of the QRC file.
|
||||
*/
|
||||
QString RuntimeQML::qrcFilename() const
|
||||
{
|
||||
return m_qrcFilename;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief If true, files are watched for changes and auto-reloaded.
|
||||
* Otherwise, you need to trigger a reload manually from your code by calling reload().
|
||||
* \sa reload
|
||||
*/
|
||||
bool RuntimeQML::autoReload() const
|
||||
{
|
||||
return m_autoReload;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief If true, all open windows will be closed upon reload.
|
||||
* \default true
|
||||
*/
|
||||
bool RuntimeQML::closeAllOnReload() const
|
||||
{
|
||||
return m_closeAllOnReload;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief QRC prefixes that are ignored.
|
||||
*/
|
||||
const QList<QString>& RuntimeQML::prefixIgnoreList() const
|
||||
{
|
||||
return m_prefixIgnoreList;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Files that are ignored.
|
||||
*/
|
||||
const QList<QString> &RuntimeQML::fileIgnoreList() const
|
||||
{
|
||||
return m_fileIgnoreList;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allowed suffixes to filter files to watch for changes.
|
||||
* By default contains only "qml".
|
||||
*/
|
||||
const QList<QString> &RuntimeQML::allowedSuffixes() const
|
||||
{
|
||||
return m_allowedSuffixList;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Call it if you don't want debug outputs from this class.
|
||||
*/
|
||||
void RuntimeQML::noDebug()
|
||||
{
|
||||
if (m_noDebug)
|
||||
return;
|
||||
m_noDebug = true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Reload the window.
|
||||
*/
|
||||
void RuntimeQML::reload()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "reloadQml", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Call it from QML to set the current QQuickWindow.
|
||||
* You shouldn't need to call it as it is done automatically on reload.
|
||||
* \param window
|
||||
*/
|
||||
void RuntimeQML::setWindow(QQuickWindow* window)
|
||||
{
|
||||
if (window == m_window)
|
||||
return;
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Set the QRC filename for files to watch for changes.
|
||||
* \param qrcFilename Path to a .qrc file.
|
||||
*/
|
||||
void RuntimeQML::setQrcFilename(QString qrcFilename)
|
||||
{
|
||||
if (m_qrcFilename == qrcFilename)
|
||||
return;
|
||||
|
||||
m_qrcFilename = qrcFilename;
|
||||
emit qrcFilenameChanged(qrcFilename);
|
||||
|
||||
loadQrcFiles();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set the name of the main qml file.
|
||||
* Default is "main.qml".
|
||||
* \param filename The main qml filename.
|
||||
*/
|
||||
void RuntimeQML::setMainQmlFilename(QString filename)
|
||||
{
|
||||
if (m_mainQmlFilename == filename)
|
||||
return;
|
||||
|
||||
m_mainQmlFilename = filename;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief If true, files are watched for changes and auto-reloaded.
|
||||
* Otherwise, you need to trigger a reload manually from your code by calling reload().
|
||||
* \param reload True to auto-reload, false otherwise.
|
||||
*/
|
||||
void RuntimeQML::setAutoReload(bool autoReload)
|
||||
{
|
||||
if (m_autoReload == autoReload)
|
||||
return;
|
||||
|
||||
m_autoReload = autoReload;
|
||||
emit autoReloadChanged(autoReload);
|
||||
|
||||
if (autoReload)
|
||||
loadQrcFiles();
|
||||
else
|
||||
unloadFileWatcher();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief If true, all open windows are closed upon reload. Otherwise, might cause "link" errors with QML components.
|
||||
* \param closeAllOnReload True to close all windows on reload, false otherwise.
|
||||
*/
|
||||
void RuntimeQML::setCloseAllOnReload(bool closeAllOnReload)
|
||||
{
|
||||
if (m_closeAllOnReload == closeAllOnReload)
|
||||
return;
|
||||
|
||||
m_closeAllOnReload = closeAllOnReload;
|
||||
emit closeAllOnReloadChanged(m_closeAllOnReload);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Add a QRC prefix to ignore.
|
||||
* \note Relevant for auto-reload only.
|
||||
* \param prefix Prefix to ignore.
|
||||
*/
|
||||
void RuntimeQML::ignoreQrcPrefix(const QString& prefix)
|
||||
{
|
||||
if (m_prefixIgnoreList.contains(prefix))
|
||||
return;
|
||||
|
||||
m_prefixIgnoreList.append(prefix);
|
||||
|
||||
if (m_autoReload)
|
||||
loadQrcFiles();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Add a filename to ignore from changes.
|
||||
* Applies to the full filename in the QRC entry (i.e. the local "path"), with the prefix.
|
||||
* Supports "file globbing" matching using wildcards.
|
||||
* \note Relevant for auto-reload only.
|
||||
* \param filename Filename to ignore.
|
||||
*/
|
||||
void RuntimeQML::ignoreFile(const QString &filename)
|
||||
{
|
||||
if (m_fileIgnoreList.contains(filename))
|
||||
return;
|
||||
|
||||
m_fileIgnoreList.append(filename);
|
||||
|
||||
if (m_autoReload)
|
||||
loadQrcFiles();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Allow a file suffix to be watched for changes.
|
||||
* \note Relevant for auto-reload only.
|
||||
* \param suffix
|
||||
*/
|
||||
void RuntimeQML::addSuffix(const QString &suffix)
|
||||
{
|
||||
if (m_allowedSuffixList.contains(suffix))
|
||||
return;
|
||||
|
||||
m_allowedSuffixList.append(suffix);
|
||||
|
||||
if (m_autoReload)
|
||||
loadQrcFiles();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Reload the QML. Do not call it directly, use reload() instead.
|
||||
*/
|
||||
void RuntimeQML::reloadQml()
|
||||
{
|
||||
if (m_mainQmlFilename.isEmpty()) {
|
||||
qWarning("No QML file specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
if (m_closeAllOnReload) {
|
||||
// Find all child windows and close them
|
||||
auto const allWindows = m_window->findChildren<QQuickWindow*>();
|
||||
for (int i {0}; i < allWindows.size(); ++i) {
|
||||
QQuickWindow* w = qobject_cast<QQuickWindow*>(allWindows.at(i));
|
||||
if (w) {
|
||||
w->close();
|
||||
w->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_window->close();
|
||||
m_window->deleteLater();
|
||||
}
|
||||
|
||||
m_engine->clearComponentCache();
|
||||
// TODO: test with network files
|
||||
// TODO: QString path to QUrl doesn't work under Windows with load() (load fail)
|
||||
m_engine->load(m_selector.select(qrcAbsolutePath() + "/" + m_mainQmlFilename));
|
||||
// NOTE: QQmlApplicationEngine::rootObjects() isn't cleared, should it be?
|
||||
|
||||
if (!m_engine->rootObjects().isEmpty()) {
|
||||
QQuickWindow* w = qobject_cast<QQuickWindow*>(m_engine->rootObjects().last());
|
||||
if (w) m_window = w;
|
||||
}
|
||||
|
||||
// for (auto *o : m_engine->rootObjects()) {
|
||||
// qDebug() << "> " << o;
|
||||
// }
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called when a watched file changed, from QFileSystemWatcher.
|
||||
* \param path Path/file that triggered the signal.
|
||||
*/
|
||||
void RuntimeQML::fileChanged(const QString& path)
|
||||
{
|
||||
if (!m_noDebug)
|
||||
qDebug() << "Reloading qml:" << path;
|
||||
reload();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// Deleted files are removed from the watcher, re-add the file for
|
||||
// systems that delete files to update them
|
||||
if (m_fileWatcher)
|
||||
QTimer::singleShot(500, m_fileWatcher, [this,path](){
|
||||
m_fileWatcher->addPath(path);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Load qml from the QRC file to watch them.
|
||||
*/
|
||||
void RuntimeQML::loadQrcFiles()
|
||||
{
|
||||
unloadFileWatcher();
|
||||
|
||||
m_fileWatcher = new QFileSystemWatcher(this);
|
||||
connect(m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &RuntimeQML::fileChanged);
|
||||
|
||||
QFile file(m_qrcFilename);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning("Unable to open resource file '%s', RuntimeQML will not work! Error: %s",
|
||||
qPrintable(m_qrcFilename), qPrintable(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
QString const basePath = qrcAbsolutePath() + "/";
|
||||
QString currentPrefix;
|
||||
|
||||
// Read each entry
|
||||
QXmlStreamReader inputStream(&file);
|
||||
while (!inputStream.atEnd() && !inputStream.hasError()) {
|
||||
inputStream.readNext();
|
||||
if (inputStream.isStartElement()) {
|
||||
QString name { inputStream.name().toString() };
|
||||
|
||||
// Check prefix
|
||||
if (name == "qresource") {
|
||||
if (inputStream.attributes().hasAttribute("prefix")) {
|
||||
auto p = inputStream.attributes().value("prefix").toString();
|
||||
if (m_prefixIgnoreList.contains(p)) {
|
||||
// Ignore this prefix, loop through elements in this 'qresource' tag
|
||||
while (!inputStream.atEnd() && !inputStream.hasError()) {
|
||||
inputStream.readNext();
|
||||
if (inputStream.isEndElement() && inputStream.name() == "qresource")
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
currentPrefix = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Check file name
|
||||
if (name == "file") {
|
||||
QString const filename { inputStream.readElementText() };
|
||||
|
||||
// Check ignore list
|
||||
QString const fullFilename { currentPrefix + filename };
|
||||
auto it = std::find_if(m_fileIgnoreList.cbegin(), m_fileIgnoreList.cend(), [&](QString const& pattern) {
|
||||
QRegExp re(pattern);
|
||||
re.setPatternSyntax(QRegExp::WildcardUnix);
|
||||
return re.exactMatch(fullFilename);
|
||||
});
|
||||
|
||||
if (it != m_fileIgnoreList.cend())
|
||||
continue;
|
||||
|
||||
QFileInfo const file { filename };
|
||||
|
||||
// Add to the watch list if the file suffix is allowed
|
||||
if (m_allowedSuffixList.contains(file.suffix())) {
|
||||
QString fp { m_selector.select(basePath + filename) };
|
||||
m_fileWatcher->addPath(fp);
|
||||
//qDebug() << " " << file.absoluteFilePath() << fp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_noDebug) {
|
||||
qDebug("Watching QML files:");
|
||||
int const fileCount = m_fileWatcher->files().size();
|
||||
|
||||
for (auto &f : m_fileWatcher->files()) {
|
||||
qDebug() << " " << f;
|
||||
}
|
||||
|
||||
if (fileCount > 0)
|
||||
qDebug(" Total: %d", fileCount);
|
||||
else
|
||||
qDebug(" None.");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unload the file watcher.
|
||||
*/
|
||||
void RuntimeQML::unloadFileWatcher()
|
||||
{
|
||||
if (m_fileWatcher) {
|
||||
disconnect(m_fileWatcher);
|
||||
delete m_fileWatcher;
|
||||
m_fileWatcher = nullptr;
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
#ifndef RUNTIMEQML_H
|
||||
#define RUNTIMEQML_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickWindow>
|
||||
#include <QFileSelector>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
class RuntimeQML : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString qrcFilename READ qrcFilename WRITE setQrcFilename NOTIFY qrcFilenameChanged)
|
||||
Q_PROPERTY(bool autoReload READ autoReload WRITE setAutoReload NOTIFY autoReloadChanged)
|
||||
Q_PROPERTY(bool closeAllOnReload READ closeAllOnReload WRITE setCloseAllOnReload NOTIFY closeAllOnReloadChanged)
|
||||
|
||||
public:
|
||||
explicit RuntimeQML(QQmlApplicationEngine *engine, QString const& qrcFilename = QString(), QObject *parent = 0);
|
||||
|
||||
// If using QQmlFileSelector with Loader
|
||||
Q_INVOKABLE QString adjustPath(QString qmlFile);
|
||||
Q_INVOKABLE QString qrcAbsolutePath() const;
|
||||
|
||||
QString qrcFilename() const;
|
||||
|
||||
bool autoReload() const;
|
||||
bool closeAllOnReload() const;
|
||||
|
||||
QList<QString> const & prefixIgnoreList() const;
|
||||
QList<QString> const & fileIgnoreList() const;
|
||||
QList<QString> const & allowedSuffixes() const;
|
||||
|
||||
void noDebug();
|
||||
|
||||
signals:
|
||||
void autoReloadChanged(bool autoReload);
|
||||
void qrcFilenameChanged(QString qrcFilename);
|
||||
void closeAllOnReloadChanged(bool closeAllOnReload);
|
||||
|
||||
public slots:
|
||||
void reload();
|
||||
void setWindow(QQuickWindow* window);
|
||||
|
||||
void setQrcFilename(QString qrcFilename);
|
||||
void setMainQmlFilename(QString filename);
|
||||
|
||||
void setAutoReload(bool autoReload);
|
||||
void setCloseAllOnReload(bool closeAllOnReload);
|
||||
|
||||
void ignoreQrcPrefix(QString const& prefix);
|
||||
void ignoreFile(QString const& filename);
|
||||
|
||||
void addSuffix(QString const& suffix);
|
||||
|
||||
private slots:
|
||||
void reloadQml();
|
||||
void fileChanged(const QString &path);
|
||||
|
||||
private:
|
||||
void loadQrcFiles();
|
||||
void unloadFileWatcher();
|
||||
|
||||
QQmlApplicationEngine *m_engine {nullptr};
|
||||
QQuickWindow *m_window {nullptr};
|
||||
QFileSelector m_selector;
|
||||
|
||||
QString m_qrcFilename;
|
||||
QString m_mainQmlFilename;
|
||||
|
||||
bool m_autoReload {false};
|
||||
QFileSystemWatcher* m_fileWatcher {nullptr};
|
||||
QList<QString> m_prefixIgnoreList;
|
||||
QList<QString> m_fileIgnoreList;
|
||||
QList<QString> m_allowedSuffixList;
|
||||
bool m_noDebug {false};
|
||||
bool m_closeAllOnReload {true};
|
||||
};
|
||||
|
||||
#endif // RUNTIMEQML_H
|
|
@ -1,13 +0,0 @@
|
|||
# Qt Quick Runtime Reloader
|
||||
|
||||
QT += core qml quick
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
DEFINES += "QRC_SOURCE_PATH=\\\"$$PWD/..\\\""
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/runtimeqml.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/runtimeqml.h
|
|
@ -1,18 +0,0 @@
|
|||
import qbs 1.0
|
||||
|
||||
StaticLibrary {
|
||||
name: "runtimeqml"
|
||||
files: [
|
||||
"runtimeqml.cpp",
|
||||
"runtimeqml.h",
|
||||
]
|
||||
Depends { name: 'cpp' }
|
||||
Depends { name: "Qt.core" }
|
||||
Depends { name: "Qt.quick" }
|
||||
|
||||
Export {
|
||||
Depends { name: "cpp" }
|
||||
cpp.includePaths: [product.sourceDirectory]
|
||||
cpp.defines: ['QRC_SOURCE_PATH="'+path+'/.."']
|
||||
}
|
||||
}
|
|
@ -14,10 +14,6 @@
|
|||
#include <QSequentialIterable>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef DISCORD
|
||||
#include "discord_rpc.h"
|
||||
#endif
|
||||
|
||||
void
|
||||
wakeup(void* ctx)
|
||||
{
|
||||
|
@ -79,12 +75,6 @@ DirectMpvPlayerBackend::DirectMpvPlayerBackend(QQuickItem* parent)
|
|||
if (!mpv)
|
||||
throw std::runtime_error("could not create mpv context");
|
||||
|
||||
#ifdef DISCORD
|
||||
DiscordEventHandlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
Discord_Initialize("511220330996432896", &handlers, 1, NULL);
|
||||
#endif
|
||||
|
||||
mpv_set_option_string(mpv, "terminal", "yes");
|
||||
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||
|
||||
|
@ -234,25 +224,6 @@ DirectMpvPlayerBackend::launchAboutQt()
|
|||
qapp->aboutQt();
|
||||
}
|
||||
|
||||
#ifdef DISCORD
|
||||
void
|
||||
DirectMpvPlayerBackend::updateDiscord()
|
||||
{
|
||||
char buffer[256];
|
||||
DiscordRichPresence discordPresence;
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
|
||||
sprintf(buffer,
|
||||
"Currently Playing: Video %s",
|
||||
getProperty("media-title").toString().toUtf8().constData());
|
||||
discordPresence.details = buffer;
|
||||
discordPresence.startTimestamp = time(0);
|
||||
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
|
||||
getProperty("time-pos").toFloat());
|
||||
discordPresence.instance = 0;
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
#endif
|
||||
QVariant
|
||||
DirectMpvPlayerBackend::playerCommand(const Enums::Commands& cmd)
|
||||
{
|
||||
|
@ -606,9 +577,6 @@ DirectMpvPlayerBackend::handle_mpv_event(mpv_event* event)
|
|||
double speed = *(double*)prop->data;
|
||||
emit speedChanged(speed);
|
||||
}
|
||||
#ifdef DISCORD
|
||||
updateDiscord();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MPV_EVENT_SHUTDOWN: {
|
||||
|
|
|
@ -103,9 +103,6 @@ private slots:
|
|||
|
||||
private:
|
||||
void handle_mpv_event(mpv_event* event);
|
||||
#ifdef DISCORD
|
||||
void updateDiscord();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,10 +12,6 @@
|
|||
#include <QSequentialIterable>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef DISCORD
|
||||
#include "discord_rpc.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <QX11Info>
|
||||
#include <QtX11Extras/QX11Info>
|
||||
|
@ -136,12 +132,6 @@ MpvPlayerBackend::MpvPlayerBackend(QQuickItem* parent)
|
|||
if (!mpv)
|
||||
throw std::runtime_error("could not create mpv context");
|
||||
|
||||
#ifdef DISCORD
|
||||
DiscordEventHandlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
Discord_Initialize("511220330996432896", &handlers, 1, NULL);
|
||||
#endif
|
||||
|
||||
mpv_set_option_string(mpv, "terminal", "yes");
|
||||
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||
|
||||
|
@ -243,33 +233,6 @@ MpvPlayerBackend::setOption(const QString& name, const QVariant& value)
|
|||
mpv::qt::set_option_variant(mpv, name, value);
|
||||
}
|
||||
|
||||
void
|
||||
MpvPlayerBackend::launchAboutQt()
|
||||
{
|
||||
QApplication* qapp =
|
||||
qobject_cast<QApplication*>(QCoreApplication::instance());
|
||||
qapp->aboutQt();
|
||||
}
|
||||
|
||||
#ifdef DISCORD
|
||||
void
|
||||
MpvPlayerBackend::updateDiscord()
|
||||
{
|
||||
char buffer[256];
|
||||
DiscordRichPresence discordPresence;
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
discordPresence.state = getProperty("pause").toBool() ? "Paused" : "Playing";
|
||||
sprintf(buffer,
|
||||
"Currently Playing: Video %s",
|
||||
getProperty("media-title").toString().toUtf8().constData());
|
||||
discordPresence.details = buffer;
|
||||
discordPresence.startTimestamp = time(0);
|
||||
discordPresence.endTimestamp = time(0) + (getProperty("duration").toFloat() -
|
||||
getProperty("time-pos").toFloat());
|
||||
discordPresence.instance = 0;
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
#endif
|
||||
QVariant
|
||||
MpvPlayerBackend::playerCommand(const Enums::Commands& cmd)
|
||||
{
|
||||
|
@ -496,12 +459,6 @@ MpvPlayerBackend::updateDurationString(int numTime)
|
|||
emit durationStringChanged(durationString);
|
||||
}
|
||||
|
||||
void
|
||||
MpvPlayerBackend::updateAppImage()
|
||||
{
|
||||
Utils::updateAppImage();
|
||||
}
|
||||
|
||||
QVariantMap
|
||||
MpvPlayerBackend::getAudioDevices(const QVariant& drivers) const
|
||||
{
|
||||
|
@ -591,9 +548,6 @@ MpvPlayerBackend::handle_mpv_event(mpv_event* event)
|
|||
double speed = *(double*)prop->data;
|
||||
emit speedChanged(speed);
|
||||
}
|
||||
#ifdef DISCORD
|
||||
updateDiscord();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MPV_EVENT_SHUTDOWN: {
|
||||
|
|
|
@ -46,9 +46,7 @@ public:
|
|||
public slots:
|
||||
QVariant playerCommand(const Enums::Commands& command, const QVariant& args);
|
||||
QVariant playerCommand(const Enums::Commands& command);
|
||||
void launchAboutQt();
|
||||
void toggleOnTop();
|
||||
void updateAppImage();
|
||||
// Optional but handy for MPV or custom backend settings.
|
||||
void command(const QVariant& params);
|
||||
void setProperty(const QString& name, const QVariant& value);
|
||||
|
@ -87,9 +85,6 @@ private slots:
|
|||
|
||||
private:
|
||||
void handle_mpv_event(mpv_event* event);
|
||||
#ifdef DISCORD
|
||||
void updateDiscord();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,9 +17,7 @@ public slots:
|
|||
virtual QVariant playerCommand(const Enums::Commands& command,
|
||||
const QVariant& args) = 0;
|
||||
virtual QVariant playerCommand(const Enums::Commands& command) = 0;
|
||||
virtual void launchAboutQt() = 0;
|
||||
virtual void toggleOnTop() = 0;
|
||||
virtual void updateAppImage() = 0;
|
||||
// Optional but handy for MPV or custom backend settings.
|
||||
virtual void command(const QVariant& params) = 0;
|
||||
virtual void setProperty(const QString& name, const QVariant& value) = 0;
|
||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -1,7 +1,3 @@
|
|||
#ifdef QRC_SOURCE_PATH
|
||||
#include "runtimeqml/runtimeqml.h"
|
||||
#endif
|
||||
|
||||
#include "DirectMpvPlayerBackend.h"
|
||||
#ifndef DISABLE_MpvPlayerBackend
|
||||
#include "MpvPlayerBackend.h"
|
||||
|
@ -138,7 +134,6 @@ main(int argc, char* argv[])
|
|||
qRegisterMetaType<Enums::PlayStatus>("Enums.PlayStatus");
|
||||
qRegisterMetaType<Enums::VolumeStatus>("Enums.VolumeStatus");
|
||||
qRegisterMetaType<Enums::Backends>("Enums.Backends");
|
||||
|
||||
qRegisterMetaType<Enums::Commands>("Enums.Commands");
|
||||
|
||||
qmlRegisterType<UtilsClass>("player", 1, 0, "Utils");
|
||||
|
@ -164,15 +159,7 @@ main(int argc, char* argv[])
|
|||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
#ifdef QRC_SOURCE_PATH
|
||||
RuntimeQML* rt = new RuntimeQML(&engine, QRC_SOURCE_PATH "/qml.qrc");
|
||||
|
||||
rt->setAutoReload(true);
|
||||
rt->setMainQmlFilename("main.qml");
|
||||
rt->reload();
|
||||
#else
|
||||
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ Item {
|
|||
|
||||
Item {
|
||||
id: controlsBar
|
||||
height: controlsBar.visible ? mainWindow.virtualHeight / 24 : 0
|
||||
height: controlsBar.visible ? mainWindow.virtualHeight / 20 : 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: parent.width / 128
|
||||
anchors.left: parent.left
|
||||
|
|
|
@ -218,7 +218,7 @@ MenuBar {
|
|||
}
|
||||
Action {
|
||||
text: translate.getTranslation("UPDATE", i18n.language)
|
||||
onTriggered: player.updateAppImage()
|
||||
onTriggered: utils.updateAppImage()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,7 @@ MenuBar {
|
|||
Action {
|
||||
text: translate.getTranslation("ABOUT_QT", i18n.language)
|
||||
onTriggered: {
|
||||
player.launchAboutQt()
|
||||
utils.launchAboutQt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -19,7 +19,6 @@ Button {
|
|||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||
display: AbstractButton.IconOnly
|
||||
|
||||
|
||||
onClicked: {
|
||||
var aptn = appearance.themeName
|
||||
appearance.themeName = aptn == "YouTube" ? "RoosterTeeth" : aptn
|
||||
|
|
|
@ -24,17 +24,17 @@ Button {
|
|||
}
|
||||
|
||||
function updateStatus(status) {
|
||||
if (volumeButton == null)
|
||||
console.log("OwO")
|
||||
if (volumeButton == null)
|
||||
console.log("OwO")
|
||||
|
||||
if (status == Enums.VolumeStatus.Muted) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-mute.svg"
|
||||
} else if (status == Enums.VolumeStatus.Low) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-down.svg"
|
||||
} else if (status == Enums.VolumeStatus.Normal) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-up.svg"
|
||||
}
|
||||
if (status == Enums.VolumeStatus.Muted) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-mute.svg"
|
||||
} else if (status == Enums.VolumeStatus.Low) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-down.svg"
|
||||
} else if (status == Enums.VolumeStatus.Normal) {
|
||||
volumeButton.icon.source = "qrc:/icons/" + appearance.themeName + "/volume-up.svg"
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: player
|
||||
|
|
|
@ -45,7 +45,7 @@ Slider {
|
|||
x: volumeBar.leftPadding
|
||||
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
|
||||
implicitWidth: layout.width / 11
|
||||
implicitHeight: appearance.themeName == "Niconico" ? layout.height / 8 : layout.height / 10
|
||||
implicitHeight: appearance.themeName == "Niconico" ? layout.height / 6 : layout.height / 10
|
||||
width: volumeBar.availableWidth
|
||||
height: implicitHeight
|
||||
color: getAppearanceValueForTheme(appearance.themeName,
|
||||
|
|
|
@ -45,8 +45,7 @@ Item {
|
|||
anchors.left: volumeButton.left
|
||||
anchors.right: volumeSlider.right
|
||||
anchors.top: parent.top
|
||||
width: volumeButton.width
|
||||
+ (volumeSlider.visible ? volumeSlider.width : 0)
|
||||
width: volumeButton.width + (volumeSlider.visible ? volumeSlider.width : 0)
|
||||
hoverEnabled: true
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
|
|
|
@ -25,6 +25,15 @@ getPlatformName()
|
|||
qobject_cast<QGuiApplication*>(QCoreApplication::instance());
|
||||
return qapp->platformName();
|
||||
}
|
||||
|
||||
void
|
||||
launchAboutQt()
|
||||
{
|
||||
QApplication* qapp =
|
||||
qobject_cast<QApplication*>(QCoreApplication::instance());
|
||||
qapp->aboutQt();
|
||||
}
|
||||
|
||||
void
|
||||
updateAppImage()
|
||||
{
|
||||
|
|
|
@ -15,8 +15,12 @@ void
|
|||
AlwaysOnTop(WId wid, bool on);
|
||||
void
|
||||
updateAppImage();
|
||||
int
|
||||
fast_mod(const int input, const int ceil);
|
||||
QString
|
||||
createTimestamp(int seconds);
|
||||
void
|
||||
launchAboutQt();
|
||||
}
|
||||
|
||||
class UtilsClass : public QObject
|
||||
|
@ -26,6 +30,8 @@ public slots:
|
|||
void SetDPMS(bool on) { Utils::SetDPMS(on); };
|
||||
void AlwaysOnTop(WId wid, bool on) { Utils::AlwaysOnTop(wid, on); };
|
||||
void updateAppImage() { Utils::updateAppImage(); };
|
||||
void launchAboutQt() { Utils::launchAboutQt(); };
|
||||
|
||||
QString createTimestamp(int seconds)
|
||||
{
|
||||
return Utils::createTimestamp(seconds);
|
||||
|
|
Loading…
Reference in a new issue