summaryrefslogtreecommitdiff
path: root/Userland/Services/WindowServer/WindowFrame.h
blob: 30483af6cdc5578a044f325fe5cfe17d51bc721e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include "HitTestResult.h"
#include <AK/Forward.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/RefPtr.h>
#include <LibCore/Forward.h>
#include <LibGfx/Forward.h>
#include <LibGfx/WindowTheme.h>

namespace WindowServer {

class Button;
class Menu;
class MouseEvent;
class MultiScaleBitmaps;
class Screen;
class Window;

class WindowFrame {
public:
    class PerScaleRenderedCache {
        friend class WindowFrame;

    public:
        void paint(WindowFrame&, Gfx::Painter&, Gfx::IntRect const&);
        void render(WindowFrame&, Screen&);
        Optional<HitTestResult> hit_test(WindowFrame&, Gfx::IntPoint const&, Gfx::IntPoint const&);

    private:
        RefPtr<Gfx::Bitmap> m_top_bottom;
        RefPtr<Gfx::Bitmap> m_left_right;
        int m_bottom_y { 0 }; // y-offset in m_top_bottom for the bottom half
        int m_right_x { 0 };  // x-offset in m_left_right for the right half
        bool m_shadow_dirty { true };
        bool m_dirty { true };
    };
    friend class RenderedCache;

    static void reload_config();

    explicit WindowFrame(Window&);
    ~WindowFrame();

    void window_was_constructed(Badge<Window>);

    Window& window() { return m_window; }
    Window const& window() const { return m_window; }

    Gfx::IntRect rect() const;
    Gfx::IntRect render_rect() const;
    Gfx::IntRect unconstrained_render_rect() const;
    Gfx::DisjointRectSet opaque_render_rects() const;
    Gfx::DisjointRectSet transparent_render_rects() const;

    void paint(Screen&, Gfx::Painter&, Gfx::IntRect const&);
    void render(Screen&, Gfx::Painter&);
    PerScaleRenderedCache* render_to_cache(Screen&);

    void handle_mouse_event(MouseEvent const&);
    void handle_titlebar_mouse_event(MouseEvent const&);
    bool handle_titlebar_icon_mouse_event(MouseEvent const&);
    void handle_border_mouse_event(MouseEvent const&);

    void window_rect_changed(Gfx::IntRect const& old_rect, Gfx::IntRect const& new_rect);
    void invalidate_titlebar();
    void invalidate_menubar();
    void invalidate(Gfx::IntRect relative_rect);
    void invalidate();

    Gfx::IntRect titlebar_rect() const;
    Gfx::IntRect titlebar_icon_rect() const;
    Gfx::IntRect titlebar_text_rect() const;

    Gfx::IntRect menubar_rect() const;
    int menu_row_count() const;

    void did_set_maximized(Badge<Window>, bool);

    void layout_buttons();
    void set_button_icons();

    void start_flash_animation();

    bool has_alpha_channel() const { return m_has_alpha_channel; }
    void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
    bool has_shadow() const;

    void set_opacity(float);
    float opacity() const { return m_opacity; }

    bool is_opaque() const
    {
        if (opacity() < 1.0f)
            return false;
        if (has_alpha_channel())
            return false;
        return true;
    }

    void set_dirty(bool re_render_shadow = false)
    {
        for (auto& it : m_rendered_cache) {
            auto& cached = *it.value;
            cached.m_dirty = true;
            cached.m_shadow_dirty |= re_render_shadow;
        }
    }

    void theme_changed();

    Optional<HitTestResult> hit_test(Gfx::IntPoint const&);

    void open_menubar_menu(Menu&);

private:
    void paint_notification_frame(Gfx::Painter&);
    void paint_normal_frame(Gfx::Painter&);
    void paint_tool_window_frame(Gfx::Painter&);
    void paint_menubar(Gfx::Painter&);
    MultiScaleBitmaps const* shadow_bitmap() const;
    Gfx::IntRect inflated_for_shadow(Gfx::IntRect const&) const;

    void handle_menubar_mouse_event(MouseEvent const&);
    void handle_menu_mouse_event(Menu&, MouseEvent const&);

    Gfx::WindowTheme::WindowState window_state_for_theme() const;
    String computed_title() const;

    Gfx::IntRect constrained_render_rect_to_screen(Gfx::IntRect const&) const;
    Gfx::IntRect leftmost_titlebar_button_rect() const;

    Window& m_window;
    NonnullOwnPtrVector<Button> m_buttons;
    Button* m_close_button { nullptr };
    Button* m_maximize_button { nullptr };
    Button* m_minimize_button { nullptr };

    HashMap<int, NonnullOwnPtr<PerScaleRenderedCache>> m_rendered_cache;

    RefPtr<Core::Timer> m_flash_timer;
    size_t m_flash_counter { 0 };
    float m_opacity { 1 };
    bool m_has_alpha_channel { false };
};

}