BackgroundSettingsWidget.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. #include "BackgroundSettingsWidget.h"
  9. #include <AK/LexicalPath.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 <LibFileSystemAccessClient/Client.h>
  16. #include <LibGUI/Application.h>
  17. #include <LibGUI/BoxLayout.h>
  18. #include <LibGUI/Button.h>
  19. #include <LibGUI/Clipboard.h>
  20. #include <LibGUI/ComboBox.h>
  21. #include <LibGUI/ConnectionToWindowServer.h>
  22. #include <LibGUI/Desktop.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. namespace DisplaySettings {
  31. ErrorOr<NonnullRefPtr<BackgroundSettingsWidget>> BackgroundSettingsWidget::try_create(bool& background_settings_changed)
  32. {
  33. auto background_settings_widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) BackgroundSettingsWidget(background_settings_changed)));
  34. TRY(background_settings_widget->m_modes.try_append("Tile"_string));
  35. TRY(background_settings_widget->m_modes.try_append("Center"_string));
  36. TRY(background_settings_widget->m_modes.try_append("Stretch"_string));
  37. TRY(background_settings_widget->create_frame());
  38. TRY(background_settings_widget->load_current_settings());
  39. return background_settings_widget;
  40. }
  41. BackgroundSettingsWidget::BackgroundSettingsWidget(bool& background_settings_changed)
  42. : m_background_settings_changed { background_settings_changed }
  43. {
  44. }
  45. ErrorOr<void> BackgroundSettingsWidget::create_frame()
  46. {
  47. TRY(load_from_gml(background_settings_gml));
  48. m_monitor_widget = *find_descendant_of_type_named<DisplaySettings::MonitorWidget>("monitor_widget");
  49. m_wallpaper_view = *find_descendant_of_type_named<GUI::IconView>("wallpaper_view");
  50. m_wallpaper_view->set_model(GUI::FileSystemModel::create("/res/wallpapers"));
  51. m_wallpaper_view->set_model_column(GUI::FileSystemModel::Column::Name);
  52. m_wallpaper_view->on_selection_change = [this] {
  53. String path;
  54. if (!m_wallpaper_view->selection().is_empty()) {
  55. auto index = m_wallpaper_view->selection().first();
  56. auto path_or_error = String::from_byte_string(static_cast<GUI::FileSystemModel*>(m_wallpaper_view->model())->full_path(index));
  57. if (path_or_error.is_error()) {
  58. GUI::MessageBox::show_error(window(), "Unable to load wallpaper"sv);
  59. return;
  60. }
  61. path = path_or_error.release_value();
  62. }
  63. m_monitor_widget->set_wallpaper(path);
  64. set_modified(true);
  65. };
  66. m_context_menu = GUI::Menu::construct();
  67. auto const file_manager_icon = TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-file-manager.png"sv));
  68. m_show_in_file_manager_action = GUI::Action::create("Show in File Manager", file_manager_icon, [this](GUI::Action const&) {
  69. LexicalPath path { m_monitor_widget->wallpaper().value().to_byte_string() };
  70. Desktop::Launcher::open(URL::create_with_file_scheme(path.dirname(), path.basename()));
  71. });
  72. m_context_menu->add_action(*m_show_in_file_manager_action);
  73. m_context_menu->add_separator();
  74. m_copy_action = GUI::CommonActions::make_copy_action(
  75. [this](auto&) {
  76. auto wallpaper = m_monitor_widget->wallpaper();
  77. if (wallpaper.has_value()) {
  78. auto url = URL::create_with_file_scheme(wallpaper.value()).to_byte_string();
  79. GUI::Clipboard::the().set_data(url.bytes(), "text/uri-list");
  80. }
  81. },
  82. this);
  83. m_context_menu->add_action(*m_copy_action);
  84. m_wallpaper_view->on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
  85. if (index.is_valid()) {
  86. m_context_menu->popup(event.screen_position(), m_show_in_file_manager_action);
  87. }
  88. };
  89. auto& button = *find_descendant_of_type_named<GUI::Button>("wallpaper_open_button");
  90. button.on_click = [this](auto) {
  91. FileSystemAccessClient::OpenFileOptions options {
  92. .window_title = "Select Wallpaper"sv,
  93. .path = "/res/wallpapers"sv,
  94. .allowed_file_types = { { GUI::FileTypeFilter::image_files() } }
  95. };
  96. auto response = FileSystemAccessClient::Client::the().open_file(window(), options);
  97. if (response.is_error())
  98. return;
  99. m_wallpaper_view->selection().clear();
  100. m_monitor_widget->set_wallpaper(MUST(String::from_byte_string(response.release_value().filename())));
  101. m_background_settings_changed = true;
  102. set_modified(true);
  103. };
  104. m_mode_combo = *find_descendant_of_type_named<GUI::ComboBox>("mode_combo");
  105. m_mode_combo->set_only_allow_values_from_model(true);
  106. m_mode_combo->set_model(*GUI::ItemListModel<String>::create(m_modes));
  107. bool first_mode_change = true;
  108. m_mode_combo->on_change = [this, first_mode_change](auto&, const GUI::ModelIndex& index) mutable {
  109. m_monitor_widget->set_wallpaper_mode(m_modes.at(index.row()));
  110. m_background_settings_changed = !first_mode_change;
  111. first_mode_change = false;
  112. set_modified(true);
  113. };
  114. m_color_input = *find_descendant_of_type_named<GUI::ColorInput>("color_input");
  115. m_color_input->set_color_has_alpha_channel(false);
  116. m_color_input->set_color_picker_title("Select Desktop Color");
  117. bool first_color_change = true;
  118. m_color_input->on_change = [this, first_color_change]() mutable {
  119. m_monitor_widget->set_background_color(m_color_input->color());
  120. m_background_settings_changed = !first_color_change;
  121. first_color_change = false;
  122. set_modified(true);
  123. };
  124. return {};
  125. }
  126. ErrorOr<void> BackgroundSettingsWidget::load_current_settings()
  127. {
  128. auto ws_config = TRY(Core::ConfigFile::open("/etc/WindowServer.ini"));
  129. auto selected_wallpaper = TRY(String::from_byte_string(Config::read_string("WindowManager"sv, "Background"sv, "Wallpaper"sv, ""sv)));
  130. if (!selected_wallpaper.is_empty()) {
  131. auto index = static_cast<GUI::FileSystemModel*>(m_wallpaper_view->model())->index(selected_wallpaper.to_byte_string(), m_wallpaper_view->model_column());
  132. m_wallpaper_view->set_cursor(index, GUI::AbstractView::SelectionUpdate::Set);
  133. m_monitor_widget->set_wallpaper(selected_wallpaper);
  134. }
  135. auto mode = TRY(String::from_byte_string(ws_config->read_entry("Background", "Mode", "Center")));
  136. if (!m_modes.contains_slow(mode)) {
  137. warnln("Invalid background mode '{}' in WindowServer config, falling back to 'Center'", mode);
  138. mode = "Center"_string;
  139. }
  140. m_monitor_widget->set_wallpaper_mode(mode);
  141. m_mode_combo->set_selected_index(m_modes.find_first_index(mode).value_or(0), GUI::AllowCallback::No);
  142. auto palette_desktop_color = palette().desktop_background();
  143. auto background_color = ws_config->read_entry("Background", "Color", "");
  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. m_color_input->set_color(palette_desktop_color, GUI::AllowCallback::No);
  150. m_monitor_widget->set_background_color(palette_desktop_color);
  151. m_background_settings_changed = false;
  152. return {};
  153. }
  154. void BackgroundSettingsWidget::apply_settings()
  155. {
  156. auto wallpaper_path_or_empty = m_monitor_widget->wallpaper();
  157. if (!GUI::Desktop::the().set_wallpaper(m_monitor_widget->wallpaper_bitmap(), wallpaper_path_or_empty)) {
  158. if (!wallpaper_path_or_empty.has_value()) {
  159. GUI::MessageBox::show_error(window(), "Unable to load wallpaper"sv);
  160. } else {
  161. auto detailed_error_message = String::formatted("Unable to load file {} as wallpaper", wallpaper_path_or_empty.value());
  162. if (!detailed_error_message.is_error())
  163. GUI::MessageBox::show_error(window(), detailed_error_message.release_value());
  164. else
  165. GUI::MessageBox::show_error(window(), "Unable to load wallpaper"sv);
  166. }
  167. }
  168. GUI::Desktop::the().set_background_color(m_color_input->text());
  169. GUI::Desktop::the().set_wallpaper_mode(m_monitor_widget->wallpaper_mode());
  170. }
  171. }