diff --git a/Base/etc/shellrc b/Base/etc/shellrc index 92d8fd10db..33b40ba1b9 100644 --- a/Base/etc/shellrc +++ b/Base/etc/shellrc @@ -2,6 +2,7 @@ alias fm=FileManager alias irc=IRCClient +alias mag=Magnifier alias ms=Minesweeper alias sh=Shell alias sn=Snake diff --git a/Userland/Applications/CMakeLists.txt b/Userland/Applications/CMakeLists.txt index c1ec252db0..c3c07f5abd 100644 --- a/Userland/Applications/CMakeLists.txt +++ b/Userland/Applications/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(HexEditor) add_subdirectory(IRCClient) add_subdirectory(KeyboardMapper) add_subdirectory(KeyboardSettings) +add_subdirectory(Magnifier) add_subdirectory(MouseSettings) add_subdirectory(Piano) add_subdirectory(PixelPaint) diff --git a/Userland/Applications/Magnifier/CMakeLists.txt b/Userland/Applications/Magnifier/CMakeLists.txt new file mode 100644 index 0000000000..0979947268 --- /dev/null +++ b/Userland/Applications/Magnifier/CMakeLists.txt @@ -0,0 +1,8 @@ +set(SOURCES + MagnifierWidget.cpp + MagnifierWidget.h + main.cpp +) + +serenity_app(Magnifier ICON find) +target_link_libraries(Magnifier LibGUI) diff --git a/Userland/Applications/Magnifier/MagnifierWidget.cpp b/Userland/Applications/Magnifier/MagnifierWidget.cpp new file mode 100644 index 0000000000..e903b28206 --- /dev/null +++ b/Userland/Applications/Magnifier/MagnifierWidget.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, Valtteri Koskivuori + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "MagnifierWidget.h" +#include +#include +#include +#include +#include + +MagnifierWidget::MagnifierWidget() +{ +} + +MagnifierWidget::~MagnifierWidget() +{ +} + +void MagnifierWidget::track_cursor_globally() +{ + VERIFY(window()); + auto window_id = window()->window_id(); + VERIFY(window_id >= 0); + + set_global_cursor_tracking(true); + GUI::WindowServerConnection::the().set_global_cursor_tracking(window_id, true); +} + +void MagnifierWidget::set_scale_factor(int scale_factor) +{ + VERIFY(scale_factor == 2 || scale_factor == 4); + m_scale_factor = scale_factor; + update(); +} + +void MagnifierWidget::timer_event(Core::TimerEvent&) +{ + m_mouse_position = GUI::WindowServerConnection::the().get_global_cursor_position(); + update(); +} + +void MagnifierWidget::paint_event(GUI::PaintEvent&) +{ + GUI::Painter painter(*this); + + int grab_frame_size = 200; + + grab_frame_size /= m_scale_factor; + + // Paint our screenshot + Gfx::Rect region { m_mouse_position.x() - (grab_frame_size / 2), m_mouse_position.y() - (grab_frame_size / 2), grab_frame_size, grab_frame_size }; + auto map = GUI::WindowServerConnection::the().get_screen_bitmap(region); + painter.draw_scaled_bitmap(rect(), *map.bitmap(), map.bitmap()->rect()); +} diff --git a/Userland/Applications/Magnifier/MagnifierWidget.h b/Userland/Applications/Magnifier/MagnifierWidget.h new file mode 100644 index 0000000000..f58d7d54d5 --- /dev/null +++ b/Userland/Applications/Magnifier/MagnifierWidget.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Valtteri Koskivuori + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +class MagnifierWidget final : public GUI::Widget { + C_OBJECT(MagnifierWidget) + +public: + MagnifierWidget(); + virtual ~MagnifierWidget(); + void set_scale_factor(int scale_factor); + void track_cursor_globally(); + +private: + virtual void timer_event(Core::TimerEvent&) override; + virtual void paint_event(GUI::PaintEvent&) override; + + Gfx::IntPoint m_mouse_position; + int m_scale_factor { 2 }; +}; diff --git a/Userland/Applications/Magnifier/main.cpp b/Userland/Applications/Magnifier/main.cpp new file mode 100644 index 0000000000..99bb049436 --- /dev/null +++ b/Userland/Applications/Magnifier/main.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021, Valtteri Koskivuori + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "MagnifierWidget.h" +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (pledge("stdio cpath rpath recvfd sendfd unix fattr", nullptr) < 0) { + perror("pledge"); + return 1; + } + + auto app = GUI::Application::construct(argc, argv); + + if (pledge("stdio cpath rpath recvfd sendfd", nullptr) < 0) { + perror("pledge"); + return 1; + } + + if (unveil("/res", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + // Sneaky! + // FIXME: Doesn't have a 32x32 icon yet, need to make one! + auto app_icon = GUI::Icon::default_icon("find"); + + // 4px on each side for padding + constexpr int window_dimensions = 200 + 4 + 4; + auto window = GUI::Window::construct(); + window->set_title("Magnifier"); + window->resize(window_dimensions, window_dimensions); + window->set_resizable(false); + window->set_minimizable(false); + window->set_icon(app_icon.bitmap_for_size(16)); + auto& magnifier = window->set_main_widget(); + + auto menubar = GUI::Menubar::construct(); + auto& file_menu = menubar->add_menu("&File"); + file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { + app->quit(); + })); + + auto size_action_group = make(); + + auto two_x_action = GUI::Action::create_checkable( + "&2x", [&](auto&) { + magnifier.set_scale_factor(2); + }); + + auto four_x_action = GUI::Action::create_checkable( + "&4x", [&](auto&) { + magnifier.set_scale_factor(4); + }); + + size_action_group->add_action(two_x_action); + size_action_group->add_action(four_x_action); + size_action_group->set_exclusive(true); + + auto& view_menu = menubar->add_menu("&View"); + view_menu.add_action(two_x_action); + view_menu.add_action(four_x_action); + two_x_action->set_checked(true); + + auto& help_menu = menubar->add_menu("&Help"); + help_menu.add_action(GUI::CommonActions::make_about_action("Magnifier", app_icon, window)); + window->set_menubar(move(menubar)); + + window->show(); + magnifier.track_cursor_globally(); + magnifier.start_timer(16); + return app->exec(); +}