From 9c5915b5b4ed7e00f2e68247fd84e4c97d48d118 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 2 Jan 2023 12:14:04 -0500 Subject: [PATCH] Screensaver: Add a screensaver launcher application Similar to the Settings application, this adds a single Screensaver application to launch all screensaver demos. This is to declutter the taskbar menu a bit. --- Base/res/apps/GradientScreensaver.af | 3 +- Base/res/apps/Screensaver.af | 4 + Base/res/apps/Starfield.af | 3 +- Base/res/apps/Tubes.af | 3 +- Userland/Demos/CMakeLists.txt | 1 + Userland/Demos/Screensaver/CMakeLists.txt | 11 +++ Userland/Demos/Screensaver/main.cpp | 107 ++++++++++++++++++++++ 7 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 Base/res/apps/Screensaver.af create mode 100644 Userland/Demos/Screensaver/CMakeLists.txt create mode 100644 Userland/Demos/Screensaver/main.cpp diff --git a/Base/res/apps/GradientScreensaver.af b/Base/res/apps/GradientScreensaver.af index 41ca0af3ed..6677d4900f 100644 --- a/Base/res/apps/GradientScreensaver.af +++ b/Base/res/apps/GradientScreensaver.af @@ -1,4 +1,5 @@ [App] Name=Gradient Screensaver Executable=/bin/GradientScreensaver -Category=Demos +Category=Demos/Screensaver +ExcludeFromSystemMenu=true diff --git a/Base/res/apps/Screensaver.af b/Base/res/apps/Screensaver.af new file mode 100644 index 0000000000..3765c6fbc9 --- /dev/null +++ b/Base/res/apps/Screensaver.af @@ -0,0 +1,4 @@ +[App] +Name=Screensaver +Executable=/bin/Screensaver +Category=Demos diff --git a/Base/res/apps/Starfield.af b/Base/res/apps/Starfield.af index fbdaea4132..5c0d8dade7 100644 --- a/Base/res/apps/Starfield.af +++ b/Base/res/apps/Starfield.af @@ -1,4 +1,5 @@ [App] Name=Starfield Executable=/bin/Starfield -Category=Demos +Category=Demos/Screensaver +ExcludeFromSystemMenu=true diff --git a/Base/res/apps/Tubes.af b/Base/res/apps/Tubes.af index 547a0fc01a..18414021ca 100644 --- a/Base/res/apps/Tubes.af +++ b/Base/res/apps/Tubes.af @@ -1,4 +1,5 @@ [App] Name=Tubes Executable=/bin/Tubes -Category=Demos +Category=Demos/Screensaver +ExcludeFromSystemMenu=true diff --git a/Userland/Demos/CMakeLists.txt b/Userland/Demos/CMakeLists.txt index 7f3113a481..4e9c4569e7 100644 --- a/Userland/Demos/CMakeLists.txt +++ b/Userland/Demos/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(LibGfxDemo) add_subdirectory(LibGfxScaleDemo) add_subdirectory(Mandelbrot) add_subdirectory(ModelGallery) +add_subdirectory(Screensaver) add_subdirectory(Starfield) add_subdirectory(Tubes) add_subdirectory(WidgetGallery) diff --git a/Userland/Demos/Screensaver/CMakeLists.txt b/Userland/Demos/Screensaver/CMakeLists.txt new file mode 100644 index 0000000000..767fc3a35d --- /dev/null +++ b/Userland/Demos/Screensaver/CMakeLists.txt @@ -0,0 +1,11 @@ +serenity_component( + Screensaver + TARGETS Screensaver +) + +set(SOURCES + main.cpp +) + +serenity_app(Screensaver ICON app-screensaver) +target_link_libraries(Screensaver PRIVATE LibDesktop LibGUI LibCore LibGfx LibMain) diff --git a/Userland/Demos/Screensaver/main.cpp b/Userland/Demos/Screensaver/main.cpp new file mode 100644 index 0000000000..53eca2a247 --- /dev/null +++ b/Userland/Demos/Screensaver/main.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ScreensaverAppsModel final : public GUI::Model { +public: + ScreensaverAppsModel() + { + Desktop::AppFile::for_each([&](Desktop::AppFile& app_file) { + if (app_file.category() != "Demos/Screensaver"sv) + return; + m_apps.append(app_file); + }); + + quick_sort(m_apps, [](auto& a, auto& b) { return a->name() < b->name(); }); + } + + virtual int row_count(GUI::ModelIndex const&) const override { return static_cast(m_apps.size()); } + virtual int column_count(GUI::ModelIndex const&) const override { return 1; } + + virtual GUI::ModelIndex index(int row, int column, GUI::ModelIndex const&) const override + { + if (row < 0 || row >= static_cast(m_apps.size())) + return {}; + return create_index(row, column, &m_apps[row]); + } + + virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role) const override + { + auto const& app = m_apps[index.row()]; + if (role == GUI::ModelRole::Icon) + return app->icon(); + + if (role == GUI::ModelRole::Display) { + if (app->name().ends_with(" Screensaver"sv)) + return app->name().substring(0, app->name().length() - " Screensaver"sv.length()); + return app->name(); + } + + if (role == GUI::ModelRole::Custom) + return app->executable(); + + return {}; + } + +private: + // NonnullRefPtrVector doesn't allow us to quick_sort() it, because its operator[] returns T&. + Vector> m_apps; +}; + +ErrorOr serenity_main(Main::Arguments arguments) +{ + TRY(Core::System::pledge("stdio thread recvfd sendfd rpath cpath wpath unix proc exec")); + + auto app = TRY(GUI::Application::try_create(arguments)); + + TRY(Core::System::pledge("stdio thread recvfd sendfd rpath cpath wpath proc exec")); + + auto app_icon = GUI::Icon::default_icon("app-screensaver"sv); + + auto window = TRY(GUI::Window::try_create()); + window->set_title("Screensaver"); + window->resize(360, 240); + + auto file_menu = TRY(window->try_add_menu("&File")); + file_menu->add_action(GUI::CommonActions::make_quit_action([&](auto&) { + app->quit(); + })); + + auto help_menu = TRY(window->try_add_menu("&Help")); + TRY(help_menu->try_add_action(GUI::CommonActions::make_command_palette_action(window))); + TRY(help_menu->try_add_action(GUI::CommonActions::make_about_action("Screensaver", app_icon, window))); + + auto main_widget = TRY(window->try_set_main_widget()); + main_widget->set_fill_with_background_color(true); + main_widget->set_layout(); + + auto icon_view = TRY(main_widget->try_add()); + icon_view->set_should_hide_unnecessary_scrollbars(true); + auto model = adopt_ref(*new ScreensaverAppsModel); + icon_view->set_model(*model); + + icon_view->on_activation = [&](GUI::ModelIndex const& index) { + auto executable = model->data(index, GUI::ModelRole::Custom).as_string(); + GUI::Process::spawn_or_show_error(window, executable); + }; + + window->set_icon(app_icon.bitmap_for_size(16)); + window->show(); + + return app->exec(); +}