diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run
index 3075d2c4d7..2be567f76d 100644
--- a/repos/gems/run/sculpt.run
+++ b/repos/gems/run/sculpt.run
@@ -273,6 +273,8 @@ install_config {
+
+
+
+
diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default
index 0a78d94848..9cc73ec70f 100644
--- a/repos/gems/sculpt/leitzentrale/default
+++ b/repos/gems/sculpt/leitzentrale/default
@@ -254,6 +254,8 @@
+
+
diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc
index 4073811bc5..57b1f891fe 100644
--- a/repos/gems/src/app/sculpt_manager/main.cc
+++ b/repos/gems/src/app/sculpt_manager/main.cc
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -71,7 +72,8 @@ struct Sculpt::Main : Input_event_handler,
Panel_dialog::State,
Dialog,
Popup_dialog::Refresh,
- Menu_view::Hover_update_handler
+ Menu_view::Hover_update_handler,
+ Screensaver::Action
{
Env &_env;
@@ -114,6 +116,16 @@ struct Sculpt::Main : Input_event_handler,
void _handle_gui_mode();
+ Screensaver _screensaver { _env, *this };
+
+ /**
+ * Screensaver::Action interface
+ */
+ void screensaver_changed() override
+ {
+ /* hook for driving the lifetime of the display driver */
+ }
+
Managed_config _fonts_config {
_env, "config", "fonts", *this, &Main::_handle_fonts_config };
diff --git a/repos/gems/src/app/sculpt_manager/model/screensaver.h b/repos/gems/src/app/sculpt_manager/model/screensaver.h
new file mode 100644
index 0000000000..6770fbe9ff
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/model/screensaver.h
@@ -0,0 +1,140 @@
+/*
+ * \brief Logic for activating/deactivating the screensaver
+ * \author Norman Feske
+ * \date 2023-06-27
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _MODEL__SCREENSAVER_H_
+#define _MODEL__SCREENSAVER_H_
+
+#include
+
+namespace Sculpt { class Screensaver; }
+
+
+class Sculpt::Screensaver : Noncopyable
+{
+ public:
+
+ struct Action : Interface
+ {
+ virtual void screensaver_changed() = 0;
+ };
+
+ private:
+
+ Env &_env;
+ Action &_action;
+
+ /* config */
+ unsigned _max_seconds_of_inactivity = 10;
+ bool _blank_after_some_time = true;
+
+ /* state */
+ uint64_t _last_activity_ms = 0;
+ bool _recent_user_activity = true;
+ bool _forced_blanked = false;
+
+ Timer::Connection _timer { _env };
+
+ Signal_handler _timer_handler {
+ _env.ep(), *this, &Screensaver::_handle_timer };
+
+ void _handle_timer()
+ {
+ uint64_t const now = _timer.elapsed_ms();
+
+ if (now - _last_activity_ms > _max_seconds_of_inactivity*1000) {
+ if (_recent_user_activity) {
+ _recent_user_activity = false;
+ _action.screensaver_changed();
+ }
+ }
+ }
+
+ void _wake_up()
+ {
+ _last_activity_ms = _timer.elapsed_ms();
+ _timer.trigger_once(_max_seconds_of_inactivity*1024*1024);
+ if (!_recent_user_activity) {
+ _recent_user_activity = true;
+ _action.screensaver_changed();
+ }
+ }
+
+ /**
+ * Utility for watching the 'active' attribute of a ROM module
+ */
+ struct Watched_rom : Noncopyable
+ {
+ Screensaver &_screensaver;
+
+ Attached_rom_dataspace _rom;
+
+ Signal_handler _handler {
+ _screensaver._env.ep(), *this, &Watched_rom::_handle };
+
+ Watched_rom(Screensaver &screensaver, char const *label)
+ :
+ _screensaver(screensaver), _rom(screensaver._env, label)
+ {
+ _rom.sigh(_handler);
+ }
+
+ void _handle()
+ {
+ _rom.update();
+ if (_rom.xml().attribute_value("active", false))
+ _screensaver._wake_up();
+ }
+ };
+
+ Watched_rom _nitpicker_focus { *this, "nitpicker_focus" };
+ Watched_rom _nitpicker_hover { *this, "nitpicker_hover" };
+
+ public:
+
+ Screensaver(Env &env, Action &action) : _env(env), _action(action)
+ {
+ _timer.sigh(_timer_handler);
+ }
+
+ bool display_enabled() const
+ {
+ if (_forced_blanked)
+ return false;
+
+ if (_blank_after_some_time && !_recent_user_activity)
+ return false;
+
+ return true;
+ }
+
+ void blank_after_some_time(bool blank_after_some_time)
+ {
+ _blank_after_some_time = blank_after_some_time;
+ _wake_up();
+ }
+
+ /**
+ * User enforces the enabling or disabling of the display (power button)
+ */
+ void force_toggle()
+ {
+ if (display_enabled())
+ _forced_blanked = true;
+ else
+ _forced_blanked = false;
+
+ _action.screensaver_changed();
+ }
+};
+
+#endif /* _MODEL__SCREENSAVER_H_ */