diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index 019737f006..c2b29d3e7e 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -948,6 +948,7 @@ bool Window::is_maximized() const void Window::set_maximized(bool maximized) { + VERIFY(m_window_id != 0); WindowServerConnection::the().async_set_maximized(m_window_id, maximized); } diff --git a/Userland/Services/WindowServer/Compositor.cpp b/Userland/Services/WindowServer/Compositor.cpp index f46c925976..c1ae95202d 100644 --- a/Userland/Services/WindowServer/Compositor.cpp +++ b/Userland/Services/WindowServer/Compositor.cpp @@ -504,7 +504,8 @@ void Compositor::compose() // Paint the window stack. if (m_invalidated_window) { - if (auto* fullscreen_window = wm.active_fullscreen_window()) { + auto* fullscreen_window = wm.active_fullscreen_window(); + if (fullscreen_window && fullscreen_window->is_opaque()) { compose_window(*fullscreen_window); fullscreen_window->clear_dirty_rects(); } else { @@ -1071,7 +1072,8 @@ void Compositor::recompute_occlusions() bool window_stack_transition_in_progress = m_transitioning_to_window_stack != nullptr; auto& main_screen = Screen::main(); - if (auto* fullscreen_window = wm.active_fullscreen_window()) { + auto* fullscreen_window = wm.active_fullscreen_window(); + if (fullscreen_window) { // TODO: support fullscreen windows on all screens auto screen_rect = main_screen.rect(); wm.for_each_visible_window_from_front_to_back([&](Window& w) { @@ -1099,7 +1101,8 @@ void Compositor::recompute_occlusions() }); m_opaque_wallpaper_rects.clear(); - } else { + } + if (!fullscreen_window || (fullscreen_window && !fullscreen_window->is_opaque())) { Gfx::DisjointRectSet visible_rects; visible_rects.add_many(Screen::rects()); bool have_transparent = false; diff --git a/Userland/Utilities/shot.cpp b/Userland/Utilities/shot.cpp index 2a4cffe76a..6ccd4e9433 100644 --- a/Userland/Utilities/shot.cpp +++ b/Userland/Utilities/shot.cpp @@ -1,19 +1,91 @@ /* * Copyright (c) 2021, Andreas Kling + * Copyright (c) 2021, Aziz Berkay Yesilyurt * * SPDX-License-Identifier: BSD-2-Clause */ #include +#include #include #include #include #include #include +#include +#include +#include #include #include +#include #include +class SelectableLayover final : public GUI::Widget { + C_OBJECT(SelectableLayover) +public: + SelectableLayover(GUI::Window* window) + : m_window(window) + , m_background_color(palette().threed_highlight()) + { + set_override_cursor(Gfx::StandardCursor::Crosshair); + } + + virtual ~SelectableLayover() override {}; + + Gfx::IntRect region() const + { + return m_region; + } + +private: + virtual void mousedown_event(GUI::MouseEvent& event) override + { + if (event.button() == GUI::MouseButton::Left) + m_anchor_point = event.position(); + }; + + virtual void mousemove_event(GUI::MouseEvent& event) override + { + if (m_anchor_point.has_value()) { + m_region = Gfx::IntRect::from_two_points(*m_anchor_point, event.position()); + update(); + } + }; + + virtual void mouseup_event(GUI::MouseEvent& event) override + { + if (event.button() == GUI::MouseButton::Left) + m_window->close(); + }; + + virtual void paint_event(GUI::PaintEvent&) override + { + if (m_region.is_empty()) { + GUI::Painter painter(*this); + painter.fill_rect(m_window->rect(), m_background_color); + return; + } + + GUI::Painter painter(*this); + painter.fill_rect(m_region, Gfx::Color::Transparent); + for (auto rect : m_window->rect().shatter(m_region)) + painter.fill_rect(rect, m_background_color); + } + + virtual void keydown_event(GUI::KeyEvent& event) override + { + if (event.key() == Key_Escape) { + m_region = Gfx::IntRect(); + m_window->close(); + } + } + + Optional m_anchor_point; + Gfx::IntRect m_region; + GUI::Window* m_window = nullptr; + Gfx::Color const m_background_color; +}; + int main(int argc, char** argv) { Core::ArgsParser args_parser; @@ -21,12 +93,14 @@ int main(int argc, char** argv) String output_path; bool output_to_clipboard = false; unsigned delay = 0; + bool select_region = false; int screen = -1; args_parser.add_positional_argument(output_path, "Output filename", "output", Core::ArgsParser::Required::No); args_parser.add_option(output_to_clipboard, "Output to clipboard", "clipboard", 'c'); args_parser.add_option(delay, "Seconds to wait before taking a screenshot", "delay", 'd', "seconds"); args_parser.add_option(screen, "The index of the screen (default: -1 for all screens)", "screen", 's', "index"); + args_parser.add_option(select_region, "Select a region to capture", "region", 'r'); args_parser.parse(argc, argv); @@ -35,6 +109,25 @@ int main(int argc, char** argv) } auto app = GUI::Application::construct(argc, argv); + Gfx::IntRect crop_region; + if (select_region) { + auto window = GUI::Window::construct(); + auto& container = window->set_main_widget(window); + container.set_fill_with_background_color(true); + + window->set_title("shot"); + window->set_opacity(0.2); + window->set_fullscreen(true); + window->show(); + app->exec(); + + crop_region = container.region(); + if (crop_region.is_empty()) { + dbgln("cancelled..."); + return 0; + } + } + sleep(delay); Optional screen_index; if (screen >= 0) @@ -43,12 +136,16 @@ int main(int argc, char** argv) auto shared_bitmap = GUI::WindowServerConnection::the().get_screen_bitmap({}, screen_index); dbgln("got screenshot"); - auto* bitmap = shared_bitmap.bitmap(); + RefPtr bitmap = shared_bitmap.bitmap(); if (!bitmap) { warnln("Failed to grab screenshot"); return 1; } + if (select_region) { + bitmap = bitmap->cropped(crop_region); + } + if (output_to_clipboard) { GUI::Clipboard::the().set_bitmap(*bitmap); return 0;