Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcd29b9fd2 | ||
|
|
046c221bc6 | ||
|
|
29a39b4e7f | ||
|
|
9fb3d06aac | ||
|
|
142d5e2347 | ||
|
|
58ea0bcbb0 | ||
|
|
1c0bbe5d33 | ||
|
|
8a7bba8ef3 | ||
|
|
3b93963688 | ||
|
|
77e5d0288f | ||
|
|
460e78a1b8 | ||
|
|
fcbade267d | ||
|
|
41b99d9aa0 | ||
|
|
96c761dbb5 | ||
|
|
d297564236 | ||
|
|
bca1a98938 | ||
|
|
23205bef65 | ||
|
|
7613b2f526 | ||
|
|
c5a521af1f | ||
|
|
f15c85e807 | ||
|
|
6129ad1f4d | ||
|
|
9972dc192b | ||
|
|
32b96a25e8 | ||
|
|
9d09e7f6fe | ||
|
|
5927483402 | ||
|
|
f228f79a8a | ||
|
|
072a3065cd | ||
|
|
718bd4c081 | ||
|
|
542cc0ec2f | ||
|
|
b357634f51 | ||
|
|
6968c4d0fb | ||
|
|
e35d618133 | ||
|
|
4a23fde6bf | ||
|
|
1ae577641d | ||
|
|
686a3bb42b | ||
|
|
1771d41871 | ||
|
|
ee8f4ca7ab | ||
|
|
4197a508a3 | ||
|
|
f38ffb505d | ||
|
|
679caf73d1 | ||
|
|
56d25c346c | ||
|
|
6ba26ba289 | ||
|
|
27582b7a4e | ||
|
|
2f4417d683 | ||
|
|
de97d29a82 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -39,6 +39,7 @@ Thumbs.db
|
||||
*.plist
|
||||
maketarball.sh
|
||||
dist/debian/changelog
|
||||
dist/pacman/PKGBUILD
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
@@ -23,7 +23,7 @@ before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install chromaprint ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export Qt5_DIR=/usr/local/opt/qt5/lib/cmake ; fi
|
||||
before_script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build cmake -Hstrawberry -Bbuild -DENABLE_STREAM_DEEZER=ON ; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DFORCE_GIT_REVISION="0.0.0-0-g0000000"; fi
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi
|
||||
|
||||
8
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
8
3rdparty/qtsingleapplication/CMakeLists.txt
vendored
@@ -13,11 +13,11 @@ set(SINGLEAPP-MOC-HEADERS
|
||||
qtsinglecoreapplication.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_win.cpp)
|
||||
elseif(WIN32)
|
||||
if(UNIX)
|
||||
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_unix.cpp)
|
||||
endif(WIN32)
|
||||
elseif(WIN32)
|
||||
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_win.cpp)
|
||||
endif()
|
||||
|
||||
QT5_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})
|
||||
|
||||
|
||||
2
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
2
3rdparty/qtsingleapplication/qtlocalpeer.cpp
vendored
@@ -157,7 +157,7 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||
Sleep(DWORD(ms));
|
||||
#else
|
||||
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
|
||||
nanosleep(&ts, NULL);
|
||||
nanosleep(&ts, nullptr);
|
||||
#endif
|
||||
}
|
||||
if (!connOk)
|
||||
|
||||
@@ -58,7 +58,7 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
||||
|
||||
Qt::HANDLE mutex;
|
||||
if (doCreate) {
|
||||
mutex = CreateMutexW(NULL, FALSE, (WCHAR*)mname.utf16());
|
||||
mutex = CreateMutexW(nullptr, FALSE, (WCHAR*)mname.utf16());
|
||||
if (!mutex) {
|
||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||
return 0;
|
||||
|
||||
@@ -45,10 +45,6 @@
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
|
||||
#ifdef HAVE_X11_ // FIXME
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#include "qtlocalpeer.h"
|
||||
|
||||
/*!
|
||||
@@ -178,47 +174,6 @@ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char *
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_X11_) // FIXME
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
||||
and \a cmap are passed on to the QApplication constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, visual, cmap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||
constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, argc, argv, visual, cmap)
|
||||
{
|
||||
sysInit();
|
||||
}
|
||||
|
||||
/*!
|
||||
Special constructor for X11, ref. the documentation of
|
||||
QApplication's corresponding constructor. The application identifier
|
||||
will be \a appId. \a dpy, \a argc, \a
|
||||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||
constructor.
|
||||
*/
|
||||
QtSingleApplication::QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||
: QApplication(dpy, argc, argv, visual, cmap)
|
||||
{
|
||||
sysInit(appId);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
Returns true if another instance of this application is running;
|
||||
otherwise false.
|
||||
|
||||
@@ -48,10 +48,6 @@
|
||||
#include <QApplication>
|
||||
#include <QString>
|
||||
|
||||
#if defined(HAVE_X11_) // FIXME
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class QtLocalPeer;
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_WIN32)
|
||||
@@ -77,11 +73,6 @@ class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
|
||||
public:
|
||||
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
||||
QtSingleApplication(const QString &id, int &argc, char **argv);
|
||||
#if defined(HAVE_X11_) // FIXME
|
||||
QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
|
||||
QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||
#endif
|
||||
|
||||
bool isRunning();
|
||||
QString id() const;
|
||||
|
||||
40
3rdparty/qxt/CMakeLists.txt
vendored
40
3rdparty/qxt/CMakeLists.txt
vendored
@@ -1,6 +1,13 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(X11)
|
||||
if (X11_FOUND)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
endif(X11_FOUND)
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
@@ -9,25 +16,16 @@ if (NOT WIN32 AND NOT APPLE)
|
||||
endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
|
||||
endif(NOT WIN32 AND NOT APPLE)
|
||||
|
||||
set(QXT-SOURCES
|
||||
qxtglobal.cpp
|
||||
qxtglobalshortcut.cpp
|
||||
)
|
||||
set(QXT-SOURCES qxtglobal.cpp qxtglobalshortcut.cpp)
|
||||
set(QXT-MOC-HEADERS qxtglobalshortcut.h )
|
||||
|
||||
set(QXT-MOC-HEADERS
|
||||
qxtglobalshortcut.h
|
||||
)
|
||||
|
||||
find_package(X11)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
|
||||
if(WIN32)
|
||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
|
||||
if(X11_FOUND)
|
||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp)
|
||||
elseif(APPLE)
|
||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp)
|
||||
else(WIN32)
|
||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp)
|
||||
endif(WIN32)
|
||||
elseif(WIN32)
|
||||
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
|
||||
endif()
|
||||
|
||||
QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS})
|
||||
|
||||
@@ -36,8 +34,8 @@ ADD_LIBRARY(qxt STATIC
|
||||
${QXT-SOURCES-MOC}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
|
||||
else(WIN32)
|
||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras)
|
||||
endif(WIN32)
|
||||
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
|
||||
|
||||
if(X11_FOUND)
|
||||
target_link_libraries(qxt Qt5::X11Extras)
|
||||
endif(X11_FOUND)
|
||||
|
||||
1
3rdparty/qxt/qxtglobal.cpp
vendored
1
3rdparty/qxt/qxtglobal.cpp
vendored
@@ -1,4 +1,3 @@
|
||||
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
|
||||
107
3rdparty/qxt/qxtglobal.h
vendored
107
3rdparty/qxt/qxtglobal.h
vendored
@@ -1,4 +1,3 @@
|
||||
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
@@ -161,73 +160,73 @@ template <typename PUB>
|
||||
class QxtPrivate
|
||||
{
|
||||
public:
|
||||
virtual ~QxtPrivate()
|
||||
{}
|
||||
inline void QXT_setPublic(PUB* pub)
|
||||
{
|
||||
qxt_p_ptr = pub;
|
||||
}
|
||||
virtual ~QxtPrivate()
|
||||
{}
|
||||
inline void QXT_setPublic(PUB* pub)
|
||||
{
|
||||
qxt_p_ptr = pub;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline PUB& qxt_p()
|
||||
{
|
||||
return *qxt_p_ptr;
|
||||
}
|
||||
inline const PUB& qxt_p() const
|
||||
{
|
||||
return *qxt_p_ptr;
|
||||
}
|
||||
inline PUB* qxt_ptr()
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
inline const PUB* qxt_ptr() const
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
inline PUB& qxt_p()
|
||||
{
|
||||
return *qxt_p_ptr;
|
||||
}
|
||||
inline const PUB& qxt_p() const
|
||||
{
|
||||
return *qxt_p_ptr;
|
||||
}
|
||||
inline PUB* qxt_ptr()
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
inline const PUB* qxt_ptr() const
|
||||
{
|
||||
return qxt_p_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
PUB* qxt_p_ptr;
|
||||
PUB* qxt_p_ptr;
|
||||
};
|
||||
|
||||
template <typename PUB, typename PVT>
|
||||
class QxtPrivateInterface
|
||||
{
|
||||
friend class QxtPrivate<PUB>;
|
||||
friend class QxtPrivate<PUB>;
|
||||
public:
|
||||
QxtPrivateInterface()
|
||||
{
|
||||
pvt = new PVT;
|
||||
}
|
||||
~QxtPrivateInterface()
|
||||
{
|
||||
delete pvt;
|
||||
}
|
||||
QxtPrivateInterface()
|
||||
{
|
||||
pvt = new PVT;
|
||||
}
|
||||
~QxtPrivateInterface()
|
||||
{
|
||||
delete pvt;
|
||||
}
|
||||
|
||||
inline void setPublic(PUB* pub)
|
||||
{
|
||||
pvt->QXT_setPublic(pub);
|
||||
}
|
||||
inline PVT& operator()()
|
||||
{
|
||||
return *static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline const PVT& operator()() const
|
||||
{
|
||||
return *static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline PVT * operator->()
|
||||
{
|
||||
inline void setPublic(PUB* pub)
|
||||
{
|
||||
pvt->QXT_setPublic(pub);
|
||||
}
|
||||
inline PVT& operator()()
|
||||
{
|
||||
return *static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline const PVT& operator()() const
|
||||
{
|
||||
return *static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline PVT * operator->()
|
||||
{
|
||||
return static_cast<PVT*>(pvt);
|
||||
}
|
||||
inline const PVT * operator->() const
|
||||
{
|
||||
}
|
||||
inline const PVT * operator->() const
|
||||
{
|
||||
return static_cast<PVT*>(pvt);
|
||||
}
|
||||
}
|
||||
private:
|
||||
QxtPrivateInterface(const QxtPrivateInterface&) { }
|
||||
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
|
||||
QxtPrivate<PUB>* pvt;
|
||||
QxtPrivateInterface(const QxtPrivateInterface&) { }
|
||||
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
|
||||
QxtPrivate<PUB>* pvt;
|
||||
};
|
||||
|
||||
#endif // QXT_GLOBAL
|
||||
|
||||
221
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
221
3rdparty/qxt/qxtglobalshortcut.cpp
vendored
@@ -38,185 +38,160 @@
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
|
||||
bool QxtGlobalShortcutPrivate::error = false;
|
||||
#ifndef Q_OS_MAC
|
||||
#ifndef Q_OS_MACOS
|
||||
int QxtGlobalShortcutPrivate::ref = 0;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
|
||||
#endif
|
||||
#endif // Q_OS_MAC
|
||||
#endif // Q_OS_MACOS
|
||||
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
|
||||
|
||||
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
if (!ref++)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
|
||||
#else
|
||||
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) {
|
||||
#ifndef Q_OS_MACOS
|
||||
if (!ref++)
|
||||
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
|
||||
#endif
|
||||
#endif // Q_OS_MAC
|
||||
#endif // Q_OS_MACOS
|
||||
}
|
||||
|
||||
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
if (!--ref)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
|
||||
#else
|
||||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
||||
#endif
|
||||
#endif // Q_OS_MAC
|
||||
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() {
|
||||
#ifndef Q_OS_MACOS
|
||||
if (!--ref)
|
||||
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
|
||||
#endif // Q_OS_MACOS
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)
|
||||
{
|
||||
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
|
||||
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
|
||||
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
|
||||
const quint32 nativeKey = nativeKeycode(key);
|
||||
const quint32 nativeMods = nativeModifiers(mods);
|
||||
const bool res = registerShortcut(nativeKey, nativeMods);
|
||||
if (res)
|
||||
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
|
||||
else
|
||||
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
|
||||
return res;
|
||||
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) {
|
||||
|
||||
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
|
||||
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
|
||||
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
|
||||
const quint32 nativeKey = nativeKeycode(key);
|
||||
const quint32 nativeMods = nativeModifiers(mods);
|
||||
const bool res = registerShortcut(nativeKey, nativeMods);
|
||||
if (res)
|
||||
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
|
||||
else
|
||||
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unsetShortcut()
|
||||
{
|
||||
bool res = false;
|
||||
const quint32 nativeKey = nativeKeycode(key);
|
||||
const quint32 nativeMods = nativeModifiers(mods);
|
||||
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
|
||||
res = unregisterShortcut(nativeKey, nativeMods);
|
||||
if (res)
|
||||
shortcuts.remove(qMakePair(nativeKey, nativeMods));
|
||||
else
|
||||
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
|
||||
key = Qt::Key(0);
|
||||
mods = Qt::KeyboardModifiers(0);
|
||||
return res;
|
||||
bool QxtGlobalShortcutPrivate::unsetShortcut() {
|
||||
bool res = false;
|
||||
const quint32 nativeKey = nativeKeycode(key);
|
||||
const quint32 nativeMods = nativeModifiers(mods);
|
||||
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
|
||||
res = unregisterShortcut(nativeKey, nativeMods);
|
||||
if (res)
|
||||
shortcuts.remove(qMakePair(nativeKey, nativeMods));
|
||||
else
|
||||
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
|
||||
key = Qt::Key(0);
|
||||
mods = Qt::KeyboardModifiers(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
|
||||
if (shortcut && shortcut->isEnabled())
|
||||
emit shortcut->activated();
|
||||
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
|
||||
if (shortcut && shortcut->isEnabled())
|
||||
emit shortcut->activated();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QxtGlobalShortcut
|
||||
\inmodule QxtWidgets
|
||||
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
|
||||
\class QxtGlobalShortcut
|
||||
\inmodule QxtWidgets
|
||||
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
|
||||
|
||||
A global shortcut triggers even if the application is not active. This
|
||||
makes it easy to implement applications that react to certain shortcuts
|
||||
still if some other application is active or if the application is for
|
||||
example minimized to the system tray.
|
||||
A global shortcut triggers even if the application is not active. This
|
||||
makes it easy to implement applications that react to certain shortcuts
|
||||
still if some other application is active or if the application is for
|
||||
example minimized to the system tray.
|
||||
|
||||
Example usage:
|
||||
\code
|
||||
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
|
||||
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
|
||||
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
|
||||
\endcode
|
||||
Example usage:
|
||||
\code
|
||||
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
|
||||
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
|
||||
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
|
||||
\endcode
|
||||
|
||||
\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
|
||||
\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QxtGlobalShortcut::activated()
|
||||
\fn QxtGlobalShortcut::activated()
|
||||
|
||||
This signal is emitted when the user types the shortcut's key sequence.
|
||||
This signal is emitted when the user types the shortcut's key sequence.
|
||||
|
||||
\sa shortcut
|
||||
\sa shortcut
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a new QxtGlobalShortcut with \a parent.
|
||||
Constructs a new QxtGlobalShortcut with \a parent.
|
||||
*/
|
||||
QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
||||
QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) : QObject(parent) {
|
||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
|
||||
Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
|
||||
*/
|
||||
QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
||||
setShortcut(shortcut);
|
||||
QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) : QObject(parent) {
|
||||
QXT_INIT_PRIVATE(QxtGlobalShortcut);
|
||||
setShortcut(shortcut);
|
||||
}
|
||||
|
||||
/*!
|
||||
Destructs the QxtGlobalShortcut.
|
||||
Destructs the QxtGlobalShortcut.
|
||||
*/
|
||||
QxtGlobalShortcut::~QxtGlobalShortcut()
|
||||
{
|
||||
if (qxt_d().key != 0)
|
||||
qxt_d().unsetShortcut();
|
||||
QxtGlobalShortcut::~QxtGlobalShortcut() {
|
||||
if (qxt_d().key != 0) qxt_d().unsetShortcut();
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QxtGlobalShortcut::shortcut
|
||||
\brief the shortcut key sequence
|
||||
\property QxtGlobalShortcut::shortcut
|
||||
\brief the shortcut key sequence
|
||||
|
||||
\bold {Note:} Notice that corresponding key press and release events are not
|
||||
delivered for registered global shortcuts even if they are disabled.
|
||||
Also, comma separated key sequences are not supported.
|
||||
Only the first part is used:
|
||||
\bold {Note:} Notice that corresponding key press and release events are not
|
||||
delivered for registered global shortcuts even if they are disabled.
|
||||
Also, comma separated key sequences are not supported.
|
||||
Only the first part is used:
|
||||
|
||||
\code
|
||||
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
|
||||
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
|
||||
\endcode
|
||||
\code
|
||||
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
|
||||
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
|
||||
\endcode
|
||||
*/
|
||||
QKeySequence QxtGlobalShortcut::shortcut() const
|
||||
{
|
||||
return QKeySequence(qxt_d().key | qxt_d().mods);
|
||||
QKeySequence QxtGlobalShortcut::shortcut() const {
|
||||
return QKeySequence(qxt_d().key | qxt_d().mods);
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut)
|
||||
{
|
||||
if (qxt_d().key != 0)
|
||||
qxt_d().unsetShortcut();
|
||||
return qxt_d().setShortcut(shortcut);
|
||||
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) {
|
||||
if (qxt_d().key != 0)
|
||||
qxt_d().unsetShortcut();
|
||||
return qxt_d().setShortcut(shortcut);
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QxtGlobalShortcut::enabled
|
||||
\brief whether the shortcut is enabled
|
||||
\property QxtGlobalShortcut::enabled
|
||||
\brief whether the shortcut is enabled
|
||||
|
||||
A disabled shortcut does not get activated.
|
||||
A disabled shortcut does not get activated.
|
||||
|
||||
The default value is \c true.
|
||||
The default value is \c true.
|
||||
|
||||
\sa setDisabled()
|
||||
\sa setDisabled()
|
||||
*/
|
||||
bool QxtGlobalShortcut::isEnabled() const
|
||||
{
|
||||
return qxt_d().enabled;
|
||||
bool QxtGlobalShortcut::isEnabled() const {
|
||||
return qxt_d().enabled;
|
||||
}
|
||||
|
||||
void QxtGlobalShortcut::setEnabled(bool enabled)
|
||||
{
|
||||
qxt_d().enabled = enabled;
|
||||
void QxtGlobalShortcut::setEnabled(bool enabled) {
|
||||
qxt_d().enabled = enabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the shortcut \a disabled.
|
||||
Sets the shortcut \a disabled.
|
||||
|
||||
\sa enabled
|
||||
\sa enabled
|
||||
*/
|
||||
void QxtGlobalShortcut::setDisabled(bool disabled)
|
||||
{
|
||||
qxt_d().enabled = !disabled;
|
||||
void QxtGlobalShortcut::setDisabled(bool disabled) {
|
||||
qxt_d().enabled = !disabled;
|
||||
}
|
||||
|
||||
|
||||
33
3rdparty/qxt/qxtglobalshortcut.h
vendored
33
3rdparty/qxt/qxtglobalshortcut.h
vendored
@@ -1,4 +1,3 @@
|
||||
#ifndef QXTGLOBALSHORTCUT_H
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
@@ -29,6 +28,7 @@
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QXTGLOBALSHORTCUT_H
|
||||
#define QXTGLOBALSHORTCUT_H
|
||||
|
||||
#include <QObject>
|
||||
@@ -39,30 +39,29 @@
|
||||
|
||||
class QxtGlobalShortcutPrivate;
|
||||
|
||||
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
||||
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
|
||||
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject {
|
||||
Q_OBJECT
|
||||
QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
||||
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
|
||||
|
||||
public:
|
||||
explicit QxtGlobalShortcut(QObject* parent = 0);
|
||||
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);
|
||||
virtual ~QxtGlobalShortcut();
|
||||
explicit QxtGlobalShortcut(QObject* parent = nullptr);
|
||||
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = nullptr);
|
||||
~QxtGlobalShortcut();
|
||||
|
||||
QKeySequence shortcut() const;
|
||||
bool setShortcut(const QKeySequence& shortcut);
|
||||
QKeySequence shortcut() const;
|
||||
bool setShortcut(const QKeySequence& shortcut);
|
||||
|
||||
bool isEnabled() const;
|
||||
bool isEnabled() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setEnabled(bool enabled = true);
|
||||
void setDisabled(bool disabled = true);
|
||||
void setEnabled(bool enabled = true);
|
||||
void setDisabled(bool disabled = true);
|
||||
|
||||
Q_SIGNALS:
|
||||
void activated();
|
||||
void activated();
|
||||
};
|
||||
|
||||
#endif // QXTGLOBALSHORTCUT_H
|
||||
#endif // QXTGLOBALSHORTCUT_H
|
||||
|
||||
|
||||
405
3rdparty/qxt/qxtglobalshortcut_mac.cpp
vendored
405
3rdparty/qxt/qxtglobalshortcut_mac.cpp
vendored
@@ -1,4 +1,3 @@
|
||||
#include <Carbon/Carbon.h>
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
@@ -29,230 +28,180 @@
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QtDebug>
|
||||
#include <QApplication>
|
||||
|
||||
typedef QPair<uint, uint> Identifier;
|
||||
static QMap<quint32, EventHotKeyRef> keyRefs;
|
||||
static QHash<Identifier, quint32> keyIDs;
|
||||
static quint32 hotKeySerial = 0;
|
||||
static bool qxt_mac_handler_installed = false;
|
||||
|
||||
OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
|
||||
{
|
||||
Q_UNUSED(nextHandler);
|
||||
Q_UNUSED(data);
|
||||
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
|
||||
{
|
||||
EventHotKeyID keyID;
|
||||
GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);
|
||||
Identifier id = keyIDs.key(keyID.id);
|
||||
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier)
|
||||
native |= shiftKey;
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
native |= cmdKey;
|
||||
if (modifiers & Qt::AltModifier)
|
||||
native |= optionKey;
|
||||
if (modifiers & Qt::MetaModifier)
|
||||
native |= controlKey;
|
||||
if (modifiers & Qt::KeypadModifier)
|
||||
native |= kEventKeyModifierNumLockMask;
|
||||
return native;
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
||||
{
|
||||
UTF16Char ch;
|
||||
// Constants found in NSEvent.h from AppKit.framework
|
||||
switch (key)
|
||||
{
|
||||
case Qt::Key_Return:
|
||||
return kVK_Return;
|
||||
case Qt::Key_Enter:
|
||||
return kVK_ANSI_KeypadEnter;
|
||||
case Qt::Key_Tab:
|
||||
return kVK_Tab;
|
||||
case Qt::Key_Space:
|
||||
return kVK_Space;
|
||||
case Qt::Key_Backspace:
|
||||
return kVK_Delete;
|
||||
case Qt::Key_Control:
|
||||
return kVK_Command;
|
||||
case Qt::Key_Shift:
|
||||
return kVK_Shift;
|
||||
case Qt::Key_CapsLock:
|
||||
return kVK_CapsLock;
|
||||
case Qt::Key_Option:
|
||||
return kVK_Option;
|
||||
case Qt::Key_Meta:
|
||||
return kVK_Control;
|
||||
case Qt::Key_F17:
|
||||
return kVK_F17;
|
||||
case Qt::Key_VolumeUp:
|
||||
return kVK_VolumeUp;
|
||||
case Qt::Key_VolumeDown:
|
||||
return kVK_VolumeDown;
|
||||
case Qt::Key_F18:
|
||||
return kVK_F18;
|
||||
case Qt::Key_F19:
|
||||
return kVK_F19;
|
||||
case Qt::Key_F20:
|
||||
return kVK_F20;
|
||||
case Qt::Key_F5:
|
||||
return kVK_F5;
|
||||
case Qt::Key_F6:
|
||||
return kVK_F6;
|
||||
case Qt::Key_F7:
|
||||
return kVK_F7;
|
||||
case Qt::Key_F3:
|
||||
return kVK_F3;
|
||||
case Qt::Key_F8:
|
||||
return kVK_F8;
|
||||
case Qt::Key_F9:
|
||||
return kVK_F9;
|
||||
case Qt::Key_F11:
|
||||
return kVK_F11;
|
||||
case Qt::Key_F13:
|
||||
return kVK_F13;
|
||||
case Qt::Key_F16:
|
||||
return kVK_F16;
|
||||
case Qt::Key_F14:
|
||||
return kVK_F14;
|
||||
case Qt::Key_F10:
|
||||
return kVK_F10;
|
||||
case Qt::Key_F12:
|
||||
return kVK_F12;
|
||||
case Qt::Key_F15:
|
||||
return kVK_F15;
|
||||
case Qt::Key_Help:
|
||||
return kVK_Help;
|
||||
case Qt::Key_Home:
|
||||
return kVK_Home;
|
||||
case Qt::Key_PageUp:
|
||||
return kVK_PageUp;
|
||||
case Qt::Key_Delete:
|
||||
return kVK_ForwardDelete;
|
||||
case Qt::Key_F4:
|
||||
return kVK_F4;
|
||||
case Qt::Key_End:
|
||||
return kVK_End;
|
||||
case Qt::Key_F2:
|
||||
return kVK_F2;
|
||||
case Qt::Key_PageDown:
|
||||
return kVK_PageDown;
|
||||
case Qt::Key_F1:
|
||||
return kVK_F1;
|
||||
case Qt::Key_Left:
|
||||
return kVK_LeftArrow;
|
||||
case Qt::Key_Right:
|
||||
return kVK_RightArrow;
|
||||
case Qt::Key_Down:
|
||||
return kVK_DownArrow;
|
||||
case Qt::Key_Up:
|
||||
return kVK_UpArrow;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (key == Qt::Key_Escape) ch = 27;
|
||||
else if (key == Qt::Key_Return) ch = 13;
|
||||
else if (key == Qt::Key_Enter) ch = 3;
|
||||
else if (key == Qt::Key_Tab) ch = 9;
|
||||
else ch = key;
|
||||
|
||||
CFDataRef currentLayoutData;
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
||||
|
||||
if (currentKeyboard == NULL)
|
||||
return 0;
|
||||
|
||||
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
CFRelease(currentKeyboard);
|
||||
if (currentLayoutData == NULL)
|
||||
return 0;
|
||||
|
||||
UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
|
||||
UCKeyboardTypeHeader* table = header->keyboardTypeList;
|
||||
|
||||
uint8_t *data = (uint8_t*)header;
|
||||
// God, would a little documentation for this shit kill you...
|
||||
for (quint32 i=0; i < header->keyboardTypeCount; i++)
|
||||
{
|
||||
UCKeyStateRecordsIndex* stateRec = 0;
|
||||
if (table[i].keyStateRecordsIndexOffset != 0)
|
||||
{
|
||||
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
|
||||
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
|
||||
}
|
||||
|
||||
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
|
||||
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
|
||||
|
||||
for (quint32 j=0; j < charTable->keyToCharTableCount; j++)
|
||||
{
|
||||
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
|
||||
for (quint32 k=0; k < charTable->keyToCharTableSize; k++)
|
||||
{
|
||||
if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
|
||||
{
|
||||
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
|
||||
if (stateRec && idx < stateRec->keyStateRecordCount)
|
||||
{
|
||||
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
|
||||
if (rec->stateZeroCharData == ch) return k;
|
||||
}
|
||||
}
|
||||
else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
|
||||
{
|
||||
if (keyToChar[k] == ch) return k;
|
||||
}
|
||||
} // for k
|
||||
} // for j
|
||||
} // for i
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
if (!qxt_mac_handler_installed)
|
||||
{
|
||||
EventTypeSpec t;
|
||||
t.eventClass = kEventClassKeyboard;
|
||||
t.eventKind = kEventHotKeyPressed;
|
||||
InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
|
||||
}
|
||||
|
||||
EventHotKeyID keyID;
|
||||
keyID.signature = 'cute';
|
||||
keyID.id = ++hotKeySerial;
|
||||
|
||||
EventHotKeyRef ref = 0;
|
||||
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
|
||||
if (rv)
|
||||
{
|
||||
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
|
||||
keyRefs.insert(keyID.id, ref);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
Identifier id(nativeMods, nativeKey);
|
||||
if (!keyIDs.contains(id)) return false;
|
||||
|
||||
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
|
||||
keyIDs.remove(id);
|
||||
return !UnregisterEventHotKey(ref);
|
||||
}
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QPair>
|
||||
#include <QtDebug>
|
||||
#include <QApplication>
|
||||
|
||||
typedef QPair<uint, uint> Identifier;
|
||||
static QMap<quint32, EventHotKeyRef> keyRefs;
|
||||
static QHash<Identifier, quint32> keyIDs;
|
||||
static quint32 hotKeySerial = 0;
|
||||
static bool qxt_mac_handler_installed = false;
|
||||
|
||||
OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) {
|
||||
|
||||
Q_UNUSED(nextHandler);
|
||||
Q_UNUSED(data);
|
||||
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) {
|
||||
EventHotKeyID keyID;
|
||||
GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, nullptr, sizeof(keyID), nullptr, &keyID);
|
||||
Identifier id = keyIDs.key(keyID.id);
|
||||
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
|
||||
}
|
||||
return noErr;
|
||||
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
|
||||
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier) native |= shiftKey;
|
||||
if (modifiers & Qt::ControlModifier) native |= cmdKey;
|
||||
if (modifiers & Qt::AltModifier) native |= optionKey;
|
||||
if (modifiers & Qt::MetaModifier) native |= controlKey;
|
||||
if (modifiers & Qt::KeypadModifier) native |= kEventKeyModifierNumLockMask;
|
||||
return native;
|
||||
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
|
||||
|
||||
UTF16Char ch;
|
||||
// Constants found in NSEvent.h from AppKit.framework
|
||||
switch (key) {
|
||||
case Qt::Key_Return: return kVK_Return;
|
||||
case Qt::Key_Enter: return kVK_ANSI_KeypadEnter;
|
||||
case Qt::Key_Tab: return kVK_Tab;
|
||||
case Qt::Key_Space: return kVK_Space;
|
||||
case Qt::Key_Backspace: return kVK_Delete;
|
||||
case Qt::Key_Control: return kVK_Command;
|
||||
case Qt::Key_Shift: return kVK_Shift;
|
||||
case Qt::Key_CapsLock: return kVK_CapsLock;
|
||||
case Qt::Key_Option: return kVK_Option;
|
||||
case Qt::Key_Meta: return kVK_Control;
|
||||
case Qt::Key_F17: return kVK_F17;
|
||||
case Qt::Key_VolumeUp: return kVK_VolumeUp;
|
||||
case Qt::Key_VolumeDown: return kVK_VolumeDown;
|
||||
case Qt::Key_F18: return kVK_F18;
|
||||
case Qt::Key_F19: return kVK_F19;
|
||||
case Qt::Key_F20: return kVK_F20;
|
||||
case Qt::Key_F5: return kVK_F5;
|
||||
case Qt::Key_F6: return kVK_F6;
|
||||
case Qt::Key_F7: return kVK_F7;
|
||||
case Qt::Key_F3: return kVK_F3;
|
||||
case Qt::Key_F8: return kVK_F8;
|
||||
case Qt::Key_F9: return kVK_F9;
|
||||
case Qt::Key_F11: return kVK_F11;
|
||||
case Qt::Key_F13: return kVK_F13;
|
||||
case Qt::Key_F16: return kVK_F16;
|
||||
case Qt::Key_F14: return kVK_F14;
|
||||
case Qt::Key_F10: return kVK_F10;
|
||||
case Qt::Key_F12: return kVK_F12;
|
||||
case Qt::Key_F15: return kVK_F15;
|
||||
case Qt::Key_Help: return kVK_Help;
|
||||
case Qt::Key_Home: return kVK_Home;
|
||||
case Qt::Key_PageUp: return kVK_PageUp;
|
||||
case Qt::Key_Delete: return kVK_ForwardDelete;
|
||||
case Qt::Key_F4: return kVK_F4;
|
||||
case Qt::Key_End: return kVK_End;
|
||||
case Qt::Key_F2: return kVK_F2;
|
||||
case Qt::Key_PageDown: return kVK_PageDown;
|
||||
case Qt::Key_F1: return kVK_F1;
|
||||
case Qt::Key_Left: return kVK_LeftArrow;
|
||||
case Qt::Key_Right: return kVK_RightArrow;
|
||||
case Qt::Key_Down: return kVK_DownArrow;
|
||||
case Qt::Key_Up: return kVK_UpArrow;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (key == Qt::Key_Escape) ch = 27;
|
||||
else if (key == Qt::Key_Return) ch = 13;
|
||||
else if (key == Qt::Key_Enter) ch = 3;
|
||||
else if (key == Qt::Key_Tab) ch = 9;
|
||||
else ch = key;
|
||||
|
||||
CFDataRef currentLayoutData;
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
||||
|
||||
if (currentKeyboard == nullptr)
|
||||
return 0;
|
||||
|
||||
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
CFRelease(currentKeyboard);
|
||||
if (currentLayoutData == nullptr)
|
||||
return 0;
|
||||
|
||||
UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
|
||||
UCKeyboardTypeHeader* table = header->keyboardTypeList;
|
||||
|
||||
uint8_t *data = (uint8_t*)header;
|
||||
// God, would a little documentation for this shit kill you...
|
||||
for (quint32 i=0; i < header->keyboardTypeCount; i++) {
|
||||
UCKeyStateRecordsIndex* stateRec = 0;
|
||||
if (table[i].keyStateRecordsIndexOffset != 0) {
|
||||
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
|
||||
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
|
||||
}
|
||||
|
||||
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
|
||||
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
|
||||
|
||||
for (quint32 j=0; j < charTable->keyToCharTableCount; j++) {
|
||||
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
|
||||
for (quint32 k=0; k < charTable->keyToCharTableSize; k++) {
|
||||
if (keyToChar[k] & kUCKeyOutputTestForIndexMask) {
|
||||
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
|
||||
if (stateRec && idx < stateRec->keyStateRecordCount) {
|
||||
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
|
||||
if (rec->stateZeroCharData == ch) return k;
|
||||
}
|
||||
}
|
||||
else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) {
|
||||
if (keyToChar[k] == ch) return k;
|
||||
}
|
||||
} // for k
|
||||
} // for j
|
||||
} // for i
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
|
||||
if (!qxt_mac_handler_installed) {
|
||||
EventTypeSpec t;
|
||||
t.eventClass = kEventClassKeyboard;
|
||||
t.eventKind = kEventHotKeyPressed;
|
||||
InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, nullptr, nullptr);
|
||||
}
|
||||
|
||||
EventHotKeyID keyID;
|
||||
keyID.signature = 'cute';
|
||||
keyID.id = ++hotKeySerial;
|
||||
|
||||
EventHotKeyRef ref = 0;
|
||||
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
|
||||
if (rv) {
|
||||
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
|
||||
keyRefs.insert(keyID.id, ref);
|
||||
}
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
|
||||
Identifier id(nativeMods, nativeKey);
|
||||
if (!keyIDs.contains(id)) return false;
|
||||
|
||||
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
|
||||
keyIDs.remove(id);
|
||||
return !UnregisterEventHotKey(ref);
|
||||
|
||||
}
|
||||
|
||||
156
3rdparty/qxt/qxtglobalshortcut_p.h
vendored
156
3rdparty/qxt/qxtglobalshortcut_p.h
vendored
@@ -1,84 +1,72 @@
|
||||
#ifndef QXTGLOBALSHORTCUT_P_H
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#define QXTGLOBALSHORTCUT_P_H
|
||||
|
||||
#include "qxtglobalshortcut.h"
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QKeySequence>
|
||||
#include <QHash>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#endif
|
||||
|
||||
|
||||
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
,public QAbstractNativeEventFilter
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
|
||||
QxtGlobalShortcutPrivate();
|
||||
~QxtGlobalShortcutPrivate();
|
||||
|
||||
bool enabled;
|
||||
Qt::Key key;
|
||||
Qt::KeyboardModifiers mods;
|
||||
|
||||
bool setShortcut(const QKeySequence& shortcut);
|
||||
bool unsetShortcut();
|
||||
|
||||
static bool error;
|
||||
#ifndef Q_OS_MAC
|
||||
static int ref;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
static QAbstractEventDispatcher::EventFilter prevEventFilter;
|
||||
static bool eventFilter(void* message);
|
||||
#else
|
||||
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
|
||||
#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
|
||||
private:
|
||||
static quint32 nativeKeycode(Qt::Key keycode);
|
||||
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
|
||||
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
|
||||
};
|
||||
|
||||
#endif // QXTGLOBALSHORTCUT_P_H
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QXTGLOBALSHORTCUT_P_H
|
||||
#define QXTGLOBALSHORTCUT_P_H
|
||||
|
||||
#include "qxtglobalshortcut.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QKeySequence>
|
||||
|
||||
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>, public QAbstractNativeEventFilter {
|
||||
public:
|
||||
QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
|
||||
QxtGlobalShortcutPrivate();
|
||||
~QxtGlobalShortcutPrivate();
|
||||
|
||||
bool enabled;
|
||||
Qt::Key key;
|
||||
Qt::KeyboardModifiers mods;
|
||||
|
||||
bool setShortcut(const QKeySequence& shortcut);
|
||||
bool unsetShortcut();
|
||||
|
||||
static bool error;
|
||||
#ifndef Q_OS_MACOS
|
||||
static int ref;
|
||||
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
|
||||
private:
|
||||
static quint32 nativeKeycode(Qt::Key keycode);
|
||||
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
|
||||
|
||||
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
|
||||
};
|
||||
|
||||
#endif // QXTGLOBALSHORTCUT_P_H
|
||||
|
||||
486
3rdparty/qxt/qxtglobalshortcut_win.cpp
vendored
486
3rdparty/qxt/qxtglobalshortcut_win.cpp
vendored
@@ -1,247 +1,239 @@
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#include <qt_windows.h>
|
||||
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
bool QxtGlobalShortcutPrivate::eventFilter(void* message)
|
||||
{
|
||||
#else
|
||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
|
||||
void * message, long * result)
|
||||
{
|
||||
Q_UNUSED(eventType);
|
||||
Q_UNUSED(result);
|
||||
#endif
|
||||
MSG* msg = static_cast<MSG*>(message);
|
||||
if (msg->message == WM_HOTKEY)
|
||||
{
|
||||
const quint32 keycode = HIWORD(msg->lParam);
|
||||
const quint32 modifiers = LOWORD(msg->lParam);
|
||||
activateShortcut(keycode, modifiers);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier)
|
||||
native |= MOD_SHIFT;
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
native |= MOD_CONTROL;
|
||||
if (modifiers & Qt::AltModifier)
|
||||
native |= MOD_ALT;
|
||||
if (modifiers & Qt::MetaModifier)
|
||||
native |= MOD_WIN;
|
||||
// TODO: resolve these?
|
||||
//if (modifiers & Qt::KeypadModifier)
|
||||
//if (modifiers & Qt::GroupSwitchModifier)
|
||||
return native;
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Qt::Key_Escape:
|
||||
return VK_ESCAPE;
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
return VK_TAB;
|
||||
case Qt::Key_Backspace:
|
||||
return VK_BACK;
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
return VK_RETURN;
|
||||
case Qt::Key_Insert:
|
||||
return VK_INSERT;
|
||||
case Qt::Key_Delete:
|
||||
return VK_DELETE;
|
||||
case Qt::Key_Pause:
|
||||
return VK_PAUSE;
|
||||
case Qt::Key_Print:
|
||||
return VK_PRINT;
|
||||
case Qt::Key_Clear:
|
||||
return VK_CLEAR;
|
||||
case Qt::Key_Home:
|
||||
return VK_HOME;
|
||||
case Qt::Key_End:
|
||||
return VK_END;
|
||||
case Qt::Key_Left:
|
||||
return VK_LEFT;
|
||||
case Qt::Key_Up:
|
||||
return VK_UP;
|
||||
case Qt::Key_Right:
|
||||
return VK_RIGHT;
|
||||
case Qt::Key_Down:
|
||||
return VK_DOWN;
|
||||
case Qt::Key_PageUp:
|
||||
return VK_PRIOR;
|
||||
case Qt::Key_PageDown:
|
||||
return VK_NEXT;
|
||||
case Qt::Key_F1:
|
||||
return VK_F1;
|
||||
case Qt::Key_F2:
|
||||
return VK_F2;
|
||||
case Qt::Key_F3:
|
||||
return VK_F3;
|
||||
case Qt::Key_F4:
|
||||
return VK_F4;
|
||||
case Qt::Key_F5:
|
||||
return VK_F5;
|
||||
case Qt::Key_F6:
|
||||
return VK_F6;
|
||||
case Qt::Key_F7:
|
||||
return VK_F7;
|
||||
case Qt::Key_F8:
|
||||
return VK_F8;
|
||||
case Qt::Key_F9:
|
||||
return VK_F9;
|
||||
case Qt::Key_F10:
|
||||
return VK_F10;
|
||||
case Qt::Key_F11:
|
||||
return VK_F11;
|
||||
case Qt::Key_F12:
|
||||
return VK_F12;
|
||||
case Qt::Key_F13:
|
||||
return VK_F13;
|
||||
case Qt::Key_F14:
|
||||
return VK_F14;
|
||||
case Qt::Key_F15:
|
||||
return VK_F15;
|
||||
case Qt::Key_F16:
|
||||
return VK_F16;
|
||||
case Qt::Key_F17:
|
||||
return VK_F17;
|
||||
case Qt::Key_F18:
|
||||
return VK_F18;
|
||||
case Qt::Key_F19:
|
||||
return VK_F19;
|
||||
case Qt::Key_F20:
|
||||
return VK_F20;
|
||||
case Qt::Key_F21:
|
||||
return VK_F21;
|
||||
case Qt::Key_F22:
|
||||
return VK_F22;
|
||||
case Qt::Key_F23:
|
||||
return VK_F23;
|
||||
case Qt::Key_F24:
|
||||
return VK_F24;
|
||||
case Qt::Key_Space:
|
||||
return VK_SPACE;
|
||||
case Qt::Key_Asterisk:
|
||||
return VK_MULTIPLY;
|
||||
case Qt::Key_Plus:
|
||||
return VK_ADD;
|
||||
case Qt::Key_Comma:
|
||||
return VK_SEPARATOR;
|
||||
case Qt::Key_Minus:
|
||||
return VK_SUBTRACT;
|
||||
case Qt::Key_Slash:
|
||||
return VK_DIVIDE;
|
||||
case Qt::Key_MediaNext:
|
||||
return VK_MEDIA_NEXT_TRACK;
|
||||
case Qt::Key_MediaPrevious:
|
||||
return VK_MEDIA_PREV_TRACK;
|
||||
case Qt::Key_MediaPlay:
|
||||
return VK_MEDIA_PLAY_PAUSE;
|
||||
case Qt::Key_MediaStop:
|
||||
return VK_MEDIA_STOP;
|
||||
// couldn't find those in VK_*
|
||||
//case Qt::Key_MediaLast:
|
||||
//case Qt::Key_MediaRecord:
|
||||
case Qt::Key_VolumeDown:
|
||||
return VK_VOLUME_DOWN;
|
||||
case Qt::Key_VolumeUp:
|
||||
return VK_VOLUME_UP;
|
||||
case Qt::Key_VolumeMute:
|
||||
return VK_VOLUME_MUTE;
|
||||
|
||||
// numbers
|
||||
case Qt::Key_0:
|
||||
case Qt::Key_1:
|
||||
case Qt::Key_2:
|
||||
case Qt::Key_3:
|
||||
case Qt::Key_4:
|
||||
case Qt::Key_5:
|
||||
case Qt::Key_6:
|
||||
case Qt::Key_7:
|
||||
case Qt::Key_8:
|
||||
case Qt::Key_9:
|
||||
return key;
|
||||
|
||||
// letters
|
||||
case Qt::Key_A:
|
||||
case Qt::Key_B:
|
||||
case Qt::Key_C:
|
||||
case Qt::Key_D:
|
||||
case Qt::Key_E:
|
||||
case Qt::Key_F:
|
||||
case Qt::Key_G:
|
||||
case Qt::Key_H:
|
||||
case Qt::Key_I:
|
||||
case Qt::Key_J:
|
||||
case Qt::Key_K:
|
||||
case Qt::Key_L:
|
||||
case Qt::Key_M:
|
||||
case Qt::Key_N:
|
||||
case Qt::Key_O:
|
||||
case Qt::Key_P:
|
||||
case Qt::Key_Q:
|
||||
case Qt::Key_R:
|
||||
case Qt::Key_S:
|
||||
case Qt::Key_T:
|
||||
case Qt::Key_U:
|
||||
case Qt::Key_V:
|
||||
case Qt::Key_W:
|
||||
case Qt::Key_X:
|
||||
case Qt::Key_Y:
|
||||
case Qt::Key_Z:
|
||||
return key;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
return UnregisterHotKey(0, nativeMods ^ nativeKey);
|
||||
}
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#include <qt_windows.h>
|
||||
|
||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, void * message, long * result) {
|
||||
|
||||
Q_UNUSED(eventType);
|
||||
Q_UNUSED(result);
|
||||
MSG* msg = static_cast<MSG*>(message);
|
||||
if (msg->message == WM_HOTKEY) {
|
||||
const quint32 keycode = HIWORD(msg->lParam);
|
||||
const quint32 modifiers = LOWORD(msg->lParam);
|
||||
activateShortcut(keycode, modifiers);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
|
||||
|
||||
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier)
|
||||
native |= MOD_SHIFT;
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
native |= MOD_CONTROL;
|
||||
if (modifiers & Qt::AltModifier)
|
||||
native |= MOD_ALT;
|
||||
if (modifiers & Qt::MetaModifier)
|
||||
native |= MOD_WIN;
|
||||
// TODO: resolve these?
|
||||
//if (modifiers & Qt::KeypadModifier)
|
||||
//if (modifiers & Qt::GroupSwitchModifier)
|
||||
return native;
|
||||
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
|
||||
|
||||
switch (key) {
|
||||
case Qt::Key_Escape:
|
||||
return VK_ESCAPE;
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
return VK_TAB;
|
||||
case Qt::Key_Backspace:
|
||||
return VK_BACK;
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
return VK_RETURN;
|
||||
case Qt::Key_Insert:
|
||||
return VK_INSERT;
|
||||
case Qt::Key_Delete:
|
||||
return VK_DELETE;
|
||||
case Qt::Key_Pause:
|
||||
return VK_PAUSE;
|
||||
case Qt::Key_Print:
|
||||
return VK_PRINT;
|
||||
case Qt::Key_Clear:
|
||||
return VK_CLEAR;
|
||||
case Qt::Key_Home:
|
||||
return VK_HOME;
|
||||
case Qt::Key_End:
|
||||
return VK_END;
|
||||
case Qt::Key_Left:
|
||||
return VK_LEFT;
|
||||
case Qt::Key_Up:
|
||||
return VK_UP;
|
||||
case Qt::Key_Right:
|
||||
return VK_RIGHT;
|
||||
case Qt::Key_Down:
|
||||
return VK_DOWN;
|
||||
case Qt::Key_PageUp:
|
||||
return VK_PRIOR;
|
||||
case Qt::Key_PageDown:
|
||||
return VK_NEXT;
|
||||
case Qt::Key_F1:
|
||||
return VK_F1;
|
||||
case Qt::Key_F2:
|
||||
return VK_F2;
|
||||
case Qt::Key_F3:
|
||||
return VK_F3;
|
||||
case Qt::Key_F4:
|
||||
return VK_F4;
|
||||
case Qt::Key_F5:
|
||||
return VK_F5;
|
||||
case Qt::Key_F6:
|
||||
return VK_F6;
|
||||
case Qt::Key_F7:
|
||||
return VK_F7;
|
||||
case Qt::Key_F8:
|
||||
return VK_F8;
|
||||
case Qt::Key_F9:
|
||||
return VK_F9;
|
||||
case Qt::Key_F10:
|
||||
return VK_F10;
|
||||
case Qt::Key_F11:
|
||||
return VK_F11;
|
||||
case Qt::Key_F12:
|
||||
return VK_F12;
|
||||
case Qt::Key_F13:
|
||||
return VK_F13;
|
||||
case Qt::Key_F14:
|
||||
return VK_F14;
|
||||
case Qt::Key_F15:
|
||||
return VK_F15;
|
||||
case Qt::Key_F16:
|
||||
return VK_F16;
|
||||
case Qt::Key_F17:
|
||||
return VK_F17;
|
||||
case Qt::Key_F18:
|
||||
return VK_F18;
|
||||
case Qt::Key_F19:
|
||||
return VK_F19;
|
||||
case Qt::Key_F20:
|
||||
return VK_F20;
|
||||
case Qt::Key_F21:
|
||||
return VK_F21;
|
||||
case Qt::Key_F22:
|
||||
return VK_F22;
|
||||
case Qt::Key_F23:
|
||||
return VK_F23;
|
||||
case Qt::Key_F24:
|
||||
return VK_F24;
|
||||
case Qt::Key_Space:
|
||||
return VK_SPACE;
|
||||
case Qt::Key_Asterisk:
|
||||
return VK_MULTIPLY;
|
||||
case Qt::Key_Plus:
|
||||
return VK_ADD;
|
||||
case Qt::Key_Comma:
|
||||
return VK_SEPARATOR;
|
||||
case Qt::Key_Minus:
|
||||
return VK_SUBTRACT;
|
||||
case Qt::Key_Slash:
|
||||
return VK_DIVIDE;
|
||||
case Qt::Key_MediaNext:
|
||||
return VK_MEDIA_NEXT_TRACK;
|
||||
case Qt::Key_MediaPrevious:
|
||||
return VK_MEDIA_PREV_TRACK;
|
||||
case Qt::Key_MediaPlay:
|
||||
return VK_MEDIA_PLAY_PAUSE;
|
||||
case Qt::Key_MediaStop:
|
||||
return VK_MEDIA_STOP;
|
||||
// couldn't find those in VK_*
|
||||
//case Qt::Key_MediaLast:
|
||||
//case Qt::Key_MediaRecord:
|
||||
case Qt::Key_VolumeDown:
|
||||
return VK_VOLUME_DOWN;
|
||||
case Qt::Key_VolumeUp:
|
||||
return VK_VOLUME_UP;
|
||||
case Qt::Key_VolumeMute:
|
||||
return VK_VOLUME_MUTE;
|
||||
|
||||
// numbers
|
||||
case Qt::Key_0:
|
||||
case Qt::Key_1:
|
||||
case Qt::Key_2:
|
||||
case Qt::Key_3:
|
||||
case Qt::Key_4:
|
||||
case Qt::Key_5:
|
||||
case Qt::Key_6:
|
||||
case Qt::Key_7:
|
||||
case Qt::Key_8:
|
||||
case Qt::Key_9:
|
||||
return key;
|
||||
|
||||
// letters
|
||||
case Qt::Key_A:
|
||||
case Qt::Key_B:
|
||||
case Qt::Key_C:
|
||||
case Qt::Key_D:
|
||||
case Qt::Key_E:
|
||||
case Qt::Key_F:
|
||||
case Qt::Key_G:
|
||||
case Qt::Key_H:
|
||||
case Qt::Key_I:
|
||||
case Qt::Key_J:
|
||||
case Qt::Key_K:
|
||||
case Qt::Key_L:
|
||||
case Qt::Key_M:
|
||||
case Qt::Key_N:
|
||||
case Qt::Key_O:
|
||||
case Qt::Key_P:
|
||||
case Qt::Key_Q:
|
||||
case Qt::Key_R:
|
||||
case Qt::Key_S:
|
||||
case Qt::Key_T:
|
||||
case Qt::Key_U:
|
||||
case Qt::Key_V:
|
||||
case Qt::Key_W:
|
||||
case Qt::Key_X:
|
||||
case Qt::Key_Y:
|
||||
case Qt::Key_Z:
|
||||
return key;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
return UnregisterHotKey(0, nativeMods ^ nativeKey);
|
||||
}
|
||||
|
||||
499
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
499
3rdparty/qxt/qxtglobalshortcut_x11.cpp
vendored
@@ -1,263 +1,236 @@
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
# include <QX11Info>
|
||||
#else
|
||||
# include <qpa/qplatformnativeinterface.h>
|
||||
# include <xcb/xcb.h>
|
||||
# include <QApplication>
|
||||
#endif
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QByteArray>
|
||||
#include <QGuiApplication>
|
||||
#include <QKeySequence>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "keymapper_x11.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const QVector<quint32> maskModifiers = QVector<quint32>()
|
||||
<< 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
|
||||
|
||||
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
|
||||
|
||||
class QxtX11ErrorHandler {
|
||||
public:
|
||||
static bool error;
|
||||
|
||||
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
|
||||
{
|
||||
Q_UNUSED(display);
|
||||
switch (event->error_code)
|
||||
{
|
||||
case BadAccess:
|
||||
case BadValue:
|
||||
case BadWindow:
|
||||
if (event->request_code == 33 /* X_GrabKey */ ||
|
||||
event->request_code == 34 /* X_UngrabKey */)
|
||||
{
|
||||
error = true;
|
||||
//TODO:
|
||||
//char errstr[256];
|
||||
//XGetErrorText(dpy, err->error_code, errstr, 256);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QxtX11ErrorHandler()
|
||||
{
|
||||
error = false;
|
||||
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
|
||||
}
|
||||
|
||||
~QxtX11ErrorHandler()
|
||||
{
|
||||
XSetErrorHandler(m_previousErrorHandler);
|
||||
}
|
||||
|
||||
private:
|
||||
X11ErrorHandler m_previousErrorHandler;
|
||||
};
|
||||
|
||||
bool QxtX11ErrorHandler::error = false;
|
||||
|
||||
class QxtX11Data {
|
||||
public:
|
||||
QxtX11Data()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
m_display = QX11Info::display();
|
||||
#else
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
void *display = native->nativeResourceForScreen(QByteArray("display"),
|
||||
QGuiApplication::primaryScreen());
|
||||
m_display = reinterpret_cast<Display *>(display);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
return m_display != 0;
|
||||
}
|
||||
|
||||
Display *display()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
return m_display;
|
||||
}
|
||||
|
||||
Window rootWindow()
|
||||
{
|
||||
return DefaultRootWindow(display());
|
||||
}
|
||||
|
||||
bool grabKey(quint32 keycode, quint32 modifiers, Window window)
|
||||
{
|
||||
QxtX11ErrorHandler errorHandler;
|
||||
|
||||
for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
|
||||
XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
|
||||
GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
|
||||
if (errorHandler.error) {
|
||||
ungrabKey(keycode, modifiers, window);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
|
||||
{
|
||||
QxtX11ErrorHandler errorHandler;
|
||||
|
||||
foreach (quint32 maskMods, maskModifiers) {
|
||||
XUngrabKey(display(), keycode, modifiers | maskMods, window);
|
||||
}
|
||||
|
||||
return !errorHandler.error;
|
||||
}
|
||||
|
||||
private:
|
||||
Display *m_display;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
bool QxtGlobalShortcutPrivate::eventFilter(void *message)
|
||||
{
|
||||
XEvent *event = static_cast<XEvent *>(message);
|
||||
if (event->type == KeyPress)
|
||||
{
|
||||
XKeyEvent *key = reinterpret_cast<XKeyEvent *>(event);
|
||||
unsigned int keycode = key->keycode;
|
||||
unsigned int keystate = key->state;
|
||||
#else
|
||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
|
||||
void *message, long *result)
|
||||
{
|
||||
Q_UNUSED(result);
|
||||
|
||||
xcb_key_press_event_t *kev = 0;
|
||||
if (eventType == "xcb_generic_event_t") {
|
||||
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
|
||||
if ((ev->response_type & 127) == XCB_KEY_PRESS)
|
||||
kev = static_cast<xcb_key_press_event_t *>(message);
|
||||
}
|
||||
|
||||
if (kev != 0) {
|
||||
unsigned int keycode = kev->detail;
|
||||
unsigned int keystate = 0;
|
||||
if(kev->state & XCB_MOD_MASK_1)
|
||||
keystate |= Mod1Mask;
|
||||
if(kev->state & XCB_MOD_MASK_CONTROL)
|
||||
keystate |= ControlMask;
|
||||
if(kev->state & XCB_MOD_MASK_4)
|
||||
keystate |= Mod4Mask;
|
||||
if(kev->state & XCB_MOD_MASK_SHIFT)
|
||||
keystate |= ShiftMask;
|
||||
#endif
|
||||
activateShortcut(keycode,
|
||||
// Mod1Mask == Alt, Mod4Mask == Meta
|
||||
keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier)
|
||||
native |= ShiftMask;
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
native |= ControlMask;
|
||||
if (modifiers & Qt::AltModifier)
|
||||
native |= Mod1Mask;
|
||||
if (modifiers & Qt::MetaModifier)
|
||||
native |= Mod4Mask;
|
||||
|
||||
// TODO: resolve these?
|
||||
//if (modifiers & Qt::MetaModifier)
|
||||
//if (modifiers & Qt::KeypadModifier)
|
||||
//if (modifiers & Qt::GroupSwitchModifier)
|
||||
return native;
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
|
||||
{
|
||||
// (davidsansome) Try the table from QKeyMapper first - this seems to be
|
||||
// the only way to get Keysyms for the media keys.
|
||||
unsigned int keysym = 0;
|
||||
int i = 0;
|
||||
while (KeyTbl[i]) {
|
||||
if (KeyTbl[i+1] == static_cast<uint>(key)) {
|
||||
keysym = KeyTbl[i];
|
||||
break;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
|
||||
// If that didn't work then fall back on XStringToKeysym
|
||||
if (!keysym) {
|
||||
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
|
||||
if (keysym == NoSymbol)
|
||||
keysym = static_cast<ushort>(key);
|
||||
}
|
||||
|
||||
QxtX11Data x11;
|
||||
if (!x11.isValid())
|
||||
return 0;
|
||||
|
||||
return XKeysymToKeycode(x11.display(), keysym);
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
QxtX11Data x11;
|
||||
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
|
||||
{
|
||||
QxtX11Data x11;
|
||||
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
|
||||
}
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** 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 LibQxt project 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.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qxtglobalshortcut_p.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QKeySequence>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QX11Info>
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include "keymapper_x11.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const QVector<quint32> maskModifiers = QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
|
||||
|
||||
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
|
||||
|
||||
class QxtX11ErrorHandler {
|
||||
public:
|
||||
static bool error;
|
||||
|
||||
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) {
|
||||
Q_UNUSED(display);
|
||||
switch (event->error_code) {
|
||||
case BadAccess:
|
||||
case BadValue:
|
||||
case BadWindow:
|
||||
if (event->request_code == 33 /* X_GrabKey */ ||
|
||||
event->request_code == 34 /* X_UngrabKey */)
|
||||
{
|
||||
error = true;
|
||||
//TODO:
|
||||
//char errstr[256];
|
||||
//XGetErrorText(dpy, err->error_code, errstr, 256);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QxtX11ErrorHandler() {
|
||||
error = false;
|
||||
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
|
||||
}
|
||||
|
||||
~QxtX11ErrorHandler() {
|
||||
XSetErrorHandler(m_previousErrorHandler);
|
||||
}
|
||||
|
||||
private:
|
||||
X11ErrorHandler m_previousErrorHandler;
|
||||
};
|
||||
|
||||
bool QxtX11ErrorHandler::error = false;
|
||||
|
||||
class QxtX11Data {
|
||||
public:
|
||||
QxtX11Data() {
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
//void *display = native->nativeResourceForScreen(QByteArray("display"), QGuiApplication::primaryScreen());
|
||||
//m_display = reinterpret_cast<Display *>(display);
|
||||
m_display = QX11Info::display();
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return m_display != nullptr;
|
||||
}
|
||||
|
||||
Display *display() {
|
||||
Q_ASSERT(isValid());
|
||||
return m_display;
|
||||
}
|
||||
|
||||
Window rootWindow() {
|
||||
return DefaultRootWindow(display());
|
||||
}
|
||||
|
||||
bool grabKey(quint32 keycode, quint32 modifiers, Window window) {
|
||||
QxtX11ErrorHandler errorHandler;
|
||||
|
||||
for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
|
||||
XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True, GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
|
||||
if (errorHandler.error) {
|
||||
ungrabKey(keycode, modifiers, window);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ungrabKey(quint32 keycode, quint32 modifiers, Window window) {
|
||||
QxtX11ErrorHandler errorHandler;
|
||||
|
||||
foreach (quint32 maskMods, maskModifiers) {
|
||||
XUngrabKey(display(), keycode, modifiers | maskMods, window);
|
||||
}
|
||||
|
||||
return !errorHandler.error;
|
||||
}
|
||||
|
||||
private:
|
||||
Display *m_display;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, void *message, long *result) {
|
||||
|
||||
Q_UNUSED(result);
|
||||
|
||||
xcb_key_press_event_t *kev = nullptr;
|
||||
if (eventType == "xcb_generic_event_t") {
|
||||
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
|
||||
if ((ev->response_type & 127) == XCB_KEY_PRESS)
|
||||
kev = static_cast<xcb_key_press_event_t *>(message);
|
||||
}
|
||||
|
||||
if (kev != nullptr) {
|
||||
unsigned int keycode = kev->detail;
|
||||
unsigned int keystate = 0;
|
||||
if(kev->state & XCB_MOD_MASK_1)
|
||||
keystate |= Mod1Mask;
|
||||
if(kev->state & XCB_MOD_MASK_CONTROL)
|
||||
keystate |= ControlMask;
|
||||
if(kev->state & XCB_MOD_MASK_4)
|
||||
keystate |= Mod4Mask;
|
||||
if(kev->state & XCB_MOD_MASK_SHIFT)
|
||||
keystate |= ShiftMask;
|
||||
|
||||
activateShortcut(keycode,
|
||||
// Mod1Mask == Alt, Mod4Mask == Meta
|
||||
keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
|
||||
|
||||
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
|
||||
quint32 native = 0;
|
||||
if (modifiers & Qt::ShiftModifier)
|
||||
native |= ShiftMask;
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
native |= ControlMask;
|
||||
if (modifiers & Qt::AltModifier)
|
||||
native |= Mod1Mask;
|
||||
if (modifiers & Qt::MetaModifier)
|
||||
native |= Mod4Mask;
|
||||
|
||||
// TODO: resolve these?
|
||||
//if (modifiers & Qt::MetaModifier)
|
||||
//if (modifiers & Qt::KeypadModifier)
|
||||
//if (modifiers & Qt::GroupSwitchModifier)
|
||||
return native;
|
||||
|
||||
}
|
||||
|
||||
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
|
||||
|
||||
// (davidsansome) Try the table from QKeyMapper first - this seems to be
|
||||
// the only way to get Keysyms for the media keys.
|
||||
unsigned int keysym = 0;
|
||||
int i = 0;
|
||||
while (KeyTbl[i]) {
|
||||
if (KeyTbl[i+1] == static_cast<uint>(key)) {
|
||||
keysym = KeyTbl[i];
|
||||
break;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
|
||||
// If that didn't work then fall back on XStringToKeysym
|
||||
if (!keysym) {
|
||||
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
|
||||
if (keysym == NoSymbol)
|
||||
keysym = static_cast<ushort>(key);
|
||||
}
|
||||
|
||||
QxtX11Data x11;
|
||||
if (!x11.isValid())
|
||||
return 0;
|
||||
|
||||
return XKeysymToKeycode(x11.display(), keysym);
|
||||
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
QxtX11Data x11;
|
||||
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
|
||||
}
|
||||
|
||||
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
|
||||
QxtX11Data x11;
|
||||
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@ cmake_minimum_required(VERSION 2.8.11)
|
||||
if(${CMAKE_VERSION} VERSION_GREATER "3.0")
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFiles)
|
||||
@@ -91,16 +88,12 @@ else(LINUX)
|
||||
find_package(ALSA)
|
||||
pkg_check_modules(DBUS dbus-1)
|
||||
endif(LINUX)
|
||||
if(ALSA_FOUND)
|
||||
set(HAVE_ALSA ON)
|
||||
endif()
|
||||
if (NOT APPLE)
|
||||
find_package(X11)
|
||||
endif()
|
||||
if(X11_FOUND)
|
||||
set(HAVE_X11 ON)
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED)
|
||||
pkg_check_modules(GSTREAMER gstreamer-1.0)
|
||||
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
|
||||
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-1.0)
|
||||
@@ -114,9 +107,9 @@ pkg_check_modules(LIBPULSE libpulse)
|
||||
pkg_check_modules(CHROMAPRINT libchromaprint)
|
||||
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
|
||||
pkg_check_modules(LIBMTP libmtp>=1.0)
|
||||
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0)
|
||||
pkg_check_modules(USBMUXD libusbmuxd)
|
||||
pkg_check_modules(PLIST libplist)
|
||||
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
|
||||
pkg_check_modules(LIBUSBMUXD libusbmuxd)
|
||||
pkg_check_modules(LIBPLIST libplist)
|
||||
pkg_check_modules(LIBDEEZER libdeezer)
|
||||
pkg_check_modules(LIBDZMEDIA libdzmedia)
|
||||
|
||||
@@ -126,7 +119,7 @@ endif(WIN32)
|
||||
|
||||
# QT
|
||||
set(QT_MIN_VERSION 5.5.1)
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Concurrent Widgets Network Sql OpenGL Xml)
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Concurrent Widgets Network Sql Xml)
|
||||
if(X11_FOUND)
|
||||
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras)
|
||||
endif()
|
||||
@@ -141,7 +134,7 @@ if(WIN32)
|
||||
find_package(Qt5 REQUIRED COMPONENTS WinExtras)
|
||||
endif()
|
||||
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::OpenGL Qt5::Xml)
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::Xml)
|
||||
|
||||
if(DBUS_FOUND)
|
||||
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::DBus)
|
||||
@@ -158,15 +151,25 @@ endif()
|
||||
|
||||
# TAGLIB
|
||||
pkg_check_modules(TAGLIB taglib)
|
||||
# Only use system taglib if it's greater than 1.11.1 because of audio file detection by content.
|
||||
# But let the user override as strawberry will still compile and work without.
|
||||
# Only use system taglib if it's greater than 1.11.1
|
||||
# There is a bug in version 1.11.1 corrupting Ogg files, see: https://github.com/taglib/taglib/issues/864
|
||||
# If you decide to use the systems taglib, make sure it has been patched with the following commit:
|
||||
# https://github.com/taglib/taglib/commit/9336c82da3a04552168f208cd7a5fa4646701ea4
|
||||
# The current taglib in 3rdparty also has the following features used by strawberry:
|
||||
# - Audio file detection by content.
|
||||
# - DSF and DSDIFF support
|
||||
#
|
||||
if (TAGLIB_VERSION VERSION_GREATER 1.11.1 OR WIN32)
|
||||
option(USE_SYSTEM_TAGLIB "Use system taglib" ON)
|
||||
else()
|
||||
option(USE_SYSTEM_TAGLIB "Use system taglib" OFF)
|
||||
endif()
|
||||
if (TAGLIB_FOUND AND USE_SYSTEM_TAGLIB)
|
||||
message(STATUS "Using system taglib library")
|
||||
if (TAGLIB_VERSION VERSION_GREATER 1.11.1 OR WIN32)
|
||||
message(STATUS "Using system taglib library")
|
||||
else()
|
||||
message(WARNING "Using system taglib library. Version 1.11.1 or less has a bug corrupting Ogg files, make sure your systems version has been patched!")
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_INCLUDES "${TAGLIB_INCLUDE_DIRS}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES)
|
||||
@@ -263,6 +266,14 @@ if(WIN32)
|
||||
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
|
||||
endif(WIN32)
|
||||
|
||||
optional_component(ALSA ON "ALSA integration"
|
||||
DEPENDS "alsa" ALSA_FOUND
|
||||
)
|
||||
|
||||
optional_component(LIBPULSE ON "Pulse audio integration"
|
||||
DEPENDS "libpulse" LIBPULSE_FOUND
|
||||
)
|
||||
|
||||
optional_component(DBUS ON "D-Bus support"
|
||||
DEPENDS "D-Bus" DBUS_FOUND
|
||||
)
|
||||
@@ -299,10 +310,6 @@ else ()
|
||||
)
|
||||
endif()
|
||||
|
||||
optional_component(LIBPULSE ON "Pulse audio integration"
|
||||
DEPENDS "libpulse" LIBPULSE_FOUND
|
||||
)
|
||||
|
||||
optional_component(LIBLASTFM ON "Last.fm album cover provider"
|
||||
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS
|
||||
)
|
||||
@@ -337,9 +344,9 @@ optional_component(LIBMTP ON "Devices: MTP support"
|
||||
)
|
||||
|
||||
optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
|
||||
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND
|
||||
DEPENDS "libplist" PLIST_FOUND
|
||||
DEPENDS "libusbmuxd" USBMUXD_FOUND
|
||||
DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
|
||||
DEPENDS "libplist" LIBPLIST_FOUND
|
||||
DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
|
||||
DEPENDS "iPod classic support" LIBGPOD_FOUND
|
||||
)
|
||||
|
||||
@@ -349,7 +356,12 @@ optional_component(SPARKLE ON "Sparkle integration"
|
||||
)
|
||||
|
||||
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
|
||||
optional_component(STREAM_DEEZER ON "Streaming: Deezer support")
|
||||
|
||||
if (LIBDZMEDIA_FOUND OR LIBDEEZER_FOUND)
|
||||
optional_component(STREAM_DEEZER ON "Streaming: Deezer support")
|
||||
else()
|
||||
optional_component(STREAM_DEEZER OFF "Streaming: Deezer support")
|
||||
endif()
|
||||
|
||||
optional_component(DZMEDIA ON "DZMedia"
|
||||
DEPENDS "libdzmedia" LIBDZMEDIA_FOUND
|
||||
@@ -376,7 +388,7 @@ include_directories(${GLIB_INCLUDE_DIRS})
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
|
||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||
|
||||
if(ENABLE_IMOBILEDEVICE AND IMOBILEDEVICE_VERSION VERSION_GREATER 1.1.1)
|
||||
if(HAVE_IMOBILEDEVICE AND LIBIMOBILEDEVICE_VERSION VERSION_GREATER 1.1.1)
|
||||
set(IMOBILEDEVICE_USES_UDIDS ON)
|
||||
endif()
|
||||
|
||||
|
||||
14
Changelog
14
Changelog
@@ -2,6 +2,20 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
Version 0.4.2:
|
||||
|
||||
* Updated AppStream data file to newer specifications
|
||||
* Fixed Deezer engine to use quality setting
|
||||
* Removed unneeded dependency Qt5OpenGL
|
||||
* Removed obsolete xine warning and engine reinitialization
|
||||
* Added ALSA as optional component in cmake
|
||||
* Fixed bug in playlist columns setting all visible
|
||||
* Added option to reset playlist columns
|
||||
* Fixed/Improved console logging
|
||||
* Added queue to play next option
|
||||
* (Windows) Corrected uninstalled files on x64 installer
|
||||
* (MacOS) Fixed poor performance
|
||||
|
||||
Version 0.4.1:
|
||||
|
||||
* Fixed crash in analyzer
|
||||
|
||||
@@ -4,12 +4,11 @@ run zypper --non-interactive --gpg-auto-import-keys ref
|
||||
run zypper --non-interactive --gpg-auto-import-keys dup -l -y
|
||||
|
||||
run zypper --non-interactive --gpg-auto-import-keys install \
|
||||
lsb-release \
|
||||
git tar make cmake gcc gcc-c++ pkg-config \
|
||||
lsb-release git tar make cmake gcc gcc-c++ pkg-config \
|
||||
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
|
||||
boost-devel protobuf-devel sqlite3-devel taglib-devel \
|
||||
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-devel \
|
||||
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5OpenGL-devel libQt5Sql-devel \
|
||||
libQt5Core-devel libQt5Gui-devel libQt5Widgets-devel libQt5Concurrent-devel libQt5Network-devel libQt5Sql-devel \
|
||||
libqt5-qtx11extras-devel libQt5Gui-private-headers-devel libqt5-qtbase-common-devel liblastfm-qt5-devel \
|
||||
libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel
|
||||
|
||||
|
||||
13
README.md
13
README.md
@@ -1,8 +1,8 @@
|
||||
:strawberry: Strawberry Music Player [](https://travis-ci.org/jonaski/strawberry)
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8)
|
||||
=======================
|
||||
|
||||
Strawberry is a audio player and music collection organizer. It is a fork of Clementine created in 2013 with a diffrent goal.
|
||||
It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
|
||||
Strawberry is a audio player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles. The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.
|
||||
|
||||
* Website: http://www.strawbs.org/
|
||||
* Github: https://github.com/jonaski/strawberry
|
||||
@@ -16,7 +16,7 @@ It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
|
||||
* Audio CD playback
|
||||
* Native desktop notifications
|
||||
* Playlists in multiple formats
|
||||
* Advanced output and device options with support for bit perfect playback on Linux
|
||||
* Advanced audio output and device configuration for bit-perfect playback on Linux
|
||||
* Edit tags on music files
|
||||
* Fetch tags from MusicBrainz
|
||||
* Album cover art from Last.fm, Musicbrainz and Discogs
|
||||
@@ -39,7 +39,8 @@ To build Strawberry from source you need the following installed on your system
|
||||
* [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
|
||||
* [Protobuf library and compiler](https://developers.google.com/protocol-buffers/)
|
||||
* [Boost development headers](https://www.boost.org/)
|
||||
* [Qt 5 with components Core, Gui, Widgets, Concurrent, Network, Sql, Xml, OpenGL, X11Extras and DBus](https://www.qt.io/)
|
||||
* [Qt 5 with components Core, Gui, Widgets, Concurrent, Network, Sql and Xml](https://www.qt.io/)
|
||||
* [Qt 5 components X11Extras and DBus for Linux/BSD, MacExtras for MacOs and WinExtras for Windows](https://www.qt.io/)
|
||||
* [SQLite3](https://www.sqlite.org)
|
||||
* [TagLib 1.11.1 or higher](http://taglib.org/)
|
||||
* [Chromaprint library](https://acoustid.org/chromaprint)
|
||||
@@ -81,3 +82,7 @@ Optional:
|
||||
|
||||
|
||||

|
||||
|
||||
### :moneybag: Donate
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8)
|
||||
|
||||
@@ -48,7 +48,7 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
|
||||
)
|
||||
elseif (${DIST_NAME} STREQUAL "fedora")
|
||||
if (DIST_VERSION)
|
||||
set(RPM_DISTRO "${DIST_NAME}${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
|
||||
set(RPM_DISTRO "fc${DIST_VERSION}" CACHE STRING "Suffix of the rpm file")
|
||||
else ()
|
||||
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
|
||||
endif()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||
set(STRAWBERRY_VERSION_MINOR 4)
|
||||
set(STRAWBERRY_VERSION_PATCH 1)
|
||||
set(STRAWBERRY_VERSION_PATCH 2)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
@@ -8,9 +8,11 @@ set(INCLUDE_GIT_REVISION OFF)
|
||||
set(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
|
||||
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_RPM_R "1")
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PAC_V "${majorminorpatch}")
|
||||
set(STRAWBERRY_VERSION_PAC_R "1")
|
||||
|
||||
if(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
|
||||
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}")
|
||||
@@ -82,10 +84,13 @@ if(GIT_REVISION)
|
||||
set(STRAWBERRY_VERSION_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
|
||||
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}")
|
||||
set(STRAWBERRY_VERSION_PAC_V "${GIT_TAGNAME}")
|
||||
set(STRAWBERRY_VERSION_PAC_R "${GIT_COMMITCOUNT}")
|
||||
|
||||
endif()
|
||||
|
||||
message(STATUS "Strawberry Version:")
|
||||
message(STATUS "Display: ${STRAWBERRY_VERSION_DISPLAY}")
|
||||
message(STATUS "Package: ${STRAWBERRY_VERSION_PACKAGE}")
|
||||
message(STATUS "Rpm: ${STRAWBERRY_VERSION_RPM_V}-${STRAWBERRY_VERSION_RPM_R}")
|
||||
message(STATUS "RPM: ${STRAWBERRY_VERSION_RPM_V}-${STRAWBERRY_VERSION_RPM_R}")
|
||||
message(STATUS "PAC: ${STRAWBERRY_VERSION_PAC_V}-${STRAWBERRY_VERSION_PAC_R}")
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<file>misc/playing_tooltip.txt</file>
|
||||
<file>misc/oauthsuccess.html</file>
|
||||
<file>pictures/strawberry.png</file>
|
||||
<file>pictures/strawbs-transparent.png</file>
|
||||
<file>pictures/noalbumart.png</file>
|
||||
<file>pictures/nomusic.png</file>
|
||||
<file>pictures/musicbrainz.png</file>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 175 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
@@ -4,7 +4,6 @@
|
||||
}
|
||||
|
||||
#playlist[default_background_enabled = "true"] {
|
||||
background-image: url(:pictures/strawbs-transparent.png);
|
||||
background-attachment: fixed;
|
||||
background-position: bottom right;
|
||||
background-repeat: none;
|
||||
|
||||
1
dist/CMakeLists.txt
vendored
1
dist/CMakeLists.txt
vendored
@@ -7,6 +7,7 @@ if (RPM_DISTRO)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec @ONLY)
|
||||
endif()
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pacman/PKGBUILD.in ${CMAKE_CURRENT_SOURCE_DIR}/pacman/PKGBUILD @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist.in ${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry.nsi @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi.in ${CMAKE_CURRENT_SOURCE_DIR}/windows/strawberry-64.nsi @ONLY)
|
||||
|
||||
4
dist/debian/control
vendored
4
dist/debian/control
vendored
@@ -20,7 +20,6 @@ Build-Depends: debhelper (>= 7),
|
||||
qtbase5-dev-tools,
|
||||
qtbase5-private-dev,
|
||||
qt5-dev-tools,
|
||||
libqt5opengl5-dev,
|
||||
libqt5x11extras5-dev,
|
||||
libgstreamer1.0-dev,
|
||||
libgstreamer-plugins-base1.0-dev,
|
||||
@@ -42,13 +41,14 @@ Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
libsqlite3-0,
|
||||
libqt5sql5-sqlite,
|
||||
gstreamer1.0-plugins-base,
|
||||
gstreamer1.0-plugins-good,
|
||||
gstreamer1.0-alsa,
|
||||
gstreamer1.0-pulseaudio
|
||||
Homepage: http://www.strawbs.org/
|
||||
Description: Audio player and music collection organizer
|
||||
Strawberry is a audio player especially aimed at audiophiles.
|
||||
Strawberry is a audio player aimed at music collectors, audio enthusiasts and audiophiles.
|
||||
.
|
||||
Features:
|
||||
- Play and organize music
|
||||
|
||||
8
dist/fedora/strawberry.spec.in
vendored
8
dist/fedora/strawberry.spec.in
vendored
@@ -10,6 +10,7 @@ Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
|
||||
BuildRequires: boost-devel
|
||||
BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: libappstream-glib
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: hicolor-icon-theme
|
||||
BuildRequires: liblastfm-qt5-devel
|
||||
@@ -34,7 +35,6 @@ BuildRequires: pkgconfig(Qt5Network)
|
||||
BuildRequires: pkgconfig(Qt5Xml)
|
||||
BuildRequires: pkgconfig(Qt5X11Extras)
|
||||
BuildRequires: pkgconfig(Qt5DBus)
|
||||
BuildRequires: pkgconfig(Qt5OpenGL)
|
||||
BuildRequires: pkgconfig(gstreamer-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-app-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-audio-1.0)
|
||||
@@ -67,7 +67,7 @@ Features:
|
||||
* Audio analyzer
|
||||
* Equalizer
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Integrated Tidal support
|
||||
* Integrated Tidal and Deezer support
|
||||
|
||||
%prep
|
||||
%setup -qn %{name}-@STRAWBERRY_VERSION_PACKAGE@
|
||||
@@ -91,10 +91,11 @@ popd
|
||||
|
||||
%install
|
||||
make install DESTDIR=%{buildroot} -C %{_target_platform}
|
||||
rm -rf %{buildroot}%{_datadir}/metainfo
|
||||
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
||||
|
||||
%check
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry.appdata.xml
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
@@ -107,6 +108,7 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
|
||||
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
||||
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
||||
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
||||
%{_datadir}/appdata/strawberry.appdata.xml
|
||||
%{_mandir}/man1/strawberry.1.*
|
||||
%{_mandir}/man1/strawberry-tagreader.1.*
|
||||
|
||||
|
||||
23
dist/opensuse/strawberry.spec.in
vendored
23
dist/opensuse/strawberry.spec.in
vendored
@@ -15,6 +15,7 @@ BuildRequires: boost-devel
|
||||
%endif
|
||||
BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: appstream-glib
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: hicolor-icon-theme
|
||||
BuildRequires: libQt5Gui-private-headers-devel
|
||||
@@ -41,7 +42,6 @@ BuildRequires: pkgconfig(Qt5Network)
|
||||
BuildRequires: pkgconfig(Qt5Xml)
|
||||
BuildRequires: pkgconfig(Qt5X11Extras)
|
||||
BuildRequires: pkgconfig(Qt5DBus)
|
||||
BuildRequires: pkgconfig(Qt5OpenGL)
|
||||
BuildRequires: pkgconfig(gstreamer-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-app-1.0)
|
||||
BuildRequires: pkgconfig(gstreamer-audio-1.0)
|
||||
@@ -57,6 +57,8 @@ BuildRequires: pkgconfig(libudf)
|
||||
BuildRequires: pkgconfig(libxine)
|
||||
BuildRequires: pkgconfig(libvlc)
|
||||
|
||||
Requires: libQt5Sql5-sqlite
|
||||
|
||||
%description
|
||||
Strawberry is a audio player and music collection organizer.
|
||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
@@ -76,7 +78,7 @@ Features:
|
||||
* Audio analyzer
|
||||
* Equalizer
|
||||
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
|
||||
* Integrated Tidal support
|
||||
* Integrated Tidal and Deezer support
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@
|
||||
@@ -88,12 +90,22 @@ make %{?_smp_mflags}
|
||||
%install
|
||||
cd build
|
||||
make install DESTDIR=$RPM_BUILD_ROOT
|
||||
rm -rf %{buildroot}%{_datadir}/metainfo
|
||||
%if 0%{?suse_version} < 1500
|
||||
mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
|
||||
%endif
|
||||
|
||||
%clean
|
||||
cd build
|
||||
make clean
|
||||
|
||||
%check
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
|
||||
%if 0%{?suse_version} >= 1500
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/strawberry.appdata.xml
|
||||
%else
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry.appdata.xml
|
||||
%endif
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc README.md Changelog
|
||||
@@ -105,6 +117,11 @@ make clean
|
||||
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
|
||||
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
|
||||
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
|
||||
%if 0%{?suse_version} >= 1500
|
||||
%{_datadir}/metainfo/strawberry.appdata.xml
|
||||
%else
|
||||
%{_datadir}/appdata/strawberry.appdata.xml
|
||||
%endif
|
||||
%{_mandir}/man1/%{name}.1%{?ext_man}
|
||||
%{_mandir}/man1/%{name}-tagreader.1%{?ext_man}
|
||||
|
||||
|
||||
65
dist/pacman/PKGBUILD.in
vendored
Normal file
65
dist/pacman/PKGBUILD.in
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Maintainer: Jonas Kvinge <jonas@jkvinge.net>
|
||||
pkgname=strawberry
|
||||
pkgver=@STRAWBERRY_VERSION_PAC_V@
|
||||
pkgrel=@STRAWBERRY_VERSION_PAC_R@
|
||||
pkgdesc="A music player aimed at audio enthusiasts and music collectors"
|
||||
arch=(x86_64)
|
||||
url="http://www.strawbs.org/"
|
||||
license=(GPL3)
|
||||
makedepends=(git cmake make gcc boost)
|
||||
depends=(
|
||||
desktop-file-utils
|
||||
hicolor-icon-theme
|
||||
udisks2
|
||||
protobuf
|
||||
qt5-base
|
||||
qt5-x11extras
|
||||
sqlite3
|
||||
alsa-lib
|
||||
pulseaudio
|
||||
dbus
|
||||
taglib
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
xine-lib
|
||||
vlc
|
||||
phonon-qt5
|
||||
chromaprint
|
||||
liblastfm-qt5
|
||||
)
|
||||
optdepends=(
|
||||
'libgpod: iPod classic support'
|
||||
'liblastfm-qt5: LastFM cover provider'
|
||||
'libcdio: Audio CD playback'
|
||||
'libmtp: MTP device support'
|
||||
'libusbmuxd: iPod Touch, iPhone, iPad support'
|
||||
'libplist: iPod Touch, iPhone, iPad support'
|
||||
'libimobiledevice: iPod Touch, iPhone, iPad support'
|
||||
)
|
||||
provides=(strawberry)
|
||||
conflicts=(strawberry)
|
||||
source=("git+https://github.com/jonaski/strawberry.git")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "strawberry"
|
||||
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/strawberry"
|
||||
install -d strawberry-build
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/strawberry/strawberry-build"
|
||||
cmake .. \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr
|
||||
make
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/strawberry/strawberry-build"
|
||||
make DESTDIR="${pkgdir}" install
|
||||
}
|
||||
35
dist/unix/strawberry.appdata.xml
vendored
35
dist/unix/strawberry.appdata.xml
vendored
@@ -1,16 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<application>
|
||||
<id type="desktop">strawberry.desktop</id>
|
||||
<component>
|
||||
<id>org.strawberry.strawberry</id>
|
||||
<launchable type="desktop-id">strawberry.desktop</launchable>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<provides>
|
||||
<binary>strawberry</binary>
|
||||
<binary>strawberry-tagreader</binary>
|
||||
</provides>
|
||||
<name>Strawberry Music Player</name>
|
||||
<summary>An audio player and music collection organizer</summary>
|
||||
<url type="homepage">https://www.strawbs.org/</url>
|
||||
<url type="bugtracker">https://github.com/jonaski/strawberry/</url>
|
||||
<translation type="qt">strawberry</translation>
|
||||
<description>
|
||||
<p>
|
||||
Strawberry is a audio player and music collection organizer.
|
||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
</p>
|
||||
<p>Features::</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Play and organize music</li>
|
||||
<li>Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF</li>
|
||||
@@ -24,15 +32,20 @@ It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
<li>Song lyrics from AudD and API Seeds</li>
|
||||
<li>Support for multiple backends</li>
|
||||
<li>Audio analyzer</li>
|
||||
<li>Equalizer</li>
|
||||
<li>Audio equalizer</li>
|
||||
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
|
||||
<li>Integrated Tidal support</li>
|
||||
<li>Integrated Tidal and Deezer support</li>
|
||||
</ul>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default" width="1920" height="1049">https://www.strawbs.org/pictures/screenshot-002-large.png</screenshot>
|
||||
<screenshot width="1920" height="1080">https://www.strawbs.org/pictures/screenshot-006-large.png</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Song playing showing context</caption>
|
||||
<image width="1600" height="874">https://www.strawbs.org/pictures/appdata-screenshot-001.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<caption>Collection overview</caption>
|
||||
<image width="1600" height="874">https://www.strawbs.org/pictures/appdata-screenshot-002.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">http://www.strawbs.org/</url>
|
||||
<updatecontact>eclipseo@fedoraproject.org</updatecontact>
|
||||
</application>
|
||||
<update_contact>eclipseo@fedoraproject.org</update_contact>
|
||||
</component>
|
||||
|
||||
6
dist/windows/strawberry-64.nsi.in
vendored
6
dist/windows/strawberry-64.nsi.in
vendored
@@ -315,12 +315,12 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\libbz2.dll"
|
||||
Delete "$INSTDIR\libcdio-18.dll"
|
||||
Delete "$INSTDIR\libchromaprint.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1-x64.dll"
|
||||
Delete "$INSTDIR\libfaad-2.dll"
|
||||
Delete "$INSTDIR\libffi-6.dll"
|
||||
Delete "$INSTDIR\libFLAC-8.dll"
|
||||
Delete "$INSTDIR\libfreetype-6.dll"
|
||||
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||
Delete "$INSTDIR\libgcc_s_seh-1.dll"
|
||||
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||
@@ -352,7 +352,7 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
||||
Delete "$INSTDIR\libspeex-1.dll"
|
||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||
Delete "$INSTDIR\libssl-1_1.dll"
|
||||
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
||||
Delete "$INSTDIR\libstdc++-6.dll"
|
||||
Delete "$INSTDIR\libtag.dll"
|
||||
Delete "$INSTDIR\libvorbis-0.dll"
|
||||
|
||||
6
dist/windows/strawberry-debug-64.nsi.in
vendored
6
dist/windows/strawberry-debug-64.nsi.in
vendored
@@ -347,12 +347,12 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\libbz2.dll"
|
||||
Delete "$INSTDIR\libcdio-18.dll"
|
||||
Delete "$INSTDIR\libchromaprint.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1.dll"
|
||||
Delete "$INSTDIR\libcrypto-1_1-x64.dll"
|
||||
Delete "$INSTDIR\libfaad-2.dll"
|
||||
Delete "$INSTDIR\libffi-6.dll"
|
||||
Delete "$INSTDIR\libFLAC-8.dll"
|
||||
Delete "$INSTDIR\libfreetype-6.dll"
|
||||
Delete "$INSTDIR\libgcc_s_sjlj-1.dll"
|
||||
Delete "$INSTDIR\libgcc_s_seh-1.dll"
|
||||
Delete "$INSTDIR\libgio-2.0-0.dll"
|
||||
Delete "$INSTDIR\libglib-2.0-0.dll"
|
||||
Delete "$INSTDIR\libgmodule-2.0-0.dll"
|
||||
@@ -384,7 +384,7 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\libprotobuf-15.dll"
|
||||
Delete "$INSTDIR\libspeex-1.dll"
|
||||
Delete "$INSTDIR\libsqlite3-0.dll"
|
||||
Delete "$INSTDIR\libssl-1_1.dll"
|
||||
Delete "$INSTDIR\libssl-1_1-x64.dll"
|
||||
Delete "$INSTDIR\libstdc++-6.dll"
|
||||
Delete "$INSTDIR\libtag.dll"
|
||||
Delete "$INSTDIR\libvorbis-0.dll"
|
||||
|
||||
@@ -263,7 +263,6 @@ void DumpStackTrace() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
QDebug CreateLoggerFatal(int line, const char *class_name) { return qCreateLogger(line, class_name, Fatal); }
|
||||
QDebug CreateLoggerError(int line, const char *class_name) { return qCreateLogger(line, class_name, Error); }
|
||||
|
||||
@@ -280,7 +279,6 @@ QNoDebug CreateLoggerDebug(int, const char*) { return QNoDebug(); }
|
||||
QDebug CreateLoggerInfo(int line, const char *class_name) { return qCreateLogger(line, class_name, Info); }
|
||||
QDebug CreateLoggerDebug(int line, const char *class_name) { return qCreateLogger(line, class_name, Debug); }
|
||||
#endif // QT_NO_DEBUG_OUTPUT
|
||||
#endif
|
||||
|
||||
} // namespace logging
|
||||
|
||||
|
||||
@@ -27,22 +27,11 @@
|
||||
#ifdef QT_NO_DEBUG_STREAM
|
||||
# define qLog(level) while (false) QNoDebug()
|
||||
#else
|
||||
#define qLog(level) \
|
||||
logging::CreateLogger(logging::Level_##level, \
|
||||
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), \
|
||||
__LINE__)
|
||||
#define qLog(level) logging::CreateLogger##level(__LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
#define qCreateLogger(line, class_name, level) logging::CreateLogger(logging::Level_##level, logging::ParsePrettyFunction(class_name), line)
|
||||
#endif // QT_NO_DEBUG_STREAM
|
||||
|
||||
#if 0
|
||||
#define qLog(level) \
|
||||
logging::CreateLogger##level(__LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
#define qCreateLogger(line, class_name, level) \
|
||||
logging::CreateLogger(logging::Level_##level, \
|
||||
logging::ParsePrettyFunction(class_name), \
|
||||
line)
|
||||
#endif
|
||||
|
||||
namespace logging {
|
||||
class NullDevice : public QIODevice {
|
||||
protected:
|
||||
|
||||
@@ -42,7 +42,6 @@ include_directories(${GOBJECT_INCLUDE_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${LIBXML_INCLUDE_DIRS})
|
||||
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
|
||||
if(HAVE_GSTREAMER)
|
||||
link_directories(${GSTREAMER_LIBRARY_DIRS})
|
||||
@@ -718,12 +717,12 @@ optional_source(HAVE_GIO
|
||||
HEADERS device/giolister.h
|
||||
)
|
||||
|
||||
# libimobiledevice backend and device
|
||||
# imobiledevice backend and device
|
||||
optional_source(HAVE_IMOBILEDEVICE
|
||||
INCLUDE_DIRECTORIES
|
||||
${IMOBILEDEVICE_INCLUDE_DIRS}
|
||||
${PLIST_INCLUDE_DIRS}
|
||||
${PLISTPP_INCLUDE_DIRS}
|
||||
${LIBIMOBILEDEVICE_INCLUDE_DIRS}
|
||||
${LIBPLIST_INCLUDE_DIRS}
|
||||
${LIBPLISTPP_INCLUDE_DIRS}
|
||||
SOURCES
|
||||
device/afcdevice.cpp
|
||||
device/afcfile.cpp
|
||||
@@ -966,12 +965,12 @@ endif(HAVE_AUDIOCD)
|
||||
|
||||
if(HAVE_IMOBILEDEVICE)
|
||||
target_link_libraries(strawberry_lib
|
||||
${IMOBILEDEVICE_LIBRARIES}
|
||||
${PLIST_LIBRARIES}
|
||||
${USBMUXD_LIBRARIES}
|
||||
${LIBIMOBILEDEVICE_LIBRARIES}
|
||||
${LIBPLIST_LIBRARIES}
|
||||
${LIBUSBMUXD_LIBRARIES}
|
||||
)
|
||||
link_directories(${IMOBILEDEVICE_LIBRARY_DIRS})
|
||||
link_directories(${USBMUXD_LIBRARY_DIRS})
|
||||
link_directories(${LIBIMOBILEDEVICE_LIBRARY_DIRS})
|
||||
link_directories(${LIBUSBMUXD_LIBRARY_DIRS})
|
||||
endif(HAVE_IMOBILEDEVICE)
|
||||
|
||||
if(HAVE_LIBMTP)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QGLWidget>
|
||||
#include <QVector>
|
||||
|
||||
#include "analyzer.h"
|
||||
|
||||
#include "engine/enginebase.h"
|
||||
|
||||
AnalyzerBase::AnalyzerBase(QWidget *parent)
|
||||
: QGLWidget(parent), engine_(nullptr) {}
|
||||
|
||||
void AnalyzerBase::set_engine(Engine::Base *engine) {
|
||||
disconnect(engine_);
|
||||
engine_ = engine;
|
||||
if (engine_) {
|
||||
connect(engine_, SIGNAL(SpectrumAvailable(const QVector<float>&)), SLOT(SpectrumAvailable(const QVector<float>&)));
|
||||
}
|
||||
}
|
||||
@@ -458,6 +458,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
|
||||
context_menu_->addSeparator();
|
||||
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, SLOT(AddToPlaylistEnqueue()));
|
||||
add_to_playlist_enqueue_next_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue to play next"), this, SLOT(AddToPlaylistEnqueueNext()));
|
||||
|
||||
#ifdef HAVE_GSTREAMER
|
||||
context_menu_->addSeparator();
|
||||
@@ -616,6 +617,16 @@ void CollectionView::AddToPlaylistEnqueue() {
|
||||
|
||||
}
|
||||
|
||||
void CollectionView::AddToPlaylistEnqueueNext() {
|
||||
|
||||
QMimeData *data = model()->mimeData(selectedIndexes());
|
||||
if (MimeData *mime_data = qobject_cast<MimeData*>(data)) {
|
||||
mime_data->enqueue_next_now_ = true;
|
||||
}
|
||||
emit AddToPlaylistSignal(data);
|
||||
|
||||
}
|
||||
|
||||
void CollectionView::OpenInNewPlaylist() {
|
||||
|
||||
QMimeData *data = model()->mimeData(selectedIndexes());
|
||||
|
||||
@@ -117,6 +117,7 @@ signals:
|
||||
void Load();
|
||||
void AddToPlaylist();
|
||||
void AddToPlaylistEnqueue();
|
||||
void AddToPlaylistEnqueueNext();
|
||||
void OpenInNewPlaylist();
|
||||
#ifdef HAVE_GSTREAMER
|
||||
void Organise();
|
||||
@@ -148,6 +149,7 @@ signals:
|
||||
QAction *load_;
|
||||
QAction *add_to_playlist_;
|
||||
QAction *add_to_playlist_enqueue_;
|
||||
QAction *add_to_playlist_enqueue_next_;
|
||||
QAction *open_in_new_playlist_;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
QAction *organise_;
|
||||
|
||||
@@ -76,7 +76,6 @@ CollectionWatcher::CollectionWatcher(QObject *parent)
|
||||
rescan_paused_(false),
|
||||
total_watches_(0),
|
||||
cue_parser_(new CueParser(backend_, this)) {
|
||||
Utilities::SetThreadIOPriority(Utilities::IOPRIO_CLASS_IDLE);
|
||||
|
||||
rescan_timer_->setInterval(1000);
|
||||
rescan_timer_->setSingleShot(true);
|
||||
|
||||
@@ -313,7 +313,7 @@ QString GetApplicationSupportPath() {
|
||||
NSString* user_path = [paths objectAtIndex:0];
|
||||
ret = QString::fromUtf8([user_path UTF8String]);
|
||||
} else {
|
||||
ret = "~/Collection/Application Support";
|
||||
ret = "~/Library/Application Support";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -544,6 +544,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
|
||||
playlist_queue_->setVisible(false);
|
||||
playlist_queue_->setShortcut(QKeySequence("Ctrl+D"));
|
||||
ui_->playlist->addAction(playlist_queue_);
|
||||
playlist_queue_play_next_ = playlist_menu_->addAction(IconLoader::Load("go-next"), tr("Queue selected tracks to play next"), this, SLOT(PlaylistQueuePlayNext()));
|
||||
playlist_queue_play_next_->setShortcut(QKeySequence("Ctrl+Shift+D"));
|
||||
playlist_queue_play_next_->setVisible(false);
|
||||
ui_->playlist->addAction(playlist_queue_play_next_);
|
||||
playlist_skip_ = playlist_menu_->addAction(IconLoader::Load("media-forward"), tr("Toggle skip status"), this, SLOT(PlaylistSkip()));
|
||||
playlist_skip_->setVisible(false);
|
||||
ui_->playlist->addAction(playlist_skip_);
|
||||
@@ -1184,8 +1188,6 @@ void MainWindow::UpdateTrackPosition() {
|
||||
|
||||
if (length <= 0) {
|
||||
// Probably a stream that we don't know the length of
|
||||
//ui_->track_slider->SetStopped();
|
||||
//tray_icon_->SetProgress(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1403,10 +1405,12 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
|
||||
if (selected < 1) {
|
||||
playlist_queue_->setVisible(false);
|
||||
playlist_queue_play_next_->setVisible(false);
|
||||
playlist_skip_->setVisible(false);
|
||||
}
|
||||
else {
|
||||
playlist_queue_->setVisible(true);
|
||||
playlist_queue_play_next_->setVisible(true);
|
||||
playlist_skip_->setVisible(true);
|
||||
if (in_queue == 1 && not_in_queue == 0) playlist_queue_->setText(tr("Dequeue track"));
|
||||
else if (in_queue > 1 && not_in_queue == 0) playlist_queue_->setText(tr("Dequeue selected tracks"));
|
||||
@@ -1414,6 +1418,11 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
|
||||
else if (in_queue == 0 && not_in_queue > 1) playlist_queue_->setText(tr("Queue selected tracks"));
|
||||
else playlist_queue_->setText(tr("Toggle queue status"));
|
||||
|
||||
if (selected > 1)
|
||||
playlist_queue_play_next_->setText(tr("Queue selected tracks to play next"));
|
||||
else
|
||||
playlist_queue_play_next_->setText(tr("Queue to play next"));
|
||||
|
||||
if (in_skipped == 1 && not_in_skipped == 0) playlist_skip_->setText(tr("Unskip track"));
|
||||
else if (in_skipped > 1 && not_in_skipped == 0) playlist_skip_->setText(tr("Unskip selected tracks"));
|
||||
else if (in_skipped == 0 && not_in_skipped == 1) playlist_skip_->setText(tr("Skip track"));
|
||||
@@ -2039,6 +2048,15 @@ void MainWindow::PlaylistQueue() {
|
||||
app_->playlist_manager()->current()->queue()->ToggleTracks(indexes);
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistQueuePlayNext() {
|
||||
QModelIndexList indexes;
|
||||
for (const QModelIndex& proxy_index : ui_->playlist->view()->selectionModel()->selectedRows()) {
|
||||
indexes << app_->playlist_manager()->current()->proxy()->mapToSource(proxy_index);
|
||||
}
|
||||
|
||||
app_->playlist_manager()->current()->queue()->InsertFirst(indexes);
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistSkip() {
|
||||
|
||||
QModelIndexList indexes;
|
||||
|
||||
@@ -168,6 +168,7 @@ signals:
|
||||
void PlaylistPlay();
|
||||
void PlaylistStopAfter();
|
||||
void PlaylistQueue();
|
||||
void PlaylistQueuePlayNext();
|
||||
void PlaylistSkip();
|
||||
void PlaylistRemoveCurrent();
|
||||
void PlaylistEditFinished(const QModelIndex& index);
|
||||
@@ -360,6 +361,7 @@ signals:
|
||||
#endif
|
||||
QAction *playlist_open_in_browser_;
|
||||
QAction *playlist_queue_;
|
||||
QAction* playlist_queue_play_next_;
|
||||
QAction *playlist_skip_;
|
||||
QAction *playlist_add_to_another_;
|
||||
QList<QAction*> playlistitem_actions_;
|
||||
|
||||
@@ -31,11 +31,12 @@ class MimeData : public QMimeData {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MimeData(bool clear = false, bool play_now = false, bool enqueue = false, bool open_in_new_playlist = false)
|
||||
MimeData(bool clear = false, bool play_now = false, bool enqueue = false, bool enqueue_next_now = false, bool open_in_new_playlist = false)
|
||||
: override_user_settings_(false),
|
||||
clear_first_(clear),
|
||||
play_now_(play_now),
|
||||
enqueue_now_(enqueue),
|
||||
enqueue_next_now_(enqueue_next_now),
|
||||
open_in_new_playlist_(open_in_new_playlist),
|
||||
name_for_new_playlist_(QString()),
|
||||
from_doubleclick_(false) {}
|
||||
|
||||
@@ -188,10 +188,6 @@ void QtSystemTrayIcon::SetStopped() {
|
||||
|
||||
}
|
||||
|
||||
void QtSystemTrayIcon::LastFMButtonVisibilityChanged(bool value) {
|
||||
|
||||
}
|
||||
|
||||
void QtSystemTrayIcon::MuteButtonStateChanged(bool value) {
|
||||
if (action_mute_) action_mute_->setChecked(value);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ protected:
|
||||
void SetPaused();
|
||||
void SetPlaying(bool enable_play_pause = false);
|
||||
void SetStopped();
|
||||
void LastFMButtonVisibilityChanged(bool value);
|
||||
void MuteButtonStateChanged(bool value);
|
||||
|
||||
// QObject
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
# include <QDBusConnection>
|
||||
# include <QDBusConnectionInterface>
|
||||
|
||||
@@ -117,7 +117,6 @@ void DeezerService::ReloadSettings() {
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(DeezerSettingsPage::kSettingsGroup);
|
||||
quality_ = s.value("quality", "FLAC").toString();
|
||||
searchdelay_ = s.value("searchdelay", 1500).toInt();
|
||||
albumssearchlimit_ = s.value("albumssearchlimit", 100).toInt();
|
||||
songssearchlimit_ = s.value("songssearchlimit", 100).toInt();
|
||||
|
||||
@@ -133,7 +133,6 @@ class DeezerService : public InternetService {
|
||||
#endif
|
||||
QTimer *timer_searchdelay_;
|
||||
|
||||
QString quality_;
|
||||
int searchdelay_;
|
||||
int albumssearchlimit_;
|
||||
int songssearchlimit_;
|
||||
|
||||
@@ -102,8 +102,8 @@ class DeviceManager : public QAbstractListModel {
|
||||
void SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format);
|
||||
|
||||
// QAbstractListModel
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
public slots:
|
||||
void Unmount(int row);
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
DeviceStateFilterModel::DeviceStateFilterModel(QObject *parent, DeviceManager::State state)
|
||||
: QSortFilterProxyModel(parent),
|
||||
state_(state)
|
||||
{
|
||||
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(ProxyRowCountChanged()));
|
||||
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(ProxyRowCountChanged()));
|
||||
connect(this, SIGNAL(modelReset()), SLOT(ProxyRowCountChanged()));
|
||||
state_(state) {
|
||||
|
||||
connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(ProxyRowCountChanged(QModelIndex, int, int)));
|
||||
connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(ProxyRowCountChanged(QModelIndex, int, int)));
|
||||
connect(this, SIGNAL(modelReset()), this, SLOT(ProxyRowCountChanged()));
|
||||
}
|
||||
|
||||
bool DeviceStateFilterModel::filterAcceptsRow(int row, const QModelIndex&) const {
|
||||
@@ -45,6 +45,10 @@ void DeviceStateFilterModel::ProxyRowCountChanged() {
|
||||
emit IsEmptyChanged(rowCount() == 0);
|
||||
}
|
||||
|
||||
void DeviceStateFilterModel::ProxyRowCountChanged(QModelIndex index, int first, int last) {
|
||||
emit IsEmptyChanged(rowCount() == 0);
|
||||
}
|
||||
|
||||
void DeviceStateFilterModel::setSourceModel(QAbstractItemModel *sourceModel) {
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
setDynamicSortFilter(true);
|
||||
|
||||
@@ -49,6 +49,7 @@ protected:
|
||||
|
||||
private slots:
|
||||
void ProxyRowCountChanged();
|
||||
void ProxyRowCountChanged(QModelIndex index, int first, int last);
|
||||
|
||||
private:
|
||||
DeviceManager::State state_;
|
||||
|
||||
@@ -71,24 +71,23 @@ const int DeviceItemDelegate::kIconPadding = 6;
|
||||
|
||||
DeviceItemDelegate::DeviceItemDelegate(QObject *parent) : CollectionItemDelegate(parent) {}
|
||||
|
||||
void DeviceItemDelegate::paint(QPainter *p, const QStyleOptionViewItem &opt, const QModelIndex &index) const {
|
||||
void DeviceItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
||||
|
||||
// Is it a device or a collection item?
|
||||
if (index.data(DeviceManager::Role::Role_State).isNull()) {
|
||||
CollectionItemDelegate::paint(p, opt, index);
|
||||
CollectionItemDelegate::paint(painter, option, index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw the background
|
||||
const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem*>(&opt);
|
||||
const QWidget *widget = vopt->widget;
|
||||
const QWidget *widget = option.widget;
|
||||
QStyle *style = widget->style() ? widget->style() : QApplication::style();
|
||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, widget);
|
||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget);
|
||||
|
||||
p->save();
|
||||
painter->save();
|
||||
|
||||
// Font for the status line
|
||||
QFont status_font(opt.font);
|
||||
QFont status_font(option.font);
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
status_font.setPointSize(status_font.pointSize() - 1);
|
||||
@@ -96,25 +95,25 @@ void DeviceItemDelegate::paint(QPainter *p, const QStyleOptionViewItem &opt, con
|
||||
status_font.setPointSize(status_font.pointSize() - 2);
|
||||
#endif
|
||||
|
||||
const int text_height = QFontMetrics(opt.font).height() + QFontMetrics(status_font).height();
|
||||
const int text_height = QFontMetrics(option.font).height() + QFontMetrics(status_font).height();
|
||||
|
||||
QRect line1(opt.rect);
|
||||
QRect line2(opt.rect);
|
||||
line1.setTop(line1.top() + (opt.rect.height() - text_height) / 2);
|
||||
line2.setTop(line1.top() + QFontMetrics(opt.font).height());
|
||||
QRect line1(option.rect);
|
||||
QRect line2(option.rect);
|
||||
line1.setTop(line1.top() + (option.rect.height() - text_height) / 2);
|
||||
line2.setTop(line1.top() + QFontMetrics(option.font).height());
|
||||
line1.setLeft(line1.left() + DeviceManager::kDeviceIconSize + kIconPadding);
|
||||
line2.setLeft(line2.left() + DeviceManager::kDeviceIconSize + kIconPadding);
|
||||
|
||||
// Change the color for selected items
|
||||
if (opt.state & QStyle::State_Selected) {
|
||||
p->setPen(opt.palette.color(QPalette::HighlightedText));
|
||||
if (option.state & QStyle::State_Selected) {
|
||||
painter->setPen(option.palette.color(QPalette::HighlightedText));
|
||||
}
|
||||
|
||||
// Draw the icon
|
||||
p->drawPixmap(opt.rect.topLeft(), index.data(Qt::DecorationRole).value<QPixmap>());
|
||||
painter->drawPixmap(option.rect.topLeft(), index.data(Qt::DecorationRole).value<QPixmap>());
|
||||
|
||||
// Draw the first line (device name)
|
||||
p->drawText(line1, Qt::AlignLeft | Qt::AlignTop, index.data().toString());
|
||||
painter->drawText(line1, Qt::AlignLeft | Qt::AlignTop, index.data().toString());
|
||||
|
||||
// Draw the second line (status)
|
||||
DeviceManager::State state = static_cast<DeviceManager::State>(index.data(DeviceManager::Role_State).toInt());
|
||||
@@ -155,14 +154,15 @@ void DeviceItemDelegate::paint(QPainter *p, const QStyleOptionViewItem &opt, con
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.state & QStyle::State_Selected)
|
||||
p->setPen(opt.palette.color(QPalette::HighlightedText));
|
||||
if (option.state & QStyle::State_Selected)
|
||||
painter->setPen(option.palette.color(QPalette::HighlightedText));
|
||||
else
|
||||
p->setPen(opt.palette.color(QPalette::Dark));
|
||||
p->setFont(status_font);
|
||||
p->drawText(line2, Qt::AlignLeft | Qt::AlignTop, status_text);
|
||||
painter->setPen(option.palette.color(QPalette::Dark));
|
||||
|
||||
p->restore();
|
||||
painter->setFont(status_font);
|
||||
painter->drawText(line2, Qt::AlignLeft | Qt::AlignTop, status_text);
|
||||
|
||||
painter->restore();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>300</height>
|
||||
<width>400</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
||||
@@ -84,7 +84,7 @@ class ScopedIOObject {
|
||||
|
||||
// Helpful MTP & USB links:
|
||||
// Apple USB device interface guide:
|
||||
// http://developer.apple.com/mac/collection/documentation/DeviceDrivers/Conceptual/USBBook/USBDeviceInterfaces/USBDevInterfaces.html
|
||||
// http://developer.apple.com/mac/library/documentation/DeviceDrivers/Conceptual/USBBook/USBDeviceInterfaces/USBDevInterfaces.html
|
||||
// Example Apple code for requesting a USB device descriptor:
|
||||
// http://www.opensource.apple.com/source/IOUSBFamily/IOUSBFamily-208.4.5/USBProber/BusProbeClass.m
|
||||
// Libmtp's detection code:
|
||||
@@ -122,12 +122,9 @@ void MacDeviceLister::Init() {
|
||||
for (int i = 0; i < num; ++i) {
|
||||
LIBMTP_device_entry_t device = devices[i];
|
||||
MTPDevice d;
|
||||
// FIXME:
|
||||
//d.vendor = QString::toLatin1(device.vendor);
|
||||
d.vendor = device.vendor;
|
||||
d.vendor = QString::fromLatin1(device.vendor);
|
||||
d.vendor_id = device.vendor_id;
|
||||
//d.product = QString::toLatin1(device.product);
|
||||
d.product = device.product;
|
||||
d.product = QString::fromLatin1(device.product);
|
||||
d.product_id = device.product_id;
|
||||
d.quirks = device.device_flags;
|
||||
sMTPDeviceList << d;
|
||||
@@ -355,9 +352,7 @@ void MacDeviceLister::DiskAddedCallback(DADiskRef disk, void* context) {
|
||||
#ifdef HAVE_AUDIOCD
|
||||
if (kind && strcmp([kind UTF8String], kIOCDMediaClass) == 0) {
|
||||
// CD inserted.
|
||||
// FIXME:
|
||||
//QString bsd_name = QString::toLatin1(DADiskGetBSDName(disk));
|
||||
QString bsd_name = DADiskGetBSDName(disk);
|
||||
QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk));
|
||||
me->cd_devices_ << bsd_name;
|
||||
emit me->DeviceAdded(bsd_name);
|
||||
return;
|
||||
@@ -396,9 +391,7 @@ void MacDeviceLister::DiskRemovedCallback(DADiskRef disk, void* context) {
|
||||
// We cannot access the USB tree when the disk is removed but we still get
|
||||
// the BSD disk name.
|
||||
|
||||
// FIXME:
|
||||
//QString bsd_name = QString::toLatin1(DADiskGetBSDName(disk));
|
||||
QString bsd_name = DADiskGetBSDName(disk);
|
||||
QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk));
|
||||
if (me->cd_devices_.remove(bsd_name)) {
|
||||
emit me->DeviceRemoved(bsd_name);
|
||||
return;
|
||||
@@ -571,9 +564,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
if (!ret || data.at(0) != 0x28)
|
||||
continue;
|
||||
|
||||
// FIXME:
|
||||
//if (QString::toLatin1(data.data() + 0x12, 3) != "MTP") {
|
||||
if (QString(data.data() + 0x12) != "MTP") {
|
||||
if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") {
|
||||
// Not quite.
|
||||
continue;
|
||||
}
|
||||
@@ -583,9 +574,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
//if (QString::toLatin1(data.data() + 0x12) != "MTP") {
|
||||
if (QString(data.data() + 0x12) != "MTP") {
|
||||
if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") {
|
||||
// Not quite.
|
||||
continue;
|
||||
}
|
||||
@@ -684,14 +673,14 @@ QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
|
||||
const MTPDevice& device = mtp_devices_[serial];
|
||||
QString str;
|
||||
str.sprintf("gphoto2://usb-%d-%d/", device.bus, device.address);
|
||||
QUrlQuery url_query;
|
||||
url_query.addQueryItem("vendor", device.vendor);
|
||||
url_query.addQueryItem("vendor_id", QString::number(device.vendor_id));
|
||||
url_query.addQueryItem("product", device.product);
|
||||
url_query.addQueryItem("product_id", QString::number(device.product_id));
|
||||
url_query.addQueryItem("quirks", QString::number(device.quirks));
|
||||
QUrl url(str);
|
||||
// FIXME:
|
||||
//QUrlQuery url(str);
|
||||
//url.addQueryItem("vendor", device.vendor);
|
||||
//url.addQueryItem("vendor_id", QString::number(device.vendor_id));
|
||||
//url.addQueryItem("product", device.product);
|
||||
//url.addQueryItem("product_id", QString::number(device.product_id));
|
||||
//url.addQueryItem("quirks", QString::number(device.quirks));
|
||||
url.setQuery(url_query);
|
||||
return QList<QUrl>() << url;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ QString About::MainHtml() const {
|
||||
|
||||
ret += QString("<p>");
|
||||
ret += QString("Strawberry is a audio player and music collection organizer.<br />");
|
||||
ret += QString("It's based on Clementine and Amarok 1.4, especially aimed at audiophiles.<br />");
|
||||
ret += QString("The name is inspired by the band Strawbs.");
|
||||
ret += QString("It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles.<br />");
|
||||
ret += QString("The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.");
|
||||
ret += QString("</p>");
|
||||
//ret += QString("<p>Website: <a href=\"http://www.strawbs.org/licenses/\">http://www.strawbs.org/</a></p>");
|
||||
ret += QString("<p>");
|
||||
|
||||
@@ -61,7 +61,6 @@ DeezerEngine::DeezerEngine(TaskManager *task_manager)
|
||||
stopping_(false) {
|
||||
|
||||
type_ = Engine::Deezer;
|
||||
ReloadSettings();
|
||||
|
||||
}
|
||||
|
||||
@@ -158,11 +157,37 @@ bool DeezerEngine::Init() {
|
||||
}
|
||||
|
||||
LoadAccessToken();
|
||||
ReloadSettings();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::ReloadSettings() {
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(DeezerSettingsPage::kSettingsGroup);
|
||||
QString quality = s.value("quality", "FLAC").toString();
|
||||
s.endGroup();
|
||||
dz_error_t dzerr;
|
||||
|
||||
if (quality == "MP3_128")
|
||||
dzerr = dz_player_set_track_quality(player_, nullptr, nullptr, DZ_TRACK_QUALITY_STANDARD);
|
||||
else if (quality == "MP3_320")
|
||||
dzerr = dz_player_set_track_quality(player_, nullptr, nullptr, DZ_TRACK_QUALITY_HIGHQUALITY);
|
||||
else if (quality == "FLAC")
|
||||
dzerr = dz_player_set_track_quality(player_, nullptr, nullptr, DZ_TRACK_QUALITY_CDQUALITY);
|
||||
else if (quality == "DATA_EFFICIENT")
|
||||
dzerr = dz_player_set_track_quality(player_, nullptr, nullptr, DZ_TRACK_QUALITY_DATA_EFFICIENT);
|
||||
else
|
||||
dzerr = dz_player_set_track_quality(player_, nullptr, nullptr, DZ_TRACK_QUALITY_CDQUALITY);
|
||||
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set quality.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DeezerEngine::Initialised() const {
|
||||
|
||||
if (connect_ && player_) return true;
|
||||
|
||||
@@ -45,6 +45,7 @@ class DeezerEngine : public Engine::Base {
|
||||
~DeezerEngine();
|
||||
|
||||
bool Init();
|
||||
void ReloadSettings();
|
||||
Engine::State state() const { return state_; }
|
||||
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
|
||||
@@ -106,24 +106,11 @@ GstEngine::GstEngine(TaskManager *task_manager)
|
||||
|
||||
ReloadSettings();
|
||||
|
||||
#ifdef Q_OS_MACOS___ // FIXME
|
||||
QDir resources_dir(mac::getResourcesPath());
|
||||
QString ca_cert_path = resources_dir.filePath("cacert.pem");
|
||||
GError *error = nullptr;
|
||||
tls_database_ = g_tls_file_database_new(ca_cert_path.toUtf8().data(), &error);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
GstEngine::~GstEngine() {
|
||||
|
||||
EnsureInitialised();
|
||||
|
||||
current_pipeline_.reset();
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
g_object_unref(tls_database_);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GstEngine::Init() {
|
||||
@@ -436,13 +423,7 @@ void GstEngine::SetEnvironment() {
|
||||
QString plugin_path;
|
||||
QString registry_filename;
|
||||
|
||||
// On windows and mac we bundle the gstreamer plugins with strawberry
|
||||
#if defined(Q_OS_MACOS)
|
||||
//scanner_path = QCoreApplication::applicationDirPath() + "/../PlugIns/gst-plugin-scanner";
|
||||
//plugin_path = QCoreApplication::applicationDirPath() + "/../PlugIns/gstreamer";
|
||||
scanner_path = "/usr/local/Cellar/gstreamer/1.14.1/libexec/gstreamer-1.0/gst-plugin-scanner";
|
||||
plugin_path = "/usr/local/lib/gstreamer-1.0";
|
||||
#endif
|
||||
// On windows we bundle the gstreamer plugins with strawberry
|
||||
#if defined(Q_OS_WIN32)
|
||||
plugin_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/gstreamer-plugins");
|
||||
#endif
|
||||
@@ -463,10 +444,6 @@ void GstEngine::SetEnvironment() {
|
||||
Utilities::SetEnv("GST_REGISTRY", registry_filename);
|
||||
}
|
||||
|
||||
//#ifdef Q_OS_MACOS
|
||||
//Utilities::SetEnv("GIO_EXTRA_MODULES", QCoreApplication::applicationDirPath() + "/../PlugIns/gio-modules");
|
||||
//#endif
|
||||
|
||||
Utilities::SetEnv("PULSE_PROP_media.role", "music");
|
||||
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
|
||||
// Dragged from a collection
|
||||
// We want to check if these songs are from the actual local file backend, if they are we treat them differently.
|
||||
if (song_data->backend && song_data->backend->songs_table() == SCollection::kSongsTable)
|
||||
InsertSongItems<CollectionPlaylistItem>(song_data->songs, row, play_now, enqueue_now);
|
||||
InsertSongItems<CollectionPlaylistItem>(song_data->songs, row, play_now, enqueue_now, enqueue_next_now);
|
||||
else
|
||||
InsertSongItems<SongPlaylistItem>(song_data->songs, row, play_now, enqueue_now, enqueue_next_now);
|
||||
}
|
||||
@@ -700,7 +700,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
|
||||
|
||||
if (items.count() > kUndoItemLimit) {
|
||||
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
|
||||
InsertItemsWithoutUndo(items, row, false);
|
||||
InsertItemsWithoutUndo(items, row, false, false);
|
||||
undo_stack_->clear();
|
||||
}
|
||||
else {
|
||||
@@ -718,11 +718,11 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
|
||||
else if (data->hasFormat(kCddaMimeType)) {
|
||||
SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player());
|
||||
connect(inserter, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||
inserter->LoadAudioCD(this, row, play_now, enqueue_now);
|
||||
inserter->LoadAudioCD(this, row, play_now, enqueue_now, enqueue_next_now);
|
||||
}
|
||||
else if (data->hasUrls()) {
|
||||
// URL list dragged from the file list or some other app
|
||||
InsertUrls(data->urls(), row, play_now, enqueue_now);
|
||||
InsertUrls(data->urls(), row, play_now, enqueue_now, enqueue_next_now);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -734,7 +734,7 @@ void Playlist::InsertUrls(const QList<QUrl> &urls, int pos, bool play_now, bool
|
||||
SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player());
|
||||
connect(inserter, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||
|
||||
inserter->Load(this, pos, play_now, enqueue, urls);
|
||||
inserter->Load(this, pos, play_now, enqueue, enqueue_next, urls);
|
||||
|
||||
}
|
||||
|
||||
@@ -891,17 +891,17 @@ void Playlist::InsertItems(const PlaylistItemList &itemsIn, int pos, bool play_n
|
||||
|
||||
if (items.count() > kUndoItemLimit) {
|
||||
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
|
||||
InsertItemsWithoutUndo(items, pos, enqueue);
|
||||
InsertItemsWithoutUndo(items, pos, enqueue, enqueue_next);
|
||||
undo_stack_->clear();
|
||||
} else {
|
||||
undo_stack_->push(new PlaylistUndoCommands::InsertItems(this, items, pos, enqueue));
|
||||
undo_stack_->push(new PlaylistUndoCommands::InsertItems(this, items, pos, enqueue, enqueue_next));
|
||||
}
|
||||
|
||||
if (play_now) emit PlayRequested(index(start, 0));
|
||||
|
||||
}
|
||||
|
||||
void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bool enqueue) {
|
||||
void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bool enqueue, bool enqueue_next) {
|
||||
|
||||
if (items.isEmpty()) return;
|
||||
|
||||
@@ -937,6 +937,14 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bo
|
||||
queue_->ToggleTracks(indexes);
|
||||
}
|
||||
|
||||
if (enqueue_next) {
|
||||
QModelIndexList indexes;
|
||||
for (int i = start; i <= end; ++i) {
|
||||
indexes << index(i, 0);
|
||||
}
|
||||
queue_->InsertFirst(indexes);
|
||||
}
|
||||
|
||||
Save();
|
||||
ReshuffleIndices();
|
||||
|
||||
@@ -1110,6 +1118,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr<Playlist
|
||||
|
||||
case Column_Comment: strcmp(comment);
|
||||
case Column_Source: cmp(source);
|
||||
default: qLog(Error) << "No such column" << column;
|
||||
}
|
||||
|
||||
#undef cmp
|
||||
@@ -1165,7 +1174,7 @@ QString Playlist::column_name(Column column) {
|
||||
|
||||
case Column_Comment: return tr("Comment");
|
||||
case Column_Source: return tr("Source");
|
||||
default: return QString();
|
||||
default: qLog(Error) << "No such column" << column;;
|
||||
}
|
||||
return "";
|
||||
|
||||
@@ -1263,10 +1272,6 @@ void Playlist::Save() const {
|
||||
|
||||
}
|
||||
|
||||
//namespace {
|
||||
//typedef QFutureWatcher<QList<PlaylistItemPtr>> PlaylistItemFutureWatcher;
|
||||
//}
|
||||
|
||||
void Playlist::Restore() {
|
||||
|
||||
if (!backend_) return;
|
||||
@@ -1824,7 +1829,7 @@ void Playlist::RemoveDeletedSongs() {
|
||||
PlaylistItemPtr item = items_[row];
|
||||
Song song = item->Metadata();
|
||||
|
||||
if (!QFile::exists(song.url().toLocalFile())) {
|
||||
if (!song.is_stream() && !QFile::exists(song.url().toLocalFile())) {
|
||||
rows_to_remove.append(row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ private:
|
||||
void InsertSongItems(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next = false);
|
||||
|
||||
// Modify the playlist without changing the undo stack. These are used by our friends in PlaylistUndoCommands
|
||||
void InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bool enqueue = false);
|
||||
void InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bool enqueue = false, bool enqueue_next = false);
|
||||
PlaylistItemList RemoveItemsWithoutUndo(int pos, int count);
|
||||
void MoveItemsWithoutUndo(const QList<int> &source_rows, int pos);
|
||||
void MoveItemWithoutUndo(int source, int dest);
|
||||
|
||||
@@ -45,28 +45,29 @@ PlaylistFilter::PlaylistFilter(QObject *parent)
|
||||
column_names_["artist"] = Playlist::Column_Artist;
|
||||
column_names_["album"] = Playlist::Column_Album;
|
||||
column_names_["albumartist"] = Playlist::Column_AlbumArtist;
|
||||
column_names_["composer"] = Playlist::Column_Composer;
|
||||
column_names_["performer"] = Playlist::Column_Performer;
|
||||
column_names_["grouping"] = Playlist::Column_Grouping;
|
||||
column_names_["length"] = Playlist::Column_Length;
|
||||
column_names_["track"] = Playlist::Column_Track;
|
||||
column_names_["disc"] = Playlist::Column_Disc;
|
||||
column_names_["composer"] = Playlist::Column_Composer;
|
||||
column_names_["year"] = Playlist::Column_Year;
|
||||
column_names_["originalyear"] = Playlist::Column_OriginalYear;
|
||||
column_names_["track"] = Playlist::Column_Track;
|
||||
column_names_["disc"] = Playlist::Column_Disc;
|
||||
column_names_["length"] = Playlist::Column_Length;
|
||||
column_names_["genre"] = Playlist::Column_Genre;
|
||||
column_names_["comment"] = Playlist::Column_Comment;
|
||||
column_names_["bitrate"] = Playlist::Column_Bitrate;
|
||||
column_names_["samplerate"] = Playlist::Column_Samplerate;
|
||||
column_names_["bitdepth"] = Playlist::Column_Bitdepth;
|
||||
column_names_["bitrate"] = Playlist::Column_Bitrate;
|
||||
column_names_["filename"] = Playlist::Column_Filename;
|
||||
column_names_["grouping"] = Playlist::Column_Grouping;
|
||||
column_names_["comment"] = Playlist::Column_Comment;
|
||||
|
||||
numerical_columns_ << Playlist::Column_Length
|
||||
numerical_columns_ << Playlist::Column_Year
|
||||
<< Playlist::Column_OriginalYear
|
||||
<< Playlist::Column_Track
|
||||
<< Playlist::Column_Disc
|
||||
<< Playlist::Column_Year
|
||||
<< Playlist::Column_Bitrate
|
||||
<< Playlist::Column_Length
|
||||
<< Playlist::Column_Samplerate
|
||||
<< Playlist::Column_Bitdepth;
|
||||
<< Playlist::Column_Bitdepth
|
||||
<< Playlist::Column_Bitrate;
|
||||
}
|
||||
|
||||
PlaylistFilter::~PlaylistFilter() {
|
||||
|
||||
@@ -47,6 +47,7 @@ PlaylistHeader::PlaylistHeader(Qt::Orientation orientation, PlaylistView *view,
|
||||
|
||||
hide_action_ = menu_->addAction(tr("&Hide..."), this, SLOT(HideCurrent()));
|
||||
stretch_action_ = menu_->addAction(tr("&Stretch columns to fit window"), this, SLOT(ToggleStretchEnabled()));
|
||||
reset_action_ = menu_->addAction(tr("&Reset columns to default"), this, SLOT(ResetColumns()));
|
||||
menu_->addSeparator();
|
||||
|
||||
QMenu *align_menu = new QMenu(tr("&Align text"), this);
|
||||
@@ -141,3 +142,6 @@ void PlaylistHeader::enterEvent(QEvent*) {
|
||||
emit MouseEntered();
|
||||
}
|
||||
|
||||
void PlaylistHeader::ResetColumns() {
|
||||
view_->ResetColumns();
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class PlaylistHeader : public StretchHeaderView {
|
||||
private slots:
|
||||
void HideCurrent();
|
||||
void ToggleVisible(int section);
|
||||
void ResetColumns();
|
||||
void SetColumnAlignment(QAction *action);
|
||||
|
||||
private:
|
||||
@@ -67,6 +68,7 @@ class PlaylistHeader : public StretchHeaderView {
|
||||
QMenu *menu_;
|
||||
QAction *hide_action_;
|
||||
QAction *stretch_action_;
|
||||
QAction *reset_action_;
|
||||
QAction *align_left_action_;
|
||||
QAction *align_center_action_;
|
||||
QAction *align_right_action_;
|
||||
|
||||
@@ -36,17 +36,18 @@ namespace PlaylistUndoCommands {
|
||||
Base::Base(Playlist* playlist) : QUndoCommand(0), playlist_(playlist) {}
|
||||
|
||||
|
||||
InsertItems::InsertItems(Playlist *playlist, const PlaylistItemList &items, int pos, bool enqueue)
|
||||
InsertItems::InsertItems(Playlist *playlist, const PlaylistItemList &items, int pos, bool enqueue, bool enqueue_next)
|
||||
: Base(playlist),
|
||||
items_(items),
|
||||
pos_(pos),
|
||||
enqueue_(enqueue)
|
||||
enqueue_(enqueue),
|
||||
enqueue_next_(enqueue_next)
|
||||
{
|
||||
setText(tr("add %n songs", "", items_.count()));
|
||||
}
|
||||
|
||||
void InsertItems::redo() {
|
||||
playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_);
|
||||
playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_, enqueue_next_);
|
||||
}
|
||||
|
||||
void InsertItems::undo() {
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace PlaylistUndoCommands {
|
||||
|
||||
class InsertItems : public Base {
|
||||
public:
|
||||
InsertItems(Playlist *playlist, const PlaylistItemList &items, int pos, bool enqueue = false);
|
||||
InsertItems(Playlist *playlist, const PlaylistItemList &items, int pos, bool enqueue = false, bool enqueue_next = false);
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
@@ -64,6 +64,7 @@ namespace PlaylistUndoCommands {
|
||||
PlaylistItemList items_;
|
||||
int pos_;
|
||||
bool enqueue_;
|
||||
bool enqueue_next_;
|
||||
};
|
||||
|
||||
class RemoveItems : public Base {
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
|
||||
using std::sort;
|
||||
|
||||
const int PlaylistView::kStateVersion = 6;
|
||||
const int PlaylistView::kGlowIntensitySteps = 24;
|
||||
const int PlaylistView::kAutoscrollGraceTimeout = 30; // seconds
|
||||
const int PlaylistView::kDropIndicatorWidth = 2;
|
||||
@@ -135,8 +134,8 @@ PlaylistView::PlaylistView(QWidget *parent)
|
||||
style_(new PlaylistProxyStyle(style())),
|
||||
playlist_(nullptr),
|
||||
header_(new PlaylistHeader(Qt::Horizontal, this, this)),
|
||||
initialized_(false),
|
||||
setting_initial_header_layout_(false),
|
||||
upgrading_from_qheaderview_(false),
|
||||
read_only_settings_(true),
|
||||
header_loaded_(false),
|
||||
background_initialized_(false),
|
||||
@@ -159,19 +158,18 @@ PlaylistView::PlaylistView(QWidget *parent)
|
||||
currenttrack_pause_(":/pictures/currenttrack_pause.png"),
|
||||
cached_current_row_row_(-1),
|
||||
drop_indicator_row_(-1),
|
||||
drag_over_(false)
|
||||
{
|
||||
drag_over_(false) {
|
||||
|
||||
setHeader(header_);
|
||||
header_->setSectionsMovable(true);
|
||||
setStyle(style_);
|
||||
setMouseTracking(true);
|
||||
|
||||
|
||||
connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(SaveGeometry()));
|
||||
connect(header_, SIGNAL(sectionMoved(int,int,int)), SLOT(SaveGeometry()));
|
||||
connect(header_, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(SaveGeometry()));
|
||||
connect(header_, SIGNAL(SectionVisibilityChanged(int,bool)), SLOT(SaveGeometry()));
|
||||
|
||||
connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(InvalidateCachedCurrentPixmap()));
|
||||
connect(header_, SIGNAL(sectionMoved(int,int,int)), SLOT(InvalidateCachedCurrentPixmap()));
|
||||
connect(header_, SIGNAL(SectionVisibilityChanged(int,bool)), SLOT(InvalidateCachedCurrentPixmap()));
|
||||
@@ -196,6 +194,8 @@ PlaylistView::PlaylistView(QWidget *parent)
|
||||
connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousBackgroundImage(qreal)));
|
||||
fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
}
|
||||
|
||||
PlaylistView::~PlaylistView() {
|
||||
@@ -253,7 +253,7 @@ void PlaylistView::SetPlaylist(Playlist *playlist) {
|
||||
}
|
||||
|
||||
playlist_ = playlist;
|
||||
if (!header_loaded_) LoadGeometry();
|
||||
LoadGeometry();
|
||||
ReloadSettings();
|
||||
setFocus();
|
||||
read_only_settings_ = false;
|
||||
@@ -285,39 +285,35 @@ void PlaylistView::setModel(QAbstractItemModel *m) {
|
||||
void PlaylistView::LoadGeometry() {
|
||||
|
||||
QSettings settings;
|
||||
header_loaded_ = true;
|
||||
settings.beginGroup(Playlist::kSettingsGroup);
|
||||
|
||||
QByteArray state(settings.value("state").toByteArray());
|
||||
if (!header_->RestoreState(state)) {
|
||||
// Maybe we're upgrading from a version that persisted the state with QHeaderView.
|
||||
if (!header_->restoreState(state)) {
|
||||
header_->HideSection(Playlist::Column_Disc);
|
||||
header_->HideSection(Playlist::Column_AlbumArtist);
|
||||
header_->HideSection(Playlist::Column_Performer);
|
||||
header_->HideSection(Playlist::Column_Composer);
|
||||
header_->HideSection(Playlist::Column_Year);
|
||||
header_->HideSection(Playlist::Column_OriginalYear);
|
||||
header_->HideSection(Playlist::Column_Disc);
|
||||
header_->HideSection(Playlist::Column_Genre);
|
||||
header_->HideSection(Playlist::Column_Filename);
|
||||
header_->HideSection(Playlist::Column_BaseFilename);
|
||||
header_->HideSection(Playlist::Column_Filesize);
|
||||
header_->HideSection(Playlist::Column_DateCreated);
|
||||
header_->HideSection(Playlist::Column_DateModified);
|
||||
header_->HideSection(Playlist::Column_AlbumArtist);
|
||||
header_->HideSection(Playlist::Column_Composer);
|
||||
header_->HideSection(Playlist::Column_Performer);
|
||||
header_->HideSection(Playlist::Column_Grouping);
|
||||
header_->HideSection(Playlist::Column_PlayCount);
|
||||
header_->HideSection(Playlist::Column_SkipCount);
|
||||
header_->HideSection(Playlist::Column_LastPlayed);
|
||||
header_->HideSection(Playlist::Column_Comment);
|
||||
header_->HideSection(Playlist::Column_BaseFilename);
|
||||
|
||||
header_->HideSection(Playlist::Column_Samplerate);
|
||||
header_->HideSection(Playlist::Column_Bitdepth);
|
||||
header_->HideSection(Playlist::Column_Grouping);
|
||||
|
||||
header_->moveSection(header_->visualIndex(Playlist::Column_Track), 0);
|
||||
setting_initial_header_layout_ = true;
|
||||
}
|
||||
else {
|
||||
upgrading_from_qheaderview_ = true;
|
||||
setting_initial_header_layout_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,11 +329,13 @@ void PlaylistView::LoadGeometry() {
|
||||
header_->ShowSection(Playlist::Column_Title);
|
||||
}
|
||||
|
||||
header_loaded_ = true;
|
||||
|
||||
}
|
||||
|
||||
void PlaylistView::SaveGeometry() {
|
||||
|
||||
if (read_only_settings_) return;
|
||||
if (!initialized_ || read_only_settings_) return;
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup(Playlist::kSettingsGroup);
|
||||
@@ -929,11 +927,10 @@ void PlaylistView::ReloadSettings() {
|
||||
glow_enabled_ = s.value("glow_effect", true).toBool();
|
||||
s.endGroup();
|
||||
|
||||
if (setting_initial_header_layout_ || upgrading_from_qheaderview_) {
|
||||
if (setting_initial_header_layout_) {
|
||||
s.beginGroup(Playlist::kSettingsGroup);
|
||||
header_->SetStretchEnabled(s.value("stretch", true).toBool());
|
||||
s.endGroup();
|
||||
upgrading_from_qheaderview_ = false;
|
||||
}
|
||||
|
||||
if (currently_glowing_ && glow_enabled_ && isVisible()) StartGlowing();
|
||||
@@ -1035,7 +1032,7 @@ void PlaylistView::ReloadSettings() {
|
||||
|
||||
void PlaylistView::SaveSettings() {
|
||||
|
||||
if (read_only_settings_) return;
|
||||
if (!initialized_ || read_only_settings_) return;
|
||||
|
||||
QSettings s;
|
||||
|
||||
@@ -1054,6 +1051,7 @@ void PlaylistView::SaveSettings() {
|
||||
}
|
||||
|
||||
void PlaylistView::StretchChanged(bool stretch) {
|
||||
if (!initialized_) return;
|
||||
setHorizontalScrollBarPolicy(stretch ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
|
||||
SaveGeometry();
|
||||
}
|
||||
@@ -1084,17 +1082,17 @@ ColumnAlignmentMap PlaylistView::DefaultColumnAlignment() {
|
||||
|
||||
ColumnAlignmentMap ret;
|
||||
|
||||
ret[Playlist::Column_Length] =
|
||||
ret[Playlist::Column_Year] =
|
||||
ret[Playlist::Column_OriginalYear] =
|
||||
ret[Playlist::Column_Track] =
|
||||
ret[Playlist::Column_Disc] =
|
||||
ret[Playlist::Column_Year] =
|
||||
ret[Playlist::Column_Bitrate] =
|
||||
ret[Playlist::Column_Length] =
|
||||
ret[Playlist::Column_Samplerate] =
|
||||
ret[Playlist::Column_Bitdepth] =
|
||||
ret[Playlist::Column_Bitrate] =
|
||||
ret[Playlist::Column_Filesize] =
|
||||
ret[Playlist::Column_PlayCount] =
|
||||
ret[Playlist::Column_SkipCount] =
|
||||
ret[Playlist::Column_OriginalYear] =
|
||||
(Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
return ret;
|
||||
@@ -1228,3 +1226,20 @@ void PlaylistView::focusInEvent(QFocusEvent *event) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PlaylistView::ResetColumns() {
|
||||
|
||||
read_only_settings_ = true;
|
||||
setting_initial_header_layout_ = true;
|
||||
QSettings settings;
|
||||
settings.beginGroup(Playlist::kSettingsGroup);
|
||||
settings.remove("state");
|
||||
settings.endGroup();
|
||||
ReloadSettings();
|
||||
LoadGeometry();
|
||||
ReloadSettings();
|
||||
read_only_settings_ = false;
|
||||
SaveGeometry();
|
||||
SetPlaylist(playlist_);
|
||||
|
||||
}
|
||||
|
||||
@@ -99,7 +99,6 @@ class PlaylistView : public QTreeView {
|
||||
PlaylistView(QWidget *parent = nullptr);
|
||||
~PlaylistView();
|
||||
|
||||
static const int kStateVersion;
|
||||
// Constants for settings: are persistent, values should not be changed
|
||||
static const char *kSettingBackgroundImageType;
|
||||
static const char *kSettingBackgroundImageFilename;
|
||||
@@ -125,6 +124,8 @@ class PlaylistView : public QTreeView {
|
||||
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
void setModel(QAbstractItemModel *model);
|
||||
|
||||
void ResetColumns();
|
||||
|
||||
public slots:
|
||||
void ReloadSettings();
|
||||
void StopGlowing();
|
||||
@@ -214,8 +215,8 @@ class PlaylistView : public QTreeView {
|
||||
PlaylistProxyStyle *style_;
|
||||
Playlist *playlist_;
|
||||
PlaylistHeader *header_;
|
||||
bool initialized_;
|
||||
bool setting_initial_header_layout_;
|
||||
bool upgrading_from_qheaderview_;
|
||||
bool read_only_settings_;
|
||||
bool header_loaded_;
|
||||
|
||||
|
||||
@@ -43,12 +43,13 @@ SongLoaderInserter::SongLoaderInserter(TaskManager *task_manager, CollectionBack
|
||||
|
||||
SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); }
|
||||
|
||||
void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, bool enqueue, const QList<QUrl> &urls) {
|
||||
void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList<QUrl> &urls) {
|
||||
|
||||
destination_ = destination;
|
||||
row_ = row;
|
||||
play_now_ = play_now;
|
||||
enqueue_ = enqueue;
|
||||
enqueue_next_ = enqueue_next;
|
||||
|
||||
connect(destination, SIGNAL(destroyed()), SLOT(DestinationDestroyed()));
|
||||
connect(this, SIGNAL(PreloadFinished()), SLOT(InsertSongs()));
|
||||
@@ -84,12 +85,13 @@ void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, boo
|
||||
// First, we add tracks (without metadata) into the playlist
|
||||
// In the meantime, MusicBrainz will be queried to get songs' metadata.
|
||||
// AudioCDTagsLoaded will be called next, and playlist's items will be updated.
|
||||
void SongLoaderInserter::LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue) {
|
||||
void SongLoaderInserter::LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next) {
|
||||
|
||||
destination_ = destination;
|
||||
row_ = row;
|
||||
play_now_ = play_now;
|
||||
enqueue_ = enqueue;
|
||||
enqueue_next_ = enqueue_next;
|
||||
|
||||
SongLoader *loader = new SongLoader(collection_, player_, this);
|
||||
NewClosure(loader, SIGNAL(AudioCDTracksLoaded()), this, SLOT(AudioCDTracksLoaded(SongLoader*)), loader);
|
||||
@@ -128,7 +130,7 @@ void SongLoaderInserter::AudioCDTagsLoaded(bool success) {
|
||||
void SongLoaderInserter::InsertSongs() {
|
||||
// Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely
|
||||
if (destination_) {
|
||||
destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_);
|
||||
destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_, enqueue_next_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ class SongLoaderInserter : public QObject {
|
||||
SongLoaderInserter(TaskManager *task_manager, CollectionBackendInterface *collection, const Player *player);
|
||||
~SongLoaderInserter();
|
||||
|
||||
void Load(Playlist *destination, int row, bool play_now, bool enqueue, const QList<QUrl> &urls);
|
||||
void LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue);
|
||||
void Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList<QUrl> &urls);
|
||||
void LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next);
|
||||
|
||||
signals:
|
||||
void Error(const QString &message);
|
||||
@@ -68,6 +68,7 @@ signals:
|
||||
int row_;
|
||||
bool play_now_;
|
||||
bool enqueue_;
|
||||
bool enqueue_next_;
|
||||
|
||||
SongList songs_;
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@ void BackendSettingsPage::Load() {
|
||||
|
||||
configloaded_ = false;
|
||||
engineloaded_ = false;
|
||||
xinewarning_ = false;
|
||||
|
||||
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineName(Engine::None)).toString());
|
||||
if (enginetype == Engine::None && engine()) enginetype = engine()->type();
|
||||
@@ -193,7 +192,6 @@ void BackendSettingsPage::Load_Engine(Engine::EngineType enginetype) {
|
||||
qLog(Debug) << "Switching engine.";
|
||||
Engine::EngineType new_enginetype = dialog()->app()->player()->CreateEngine(enginetype);
|
||||
dialog()->app()->player()->Init();
|
||||
dialog()->set_output_changed(false);
|
||||
if (new_enginetype != enginetype) {
|
||||
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(engine()->type()));
|
||||
}
|
||||
@@ -373,10 +371,6 @@ void BackendSettingsPage::Save() {
|
||||
else if (ui_->radiobutton_alsa_plughw->isChecked()) s_.setValue("alsaplugin", static_cast<int>(alsa_plugin::alsa_plughw));
|
||||
else s_.remove("alsaplugin");
|
||||
|
||||
// If engine has not been changed, but output or device has been changed,
|
||||
// then set_output_changed(true) to reinitialize engine when dialog closes.
|
||||
if (enginetype == enginetype_current_ && (output_name != output_current_ || device_value != device_current_)) dialog()->set_output_changed(true);
|
||||
|
||||
}
|
||||
|
||||
void BackendSettingsPage::Cancel() {
|
||||
@@ -402,7 +396,6 @@ void BackendSettingsPage::EngineChanged(int index) {
|
||||
}
|
||||
|
||||
engineloaded_ = false;
|
||||
xinewarning_ = false;
|
||||
ResetWarning();
|
||||
Load_Engine(enginetype);
|
||||
|
||||
@@ -415,8 +408,6 @@ void BackendSettingsPage::OutputChanged(int index) {
|
||||
EngineBase::OutputDetails output = ui_->combobox_output->itemData(index).value<EngineBase::OutputDetails>();
|
||||
Load_Device(output.name, QVariant());
|
||||
|
||||
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
|
||||
|
||||
}
|
||||
|
||||
void BackendSettingsPage::DeviceSelectionChanged(int index) {
|
||||
@@ -438,8 +429,6 @@ void BackendSettingsPage::DeviceSelectionChanged(int index) {
|
||||
if (!ui_->lineedit_device->text().isEmpty()) ui_->lineedit_device->setText("");
|
||||
}
|
||||
|
||||
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
|
||||
|
||||
}
|
||||
|
||||
void BackendSettingsPage::DeviceStringChanged() {
|
||||
@@ -541,19 +530,6 @@ void BackendSettingsPage::ResetWarning() {
|
||||
|
||||
}
|
||||
|
||||
void BackendSettingsPage::XineWarning() {
|
||||
|
||||
if (!engineloaded_) return;
|
||||
if (!configloaded_) return;
|
||||
if (engine()->type() != Engine::Xine) return;
|
||||
if (engine()->state() == Engine::Empty) return;
|
||||
if (xinewarning_) return;
|
||||
|
||||
ShowWarning("You need to restart Strawberry for output/device changes to take affect for Xine.");
|
||||
xinewarning_ = true;
|
||||
|
||||
}
|
||||
|
||||
void BackendSettingsPage::SwitchALSADevices(alsa_plugin alsaplugin) {
|
||||
|
||||
// All ALSA devices are listed twice, one for "hw" and one for "plughw"
|
||||
|
||||
@@ -91,7 +91,6 @@ private:
|
||||
QSettings s_;
|
||||
bool configloaded_;
|
||||
bool engineloaded_;
|
||||
bool xinewarning_;
|
||||
ErrorDialog errordialog_;
|
||||
|
||||
Engine::EngineType enginetype_current_;
|
||||
|
||||
@@ -52,12 +52,10 @@ DeezerSettingsPage::DeezerSettingsPage(SettingsDialog *parent)
|
||||
|
||||
dialog()->installEventFilter(this);
|
||||
|
||||
ui_->combobox_quality->addItem("AAC (64)", "AAC_64");
|
||||
ui_->combobox_quality->addItem("MP3 (64)", "MP3_64");
|
||||
ui_->combobox_quality->addItem("MP3 (128)", "MP3_128");
|
||||
ui_->combobox_quality->addItem("MP3 (256)", "MP3_256");
|
||||
ui_->combobox_quality->addItem("MP3 (320)", "MP3_320");
|
||||
ui_->combobox_quality->addItem("FLAC", "FLAC");
|
||||
ui_->combobox_quality->addItem("MP3 128kbps \"Standard\"", "MP3_128");
|
||||
ui_->combobox_quality->addItem("MP3 320kbps \"High Quality\"", "MP3_320");
|
||||
ui_->combobox_quality->addItem("FLAC \"CD Quality\"", "FLAC");
|
||||
ui_->combobox_quality->addItem("\"Data Efficient\"", "DATA_EFFICIENT");
|
||||
|
||||
ui_->combobox_coversize->addItem("Small", "cover_small");
|
||||
ui_->combobox_coversize->addItem("Medium", "cover_medium");
|
||||
@@ -74,10 +72,6 @@ void DeezerSettingsPage::Load() {
|
||||
|
||||
s.beginGroup(kSettingsGroup);
|
||||
ui_->checkbox_enable->setChecked(s.value("enabled", false).toBool());
|
||||
ui_->username->setText(s.value("username").toString());
|
||||
QByteArray password = s.value("password").toByteArray();
|
||||
if (password.isEmpty()) ui_->password->clear();
|
||||
else ui_->password->setText(QString::fromUtf8(QByteArray::fromBase64(password)));
|
||||
dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_quality, "quality", "FLAC");
|
||||
ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt());
|
||||
ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 100).toInt());
|
||||
@@ -102,8 +96,6 @@ void DeezerSettingsPage::Save() {
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
s.setValue("enabled", ui_->checkbox_enable->isChecked());
|
||||
s.setValue("username", ui_->username->text());
|
||||
s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64()));
|
||||
s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex()));
|
||||
s.setValue("searchdelay", ui_->spinbox_searchdelay->value());
|
||||
s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value());
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>715</width>
|
||||
<height>547</height>
|
||||
<height>575</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -55,76 +55,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layout_username">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_username">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="username"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer_username">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layout_password">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_password">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="password">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer_password">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LoginStateWidget" name="login_state" native="true"/>
|
||||
</item>
|
||||
|
||||
@@ -112,8 +112,7 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
|
||||
model_(app_->collection_model()->directory_model()),
|
||||
appearance_(app_->appearance()),
|
||||
ui_(new Ui_SettingsDialog),
|
||||
loading_settings_(false),
|
||||
output_changed_(false) {
|
||||
loading_settings_(false) {
|
||||
|
||||
ui_->setupUi(this);
|
||||
ui_->list->setItemDelegate(new SettingsItemDelegate(this));
|
||||
@@ -129,8 +128,13 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
|
||||
AddPage(Page_Transcoding, new TranscoderSettingsPage(this), general);
|
||||
#endif
|
||||
|
||||
QTreeWidgetItem *iface = AddCategory(tr("User interface"));
|
||||
AddPage(Page_Appearance, new AppearanceSettingsPage(this), iface);
|
||||
AddPage(Page_Notifications, new NotificationsSettingsPage(this), iface);
|
||||
AddPage(Page_GlobalShortcuts, new GlobalShortcutsSettingsPage(this), iface);
|
||||
|
||||
#if defined(HAVE_STREAM_TIDAL) || defined(HAVE_STREAM_DEEZER)
|
||||
QTreeWidgetItem *internet = AddCategory(tr("Internet"));
|
||||
QTreeWidgetItem *internet = AddCategory(tr("Streaming"));
|
||||
#endif
|
||||
#ifdef HAVE_STREAM_TIDAL
|
||||
AddPage(Page_Tidal, new TidalSettingsPage(this), internet);
|
||||
@@ -139,12 +143,6 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
|
||||
AddPage(Page_Deezer, new DeezerSettingsPage(this), internet);
|
||||
#endif
|
||||
|
||||
// User interface
|
||||
QTreeWidgetItem *iface = AddCategory(tr("User interface"));
|
||||
AddPage(Page_GlobalShortcuts, new GlobalShortcutsSettingsPage(this), iface);
|
||||
AddPage(Page_Appearance, new AppearanceSettingsPage(this), iface);
|
||||
AddPage(Page_Notifications, new NotificationsSettingsPage(this), iface);
|
||||
|
||||
// List box
|
||||
connect(ui_->list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(CurrentItemChanged(QTreeWidgetItem*)));
|
||||
ui_->list->setCurrentItem(pages_[Page_Behaviour].item_);
|
||||
@@ -221,11 +219,6 @@ void SettingsDialog::Save() {
|
||||
|
||||
void SettingsDialog::accept() {
|
||||
Save();
|
||||
// Only Xine needs to reinitialize to switch output and device.
|
||||
if (output_changed_ && engine() && engine()->type() == Engine::Xine && engine()->state() == Engine::Empty) {
|
||||
engine()->ReloadSettings();
|
||||
engine()->Init();
|
||||
}
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -109,8 +109,6 @@ public:
|
||||
// QWidget
|
||||
void showEvent(QShowEvent *e);
|
||||
|
||||
void set_output_changed(bool output_changed) { output_changed_ = output_changed; }
|
||||
|
||||
void ComboBoxLoadFromSettings(QSettings &s, QComboBox *combobox, QString setting, QString default_value);
|
||||
|
||||
signals:
|
||||
@@ -144,8 +142,6 @@ private:
|
||||
bool loading_settings_;
|
||||
|
||||
QMap<Page, PageData> pages_;
|
||||
|
||||
bool output_changed_;
|
||||
};
|
||||
|
||||
#endif // SETTINGSDIALOG_H
|
||||
|
||||
@@ -100,7 +100,10 @@ void TrackSlider::SetValue(int elapsed, int total) {
|
||||
|
||||
setting_value_ = true; // This is so we don't emit from QAbstractSlider::valueChanged
|
||||
ui_->slider->setMaximum(total);
|
||||
ui_->slider->setValue(elapsed);
|
||||
if (!ui_->slider->isSliderDown()) {
|
||||
ui_->slider->setValue(elapsed);
|
||||
}
|
||||
|
||||
setting_value_ = false;
|
||||
|
||||
UpdateTimes(elapsed / kMsecPerSec);
|
||||
@@ -116,7 +119,7 @@ void TrackSlider::UpdateTimes(int elapsed) {
|
||||
}
|
||||
else {
|
||||
// Check if slider maximum value is changed before updating
|
||||
if (slider_maximum_value_ != ui_->slider->maximum()) {
|
||||
if (slider_maximum_value_ != ui_->slider->maximum() || !ui_->slider->isEnabled()) {
|
||||
slider_maximum_value_ = ui_->slider->maximum();
|
||||
ui_->remaining->setText(Utilities::PrettyTime((ui_->slider->maximum() / kMsecPerSec)));
|
||||
}
|
||||
|
||||
@@ -111,7 +111,11 @@ void TrackSliderSlider::enterEvent(QEvent* e) {
|
||||
|
||||
void TrackSliderSlider::leaveEvent(QEvent* e) {
|
||||
QSlider::leaveEvent(e);
|
||||
popup_->hide();
|
||||
// On some (but not all) systems, displaying the TrackSliderPopup
|
||||
// generates a leaveEvent. Ensure that this leaveEvent is genuine.
|
||||
if (!geometry().contains(mapFromGlobal(QCursor::pos()))) {
|
||||
popup_->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackSliderSlider::keyPressEvent(QKeyEvent* event) {
|
||||
@@ -130,7 +134,7 @@ void TrackSliderSlider::keyPressEvent(QKeyEvent* event) {
|
||||
|
||||
void TrackSliderSlider::UpdateDeltaTime() {
|
||||
if (popup_->isVisible()) {
|
||||
int delta_seconds = mouse_hover_seconds_ - value();
|
||||
int delta_seconds = mouse_hover_seconds_ - (value() / kMsecPerSec);
|
||||
popup_->SetSmallText(Utilities::PrettyTimeDelta(delta_seconds));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user