Serenity Operating System
1/*
2 * Copyright (c) 2019-2020, Jesse Buhagiar <jooster669@gmail.com>
3 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
4 * Copyright (c) 2022, the SerenityOS developers.
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#include "BackgroundSettingsWidget.h"
10#include <AK/StringBuilder.h>
11#include <Applications/DisplaySettings/BackgroundSettingsGML.h>
12#include <LibConfig/Client.h>
13#include <LibCore/ConfigFile.h>
14#include <LibDesktop/Launcher.h>
15#include <LibGUI/Application.h>
16#include <LibGUI/BoxLayout.h>
17#include <LibGUI/Button.h>
18#include <LibGUI/Clipboard.h>
19#include <LibGUI/ComboBox.h>
20#include <LibGUI/ConnectionToWindowServer.h>
21#include <LibGUI/Desktop.h>
22#include <LibGUI/FilePicker.h>
23#include <LibGUI/FileSystemModel.h>
24#include <LibGUI/FileTypeFilter.h>
25#include <LibGUI/IconView.h>
26#include <LibGUI/ItemListModel.h>
27#include <LibGUI/MessageBox.h>
28#include <LibGfx/Palette.h>
29#include <LibGfx/SystemTheme.h>
30
31namespace DisplaySettings {
32
33BackgroundSettingsWidget::BackgroundSettingsWidget(bool& background_settings_changed)
34 : m_background_settings_changed { background_settings_changed }
35{
36 m_modes.append("Tile");
37 m_modes.append("Center");
38 m_modes.append("Stretch");
39
40 create_frame();
41 load_current_settings();
42}
43
44void BackgroundSettingsWidget::create_frame()
45{
46 load_from_gml(background_settings_gml).release_value_but_fixme_should_propagate_errors();
47
48 m_monitor_widget = *find_descendant_of_type_named<DisplaySettings::MonitorWidget>("monitor_widget");
49
50 m_wallpaper_view = *find_descendant_of_type_named<GUI::IconView>("wallpaper_view");
51 m_wallpaper_view->set_model(GUI::FileSystemModel::create("/res/wallpapers"));
52 m_wallpaper_view->set_model_column(GUI::FileSystemModel::Column::Name);
53 m_wallpaper_view->on_selection_change = [this] {
54 DeprecatedString path;
55 if (m_wallpaper_view->selection().is_empty()) {
56 path = "";
57 } else {
58 auto index = m_wallpaper_view->selection().first();
59 path = static_cast<GUI::FileSystemModel*>(m_wallpaper_view->model())->full_path(index);
60 }
61
62 m_monitor_widget->set_wallpaper(path);
63 set_modified(true);
64 };
65
66 m_context_menu = GUI::Menu::construct();
67 m_show_in_file_manager_action = GUI::Action::create("Show in File Manager", Gfx::Bitmap::load_from_file("/res/icons/16x16/app-file-manager.png"sv).release_value_but_fixme_should_propagate_errors(), [this](GUI::Action const&) {
68 LexicalPath path { m_monitor_widget->wallpaper() };
69 Desktop::Launcher::open(URL::create_with_file_scheme(path.dirname(), path.basename()));
70 });
71 m_context_menu->add_action(*m_show_in_file_manager_action);
72
73 m_context_menu->add_separator();
74 m_copy_action = GUI::CommonActions::make_copy_action(
75 [this](auto&) {
76 auto url = URL::create_with_file_scheme(m_monitor_widget->wallpaper()).to_deprecated_string();
77 GUI::Clipboard::the().set_data(url.bytes(), "text/uri-list");
78 },
79 this);
80 m_context_menu->add_action(*m_copy_action);
81
82 m_wallpaper_view->on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
83 if (index.is_valid()) {
84 m_context_menu->popup(event.screen_position(), m_show_in_file_manager_action);
85 }
86 };
87
88 auto& button = *find_descendant_of_type_named<GUI::Button>("wallpaper_open_button");
89 button.on_click = [this](auto) {
90 auto path = GUI::FilePicker::get_open_filepath(window(), "Select wallpaper from file system", "/res/wallpapers"sv, false, GUI::Dialog::ScreenPosition::CenterWithinParent, { { GUI::FileTypeFilter::image_files(), GUI::FileTypeFilter::all_files() } });
91 if (!path.has_value())
92 return;
93 m_wallpaper_view->selection().clear();
94 m_monitor_widget->set_wallpaper(path.value());
95 m_background_settings_changed = true;
96 set_modified(true);
97 };
98
99 m_mode_combo = *find_descendant_of_type_named<GUI::ComboBox>("mode_combo");
100 m_mode_combo->set_only_allow_values_from_model(true);
101 m_mode_combo->set_model(*GUI::ItemListModel<DeprecatedString>::create(m_modes));
102 bool first_mode_change = true;
103 m_mode_combo->on_change = [this, first_mode_change](auto&, const GUI::ModelIndex& index) mutable {
104 m_monitor_widget->set_wallpaper_mode(m_modes.at(index.row()));
105 m_background_settings_changed = !first_mode_change;
106 first_mode_change = false;
107 set_modified(true);
108 };
109
110 m_color_input = *find_descendant_of_type_named<GUI::ColorInput>("color_input");
111 m_color_input->set_color_has_alpha_channel(false);
112 m_color_input->set_color_picker_title("Select color for desktop");
113 bool first_color_change = true;
114 m_color_input->on_change = [this, first_color_change]() mutable {
115 m_monitor_widget->set_background_color(m_color_input->color());
116 m_background_settings_changed = !first_color_change;
117 first_color_change = false;
118 set_modified(true);
119 };
120}
121
122void BackgroundSettingsWidget::load_current_settings()
123{
124 auto ws_config = Core::ConfigFile::open("/etc/WindowServer.ini").release_value_but_fixme_should_propagate_errors();
125
126 auto selected_wallpaper = Config::read_string("WindowManager"sv, "Background"sv, "Wallpaper"sv, ""sv);
127 if (!selected_wallpaper.is_empty()) {
128 auto index = static_cast<GUI::FileSystemModel*>(m_wallpaper_view->model())->index(selected_wallpaper, m_wallpaper_view->model_column());
129 m_wallpaper_view->set_cursor(index, GUI::AbstractView::SelectionUpdate::Set);
130 m_monitor_widget->set_wallpaper(selected_wallpaper);
131 }
132
133 auto mode = ws_config->read_entry("Background", "Mode", "Center");
134 if (!m_modes.contains_slow(mode)) {
135 warnln("Invalid background mode '{}' in WindowServer config, falling back to 'Center'", mode);
136 mode = "Center";
137 }
138 m_monitor_widget->set_wallpaper_mode(mode);
139 m_mode_combo->set_selected_index(m_modes.find_first_index(mode).value_or(0), GUI::AllowCallback::No);
140
141 auto palette_desktop_color = palette().desktop_background();
142 auto background_color = ws_config->read_entry("Background", "Color", "");
143
144 if (!background_color.is_empty()) {
145 auto opt_color = Color::from_string(background_color);
146 if (opt_color.has_value())
147 palette_desktop_color = opt_color.value();
148 }
149
150 m_color_input->set_color(palette_desktop_color, GUI::AllowCallback::No);
151 m_monitor_widget->set_background_color(palette_desktop_color);
152 m_background_settings_changed = false;
153}
154
155void BackgroundSettingsWidget::apply_settings()
156{
157 if (!GUI::Desktop::the().set_wallpaper(m_monitor_widget->wallpaper_bitmap(), m_monitor_widget->wallpaper()))
158 GUI::MessageBox::show_error(window(), DeprecatedString::formatted("Unable to load file {} as wallpaper", m_monitor_widget->wallpaper()));
159
160 GUI::Desktop::the().set_background_color(m_color_input->text());
161 GUI::Desktop::the().set_wallpaper_mode(m_monitor_widget->wallpaper_mode());
162}
163
164}