Merge branch 'master' into clangen/upstream-pdcurses

This commit is contained in:
casey langen 2020-04-01 09:42:39 -07:00
commit edd0e2cb9b
19 changed files with 312 additions and 89 deletions

View File

@ -147,6 +147,7 @@ PlaybackService::PlaybackService(
, unshuffled(library)
, repeatMode(RepeatNone)
, messageQueue(messageQueue)
, timeChangeMode(TimeChangeSeek)
, seekPosition(-1.0f)
, index(NO_POSITION)
, nextIndex(NO_POSITION)

View File

@ -30,6 +30,7 @@ set (CUBE_SRCS
./app/util/ConsoleLogger.cpp
./app/util/GlobalHotkeys.cpp
./app/util/Hotkeys.cpp
./app/util/MagicConstants.cpp
./app/util/PreferenceKeys.cpp
./app/util/Playback.cpp
./app/util/Rating.cpp

View File

@ -43,7 +43,6 @@
#include <app/util/Playback.h>
#include <app/util/Messages.h>
#include <app/overlay/PlayQueueOverlays.h>
#include <app/overlay/BrowseOverlays.h>
#include "DirectoryLayout.h"
@ -178,7 +177,7 @@ void DirectoryLayout::OnDirectoryChanged(
}
void DirectoryLayout::UpdateTitle() {
std::string title = _TSTR("browse_title_tracks");
std::string title = "";
size_t selected = this->directoryList->GetSelectedIndex();
if (selected != ListWindow::NO_SELECTION) {
@ -242,10 +241,22 @@ bool DirectoryLayout::KeyPress(const std::string& key) {
}
}
else if (Hotkeys::Is(Hotkeys::ContextMenu, key)) {
auto tracks = this->trackList->GetTrackList();
auto index = this->trackList->GetSelectedTrackIndex();
index = (index == ListWindow::NO_SELECTION) ? 0 : index;
this->playback.Play(*tracks.get(), index);
if (this->GetFocus() == this->directoryList) {
size_t index = this->directoryList->GetSelectedIndex();
if (index != DirectoryAdapter::NO_INDEX) {
auto path = this->adapter->GetFullPathAt(index);
if (path.size()) {
PlayQueueOverlays::ShowAddDirectoryOverlay(
Window::MessageQueue(), this->playback, this->library, path);
}
}
}
else {
auto tracks = this->trackList->GetTrackList();
auto index = this->trackList->GetSelectedTrackIndex();
index = (index == ListWindow::NO_SELECTION) ? 0 : index;
this->playback.Play(*tracks.get(), index);
}
}
else if (Hotkeys::Is(Hotkeys::ViewRefresh, key)) {
this->queryHash = 0;

View File

@ -48,6 +48,7 @@
#include <app/util/Hotkeys.h>
#include <app/util/Messages.h>
#include <app/util/PreferenceKeys.h>
#include <app/util/MagicConstants.h>
#include <core/support/Playback.h>
#include "LibraryLayout.h"
@ -392,6 +393,14 @@ void LibraryLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
LayoutBase::ProcessMessage(message);
}
void LibraryLayout::ShowDirectoryChooser() {
BrowseOverlays::ShowDirectoryChooser(
this->library,
[this](std::string directory) {
this->ShowDirectories(directory);
});
}
bool LibraryLayout::KeyPress(const std::string& key) {
if (this->visibleLayout == this->browseLayout ||
this->visibleLayout == this->directoryLayout)
@ -419,8 +428,13 @@ bool LibraryLayout::KeyPress(const std::string& key) {
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseChooseCategory, key)) {
BrowseOverlays::ShowCategoryChooser(
this->library,
[this](std::string category) {
this->ShowBrowse(category);
[this](std::string category, std::string type) {
if (type == MagicConstants::DirectoryCategoryType) {
this->ShowDirectoryChooser();
}
else {
this->ShowBrowse(category);
}
});
return true;
}
@ -443,11 +457,7 @@ bool LibraryLayout::KeyPress(const std::string& key) {
return true;
}
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseDirectories, key)) {
BrowseOverlays::ShowDirectoryChooser(
this->library,
[this](std::string directory) {
this->ShowDirectories(directory);
});
this->ShowDirectoryChooser();
return true;
}
else if (this->GetFocus() == this->transportView && Hotkeys::Is(Hotkeys::Up, key)) {

View File

@ -96,6 +96,7 @@ namespace musik {
void ShowBrowse(const std::string& category = "");
void ShowCategorySearch();
void ShowTrackSearch();
void ShowDirectoryChooser();
void ShowDirectories(const std::string& directory);
void ChangeMainLayout(std::shared_ptr<cursespp::LayoutBase> newLayout);

View File

@ -35,7 +35,9 @@
#include <stdafx.h>
#include "BrowseOverlays.h"
#include <app/util/MagicConstants.h>
#include <core/library/query/local/AllCategoriesQuery.h>
#include <core/i18n/Locale.h>
#include <cursespp/SimpleScrollAdapter.h>
#include <cursespp/ListOverlay.h>
#include <cursespp/DialogOverlay.h>
@ -48,7 +50,7 @@ using namespace musik::core;
using namespace musik::core::db;
using namespace musik::core::db::local;
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id" };
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id", "directory" };
static std::string lastSelectedCategory, lastSelectedDirectory;
static void showNoPathsError() {
@ -64,7 +66,7 @@ static void showNoPathsError() {
void BrowseOverlays::ShowCategoryChooser(
musik::core::ILibraryPtr library,
std::function<void(std::string)> callback)
std::function<void(std::string, std::string)> callback)
{
using Adapter = cursespp::SimpleScrollAdapter;
using ListOverlay = cursespp::ListOverlay;
@ -77,16 +79,29 @@ void BrowseOverlays::ShowCategoryChooser(
adapter->SetSelectable(true);
size_t index = 0;
auto filtered = query->GetResult()->Filter([&index, adapter](const Value& value) -> bool {
auto result = query->GetResult();
auto filtered = result->Filter([&index, adapter](const Value& value) -> bool {
auto str = value->ToString();
if (BLACKLIST.find(str) == BLACKLIST.end()) {
adapter->AddEntry(str);
if (lastSelectedCategory == str) {
index = adapter->GetEntryCount() - 1;
}
return true;
return BLACKLIST.find(str) == BLACKLIST.end();
});
filtered->Add(std::make_shared<SdkValue>(
_TSTR("browse_title_directory"),
-1LL,
MagicConstants::DirectoryCategoryType));
filtered->Sort([](const auto a, const auto b) -> bool {
return a->ToString() < b->ToString();
});
filtered->Each([&index, adapter](const Value& value) {
auto str = value->ToString();
adapter->AddEntry(str);
if (lastSelectedCategory == str) {
index = adapter->GetEntryCount() - 1;
}
return false;
});
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
@ -98,8 +113,9 @@ void BrowseOverlays::ShowCategoryChooser(
.SetItemSelectedCallback(
[callback, filtered]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
lastSelectedCategory = filtered->At(index)->ToString();
callback(lastSelectedCategory);
auto selected = filtered->At(index);
lastSelectedCategory = selected->ToString();
callback(lastSelectedCategory, selected->GetType());
});
cursespp::App::Overlays().Push(dialog);

View File

@ -43,7 +43,7 @@ namespace musik {
public:
static void ShowCategoryChooser(
musik::core::ILibraryPtr library,
std::function<void(std::string)> callback);
std::function<void(std::string, std::string)> callback);
static void ShowDirectoryChooser(
musik::core::ILibraryPtr library,

View File

@ -43,12 +43,14 @@
#include <core/library/query/local/CategoryTrackListQuery.h>
#include <core/library/query/local/CategoryListQuery.h>
#include <core/library/query/local/DirectoryTrackListQuery.h>
#include <core/library/query/local/GetPlaylistQuery.h>
#include <core/library/query/local/SavePlaylistQuery.h>
#include <core/library/query/local/DeletePlaylistQuery.h>
#include <core/runtime/Message.h>
#include <app/util/Messages.h>
#include <app/util/MagicConstants.h>
#include <cursespp/App.h>
#include <cursespp/SimpleScrollAdapter.h>
@ -119,6 +121,31 @@ static std::string stringWithFormat(const std::string& key, const std::string& v
return u8fmt(_TSTR(key), value.c_str());
}
static std::shared_ptr<TrackList> queryTracksByCategory(
ILibraryPtr library,
const std::string& categoryType,
const std::string& categoryValue,
int64_t categoryId)
{
/* ShowAddDirectoryOverlay() calls through to ShowAddCategoryOverlay() with a
special `fieldColumn` called `kDirectoryFieldColumn`. If we detect this case
we'll run a special query for directory path matching */
std::shared_ptr<TrackListQueryBase> query;
if (categoryType == MagicConstants::DirectoryCategoryType) {
query = std::make_shared<DirectoryTrackListQuery>(library, categoryValue);
}
else {
query = std::make_shared<CategoryTrackListQuery>(library, categoryType, categoryId);
}
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
return query->GetResult();
}
return std::shared_ptr<TrackList>();
}
static std::shared_ptr<CategoryListQuery> queryPlaylists(ILibraryPtr library) {
std::shared_ptr<CategoryListQuery> query(
new CategoryListQuery(Playlists::TABLE_NAME, ""));
@ -209,30 +236,6 @@ static void createNewPlaylist(
cursespp::App::Overlays().Push(dialog);
}
static void createNewPlaylist(
IMessageQueue& queue,
ILibraryPtr library,
const std::string& categoryType,
int64_t categoryId)
{
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
dialog->SetTitle(_TSTR("playqueue_overlay_playlist_name_title"))
.SetWidth(_DIMEN("playqueue_playlist_name_overlay_width", DEFAULT_OVERLAY_WIDTH))
.SetText("")
.SetInputAcceptedCallback(
[&queue, library, categoryType, categoryId](const std::string& name) {
if (name.size()) {
auto query = SavePlaylistQuery::Save(library, name, categoryType, categoryId);
library->Enqueue(query, ILibrary::QuerySynchronous, [](auto query) {
setLastPlaylistId(std::static_pointer_cast<SavePlaylistQuery>(query)->GetPlaylistId());
});
}
});
cursespp::App::Overlays().Push(dialog);
}
void PlayQueueOverlays::ShowRenamePlaylistOverlay(
ILibraryPtr library,
const int64_t playlistId,
@ -295,17 +298,14 @@ static void handleAddCategorySelectionToPlayQueue(
PlaybackService& playback,
ILibraryPtr library,
const std::string& fieldColumn,
const std::string& fieldValue,
int64_t fieldId,
size_t type)
{
std::shared_ptr<CategoryTrackListQuery> query(
new CategoryTrackListQuery(library, fieldColumn, fieldId));
auto tracks = queryTracksByCategory(library, fieldColumn, fieldValue, fieldId);
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
if (tracks) {
auto editor = playback.Edit();
auto tracks = query->GetResult();
size_t position = playback.GetIndex();
if (type == 0) { /* start */
@ -355,6 +355,7 @@ static void showAddCategorySelectionToPlaylistOverlay(
IMessageQueue& queue,
ILibraryPtr library,
const std::string& categoryType,
const std::string& categoryValue,
int64_t categoryId)
{
std::shared_ptr<CategoryListQuery> query = queryPlaylists(library);
@ -376,20 +377,19 @@ static void showAddCategorySelectionToPlaylistOverlay(
showPlaylistListOverlay(
_TSTR("playqueue_overlay_select_playlist_title"),
adapter,
[&queue, library, categoryType, categoryId, result]
[&queue, library, categoryType, categoryValue, categoryId, result]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
if (index != ListWindow::NO_SELECTION) {
if (index == 0) { /* new playlist */
createNewPlaylist(queue, library, categoryType, categoryId);
}
else { /* add to existing */
int64_t playlistId = (*result)[index - 1]->GetId();
setLastPlaylistId(playlistId);
auto query = SavePlaylistQuery::Append(
library, playlistId, categoryType, categoryId);
library->Enqueue(query, 0);
auto tracks = queryTracksByCategory(library, categoryType, categoryValue, categoryId);
if (tracks) {
if (index == 0) { /* new playlist */
createNewPlaylist(queue, tracks, library);
}
else { /* add to existing */
int64_t playlistId = (*result)[index - 1]->GetId();
setLastPlaylistId(playlistId);
library->Enqueue(SavePlaylistQuery::Append(library, playlistId, tracks));
}
}
}
},
@ -530,7 +530,7 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
.SetWidth(_DIMEN("playqueue_playlist_add_to_queue_overlay_width", DEFAULT_OVERLAY_WIDTH))
.SetSelectedIndex(selectedIndex)
.SetItemSelectedCallback(
[&playback, &messageQueue, library, fieldColumn, fieldId]
[&playback, &messageQueue, library, fieldColumn, fieldValue, fieldId]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
if (index == ListWindow::NO_SELECTION) {
return;
@ -540,17 +540,32 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
if (index == 0) {
showAddCategorySelectionToPlaylistOverlay(
messageQueue, library, fieldColumn, fieldId);
messageQueue, library, fieldColumn, fieldValue, fieldId);
}
else {
handleAddCategorySelectionToPlayQueue(
playback, library, fieldColumn, fieldId, index - 1);
playback, library, fieldColumn, fieldValue, fieldId, index - 1);
}
});
cursespp::App::Overlays().Push(dialog);
}
void PlayQueueOverlays::ShowAddDirectoryOverlay(
musik::core::runtime::IMessageQueue& messageQueue,
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
const std::string& directory)
{
ShowAddCategoryOverlay(
messageQueue,
playback,
library,
MagicConstants::DirectoryCategoryType,
directory,
-1LL);
}
void PlayQueueOverlays::ShowAlbumDividerOverlay(
IMessageQueue& messageQueue, PlaybackService& playback, ILibraryPtr library, TrackPtr firstTrack)
{
@ -598,12 +613,12 @@ void PlayQueueOverlays::ShowAlbumDividerOverlay(
/* add to playlist */
else if (index == 4) {
showAddCategorySelectionToPlaylistOverlay(
messageQueue, library, albumColumn, albumId);
messageQueue, library, albumColumn, "", albumId);
}
/* the other are our standard play queue operations */
else {
handleAddCategorySelectionToPlayQueue(
playback, library, albumColumn, albumId, index - 5);
playback, library, albumColumn, "", albumId, index - 5);
}
});

View File

@ -60,6 +60,12 @@ namespace musik {
const std::string& fieldValue,
int64_t fieldId);
static void ShowAddDirectoryOverlay(
musik::core::runtime::IMessageQueue& messageQueue,
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
const std::string& directory);
static void ShowAlbumDividerOverlay(
musik::core::runtime::IMessageQueue& messageQueue,
musik::core::audio::PlaybackService& playback,

View File

@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#include <stdafx.h>
#include "MagicConstants.h"
using namespace musik::cube;
namespace musik { namespace cube {
const std::string MagicConstants::DirectoryCategoryType = "__DirectoryCategoryType__";
} }

View File

@ -0,0 +1,55 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
namespace musik { namespace cube {
/**
* MagicConstants is used to house shared constants that are typically used as markers
* to glue together otherwise disjoint features that may make sense to interoperate in
* and integrate in the UI layer. One example of this: present directory browsing as
* a category type, even though it's a category in the database.
*
* We should strive for magic constants to be empty, but in some cases doing serious
* refactors of subsystems is prohibitively expensive and would not gain much.
*/
struct MagicConstants {
static const std::string DirectoryCategoryType;
private: MagicConstants(){}
};
} }

View File

@ -304,6 +304,14 @@ static size_t writePlayingFormat(
}
}
/* any % in the value string might be parsed by wprintw, so replace it */
std::size_t percentSignIndex = value.find("%");
while (percentSignIndex != std::string::npos) {
value.replace(percentSignIndex, 1, "%%");
/* we replaced one % with 2 of them, so we need to skip ahead 2 chars */
percentSignIndex = value.find("%", percentSignIndex + 2);
}
ON(w, attr);
checked_wprintw(w, value.c_str());
OFF(w, attr);
@ -737,4 +745,4 @@ void TransportWindow::Update(TimeMode timeMode) {
OFF(c, repeatAttrs);
this->Invalidate();
}
}

View File

@ -77,19 +77,38 @@ static void resizedHandler(int signal) {
resizeAt = App::Now() + REDRAW_DEBOUNCE_MS;
}
static bool isLangUtf8() {
const char* lang = std::getenv("LANG");
static std::string getEnvironmentVariable(const std::string& name) {
std::string result;
const char* value = std::getenv(name.c_str());
if (value) {
result = value;
}
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
if (!lang) {
return false;
static bool containsUtf8(const std::string& value) {
return
value.find("utf-8") != std::string::npos ||
value.find("utf8") != std::string::npos;
}
static bool isLangUtf8() {
/* https://github.com/clangen/musikcube/issues/324 */
std::string lcAll = getEnvironmentVariable("LC_ALL");
std::string lcCType = getEnvironmentVariable("LC_CTYPE");
std::string lang = getEnvironmentVariable("LANG");
if (lcAll.size()) {
return containsUtf8(lcAll);
}
std::string str = std::string(lang);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (lcCType.size()) {
return containsUtf8(lcCType);
}
return
str.find("utf-8") != std::string::npos ||
str.find("utf8") != std::string::npos;
return containsUtf8(lang);
}
#endif

View File

@ -67,6 +67,7 @@ bool sortByFocusOrder(IWindowPtr a, IWindowPtr b) {
LayoutBase::LayoutBase(IWindow* parent)
: Window(parent)
, focused(0)
, focusMode(FocusModeCircular) {
this->SetFrameVisible(false);
}

View File

@ -298,7 +298,22 @@ namespace cursespp {
{ "M-KEY_UP", "M-up" },
{ "M-KEY_DOWN", "M-down" },
{ "kUP5", "CTL_UP" },
{ "kDN5", "CTL_DOWN" }
{ "kDN5", "CTL_DOWN" },
#ifdef PDCURSES_WINCON
/* special bindings for the "Windows Terminal" app */
{ "KEY_A2", "KEY_UP" },
{ "KEY_C2", "KEY_DOWN" },
{ "KEY_B3", "KEY_RIGHT" },
{ "KEY_B1", "KEY_LEFT" },
{ "KEY_A3", "KEY_PPAGE" },
{ "KEY_C3", "KEY_NPAGE" },
{ "KEY_A1", "KEY_HOME" },
{ "KEY_C1", "KEY_END" },
{ "CTL_PAD4", "CTL_LEFT" },
{ "CTL_PAD6", "CTL_RIGHT" },
{ "CTL_PAD8", "CTL_UP" },
{ "CTL_PAD9", "CTL_DOWN" },
#endif
};
std::string Normalize(const std::string& kn) {

View File

@ -802,6 +802,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win\font\*.ttf" "$(TargetDir)fonts\" /Y /e
<ClCompile Include="app\util\ConsoleLogger.cpp" />
<ClCompile Include="app\util\GlobalHotkeys.cpp" />
<ClCompile Include="app\util\Hotkeys.cpp" />
<ClCompile Include="app\util\MagicConstants.cpp" />
<ClCompile Include="app\util\Playback.cpp" />
<ClCompile Include="app\util\PreferenceKeys.cpp" />
<ClCompile Include="app\util\Rating.cpp" />
@ -883,6 +884,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win\font\*.ttf" "$(TargetDir)fonts\" /Y /e
<ClInclude Include="app\util\ConsoleLogger.h" />
<ClInclude Include="app\util\GlobalHotkeys.h" />
<ClInclude Include="app\util\Hotkeys.h" />
<ClInclude Include="app\util\MagicConstants.h" />
<ClInclude Include="app\util\Messages.h" />
<ClInclude Include="app\util\Playback.h" />
<ClInclude Include="app\util\PreferenceKeys.h" />

View File

@ -192,6 +192,9 @@
<ClCompile Include="app\util\Rating.cpp">
<Filter>app\util</Filter>
</ClCompile>
<ClCompile Include="app\util\MagicConstants.cpp">
<Filter>app\util</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
@ -439,6 +442,9 @@
<ClInclude Include="app\util\Rating.h">
<Filter>app\util</Filter>
</ClInclude>
<ClInclude Include="app\util\MagicConstants.h">
<Filter>app\util</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="cursespp">

View File

@ -27,7 +27,8 @@ using namespace musik::core;
using namespace musik::core::audio;
using namespace musik::core::runtime;
static const char* LOCKFILE = "/tmp/musikcubed.lock";
static const char* DEFAULT_LOCKFILE = "/tmp/musikcubed.lock";
static const char* LOCKFILE_OVERRIDE = "MUSIKCUBED_LOCKFILE_OVERRIDE";
static const short EVENT_DISPATCH = 1;
static const short EVENT_QUIT = 2;
static const pid_t NOT_RUNNING = (pid_t) -1;
@ -145,6 +146,15 @@ static void handleCommandLine(int argc, char** argv) {
}
}
static std::string getLockfileFn() {
std::string result = DEFAULT_LOCKFILE;
const char* userLock = std::getenv(LOCKFILE_OVERRIDE);
if (userLock && strlen(userLock)) {
result = userLock;
}
return result;
}
static void stopDaemon() {
pid_t pid = getDaemonPid();
if (pid == NOT_RUNNING) {
@ -173,7 +183,7 @@ static void stopDaemon() {
}
static pid_t getDaemonPid() {
std::ifstream lock(LOCKFILE);
std::ifstream lock(getLockfileFn());
if (lock.good()) {
int pid;
lock >> pid;
@ -223,7 +233,7 @@ static void initDaemon() {
close(STDOUT_FILENO);
freopen("/tmp/musikcube.log", "w", stderr);
std::ofstream lock(LOCKFILE);
std::ofstream lock(getLockfileFn());
if (lock.good()) {
lock << std::to_string((int) getpid());
}
@ -239,7 +249,7 @@ static void initForeground() {
exit(EXIT_FAILURE);
}
std::ofstream lock(LOCKFILE);
std::ofstream lock(getLockfileFn());
if (lock.good()) {
lock << std::to_string((int) getpid());
}
@ -258,6 +268,7 @@ static void initUtf8() {
int main(int argc, char** argv) {
initUtf8();
std::cout << "\n using lockfile at: " << getLockfileFn();
handleCommandLine(argc, argv);
exitIfRunning();
@ -286,5 +297,5 @@ int main(int argc, char** argv) {
plugin::Deinit();
remove(LOCKFILE);
remove(getLockfileFn().c_str());
}

View File

@ -134,6 +134,7 @@ FfmpegDecoder::FfmpegDecoder() {
this->resampler = nullptr;
this->bufferSize = AV_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
this->buffer = new unsigned char[this->bufferSize];
this->outputFifo = nullptr;
}
FfmpegDecoder::~FfmpegDecoder() {