Serenity Operating System
at hosted 384 lines 17 kB view raw
1/* 2 * Copyright (c) 2019-2020, Jesse Buhagiar <jooster669@gmail.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "DisplayProperties.h" 28#include "ItemListModel.h" 29#include <AK/StringBuilder.h> 30#include <LibCore/ConfigFile.h> 31#include <LibCore/DirIterator.h> 32#include <LibGUI/Application.h> 33#include <LibGUI/BoxLayout.h> 34#include <LibGUI/Button.h> 35#include <LibGUI/ColorPicker.h> 36#include <LibGUI/ComboBox.h> 37#include <LibGUI/Desktop.h> 38#include <LibGUI/FilePicker.h> 39#include <LibGUI/Label.h> 40#include <LibGUI/MessageBox.h> 41#include <LibGUI/TextBox.h> 42#include <LibGUI/ToolBar.h> 43#include <LibGUI/Widget.h> 44#include <LibGUI/Window.h> 45#include <LibGUI/WindowServerConnection.h> 46#include <Servers/WindowServer/WindowManager.h> 47 48//#define DEBUG_MODE 49 50DisplayPropertiesWidget::DisplayPropertiesWidget() 51{ 52 create_resolution_list(); 53 create_wallpaper_list(); 54 55 create_frame(); 56 57 load_current_settings(); 58} 59 60void DisplayPropertiesWidget::create_resolution_list() 61{ 62 // TODO: Find a better way to get the default resolution 63 m_resolutions.append({ 640, 480 }); 64 m_resolutions.append({ 800, 600 }); 65 m_resolutions.append({ 1024, 768 }); 66 m_resolutions.append({ 1280, 720 }); 67 m_resolutions.append({ 1280, 768 }); 68 m_resolutions.append({ 1280, 1024 }); 69 m_resolutions.append({ 1360, 768 }); 70 m_resolutions.append({ 1368, 768 }); 71 m_resolutions.append({ 1440, 900 }); 72 m_resolutions.append({ 1600, 900 }); 73 m_resolutions.append({ 1920, 1080 }); 74 m_resolutions.append({ 2560, 1080 }); 75} 76 77void DisplayPropertiesWidget::create_wallpaper_list() 78{ 79 Core::DirIterator iterator("/res/wallpapers/", Core::DirIterator::Flags::SkipDots); 80 81 while (iterator.has_next()) { 82 m_wallpapers.append(iterator.next_path()); 83 } 84 85 m_modes.append("simple"); 86 m_modes.append("tile"); 87 m_modes.append("center"); 88 m_modes.append("scaled"); 89} 90 91void DisplayPropertiesWidget::create_frame() 92{ 93 m_root_widget = GUI::Widget::construct(); 94 m_root_widget->set_layout<GUI::VerticalBoxLayout>(); 95 m_root_widget->set_fill_with_background_color(true); 96 m_root_widget->layout()->set_margins({ 4, 4, 4, 4 }); 97 98 auto& settings_content = m_root_widget->add<GUI::Widget>(); 99 settings_content.set_layout<GUI::VerticalBoxLayout>(); 100 settings_content.set_backcolor("red"); 101 settings_content.set_background_color(Color::Blue); 102 settings_content.set_background_role(ColorRole::Window); 103 settings_content.layout()->set_margins({ 4, 4, 4, 4 }); 104 105 /// Wallpaper Preview ///////////////////////////////////////////////////////////////////////// 106 107 m_monitor_widget = settings_content.add<MonitorWidget>(); 108 m_monitor_widget->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); 109 m_monitor_widget->set_preferred_size(338, 248); 110 111 /// Wallpaper Row ///////////////////////////////////////////////////////////////////////////// 112 113 auto& m_wallpaper_selection_container = settings_content.add<GUI::Widget>(); 114 m_wallpaper_selection_container.set_layout<GUI::HorizontalBoxLayout>(); 115 m_wallpaper_selection_container.layout()->set_margins({ 0, 4, 0, 0 }); 116 m_wallpaper_selection_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 117 m_wallpaper_selection_container.set_preferred_size(0, 22); 118 119 auto& m_wallpaper_label = m_wallpaper_selection_container.add<GUI::Label>(); 120 m_wallpaper_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); 121 m_wallpaper_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); 122 m_wallpaper_label.set_preferred_size({ 70, 0 }); 123 m_wallpaper_label.set_text("Wallpaper:"); 124 125 m_wallpaper_combo = m_wallpaper_selection_container.add<GUI::ComboBox>(); 126 m_wallpaper_combo->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 127 m_wallpaper_combo->set_preferred_size(0, 22); 128 m_wallpaper_combo->set_only_allow_values_from_model(true); 129 m_wallpaper_combo->set_model(*ItemListModel<AK::String>::create(m_wallpapers)); 130 m_wallpaper_combo->on_change = [this](auto& text, const GUI::ModelIndex& index) { 131 String path = text; 132 if (index.is_valid()) { 133 134 StringBuilder builder; 135 builder.append("/res/wallpapers/"); 136 builder.append(path); 137 path = builder.to_string(); 138 } 139 140#ifdef DEBUG_MODE 141 dbg() << "New wallpaper path:" << path; 142#endif 143 144 this->m_monitor_widget->set_wallpaper(path); 145 this->m_monitor_widget->update(); 146 }; 147 148 auto& button = m_wallpaper_selection_container.add<GUI::Button>(); 149 button.set_tooltip("Select Wallpaper from file system."); 150 button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/open.png")); 151 button.set_button_style(Gfx::ButtonStyle::CoolBar); 152 button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); 153 button.set_preferred_size(22, 22); 154 button.on_click = [this]() { 155 Optional<String> open_path = GUI::FilePicker::get_open_filepath("Select wallpaper from file system"); 156 157 if (!open_path.has_value()) 158 return; 159 160#ifdef DEBUG_MODE 161 dbg() << "Selected file : " << open_path.value(); 162#endif 163 164 m_wallpaper_combo->set_only_allow_values_from_model(false); 165 this->m_wallpaper_combo->set_text(open_path.value()); 166 m_wallpaper_combo->set_only_allow_values_from_model(true); 167 }; 168 169 /// Mode ////////////////////////////////////////////////////////////////////////////////////// 170 171 auto& m_mode_selection_container = settings_content.add<GUI::Widget>(); 172 m_mode_selection_container.set_layout<GUI::HorizontalBoxLayout>(); 173 m_mode_selection_container.layout()->set_margins({ 0, 4, 0, 0 }); 174 m_mode_selection_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 175 m_mode_selection_container.set_preferred_size(0, 22); 176 177 auto& m_mode_label = m_mode_selection_container.add<GUI::Label>(); 178 m_mode_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); 179 m_mode_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); 180 m_mode_label.set_preferred_size({ 70, 0 }); 181 m_mode_label.set_text("Mode:"); 182 183 m_mode_combo = m_mode_selection_container.add<GUI::ComboBox>(); 184 m_mode_combo->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 185 m_mode_combo->set_preferred_size(0, 22); 186 m_mode_combo->set_only_allow_values_from_model(true); 187 m_mode_combo->set_model(*ItemListModel<AK::String>::create(m_modes)); 188 m_mode_combo->on_change = [this](auto&, const GUI::ModelIndex& index) { 189 this->m_monitor_widget->set_wallpaper_mode(m_modes.at(index.row())); 190 this->m_monitor_widget->update(); 191 }; 192 193 /// Resulation Row //////////////////////////////////////////////////////////////////////////// 194 195 auto& m_resolution_selection_container = settings_content.add<GUI::Widget>(); 196 m_resolution_selection_container.set_layout<GUI::HorizontalBoxLayout>(); 197 m_resolution_selection_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 198 m_resolution_selection_container.set_preferred_size(0, 22); 199 200 auto& m_resolution_label = m_resolution_selection_container.add<GUI::Label>(); 201 m_resolution_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); 202 m_resolution_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); 203 m_resolution_label.set_preferred_size({ 70, 0 }); 204 m_resolution_label.set_text("Resolution:"); 205 206 m_resolution_combo = m_resolution_selection_container.add<GUI::ComboBox>(); 207 m_resolution_combo->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 208 m_resolution_combo->set_preferred_size(0, 22); 209 m_resolution_combo->set_only_allow_values_from_model(true); 210 m_resolution_combo->set_model(*ItemListModel<Gfx::Size>::create(m_resolutions)); 211 m_resolution_combo->on_change = [this](auto&, const GUI::ModelIndex& index) { 212 this->m_monitor_widget->set_desktop_resolution(m_resolutions.at(index.row())); 213 this->m_monitor_widget->update(); 214 }; 215 216 /// Background Color Row ////////////////////////////////////////////////////////////////////// 217 218 auto& m_color_selection_container = settings_content.add<GUI::Widget>(); 219 m_color_selection_container.set_layout<GUI::HorizontalBoxLayout>(); 220 m_color_selection_container.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 221 m_color_selection_container.set_preferred_size(0, 22); 222 223 auto& m_color_label = m_color_selection_container.add<GUI::Label>(); 224 m_color_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); 225 m_color_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); 226 m_color_label.set_preferred_size({ 70, 0 }); 227 m_color_label.set_text("Color Name:"); 228 229 m_color_textbox = m_color_selection_container.add<GUI::TextBox>(); 230 m_color_textbox->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill); 231 m_color_textbox->set_preferred_size({ 0, 0 }); 232 m_color_textbox->on_change = [this] { 233 auto optional = Color::from_string(this->m_color_textbox->text()); 234 if (!optional.has_value()) 235 return; 236 237 this->m_monitor_widget->set_background_color(optional.value()); 238 this->m_monitor_widget->update(); 239 }; 240 241 auto& color_button = m_color_selection_container.add<GUI::Button>(); 242 color_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); 243 color_button.set_preferred_size(22, 0); 244 color_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/color-chooser.png")); 245 color_button.set_tooltip("Color Chooser"); 246 color_button.on_click = [this]() { 247 auto optional = Color::from_string(this->m_color_textbox->text()); 248 249 Color default_color = this->palette().desktop_background(); 250 if (optional.has_value()) 251 default_color = optional.value(); 252 253 auto dialog = GUI::ColorPicker::construct(default_color, window()); 254 if (dialog->exec() == GUI::Dialog::ExecOK) { 255 auto tmp = dialog->color(); 256 m_color_textbox->set_text(tmp.to_string()); 257 } 258 }; 259 260 /// Add the apply and cancel buttons ////////////////////////////////////////////////////////// 261 262 auto& bottom_widget = settings_content.add<GUI::Widget>(); 263 bottom_widget.set_layout<GUI::HorizontalBoxLayout>(); 264 bottom_widget.layout()->add_spacer(); 265 //bottom_widget.layout()->set_margins({ 4, 10, 4, 10 }); 266 bottom_widget.set_size_policy(Orientation::Vertical, GUI::SizePolicy::Fixed); 267 bottom_widget.set_preferred_size(1, 22); 268 269 auto& apply_button = bottom_widget.add<GUI::Button>(); 270 apply_button.set_text("Apply"); 271 apply_button.set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 272 apply_button.set_preferred_size(60, 22); 273 apply_button.on_click = [this] { 274 send_settings_to_window_server(); 275 }; 276 277 auto& ok_button = bottom_widget.add<GUI::Button>(); 278 ok_button.set_text("OK"); 279 ok_button.set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 280 ok_button.set_preferred_size(60, 22); 281 ok_button.on_click = [this] { 282 send_settings_to_window_server(); 283 GUI::Application::the().quit(); 284 }; 285 286 auto& cancel_button = bottom_widget.add<GUI::Button>(); 287 cancel_button.set_text("Cancel"); 288 cancel_button.set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 289 cancel_button.set_preferred_size(60, 22); 290 cancel_button.on_click = [] { 291 GUI::Application::the().quit(); 292 }; 293} 294 295void DisplayPropertiesWidget::load_current_settings() 296{ 297 auto m_ws_config(Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini")); 298 auto wm_config = Core::ConfigFile::get_for_app("WindowManager"); 299 300 /// Wallpaper path //////////////////////////////////////////////////////////////////////////// 301 /// Read wallpaper path from config file and set value to monitor widget and combo box. 302 auto m_selected_wallpaper = wm_config->read_entry("Background", "Wallpaper", ""); 303 if (!m_selected_wallpaper.is_empty()) { 304 m_monitor_widget->set_wallpaper(m_selected_wallpaper); 305 306 Optional<size_t> optional_index; 307 if (m_selected_wallpaper.starts_with("/res/wallpapers/")) { 308 auto name_parts = m_selected_wallpaper.split('/'); 309 optional_index = m_wallpapers.find_first_index(name_parts[2]); 310 311 if (optional_index.has_value()) { 312 m_wallpaper_combo->set_selected_index(optional_index.value()); 313 } 314 } 315 316 if (!optional_index.has_value()) { 317 m_wallpaper_combo->set_only_allow_values_from_model(false); 318 m_wallpaper_combo->set_text(m_selected_wallpaper); 319 m_wallpaper_combo->set_only_allow_values_from_model(true); 320 } 321 } 322 323 /// Mode ////////////////////////////////////////////////////////////////////////////////////// 324 auto mode = m_ws_config->read_entry("Background", "Mode"); 325 if (!mode.is_empty()) { 326 this->m_monitor_widget->set_wallpaper_mode(mode); 327 auto index = m_modes.find_first_index(mode).value(); 328 m_mode_combo->set_selected_index(index); 329 } 330 331 /// Resolution //////////////////////////////////////////////////////////////////////////////// 332 Gfx::Size find_size; 333 334 bool okay = false; 335 // Let's attempt to find the current resolution and select it! 336 find_size.set_width(m_ws_config->read_entry("Screen", "Width", "1024").to_int(okay)); 337 if (!okay) { 338 fprintf(stderr, "DisplayProperties: failed to convert width to int!"); 339 ASSERT_NOT_REACHED(); 340 } 341 342 find_size.set_height(m_ws_config->read_entry("Screen", "Height", "768").to_int(okay)); 343 if (!okay) { 344 fprintf(stderr, "DisplayProperties: failed to convert height to int!"); 345 ASSERT_NOT_REACHED(); 346 } 347 348 size_t index = m_resolutions.find_first_index(find_size).value_or(0); 349 Gfx::Size m_current_resolution = m_resolutions.at(index); 350 m_monitor_widget->set_desktop_resolution(m_current_resolution); 351 m_resolution_combo->set_selected_index(index); 352 353 /// Color ///////////////////////////////////////////////////////////////////////////////////// 354 /// If presend read from config file. If not paint with palet color. 355 auto background_color = m_ws_config->read_entry("Background", "Color", ""); 356 if (!background_color.is_empty()) { 357 m_color_textbox->set_text(background_color); 358 m_monitor_widget->set_background_color(Color::from_string(background_color).value()); 359 } else { 360 Color palette_desktop_color = this->palette().desktop_background(); 361 m_monitor_widget->set_background_color(palette_desktop_color); 362 } 363 364 m_monitor_widget->update(); 365} 366 367void DisplayPropertiesWidget::send_settings_to_window_server() 368{ 369 auto result = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(m_monitor_widget->desktop_resolution()); 370 if (!result->success()) { 371 GUI::MessageBox::show(String::format("Reverting to resolution %dx%d", result->resolution().width(), result->resolution().height()), 372 String::format("Unable to set resolution"), GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK); 373 } 374 375 if (!m_monitor_widget->wallpaper().is_empty()) { 376 GUI::Desktop::the().set_wallpaper(m_monitor_widget->wallpaper()); 377 } 378 379 GUI::Desktop::the().set_wallpaper_mode(m_monitor_widget->wallpaper_mode()); 380 381 if (!m_color_textbox->text().is_empty()) { 382 GUI::Desktop::the().set_background_color(m_color_textbox->text()); 383 } 384}