Added "minimize to tray" and "start minimized" to platforms that support

this functionality (currently only win32).
This commit is contained in:
casey langen 2017-05-27 13:55:12 -07:00
parent 025ad8825f
commit 2c6dcb907f
11 changed files with 175 additions and 19 deletions

View File

@ -170,6 +170,12 @@ int main(int argc, char* argv[]) {
app.SetColorTheme(colorTheme);
}
/* tray icon options */
app.SetMinimizeToTray(prefs->GetBool(musik::box::prefs::keys::MinimizeToTray, false));
if (prefs->GetBool(musik::box::prefs::keys::StartMinimized, false)) {
app.Minimize();
}
app.SetMinimumSize(MIN_WIDTH, MIN_HEIGHT);
using Layout = std::shared_ptr<LayoutBase>;
@ -177,7 +183,7 @@ int main(int argc, char* argv[]) {
Layout libraryLayout(new LibraryLayout(playback, library));
Layout consoleLayout(new ConsoleLayout(transport, library));
Layout settingsLayout(new SettingsLayout(library, playback, transport));
Layout settingsLayout(new SettingsLayout(app, library, playback, transport));
Main mainLayout(new MainLayout(library));

View File

@ -71,6 +71,10 @@ using namespace std::placeholders;
#define ENABLE_256_COLOR_OPTION
#endif
#ifdef WIN32
#define ENABLE_MINIMIZE_TO_TRAY
#endif
#define LABEL_HEIGHT 1
#define INPUT_HEIGHT 3
#define HOTKEY_INPUT_WIDTH 20
@ -91,15 +95,17 @@ static const std::string arrow = "\xe2\x96\xba ";
static bool showDotfiles = false;
SettingsLayout::SettingsLayout(
cursespp::App& app,
musik::core::ILibraryPtr library,
musik::core::sdk::IPlaybackService& playback,
musik::glue::audio::MasterTransport& transport)
: LayoutBase()
, library(library)
, indexer(library->Indexer())
, transport(transport)
, playback(playback)
, pathsUpdated(false) {
: LayoutBase()
, app(app)
, library(library)
, indexer(library->Indexer())
, transport(transport)
, playback(playback)
, pathsUpdated(false) {
this->prefs = Preferences::ForComponent(core::prefs::components::Settings);
this->browseAdapter.reset(new DirectoryAdapter());
this->addedPathsAdapter.reset(new SimpleScrollAdapter());
@ -125,7 +131,7 @@ void SettingsLayout::OnCheckboxChanged(cursespp::Checkbox* cb, bool checked) {
}
else if (cb == seekScrubCheckbox.get()) {
TimeChangeMode mode = cb->IsChecked() ? TimeChangeSeek : TimeChangeScrub;
this->prefs->SetInt(core::prefs::keys::TimeChangeMode, (int) mode);
this->prefs->SetInt(core::prefs::keys::TimeChangeMode, (int)mode);
this->seekScrubCheckbox->SetChecked(this->prefs->GetInt(core::prefs::keys::TimeChangeMode) == (int)TimeChangeSeek);
this->playback.SetTimeChangeMode(mode);
}
@ -134,8 +140,17 @@ void SettingsLayout::OnCheckboxChanged(cursespp::Checkbox* cb, bool checked) {
ColorThemeOverlay::Show256ColorsInfo(
checked,
[this]() {
this->LoadPreferences();
});
this->LoadPreferences();
});
}
#endif
#ifdef ENABLE_MINIMIZE_TO_TRAY
else if (cb == minimizeToTrayCheckbox.get()) {
app.SetMinimizeToTray(checked);
this->prefs->SetBool(box::prefs::keys::MinimizeToTray, checked);
}
else if (cb == startMinimizedCheckbox.get()) {
this->prefs->SetBool(box::prefs::keys::StartMinimized, checked);
}
#endif
}
@ -231,6 +246,10 @@ void SettingsLayout::OnLayout() {
this->syncOnStartupCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
this->removeCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
this->seekScrubCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
#ifdef ENABLE_MINIMIZE_TO_TRAY
this->minimizeToTrayCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
this->startMinimizedCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
#endif
}
void SettingsLayout::RefreshAddedPaths() {
@ -305,9 +324,6 @@ void SettingsLayout::InitializeWindows() {
this->themeDropdown.reset(new TextLabel());
this->themeDropdown->SetText(arrow + _TSTR("settings_color_theme") + _TSTR("settings_default_theme_name"));
this->themeDropdown->Activated.connect(this, &SettingsLayout::OnThemeDropdownActivate);
#ifdef ENABLE_256_COLOR_OPTION
CREATE_CHECKBOX(this->paletteCheckbox, _TSTR("settings_degrade_256"));
#endif
this->hotkeyDropdown.reset(new TextLabel());
this->hotkeyDropdown->SetText(arrow + _TSTR("settings_hotkey_tester"));
@ -318,6 +334,14 @@ void SettingsLayout::InitializeWindows() {
CREATE_CHECKBOX(this->removeCheckbox, _TSTR("settings_remove_missing"));
CREATE_CHECKBOX(this->seekScrubCheckbox, _TSTR("settings_seek_not_scrub"));
#ifdef ENABLE_256_COLOR_OPTION
CREATE_CHECKBOX(this->paletteCheckbox, _TSTR("settings_degrade_256"));
#endif
#ifdef ENABLE_MINIMIZE_TO_TRAY
CREATE_CHECKBOX(this->minimizeToTrayCheckbox, _TSTR("settings_minimize_to_tray"));
CREATE_CHECKBOX(this->startMinimizedCheckbox, _TSTR("settings_start_minimized"));
#endif
int order = 0;
this->browseList->SetFocusOrder(order++);
this->addedPathsList->SetFocusOrder(order++);
@ -334,6 +358,10 @@ void SettingsLayout::InitializeWindows() {
this->syncOnStartupCheckbox->SetFocusOrder(order++);
this->removeCheckbox->SetFocusOrder(order++);
this->seekScrubCheckbox->SetFocusOrder(order++);
#ifdef ENABLE_MINIMIZE_TO_TRAY
this->minimizeToTrayCheckbox->SetFocusOrder(order++);
this->startMinimizedCheckbox->SetFocusOrder(order++);
#endif
this->AddWindow(this->browseLabel);
this->AddWindow(this->addedPathsLabel);
@ -352,6 +380,10 @@ void SettingsLayout::InitializeWindows() {
this->AddWindow(this->syncOnStartupCheckbox);
this->AddWindow(this->removeCheckbox);
this->AddWindow(this->seekScrubCheckbox);
#ifdef ENABLE_MINIMIZE_TO_TRAY
this->AddWindow(this->minimizeToTrayCheckbox);
this->AddWindow(this->startMinimizedCheckbox);
#endif
}
void SettingsLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) {
@ -435,11 +467,15 @@ void SettingsLayout::LoadPreferences() {
#ifdef ENABLE_256_COLOR_OPTION
this->paletteCheckbox->CheckChanged.disconnect(this);
this->paletteCheckbox->SetChecked(
this->prefs->GetBool(box::prefs::keys::UsePaletteColors, true));
this->paletteCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::UsePaletteColors, true));
this->paletteCheckbox->CheckChanged.connect(this, &SettingsLayout::OnCheckboxChanged);
#endif
#ifdef ENABLE_MINIMIZE_TO_TRAY
this->minimizeToTrayCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::MinimizeToTray, false));
this->startMinimizedCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::StartMinimized, false));
#endif
/* output plugin */
std::shared_ptr<IOutput> output = outputs::SelectedOutput();
if (output) {

View File

@ -34,6 +34,7 @@
#pragma once
#include <cursespp/App.h>
#include <cursespp/Checkbox.h>
#include <cursespp/LayoutBase.h>
#include <cursespp/ListWindow.h>
@ -68,6 +69,7 @@ namespace musik {
{
public:
SettingsLayout(
cursespp::App& app,
musik::core::ILibraryPtr library,
musik::core::sdk::IPlaybackService& playback,
musik::glue::audio::MasterTransport& transport);
@ -108,6 +110,7 @@ namespace musik {
size_t line,
cursespp::IScrollAdapter::EntryPtr entry);
cursespp::App& app;
musik::core::ILibraryPtr library;
musik::core::IIndexer* indexer;
musik::core::sdk::IPlaybackService& playback;
@ -128,6 +131,8 @@ namespace musik {
std::shared_ptr<cursespp::Checkbox> syncOnStartupCheckbox;
std::shared_ptr<cursespp::Checkbox> removeCheckbox;
std::shared_ptr<cursespp::Checkbox> seekScrubCheckbox;
std::shared_ptr<cursespp::Checkbox> minimizeToTrayCheckbox;
std::shared_ptr<cursespp::Checkbox> startMinimizedCheckbox;
std::shared_ptr<cursespp::TextLabel> browseLabel;
std::shared_ptr<cursespp::TextLabel> addedPathsLabel;

View File

@ -41,6 +41,8 @@ namespace musik { namespace box { namespace prefs {
const std::string keys::UsePaletteColors = "UsePaletteColors";
const std::string keys::FirstRunSettingsDisplayed = "FirstRunSettingsDisplayed";
const std::string keys::ColorTheme = "ColorTheme";
const std::string keys::MinimizeToTray = "MinimizeToTray";
const std::string keys::StartMinimized = "StartMinimized";
} } }

View File

@ -43,6 +43,8 @@ namespace musik { namespace box { namespace prefs {
extern const std::string UsePaletteColors;
extern const std::string FirstRunSettingsDisplayed;
extern const std::string ColorTheme;
extern const std::string MinimizeToTray;
extern const std::string StartMinimized;
}
} } }

View File

@ -100,6 +100,8 @@ App::App(const std::string& title) {
#ifdef __PDCURSES__
PDC_set_title(title.c_str());
win32::InterceptWndProc();
win32::SetAppTitle(title);
#endif
}
@ -137,6 +139,24 @@ void App::SetIcon(int resourceId) {
}
#endif
void App::SetMinimizeToTray(bool minimizeToTray) {
#ifdef WIN32
win32::SetMinimizeToTray(minimizeToTray);
#endif
}
void App::Minimize() {
#ifdef WIN32
win32::Minimize();
#endif
}
void App::Restore() {
#ifdef WIN32
win32::ShowMainWindow();
#endif
}
void App::OnResized() {
int cx = Screen::GetWidth();
int cy = Screen::GetHeight();

View File

@ -56,6 +56,9 @@ namespace cursespp {
void SetColorTheme(const std::string& fn);
void SetMinimumSize(int width, int height);
bool IsOverlayVisible() { return this->state.overlay != nullptr; }
void SetMinimizeToTray(bool minimizeToTray);
void Minimize();
void Restore();
#ifdef WIN32
void SetIcon(int resourceId);

View File

@ -36,11 +36,20 @@
#include "stdafx.h"
#include <Windows.h>
#include <Commctrl.h>
#include <shellapi.h>
#ifdef WIN32
#define WM_TRAYICON (WM_USER + 2000)
static std::basic_string<TCHAR> className = L"Curses_App";
static HWND mainWindow = nullptr;
static WNDPROC oldWndProc = nullptr;
static std::unique_ptr<NOTIFYICONDATA> trayIcon;
static bool minimizeToTray = false, minimizedToTray = false;
static std::string appTitle;
static HICON icon16 = nullptr, icon32 = nullptr;
static void findMainWindow() {
static TCHAR buffer[256];
@ -73,6 +82,51 @@ static HICON loadIcon(int resourceId, int size) {
0);
}
static void initTrayIcon(HWND hwnd) {
if (!trayIcon) {
trayIcon.reset(new NOTIFYICONDATA());
SecureZeroMemory(trayIcon.get(), sizeof(*trayIcon));
trayIcon->hWnd = hwnd;
trayIcon->uID = 0;
trayIcon->uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
trayIcon->uCallbackMessage = WM_TRAYICON;
trayIcon->hIcon = icon16;
std::wstring title = u8to16(appTitle);
::wcscpy_s(trayIcon->szTip, 255, title.c_str());
}
}
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id, DWORD_PTR data) {
if (minimizeToTray) {
if ((msg == WM_SIZE && wparam == SIZE_MINIMIZED) ||
(msg == WM_SYSCOMMAND && wparam == SC_MINIMIZE))
{
if (!minimizedToTray) {
initTrayIcon(hwnd);
minimizedToTray = (Shell_NotifyIcon(NIM_ADD, trayIcon.get()) != 0);
if (minimizedToTray) {
ShowWindow(hwnd, SW_HIDE);
trayIcon->uVersion = NOTIFYICON_VERSION;
::Shell_NotifyIcon(NIM_SETVERSION, trayIcon.get());
return 1;
}
}
}
}
if (msg == WM_TRAYICON) {
if (LOWORD(lparam) == WM_LBUTTONUP) {
Shell_NotifyIcon(NIM_DELETE, trayIcon.get());
minimizedToTray = false;
ShowWindow(hwnd, SW_SHOWNORMAL);
return 1;
}
}
return DefSubclassProc(hwnd, msg, wparam, lparam);
}
namespace cursespp {
namespace win32 {
void ShowMainWindow() {
@ -89,6 +143,13 @@ namespace cursespp {
}
}
void Minimize() {
findMainWindow();
if (mainWindow) {
ShowWindow(mainWindow, SW_SHOWMINIMIZED);
}
}
HWND GetMainWindow() {
findMainWindow();
return mainWindow;
@ -96,11 +157,26 @@ namespace cursespp {
void SetIcon(int resourceId) {
const HWND hwnd = GetMainWindow();
const HICON icon16 = loadIcon(resourceId, 16);
const HICON icon32 = loadIcon(resourceId, 48);
icon16 = loadIcon(resourceId, 16);
icon32 = loadIcon(resourceId, 48);
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) icon16);
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) icon32);
}
void InterceptWndProc() {
HWND hwnd = GetMainWindow();
if (hwnd) {
SetWindowSubclass(hwnd, wndProc, 1001, 0);
}
}
void SetMinimizeToTray(bool enabled) {
minimizeToTray = enabled;
}
void SetAppTitle(const std::string& title) {
appTitle = title;
}
}
}

View File

@ -40,10 +40,14 @@
namespace cursespp {
namespace win32 {
void InterceptWndProc();
void ShowMainWindow();
void HideMainWindow();
void Minimize();
HWND GetMainWindow();
void SetIcon(int resourceId);
void SetAppTitle(const std::string& title);
void SetMinimizeToTray(bool enabled);
}
}

View File

@ -34,6 +34,8 @@
"settings_needs_restart": "you will need to restart musikbox for this change to take effect.",
"settings_selected_locale": "locale: ",
"settings_seek_not_scrub": "seek playback (don't scrub)",
"settings_minimize_to_tray": "minimize to tray",
"settings_start_minimized": "start minimized",
"locale_overlay_select_title": "select locale",

View File

@ -81,7 +81,7 @@
<ImportLibrary>
</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>pdh.lib;psapi.lib;Ws2_32.lib;wldap32.lib;libcurl.lib;crypto-41.lib;ssl-43.lib;tls-15.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>pdh.lib;psapi.lib;Ws2_32.lib;wldap32.lib;Comctl32.lib;libcurl.lib;crypto-41.lib;ssl-43.lib;tls-15.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
<PostBuildEvent>
@ -122,7 +122,7 @@ xcopy "$(SolutionDir)src\plugins\websocket_remote\3rdparty\win32_bin\$(Configura
<ImportLibrary>
</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>pdh.lib;psapi.lib;Ws2_32.lib;wldap32.lib;libcurl.lib;crypto-41.lib;ssl-43.lib;tls-15.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>pdh.lib;psapi.lib;Ws2_32.lib;wldap32.lib;Comctl32.lib;libcurl.lib;crypto-41.lib;ssl-43.lib;tls-15.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>true</ImageHasSafeExceptionHandlers>
</Link>
<PostBuildEvent>