Procházet zdrojové kódy

LibVT: Enable TerminalWidget copy/paste menu actions conditionally

The copy action is now only enabled if there is a selection.
The paste action is now only enabled if the clipboard contains something
the terminal considers pasteable - that is, non-empty data with a text/*
MIME-type. Previously we'd happily paste things like bitmaps into the
terminal, causing it to blow up.
Linus Groh před 4 roky
rodič
revize
6b7061d00b

+ 28 - 1
Libraries/LibVT/TerminalWidget.cpp

@@ -141,10 +141,12 @@ TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<Co
     m_copy_action = GUI::Action::create("Copy", { Mod_Ctrl | Mod_Shift, Key_C }, Gfx::Bitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [this](auto&) {
     m_copy_action = GUI::Action::create("Copy", { Mod_Ctrl | Mod_Shift, Key_C }, Gfx::Bitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [this](auto&) {
         copy();
         copy();
     });
     });
+    m_copy_action->set_swallow_key_event_when_disabled(true);
 
 
     m_paste_action = GUI::Action::create("Paste", { Mod_Ctrl | Mod_Shift, Key_V }, Gfx::Bitmap::load_from_file("/res/icons/16x16/paste.png"), [this](auto&) {
     m_paste_action = GUI::Action::create("Paste", { Mod_Ctrl | Mod_Shift, Key_V }, Gfx::Bitmap::load_from_file("/res/icons/16x16/paste.png"), [this](auto&) {
         paste();
         paste();
     });
     });
+    m_paste_action->set_swallow_key_event_when_disabled(true);
 
 
     m_clear_including_history_action = GUI::Action::create("Clear including history", { Mod_Ctrl | Mod_Shift, Key_K }, [this](auto&) {
     m_clear_including_history_action = GUI::Action::create("Clear including history", { Mod_Ctrl | Mod_Shift, Key_K }, [this](auto&) {
         clear_including_history();
         clear_including_history();
@@ -155,6 +157,13 @@ TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<Co
     m_context_menu->add_action(paste_action());
     m_context_menu->add_action(paste_action());
     m_context_menu->add_separator();
     m_context_menu->add_separator();
     m_context_menu->add_action(clear_including_history_action());
     m_context_menu->add_action(clear_including_history_action());
+
+    GUI::Clipboard::the().on_change = [this](const String&) {
+        update_paste_action();
+    };
+
+    update_copy_action();
+    update_paste_action();
 }
 }
 
 
 TerminalWidget::~TerminalWidget()
 TerminalWidget::~TerminalWidget()
@@ -248,6 +257,7 @@ void TerminalWidget::keydown_event(GUI::KeyEvent& event)
 
 
     if (future_cursor_column <= last_selection_column_on_row(m_terminal.cursor_row()) && m_terminal.cursor_row() >= min_selection_row && m_terminal.cursor_row() <= max_selection_row) {
     if (future_cursor_column <= last_selection_column_on_row(m_terminal.cursor_row()) && m_terminal.cursor_row() >= min_selection_row && m_terminal.cursor_row() <= max_selection_row) {
         m_selection_end = {};
         m_selection_end = {};
+        update_copy_action();
         update();
         update();
     }
     }
 
 
@@ -553,6 +563,7 @@ void TerminalWidget::doubleclick_event(GUI::MouseEvent& event)
 
 
         m_selection_start = { position.row(), start_column };
         m_selection_start = { position.row(), start_column };
         m_selection_end = { position.row(), end_column };
         m_selection_end = { position.row(), end_column };
+        update_copy_action();
     }
     }
     GUI::Frame::doubleclick_event(event);
     GUI::Frame::doubleclick_event(event);
 }
 }
@@ -561,6 +572,9 @@ void TerminalWidget::paste()
 {
 {
     if (m_ptm_fd == -1)
     if (m_ptm_fd == -1)
         return;
         return;
+    auto mime_type = GUI::Clipboard::the().mime_type();
+    if (!mime_type.starts_with("text/"))
+        return;
     auto text = GUI::Clipboard::the().data();
     auto text = GUI::Clipboard::the().data();
     if (text.is_empty())
     if (text.is_empty())
         return;
         return;
@@ -625,6 +639,7 @@ void TerminalWidget::mousedown_event(GUI::MouseEvent& event)
         else if (m_rectangle_selection)
         else if (m_rectangle_selection)
             m_rectangle_selection = false;
             m_rectangle_selection = false;
 
 
+        update_copy_action();
         update();
         update();
     }
     }
 }
 }
@@ -684,8 +699,10 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
 
 
     auto old_selection_end = m_selection_end;
     auto old_selection_end = m_selection_end;
     m_selection_end = position;
     m_selection_end = position;
-    if (old_selection_end != m_selection_end)
+    if (old_selection_end != m_selection_end) {
+        update_copy_action();
         update();
         update();
+    }
 }
 }
 
 
 void TerminalWidget::leave_event(Core::Event&)
 void TerminalWidget::leave_event(Core::Event&)
@@ -911,3 +928,13 @@ void TerminalWidget::scroll_to_bottom()
 {
 {
     m_scrollbar->set_value(m_scrollbar->max());
     m_scrollbar->set_value(m_scrollbar->max());
 }
 }
+
+void TerminalWidget::update_copy_action()
+{
+    m_copy_action->set_enabled(has_selection());
+}
+
+void TerminalWidget::update_paste_action()
+{
+    m_paste_action->set_enabled(GUI::Clipboard::the().mime_type().starts_with("text/") && !GUI::Clipboard::the().data().is_empty());
+}

+ 3 - 0
Libraries/LibVT/TerminalWidget.h

@@ -130,6 +130,9 @@ private:
 
 
     void relayout(const Gfx::IntSize&);
     void relayout(const Gfx::IntSize&);
 
 
+    void update_copy_action();
+    void update_paste_action();
+
     Gfx::IntSize compute_base_size() const;
     Gfx::IntSize compute_base_size() const;
     int first_selection_column_on_row(int row) const;
     int first_selection_column_on_row(int row) const;
     int last_selection_column_on_row(int row) const;
     int last_selection_column_on_row(int row) const;