summaryrefslogtreecommitdiff
path: root/Applications/Terminal/Terminal.h
blob: 13b3440cfd3f203a5595a441b429affc0d3c1421 (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#pragma once

#include <AK/AKString.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibCore/CConfigFile.h>
#include <LibCore/CNotifier.h>
#include <LibCore/CTimer.h>
#include <LibGUI/GFrame.h>
#include <SharedGraphics/GraphicsBitmap.h>
#include <SharedGraphics/Rect.h>

class Font;

class Terminal final : public GFrame {
public:
    explicit Terminal(int ptm_fd, RetainPtr<CConfigFile> config);
    virtual ~Terminal() override;

    void create_window();
    void on_char(byte);

    void flush_dirty_lines();
    void force_repaint();

    void apply_size_increments_to_window(GWindow&);

    void set_opacity(float);

    RetainPtr<CConfigFile> config() const { return m_config; }

private:
    typedef Vector<unsigned, 4> ParamVector;

    virtual void event(CEvent&) override;
    virtual void paint_event(GPaintEvent&) override;
    virtual void resize_event(GResizeEvent&) override;
    virtual void keydown_event(GKeyEvent&) override;
    virtual const char* class_name() const override { return "Terminal"; }

    void scroll_up();
    void newline();
    void set_cursor(unsigned row, unsigned column);
    void put_character_at(unsigned row, unsigned column, byte ch);
    void invalidate_cursor();
    void set_window_title(const String&);

    void inject_string(const String&);
    void unimplemented_escape();
    void unimplemented_xterm_escape();

    void escape$A(const ParamVector&);
    void escape$B(const ParamVector&);
    void escape$C(const ParamVector&);
    void escape$D(const ParamVector&);
    void escape$H(const ParamVector&);
    void escape$J(const ParamVector&);
    void escape$K(const ParamVector&);
    void escape$M(const ParamVector&);
    void escape$G(const ParamVector&);
    void escape$X(const ParamVector&);
    void escape$d(const ParamVector&);
    void escape$m(const ParamVector&);
    void escape$s(const ParamVector&);
    void escape$u(const ParamVector&);
    void escape$t(const ParamVector&);
    void escape$r(const ParamVector&);

    void clear();

    void set_size(word columns, word rows);
    word columns() const { return m_columns; }
    word rows() const { return m_rows; }
    Rect glyph_rect(word row, word column);
    Rect row_rect(word row);
    void update_cursor();

    struct Attribute {
        Attribute() { reset(); }

        static byte default_foreground_color;
        static byte default_background_color;

        void reset()
        {
            foreground_color = default_foreground_color;
            background_color = default_background_color;
            flags = Flags::NoAttributes;
        }
        byte foreground_color;
        byte background_color;

        enum Flags {
            NoAttributes = 0x00,
            Bold = 0x01,
            Italic = 0x02,
            Underline = 0x04,
            Negative = 0x08,
            Blink = 0x10,
        };

        // TODO: it would be really nice if we had a helper for enums that
        // exposed bit ops for class enums...
        int flags = Flags::NoAttributes;

        bool operator==(const Attribute& other) const
        {
            return foreground_color == other.foreground_color && background_color == other.background_color && flags == other.flags;
        }
        bool operator!=(const Attribute& other) const
        {
            return !(*this == other);
        }
    };

    struct Line {
        explicit Line(word columns);
        ~Line();
        void clear(Attribute);
        bool has_only_one_background_color() const;
        byte* characters { nullptr };
        Attribute* attributes { nullptr };
        bool dirty { false };
        word length { 0 };
    };
    Line& line(size_t index)
    {
        ASSERT(index < m_rows);
        return *m_lines[index];
    }

    Line** m_lines { nullptr };

    word m_columns { 0 };
    word m_rows { 0 };

    byte m_cursor_row { 0 };
    byte m_cursor_column { 0 };
    byte m_saved_cursor_row { 0 };
    byte m_saved_cursor_column { 0 };
    bool m_stomp { false };

    Attribute m_current_attribute;

    void execute_escape_sequence(byte final);
    void execute_xterm_command();

    enum EscapeState
    {
        Normal,
        ExpectBracket,
        ExpectParameter,
        ExpectIntermediate,
        ExpectFinal,

        ExpectXtermParameter1,
        ExpectXtermParameter2,
        ExpectXtermFinal,
    };
    EscapeState m_escape_state { Normal };
    Vector<byte> m_parameters;
    Vector<byte> m_intermediates;
    Vector<byte> m_xterm_param1;
    Vector<byte> m_xterm_param2;
    byte m_final { 0 };
    byte* m_horizontal_tabs { nullptr };
    bool m_belling { false };

    int m_pixel_width { 0 };
    int m_pixel_height { 0 };
    int m_rows_to_scroll_backing_store { 0 };

    int m_inset { 2 };
    int m_line_spacing { 4 };
    int m_line_height { 0 };

    int m_ptm_fd { -1 };

    bool m_swallow_current { false };

    bool m_in_active_window { false };
    bool m_need_full_flush { false };

    CNotifier m_notifier;

    float m_opacity { 1 };
    bool m_needs_background_fill { true };
    bool m_cursor_blink_state { true };

    int m_glyph_width { 0 };

    CTimer m_cursor_blink_timer;
    RetainPtr<CConfigFile> m_config;
};