diff --git a/Applications/Browser/ConsoleWidget.cpp b/Applications/Browser/ConsoleWidget.cpp index 9d9e22f43c..23e43be4c0 100644 --- a/Applications/Browser/ConsoleWidget.cpp +++ b/Applications/Browser/ConsoleWidget.cpp @@ -165,7 +165,7 @@ void ConsoleWidget::clear_output() m_output_view->update(); } -void ConsoleWidget::focusin_event(Core::Event&) +void ConsoleWidget::focusin_event(GUI::FocusEvent&) { m_input->set_focus(true); } diff --git a/Applications/Browser/ConsoleWidget.h b/Applications/Browser/ConsoleWidget.h index cb1a1313a8..afc6178ffc 100644 --- a/Applications/Browser/ConsoleWidget.h +++ b/Applications/Browser/ConsoleWidget.h @@ -48,7 +48,7 @@ private: ConsoleWidget(); virtual bool accepts_focus() const override { return true; } - virtual void focusin_event(Core::Event&) override; + virtual void focusin_event(GUI::FocusEvent&) override; RefPtr m_input; RefPtr m_output_view; diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp index c6b07ca749..3701511ba7 100644 --- a/DevTools/HackStudio/Editor.cpp +++ b/DevTools/HackStudio/Editor.cpp @@ -65,7 +65,7 @@ const EditorWrapper& Editor::wrapper() const return static_cast(*parent()); } -void Editor::focusin_event(Core::Event& event) +void Editor::focusin_event(GUI::FocusEvent& event) { wrapper().set_editor_has_focus({}, true); if (on_focus) @@ -73,7 +73,7 @@ void Editor::focusin_event(Core::Event& event) GUI::TextEditor::focusin_event(event); } -void Editor::focusout_event(Core::Event& event) +void Editor::focusout_event(GUI::FocusEvent& event) { wrapper().set_editor_has_focus({}, false); GUI::TextEditor::focusout_event(event); diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h index 6d4e15c0ba..accf1bec6b 100644 --- a/DevTools/HackStudio/Editor.h +++ b/DevTools/HackStudio/Editor.h @@ -51,8 +51,8 @@ public: BreakpointChangeCallback on_breakpoint_change; private: - virtual void focusin_event(Core::Event&) override; - virtual void focusout_event(Core::Event&) override; + virtual void focusin_event(GUI::FocusEvent&) override; + virtual void focusout_event(GUI::FocusEvent&) override; virtual void paint_event(GUI::PaintEvent&) override; virtual void mousemove_event(GUI::MouseEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; diff --git a/Libraries/LibGUI/Event.h b/Libraries/LibGUI/Event.h index a61301ee26..a36e081017 100644 --- a/Libraries/LibGUI/Event.h +++ b/Libraries/LibGUI/Event.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -76,12 +77,12 @@ public: __End_WM_Events, }; - Event() {} + Event() { } explicit Event(Type type) : Core::Event(type) { } - virtual ~Event() {} + virtual ~Event() { } bool is_key_event() const { return type() == KeyUp || type() == KeyDown; } bool is_paint_event() const { return type() == Paint; } @@ -387,4 +388,18 @@ public: } }; +class FocusEvent final : public Event { +public: + explicit FocusEvent(Type type, FocusSource source) + : Event(type) + , m_source(source) + { + } + + FocusSource source() const { return m_source; } + +private: + FocusSource m_source { FocusSource::Programmatic }; +}; + } diff --git a/Libraries/LibGUI/FocusSource.h b/Libraries/LibGUI/FocusSource.h new file mode 100644 index 0000000000..d8e6e238df --- /dev/null +++ b/Libraries/LibGUI/FocusSource.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace GUI { + +enum class FocusSource { + Programmatic, + Keyboard, + Mouse, +}; + +} diff --git a/Libraries/LibGUI/TextEditor.cpp b/Libraries/LibGUI/TextEditor.cpp index e354171ee0..0e5a93594b 100644 --- a/Libraries/LibGUI/TextEditor.cpp +++ b/Libraries/LibGUI/TextEditor.cpp @@ -1147,7 +1147,7 @@ void TextEditor::set_cursor(const TextPosition& a_position) m_highlighter->cursor_did_change(); } -void TextEditor::focusin_event(Core::Event&) +void TextEditor::focusin_event(FocusEvent&) { m_cursor_state = true; update_cursor(); @@ -1156,7 +1156,7 @@ void TextEditor::focusin_event(Core::Event&) on_focusin(); } -void TextEditor::focusout_event(Core::Event&) +void TextEditor::focusout_event(FocusEvent&) { stop_timer(); if (on_focusout) diff --git a/Libraries/LibGUI/TextEditor.h b/Libraries/LibGUI/TextEditor.h index 86390ada75..e67c3fa801 100644 --- a/Libraries/LibGUI/TextEditor.h +++ b/Libraries/LibGUI/TextEditor.h @@ -166,8 +166,8 @@ protected: virtual void mousemove_event(MouseEvent&) override; virtual void doubleclick_event(MouseEvent&) override; virtual void keydown_event(KeyEvent&) override; - virtual void focusin_event(Core::Event&) override; - virtual void focusout_event(Core::Event&) override; + virtual void focusin_event(FocusEvent&) override; + virtual void focusout_event(FocusEvent&) override; virtual void timer_event(Core::TimerEvent&) override; virtual bool accepts_focus() const override { return true; } virtual void enter_event(Core::Event&) override; diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index f62e89c227..af779391db 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -183,9 +183,9 @@ void Widget::event(Core::Event& event) case Event::Resize: return handle_resize_event(static_cast(event)); case Event::FocusIn: - return focusin_event(event); + return focusin_event(static_cast(event)); case Event::FocusOut: - return focusout_event(event); + return focusout_event(static_cast(event)); case Event::Show: return show_event(static_cast(event)); case Event::Hide: @@ -302,7 +302,7 @@ void Widget::handle_mouseup_event(MouseEvent& event) void Widget::handle_mousedown_event(MouseEvent& event) { if (accepts_focus()) - set_focus(true); + set_focus(true, FocusSource::Mouse); mousedown_event(event); if (event.button() == MouseButton::Right) { ContextMenuEvent c_event(event.position(), screen_relative_rect().location().translated(event.position())); @@ -356,9 +356,9 @@ void Widget::keydown_event(KeyEvent& event) { if (!event.alt() && !event.ctrl() && !event.logo() && event.key() == KeyCode::Key_Tab) { if (event.shift()) - focus_previous_widget(); + focus_previous_widget(FocusSource::Keyboard); else - focus_next_widget(); + focus_next_widget(FocusSource::Keyboard); event.accept(); return; } @@ -390,11 +390,11 @@ void Widget::context_menu_event(ContextMenuEvent&) { } -void Widget::focusin_event(Core::Event&) +void Widget::focusin_event(FocusEvent&) { } -void Widget::focusout_event(Core::Event&) +void Widget::focusout_event(FocusEvent&) { } @@ -513,16 +513,16 @@ bool Widget::is_focused() const return false; } -void Widget::set_focus(bool focus) +void Widget::set_focus(bool focus, FocusSource source) { auto* win = window(); if (!win) return; if (focus) { - win->set_focused_widget(this); + win->set_focused_widget(this, source); } else { if (win->focused_widget() == this) - win->set_focused_widget(nullptr); + win->set_focused_widget(nullptr, source); } } @@ -703,29 +703,29 @@ void Widget::set_updates_enabled(bool enabled) update(); } -void Widget::focus_previous_widget() +void Widget::focus_previous_widget(FocusSource source) { auto focusable_widgets = window()->focusable_widgets(); for (int i = focusable_widgets.size() - 1; i >= 0; --i) { if (focusable_widgets[i] != this) continue; if (i > 0) - focusable_widgets[i - 1]->set_focus(true); + focusable_widgets[i - 1]->set_focus(true, source); else - focusable_widgets.last()->set_focus(true); + focusable_widgets.last()->set_focus(true, source); } } -void Widget::focus_next_widget() +void Widget::focus_next_widget(FocusSource source) { auto focusable_widgets = window()->focusable_widgets(); for (size_t i = 0; i < focusable_widgets.size(); ++i) { if (focusable_widgets[i] != this) continue; if (i < focusable_widgets.size() - 1) - focusable_widgets[i + 1]->set_focus(true); + focusable_widgets[i + 1]->set_focus(true, source); else - focusable_widgets.first()->set_focus(true); + focusable_widgets.first()->set_focus(true, source); } } diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index 2a7937f60f..5a66a472d7 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -147,7 +147,7 @@ public: virtual bool accepts_focus() const { return false; } bool is_focused() const; - void set_focus(bool); + void set_focus(bool, FocusSource = FocusSource::Programmatic); enum class ShouldRespectGreediness { No = 0, Yes }; @@ -287,8 +287,8 @@ protected: virtual void mousewheel_event(MouseEvent&); virtual void doubleclick_event(MouseEvent&); virtual void context_menu_event(ContextMenuEvent&); - virtual void focusin_event(Core::Event&); - virtual void focusout_event(Core::Event&); + virtual void focusin_event(FocusEvent&); + virtual void focusout_event(FocusEvent&); virtual void enter_event(Core::Event&); virtual void leave_event(Core::Event&); virtual void child_event(Core::ChildEvent&) override; @@ -310,8 +310,8 @@ private: void handle_mouseup_event(MouseEvent&); void handle_enter_event(Core::Event&); void handle_leave_event(Core::Event&); - void focus_previous_widget(); - void focus_next_widget(); + void focus_previous_widget(FocusSource); + void focus_next_widget(FocusSource); Window* m_window { nullptr }; RefPtr m_layout; diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp index 9add84eebf..a58b04d898 100644 --- a/Libraries/LibGUI/Window.cpp +++ b/Libraries/LibGUI/Window.cpp @@ -525,17 +525,17 @@ void Window::set_main_widget(Widget* widget) update(); } -void Window::set_focused_widget(Widget* widget) +void Window::set_focused_widget(Widget* widget, FocusSource source) { if (m_focused_widget == widget) return; if (m_focused_widget) { - Core::EventLoop::current().post_event(*m_focused_widget, make(Event::FocusOut)); + Core::EventLoop::current().post_event(*m_focused_widget, make(Event::FocusOut, source)); m_focused_widget->update(); } m_focused_widget = widget ? widget->make_weak_ptr() : nullptr; if (m_focused_widget) { - Core::EventLoop::current().post_event(*m_focused_widget, make(Event::FocusIn)); + Core::EventLoop::current().post_event(*m_focused_widget, make(Event::FocusIn, source)); m_focused_widget->update(); } } diff --git a/Libraries/LibGUI/Window.h b/Libraries/LibGUI/Window.h index fcfeaf2ae7..3284a15644 100644 --- a/Libraries/LibGUI/Window.h +++ b/Libraries/LibGUI/Window.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -152,7 +153,7 @@ public: Widget* focused_widget() { return m_focused_widget; } const Widget* focused_widget() const { return m_focused_widget; } - void set_focused_widget(Widget*); + void set_focused_widget(Widget*, FocusSource = FocusSource::Programmatic); void update(); void update(const Gfx::IntRect&); diff --git a/Libraries/LibVT/TerminalWidget.cpp b/Libraries/LibVT/TerminalWidget.cpp index cd61db7847..828b88c247 100644 --- a/Libraries/LibVT/TerminalWidget.cpp +++ b/Libraries/LibVT/TerminalWidget.cpp @@ -181,13 +181,13 @@ void TerminalWidget::set_logical_focus(bool focus) update(); } -void TerminalWidget::focusin_event(Core::Event& event) +void TerminalWidget::focusin_event(GUI::FocusEvent& event) { set_logical_focus(true); return GUI::Frame::focusin_event(event); } -void TerminalWidget::focusout_event(Core::Event& event) +void TerminalWidget::focusout_event(GUI::FocusEvent& event) { set_logical_focus(false); return GUI::Frame::focusout_event(event); diff --git a/Libraries/LibVT/TerminalWidget.h b/Libraries/LibVT/TerminalWidget.h index f4d56e21d8..cfd5de892b 100644 --- a/Libraries/LibVT/TerminalWidget.h +++ b/Libraries/LibVT/TerminalWidget.h @@ -102,8 +102,8 @@ private: virtual void mousemove_event(GUI::MouseEvent&) override; virtual void mousewheel_event(GUI::MouseEvent&) override; virtual void doubleclick_event(GUI::MouseEvent&) override; - virtual void focusin_event(Core::Event&) override; - virtual void focusout_event(Core::Event&) override; + virtual void focusin_event(GUI::FocusEvent&) override; + virtual void focusout_event(GUI::FocusEvent&) override; virtual void context_menu_event(GUI::ContextMenuEvent&) override; virtual void drop_event(GUI::DropEvent&) override; virtual void leave_event(Core::Event&) override;