Show dark logo in dark mode and improve .env loader (#7434)
* Update fingerprint on load * Update TLS controls enabled * Use official Qt way to detect dark mode and clean up dead code * Add missing includes * Simplify dark mode code * Check app config dir for .env * Use app config dir for .env * Don't check for existence of file * Resolve orgDir * Add missing example env * Fixed example * Update ChangeLog
|
|
@ -9,6 +9,9 @@
|
||||||
# Serial key value to pre-fill the activation dialog
|
# Serial key value to pre-fill the activation dialog
|
||||||
# SYNERGY_TEST_SERIAL_KEY="DEADBEEF"
|
# SYNERGY_TEST_SERIAL_KEY="DEADBEEF"
|
||||||
|
|
||||||
|
# Shows the test menu in the GUI (on by default in debug mode)
|
||||||
|
# SYNERGY_TEST_MENU=true
|
||||||
|
|
||||||
# Version checker URL to use (useful for testing)
|
# Version checker URL to use (useful for testing)
|
||||||
# SYNERGY_VERSION_URL="http://localhost:8787?version=v1"
|
# SYNERGY_VERSION_URL="http://localhost:8787?version=v1"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ Enhancements:
|
||||||
- #7430 Improve setting enable logic and test coverage
|
- #7430 Improve setting enable logic and test coverage
|
||||||
- #7431 Improve handling of Qt-related warnings and errors
|
- #7431 Improve handling of Qt-related warnings and errors
|
||||||
- #7432 Only show close to tray reminder when not quitting the app
|
- #7432 Only show close to tray reminder when not quitting the app
|
||||||
|
- #7434 Show dark logo in dark mode and improve .env loader
|
||||||
|
|
||||||
# 1.14.6
|
# 1.14.6
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,17 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/res">
|
<qresource prefix="/res">
|
||||||
<file>icons/16x16/synergy-connected.png</file>
|
<file>icons/16x16/synergy.png</file>
|
||||||
<file>icons/16x16/synergy-disconnected.png</file>
|
|
||||||
<file>icons/64x64/video-display.png</file>
|
<file>icons/64x64/video-display.png</file>
|
||||||
<file>icons/64x64/user-trash.png</file>
|
<file>icons/64x64/user-trash.png</file>
|
||||||
<file>icons/16x16/warning.png</file>
|
<file>icons/16x16/warning.png</file>
|
||||||
<file>icons/256x256/synergy.ico</file>
|
<file>icons/256x256/synergy.ico</file>
|
||||||
<file>image/about.png</file>
|
<file>image/about-light.png</file>
|
||||||
<file>image/about-dark.png</file>
|
<file>image/about-dark.png</file>
|
||||||
<file>image/spinning-wheel.gif</file>
|
|
||||||
<file>icons/16x16/padlock.png</file>
|
<file>icons/16x16/padlock.png</file>
|
||||||
<file>icons/16x16/synergy-transfering.png</file>
|
<file>icons/64x64/synergy-dark.png</file>
|
||||||
<file>icons/64x64/synergy-dark-transfering.png</file>
|
<file>icons/64x64/synergy-light.png</file>
|
||||||
<file>icons/64x64/synergy-dark-disconnected.png</file>
|
|
||||||
<file>icons/64x64/synergy-dark-connected.png</file>
|
|
||||||
<file>icons/64x64/synergy-light-transfering.png</file>
|
|
||||||
<file>icons/64x64/synergy-light-disconnected.png</file>
|
|
||||||
<file>icons/64x64/synergy-light-connected.png</file>
|
|
||||||
<file>image/welcome.png</file>
|
<file>image/welcome.png</file>
|
||||||
<file>icons/64x64/folder.png</file>
|
<file>icons/64x64/folder.png</file>
|
||||||
<file>fonts/Arial.ttf</file>
|
<file>image/setup-blocker.png</file>
|
||||||
<file>image/setupBlocker.png</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 905 B |
|
Before Width: | Height: | Size: 905 B |
|
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 905 B |
|
Before Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
|
@ -17,15 +17,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AboutDialog.h"
|
#include "AboutDialog.h"
|
||||||
|
|
||||||
#include "common/copyright.h"
|
#include "common/copyright.h"
|
||||||
|
#include "common/version.h"
|
||||||
|
#include "gui/style_utils.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <qguiapplication.h>
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
using namespace synergy::gui;
|
||||||
#include "gui/OSXHelpers.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common/version.h"
|
|
||||||
|
|
||||||
AboutDialog::AboutDialog(MainWindow *parent)
|
AboutDialog::AboutDialog(MainWindow *parent)
|
||||||
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||||
|
|
@ -53,14 +53,15 @@ int AboutDialog::exec() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AboutDialog::updateLogo() const {
|
void AboutDialog::updateLogo() const {
|
||||||
#if defined(Q_OS_MAC)
|
if (isDarkMode()) {
|
||||||
if (isOSXInterfaceStyleDark()) {
|
qDebug("dark mode detected, showing dark logo");
|
||||||
QPixmap logo(":/res/image/about-dark.png");
|
QPixmap logo(":/res/image/about-dark.png");
|
||||||
if (!logo.isNull()) {
|
if (!logo.isNull()) {
|
||||||
m_pLabel_Logo->setPixmap(logo);
|
m_pLabel_Logo->setPixmap(logo);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qDebug("light mode detected, keeping light logo");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AboutDialog::importantDevelopers() const {
|
QString AboutDialog::importantDevelopers() const {
|
||||||
|
|
|
||||||
|
|
@ -65,30 +65,12 @@ using CoreMode = CoreProcess::Mode;
|
||||||
using CoreConnectionState = CoreProcess::ConnectionState;
|
using CoreConnectionState = CoreProcess::ConnectionState;
|
||||||
using CoreProcessState = CoreProcess::ProcessState;
|
using CoreProcessState = CoreProcess::ProcessState;
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
const auto kIconFile16 = ":/res/icons/16x16/synergy.png";
|
||||||
|
|
||||||
static const char *const kLightIconFiles[] = {
|
#ifdef Q_OS_MAC
|
||||||
":/res/icons/64x64/synergy-light-disconnected.png",
|
const auto kLightIconFile = ":/res/icons/64x64/synergy-light.png";
|
||||||
":/res/icons/64x64/synergy-light-disconnected.png",
|
const auto kDarkIconFile = ":/res/icons/64x64/synergy-dark.png";
|
||||||
":/res/icons/64x64/synergy-light-connected.png",
|
#endif // Q_OS_MAC
|
||||||
":/res/icons/64x64/synergy-light-transfering.png",
|
|
||||||
":/res/icons/64x64/synergy-light-disconnected.png"};
|
|
||||||
|
|
||||||
static const char *const kDarkIconFiles[] = {
|
|
||||||
":/res/icons/64x64/synergy-dark-disconnected.png",
|
|
||||||
":/res/icons/64x64/synergy-dark-disconnected.png",
|
|
||||||
":/res/icons/64x64/synergy-dark-connected.png",
|
|
||||||
":/res/icons/64x64/synergy-dark-transfering.png",
|
|
||||||
":/res/icons/64x64/synergy-dark-disconnected.png"};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *const kDefaultIconFiles[] = {
|
|
||||||
":/res/icons/16x16/synergy-disconnected.png",
|
|
||||||
":/res/icons/16x16/synergy-disconnected.png",
|
|
||||||
":/res/icons/16x16/synergy-connected.png",
|
|
||||||
":/res/icons/16x16/synergy-transfering.png",
|
|
||||||
":/res/icons/16x16/synergy-disconnected.png"};
|
|
||||||
|
|
||||||
MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||||
: m_ConfigScopes(configScopes),
|
: m_ConfigScopes(configScopes),
|
||||||
|
|
@ -164,6 +146,7 @@ void MainWindow::setupControls() {
|
||||||
|
|
||||||
createMenuBar();
|
createMenuBar();
|
||||||
secureSocket(false);
|
secureSocket(false);
|
||||||
|
updateLocalFingerprint();
|
||||||
|
|
||||||
m_pLabelUpdate->setStyleSheet(kStyleNoticeLabel);
|
m_pLabelUpdate->setStyleSheet(kStyleNoticeLabel);
|
||||||
m_pLabelUpdate->hide();
|
m_pLabelUpdate->hide();
|
||||||
|
|
@ -262,7 +245,7 @@ void MainWindow::connectSlots() {
|
||||||
connect(m_pActionQuit, &QAction::triggered, qApp, [this] {
|
connect(m_pActionQuit, &QAction::triggered, qApp, [this] {
|
||||||
qDebug("quitting application");
|
qDebug("quitting application");
|
||||||
m_Quitting = true;
|
m_Quitting = true;
|
||||||
qApp->quit();
|
QApplication::quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -294,7 +277,7 @@ void MainWindow::onAppAboutToQuit() { m_ConfigScopes.save(); }
|
||||||
|
|
||||||
void MainWindow::onCreated() {
|
void MainWindow::onCreated() {
|
||||||
|
|
||||||
setIcon(CoreConnectionState::Disconnected);
|
setIcon();
|
||||||
|
|
||||||
m_ConfigScopes.signalReady();
|
m_ConfigScopes.signalReady();
|
||||||
|
|
||||||
|
|
@ -655,26 +638,24 @@ void MainWindow::saveSettings() {
|
||||||
m_ConfigScopes.save();
|
m_ConfigScopes.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setIcon(CoreConnectionState state) {
|
void MainWindow::setIcon() {
|
||||||
QIcon icon;
|
QIcon icon;
|
||||||
auto index = static_cast<int>(state);
|
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
switch (getOSXIconsTheme()) {
|
switch (getOSXIconsTheme()) {
|
||||||
case IconsTheme::ICONS_DARK:
|
case IconsTheme::ICONS_DARK:
|
||||||
icon.addFile(kDarkIconFiles[index]);
|
icon.addFile(kDarkIconFile);
|
||||||
break;
|
break;
|
||||||
case IconsTheme::ICONS_LIGHT:
|
case IconsTheme::ICONS_LIGHT:
|
||||||
icon.addFile(kLightIconFiles[index]);
|
icon.addFile(kLightIconFile);
|
||||||
break;
|
break;
|
||||||
case IconsTheme::ICONS_TEMPLATE:
|
case IconsTheme::ICONS_TEMPLATE:
|
||||||
default:
|
default:
|
||||||
icon.addFile(kDarkIconFiles[index]);
|
icon.addFile(kDarkIconFile);
|
||||||
icon.setIsMask(true);
|
icon.setIsMask(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
icon.addFile(kDefaultIconFiles[index]);
|
icon.addFile(kIconFile16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_TrayIcon.setIcon(icon);
|
m_TrayIcon.setIcon(icon);
|
||||||
|
|
@ -840,23 +821,18 @@ void MainWindow::updateStatus() {
|
||||||
using enum CoreProcessState;
|
using enum CoreProcessState;
|
||||||
|
|
||||||
case Starting:
|
case Starting:
|
||||||
setIcon(CoreConnectionState::Disconnected);
|
|
||||||
setStatus("Synergy is starting...");
|
setStatus("Synergy is starting...");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Stopping:
|
case Stopping:
|
||||||
setIcon(CoreConnectionState::Disconnected);
|
|
||||||
setStatus("Synergy is stopping...");
|
setStatus("Synergy is stopping...");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Stopped:
|
case Stopped:
|
||||||
setIcon(CoreConnectionState::Disconnected);
|
|
||||||
setStatus("Synergy is not running");
|
setStatus("Synergy is not running");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Started: {
|
case Started: {
|
||||||
setIcon(connection);
|
|
||||||
|
|
||||||
switch (connection) {
|
switch (connection) {
|
||||||
using enum CoreConnectionState;
|
using enum CoreConnectionState;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ private:
|
||||||
void createTrayIcon();
|
void createTrayIcon();
|
||||||
void applyConfig();
|
void applyConfig();
|
||||||
void applyCloseToTray() const;
|
void applyCloseToTray() const;
|
||||||
void setIcon(CoreProcess::ConnectionState state);
|
void setIcon();
|
||||||
bool checkForApp(int which, QString &app);
|
bool checkForApp(int which, QString &app);
|
||||||
void setStatus(const QString &status);
|
void setStatus(const QString &status);
|
||||||
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
|
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,11 @@ void AppConfig::determineScope() {
|
||||||
settingName(Setting::kLoadSystemSettings),
|
settingName(Setting::kLoadSystemSettings),
|
||||||
m_LoadFromSystemScope, ConfigScopes::Scope::User)
|
m_LoadFromSystemScope, ConfigScopes::Scope::User)
|
||||||
.toBool();
|
.toBool();
|
||||||
|
if (loadFromSystemScope) {
|
||||||
|
qDebug("user settings indicates system scope should be used");
|
||||||
|
} else {
|
||||||
|
qDebug("user settings indicates user scope should be used");
|
||||||
|
}
|
||||||
setLoadFromSystemScope(loadFromSystemScope);
|
setLoadFromSystemScope(loadFromSystemScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,6 +272,7 @@ void AppConfig::determineScope() {
|
||||||
else if (m_Scopes.scopeContains(
|
else if (m_Scopes.scopeContains(
|
||||||
settingName(Setting::kScreenName),
|
settingName(Setting::kScreenName),
|
||||||
ConfigScopes::Scope::System)) {
|
ConfigScopes::Scope::System)) {
|
||||||
|
qDebug("system settings scope contains screen name, using system scope");
|
||||||
setLoadFromSystemScope(true);
|
setLoadFromSystemScope(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -409,10 +414,8 @@ void AppConfig::setLoadFromSystemScope(bool value) {
|
||||||
using enum ConfigScopes::Scope;
|
using enum ConfigScopes::Scope;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
qDebug("loading system settings scope");
|
|
||||||
loadScope(System);
|
loadScope(System);
|
||||||
} else {
|
} else {
|
||||||
qDebug("loading user settings scope");
|
|
||||||
loadScope(User);
|
loadScope(User);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -520,7 +520,7 @@ bool CoreProcess::serverArgs(QStringList &args, QString &app) {
|
||||||
args << "--address" << correctedInterface();
|
args << "--address" << correctedInterface();
|
||||||
|
|
||||||
args << "-c" << configFilename;
|
args << "-c" << configFilename;
|
||||||
qInfo("config file: %s", qPrintable(configFilename));
|
qInfo("core config file: %s", qPrintable(configFilename));
|
||||||
|
|
||||||
if (kEnableActivation && !m_appConfig.serialKey().isEmpty()) {
|
if (kEnableActivation && !m_appConfig.serialKey().isEmpty()) {
|
||||||
args << "--serial-key" << m_appConfig.serialKey();
|
args << "--serial-key" << m_appConfig.serialKey();
|
||||||
|
|
@ -585,7 +585,8 @@ QString CoreProcess::persistConfig() const {
|
||||||
QFile configFile(configDirPath + "/" + kLastConfigFilename);
|
QFile configFile(configDirPath + "/" + kLastConfigFilename);
|
||||||
if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
qWarning(
|
qWarning(
|
||||||
"failed to open config file: %s", qPrintable(configFile.fileName()));
|
"failed to open core config file: %s",
|
||||||
|
qPrintable(configFile.fileName()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ void SettingsDialog::on_m_pCheckBoxEnableTls_clicked(bool) {
|
||||||
|
|
||||||
if (kEnableActivation && !m_tlsUtility.isAvailable()) {
|
if (kEnableActivation && !m_tlsUtility.isAvailable()) {
|
||||||
m_pCheckBoxEnableTls->setChecked(false);
|
m_pCheckBoxEnableTls->setChecked(false);
|
||||||
|
updateTlsControlsEnabled();
|
||||||
|
|
||||||
auto edition = m_license.productEdition();
|
auto edition = m_license.productEdition();
|
||||||
if (edition == Edition::kBasic) {
|
if (edition == Edition::kBasic) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
|
||||||
|
|
@ -54,15 +55,23 @@ void dotenv(const QString &filename) {
|
||||||
"no %s file in dir: %s", qPrintable(filename),
|
"no %s file in dir: %s", qPrintable(filename),
|
||||||
qPrintable(fileInfo.absolutePath()));
|
qPrintable(fileInfo.absolutePath()));
|
||||||
|
|
||||||
// if nothing in current dir, then try app dir. this makes it a bit easier
|
// if nothing in current dir, then try the app data dir.
|
||||||
// for engineers in the field to have an easily predictable location for the
|
// this makes it a bit easier for engineers in the field to have an easily
|
||||||
// .env file.
|
// predictable location for the .env file.
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir configDir(
|
||||||
filePath = dir.filePath(filename);
|
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
|
||||||
|
|
||||||
|
// HACK: since we have the org name set to the app name, the config dir is
|
||||||
|
// confusing. make this simple by using the org dir instead.
|
||||||
|
// use `filePath("..")` instead of `cdUp` to avoid the existence check.
|
||||||
|
QDir orgDir = configDir.filePath("..");
|
||||||
|
orgDir = orgDir.absolutePath();
|
||||||
|
|
||||||
|
filePath = orgDir.filePath(filename);
|
||||||
if (!open(file, filePath)) {
|
if (!open(file, filePath)) {
|
||||||
qInfo(
|
qInfo(
|
||||||
"no %s file in app dir: %s", qPrintable(filename),
|
"no %s file in app config dir: %s", qPrintable(filename),
|
||||||
qPrintable(dir.absolutePath()));
|
qPrintable(orgDir.absolutePath()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
src/lib/gui/style_utils.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2024 Symless
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file LICENSE that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QStyleHints>
|
||||||
|
|
||||||
|
namespace synergy::gui {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detects dark mode depending on Qt version.
|
||||||
|
* https://www.qt.io/blog/dark-mode-on-windows-11-with-qt-6.5
|
||||||
|
*/
|
||||||
|
inline bool isDarkMode() {
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||||
|
const auto scheme = QGuiApplication::styleHints()->colorScheme();
|
||||||
|
return scheme == Qt::ColorScheme::Dark;
|
||||||
|
#else
|
||||||
|
const QPalette defaultPalette;
|
||||||
|
const auto text = defaultPalette.color(QPalette::WindowText);
|
||||||
|
const auto window = defaultPalette.color(QPalette::Window);
|
||||||
|
return text.lightness() > window.lightness();
|
||||||
|
#endif // QT_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace synergy::gui
|
||||||