Compare commits

...

45 Commits
0.4.1 ... 0.4.2

Author SHA1 Message Date
Jonas Kvinge
bcd29b9fd2 Release 0.4.2 2018-11-28 21:53:38 +01:00
Jonas Kvinge
046c221bc6 Change internet to streaming in settings and change order of settings 2018-11-28 17:53:37 +01:00
Jonas Kvinge
29a39b4e7f Attempt to fix devices issue 2018-11-28 17:45:50 +01:00
Jonas Kvinge
9fb3d06aac Change if statement in qtsingleapplication/CMakeLists.txt 2018-11-28 17:44:45 +01:00
Jonas Kvinge
142d5e2347 Update .travis.yml 2018-11-27 19:36:22 +01:00
Jonas Kvinge
58ea0bcbb0 Turn Deezer OFF by default if dependencies arent found 2018-11-27 19:33:30 +01:00
Jonas Kvinge
1c0bbe5d33 Fix endif in qxt CMakeLists.txt 2018-11-27 19:27:09 +01:00
Jonas Kvinge
8a7bba8ef3 Remove background image
Unsure about copyright issues using it, the image is from the Strawbs boxset, removing
it for now.
2018-11-27 19:20:33 +01:00
Jonas Kvinge
3b93963688 Code cleanup in qxtglobalshortcut 2018-11-27 19:14:35 +01:00
Jonas Kvinge
77e5d0288f Fix typo 2018-11-19 01:38:55 +01:00
Jonas Kvinge
460e78a1b8 Merge branch 'master' of github.com:jonaski/strawberry 2018-11-19 01:32:26 +01:00
Jonas Kvinge
fcbade267d Update changelog and about 2018-11-19 01:31:52 +01:00
Jonas Kvinge
41b99d9aa0 Update README.md 2018-11-19 01:12:32 +01:00
Jonas Kvinge
96c761dbb5 Update README.md 2018-11-19 01:09:51 +01:00
Jonas Kvinge
d297564236 Update README.md 2018-11-19 01:09:12 +01:00
Jonas Kvinge
bca1a98938 Add option to reset playlist columns 2018-11-19 00:18:48 +01:00
Jonas Kvinge
23205bef65 Playlist fixes
- Fix bug resetting playlist view columns to show all when using more than one
playlist.
- Add queue to play next
2018-11-18 23:21:12 +01:00
Jonas Kvinge
7613b2f526 Add alsa to optional_component 2018-11-17 16:28:05 +01:00
Jonas Kvinge
c5a521af1f Fix logging 2018-11-17 03:27:46 +01:00
Jonas Kvinge
f15c85e807 Remove SetThreadIOPriority, fixes poor performance on macos 2018-11-17 03:25:42 +01:00
Jonas Kvinge
6129ad1f4d Track slider fixes 2018-11-17 03:25:21 +01:00
Jonas Kvinge
9972dc192b Add include for QtGlobal 2018-11-17 03:24:20 +01:00
Jonas Kvinge
32b96a25e8 Remove dead code 2018-11-17 03:23:49 +01:00
Jonas Kvinge
9d09e7f6fe Remove dead code 2018-11-17 03:23:22 +01:00
Jonas Kvinge
5927483402 Remove qstyleoption_cast 2018-11-16 17:45:57 +01:00
Jonas Kvinge
f228f79a8a Fix macos code 2018-11-16 17:25:39 +01:00
Jonas Kvinge
072a3065cd Don't set paths for gst scanner and plugins on macos 2018-11-15 20:20:30 +01:00
Jonas Kvinge
718bd4c081 Replace NULL and 0 with nullptr 2018-11-14 00:43:19 +01:00
Jonas Kvinge
542cc0ec2f Remove unused code 2018-11-14 00:31:04 +01:00
Jonas Kvinge
b357634f51 Add pacman package files 2018-11-11 03:37:14 +01:00
Jonas Kvinge
6968c4d0fb Remove OpenGL from Dockerfile 2018-11-09 22:24:55 +01:00
Jonas Kvinge
e35d618133 Make Deezer engine use quality setting 2018-11-09 19:27:36 +01:00
Jonas Kvinge
4a23fde6bf Merge branch 'master' of github.com:jonaski/strawberry 2018-11-05 02:12:24 +01:00
Jonas Kvinge
1ae577641d Remove Qt5OpenGL from spec files and control file 2018-11-05 02:11:26 +01:00
Jonas Kvinge
686a3bb42b Update README.md 2018-11-05 01:21:37 +01:00
Jonas Kvinge
1771d41871 Fixes to makefiles
- Add a warning when using the systems taglib less or equal to version 1.11.1
- Remove OpenGL and Qt5::OpenGL dependency, it is not used by the analyzer
- Rename some variables
2018-11-05 01:14:56 +01:00
Jonas Kvinge
ee8f4ca7ab Add libqt5sql5-sqlite to debian control 2018-11-04 23:24:49 +01:00
Jonas Kvinge
4197a508a3 Remove obsolete xine warning and engine reinitialization 2018-11-04 21:23:34 +01:00
Jonas Kvinge
f38ffb505d Add Requires libQt5Sql5-sqlite to spec 2018-11-04 00:48:39 +01:00
Jonas Kvinge
679caf73d1 Fix strawberry.appdata.xml 2018-11-03 16:30:53 +01:00
Jonas Kvinge
56d25c346c Update appdata file to new AppStream specification 2018-11-03 15:57:45 +01:00
Jonas Kvinge
6ba26ba289 Change fedora rpm suffix 2018-11-02 21:30:07 +01:00
Jonas Kvinge
27582b7a4e Add strawberry.appdata.xml to spec files 2018-11-02 20:30:12 +01:00
Jonas Kvinge
2f4417d683 Fix files to delete on uninstall in nsi 2018-11-01 22:22:39 +01:00
Jonas Kvinge
de97d29a82 Turn back git revision 2018-11-01 22:22:30 +01:00
79 changed files with 1361 additions and 1494 deletions

1
.gitignore vendored
View File

@@ -39,6 +39,7 @@ Thumbs.db
*.plist *.plist
maketarball.sh maketarball.sh
dist/debian/changelog dist/debian/changelog
dist/pacman/PKGBUILD
# qtcreator generated files # qtcreator generated files
*.pro.user* *.pro.user*

View File

@@ -23,7 +23,7 @@ before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install chromaprint ; fi - 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 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export Qt5_DIR=/usr/local/opt/qt5/lib/cmake ; fi
before_script: 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 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir build; cd build; cmake .. -DFORCE_GIT_REVISION="0.0.0-0-g0000000"; fi
script: script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker exec build make -C build -j8 ; fi

View File

@@ -13,11 +13,11 @@ set(SINGLEAPP-MOC-HEADERS
qtsinglecoreapplication.h qtsinglecoreapplication.h
) )
if(WIN32) if(UNIX)
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_win.cpp)
elseif(WIN32)
set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_unix.cpp) 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}) QT5_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS})

View File

@@ -157,7 +157,7 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
Sleep(DWORD(ms)); Sleep(DWORD(ms));
#else #else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL); nanosleep(&ts, nullptr);
#endif #endif
} }
if (!connOk) if (!connOk)

View File

@@ -58,7 +58,7 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
Qt::HANDLE mutex; Qt::HANDLE mutex;
if (doCreate) { if (doCreate) {
mutex = CreateMutexW(NULL, FALSE, (WCHAR*)mname.utf16()); mutex = CreateMutexW(nullptr, FALSE, (WCHAR*)mname.utf16());
if (!mutex) { if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
return 0; return 0;

View File

@@ -45,10 +45,6 @@
#include <QWidget> #include <QWidget>
#include <QString> #include <QString>
#ifdef HAVE_X11_ // FIXME
# include <X11/Xlib.h>
#endif
#include "qtlocalpeer.h" #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; Returns true if another instance of this application is running;
otherwise false. otherwise false.

View File

@@ -48,10 +48,6 @@
#include <QApplication> #include <QApplication>
#include <QString> #include <QString>
#if defined(HAVE_X11_) // FIXME
# include <X11/Xlib.h>
#endif
class QtLocalPeer; class QtLocalPeer;
#if defined(Q_OS_WIN) || defined(Q_OS_WIN32) #if defined(Q_OS_WIN) || defined(Q_OS_WIN32)
@@ -77,11 +73,6 @@ class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
public: public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv); 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(); bool isRunning();
QString id() const; QString id() const;

View File

@@ -1,6 +1,13 @@
cmake_minimum_required(VERSION 2.8.11) cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 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}) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if (NOT WIN32 AND NOT APPLE) if (NOT WIN32 AND NOT APPLE)
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) 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 HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
endif(NOT WIN32 AND NOT APPLE) endif(NOT WIN32 AND NOT APPLE)
set(QXT-SOURCES set(QXT-SOURCES qxtglobal.cpp qxtglobalshortcut.cpp)
qxtglobal.cpp set(QXT-MOC-HEADERS qxtglobalshortcut.h )
qxtglobalshortcut.cpp
)
set(QXT-MOC-HEADERS if(X11_FOUND)
qxtglobalshortcut.h set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp)
)
find_package(X11)
include_directories(${X11_INCLUDE_DIR})
if(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
elseif(APPLE) elseif(APPLE)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp)
else(WIN32) elseif(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
endif(WIN32) endif()
QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS}) QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS})
@@ -36,8 +34,8 @@ ADD_LIBRARY(qxt STATIC
${QXT-SOURCES-MOC} ${QXT-SOURCES-MOC}
) )
if(WIN32) target_link_libraries(qxt Qt5::Core Qt5::Widgets)
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
else(WIN32) if(X11_FOUND)
target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras) target_link_libraries(qxt Qt5::X11Extras)
endif(WIN32) endif(X11_FOUND)

View File

@@ -1,4 +1,3 @@
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.

View File

@@ -1,4 +1,3 @@
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -161,73 +160,73 @@ template <typename PUB>
class QxtPrivate class QxtPrivate
{ {
public: public:
virtual ~QxtPrivate() virtual ~QxtPrivate()
{} {}
inline void QXT_setPublic(PUB* pub) inline void QXT_setPublic(PUB* pub)
{ {
qxt_p_ptr = pub; qxt_p_ptr = pub;
} }
protected: protected:
inline PUB& qxt_p() inline PUB& qxt_p()
{ {
return *qxt_p_ptr; return *qxt_p_ptr;
} }
inline const PUB& qxt_p() const inline const PUB& qxt_p() const
{ {
return *qxt_p_ptr; return *qxt_p_ptr;
} }
inline PUB* qxt_ptr() inline PUB* qxt_ptr()
{ {
return qxt_p_ptr; return qxt_p_ptr;
} }
inline const PUB* qxt_ptr() const inline const PUB* qxt_ptr() const
{ {
return qxt_p_ptr; return qxt_p_ptr;
} }
private: private:
PUB* qxt_p_ptr; PUB* qxt_p_ptr;
}; };
template <typename PUB, typename PVT> template <typename PUB, typename PVT>
class QxtPrivateInterface class QxtPrivateInterface
{ {
friend class QxtPrivate<PUB>; friend class QxtPrivate<PUB>;
public: public:
QxtPrivateInterface() QxtPrivateInterface()
{ {
pvt = new PVT; pvt = new PVT;
} }
~QxtPrivateInterface() ~QxtPrivateInterface()
{ {
delete pvt; delete pvt;
} }
inline void setPublic(PUB* pub) inline void setPublic(PUB* pub)
{ {
pvt->QXT_setPublic(pub); pvt->QXT_setPublic(pub);
} }
inline PVT& operator()() inline PVT& operator()()
{ {
return *static_cast<PVT*>(pvt); return *static_cast<PVT*>(pvt);
} }
inline const PVT& operator()() const inline const PVT& operator()() const
{ {
return *static_cast<PVT*>(pvt); return *static_cast<PVT*>(pvt);
} }
inline PVT * operator->() inline PVT * operator->()
{ {
return static_cast<PVT*>(pvt); return static_cast<PVT*>(pvt);
} }
inline const PVT * operator->() const inline const PVT * operator->() const
{ {
return static_cast<PVT*>(pvt); return static_cast<PVT*>(pvt);
} }
private: private:
QxtPrivateInterface(const QxtPrivateInterface&) { } QxtPrivateInterface(const QxtPrivateInterface&) { }
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
QxtPrivate<PUB>* pvt; QxtPrivate<PUB>* pvt;
}; };
#endif // QXT_GLOBAL #endif // QXT_GLOBAL

View File

@@ -38,185 +38,160 @@
#include "qxtglobalshortcut_p.h" #include "qxtglobalshortcut_p.h"
bool QxtGlobalShortcutPrivate::error = false; bool QxtGlobalShortcutPrivate::error = false;
#ifndef Q_OS_MAC #ifndef Q_OS_MACOS
int QxtGlobalShortcutPrivate::ref = 0; int QxtGlobalShortcutPrivate::ref = 0;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #endif // Q_OS_MACOS
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
#endif
#endif // Q_OS_MAC
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts; QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) {
{ #ifndef Q_OS_MACOS
#ifndef Q_OS_MAC if (!ref++)
if (!ref++)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
#else
QAbstractEventDispatcher::instance()->installNativeEventFilter(this); QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif #endif // Q_OS_MACOS
#endif // Q_OS_MAC
} }
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() {
{ #ifndef Q_OS_MACOS
#ifndef Q_OS_MAC if (!--ref)
if (!--ref) QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #endif // Q_OS_MACOS
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
#else
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#endif
#endif // Q_OS_MAC
} }
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) {
{
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier; Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]); key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods); mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
const quint32 nativeKey = nativeKeycode(key); const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeMods = nativeModifiers(mods); const quint32 nativeMods = nativeModifiers(mods);
const bool res = registerShortcut(nativeKey, nativeMods); const bool res = registerShortcut(nativeKey, nativeMods);
if (res) if (res)
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
else else
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString(); qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
return res; return res;
} }
bool QxtGlobalShortcutPrivate::unsetShortcut() bool QxtGlobalShortcutPrivate::unsetShortcut() {
{ bool res = false;
bool res = false; const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeKey = nativeKeycode(key); const quint32 nativeMods = nativeModifiers(mods);
const quint32 nativeMods = nativeModifiers(mods); if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p()) res = unregisterShortcut(nativeKey, nativeMods);
res = unregisterShortcut(nativeKey, nativeMods); if (res)
if (res) shortcuts.remove(qMakePair(nativeKey, nativeMods));
shortcuts.remove(qMakePair(nativeKey, nativeMods)); else
else qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString(); key = Qt::Key(0);
key = Qt::Key(0); mods = Qt::KeyboardModifiers(0);
mods = Qt::KeyboardModifiers(0); return res;
return res;
} }
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods)); if (shortcut && shortcut->isEnabled())
if (shortcut && shortcut->isEnabled()) emit shortcut->activated();
emit shortcut->activated();
} }
/*! /*!
\class QxtGlobalShortcut \class QxtGlobalShortcut
\inmodule QxtWidgets \inmodule QxtWidgets
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey". \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
A global shortcut triggers even if the application is not active. This A global shortcut triggers even if the application is not active. This
makes it easy to implement applications that react to certain shortcuts makes it easy to implement applications that react to certain shortcuts
still if some other application is active or if the application is for still if some other application is active or if the application is for
example minimized to the system tray. example minimized to the system tray.
Example usage: Example usage:
\code \code
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window); QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility())); connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12")); shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
\endcode \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) QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) : QObject(parent) {
: QObject(parent) QXT_INIT_PRIVATE(QxtGlobalShortcut);
{
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) QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) : QObject(parent) {
: QObject(parent) QXT_INIT_PRIVATE(QxtGlobalShortcut);
{ setShortcut(shortcut);
QXT_INIT_PRIVATE(QxtGlobalShortcut);
setShortcut(shortcut);
} }
/*! /*!
Destructs the QxtGlobalShortcut. Destructs the QxtGlobalShortcut.
*/ */
QxtGlobalShortcut::~QxtGlobalShortcut() QxtGlobalShortcut::~QxtGlobalShortcut() {
{ if (qxt_d().key != 0) qxt_d().unsetShortcut();
if (qxt_d().key != 0)
qxt_d().unsetShortcut();
} }
/*! /*!
\property QxtGlobalShortcut::shortcut \property QxtGlobalShortcut::shortcut
\brief the shortcut key sequence \brief the shortcut key sequence
\bold {Note:} Notice that corresponding key press and release events are not \bold {Note:} Notice that corresponding key press and release events are not
delivered for registered global shortcuts even if they are disabled. delivered for registered global shortcuts even if they are disabled.
Also, comma separated key sequences are not supported. Also, comma separated key sequences are not supported.
Only the first part is used: Only the first part is used:
\code \code
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B")); qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A")); Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
\endcode \endcode
*/ */
QKeySequence QxtGlobalShortcut::shortcut() const QKeySequence QxtGlobalShortcut::shortcut() const {
{ return QKeySequence(qxt_d().key | qxt_d().mods);
return QKeySequence(qxt_d().key | qxt_d().mods);
} }
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) {
{ if (qxt_d().key != 0)
if (qxt_d().key != 0) qxt_d().unsetShortcut();
qxt_d().unsetShortcut(); return qxt_d().setShortcut(shortcut);
return qxt_d().setShortcut(shortcut);
} }
/*! /*!
\property QxtGlobalShortcut::enabled \property QxtGlobalShortcut::enabled
\brief whether the shortcut is 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 bool QxtGlobalShortcut::isEnabled() const {
{ return qxt_d().enabled;
return qxt_d().enabled;
} }
void QxtGlobalShortcut::setEnabled(bool enabled) void QxtGlobalShortcut::setEnabled(bool enabled) {
{ qxt_d().enabled = enabled;
qxt_d().enabled = enabled;
} }
/*! /*!
Sets the shortcut \a disabled. Sets the shortcut \a disabled.
\sa enabled \sa enabled
*/ */
void QxtGlobalShortcut::setDisabled(bool disabled) void QxtGlobalShortcut::setDisabled(bool disabled) {
{ qxt_d().enabled = !disabled;
qxt_d().enabled = !disabled;
} }

View File

@@ -1,4 +1,3 @@
#ifndef QXTGLOBALSHORTCUT_H
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,6 +28,7 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#ifndef QXTGLOBALSHORTCUT_H
#define QXTGLOBALSHORTCUT_H #define QXTGLOBALSHORTCUT_H
#include <QObject> #include <QObject>
@@ -39,30 +39,29 @@
class QxtGlobalShortcutPrivate; class QxtGlobalShortcutPrivate;
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject {
{ Q_OBJECT
Q_OBJECT QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
QXT_DECLARE_PRIVATE(QxtGlobalShortcut) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
public: public:
explicit QxtGlobalShortcut(QObject* parent = 0); explicit QxtGlobalShortcut(QObject* parent = nullptr);
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0); explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = nullptr);
virtual ~QxtGlobalShortcut(); ~QxtGlobalShortcut();
QKeySequence shortcut() const; QKeySequence shortcut() const;
bool setShortcut(const QKeySequence& shortcut); bool setShortcut(const QKeySequence& shortcut);
bool isEnabled() const; bool isEnabled() const;
public Q_SLOTS: public Q_SLOTS:
void setEnabled(bool enabled = true); void setEnabled(bool enabled = true);
void setDisabled(bool disabled = true); void setDisabled(bool disabled = true);
Q_SIGNALS: Q_SIGNALS:
void activated(); void activated();
}; };
#endif // QXTGLOBALSHORTCUT_H #endif // QXTGLOBALSHORTCUT_H

View File

@@ -1,4 +1,3 @@
#include <Carbon/Carbon.h>
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,9 +28,12 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#include <Carbon/Carbon.h>
#include "qxtglobalshortcut_p.h" #include "qxtglobalshortcut_p.h"
#include <QMap> #include <QMap>
#include <QHash> #include <QHash>
#include <QPair>
#include <QtDebug> #include <QtDebug>
#include <QApplication> #include <QApplication>
@@ -41,218 +43,165 @@ static QHash<Identifier, quint32> keyIDs;
static quint32 hotKeySerial = 0; static quint32 hotKeySerial = 0;
static bool qxt_mac_handler_installed = false; static bool qxt_mac_handler_installed = false;
OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) 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);
}
Q_UNUSED(nextHandler);
Q_UNUSED(data);
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) {
EventHotKeyID keyID; EventHotKeyID keyID;
keyID.signature = 'cute'; GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, nullptr, sizeof(keyID), nullptr, &keyID);
keyID.id = ++hotKeySerial; Identifier id = keyIDs.key(keyID.id);
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
}
return noErr;
EventHotKeyRef ref = 0; }
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
if (rv) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); quint32 native = 0;
keyRefs.insert(keyID.id, ref); 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;
} }
return rv;
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::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{
Identifier id(nativeMods, nativeKey); if (!qxt_mac_handler_installed) {
if (!keyIDs.contains(id)) return false; 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);
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
keyIDs.remove(id);
return !UnregisterEventHotKey(ref);
} }

View File

@@ -1,4 +1,3 @@
#ifndef QXTGLOBALSHORTCUT_P_H
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,56 +28,45 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#ifndef QXTGLOBALSHORTCUT_P_H
#define QXTGLOBALSHORTCUT_P_H #define QXTGLOBALSHORTCUT_P_H
#include "qxtglobalshortcut.h" #include "qxtglobalshortcut.h"
#include <QAbstractEventDispatcher>
#include <QKeySequence>
#include <QHash> #include <QHash>
#include <QAbstractEventDispatcher>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#endif #include <QKeySequence>
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>, public QAbstractNativeEventFilter {
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
,public QAbstractNativeEventFilter
#endif
{
public: public:
QXT_DECLARE_PUBLIC(QxtGlobalShortcut) QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
QxtGlobalShortcutPrivate(); QxtGlobalShortcutPrivate();
~QxtGlobalShortcutPrivate(); ~QxtGlobalShortcutPrivate();
bool enabled; bool enabled;
Qt::Key key; Qt::Key key;
Qt::KeyboardModifiers mods; Qt::KeyboardModifiers mods;
bool setShortcut(const QKeySequence& shortcut); bool setShortcut(const QKeySequence& shortcut);
bool unsetShortcut(); bool unsetShortcut();
static bool error; static bool error;
#ifndef Q_OS_MAC #ifndef Q_OS_MACOS
static int ref; static int ref;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
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 #endif // Q_OS_MAC
static void activateShortcut(quint32 nativeKey, quint32 nativeMods); static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
private: private:
static quint32 nativeKeycode(Qt::Key keycode); static quint32 nativeKeycode(Qt::Key keycode);
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts; static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
}; };
#endif // QXTGLOBALSHORTCUT_P_H #endif // QXTGLOBALSHORTCUT_P_H

View File

@@ -31,217 +31,209 @@
#include <qt_windows.h> #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;
#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) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0; quint32 native = 0;
if (modifiers & Qt::ShiftModifier) if (modifiers & Qt::ShiftModifier)
native |= MOD_SHIFT; native |= MOD_SHIFT;
if (modifiers & Qt::ControlModifier) if (modifiers & Qt::ControlModifier)
native |= MOD_CONTROL; native |= MOD_CONTROL;
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
native |= MOD_ALT; native |= MOD_ALT;
if (modifiers & Qt::MetaModifier) if (modifiers & Qt::MetaModifier)
native |= MOD_WIN; native |= MOD_WIN;
// TODO: resolve these? // TODO: resolve these?
//if (modifiers & Qt::KeypadModifier) //if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier) //if (modifiers & Qt::GroupSwitchModifier)
return native; return native;
} }
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) 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 switch (key) {
case Qt::Key_0: case Qt::Key_Escape:
case Qt::Key_1: return VK_ESCAPE;
case Qt::Key_2: case Qt::Key_Tab:
case Qt::Key_3: case Qt::Key_Backtab:
case Qt::Key_4: return VK_TAB;
case Qt::Key_5: case Qt::Key_Backspace:
case Qt::Key_6: return VK_BACK;
case Qt::Key_7: case Qt::Key_Return:
case Qt::Key_8: case Qt::Key_Enter:
case Qt::Key_9: return VK_RETURN;
return key; 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;
// letters // numbers
case Qt::Key_A: case Qt::Key_0:
case Qt::Key_B: case Qt::Key_1:
case Qt::Key_C: case Qt::Key_2:
case Qt::Key_D: case Qt::Key_3:
case Qt::Key_E: case Qt::Key_4:
case Qt::Key_F: case Qt::Key_5:
case Qt::Key_G: case Qt::Key_6:
case Qt::Key_H: case Qt::Key_7:
case Qt::Key_I: case Qt::Key_8:
case Qt::Key_J: case Qt::Key_9:
case Qt::Key_K: return key;
case Qt::Key_L:
case Qt::Key_M: // letters
case Qt::Key_N: case Qt::Key_A:
case Qt::Key_O: case Qt::Key_B:
case Qt::Key_P: case Qt::Key_C:
case Qt::Key_Q: case Qt::Key_D:
case Qt::Key_R: case Qt::Key_E:
case Qt::Key_S: case Qt::Key_F:
case Qt::Key_T: case Qt::Key_G:
case Qt::Key_U: case Qt::Key_H:
case Qt::Key_V: case Qt::Key_I:
case Qt::Key_W: case Qt::Key_J:
case Qt::Key_X: case Qt::Key_K:
case Qt::Key_Y: case Qt::Key_L:
case Qt::Key_Z: case Qt::Key_M:
return key; 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;
}
default:
return 0;
}
} }
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{ return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
} }
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
{ return UnregisterHotKey(0, nativeMods ^ nativeKey);
return UnregisterHotKey(0, nativeMods ^ nativeKey);
} }

View File

@@ -1,4 +1,3 @@
#include "qxtglobalshortcut_p.h"
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,201 +28,176 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #include "qxtglobalshortcut_p.h"
# 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 <QtGlobal>
#include <QByteArray> #include <QApplication>
#include <QGuiApplication> #include <QGuiApplication>
#include <QKeySequence> #include <QKeySequence>
#include <QByteArray>
#include <QString> #include <QString>
#include <QVector> #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" #include "keymapper_x11.h"
namespace { namespace {
const QVector<quint32> maskModifiers = QVector<quint32>() const QVector<quint32> maskModifiers = QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
<< 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event); typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
class QxtX11ErrorHandler { class QxtX11ErrorHandler {
public: public:
static bool error; static bool error;
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) {
{ Q_UNUSED(display);
Q_UNUSED(display); switch (event->error_code) {
switch (event->error_code) case BadAccess:
case BadValue:
case BadWindow:
if (event->request_code == 33 /* X_GrabKey */ ||
event->request_code == 34 /* X_UngrabKey */)
{ {
case BadAccess: error = true;
case BadValue: //TODO:
case BadWindow: //char errstr[256];
if (event->request_code == 33 /* X_GrabKey */ || //XGetErrorText(dpy, err->error_code, errstr, 256);
event->request_code == 34 /* X_UngrabKey */)
{
error = true;
//TODO:
//char errstr[256];
//XGetErrorText(dpy, err->error_code, errstr, 256);
}
} }
return 0;
} }
return 0;
}
QxtX11ErrorHandler() QxtX11ErrorHandler() {
{ error = false;
error = false; m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler); }
}
~QxtX11ErrorHandler() ~QxtX11ErrorHandler() {
{ XSetErrorHandler(m_previousErrorHandler);
XSetErrorHandler(m_previousErrorHandler); }
}
private: private:
X11ErrorHandler m_previousErrorHandler; X11ErrorHandler m_previousErrorHandler;
}; };
bool QxtX11ErrorHandler::error = false; bool QxtX11ErrorHandler::error = false;
class QxtX11Data { class QxtX11Data {
public: public:
QxtX11Data() QxtX11Data() {
{ QPlatformNativeInterface *native = qApp->platformNativeInterface();
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) //void *display = native->nativeResourceForScreen(QByteArray("display"), QGuiApplication::primaryScreen());
m_display = QX11Info::display(); //m_display = reinterpret_cast<Display *>(display);
#else m_display = QX11Info::display();
QPlatformNativeInterface *native = qApp->platformNativeInterface(); }
void *display = native->nativeResourceForScreen(QByteArray("display"),
QGuiApplication::primaryScreen()); bool isValid() {
m_display = reinterpret_cast<Display *>(display); return m_display != nullptr;
#endif }
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);
} }
bool isValid() if (errorHandler.error) {
{ ungrabKey(keycode, modifiers, window);
return m_display != 0; return false;
} }
Display *display() return true;
{ }
Q_ASSERT(isValid());
return m_display; bool ungrabKey(quint32 keycode, quint32 modifiers, Window window) {
QxtX11ErrorHandler errorHandler;
foreach (quint32 maskMods, maskModifiers) {
XUngrabKey(display(), keycode, modifiers | maskMods, window);
} }
Window rootWindow() return !errorHandler.error;
{ }
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: private:
Display *m_display; Display *m_display;
}; };
} // namespace } // namespace
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, void *message, long *result) {
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; Q_UNUSED(result);
if (eventType == "xcb_generic_event_t") {
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message); xcb_key_press_event_t *kev = nullptr;
if ((ev->response_type & 127) == XCB_KEY_PRESS) if (eventType == "xcb_generic_event_t") {
kev = static_cast<xcb_key_press_event_t *>(message); 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;
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) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
quint32 native = 0; quint32 native = 0;
if (modifiers & Qt::ShiftModifier) if (modifiers & Qt::ShiftModifier)
native |= ShiftMask; native |= ShiftMask;
if (modifiers & Qt::ControlModifier) if (modifiers & Qt::ControlModifier)
native |= ControlMask; native |= ControlMask;
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
native |= Mod1Mask; native |= Mod1Mask;
if (modifiers & Qt::MetaModifier) if (modifiers & Qt::MetaModifier)
native |= Mod4Mask; native |= Mod4Mask;
// TODO: resolve these?
//if (modifiers & Qt::MetaModifier)
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
// TODO: resolve these?
//if (modifiers & Qt::MetaModifier)
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
} }
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
{
// (davidsansome) Try the table from QKeyMapper first - this seems to be // (davidsansome) Try the table from QKeyMapper first - this seems to be
// the only way to get Keysyms for the media keys. // the only way to get Keysyms for the media keys.
unsigned int keysym = 0; unsigned int keysym = 0;
@@ -238,9 +212,9 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
// If that didn't work then fall back on XStringToKeysym // If that didn't work then fall back on XStringToKeysym
if (!keysym) { if (!keysym) {
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
if (keysym == NoSymbol) if (keysym == NoSymbol)
keysym = static_cast<ushort>(key); keysym = static_cast<ushort>(key);
} }
QxtX11Data x11; QxtX11Data x11;
@@ -248,16 +222,15 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
return 0; return 0;
return XKeysymToKeycode(x11.display(), keysym); return XKeysymToKeycode(x11.display(), keysym);
} }
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtX11Data x11;
QxtX11Data x11; return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
} }
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtX11Data x11;
QxtX11Data x11; return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
} }

View File

@@ -19,9 +19,6 @@ cmake_minimum_required(VERSION 2.8.11)
if(${CMAKE_VERSION} VERSION_GREATER "3.0") if(${CMAKE_VERSION} VERSION_GREATER "3.0")
cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0054 NEW)
endif() endif()
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
cmake_policy(SET CMP0072 NEW)
endif()
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
include(CheckIncludeFiles) include(CheckIncludeFiles)
@@ -91,16 +88,12 @@ else(LINUX)
find_package(ALSA) find_package(ALSA)
pkg_check_modules(DBUS dbus-1) pkg_check_modules(DBUS dbus-1)
endif(LINUX) endif(LINUX)
if(ALSA_FOUND)
set(HAVE_ALSA ON)
endif()
if (NOT APPLE) if (NOT APPLE)
find_package(X11) find_package(X11)
endif() endif()
if(X11_FOUND) if(X11_FOUND)
set(HAVE_X11 ON) set(HAVE_X11 ON)
endif() endif()
find_package(OpenGL REQUIRED)
pkg_check_modules(GSTREAMER gstreamer-1.0) pkg_check_modules(GSTREAMER gstreamer-1.0)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0) pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
pkg_check_modules(GSTREAMER_AUDIO gstreamer-audio-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(CHROMAPRINT libchromaprint)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92) pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0) pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0) pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
pkg_check_modules(USBMUXD libusbmuxd) pkg_check_modules(LIBUSBMUXD libusbmuxd)
pkg_check_modules(PLIST libplist) pkg_check_modules(LIBPLIST libplist)
pkg_check_modules(LIBDEEZER libdeezer) pkg_check_modules(LIBDEEZER libdeezer)
pkg_check_modules(LIBDZMEDIA libdzmedia) pkg_check_modules(LIBDZMEDIA libdzmedia)
@@ -126,7 +119,7 @@ endif(WIN32)
# QT # QT
set(QT_MIN_VERSION 5.5.1) 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) if(X11_FOUND)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras)
endif() endif()
@@ -141,7 +134,7 @@ if(WIN32)
find_package(Qt5 REQUIRED COMPONENTS WinExtras) find_package(Qt5 REQUIRED COMPONENTS WinExtras)
endif() 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) if(DBUS_FOUND)
set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::DBus) set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::DBus)
@@ -158,15 +151,25 @@ endif()
# TAGLIB # TAGLIB
pkg_check_modules(TAGLIB 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. # Only use system taglib if it's greater than 1.11.1
# But let the user override as strawberry will still compile and work without. # 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) if (TAGLIB_VERSION VERSION_GREATER 1.11.1 OR WIN32)
option(USE_SYSTEM_TAGLIB "Use system taglib" ON) option(USE_SYSTEM_TAGLIB "Use system taglib" ON)
else() else()
option(USE_SYSTEM_TAGLIB "Use system taglib" OFF) option(USE_SYSTEM_TAGLIB "Use system taglib" OFF)
endif() endif()
if (TAGLIB_FOUND AND USE_SYSTEM_TAGLIB) 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_INCLUDES "${TAGLIB_INCLUDE_DIRS}")
set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}") set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}")
set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_INCLUDES)
@@ -263,6 +266,14 @@ if(WIN32)
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF) option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
endif(WIN32) 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" optional_component(DBUS ON "D-Bus support"
DEPENDS "D-Bus" DBUS_FOUND DEPENDS "D-Bus" DBUS_FOUND
) )
@@ -299,10 +310,6 @@ else ()
) )
endif() endif()
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
)
optional_component(LIBLASTFM ON "Last.fm album cover provider" optional_component(LIBLASTFM ON "Last.fm album cover provider"
DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS 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" optional_component(IMOBILEDEVICE ON "Devices: iPod Touch, iPhone, iPad support"
DEPENDS "libimobiledevice" IMOBILEDEVICE_FOUND DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
DEPENDS "libplist" PLIST_FOUND DEPENDS "libplist" LIBPLIST_FOUND
DEPENDS "libusbmuxd" USBMUXD_FOUND DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
DEPENDS "iPod classic support" LIBGPOD_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_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" optional_component(DZMEDIA ON "DZMedia"
DEPENDS "libdzmedia" LIBDZMEDIA_FOUND DEPENDS "libdzmedia" LIBDZMEDIA_FOUND
@@ -376,7 +388,7 @@ include_directories(${GLIB_INCLUDE_DIRS})
include_directories(${GLIBCONFIG_INCLUDE_DIRS}) include_directories(${GLIBCONFIG_INCLUDE_DIRS})
include_directories(${TAGLIB_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) set(IMOBILEDEVICE_USES_UDIDS ON)
endif() endif()

View File

@@ -2,6 +2,20 @@ Strawberry Music Player
======================= =======================
ChangeLog 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: Version 0.4.1:
* Fixed crash in analyzer * Fixed crash in analyzer

View File

@@ -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 dup -l -y
run zypper --non-interactive --gpg-auto-import-keys install \ run zypper --non-interactive --gpg-auto-import-keys install \
lsb-release \ lsb-release git tar make cmake gcc gcc-c++ pkg-config \
git tar make cmake gcc gcc-c++ pkg-config \
glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \ glibc-devel glib2-devel glib2-tools dbus-1-devel alsa-devel libpulse-devel libnotify-devel \
boost-devel protobuf-devel sqlite3-devel taglib-devel \ boost-devel protobuf-devel sqlite3-devel taglib-devel \
gstreamer-devel gstreamer-plugins-base-devel libxine-devel vlc-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 \ 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 libcdio-devel libgpod-devel libplist-devel libmtp-devel libusbmuxd-devel libchromaprint-devel

View File

@@ -1,8 +1,8 @@
:strawberry: Strawberry Music Player [![Build Status](https://travis-ci.org/jonaski/strawberry.svg?branch=master)](https://travis-ci.org/jonaski/strawberry) :strawberry: Strawberry Music Player [![Build Status](https://travis-ci.org/jonaski/strawberry.svg?branch=master)](https://travis-ci.org/jonaski/strawberry)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](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. 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.
It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
* Website: http://www.strawbs.org/ * Website: http://www.strawbs.org/
* Github: https://github.com/jonaski/strawberry * 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 * Audio CD playback
* Native desktop notifications * Native desktop notifications
* Playlists in multiple formats * 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 * Edit tags on music files
* Fetch tags from MusicBrainz * Fetch tags from MusicBrainz
* Album cover art from Last.fm, Musicbrainz and Discogs * 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 * [GCC](https://gcc.gnu.org/) or [clang](https://clang.llvm.org/) compiler
* [Protobuf library and compiler](https://developers.google.com/protocol-buffers/) * [Protobuf library and compiler](https://developers.google.com/protocol-buffers/)
* [Boost development headers](https://www.boost.org/) * [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) * [SQLite3](https://www.sqlite.org)
* [TagLib 1.11.1 or higher](http://taglib.org/) * [TagLib 1.11.1 or higher](http://taglib.org/)
* [Chromaprint library](https://acoustid.org/chromaprint) * [Chromaprint library](https://acoustid.org/chromaprint)
@@ -81,3 +82,7 @@ Optional:
![Browse](https://www.strawbs.org/pictures/screenshot-002-large.png) ![Browse](https://www.strawbs.org/pictures/screenshot-002-large.png)
### :moneybag: Donate
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRJUYV5QP6HW8)

View File

@@ -48,7 +48,7 @@ if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
) )
elseif (${DIST_NAME} STREQUAL "fedora") elseif (${DIST_NAME} STREQUAL "fedora")
if (DIST_VERSION) 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 () else ()
set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file") set(RPM_DISTRO ${DIST_NAME} CACHE STRING "Suffix of the rpm file")
endif() endif()

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 0) set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 4) set(STRAWBERRY_VERSION_MINOR 4)
set(STRAWBERRY_VERSION_PATCH 1) set(STRAWBERRY_VERSION_PATCH 2)
#set(STRAWBERRY_VERSION_PRERELEASE rc1) #set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF) 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(majorminorpatch "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}.${STRAWBERRY_VERSION_PATCH}")
set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}") set(STRAWBERRY_VERSION_DISPLAY "${majorminorpatch}")
set(STRAWBERRY_VERSION_PACKAGE "${majorminorpatch}")
set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}") set(STRAWBERRY_VERSION_RPM_V "${majorminorpatch}")
set(STRAWBERRY_VERSION_RPM_R "1") 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") if(${STRAWBERRY_VERSION_PATCH} EQUAL "0")
set(STRAWBERRY_VERSION_DISPLAY "${STRAWBERRY_VERSION_MAJOR}.${STRAWBERRY_VERSION_MINOR}") 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_PACKAGE "${GIT_TAGNAME}.${GIT_COMMITCOUNT}.${GIT_SHA1}")
set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}") set(STRAWBERRY_VERSION_RPM_V "${GIT_TAGNAME}")
set(STRAWBERRY_VERSION_RPM_R "2.${GIT_COMMITCOUNT}.${GIT_SHA1}") 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() endif()
message(STATUS "Strawberry Version:") message(STATUS "Strawberry Version:")
message(STATUS "Display: ${STRAWBERRY_VERSION_DISPLAY}") message(STATUS "Display: ${STRAWBERRY_VERSION_DISPLAY}")
message(STATUS "Package: ${STRAWBERRY_VERSION_PACKAGE}") 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}")

View File

@@ -9,7 +9,6 @@
<file>misc/playing_tooltip.txt</file> <file>misc/playing_tooltip.txt</file>
<file>misc/oauthsuccess.html</file> <file>misc/oauthsuccess.html</file>
<file>pictures/strawberry.png</file> <file>pictures/strawberry.png</file>
<file>pictures/strawbs-transparent.png</file>
<file>pictures/noalbumart.png</file> <file>pictures/noalbumart.png</file>
<file>pictures/nomusic.png</file> <file>pictures/nomusic.png</file>
<file>pictures/musicbrainz.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

View File

@@ -4,7 +4,6 @@
} }
#playlist[default_background_enabled = "true"] { #playlist[default_background_enabled = "true"] {
background-image: url(:pictures/strawbs-transparent.png);
background-attachment: fixed; background-attachment: fixed;
background-position: bottom right; background-position: bottom right;
background-repeat: none; background-repeat: none;

1
dist/CMakeLists.txt vendored
View File

@@ -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) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec.in ${CMAKE_CURRENT_SOURCE_DIR}/fedora/strawberry.spec @ONLY)
endif() endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog.in ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog) 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}/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.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) 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
View File

@@ -20,7 +20,6 @@ Build-Depends: debhelper (>= 7),
qtbase5-dev-tools, qtbase5-dev-tools,
qtbase5-private-dev, qtbase5-private-dev,
qt5-dev-tools, qt5-dev-tools,
libqt5opengl5-dev,
libqt5x11extras5-dev, libqt5x11extras5-dev,
libgstreamer1.0-dev, libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev, libgstreamer-plugins-base1.0-dev,
@@ -42,13 +41,14 @@ Architecture: any
Depends: ${shlibs:Depends}, Depends: ${shlibs:Depends},
${misc:Depends}, ${misc:Depends},
libsqlite3-0, libsqlite3-0,
libqt5sql5-sqlite,
gstreamer1.0-plugins-base, gstreamer1.0-plugins-base,
gstreamer1.0-plugins-good, gstreamer1.0-plugins-good,
gstreamer1.0-alsa, gstreamer1.0-alsa,
gstreamer1.0-pulseaudio gstreamer1.0-pulseaudio
Homepage: http://www.strawbs.org/ Homepage: http://www.strawbs.org/
Description: Audio player and music collection organizer 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: Features:
- Play and organize music - Play and organize music

View File

@@ -10,6 +10,7 @@ Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
BuildRequires: boost-devel BuildRequires: boost-devel
BuildRequires: cmake BuildRequires: cmake
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
BuildRequires: libappstream-glib
BuildRequires: gcc-c++ BuildRequires: gcc-c++
BuildRequires: hicolor-icon-theme BuildRequires: hicolor-icon-theme
BuildRequires: liblastfm-qt5-devel BuildRequires: liblastfm-qt5-devel
@@ -34,7 +35,6 @@ BuildRequires: pkgconfig(Qt5Network)
BuildRequires: pkgconfig(Qt5Xml) BuildRequires: pkgconfig(Qt5Xml)
BuildRequires: pkgconfig(Qt5X11Extras) BuildRequires: pkgconfig(Qt5X11Extras)
BuildRequires: pkgconfig(Qt5DBus) BuildRequires: pkgconfig(Qt5DBus)
BuildRequires: pkgconfig(Qt5OpenGL)
BuildRequires: pkgconfig(gstreamer-1.0) BuildRequires: pkgconfig(gstreamer-1.0)
BuildRequires: pkgconfig(gstreamer-app-1.0) BuildRequires: pkgconfig(gstreamer-app-1.0)
BuildRequires: pkgconfig(gstreamer-audio-1.0) BuildRequires: pkgconfig(gstreamer-audio-1.0)
@@ -67,7 +67,7 @@ Features:
* Audio analyzer * Audio analyzer
* Equalizer * Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player * Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support * Integrated Tidal and Deezer support
%prep %prep
%setup -qn %{name}-@STRAWBERRY_VERSION_PACKAGE@ %setup -qn %{name}-@STRAWBERRY_VERSION_PACKAGE@
@@ -91,10 +91,11 @@ popd
%install %install
make install DESTDIR=%{buildroot} -C %{_target_platform} make install DESTDIR=%{buildroot} -C %{_target_platform}
rm -rf %{buildroot}%{_datadir}/metainfo mv %{buildroot}%{_datadir}/metainfo %{buildroot}%{_datadir}/appdata
%check %check
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/appdata/strawberry.appdata.xml
%files %files
%defattr(-,root,root,-) %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/64x64/apps/strawberry.png
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png %{_datadir}/icons/hicolor/128x128/apps/strawberry.png
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg %{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
%{_datadir}/appdata/strawberry.appdata.xml
%{_mandir}/man1/strawberry.1.* %{_mandir}/man1/strawberry.1.*
%{_mandir}/man1/strawberry-tagreader.1.* %{_mandir}/man1/strawberry-tagreader.1.*

View File

@@ -15,6 +15,7 @@ BuildRequires: boost-devel
%endif %endif
BuildRequires: cmake BuildRequires: cmake
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
BuildRequires: appstream-glib
BuildRequires: gcc-c++ BuildRequires: gcc-c++
BuildRequires: hicolor-icon-theme BuildRequires: hicolor-icon-theme
BuildRequires: libQt5Gui-private-headers-devel BuildRequires: libQt5Gui-private-headers-devel
@@ -41,7 +42,6 @@ BuildRequires: pkgconfig(Qt5Network)
BuildRequires: pkgconfig(Qt5Xml) BuildRequires: pkgconfig(Qt5Xml)
BuildRequires: pkgconfig(Qt5X11Extras) BuildRequires: pkgconfig(Qt5X11Extras)
BuildRequires: pkgconfig(Qt5DBus) BuildRequires: pkgconfig(Qt5DBus)
BuildRequires: pkgconfig(Qt5OpenGL)
BuildRequires: pkgconfig(gstreamer-1.0) BuildRequires: pkgconfig(gstreamer-1.0)
BuildRequires: pkgconfig(gstreamer-app-1.0) BuildRequires: pkgconfig(gstreamer-app-1.0)
BuildRequires: pkgconfig(gstreamer-audio-1.0) BuildRequires: pkgconfig(gstreamer-audio-1.0)
@@ -57,6 +57,8 @@ BuildRequires: pkgconfig(libudf)
BuildRequires: pkgconfig(libxine) BuildRequires: pkgconfig(libxine)
BuildRequires: pkgconfig(libvlc) BuildRequires: pkgconfig(libvlc)
Requires: libQt5Sql5-sqlite
%description %description
Strawberry is a audio player and music collection organizer. 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.
@@ -76,7 +78,7 @@ Features:
* Audio analyzer * Audio analyzer
* Equalizer * Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player * Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support * Integrated Tidal and Deezer support
%prep %prep
%setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@ %setup -q -n %{name}-@STRAWBERRY_VERSION_PACKAGE@
@@ -88,12 +90,22 @@ make %{?_smp_mflags}
%install %install
cd build cd build
make install DESTDIR=$RPM_BUILD_ROOT 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 %clean
cd build cd build
make clean 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 %files
%defattr(-,root,root,-) %defattr(-,root,root,-)
%doc README.md Changelog %doc README.md Changelog
@@ -105,6 +117,11 @@ make clean
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png %{_datadir}/icons/hicolor/64x64/apps/strawberry.png
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png %{_datadir}/icons/hicolor/128x128/apps/strawberry.png
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg %{_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}.1%{?ext_man}
%{_mandir}/man1/%{name}-tagreader.1%{?ext_man} %{_mandir}/man1/%{name}-tagreader.1%{?ext_man}

65
dist/pacman/PKGBUILD.in vendored Normal file
View 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
}

View File

@@ -1,16 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<application> <component>
<id type="desktop">strawberry.desktop</id> <id>org.strawberry.strawberry</id>
<launchable type="desktop-id">strawberry.desktop</launchable>
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license> <project_license>GPL-3.0+</project_license>
<provides>
<binary>strawberry</binary>
<binary>strawberry-tagreader</binary>
</provides>
<name>Strawberry Music Player</name> <name>Strawberry Music Player</name>
<summary>An audio player and music collection organizer</summary> <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> <description>
<p> <p>
Strawberry is a audio player and music collection organizer. 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>
<p>Features::</p> <p>Features:</p>
<ul> <ul>
<li>Play and organize music</li> <li>Play and organize music</li>
<li>Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF</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>Song lyrics from AudD and API Seeds</li>
<li>Support for multiple backends</li> <li>Support for multiple backends</li>
<li>Audio analyzer</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>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> </ul>
</description> </description>
<screenshots> <screenshots>
<screenshot type="default" width="1920" height="1049">https://www.strawbs.org/pictures/screenshot-002-large.png</screenshot> <screenshot type="default">
<screenshot width="1920" height="1080">https://www.strawbs.org/pictures/screenshot-006-large.png</screenshot> <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> </screenshots>
<url type="homepage">http://www.strawbs.org/</url> <update_contact>eclipseo@fedoraproject.org</update_contact>
<updatecontact>eclipseo@fedoraproject.org</updatecontact> </component>
</application>

View File

@@ -315,12 +315,12 @@ Section "Uninstall"
Delete "$INSTDIR\libbz2.dll" Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-18.dll" Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.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\libfaad-2.dll"
Delete "$INSTDIR\libffi-6.dll" Delete "$INSTDIR\libffi-6.dll"
Delete "$INSTDIR\libFLAC-8.dll" Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.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\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll" Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll" Delete "$INSTDIR\libgmodule-2.0-0.dll"
@@ -352,7 +352,7 @@ Section "Uninstall"
Delete "$INSTDIR\libprotobuf-15.dll" Delete "$INSTDIR\libprotobuf-15.dll"
Delete "$INSTDIR\libspeex-1.dll" Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.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\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll" Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libvorbis-0.dll" Delete "$INSTDIR\libvorbis-0.dll"

View File

@@ -347,12 +347,12 @@ Section "Uninstall"
Delete "$INSTDIR\libbz2.dll" Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-18.dll" Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.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\libfaad-2.dll"
Delete "$INSTDIR\libffi-6.dll" Delete "$INSTDIR\libffi-6.dll"
Delete "$INSTDIR\libFLAC-8.dll" Delete "$INSTDIR\libFLAC-8.dll"
Delete "$INSTDIR\libfreetype-6.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\libgio-2.0-0.dll"
Delete "$INSTDIR\libglib-2.0-0.dll" Delete "$INSTDIR\libglib-2.0-0.dll"
Delete "$INSTDIR\libgmodule-2.0-0.dll" Delete "$INSTDIR\libgmodule-2.0-0.dll"
@@ -384,7 +384,7 @@ Section "Uninstall"
Delete "$INSTDIR\libprotobuf-15.dll" Delete "$INSTDIR\libprotobuf-15.dll"
Delete "$INSTDIR\libspeex-1.dll" Delete "$INSTDIR\libspeex-1.dll"
Delete "$INSTDIR\libsqlite3-0.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\libstdc++-6.dll"
Delete "$INSTDIR\libtag.dll" Delete "$INSTDIR\libtag.dll"
Delete "$INSTDIR\libvorbis-0.dll" Delete "$INSTDIR\libvorbis-0.dll"

View File

@@ -263,7 +263,6 @@ void DumpStackTrace() {
#endif #endif
} }
#if 0
QDebug CreateLoggerFatal(int line, const char *class_name) { return qCreateLogger(line, class_name, Fatal); } 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); } 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 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); } QDebug CreateLoggerDebug(int line, const char *class_name) { return qCreateLogger(line, class_name, Debug); }
#endif // QT_NO_DEBUG_OUTPUT #endif // QT_NO_DEBUG_OUTPUT
#endif
} // namespace logging } // namespace logging

View File

@@ -27,22 +27,11 @@
#ifdef QT_NO_DEBUG_STREAM #ifdef QT_NO_DEBUG_STREAM
# define qLog(level) while (false) QNoDebug() # define qLog(level) while (false) QNoDebug()
#else #else
#define qLog(level) \ #define qLog(level) logging::CreateLogger##level(__LINE__, __PRETTY_FUNCTION__)
logging::CreateLogger(logging::Level_##level, \
logging::ParsePrettyFunction(__PRETTY_FUNCTION__), \ #define qCreateLogger(line, class_name, level) logging::CreateLogger(logging::Level_##level, logging::ParsePrettyFunction(class_name), line)
__LINE__)
#endif // QT_NO_DEBUG_STREAM #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 { namespace logging {
class NullDevice : public QIODevice { class NullDevice : public QIODevice {
protected: protected:

View File

@@ -42,7 +42,6 @@ include_directories(${GOBJECT_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${LIBXML_INCLUDE_DIRS}) include_directories(${LIBXML_INCLUDE_DIRS})
include_directories(${CHROMAPRINT_INCLUDE_DIRS}) include_directories(${CHROMAPRINT_INCLUDE_DIRS})
include_directories(${OPENGL_INCLUDE_DIR})
if(HAVE_GSTREAMER) if(HAVE_GSTREAMER)
link_directories(${GSTREAMER_LIBRARY_DIRS}) link_directories(${GSTREAMER_LIBRARY_DIRS})
@@ -718,12 +717,12 @@ optional_source(HAVE_GIO
HEADERS device/giolister.h HEADERS device/giolister.h
) )
# libimobiledevice backend and device # imobiledevice backend and device
optional_source(HAVE_IMOBILEDEVICE optional_source(HAVE_IMOBILEDEVICE
INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES
${IMOBILEDEVICE_INCLUDE_DIRS} ${LIBIMOBILEDEVICE_INCLUDE_DIRS}
${PLIST_INCLUDE_DIRS} ${LIBPLIST_INCLUDE_DIRS}
${PLISTPP_INCLUDE_DIRS} ${LIBPLISTPP_INCLUDE_DIRS}
SOURCES SOURCES
device/afcdevice.cpp device/afcdevice.cpp
device/afcfile.cpp device/afcfile.cpp
@@ -966,12 +965,12 @@ endif(HAVE_AUDIOCD)
if(HAVE_IMOBILEDEVICE) if(HAVE_IMOBILEDEVICE)
target_link_libraries(strawberry_lib target_link_libraries(strawberry_lib
${IMOBILEDEVICE_LIBRARIES} ${LIBIMOBILEDEVICE_LIBRARIES}
${PLIST_LIBRARIES} ${LIBPLIST_LIBRARIES}
${USBMUXD_LIBRARIES} ${LIBUSBMUXD_LIBRARIES}
) )
link_directories(${IMOBILEDEVICE_LIBRARY_DIRS}) link_directories(${LIBIMOBILEDEVICE_LIBRARY_DIRS})
link_directories(${USBMUXD_LIBRARY_DIRS}) link_directories(${LIBUSBMUXD_LIBRARY_DIRS})
endif(HAVE_IMOBILEDEVICE) endif(HAVE_IMOBILEDEVICE)
if(HAVE_LIBMTP) if(HAVE_LIBMTP)

View File

@@ -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>&)));
}
}

View File

@@ -458,6 +458,7 @@ void CollectionView::contextMenuEvent(QContextMenuEvent *e) {
context_menu_->addSeparator(); context_menu_->addSeparator();
add_to_playlist_enqueue_ = context_menu_->addAction(IconLoader::Load("go-next"), tr("Queue track"), this, SLOT(AddToPlaylistEnqueue())); 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 #ifdef HAVE_GSTREAMER
context_menu_->addSeparator(); 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() { void CollectionView::OpenInNewPlaylist() {
QMimeData *data = model()->mimeData(selectedIndexes()); QMimeData *data = model()->mimeData(selectedIndexes());

View File

@@ -117,6 +117,7 @@ signals:
void Load(); void Load();
void AddToPlaylist(); void AddToPlaylist();
void AddToPlaylistEnqueue(); void AddToPlaylistEnqueue();
void AddToPlaylistEnqueueNext();
void OpenInNewPlaylist(); void OpenInNewPlaylist();
#ifdef HAVE_GSTREAMER #ifdef HAVE_GSTREAMER
void Organise(); void Organise();
@@ -148,6 +149,7 @@ signals:
QAction *load_; QAction *load_;
QAction *add_to_playlist_; QAction *add_to_playlist_;
QAction *add_to_playlist_enqueue_; QAction *add_to_playlist_enqueue_;
QAction *add_to_playlist_enqueue_next_;
QAction *open_in_new_playlist_; QAction *open_in_new_playlist_;
#ifdef HAVE_GSTREAMER #ifdef HAVE_GSTREAMER
QAction *organise_; QAction *organise_;

View File

@@ -76,7 +76,6 @@ CollectionWatcher::CollectionWatcher(QObject *parent)
rescan_paused_(false), rescan_paused_(false),
total_watches_(0), total_watches_(0),
cue_parser_(new CueParser(backend_, this)) { cue_parser_(new CueParser(backend_, this)) {
Utilities::SetThreadIOPriority(Utilities::IOPRIO_CLASS_IDLE);
rescan_timer_->setInterval(1000); rescan_timer_->setInterval(1000);
rescan_timer_->setSingleShot(true); rescan_timer_->setSingleShot(true);

View File

@@ -313,7 +313,7 @@ QString GetApplicationSupportPath() {
NSString* user_path = [paths objectAtIndex:0]; NSString* user_path = [paths objectAtIndex:0];
ret = QString::fromUtf8([user_path UTF8String]); ret = QString::fromUtf8([user_path UTF8String]);
} else { } else {
ret = "~/Collection/Application Support"; ret = "~/Library/Application Support";
} }
return ret; return ret;
} }

View File

@@ -544,6 +544,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
playlist_queue_->setVisible(false); playlist_queue_->setVisible(false);
playlist_queue_->setShortcut(QKeySequence("Ctrl+D")); playlist_queue_->setShortcut(QKeySequence("Ctrl+D"));
ui_->playlist->addAction(playlist_queue_); 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_ = playlist_menu_->addAction(IconLoader::Load("media-forward"), tr("Toggle skip status"), this, SLOT(PlaylistSkip()));
playlist_skip_->setVisible(false); playlist_skip_->setVisible(false);
ui_->playlist->addAction(playlist_skip_); ui_->playlist->addAction(playlist_skip_);
@@ -1184,8 +1188,6 @@ void MainWindow::UpdateTrackPosition() {
if (length <= 0) { if (length <= 0) {
// Probably a stream that we don't know the length of // Probably a stream that we don't know the length of
//ui_->track_slider->SetStopped();
//tray_icon_->SetProgress(0);
return; return;
} }
@@ -1403,10 +1405,12 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
if (selected < 1) { if (selected < 1) {
playlist_queue_->setVisible(false); playlist_queue_->setVisible(false);
playlist_queue_play_next_->setVisible(false);
playlist_skip_->setVisible(false); playlist_skip_->setVisible(false);
} }
else { else {
playlist_queue_->setVisible(true); playlist_queue_->setVisible(true);
playlist_queue_play_next_->setVisible(true);
playlist_skip_->setVisible(true); playlist_skip_->setVisible(true);
if (in_queue == 1 && not_in_queue == 0) playlist_queue_->setText(tr("Dequeue track")); 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")); 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 if (in_queue == 0 && not_in_queue > 1) playlist_queue_->setText(tr("Queue selected tracks"));
else playlist_queue_->setText(tr("Toggle queue status")); 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")); 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 > 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")); 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); 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() { void MainWindow::PlaylistSkip() {
QModelIndexList indexes; QModelIndexList indexes;

View File

@@ -168,6 +168,7 @@ signals:
void PlaylistPlay(); void PlaylistPlay();
void PlaylistStopAfter(); void PlaylistStopAfter();
void PlaylistQueue(); void PlaylistQueue();
void PlaylistQueuePlayNext();
void PlaylistSkip(); void PlaylistSkip();
void PlaylistRemoveCurrent(); void PlaylistRemoveCurrent();
void PlaylistEditFinished(const QModelIndex& index); void PlaylistEditFinished(const QModelIndex& index);
@@ -360,6 +361,7 @@ signals:
#endif #endif
QAction *playlist_open_in_browser_; QAction *playlist_open_in_browser_;
QAction *playlist_queue_; QAction *playlist_queue_;
QAction* playlist_queue_play_next_;
QAction *playlist_skip_; QAction *playlist_skip_;
QAction *playlist_add_to_another_; QAction *playlist_add_to_another_;
QList<QAction*> playlistitem_actions_; QList<QAction*> playlistitem_actions_;

View File

@@ -31,11 +31,12 @@ class MimeData : public QMimeData {
Q_OBJECT Q_OBJECT
public: 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), : override_user_settings_(false),
clear_first_(clear), clear_first_(clear),
play_now_(play_now), play_now_(play_now),
enqueue_now_(enqueue), enqueue_now_(enqueue),
enqueue_next_now_(enqueue_next_now),
open_in_new_playlist_(open_in_new_playlist), open_in_new_playlist_(open_in_new_playlist),
name_for_new_playlist_(QString()), name_for_new_playlist_(QString()),
from_doubleclick_(false) {} from_doubleclick_(false) {}

View File

@@ -188,10 +188,6 @@ void QtSystemTrayIcon::SetStopped() {
} }
void QtSystemTrayIcon::LastFMButtonVisibilityChanged(bool value) {
}
void QtSystemTrayIcon::MuteButtonStateChanged(bool value) { void QtSystemTrayIcon::MuteButtonStateChanged(bool value) {
if (action_mute_) action_mute_->setChecked(value); if (action_mute_) action_mute_->setChecked(value);
} }

View File

@@ -61,7 +61,6 @@ protected:
void SetPaused(); void SetPaused();
void SetPlaying(bool enable_play_pause = false); void SetPlaying(bool enable_play_pause = false);
void SetStopped(); void SetStopped();
void LastFMButtonVisibilityChanged(bool value);
void MuteButtonStateChanged(bool value); void MuteButtonStateChanged(bool value);
// QObject // QObject

View File

@@ -20,6 +20,8 @@
#include "config.h" #include "config.h"
#include <QtGlobal>
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
# include <QDBusConnection> # include <QDBusConnection>
# include <QDBusConnectionInterface> # include <QDBusConnectionInterface>

View File

@@ -117,7 +117,6 @@ void DeezerService::ReloadSettings() {
QSettings s; QSettings s;
s.beginGroup(DeezerSettingsPage::kSettingsGroup); s.beginGroup(DeezerSettingsPage::kSettingsGroup);
quality_ = s.value("quality", "FLAC").toString();
searchdelay_ = s.value("searchdelay", 1500).toInt(); searchdelay_ = s.value("searchdelay", 1500).toInt();
albumssearchlimit_ = s.value("albumssearchlimit", 100).toInt(); albumssearchlimit_ = s.value("albumssearchlimit", 100).toInt();
songssearchlimit_ = s.value("songssearchlimit", 100).toInt(); songssearchlimit_ = s.value("songssearchlimit", 100).toInt();

View File

@@ -133,7 +133,6 @@ class DeezerService : public InternetService {
#endif #endif
QTimer *timer_searchdelay_; QTimer *timer_searchdelay_;
QString quality_;
int searchdelay_; int searchdelay_;
int albumssearchlimit_; int albumssearchlimit_;
int songssearchlimit_; int songssearchlimit_;

View File

@@ -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); void SetDeviceOptions(int row, const QString &friendly_name, const QString &icon_name, MusicStorage::TranscodeMode mode, Song::FileType format);
// QAbstractListModel // QAbstractListModel
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
public slots: public slots:
void Unmount(int row); void Unmount(int row);

View File

@@ -30,11 +30,11 @@
DeviceStateFilterModel::DeviceStateFilterModel(QObject *parent, DeviceManager::State state) DeviceStateFilterModel::DeviceStateFilterModel(QObject *parent, DeviceManager::State state)
: QSortFilterProxyModel(parent), : QSortFilterProxyModel(parent),
state_(state) state_(state) {
{
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(ProxyRowCountChanged())); connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(ProxyRowCountChanged(QModelIndex, int, int)));
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(ProxyRowCountChanged())); connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(ProxyRowCountChanged(QModelIndex, int, int)));
connect(this, SIGNAL(modelReset()), SLOT(ProxyRowCountChanged())); connect(this, SIGNAL(modelReset()), this, SLOT(ProxyRowCountChanged()));
} }
bool DeviceStateFilterModel::filterAcceptsRow(int row, const QModelIndex&) const { bool DeviceStateFilterModel::filterAcceptsRow(int row, const QModelIndex&) const {
@@ -45,6 +45,10 @@ void DeviceStateFilterModel::ProxyRowCountChanged() {
emit IsEmptyChanged(rowCount() == 0); emit IsEmptyChanged(rowCount() == 0);
} }
void DeviceStateFilterModel::ProxyRowCountChanged(QModelIndex index, int first, int last) {
emit IsEmptyChanged(rowCount() == 0);
}
void DeviceStateFilterModel::setSourceModel(QAbstractItemModel *sourceModel) { void DeviceStateFilterModel::setSourceModel(QAbstractItemModel *sourceModel) {
QSortFilterProxyModel::setSourceModel(sourceModel); QSortFilterProxyModel::setSourceModel(sourceModel);
setDynamicSortFilter(true); setDynamicSortFilter(true);

View File

@@ -49,6 +49,7 @@ protected:
private slots: private slots:
void ProxyRowCountChanged(); void ProxyRowCountChanged();
void ProxyRowCountChanged(QModelIndex index, int first, int last);
private: private:
DeviceManager::State state_; DeviceManager::State state_;

View File

@@ -71,24 +71,23 @@ const int DeviceItemDelegate::kIconPadding = 6;
DeviceItemDelegate::DeviceItemDelegate(QObject *parent) : CollectionItemDelegate(parent) {} 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? // Is it a device or a collection item?
if (index.data(DeviceManager::Role::Role_State).isNull()) { if (index.data(DeviceManager::Role::Role_State).isNull()) {
CollectionItemDelegate::paint(p, opt, index); CollectionItemDelegate::paint(painter, option, index);
return; return;
} }
// Draw the background // Draw the background
const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem*>(&opt); const QWidget *widget = option.widget;
const QWidget *widget = vopt->widget;
QStyle *style = widget->style() ? widget->style() : QApplication::style(); 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 // Font for the status line
QFont status_font(opt.font); QFont status_font(option.font);
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
status_font.setPointSize(status_font.pointSize() - 1); 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); status_font.setPointSize(status_font.pointSize() - 2);
#endif #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 line1(option.rect);
QRect line2(opt.rect); QRect line2(option.rect);
line1.setTop(line1.top() + (opt.rect.height() - text_height) / 2); line1.setTop(line1.top() + (option.rect.height() - text_height) / 2);
line2.setTop(line1.top() + QFontMetrics(opt.font).height()); line2.setTop(line1.top() + QFontMetrics(option.font).height());
line1.setLeft(line1.left() + DeviceManager::kDeviceIconSize + kIconPadding); line1.setLeft(line1.left() + DeviceManager::kDeviceIconSize + kIconPadding);
line2.setLeft(line2.left() + DeviceManager::kDeviceIconSize + kIconPadding); line2.setLeft(line2.left() + DeviceManager::kDeviceIconSize + kIconPadding);
// Change the color for selected items // Change the color for selected items
if (opt.state & QStyle::State_Selected) { if (option.state & QStyle::State_Selected) {
p->setPen(opt.palette.color(QPalette::HighlightedText)); painter->setPen(option.palette.color(QPalette::HighlightedText));
} }
// Draw the icon // 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) // 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) // Draw the second line (status)
DeviceManager::State state = static_cast<DeviceManager::State>(index.data(DeviceManager::Role_State).toInt()); 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) if (option.state & QStyle::State_Selected)
p->setPen(opt.palette.color(QPalette::HighlightedText)); painter->setPen(option.palette.color(QPalette::HighlightedText));
else else
p->setPen(opt.palette.color(QPalette::Dark)); painter->setPen(option.palette.color(QPalette::Dark));
p->setFont(status_font);
p->drawText(line2, Qt::AlignLeft | Qt::AlignTop, status_text);
p->restore(); painter->setFont(status_font);
painter->drawText(line2, Qt::AlignLeft | Qt::AlignTop, status_text);
painter->restore();
} }

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>300</width> <width>400</width>
<height>300</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">

View File

@@ -84,7 +84,7 @@ class ScopedIOObject {
// Helpful MTP & USB links: // Helpful MTP & USB links:
// Apple USB device interface guide: // 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: // Example Apple code for requesting a USB device descriptor:
// http://www.opensource.apple.com/source/IOUSBFamily/IOUSBFamily-208.4.5/USBProber/BusProbeClass.m // http://www.opensource.apple.com/source/IOUSBFamily/IOUSBFamily-208.4.5/USBProber/BusProbeClass.m
// Libmtp's detection code: // Libmtp's detection code:
@@ -122,12 +122,9 @@ void MacDeviceLister::Init() {
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
LIBMTP_device_entry_t device = devices[i]; LIBMTP_device_entry_t device = devices[i];
MTPDevice d; MTPDevice d;
// FIXME: d.vendor = QString::fromLatin1(device.vendor);
//d.vendor = QString::toLatin1(device.vendor);
d.vendor = device.vendor;
d.vendor_id = device.vendor_id; d.vendor_id = device.vendor_id;
//d.product = QString::toLatin1(device.product); d.product = QString::fromLatin1(device.product);
d.product = device.product;
d.product_id = device.product_id; d.product_id = device.product_id;
d.quirks = device.device_flags; d.quirks = device.device_flags;
sMTPDeviceList << d; sMTPDeviceList << d;
@@ -355,9 +352,7 @@ void MacDeviceLister::DiskAddedCallback(DADiskRef disk, void* context) {
#ifdef HAVE_AUDIOCD #ifdef HAVE_AUDIOCD
if (kind && strcmp([kind UTF8String], kIOCDMediaClass) == 0) { if (kind && strcmp([kind UTF8String], kIOCDMediaClass) == 0) {
// CD inserted. // CD inserted.
// FIXME: QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk));
//QString bsd_name = QString::toLatin1(DADiskGetBSDName(disk));
QString bsd_name = DADiskGetBSDName(disk);
me->cd_devices_ << bsd_name; me->cd_devices_ << bsd_name;
emit me->DeviceAdded(bsd_name); emit me->DeviceAdded(bsd_name);
return; 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 // We cannot access the USB tree when the disk is removed but we still get
// the BSD disk name. // the BSD disk name.
// FIXME: QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk));
//QString bsd_name = QString::toLatin1(DADiskGetBSDName(disk));
QString bsd_name = DADiskGetBSDName(disk);
if (me->cd_devices_.remove(bsd_name)) { if (me->cd_devices_.remove(bsd_name)) {
emit me->DeviceRemoved(bsd_name); emit me->DeviceRemoved(bsd_name);
return; return;
@@ -571,9 +564,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
if (!ret || data.at(0) != 0x28) if (!ret || data.at(0) != 0x28)
continue; continue;
// FIXME: if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") {
//if (QString::toLatin1(data.data() + 0x12, 3) != "MTP") {
if (QString(data.data() + 0x12) != "MTP") {
// Not quite. // Not quite.
continue; continue;
} }
@@ -583,9 +574,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
continue; continue;
} }
// FIXME: if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") {
//if (QString::toLatin1(data.data() + 0x12) != "MTP") {
if (QString(data.data() + 0x12) != "MTP") {
// Not quite. // Not quite.
continue; continue;
} }
@@ -684,14 +673,14 @@ QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
const MTPDevice& device = mtp_devices_[serial]; const MTPDevice& device = mtp_devices_[serial];
QString str; QString str;
str.sprintf("gphoto2://usb-%d-%d/", device.bus, device.address); 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); QUrl url(str);
// FIXME: url.setQuery(url_query);
//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));
return QList<QUrl>() << url; return QList<QUrl>() << url;
} }

View File

@@ -99,8 +99,8 @@ QString About::MainHtml() const {
ret += QString("<p>"); ret += QString("<p>");
ret += QString("Strawberry is a audio player and music collection organizer.<br />"); 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("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."); 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>");
//ret += QString("<p>Website: <a href=\"http://www.strawbs.org/licenses/\">http://www.strawbs.org/</a></p>"); //ret += QString("<p>Website: <a href=\"http://www.strawbs.org/licenses/\">http://www.strawbs.org/</a></p>");
ret += QString("<p>"); ret += QString("<p>");

View File

@@ -61,7 +61,6 @@ DeezerEngine::DeezerEngine(TaskManager *task_manager)
stopping_(false) { stopping_(false) {
type_ = Engine::Deezer; type_ = Engine::Deezer;
ReloadSettings();
} }
@@ -158,11 +157,37 @@ bool DeezerEngine::Init() {
} }
LoadAccessToken(); LoadAccessToken();
ReloadSettings();
return true; 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 { bool DeezerEngine::Initialised() const {
if (connect_ && player_) return true; if (connect_ && player_) return true;

View File

@@ -45,6 +45,7 @@ class DeezerEngine : public Engine::Base {
~DeezerEngine(); ~DeezerEngine();
bool Init(); bool Init();
void ReloadSettings();
Engine::State state() const { return state_; } 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 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); bool Play(quint64 offset_nanosec);

View File

@@ -106,24 +106,11 @@ GstEngine::GstEngine(TaskManager *task_manager)
ReloadSettings(); 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() { GstEngine::~GstEngine() {
EnsureInitialised(); EnsureInitialised();
current_pipeline_.reset(); current_pipeline_.reset();
#ifdef Q_OS_MACOS
g_object_unref(tls_database_);
#endif
} }
bool GstEngine::Init() { bool GstEngine::Init() {
@@ -436,13 +423,7 @@ void GstEngine::SetEnvironment() {
QString plugin_path; QString plugin_path;
QString registry_filename; QString registry_filename;
// On windows and mac we bundle the gstreamer plugins with strawberry // On windows 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
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
plugin_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/gstreamer-plugins"); plugin_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/gstreamer-plugins");
#endif #endif
@@ -463,10 +444,6 @@ void GstEngine::SetEnvironment() {
Utilities::SetEnv("GST_REGISTRY", registry_filename); 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"); Utilities::SetEnv("PULSE_PROP_media.role", "music");
} }

View File

@@ -657,7 +657,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
// Dragged from a collection // 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. // 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) 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 else
InsertSongItems<SongPlaylistItem>(song_data->songs, row, play_now, enqueue_now, enqueue_next_now); 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) { if (items.count() > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated. // 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(); undo_stack_->clear();
} }
else { else {
@@ -718,11 +718,11 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
else if (data->hasFormat(kCddaMimeType)) { else if (data->hasFormat(kCddaMimeType)) {
SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player()); SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player());
connect(inserter, SIGNAL(Error(QString)), SIGNAL(Error(QString))); 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()) { else if (data->hasUrls()) {
// URL list dragged from the file list or some other app // 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; 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()); SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, collection_, backend_->app()->player());
connect(inserter, SIGNAL(Error(QString)), SIGNAL(Error(QString))); 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) { if (items.count() > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated. // 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(); undo_stack_->clear();
} else { } 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)); 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; if (items.isEmpty()) return;
@@ -937,6 +937,14 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bo
queue_->ToggleTracks(indexes); queue_->ToggleTracks(indexes);
} }
if (enqueue_next) {
QModelIndexList indexes;
for (int i = start; i <= end; ++i) {
indexes << index(i, 0);
}
queue_->InsertFirst(indexes);
}
Save(); Save();
ReshuffleIndices(); ReshuffleIndices();
@@ -1110,6 +1118,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr<Playlist
case Column_Comment: strcmp(comment); case Column_Comment: strcmp(comment);
case Column_Source: cmp(source); case Column_Source: cmp(source);
default: qLog(Error) << "No such column" << column;
} }
#undef cmp #undef cmp
@@ -1165,7 +1174,7 @@ QString Playlist::column_name(Column column) {
case Column_Comment: return tr("Comment"); case Column_Comment: return tr("Comment");
case Column_Source: return tr("Source"); case Column_Source: return tr("Source");
default: return QString(); default: qLog(Error) << "No such column" << column;;
} }
return ""; return "";
@@ -1263,10 +1272,6 @@ void Playlist::Save() const {
} }
//namespace {
//typedef QFutureWatcher<QList<PlaylistItemPtr>> PlaylistItemFutureWatcher;
//}
void Playlist::Restore() { void Playlist::Restore() {
if (!backend_) return; if (!backend_) return;
@@ -1824,7 +1829,7 @@ void Playlist::RemoveDeletedSongs() {
PlaylistItemPtr item = items_[row]; PlaylistItemPtr item = items_[row];
Song song = item->Metadata(); Song song = item->Metadata();
if (!QFile::exists(song.url().toLocalFile())) { if (!song.is_stream() && !QFile::exists(song.url().toLocalFile())) {
rows_to_remove.append(row); rows_to_remove.append(row);
} }
} }

View File

@@ -308,7 +308,7 @@ private:
void InsertSongItems(const SongList &songs, int pos, bool play_now, bool enqueue, bool enqueue_next = false); 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 // 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); PlaylistItemList RemoveItemsWithoutUndo(int pos, int count);
void MoveItemsWithoutUndo(const QList<int> &source_rows, int pos); void MoveItemsWithoutUndo(const QList<int> &source_rows, int pos);
void MoveItemWithoutUndo(int source, int dest); void MoveItemWithoutUndo(int source, int dest);

View File

@@ -45,28 +45,29 @@ PlaylistFilter::PlaylistFilter(QObject *parent)
column_names_["artist"] = Playlist::Column_Artist; column_names_["artist"] = Playlist::Column_Artist;
column_names_["album"] = Playlist::Column_Album; column_names_["album"] = Playlist::Column_Album;
column_names_["albumartist"] = Playlist::Column_AlbumArtist; column_names_["albumartist"] = Playlist::Column_AlbumArtist;
column_names_["composer"] = Playlist::Column_Composer;
column_names_["performer"] = Playlist::Column_Performer; column_names_["performer"] = Playlist::Column_Performer;
column_names_["grouping"] = Playlist::Column_Grouping; column_names_["composer"] = Playlist::Column_Composer;
column_names_["length"] = Playlist::Column_Length;
column_names_["track"] = Playlist::Column_Track;
column_names_["disc"] = Playlist::Column_Disc;
column_names_["year"] = Playlist::Column_Year; column_names_["year"] = Playlist::Column_Year;
column_names_["originalyear"] = Playlist::Column_OriginalYear; 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_["genre"] = Playlist::Column_Genre;
column_names_["comment"] = Playlist::Column_Comment;
column_names_["bitrate"] = Playlist::Column_Bitrate;
column_names_["samplerate"] = Playlist::Column_Samplerate; column_names_["samplerate"] = Playlist::Column_Samplerate;
column_names_["bitdepth"] = Playlist::Column_Bitdepth; column_names_["bitdepth"] = Playlist::Column_Bitdepth;
column_names_["bitrate"] = Playlist::Column_Bitrate;
column_names_["filename"] = Playlist::Column_Filename; 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_Track
<< Playlist::Column_Disc << Playlist::Column_Disc
<< Playlist::Column_Year << Playlist::Column_Length
<< Playlist::Column_Bitrate
<< Playlist::Column_Samplerate << Playlist::Column_Samplerate
<< Playlist::Column_Bitdepth; << Playlist::Column_Bitdepth
<< Playlist::Column_Bitrate;
} }
PlaylistFilter::~PlaylistFilter() { PlaylistFilter::~PlaylistFilter() {

View File

@@ -47,6 +47,7 @@ PlaylistHeader::PlaylistHeader(Qt::Orientation orientation, PlaylistView *view,
hide_action_ = menu_->addAction(tr("&Hide..."), this, SLOT(HideCurrent())); hide_action_ = menu_->addAction(tr("&Hide..."), this, SLOT(HideCurrent()));
stretch_action_ = menu_->addAction(tr("&Stretch columns to fit window"), this, SLOT(ToggleStretchEnabled())); 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(); menu_->addSeparator();
QMenu *align_menu = new QMenu(tr("&Align text"), this); QMenu *align_menu = new QMenu(tr("&Align text"), this);
@@ -141,3 +142,6 @@ void PlaylistHeader::enterEvent(QEvent*) {
emit MouseEntered(); emit MouseEntered();
} }
void PlaylistHeader::ResetColumns() {
view_->ResetColumns();
}

View File

@@ -55,6 +55,7 @@ class PlaylistHeader : public StretchHeaderView {
private slots: private slots:
void HideCurrent(); void HideCurrent();
void ToggleVisible(int section); void ToggleVisible(int section);
void ResetColumns();
void SetColumnAlignment(QAction *action); void SetColumnAlignment(QAction *action);
private: private:
@@ -67,6 +68,7 @@ class PlaylistHeader : public StretchHeaderView {
QMenu *menu_; QMenu *menu_;
QAction *hide_action_; QAction *hide_action_;
QAction *stretch_action_; QAction *stretch_action_;
QAction *reset_action_;
QAction *align_left_action_; QAction *align_left_action_;
QAction *align_center_action_; QAction *align_center_action_;
QAction *align_right_action_; QAction *align_right_action_;

View File

@@ -36,17 +36,18 @@ namespace PlaylistUndoCommands {
Base::Base(Playlist* playlist) : QUndoCommand(0), playlist_(playlist) {} 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), : Base(playlist),
items_(items), items_(items),
pos_(pos), pos_(pos),
enqueue_(enqueue) enqueue_(enqueue),
enqueue_next_(enqueue_next)
{ {
setText(tr("add %n songs", "", items_.count())); setText(tr("add %n songs", "", items_.count()));
} }
void InsertItems::redo() { void InsertItems::redo() {
playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_); playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_, enqueue_next_);
} }
void InsertItems::undo() { void InsertItems::undo() {

View File

@@ -51,7 +51,7 @@ namespace PlaylistUndoCommands {
class InsertItems : public Base { class InsertItems : public Base {
public: 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 undo();
void redo(); void redo();
@@ -64,6 +64,7 @@ namespace PlaylistUndoCommands {
PlaylistItemList items_; PlaylistItemList items_;
int pos_; int pos_;
bool enqueue_; bool enqueue_;
bool enqueue_next_;
}; };
class RemoveItems : public Base { class RemoveItems : public Base {

View File

@@ -80,7 +80,6 @@
using std::sort; using std::sort;
const int PlaylistView::kStateVersion = 6;
const int PlaylistView::kGlowIntensitySteps = 24; const int PlaylistView::kGlowIntensitySteps = 24;
const int PlaylistView::kAutoscrollGraceTimeout = 30; // seconds const int PlaylistView::kAutoscrollGraceTimeout = 30; // seconds
const int PlaylistView::kDropIndicatorWidth = 2; const int PlaylistView::kDropIndicatorWidth = 2;
@@ -135,8 +134,8 @@ PlaylistView::PlaylistView(QWidget *parent)
style_(new PlaylistProxyStyle(style())), style_(new PlaylistProxyStyle(style())),
playlist_(nullptr), playlist_(nullptr),
header_(new PlaylistHeader(Qt::Horizontal, this, this)), header_(new PlaylistHeader(Qt::Horizontal, this, this)),
initialized_(false),
setting_initial_header_layout_(false), setting_initial_header_layout_(false),
upgrading_from_qheaderview_(false),
read_only_settings_(true), read_only_settings_(true),
header_loaded_(false), header_loaded_(false),
background_initialized_(false), background_initialized_(false),
@@ -159,19 +158,18 @@ PlaylistView::PlaylistView(QWidget *parent)
currenttrack_pause_(":/pictures/currenttrack_pause.png"), currenttrack_pause_(":/pictures/currenttrack_pause.png"),
cached_current_row_row_(-1), cached_current_row_row_(-1),
drop_indicator_row_(-1), drop_indicator_row_(-1),
drag_over_(false) drag_over_(false) {
{
setHeader(header_); setHeader(header_);
header_->setSectionsMovable(true); header_->setSectionsMovable(true);
setStyle(style_); setStyle(style_);
setMouseTracking(true); setMouseTracking(true);
connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(SaveGeometry())); connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(SaveGeometry()));
connect(header_, SIGNAL(sectionMoved(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(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(SaveGeometry()));
connect(header_, SIGNAL(SectionVisibilityChanged(int,bool)), SLOT(SaveGeometry())); connect(header_, SIGNAL(SectionVisibilityChanged(int,bool)), SLOT(SaveGeometry()));
connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(InvalidateCachedCurrentPixmap())); connect(header_, SIGNAL(sectionResized(int,int,int)), SLOT(InvalidateCachedCurrentPixmap()));
connect(header_, SIGNAL(sectionMoved(int,int,int)), SLOT(InvalidateCachedCurrentPixmap())); connect(header_, SIGNAL(sectionMoved(int,int,int)), SLOT(InvalidateCachedCurrentPixmap()));
connect(header_, SIGNAL(SectionVisibilityChanged(int,bool)), 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))); connect(fade_animation_, SIGNAL(valueChanged(qreal)), SLOT(FadePreviousBackgroundImage(qreal)));
fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0 fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0
initialized_ = true;
} }
PlaylistView::~PlaylistView() { PlaylistView::~PlaylistView() {
@@ -253,7 +253,7 @@ void PlaylistView::SetPlaylist(Playlist *playlist) {
} }
playlist_ = playlist; playlist_ = playlist;
if (!header_loaded_) LoadGeometry(); LoadGeometry();
ReloadSettings(); ReloadSettings();
setFocus(); setFocus();
read_only_settings_ = false; read_only_settings_ = false;
@@ -285,39 +285,35 @@ void PlaylistView::setModel(QAbstractItemModel *m) {
void PlaylistView::LoadGeometry() { void PlaylistView::LoadGeometry() {
QSettings settings; QSettings settings;
header_loaded_ = true;
settings.beginGroup(Playlist::kSettingsGroup); settings.beginGroup(Playlist::kSettingsGroup);
QByteArray state(settings.value("state").toByteArray()); QByteArray state(settings.value("state").toByteArray());
if (!header_->RestoreState(state)) { if (!header_->RestoreState(state)) {
// Maybe we're upgrading from a version that persisted the state with QHeaderView. // Maybe we're upgrading from a version that persisted the state with QHeaderView.
if (!header_->restoreState(state)) { 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_Year);
header_->HideSection(Playlist::Column_OriginalYear); header_->HideSection(Playlist::Column_OriginalYear);
header_->HideSection(Playlist::Column_Disc);
header_->HideSection(Playlist::Column_Genre); header_->HideSection(Playlist::Column_Genre);
header_->HideSection(Playlist::Column_Filename); header_->HideSection(Playlist::Column_Filename);
header_->HideSection(Playlist::Column_BaseFilename);
header_->HideSection(Playlist::Column_Filesize); header_->HideSection(Playlist::Column_Filesize);
header_->HideSection(Playlist::Column_DateCreated); header_->HideSection(Playlist::Column_DateCreated);
header_->HideSection(Playlist::Column_DateModified); 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_PlayCount);
header_->HideSection(Playlist::Column_SkipCount); header_->HideSection(Playlist::Column_SkipCount);
header_->HideSection(Playlist::Column_LastPlayed); header_->HideSection(Playlist::Column_LastPlayed);
header_->HideSection(Playlist::Column_Comment); header_->HideSection(Playlist::Column_Comment);
header_->HideSection(Playlist::Column_BaseFilename); header_->HideSection(Playlist::Column_Grouping);
header_->HideSection(Playlist::Column_Samplerate);
header_->HideSection(Playlist::Column_Bitdepth);
header_->moveSection(header_->visualIndex(Playlist::Column_Track), 0); header_->moveSection(header_->visualIndex(Playlist::Column_Track), 0);
setting_initial_header_layout_ = true; setting_initial_header_layout_ = true;
} }
else { else {
upgrading_from_qheaderview_ = true; setting_initial_header_layout_ = true;
} }
} }
@@ -333,11 +329,13 @@ void PlaylistView::LoadGeometry() {
header_->ShowSection(Playlist::Column_Title); header_->ShowSection(Playlist::Column_Title);
} }
header_loaded_ = true;
} }
void PlaylistView::SaveGeometry() { void PlaylistView::SaveGeometry() {
if (read_only_settings_) return; if (!initialized_ || read_only_settings_) return;
QSettings settings; QSettings settings;
settings.beginGroup(Playlist::kSettingsGroup); settings.beginGroup(Playlist::kSettingsGroup);
@@ -929,11 +927,10 @@ void PlaylistView::ReloadSettings() {
glow_enabled_ = s.value("glow_effect", true).toBool(); glow_enabled_ = s.value("glow_effect", true).toBool();
s.endGroup(); s.endGroup();
if (setting_initial_header_layout_ || upgrading_from_qheaderview_) { if (setting_initial_header_layout_) {
s.beginGroup(Playlist::kSettingsGroup); s.beginGroup(Playlist::kSettingsGroup);
header_->SetStretchEnabled(s.value("stretch", true).toBool()); header_->SetStretchEnabled(s.value("stretch", true).toBool());
s.endGroup(); s.endGroup();
upgrading_from_qheaderview_ = false;
} }
if (currently_glowing_ && glow_enabled_ && isVisible()) StartGlowing(); if (currently_glowing_ && glow_enabled_ && isVisible()) StartGlowing();
@@ -1035,7 +1032,7 @@ void PlaylistView::ReloadSettings() {
void PlaylistView::SaveSettings() { void PlaylistView::SaveSettings() {
if (read_only_settings_) return; if (!initialized_ || read_only_settings_) return;
QSettings s; QSettings s;
@@ -1054,6 +1051,7 @@ void PlaylistView::SaveSettings() {
} }
void PlaylistView::StretchChanged(bool stretch) { void PlaylistView::StretchChanged(bool stretch) {
if (!initialized_) return;
setHorizontalScrollBarPolicy(stretch ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); setHorizontalScrollBarPolicy(stretch ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
SaveGeometry(); SaveGeometry();
} }
@@ -1084,17 +1082,17 @@ ColumnAlignmentMap PlaylistView::DefaultColumnAlignment() {
ColumnAlignmentMap ret; ColumnAlignmentMap ret;
ret[Playlist::Column_Length] = ret[Playlist::Column_Year] =
ret[Playlist::Column_OriginalYear] =
ret[Playlist::Column_Track] = ret[Playlist::Column_Track] =
ret[Playlist::Column_Disc] = ret[Playlist::Column_Disc] =
ret[Playlist::Column_Year] = ret[Playlist::Column_Length] =
ret[Playlist::Column_Bitrate] =
ret[Playlist::Column_Samplerate] = ret[Playlist::Column_Samplerate] =
ret[Playlist::Column_Bitdepth] = ret[Playlist::Column_Bitdepth] =
ret[Playlist::Column_Bitrate] =
ret[Playlist::Column_Filesize] = ret[Playlist::Column_Filesize] =
ret[Playlist::Column_PlayCount] = ret[Playlist::Column_PlayCount] =
ret[Playlist::Column_SkipCount] = ret[Playlist::Column_SkipCount] =
ret[Playlist::Column_OriginalYear] =
(Qt::AlignRight | Qt::AlignVCenter); (Qt::AlignRight | Qt::AlignVCenter);
return ret; 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_);
}

View File

@@ -99,7 +99,6 @@ class PlaylistView : public QTreeView {
PlaylistView(QWidget *parent = nullptr); PlaylistView(QWidget *parent = nullptr);
~PlaylistView(); ~PlaylistView();
static const int kStateVersion;
// Constants for settings: are persistent, values should not be changed // Constants for settings: are persistent, values should not be changed
static const char *kSettingBackgroundImageType; static const char *kSettingBackgroundImageType;
static const char *kSettingBackgroundImageFilename; static const char *kSettingBackgroundImageFilename;
@@ -125,6 +124,8 @@ class PlaylistView : public QTreeView {
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setModel(QAbstractItemModel *model); void setModel(QAbstractItemModel *model);
void ResetColumns();
public slots: public slots:
void ReloadSettings(); void ReloadSettings();
void StopGlowing(); void StopGlowing();
@@ -214,8 +215,8 @@ class PlaylistView : public QTreeView {
PlaylistProxyStyle *style_; PlaylistProxyStyle *style_;
Playlist *playlist_; Playlist *playlist_;
PlaylistHeader *header_; PlaylistHeader *header_;
bool initialized_;
bool setting_initial_header_layout_; bool setting_initial_header_layout_;
bool upgrading_from_qheaderview_;
bool read_only_settings_; bool read_only_settings_;
bool header_loaded_; bool header_loaded_;

View File

@@ -43,12 +43,13 @@ SongLoaderInserter::SongLoaderInserter(TaskManager *task_manager, CollectionBack
SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); } 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; destination_ = destination;
row_ = row; row_ = row;
play_now_ = play_now; play_now_ = play_now;
enqueue_ = enqueue; enqueue_ = enqueue;
enqueue_next_ = enqueue_next;
connect(destination, SIGNAL(destroyed()), SLOT(DestinationDestroyed())); connect(destination, SIGNAL(destroyed()), SLOT(DestinationDestroyed()));
connect(this, SIGNAL(PreloadFinished()), SLOT(InsertSongs())); 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 // First, we add tracks (without metadata) into the playlist
// In the meantime, MusicBrainz will be queried to get songs' metadata. // In the meantime, MusicBrainz will be queried to get songs' metadata.
// AudioCDTagsLoaded will be called next, and playlist's items will be updated. // 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; destination_ = destination;
row_ = row; row_ = row;
play_now_ = play_now; play_now_ = play_now;
enqueue_ = enqueue; enqueue_ = enqueue;
enqueue_next_ = enqueue_next;
SongLoader *loader = new SongLoader(collection_, player_, this); SongLoader *loader = new SongLoader(collection_, player_, this);
NewClosure(loader, SIGNAL(AudioCDTracksLoaded()), this, SLOT(AudioCDTracksLoaded(SongLoader*)), loader); NewClosure(loader, SIGNAL(AudioCDTracksLoaded()), this, SLOT(AudioCDTracksLoaded(SongLoader*)), loader);
@@ -128,7 +130,7 @@ void SongLoaderInserter::AudioCDTagsLoaded(bool success) {
void SongLoaderInserter::InsertSongs() { void SongLoaderInserter::InsertSongs() {
// Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely // Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely
if (destination_) { if (destination_) {
destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_); destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_, enqueue_next_);
} }
} }

View File

@@ -44,8 +44,8 @@ class SongLoaderInserter : public QObject {
SongLoaderInserter(TaskManager *task_manager, CollectionBackendInterface *collection, const Player *player); SongLoaderInserter(TaskManager *task_manager, CollectionBackendInterface *collection, const Player *player);
~SongLoaderInserter(); ~SongLoaderInserter();
void Load(Playlist *destination, int row, bool play_now, bool enqueue, const QList<QUrl> &urls); 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); void LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next);
signals: signals:
void Error(const QString &message); void Error(const QString &message);
@@ -68,6 +68,7 @@ signals:
int row_; int row_;
bool play_now_; bool play_now_;
bool enqueue_; bool enqueue_;
bool enqueue_next_;
SongList songs_; SongList songs_;

View File

@@ -78,7 +78,6 @@ void BackendSettingsPage::Load() {
configloaded_ = false; configloaded_ = false;
engineloaded_ = false; engineloaded_ = false;
xinewarning_ = false;
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineName(Engine::None)).toString()); Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineName(Engine::None)).toString());
if (enginetype == Engine::None && engine()) enginetype = engine()->type(); if (enginetype == Engine::None && engine()) enginetype = engine()->type();
@@ -193,7 +192,6 @@ void BackendSettingsPage::Load_Engine(Engine::EngineType enginetype) {
qLog(Debug) << "Switching engine."; qLog(Debug) << "Switching engine.";
Engine::EngineType new_enginetype = dialog()->app()->player()->CreateEngine(enginetype); Engine::EngineType new_enginetype = dialog()->app()->player()->CreateEngine(enginetype);
dialog()->app()->player()->Init(); dialog()->app()->player()->Init();
dialog()->set_output_changed(false);
if (new_enginetype != enginetype) { if (new_enginetype != enginetype) {
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(engine()->type())); 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 if (ui_->radiobutton_alsa_plughw->isChecked()) s_.setValue("alsaplugin", static_cast<int>(alsa_plugin::alsa_plughw));
else s_.remove("alsaplugin"); 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() { void BackendSettingsPage::Cancel() {
@@ -402,7 +396,6 @@ void BackendSettingsPage::EngineChanged(int index) {
} }
engineloaded_ = false; engineloaded_ = false;
xinewarning_ = false;
ResetWarning(); ResetWarning();
Load_Engine(enginetype); Load_Engine(enginetype);
@@ -415,8 +408,6 @@ void BackendSettingsPage::OutputChanged(int index) {
EngineBase::OutputDetails output = ui_->combobox_output->itemData(index).value<EngineBase::OutputDetails>(); EngineBase::OutputDetails output = ui_->combobox_output->itemData(index).value<EngineBase::OutputDetails>();
Load_Device(output.name, QVariant()); Load_Device(output.name, QVariant());
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
} }
void BackendSettingsPage::DeviceSelectionChanged(int index) { 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 (!ui_->lineedit_device->text().isEmpty()) ui_->lineedit_device->setText("");
} }
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
} }
void BackendSettingsPage::DeviceStringChanged() { 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) { void BackendSettingsPage::SwitchALSADevices(alsa_plugin alsaplugin) {
// All ALSA devices are listed twice, one for "hw" and one for "plughw" // All ALSA devices are listed twice, one for "hw" and one for "plughw"

View File

@@ -91,7 +91,6 @@ private:
QSettings s_; QSettings s_;
bool configloaded_; bool configloaded_;
bool engineloaded_; bool engineloaded_;
bool xinewarning_;
ErrorDialog errordialog_; ErrorDialog errordialog_;
Engine::EngineType enginetype_current_; Engine::EngineType enginetype_current_;

View File

@@ -52,12 +52,10 @@ DeezerSettingsPage::DeezerSettingsPage(SettingsDialog *parent)
dialog()->installEventFilter(this); dialog()->installEventFilter(this);
ui_->combobox_quality->addItem("AAC (64)", "AAC_64"); ui_->combobox_quality->addItem("MP3 128kbps \"Standard\"", "MP3_128");
ui_->combobox_quality->addItem("MP3 (64)", "MP3_64"); ui_->combobox_quality->addItem("MP3 320kbps \"High Quality\"", "MP3_320");
ui_->combobox_quality->addItem("MP3 (128)", "MP3_128"); ui_->combobox_quality->addItem("FLAC \"CD Quality\"", "FLAC");
ui_->combobox_quality->addItem("MP3 (256)", "MP3_256"); ui_->combobox_quality->addItem("\"Data Efficient\"", "DATA_EFFICIENT");
ui_->combobox_quality->addItem("MP3 (320)", "MP3_320");
ui_->combobox_quality->addItem("FLAC", "FLAC");
ui_->combobox_coversize->addItem("Small", "cover_small"); ui_->combobox_coversize->addItem("Small", "cover_small");
ui_->combobox_coversize->addItem("Medium", "cover_medium"); ui_->combobox_coversize->addItem("Medium", "cover_medium");
@@ -74,10 +72,6 @@ void DeezerSettingsPage::Load() {
s.beginGroup(kSettingsGroup); s.beginGroup(kSettingsGroup);
ui_->checkbox_enable->setChecked(s.value("enabled", false).toBool()); 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"); dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_quality, "quality", "FLAC");
ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt()); ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt());
ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 100).toInt()); ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 100).toInt());
@@ -102,8 +96,6 @@ void DeezerSettingsPage::Save() {
QSettings s; QSettings s;
s.beginGroup(kSettingsGroup); s.beginGroup(kSettingsGroup);
s.setValue("enabled", ui_->checkbox_enable->isChecked()); 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("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex()));
s.setValue("searchdelay", ui_->spinbox_searchdelay->value()); s.setValue("searchdelay", ui_->spinbox_searchdelay->value());
s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value()); s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value());

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>715</width> <width>715</width>
<height>547</height> <height>575</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -55,76 +55,6 @@
</property> </property>
</spacer> </spacer>
</item> </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> <item>
<widget class="LoginStateWidget" name="login_state" native="true"/> <widget class="LoginStateWidget" name="login_state" native="true"/>
</item> </item>

View File

@@ -112,8 +112,7 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
model_(app_->collection_model()->directory_model()), model_(app_->collection_model()->directory_model()),
appearance_(app_->appearance()), appearance_(app_->appearance()),
ui_(new Ui_SettingsDialog), ui_(new Ui_SettingsDialog),
loading_settings_(false), loading_settings_(false) {
output_changed_(false) {
ui_->setupUi(this); ui_->setupUi(this);
ui_->list->setItemDelegate(new SettingsItemDelegate(this)); ui_->list->setItemDelegate(new SettingsItemDelegate(this));
@@ -129,8 +128,13 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
AddPage(Page_Transcoding, new TranscoderSettingsPage(this), general); AddPage(Page_Transcoding, new TranscoderSettingsPage(this), general);
#endif #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) #if defined(HAVE_STREAM_TIDAL) || defined(HAVE_STREAM_DEEZER)
QTreeWidgetItem *internet = AddCategory(tr("Internet")); QTreeWidgetItem *internet = AddCategory(tr("Streaming"));
#endif #endif
#ifdef HAVE_STREAM_TIDAL #ifdef HAVE_STREAM_TIDAL
AddPage(Page_Tidal, new TidalSettingsPage(this), internet); AddPage(Page_Tidal, new TidalSettingsPage(this), internet);
@@ -139,12 +143,6 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
AddPage(Page_Deezer, new DeezerSettingsPage(this), internet); AddPage(Page_Deezer, new DeezerSettingsPage(this), internet);
#endif #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 // List box
connect(ui_->list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(CurrentItemChanged(QTreeWidgetItem*))); connect(ui_->list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(CurrentItemChanged(QTreeWidgetItem*)));
ui_->list->setCurrentItem(pages_[Page_Behaviour].item_); ui_->list->setCurrentItem(pages_[Page_Behaviour].item_);
@@ -221,11 +219,6 @@ void SettingsDialog::Save() {
void SettingsDialog::accept() { void SettingsDialog::accept() {
Save(); 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(); QDialog::accept();
} }

View File

@@ -109,8 +109,6 @@ public:
// QWidget // QWidget
void showEvent(QShowEvent *e); 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); void ComboBoxLoadFromSettings(QSettings &s, QComboBox *combobox, QString setting, QString default_value);
signals: signals:
@@ -144,8 +142,6 @@ private:
bool loading_settings_; bool loading_settings_;
QMap<Page, PageData> pages_; QMap<Page, PageData> pages_;
bool output_changed_;
}; };
#endif // SETTINGSDIALOG_H #endif // SETTINGSDIALOG_H

View File

@@ -100,7 +100,10 @@ void TrackSlider::SetValue(int elapsed, int total) {
setting_value_ = true; // This is so we don't emit from QAbstractSlider::valueChanged setting_value_ = true; // This is so we don't emit from QAbstractSlider::valueChanged
ui_->slider->setMaximum(total); ui_->slider->setMaximum(total);
ui_->slider->setValue(elapsed); if (!ui_->slider->isSliderDown()) {
ui_->slider->setValue(elapsed);
}
setting_value_ = false; setting_value_ = false;
UpdateTimes(elapsed / kMsecPerSec); UpdateTimes(elapsed / kMsecPerSec);
@@ -116,7 +119,7 @@ void TrackSlider::UpdateTimes(int elapsed) {
} }
else { else {
// Check if slider maximum value is changed before updating // 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(); slider_maximum_value_ = ui_->slider->maximum();
ui_->remaining->setText(Utilities::PrettyTime((ui_->slider->maximum() / kMsecPerSec))); ui_->remaining->setText(Utilities::PrettyTime((ui_->slider->maximum() / kMsecPerSec)));
} }

View File

@@ -111,7 +111,11 @@ void TrackSliderSlider::enterEvent(QEvent* e) {
void TrackSliderSlider::leaveEvent(QEvent* e) { void TrackSliderSlider::leaveEvent(QEvent* e) {
QSlider::leaveEvent(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) { void TrackSliderSlider::keyPressEvent(QKeyEvent* event) {
@@ -130,7 +134,7 @@ void TrackSliderSlider::keyPressEvent(QKeyEvent* event) {
void TrackSliderSlider::UpdateDeltaTime() { void TrackSliderSlider::UpdateDeltaTime() {
if (popup_->isVisible()) { if (popup_->isVisible()) {
int delta_seconds = mouse_hover_seconds_ - value(); int delta_seconds = mouse_hover_seconds_ - (value() / kMsecPerSec);
popup_->SetSmallText(Utilities::PrettyTimeDelta(delta_seconds)); popup_->SetSmallText(Utilities::PrettyTimeDelta(delta_seconds));
} }
} }