Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <AK/DeprecatedString.h>
11#include <LibCore/ElapsedTimer.h>
12#include <LibCore/Notifier.h>
13#include <LibCore/Timer.h>
14#include <LibGUI/Clipboard.h>
15#include <LibGUI/Frame.h>
16#include <LibGfx/Bitmap.h>
17#include <LibGfx/Rect.h>
18#include <LibVT/Color.h>
19#include <LibVT/Range.h>
20#include <LibVT/Terminal.h>
21
22namespace VT {
23
24class TerminalWidget final
25 : public GUI::Frame
26 , public VT::TerminalClient
27 , public GUI::Clipboard::ClipboardClient {
28 C_OBJECT(TerminalWidget);
29
30public:
31 virtual ~TerminalWidget() override = default;
32
33 void set_pty_master_fd(int fd);
34 void inject_string(StringView string)
35 {
36 m_terminal.inject_string(string);
37 flush_dirty_lines();
38 }
39
40 void flush_dirty_lines();
41
42 void apply_size_increments_to_window(GUI::Window&);
43
44 void set_opacity(u8);
45 float opacity() { return m_opacity; };
46
47 void set_show_scrollbar(bool);
48
49 enum class BellMode {
50 Visible,
51 AudibleBeep,
52 Disabled
53 };
54
55 BellMode bell_mode() { return m_bell_mode; }
56 void set_bell_mode(BellMode bm) { m_bell_mode = bm; };
57
58 bool has_selection() const;
59 bool selection_contains(const VT::Position&) const;
60 DeprecatedString selected_text() const;
61 VT::Range normalized_selection() const { return m_selection.normalized(); }
62 void set_selection(const VT::Range& selection);
63 VT::Position buffer_position_at(Gfx::IntPoint) const;
64
65 VT::Range find_next(StringView, const VT::Position& start = {}, bool case_sensitivity = false, bool should_wrap = false);
66 VT::Range find_previous(StringView, const VT::Position& start = {}, bool case_sensitivity = false, bool should_wrap = false);
67
68 void scroll_to_bottom();
69 void scroll_to_row(int);
70
71 bool is_scrollable() const;
72 int scroll_length() const;
73
74 size_t max_history_size() const { return m_terminal.max_history_size(); }
75 void set_max_history_size(size_t value) { m_terminal.set_max_history_size(value); }
76
77 GUI::Action& copy_action() { return *m_copy_action; }
78 GUI::Action& paste_action() { return *m_paste_action; }
79 GUI::Action& clear_including_history_action() { return *m_clear_including_history_action; }
80
81 void copy();
82 void paste();
83 void clear_including_history();
84
85 const StringView color_scheme_name() const { return m_color_scheme_name; }
86
87 Function<void(StringView)> on_title_change;
88 Function<void(Gfx::IntSize)> on_terminal_size_change;
89 Function<void()> on_command_exit;
90
91 GUI::Menu& context_menu() { return *m_context_menu; }
92
93 constexpr Gfx::Color terminal_color_to_rgb(VT::Color) const;
94
95 void set_font_and_resize_to_fit(Gfx::Font const&);
96
97 void update_color_scheme();
98
99 void set_logical_focus(bool);
100
101 VT::CursorShape cursor_shape() { return m_cursor_shape; }
102 virtual void set_cursor_blinking(bool) override;
103 virtual void set_cursor_shape(CursorShape) override;
104
105 static Optional<VT::CursorShape> parse_cursor_shape(StringView);
106 static DeprecatedString stringify_cursor_shape(VT::CursorShape);
107
108private:
109 TerminalWidget(int ptm_fd, bool automatic_size_policy);
110
111 // ^GUI::Widget
112 virtual void event(Core::Event&) override;
113 virtual void paint_event(GUI::PaintEvent&) override;
114 virtual void resize_event(GUI::ResizeEvent&) override;
115 virtual void keydown_event(GUI::KeyEvent&) override;
116 virtual void keyup_event(GUI::KeyEvent&) override;
117 virtual void mousedown_event(GUI::MouseEvent&) override;
118 virtual void mouseup_event(GUI::MouseEvent&) override;
119 virtual void mousemove_event(GUI::MouseEvent&) override;
120 virtual void mousewheel_event(GUI::MouseEvent&) override;
121 virtual void doubleclick_event(GUI::MouseEvent&) override;
122 virtual void focusin_event(GUI::FocusEvent&) override;
123 virtual void focusout_event(GUI::FocusEvent&) override;
124 virtual void context_menu_event(GUI::ContextMenuEvent&) override;
125 virtual void drag_enter_event(GUI::DragEvent&) override;
126 virtual void drop_event(GUI::DropEvent&) override;
127 virtual void leave_event(Core::Event&) override;
128 virtual void did_change_font() override;
129
130 // ^TerminalClient
131 virtual void beep() override;
132 virtual void set_window_title(StringView) override;
133 virtual void set_window_progress(int value, int max) override;
134 virtual void terminal_did_resize(u16 columns, u16 rows) override;
135 virtual void terminal_history_changed(int delta) override;
136 virtual void emit(u8 const*, size_t) override;
137
138 // ^GUI::Clipboard::ClipboardClient
139 virtual void clipboard_content_did_change(DeprecatedString const&) override { update_paste_action(); }
140
141 void send_non_user_input(ReadonlyBytes);
142
143 Gfx::IntRect glyph_rect(u16 row, u16 column);
144 Gfx::IntRect row_rect(u16 row);
145
146 Gfx::IntSize widget_size_for_font(Gfx::Font const&) const;
147
148 void update_cursor();
149 void invalidate_cursor();
150
151 void relayout(Gfx::IntSize);
152
153 void update_copy_action();
154 void update_paste_action();
155
156 Gfx::IntSize compute_base_size() const;
157 int first_selection_column_on_row(int row) const;
158 int last_selection_column_on_row(int row) const;
159
160 u32 code_point_at(const VT::Position&) const;
161 VT::Position next_position_after(const VT::Position&, bool should_wrap) const;
162 VT::Position previous_position_before(const VT::Position&, bool should_wrap) const;
163
164 void update_cached_font_metrics();
165
166 VT::Terminal m_terminal;
167
168 VT::Range m_selection;
169
170 DeprecatedString m_hovered_href;
171 DeprecatedString m_hovered_href_id;
172
173 DeprecatedString m_active_href;
174 DeprecatedString m_active_href_id;
175
176 // Snapshot of m_hovered_href when opening a context menu for a hyperlink.
177 DeprecatedString m_context_menu_href;
178
179 Gfx::Color m_colors[256];
180 Gfx::Color m_default_foreground_color;
181 Gfx::Color m_default_background_color;
182 bool m_show_bold_text_as_bright { true };
183
184 DeprecatedString m_color_scheme_name;
185
186 BellMode m_bell_mode { BellMode::Visible };
187 bool m_alt_key_held { false };
188 bool m_rectangle_selection { false };
189
190 int m_pixel_width { 0 };
191 int m_pixel_height { 0 };
192
193 int m_inset { 2 };
194 int m_line_spacing { 4 };
195 int m_line_height { 0 };
196 int m_cell_height { 0 };
197 int m_column_width { 0 };
198
199 int m_ptm_fd { -1 };
200
201 bool m_has_logical_focus { false };
202 bool m_in_relayout { false };
203
204 RefPtr<Core::Notifier> m_notifier;
205
206 u8 m_opacity { 255 };
207 bool m_cursor_blink_state { true };
208 bool m_automatic_size_policy { false };
209
210 VT::CursorShape m_cursor_shape { VT::CursorShape::Block };
211 bool m_cursor_is_blinking_set { true };
212
213 enum class AutoScrollDirection {
214 None,
215 Up,
216 Down
217 };
218
219 void set_auto_scroll_direction(AutoScrollDirection);
220
221 AutoScrollDirection m_auto_scroll_direction { AutoScrollDirection::None };
222
223 RefPtr<Core::Timer> m_cursor_blink_timer;
224 RefPtr<Core::Timer> m_visual_beep_timer;
225 RefPtr<Core::Timer> m_auto_scroll_timer;
226
227 RefPtr<GUI::Scrollbar> m_scrollbar;
228
229 RefPtr<GUI::Action> m_copy_action;
230 RefPtr<GUI::Action> m_paste_action;
231 RefPtr<GUI::Action> m_clear_including_history_action;
232
233 RefPtr<GUI::Menu> m_context_menu;
234 RefPtr<GUI::Menu> m_context_menu_for_hyperlink;
235
236 Core::ElapsedTimer m_triple_click_timer;
237
238 Gfx::IntPoint m_left_mousedown_position;
239 VT::Position m_left_mousedown_position_buffer;
240};
241
242}