diff options
author | Daniël van de Burgt <209150+thatdutchguy@users.noreply.github.com> | 2021-04-02 07:08:18 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-02 16:08:18 +0200 |
commit | a106f852d3171ae35a4e09870cbb2aef24c2fd10 (patch) | |
tree | 1cf61fdddc03f330edb2d1d27514668521dd993e | |
parent | e55b8712d4831296ee8de48d17022f2aab9d7a62 (diff) | |
download | serenity-a106f852d3171ae35a4e09870cbb2aef24c2fd10.zip |
WindowServer+MouseSettings: Add ability to configure double-click speed (#5876)
This adds a double-click speed slider control to the Mouse Settings
panel, and value labels for both the movement speed and double-click
speed sliders.
To allow for updating and persisting the configured double-click
speed through the WindowServer, two IPC calls - `SetDoubleClickSpeed`
and `GetDoubleClickSpeed` - have been added.
10 files changed, 315 insertions, 70 deletions
diff --git a/Userland/Applications/MouseSettings/CMakeLists.txt b/Userland/Applications/MouseSettings/CMakeLists.txt index f52df8d76c..297d264054 100644 --- a/Userland/Applications/MouseSettings/CMakeLists.txt +++ b/Userland/Applications/MouseSettings/CMakeLists.txt @@ -1,5 +1,10 @@ +compile_gml(MouseSettingsWindow.gml MouseSettingsWindowGML.h mouse_settings_window_gml) + set(SOURCES main.cpp + MouseSettingsWindow.cpp + MouseSettingsWindow.h + MouseSettingsWindowGML.h ) serenity_app(MouseSettings ICON app-mouse) diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp b/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp new file mode 100644 index 0000000000..e31b657725 --- /dev/null +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020, Idan Horowitz <idan.horowitz@gmail.com> + * Copyright (c) 2021, the SerenityOS developers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "MouseSettingsWindow.h" +#include <Applications/MouseSettings/MouseSettingsWindowGML.h> +#include <LibGUI/Application.h> +#include <LibGUI/Button.h> +#include <LibGUI/Event.h> +#include <LibGUI/Label.h> +#include <LibGUI/Widget.h> +#include <LibGUI/Window.h> +#include <LibGUI/WindowServerConnection.h> +#include <WindowServer/Screen.h> +#include <WindowServer/WindowManager.h> + +constexpr double speed_slider_scale = 100.0; +constexpr int default_scroll_length = 4; +constexpr int double_click_speed_default = 250; + +void MouseSettingsWindow::update_window_server() +{ + const float factor = m_speed_slider->value() / speed_slider_scale; + GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetMouseAcceleration>(factor); + GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetScrollStepSize>(m_scroll_length_spinbox->value()); + GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetDoubleClickSpeed>(m_double_click_speed_slider->value()); +} + +void MouseSettingsWindow::reset_default_values() +{ + m_speed_slider->set_value(speed_slider_scale); + m_scroll_length_spinbox->set_value(default_scroll_length); + m_double_click_speed_slider->set_value(double_click_speed_default); + update_window_server(); +} + +MouseSettingsWindow::MouseSettingsWindow() +{ + auto& main_widget = set_main_widget<GUI::Widget>(); + main_widget.load_from_gml(mouse_settings_window_gml); + + m_speed_label = *main_widget.find_descendant_of_type_named<GUI::Label>("speed_label"); + m_speed_slider = *main_widget.find_descendant_of_type_named<GUI::HorizontalSlider>("speed_slider"); + m_speed_slider->set_range(WindowServer::mouse_accel_min * speed_slider_scale, WindowServer::mouse_accel_max * speed_slider_scale); + m_speed_slider->on_change = [&](const int value) { + m_speed_label->set_text(String::formatted("{} %", value)); + }; + const int slider_value = speed_slider_scale * GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetMouseAcceleration>()->factor(); + m_speed_slider->set_value(slider_value); + + m_scroll_length_spinbox = *main_widget.find_descendant_of_type_named<GUI::SpinBox>("scroll_length_spinbox"); + m_scroll_length_spinbox->set_min(WindowServer::scroll_step_size_min); + m_scroll_length_spinbox->set_value(GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetScrollStepSize>()->step_size()); + + m_double_click_speed_label = *main_widget.find_descendant_of_type_named<GUI::Label>("double_click_speed_label"); + m_double_click_speed_slider = *main_widget.find_descendant_of_type_named<GUI::HorizontalSlider>("double_click_speed_slider"); + m_double_click_speed_slider->set_min(WindowServer::double_click_speed_min); + m_double_click_speed_slider->set_max(WindowServer::double_click_speed_max); + m_double_click_speed_slider->on_change = [&](const int value) { + m_double_click_speed_label->set_text(String::formatted("{} ms", value)); + }; + m_double_click_speed_slider->set_value(GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetDoubleClickSpeed>()->speed()); + + m_ok_button = *main_widget.find_descendant_of_type_named<GUI::Button>("ok_button"); + m_ok_button->on_click = [this](auto) { + update_window_server(); + GUI::Application::the()->quit(); + }; + + m_apply_button = *main_widget.find_descendant_of_type_named<GUI::Button>("apply_button"); + m_apply_button->on_click = [this](auto) { + update_window_server(); + }; + + m_reset_button = *main_widget.find_descendant_of_type_named<GUI::Button>("reset_button"); + m_reset_button->on_click = [this](auto) { + reset_default_values(); + }; +} + +MouseSettingsWindow::~MouseSettingsWindow() +{ +} diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.gml b/Userland/Applications/MouseSettings/MouseSettingsWindow.gml new file mode 100644 index 0000000000..96c6ec6e9c --- /dev/null +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.gml @@ -0,0 +1,105 @@ +@GUI::Widget { + fill_with_background_color: true + + layout: @GUI::VerticalBoxLayout { + margins: [4, 4, 4, 4] + } + + @GUI::GroupBox { + title: "Mouse speed" + fixed_height: 60 + + layout: @GUI::HorizontalBoxLayout { + margins: [6, 16, 8, 6] + } + + @GUI::HorizontalSlider { + name: "speed_slider" + max: 3500 + min: 500 + value: 100 + } + + @GUI::Label { + name: "speed_label" + text: "100.0 %" + fixed_width: 50 + text_alignment: "CenterRight" + } + } + + @GUI::GroupBox { + title: "Scroll length" + fixed_height: 60 + + layout: @GUI::HorizontalBoxLayout { + margins: [16, 16, 8, 6] + } + + @GUI::Label { + text: "Scroll by " + autosize: true + text_alignment: "CenterLeft" + } + + @GUI::SpinBox { + name: "scroll_length_spinbox" + max: 32 + min: 1 + value: 4 + text_alignment: "CenterRight" + fixed_width: 80 + } + + @GUI::Label { + text: " lines at a time" + text_alignent: "CenterLeft" + autosize: true + } + } + + @GUI::GroupBox { + title: "Double-click speed" + fixed_height: 60 + + layout: @GUI::HorizontalBoxLayout { + margins: [6, 16, 8, 6] + } + + @GUI::HorizontalSlider { + name: "double_click_speed_slider" + max: 900 + min: 100 + value: 250 + } + + @GUI::Label { + name: "double_click_speed_label" + text: "250 ms" + fixed_width: 50 + text_alignment: "CenterRight" + } + } + + @GUI::Widget { + fixed_height: 22 + + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::Button { + name: "ok_button" + text: "OK" + } + + @GUI::Button { + name: "apply_button" + text: "Apply" + } + + @GUI::Button { + name: "reset_button" + text: "Reset" + } + } +} diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.h b/Userland/Applications/MouseSettings/MouseSettingsWindow.h new file mode 100644 index 0000000000..7c09d85e01 --- /dev/null +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, Idan Horowitz <idan.horowitz@gmail.com> + * Copyright (c) 2021, the SerenityOS developers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <LibGUI/Button.h> +#include <LibGUI/Slider.h> +#include <LibGUI/SpinBox.h> +#include <LibGUI/Window.h> + +class MouseSettingsWindow final : public GUI::Window { + C_OBJECT(MouseSettingsWindow) +public: + virtual ~MouseSettingsWindow() override; + +private: + MouseSettingsWindow(); + + void update_window_server(); + void reset_default_values(); + + RefPtr<GUI::HorizontalSlider> m_speed_slider; + RefPtr<GUI::Label> m_speed_label; + RefPtr<GUI::SpinBox> m_scroll_length_spinbox; + RefPtr<GUI::HorizontalSlider> m_double_click_speed_slider; + RefPtr<GUI::Label> m_double_click_speed_label; + RefPtr<GUI::Button> m_ok_button; + RefPtr<GUI::Button> m_apply_button; + RefPtr<GUI::Button> m_reset_button; +}; diff --git a/Userland/Applications/MouseSettings/main.cpp b/Userland/Applications/MouseSettings/main.cpp index 451cd960ba..a9e114daa3 100644 --- a/Userland/Applications/MouseSettings/main.cpp +++ b/Userland/Applications/MouseSettings/main.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Idan Horowitz <idan.horowitz@gmail.com> + * Copyright (c) 2021, the SerenityOS developers * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,21 +25,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "MouseSettingsWindow.h" #include <LibGUI/Action.h> #include <LibGUI/Application.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/Button.h> -#include <LibGUI/GroupBox.h> #include <LibGUI/Icon.h> #include <LibGUI/Menu.h> #include <LibGUI/MenuBar.h> -#include <LibGUI/Slider.h> -#include <LibGUI/SpinBox.h> -#include <LibGUI/Widget.h> -#include <LibGUI/Window.h> -#include <LibGUI/WindowServerConnection.h> -#include <LibGfx/SystemTheme.h> -#include <WindowServer/Screen.h> +#include <unistd.h> int main(int argc, char** argv) { @@ -55,75 +48,20 @@ int main(int argc, char** argv) } auto app_icon = GUI::Icon::default_icon("app-mouse"); - auto window = GUI::Window::construct(); + + auto window = MouseSettingsWindow::construct(); window->set_title("Mouse Settings"); - window->resize(200, 130); + window->resize(300, 220); window->set_resizable(false); + window->set_minimizable(false); window->set_icon(app_icon.bitmap_for_size(16)); - auto& settings = window->set_main_widget<GUI::Widget>(); - settings.set_fill_with_background_color(true); - settings.set_background_role(ColorRole::Button); - settings.set_layout<GUI::VerticalBoxLayout>(); - settings.layout()->set_margins({ 4, 4, 4, 4 }); - - auto& speed_container = settings.add<GUI::GroupBox>("Mouse speed"); - speed_container.set_layout<GUI::VerticalBoxLayout>(); - speed_container.layout()->set_margins({ 6, 16, 6, 6 }); - speed_container.set_fixed_height(50); - - auto& speed_slider = speed_container.add<GUI::HorizontalSlider>(); - const auto scalar = 1000.0; - speed_slider.set_range(WindowServer::mouse_accel_min * scalar, WindowServer::mouse_accel_max * scalar); // These values are scaled down (by a factor of 1000) to get fractional values - int current_value = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetMouseAcceleration>()->factor() * scalar; - speed_slider.set_value(current_value); - - auto& scroll_container = settings.add<GUI::GroupBox>("Scroll length"); - scroll_container.set_layout<GUI::VerticalBoxLayout>(); - scroll_container.layout()->set_margins({ 6, 16, 6, 6 }); - scroll_container.set_fixed_height(46); - - auto& scroll_spinbox = scroll_container.add<GUI::SpinBox>(); - scroll_spinbox.set_min(WindowServer::scroll_step_size_min); - scroll_spinbox.set_value(GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetScrollStepSize>()->step_size()); - - auto update_window_server = [&]() { - float factor = speed_slider.value() / scalar; - GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetMouseAcceleration>(factor); - GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetScrollStepSize>(scroll_spinbox.value()); - }; - - auto& prompt_buttons = settings.add<GUI::Widget>(); - prompt_buttons.set_layout<GUI::HorizontalBoxLayout>(); - prompt_buttons.set_fixed_height(22); - - auto& ok_button = prompt_buttons.add<GUI::Button>(); - ok_button.set_text("OK"); - prompt_buttons.set_fixed_height(22); - ok_button.on_click = [&](auto) { - update_window_server(); - app->quit(); - }; - auto& apply_button = prompt_buttons.add<GUI::Button>(); - apply_button.set_text("Apply"); - prompt_buttons.set_fixed_height(22); - apply_button.on_click = [&](auto) { - update_window_server(); - }; - auto& reset_button = prompt_buttons.add<GUI::Button>(); - reset_button.set_text("Reset"); - prompt_buttons.set_fixed_height(22); - reset_button.on_click = [&](auto) { - speed_slider.set_value(scalar); - scroll_spinbox.set_value(4); - update_window_server(); - }; - auto menubar = GUI::MenuBar::construct(); auto& app_menu = menubar->add_menu("File"); app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { app->quit(); })); + auto& help_menu = menubar->add_menu("Help"); help_menu.add_action(GUI::CommonActions::make_about_action("Mouse Settings", app_icon, window)); window->set_menubar(move(menubar)); diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 77ff8e1ab7..c49f8ad26d 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -966,6 +966,19 @@ OwnPtr<Messages::WindowServer::GetScrollStepSizeResponse> ClientConnection::hand { return make<Messages::WindowServer::GetScrollStepSizeResponse>(Screen::the().scroll_step_size()); } +OwnPtr<Messages::WindowServer::SetDoubleClickSpeedResponse> ClientConnection::handle(const Messages::WindowServer::SetDoubleClickSpeed& message) +{ + if (message.speed() < double_click_speed_min || message.speed() > double_click_speed_max) { + did_misbehave("SetDoubleClickSpeed with bad speed"); + return {}; + } + WindowManager::the().set_double_click_speed(message.speed()); + return make<Messages::WindowServer::SetDoubleClickSpeedResponse>(); +} +OwnPtr<Messages::WindowServer::GetDoubleClickSpeedResponse> ClientConnection::handle(const Messages::WindowServer::GetDoubleClickSpeed&) +{ + return make<Messages::WindowServer::GetDoubleClickSpeedResponse>(WindowManager::the().double_click_speed()); +} void ClientConnection::set_unresponsive(bool unresponsive) { diff --git a/Userland/Services/WindowServer/ClientConnection.h b/Userland/Services/WindowServer/ClientConnection.h index 198775adc9..37ea4eff2e 100644 --- a/Userland/Services/WindowServer/ClientConnection.h +++ b/Userland/Services/WindowServer/ClientConnection.h @@ -169,6 +169,8 @@ private: virtual OwnPtr<Messages::WindowServer::SetScrollStepSizeResponse> handle(const Messages::WindowServer::SetScrollStepSize&) override; virtual OwnPtr<Messages::WindowServer::GetScrollStepSizeResponse> handle(const Messages::WindowServer::GetScrollStepSize&) override; virtual OwnPtr<Messages::WindowServer::GetScreenBitmapResponse> handle(const Messages::WindowServer::GetScreenBitmap&) override; + virtual OwnPtr<Messages::WindowServer::SetDoubleClickSpeedResponse> handle(const Messages::WindowServer::SetDoubleClickSpeed&) override; + virtual OwnPtr<Messages::WindowServer::GetDoubleClickSpeedResponse> handle(const Messages::WindowServer::GetDoubleClickSpeed&) override; Window* window_from_id(i32 window_id); diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index af56821c23..6af3600a33 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -171,6 +171,20 @@ void WindowManager::set_scroll_step_size(unsigned step_size) m_config->sync(); } +void WindowManager::set_double_click_speed(int speed) +{ + VERIFY(speed >= double_click_speed_min && speed <= double_click_speed_max); + m_double_click_speed = speed; + dbgln("Saving double-click speed {} to config file at {}", speed, m_config->file_name()); + m_config->write_entry("Input", "DoubleClickSpeed", String::number(speed)); + m_config->sync(); +} + +int WindowManager::double_click_speed() const +{ + return m_double_click_speed; +} + int WindowManager::scale_factor() const { return Screen::the().scale_factor(); diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 9fac9581c3..97e6901418 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -47,6 +47,9 @@ namespace WindowServer { +const int double_click_speed_max = 900; +const int double_click_speed_min = 100; + class Screen; class MouseEvent; class Window; @@ -151,6 +154,8 @@ public: void set_acceleration_factor(double); void set_scroll_step_size(unsigned); + void set_double_click_speed(int); + int double_click_speed() const; Window* set_active_input_window(Window*); void restore_active_input_window(Window*); diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index fa8d70462f..5d6287b32a 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -127,4 +127,7 @@ endpoint WindowServer = 2 GetScreenBitmap() => (Gfx::ShareableBitmap bitmap) Pong() =| + + SetDoubleClickSpeed(int speed) => () + GetDoubleClickSpeed() => (int speed) } |