Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c937bb3177 | |||
| 28a277184a | |||
| 69e66d4e79 | |||
| 78d6bc0bf7 | |||
| a158fe1696 |
@@ -1,33 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <src/display/lv_display.h>
|
#include <src/display/lv_display.h>
|
||||||
|
|
||||||
namespace tt::settings::display {
|
namespace tt::settings::display {
|
||||||
|
|
||||||
enum class Orientation {
|
enum class Orientation {
|
||||||
|
// In order of rotation (to make it easier to convert to LVGL rotation)
|
||||||
Landscape,
|
Landscape,
|
||||||
Portrait,
|
Portrait,
|
||||||
LandscapeFlipped,
|
LandscapeFlipped,
|
||||||
PortraitFlipped,
|
PortraitFlipped,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ScreensaverType {
|
enum class ScreensaverType {
|
||||||
None,
|
None, // Just black screen
|
||||||
BouncingBalls,
|
BouncingBalls,
|
||||||
Mystify,
|
Mystify,
|
||||||
MatrixRain,
|
MatrixRain,
|
||||||
StackChan,
|
StackChan,
|
||||||
McpScreen,
|
McpScreen,
|
||||||
Count
|
Count // Sentinel for bounds checking - must be last
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DisplaySettings {
|
struct DisplaySettings {
|
||||||
Orientation orientation;
|
Orientation orientation;
|
||||||
uint8_t gammaCurve;
|
uint8_t gammaCurve;
|
||||||
uint8_t backlightDuty;
|
uint8_t backlightDuty;
|
||||||
bool backlightTimeoutEnabled;
|
bool backlightTimeoutEnabled;
|
||||||
uint32_t backlightTimeoutMs;
|
uint32_t backlightTimeoutMs; // 0 = Never
|
||||||
ScreensaverType screensaverType = ScreensaverType::BouncingBalls;
|
ScreensaverType screensaverType = ScreensaverType::BouncingBalls;
|
||||||
bool disableScreensaverWhenCharging = false;
|
bool disableScreensaverWhenCharging = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Compares default settings with the function parameter to return the difference */
|
||||||
lv_display_rotation_t toLvglDisplayRotation(Orientation orientation);
|
lv_display_rotation_t toLvglDisplayRotation(Orientation orientation);
|
||||||
|
|
||||||
bool load(DisplaySettings& settings);
|
bool load(DisplaySettings& settings);
|
||||||
|
|
||||||
DisplaySettings loadOrGetDefault();
|
DisplaySettings loadOrGetDefault();
|
||||||
|
|
||||||
DisplaySettings getDefault();
|
DisplaySettings getDefault();
|
||||||
|
|
||||||
bool save(const DisplaySettings& settings);
|
bool save(const DisplaySettings& settings);
|
||||||
}
|
|
||||||
|
} // namespace
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ namespace app {
|
|||||||
namespace crashdiagnostics { extern const AppManifest manifest; }
|
namespace crashdiagnostics { extern const AppManifest manifest; }
|
||||||
namespace webserversettings { extern const AppManifest manifest; }
|
namespace webserversettings { extern const AppManifest manifest; }
|
||||||
namespace mcpsettings { extern const AppManifest manifest; }
|
namespace mcpsettings { extern const AppManifest manifest; }
|
||||||
|
namespace mcpoverride { extern const AppManifest manifest; }
|
||||||
#if CONFIG_TT_TDECK_WORKAROUND == 1
|
#if CONFIG_TT_TDECK_WORKAROUND == 1
|
||||||
namespace keyboardsettings { extern const AppManifest manifest; } // T-Deck only for now
|
namespace keyboardsettings { extern const AppManifest manifest; } // T-Deck only for now
|
||||||
namespace trackballsettings { extern const AppManifest manifest; } // T-Deck only for now
|
namespace trackballsettings { extern const AppManifest manifest; } // T-Deck only for now
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ public:
|
|||||||
|
|
||||||
screensaverDropdown = lv_dropdown_create(screensaver_wrapper);
|
screensaverDropdown = lv_dropdown_create(screensaver_wrapper);
|
||||||
// Note: order correlates with settings::display::ScreensaverType enum order
|
// Note: order correlates with settings::display::ScreensaverType enum order
|
||||||
lv_dropdown_set_options(screensaverDropdown, "None\nBouncing Balls\nMystify\nMatrix Rain\nStackChan");
|
lv_dropdown_set_options(screensaverDropdown, "None\nBouncing Balls\nMystify\nMatrix Rain\nStackChan\nMcpScreen");
|
||||||
lv_obj_align(screensaverDropdown, LV_ALIGN_RIGHT_MID, 0, 0);
|
lv_obj_align(screensaverDropdown, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||||
lv_obj_add_event_cb(screensaverDropdown, onScreensaverChanged, LV_EVENT_VALUE_CHANGED, this);
|
lv_obj_add_event_cb(screensaverDropdown, onScreensaverChanged, LV_EVENT_VALUE_CHANGED, this);
|
||||||
lv_dropdown_set_selected(screensaverDropdown, static_cast<uint16_t>(displaySettings.screensaverType));
|
lv_dropdown_set_selected(screensaverDropdown, static_cast<uint16_t>(displaySettings.screensaverType));
|
||||||
@@ -295,13 +295,16 @@ public:
|
|||||||
lv_obj_add_state(screensaverDropdown, LV_STATE_DISABLED);
|
lv_obj_add_state(screensaverDropdown, LV_STATE_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable screensaver when charging toggle
|
||||||
disableWhenChargingWrapper = lv_obj_create(main_wrapper);
|
disableWhenChargingWrapper = lv_obj_create(main_wrapper);
|
||||||
lv_obj_set_size(disableWhenChargingWrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
lv_obj_set_size(disableWhenChargingWrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
lv_obj_set_style_pad_all(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT);
|
lv_obj_set_style_pad_all(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_border_width(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT);
|
lv_obj_set_style_border_width(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
auto* charging_label = lv_label_create(disableWhenChargingWrapper);
|
auto* charging_label = lv_label_create(disableWhenChargingWrapper);
|
||||||
lv_label_set_text(charging_label, "Disable on charging");
|
lv_label_set_text(charging_label, "Disable on charging");
|
||||||
lv_obj_align(charging_label, LV_ALIGN_LEFT_MID, 0, 0);
|
lv_obj_align(charging_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||||
|
|
||||||
disableWhenChargingSwitch = lv_switch_create(disableWhenChargingWrapper);
|
disableWhenChargingSwitch = lv_switch_create(disableWhenChargingWrapper);
|
||||||
if (displaySettings.disableScreensaverWhenCharging) {
|
if (displaySettings.disableScreensaverWhenCharging) {
|
||||||
lv_obj_add_state(disableWhenChargingSwitch, LV_STATE_CHECKED);
|
lv_obj_add_state(disableWhenChargingSwitch, LV_STATE_CHECKED);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include <tactility/log.h>
|
|
||||||
|
|
||||||
#include <Tactility/service/displayidle/DisplayIdleService.h>
|
#include <Tactility/service/displayidle/DisplayIdleService.h>
|
||||||
|
|
||||||
@@ -14,10 +13,10 @@
|
|||||||
#include <Tactility/hal/display/DisplayDevice.h>
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
|
#include <Tactility/mcp/McpSystem.h>
|
||||||
#include <Tactility/service/ServiceContext.h>
|
#include <Tactility/service/ServiceContext.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
#include <Tactility/mcp/McpSystem.h>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
@@ -35,12 +34,12 @@ static bool isDeviceCharging() {
|
|||||||
bool charging = false;
|
bool charging = false;
|
||||||
hal::findDevices<hal::power::PowerDevice>(hal::Device::Type::Power, [&charging](const auto& power) {
|
hal::findDevices<hal::power::PowerDevice>(hal::Device::Type::Power, [&charging](const auto& power) {
|
||||||
if (!power->supportsMetric(hal::power::PowerDevice::MetricType::IsCharging)) {
|
if (!power->supportsMetric(hal::power::PowerDevice::MetricType::IsCharging)) {
|
||||||
return true; // continue
|
return true;
|
||||||
}
|
}
|
||||||
hal::power::PowerDevice::MetricData data;
|
hal::power::PowerDevice::MetricData data;
|
||||||
if (power->getMetric(hal::power::PowerDevice::MetricType::IsCharging, data) && data.valueAsBool) {
|
if (power->getMetric(hal::power::PowerDevice::MetricType::IsCharging, data) && data.valueAsBool) {
|
||||||
charging = true;
|
charging = true;
|
||||||
return false; // stop iter
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -49,10 +48,17 @@ static bool isDeviceCharging() {
|
|||||||
|
|
||||||
void DisplayIdleService::stopScreensaverCb(lv_event_t* e) {
|
void DisplayIdleService::stopScreensaverCb(lv_event_t* e) {
|
||||||
auto* self = static_cast<DisplayIdleService*>(lv_event_get_user_data(e));
|
auto* self = static_cast<DisplayIdleService*>(lv_event_get_user_data(e));
|
||||||
self->stopScreensaverLocked();
|
lv_event_stop_bubbling(e);
|
||||||
|
self->stopScreensaverRequested.store(true, std::memory_order_release);
|
||||||
|
lv_display_trigger_activity(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayIdleService::stopScreensaverLocked() {
|
void DisplayIdleService::stopScreensaver() {
|
||||||
|
if (!lvgl::lock(100)) {
|
||||||
|
// Lock failed - keep flag set to retry on next tick
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto restoreDuty = cachedDisplaySettings.backlightDuty;
|
const auto restoreDuty = cachedDisplaySettings.backlightDuty;
|
||||||
const bool wasDimmed = displayDimmed;
|
const bool wasDimmed = displayDimmed;
|
||||||
|
|
||||||
@@ -64,6 +70,7 @@ void DisplayIdleService::stopScreensaverLocked() {
|
|||||||
lv_obj_delete(screensaverOverlay);
|
lv_obj_delete(screensaverOverlay);
|
||||||
screensaverOverlay = nullptr;
|
screensaverOverlay = nullptr;
|
||||||
}
|
}
|
||||||
|
lvgl::unlock();
|
||||||
stopScreensaverRequested.store(false, std::memory_order_relaxed);
|
stopScreensaverRequested.store(false, std::memory_order_relaxed);
|
||||||
|
|
||||||
// Reset auto-off state
|
// Reset auto-off state
|
||||||
@@ -78,15 +85,6 @@ void DisplayIdleService::stopScreensaverLocked() {
|
|||||||
displayDimmed = wasDimmed ? false : displayDimmed;
|
displayDimmed = wasDimmed ? false : displayDimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayIdleService::stopScreensaver() {
|
|
||||||
if (!lvgl::lock(100)) {
|
|
||||||
// Lock failed - keep flag set to retry on next tick
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stopScreensaverLocked();
|
|
||||||
lvgl::unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisplayIdleService::activateScreensaver() {
|
void DisplayIdleService::activateScreensaver() {
|
||||||
lv_obj_t* top = lv_layer_top();
|
lv_obj_t* top = lv_layer_top();
|
||||||
|
|
||||||
@@ -147,16 +145,6 @@ void DisplayIdleService::updateScreensaver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DisplayIdleService::tick() {
|
void DisplayIdleService::tick() {
|
||||||
// Check if MCP override is active — must not be auto-stopped by idle logic
|
|
||||||
// READ OUTSIDE LVGL lock to avoid lock inversion:
|
|
||||||
// MCP video task locks mutex -> LVGL, we must NOT do LVGL -> mutex
|
|
||||||
bool isMcpActive = false;
|
|
||||||
{
|
|
||||||
auto& st = mcp::getState();
|
|
||||||
std::lock_guard<std::mutex> lk(st.mutex);
|
|
||||||
isMcpActive = (st.drawArea != nullptr) || st.overrideActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lvgl::lock(100)) {
|
if (!lvgl::lock(100)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -171,10 +159,11 @@ void DisplayIdleService::tick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t inactive_ms = 0;
|
uint32_t inactive_ms = 0;
|
||||||
|
|
||||||
inactive_ms = lv_display_get_inactive_time(nullptr);
|
inactive_ms = lv_display_get_inactive_time(nullptr);
|
||||||
|
|
||||||
// Only update if not stopping (prevents lag on touch) — skip for MCP (no animation)
|
// Only update if not stopping (prevents lag on touch)
|
||||||
if (displayDimmed && screensaverOverlay && !stopScreensaverRequested.load(std::memory_order_acquire) && !isMcpActive) {
|
if (displayDimmed && screensaverOverlay && !stopScreensaverRequested.load(std::memory_order_acquire)) {
|
||||||
// Check if screensaver should auto-off after 5 minutes
|
// Check if screensaver should auto-off after 5 minutes
|
||||||
if (!backlightOff) {
|
if (!backlightOff) {
|
||||||
screensaverActiveCounter++;
|
screensaverActiveCounter++;
|
||||||
@@ -204,49 +193,35 @@ void DisplayIdleService::tick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto display = getDisplay();
|
auto display = getDisplay();
|
||||||
bool supportsBacklight = display != nullptr && display->supportsBacklightDuty();
|
if (display != nullptr && display->supportsBacklightDuty()) {
|
||||||
|
if (!cachedDisplaySettings.backlightTimeoutEnabled || cachedDisplaySettings.backlightTimeoutMs == 0) {
|
||||||
if (!cachedDisplaySettings.backlightTimeoutEnabled || cachedDisplaySettings.backlightTimeoutMs == 0) {
|
if (displayDimmed) {
|
||||||
// Timeout disabled (Never): ensure we restore if we were dimmed, regardless of display type
|
|
||||||
if (displayDimmed && !isMcpActive) {
|
|
||||||
if (supportsBacklight && display != nullptr) {
|
|
||||||
display->setBacklightDuty(cachedDisplaySettings.backlightDuty);
|
display->setBacklightDuty(cachedDisplaySettings.backlightDuty);
|
||||||
|
displayDimmed = false;
|
||||||
}
|
}
|
||||||
displayDimmed = false;
|
} else {
|
||||||
}
|
bool charging_blocks = cachedDisplaySettings.disableScreensaverWhenCharging && isDeviceCharging();
|
||||||
} else if (supportsBacklight) {
|
if (!displayDimmed && inactive_ms >= cachedDisplaySettings.backlightTimeoutMs) {
|
||||||
// For backlight-capable displays: full idle handling
|
if (charging_blocks) {
|
||||||
bool charging_blocks = cachedDisplaySettings.disableScreensaverWhenCharging && isDeviceCharging();
|
// Skip screensaver while charging
|
||||||
|
} else {
|
||||||
if (!displayDimmed && inactive_ms >= cachedDisplaySettings.backlightTimeoutMs) {
|
if (!lvgl::lock(100)) {
|
||||||
if (charging_blocks) {
|
return; // Retry on next tick
|
||||||
// Skip screensaver while charging
|
}
|
||||||
} else {
|
activateScreensaver();
|
||||||
if (!lvgl::lock(100)) {
|
lvgl::unlock();
|
||||||
return; // Retry on next tick
|
// Turn off backlight for "None" screensaver (just black screen)
|
||||||
}
|
if (cachedDisplaySettings.screensaverType == settings::display::ScreensaverType::None) {
|
||||||
activateScreensaver();
|
|
||||||
lvgl::unlock();
|
|
||||||
if (cachedDisplaySettings.screensaverType == settings::display::ScreensaverType::None) {
|
|
||||||
if (display != nullptr) {
|
|
||||||
display->setBacklightDuty(0);
|
display->setBacklightDuty(0);
|
||||||
}
|
}
|
||||||
|
displayDimmed = true;
|
||||||
|
}
|
||||||
|
} else if (displayDimmed) {
|
||||||
|
if (inactive_ms < kWakeActivityThresholdMs) {
|
||||||
|
stopScreensaver();
|
||||||
|
} else if (charging_blocks) {
|
||||||
|
stopScreensaver();
|
||||||
}
|
}
|
||||||
displayDimmed = true;
|
|
||||||
}
|
|
||||||
} else if (displayDimmed && !isMcpActive) {
|
|
||||||
if (inactive_ms < kWakeActivityThresholdMs) {
|
|
||||||
stopScreensaver();
|
|
||||||
} else if (charging_blocks) {
|
|
||||||
stopScreensaver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For monochrome/RLCD (no backlight): don't auto-enter screensaver (heavy full_refresh SPI causes freeze)
|
|
||||||
// Only handle wake if we are somehow dimmed (e.g. MCP left it)
|
|
||||||
if (displayDimmed && !isMcpActive) {
|
|
||||||
if (inactive_ms < kWakeActivityThresholdMs) {
|
|
||||||
stopScreensaver();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,11 +233,6 @@ bool DisplayIdleService::onStart(ServiceContext& service) {
|
|||||||
|
|
||||||
cachedDisplaySettings = settings::display::loadOrGetDefault();
|
cachedDisplaySettings = settings::display::loadOrGetDefault();
|
||||||
|
|
||||||
auto display = getDisplay();
|
|
||||||
if (display != nullptr && !display->supportsBacklightDuty()) {
|
|
||||||
LOG_I(TAG, "Monochrome/RLCD display detected (no backlight control): idle timer will run but auto-backlight off is disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::millisToTicks(TICK_INTERVAL_MS), [this]{ this->tick(); });
|
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::millisToTicks(TICK_INTERVAL_MS), [this]{ this->tick(); });
|
||||||
timer->setCallbackPriority(Thread::Priority::Lower);
|
timer->setCallbackPriority(Thread::Priority::Lower);
|
||||||
timer->start();
|
timer->start();
|
||||||
@@ -314,11 +284,6 @@ bool DisplayIdleService::isScreensaverActive() const {
|
|||||||
return screensaverOverlay != nullptr;
|
return screensaverOverlay != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayIdleService::reloadSettings() {
|
|
||||||
// Set flag for thread-safe reload - actual reload happens in tick()
|
|
||||||
settingsReloadRequested.store(true, std::memory_order_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisplayIdleService::startMcpScreensaver() {
|
void DisplayIdleService::startMcpScreensaver() {
|
||||||
if (!lvgl::lock(200)) {
|
if (!lvgl::lock(200)) {
|
||||||
LOG_W(TAG, "startMcpScreensaver: failed to acquire LVGL lock");
|
LOG_W(TAG, "startMcpScreensaver: failed to acquire LVGL lock");
|
||||||
@@ -354,7 +319,6 @@ void DisplayIdleService::startMcpScreensaver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lv_coord_t screenW = lv_display_get_horizontal_resolution(nullptr);
|
lv_coord_t screenW = lv_display_get_horizontal_resolution(nullptr);
|
||||||
|
|
||||||
lv_coord_t screenH = lv_display_get_vertical_resolution(nullptr);
|
lv_coord_t screenH = lv_display_get_vertical_resolution(nullptr);
|
||||||
|
|
||||||
lv_obj_t* top = lv_layer_top();
|
lv_obj_t* top = lv_layer_top();
|
||||||
@@ -375,6 +339,11 @@ void DisplayIdleService::startMcpScreensaver() {
|
|||||||
LOG_I(TAG, "MCP screensaver activated");
|
LOG_I(TAG, "MCP screensaver activated");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayIdleService::reloadSettings() {
|
||||||
|
// Set flag for thread-safe reload - actual reload happens in tick()
|
||||||
|
settingsReloadRequested.store(true, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<DisplayIdleService> findService() {
|
std::shared_ptr<DisplayIdleService> findService() {
|
||||||
return std::static_pointer_cast<DisplayIdleService>(
|
return std::static_pointer_cast<DisplayIdleService>(
|
||||||
findServiceById("DisplayIdle")
|
findServiceById("DisplayIdle")
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ static Orientation getDefaultOrientation() {
|
|||||||
if (display == nullptr) {
|
if (display == nullptr) {
|
||||||
return Orientation::Landscape;
|
return Orientation::Landscape;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lv_display_get_physical_horizontal_resolution(display) > lv_display_get_physical_vertical_resolution(display)) {
|
if (lv_display_get_physical_horizontal_resolution(display) > lv_display_get_physical_vertical_resolution(display)) {
|
||||||
return Orientation::Landscape;
|
return Orientation::Landscape;
|
||||||
} else {
|
} else {
|
||||||
@@ -39,51 +40,91 @@ static Orientation getDefaultOrientation() {
|
|||||||
static std::string toString(Orientation orientation) {
|
static std::string toString(Orientation orientation) {
|
||||||
switch (orientation) {
|
switch (orientation) {
|
||||||
using enum Orientation;
|
using enum Orientation;
|
||||||
case Portrait: return "Portrait";
|
case Portrait:
|
||||||
case Landscape: return "Landscape";
|
return "Portrait";
|
||||||
case PortraitFlipped: return "PortraitFlipped";
|
case Landscape:
|
||||||
case LandscapeFlipped: return "LandscapeFlipped";
|
return "Landscape";
|
||||||
default: std::unreachable();
|
case PortraitFlipped:
|
||||||
|
return "PortraitFlipped";
|
||||||
|
case LandscapeFlipped:
|
||||||
|
return "LandscapeFlipped";
|
||||||
|
default:
|
||||||
|
std::unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fromString(const std::string& str, Orientation& orientation) {
|
static bool fromString(const std::string& str, Orientation& orientation) {
|
||||||
if (str == "Portrait") { orientation = Orientation::Portrait; return true; }
|
if (str == "Portrait") {
|
||||||
else if (str == "Landscape") { orientation = Orientation::Landscape; return true; }
|
orientation = Orientation::Portrait;
|
||||||
else if (str == "PortraitFlipped") { orientation = Orientation::PortraitFlipped; return true; }
|
return true;
|
||||||
else if (str == "LandscapeFlipped") { orientation = Orientation::LandscapeFlipped; return true; }
|
} else if (str == "Landscape") {
|
||||||
else { return false; }
|
orientation = Orientation::Landscape;
|
||||||
|
return true;
|
||||||
|
} else if (str == "PortraitFlipped") {
|
||||||
|
orientation = Orientation::PortraitFlipped;
|
||||||
|
return true;
|
||||||
|
} else if (str == "LandscapeFlipped") {
|
||||||
|
orientation = Orientation::LandscapeFlipped;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string toString(ScreensaverType type) {
|
static std::string toString(ScreensaverType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
using enum ScreensaverType;
|
using enum ScreensaverType;
|
||||||
case None: return "None";
|
case None:
|
||||||
case BouncingBalls: return "BouncingBalls";
|
return "None";
|
||||||
case Mystify: return "Mystify";
|
case BouncingBalls:
|
||||||
case MatrixRain: return "MatrixRain";
|
return "BouncingBalls";
|
||||||
case StackChan: return "StackChan";
|
case Mystify:
|
||||||
case McpScreen: return "McpScreen";
|
return "Mystify";
|
||||||
case Count: return "None";
|
case MatrixRain:
|
||||||
default: std::unreachable();
|
return "MatrixRain";
|
||||||
|
case StackChan:
|
||||||
|
return "StackChan";
|
||||||
|
case McpScreen:
|
||||||
|
return "McpScreen";
|
||||||
|
default:
|
||||||
|
std::unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fromString(const std::string& str, ScreensaverType& type) {
|
static bool fromString(const std::string& str, ScreensaverType& type) {
|
||||||
if (str == "None") { type = ScreensaverType::None; return true; }
|
if (str == "None") {
|
||||||
else if (str == "BouncingBalls") { type = ScreensaverType::BouncingBalls; return true; }
|
type = ScreensaverType::None;
|
||||||
else if (str == "Mystify") { type = ScreensaverType::Mystify; return true; }
|
return true;
|
||||||
else if (str == "MatrixRain") { type = ScreensaverType::MatrixRain; return true; }
|
} else if (str == "BouncingBalls") {
|
||||||
else if (str == "StackChan") { type = ScreensaverType::StackChan; return true; }
|
type = ScreensaverType::BouncingBalls;
|
||||||
else if (str == "McpScreen") { type = ScreensaverType::McpScreen; return true; }
|
return true;
|
||||||
else { return false; }
|
} else if (str == "Mystify") {
|
||||||
|
type = ScreensaverType::Mystify;
|
||||||
|
return true;
|
||||||
|
} else if (str == "MatrixRain") {
|
||||||
|
type = ScreensaverType::MatrixRain;
|
||||||
|
return true;
|
||||||
|
} else if (str == "StackChan") {
|
||||||
|
type = ScreensaverType::StackChan;
|
||||||
|
return true;
|
||||||
|
} else if (str == "McpScreen") {
|
||||||
|
type = ScreensaverType::McpScreen;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load(DisplaySettings& settings) {
|
bool load(DisplaySettings& settings) {
|
||||||
auto settings_path = getSettingsFilePath();
|
auto settings_path = getSettingsFilePath();
|
||||||
if (!file::isFile(settings_path)) { return false; }
|
if (!file::isFile(settings_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> map;
|
std::map<std::string, std::string> map;
|
||||||
if (!file::loadPropertiesFile(settings_path, map)) { return false; }
|
if (!file::loadPropertiesFile(settings_path, map)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto orientation_entry = map.find(SETTINGS_KEY_ORIENTATION);
|
auto orientation_entry = map.find(SETTINGS_KEY_ORIENTATION);
|
||||||
Orientation orientation;
|
Orientation orientation;
|
||||||
@@ -93,13 +134,17 @@ bool load(DisplaySettings& settings) {
|
|||||||
|
|
||||||
auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE);
|
auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE);
|
||||||
int gamma_curve = 0;
|
int gamma_curve = 0;
|
||||||
if (gamma_entry != map.end()) { gamma_curve = atoi(gamma_entry->second.c_str()); }
|
if (gamma_entry != map.end()) {
|
||||||
|
gamma_curve = atoi(gamma_entry->second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
auto backlight_duty_entry = map.find(SETTINGS_KEY_BACKLIGHT_DUTY);
|
auto backlight_duty_entry = map.find(SETTINGS_KEY_BACKLIGHT_DUTY);
|
||||||
int backlight_duty = 200;
|
int backlight_duty = 200; // default
|
||||||
if (backlight_duty_entry != map.end()) {
|
if (backlight_duty_entry != map.end()) {
|
||||||
backlight_duty = atoi(backlight_duty_entry->second.c_str());
|
backlight_duty = atoi(backlight_duty_entry->second.c_str());
|
||||||
if (backlight_duty_entry->second != "0" && backlight_duty == 0) backlight_duty = 200;
|
if (backlight_duty_entry->second != "0" && backlight_duty == 0) {
|
||||||
|
backlight_duty = 200;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool timeout_enabled = false;
|
bool timeout_enabled = false;
|
||||||
@@ -108,7 +153,7 @@ bool load(DisplaySettings& settings) {
|
|||||||
timeout_enabled = (timeout_enabled_entry->second == "1" || timeout_enabled_entry->second == "true" || timeout_enabled_entry->second == "True");
|
timeout_enabled = (timeout_enabled_entry->second == "1" || timeout_enabled_entry->second == "true" || timeout_enabled_entry->second == "True");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t timeout_ms = 60000;
|
uint32_t timeout_ms = 60000; // default 60s
|
||||||
auto timeout_ms_entry = map.find(SETTINGS_KEY_TIMEOUT_MS);
|
auto timeout_ms_entry = map.find(SETTINGS_KEY_TIMEOUT_MS);
|
||||||
if (timeout_ms_entry != map.end()) {
|
if (timeout_ms_entry != map.end()) {
|
||||||
timeout_ms = static_cast<uint32_t>(std::strtoul(timeout_ms_entry->second.c_str(), nullptr, 10));
|
timeout_ms = static_cast<uint32_t>(std::strtoul(timeout_ms_entry->second.c_str(), nullptr, 10));
|
||||||
@@ -116,12 +161,14 @@ bool load(DisplaySettings& settings) {
|
|||||||
|
|
||||||
auto screensaver_entry = map.find(SETTINGS_KEY_SCREENSAVER_TYPE);
|
auto screensaver_entry = map.find(SETTINGS_KEY_SCREENSAVER_TYPE);
|
||||||
ScreensaverType screensaver_type = ScreensaverType::BouncingBalls;
|
ScreensaverType screensaver_type = ScreensaverType::BouncingBalls;
|
||||||
if (screensaver_entry != map.end()) { fromString(screensaver_entry->second, screensaver_type); }
|
if (screensaver_entry != map.end()) {
|
||||||
|
fromString(screensaver_entry->second, screensaver_type);
|
||||||
|
}
|
||||||
|
|
||||||
bool disable_when_charging = false;
|
bool disable_when_charging = false;
|
||||||
auto charging_entry = map.find(SETTINGS_KEY_DISABLE_WHEN_CHARGING);
|
auto charging_entry = map.find(SETTINGS_KEY_DISABLE_WHEN_CHARGING);
|
||||||
if (charging_entry != map.end()) {
|
if (charging_entry != map.end()) {
|
||||||
disable_when_charging = (charging_entry->second == "1" || charging_entry->second == "true");
|
disable_when_charging = (charging_entry->second == "1" || charging_entry->second == "true" || charging_entry->second == "True");
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.orientation = orientation;
|
settings.orientation = orientation;
|
||||||
@@ -131,6 +178,7 @@ bool load(DisplaySettings& settings) {
|
|||||||
settings.backlightTimeoutMs = timeout_ms;
|
settings.backlightTimeoutMs = timeout_ms;
|
||||||
settings.screensaverType = screensaver_type;
|
settings.screensaverType = screensaver_type;
|
||||||
settings.disableScreensaverWhenCharging = disable_when_charging;
|
settings.disableScreensaverWhenCharging = disable_when_charging;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +196,9 @@ DisplaySettings getDefault() {
|
|||||||
|
|
||||||
DisplaySettings loadOrGetDefault() {
|
DisplaySettings loadOrGetDefault() {
|
||||||
DisplaySettings settings;
|
DisplaySettings settings;
|
||||||
if (!load(settings)) { settings = getDefault(); }
|
if (!load(settings)) {
|
||||||
|
settings = getDefault();
|
||||||
|
}
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +212,9 @@ bool save(const DisplaySettings& settings) {
|
|||||||
map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType);
|
map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType);
|
||||||
map[SETTINGS_KEY_DISABLE_WHEN_CHARGING] = settings.disableScreensaverWhenCharging ? "1" : "0";
|
map[SETTINGS_KEY_DISABLE_WHEN_CHARGING] = settings.disableScreensaverWhenCharging ? "1" : "0";
|
||||||
auto settings_path = getSettingsFilePath();
|
auto settings_path = getSettingsFilePath();
|
||||||
if (!file::findOrCreateParentDirectory(settings_path, 0755)) { return false; }
|
if (!file::findOrCreateParentDirectory(settings_path, 0755)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return file::savePropertiesFile(settings_path, map);
|
return file::savePropertiesFile(settings_path, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,26 +222,40 @@ lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) {
|
|||||||
auto* lvgl_display = lv_display_get_default();
|
auto* lvgl_display = lv_display_get_default();
|
||||||
auto rotation = lv_display_get_rotation(lvgl_display);
|
auto rotation = lv_display_get_rotation(lvgl_display);
|
||||||
bool is_originally_landscape;
|
bool is_originally_landscape;
|
||||||
|
// The lvgl resolution code compensates for rotation. We have to revert the compensation to get the real display resolution
|
||||||
|
// TODO: Use info from display driver
|
||||||
if (rotation == LV_DISPLAY_ROTATION_0 || rotation == LV_DISPLAY_ROTATION_180) {
|
if (rotation == LV_DISPLAY_ROTATION_0 || rotation == LV_DISPLAY_ROTATION_180) {
|
||||||
is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) > lv_display_get_physical_vertical_resolution(lvgl_display);
|
is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) > lv_display_get_physical_vertical_resolution(lvgl_display);
|
||||||
} else {
|
} else {
|
||||||
is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) < lv_display_get_physical_vertical_resolution(lvgl_display);
|
is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) < lv_display_get_physical_vertical_resolution(lvgl_display);
|
||||||
}
|
}
|
||||||
if (is_originally_landscape) {
|
if (is_originally_landscape) {
|
||||||
|
// Landscape display
|
||||||
switch (orientation) {
|
switch (orientation) {
|
||||||
case Orientation::Landscape: return LV_DISPLAY_ROTATION_0;
|
case Orientation::Landscape:
|
||||||
case Orientation::Portrait: return LV_DISPLAY_ROTATION_90;
|
return LV_DISPLAY_ROTATION_0;
|
||||||
case Orientation::LandscapeFlipped: return LV_DISPLAY_ROTATION_180;
|
case Orientation::Portrait:
|
||||||
case Orientation::PortraitFlipped: return LV_DISPLAY_ROTATION_270;
|
return LV_DISPLAY_ROTATION_90;
|
||||||
default: return LV_DISPLAY_ROTATION_0;
|
case Orientation::LandscapeFlipped:
|
||||||
|
return LV_DISPLAY_ROTATION_180;
|
||||||
|
case Orientation::PortraitFlipped:
|
||||||
|
return LV_DISPLAY_ROTATION_270;
|
||||||
|
default:
|
||||||
|
return LV_DISPLAY_ROTATION_0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Portrait display
|
||||||
switch (orientation) {
|
switch (orientation) {
|
||||||
case Orientation::Landscape: return LV_DISPLAY_ROTATION_90;
|
case Orientation::Landscape:
|
||||||
case Orientation::Portrait: return LV_DISPLAY_ROTATION_0;
|
return LV_DISPLAY_ROTATION_90;
|
||||||
case Orientation::LandscapeFlipped: return LV_DISPLAY_ROTATION_270;
|
case Orientation::Portrait:
|
||||||
case Orientation::PortraitFlipped: return LV_DISPLAY_ROTATION_180;
|
return LV_DISPLAY_ROTATION_0;
|
||||||
default: return LV_DISPLAY_ROTATION_0;
|
case Orientation::LandscapeFlipped:
|
||||||
|
return LV_DISPLAY_ROTATION_270;
|
||||||
|
case Orientation::PortraitFlipped:
|
||||||
|
return LV_DISPLAY_ROTATION_180;
|
||||||
|
default:
|
||||||
|
return LV_DISPLAY_ROTATION_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user