Serenity Operating System
at portability 229 lines 9.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 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/DirIterator.h> 31#include <LibGUI/Action.h> 32#include <LibGUI/Application.h> 33#include <LibGUI/BoxLayout.h> 34#include <LibGUI/Button.h> 35#include <LibGUI/Desktop.h> 36#include <LibGUI/FileSystemModel.h> 37#include <LibGUI/GroupBox.h> 38#include <LibGUI/Label.h> 39#include <LibGUI/ListView.h> 40#include <LibGUI/ScrollBar.h> 41#include <LibGUI/Splitter.h> 42#include <LibGUI/TabWidget.h> 43#include <LibGUI/ToolBar.h> 44#include <LibGUI/Widget.h> 45#include <LibGUI/Window.h> 46#include <LibGUI/WindowServerConnection.h> 47#include <Servers/WindowServer/WindowManager.h> 48 49DisplayPropertiesWidget::DisplayPropertiesWidget() 50 : m_wm_config(Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini")) 51{ 52 create_resolution_list(); 53 create_wallpaper_list(); 54 create_root_widget(); 55 create_frame(); 56} 57 58void DisplayPropertiesWidget::create_resolution_list() 59{ 60 // TODO: Find a better way to get the default resolution 61 m_resolutions.append({ 640, 480 }); 62 m_resolutions.append({ 800, 600 }); 63 m_resolutions.append({ 1024, 768 }); 64 m_resolutions.append({ 1280, 720 }); 65 m_resolutions.append({ 1280, 1024 }); 66 m_resolutions.append({ 1440, 900 }); 67 m_resolutions.append({ 1600, 900 }); 68 m_resolutions.append({ 1920, 1080 }); 69 m_resolutions.append({ 2560, 1080 }); 70 71 Gfx::Size find_size; 72 73 bool okay = false; 74 // Let's attempt to find the current resolution and select it! 75 find_size.set_width(m_wm_config->read_entry("Screen", "Width", "1024").to_int(okay)); 76 if (!okay) { 77 fprintf(stderr, "DisplayProperties: failed to convert width to int!"); 78 return; 79 } 80 81 find_size.set_height(m_wm_config->read_entry("Screen", "Height", "768").to_int(okay)); 82 if (!okay) { 83 fprintf(stderr, "DisplayProperties: failed to convert height to int!"); 84 return; 85 } 86 87 int index = 0; 88 for (auto& resolution : m_resolutions) { 89 if (resolution == find_size) { 90 m_selected_resolution = m_resolutions.at(index); 91 return; // We don't need to do anything else 92 } 93 94 index++; 95 } 96 97 m_selected_resolution = m_resolutions.at(0); 98} 99 100void DisplayPropertiesWidget::create_root_widget() 101{ 102 m_root_widget = GUI::Widget::construct(); 103 m_root_widget->set_layout(make<GUI::VerticalBoxLayout>()); 104 m_root_widget->set_fill_with_background_color(true); 105 m_root_widget->layout()->set_margins({ 4, 4, 4, 16 }); 106} 107 108void DisplayPropertiesWidget::create_wallpaper_list() 109{ 110 m_selected_wallpaper = m_wm_config->read_entry("Background", "Wallpaper"); 111 if (!m_selected_wallpaper.is_empty()) { 112 auto name_parts = m_selected_wallpaper.split('/'); 113 m_selected_wallpaper = name_parts[2]; 114 } 115 116 Core::DirIterator iterator("/res/wallpapers/", Core::DirIterator::Flags::SkipDots); 117 118 while (iterator.has_next()) { 119 m_wallpapers.append(iterator.next_path()); 120 } 121} 122 123void DisplayPropertiesWidget::create_frame() 124{ 125 auto tab_widget = m_root_widget->add<GUI::TabWidget>(); 126 127 auto wallpaper_splitter = tab_widget->add_tab<GUI::VerticalSplitter>("Wallpaper"); 128 129 auto wallpaper_content = wallpaper_splitter->add<GUI::Widget>(); 130 wallpaper_content->set_layout(make<GUI::VerticalBoxLayout>()); 131 wallpaper_content->layout()->set_margins({ 4, 4, 4, 4 }); 132 133 m_wallpaper_preview = wallpaper_splitter->add<GUI::Label>(); 134 135 auto wallpaper_list = wallpaper_content->add<GUI::ListView>(); 136 wallpaper_list->set_background_color(Color::White); 137 wallpaper_list->set_model(*ItemListModel<AK::String>::create(m_wallpapers)); 138 139 auto wallpaper_model = wallpaper_list->model(); 140 auto find_first_wallpaper_index = m_wallpapers.find_first_index(m_selected_wallpaper); 141 ASSERT(find_first_wallpaper_index.has_value()); 142 auto wallpaper_index_in_model = wallpaper_model->index(find_first_wallpaper_index.value(), wallpaper_list->model_column()); 143 if (wallpaper_model->is_valid(wallpaper_index_in_model)) 144 wallpaper_list->selection().set(wallpaper_index_in_model); 145 146 wallpaper_list->horizontal_scrollbar().set_visible(false); 147 wallpaper_list->on_selection = [this](auto& index) { 148 StringBuilder builder; 149 m_selected_wallpaper = m_wallpapers.at(index.row()); 150 builder.append("/res/wallpapers/"); 151 builder.append(m_selected_wallpaper); 152 m_wallpaper_preview->set_icon(Gfx::Bitmap::load_from_file(builder.to_string())); 153 m_wallpaper_preview->set_should_stretch_icon(true); 154 }; 155 156 auto settings_splitter = tab_widget->add_tab<GUI::VerticalSplitter>("Settings"); 157 158 auto settings_content = settings_splitter->add<GUI::Widget>(); 159 settings_content->set_layout(make<GUI::VerticalBoxLayout>()); 160 settings_content->layout()->set_margins({ 4, 4, 4, 4 }); 161 162 auto resolution_list = settings_content->add<GUI::ListView>(); 163 resolution_list->set_background_color(Color::White); 164 resolution_list->set_model(*ItemListModel<Gfx::Size>::create(m_resolutions)); 165 166 auto resolution_model = resolution_list->model(); 167 auto find_first_resolution_index = m_resolutions.find_first_index(m_selected_resolution); 168 ASSERT(find_first_resolution_index.has_value()); 169 auto resolution_index_in_model = resolution_model->index(find_first_resolution_index.value(), resolution_list->model_column()); 170 if (resolution_model->is_valid(resolution_index_in_model)) 171 resolution_list->selection().set(resolution_index_in_model); 172 173 resolution_list->horizontal_scrollbar().set_visible(false); 174 resolution_list->on_selection = [this](auto& index) { 175 m_selected_resolution = m_resolutions.at(index.row()); 176 }; 177 178 settings_content->layout()->add_spacer(); 179 180 // Add the apply and cancel buttons 181 auto bottom_widget = m_root_widget->add<GUI::Widget>(); 182 bottom_widget->set_layout(make<GUI::HorizontalBoxLayout>()); 183 bottom_widget->layout()->add_spacer(); 184 bottom_widget->set_size_policy(Orientation::Vertical, GUI::SizePolicy::Fixed); 185 bottom_widget->set_preferred_size(1, 22); 186 187 auto apply_button = bottom_widget->add<GUI::Button>(); 188 apply_button->set_text("Apply"); 189 apply_button->set_size_policy(Orientation::Vertical, GUI::SizePolicy::Fixed); 190 apply_button->set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 191 apply_button->set_preferred_size(60, 22); 192 apply_button->on_click = [this, tab_widget](GUI::Button&) { 193 send_settings_to_window_server(tab_widget->active_tab_index()); 194 }; 195 196 auto ok_button = bottom_widget->add<GUI::Button>(); 197 ok_button->set_text("OK"); 198 ok_button->set_size_policy(Orientation::Vertical, GUI::SizePolicy::Fixed); 199 ok_button->set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 200 ok_button->set_preferred_size(60, 22); 201 ok_button->on_click = [this, tab_widget](GUI::Button&) { 202 send_settings_to_window_server(tab_widget->active_tab_index()); 203 GUI::Application::the().quit(); 204 }; 205 206 auto cancel_button = bottom_widget->add<GUI::Button>(); 207 cancel_button->set_text("Cancel"); 208 cancel_button->set_size_policy(Orientation::Vertical, GUI::SizePolicy::Fixed); 209 cancel_button->set_size_policy(Orientation::Horizontal, GUI::SizePolicy::Fixed); 210 cancel_button->set_preferred_size(60, 22); 211 cancel_button->on_click = [](auto&) { 212 GUI::Application::the().quit(); 213 }; 214} 215 216void DisplayPropertiesWidget::send_settings_to_window_server(int tab_index) 217{ 218 if (tab_index == TabIndices::Wallpaper) { 219 StringBuilder builder; 220 builder.append("/res/wallpapers/"); 221 builder.append(m_selected_wallpaper); 222 GUI::Desktop::the().set_wallpaper(builder.to_string()); 223 } else if (tab_index == TabIndices::Settings) { 224 dbg() << "Attempting to set resolution " << m_selected_resolution; 225 GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(m_selected_resolution); 226 } else { 227 dbg() << "Invalid tab index " << tab_index; 228 } 229}