diff --git a/Kernel/GUITypes.h b/Kernel/GUITypes.h index 088b94b734b..9572c97a59c 100644 --- a/Kernel/GUITypes.h +++ b/Kernel/GUITypes.h @@ -63,6 +63,8 @@ struct GUI_Event { MouseUp, KeyDown, KeyUp, + WindowActivated, + WindowDeactivated, }; Type type { Invalid }; int window_id { -1 }; diff --git a/Terminal/Terminal.cpp b/Terminal/Terminal.cpp index 51d609dc826..0b893f05a6b 100644 --- a/Terminal/Terminal.cpp +++ b/Terminal/Terminal.cpp @@ -291,7 +291,8 @@ void Terminal::scroll_up() } #endif memset(&m_buffer[(m_rows - 1) * m_columns], ' ', m_columns); - attribute_at(m_cursor_row, m_cursor_column).dirty = true; + // NOTE: We have to invalidate the cursor before memcpy()'ing the attributes. + invalidate_cursor(); memcpy(m_attributes, m_attributes + m_columns, m_columns * (m_rows - 1) * sizeof(Attribute)); for (size_t i = 0; i < m_columns; ++i) m_attributes[((m_rows - 1) * m_columns) + i].reset(); @@ -305,10 +306,10 @@ void Terminal::set_cursor(unsigned row, unsigned column) { ASSERT(row < rows()); ASSERT(column < columns()); - attribute_at(m_cursor_row, m_cursor_column).dirty = true; + invalidate_cursor(); m_cursor_row = row; m_cursor_column = column; - attribute_at(m_cursor_row, m_cursor_column).dirty = true; + invalidate_cursor(); } void Terminal::put_character_at(unsigned row, unsigned column, byte ch) @@ -449,7 +450,10 @@ void Terminal::paint() } auto cursor_rect = glyph_rect(m_cursor_row, m_cursor_column); - painter.draw_rect(cursor_rect, Color::MidGray); + if (m_in_active_window) + painter.fill_rect(cursor_rect, Color::MidGray); + else + painter.draw_rect(cursor_rect, Color::MidGray); if (m_belling) painter.draw_rect(rect, Color::Red); @@ -460,3 +464,17 @@ void Terminal::paint() exit(1); } } + +void Terminal::set_in_active_window(bool b) +{ + if (m_in_active_window == b) + return; + m_in_active_window = b; + invalidate_cursor(); + paint(); +} + +void Terminal::invalidate_cursor() +{ + attribute_at(m_cursor_row, m_cursor_column).dirty = true; +} diff --git a/Terminal/Terminal.h b/Terminal/Terminal.h index a3bc480ab51..4b069b141bb 100644 --- a/Terminal/Terminal.h +++ b/Terminal/Terminal.h @@ -17,11 +17,14 @@ public: void paint(); void on_char(byte); + void set_in_active_window(bool); + private: Font& font() { return *m_font; } void scroll_up(); void set_cursor(unsigned row, unsigned column); void put_character_at(unsigned row, unsigned column, byte ch); + void invalidate_cursor(); void escape$A(const Vector&); void escape$D(const Vector&); @@ -94,5 +97,7 @@ private: int m_line_spacing { 4 }; int m_line_height { 0 }; + bool m_in_active_window { false }; + RetainPtr m_font; }; diff --git a/Terminal/main.cpp b/Terminal/main.cpp index 3d1f1decc35..4ee790c9669 100644 --- a/Terminal/main.cpp +++ b/Terminal/main.cpp @@ -118,6 +118,8 @@ int main(int, char**) case GUI_Event::Type::MouseUp: dbgprintf("WID=%x MouseUp %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break; case GUI_Event::Type::MouseMove: dbgprintf("WID=%x MouseMove %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break; case GUI_Event::Type::KeyDown: dbgprintf("WID=%x KeyDown 0x%b (%c)\n", event.window_id, event.key.character, event.key.character); break; + case GUI_Event::Type::WindowActivated: dbgprintf("WID=%x WindowActivated\n", event.window_id); break; + case GUI_Event::Type::WindowDeactivated: dbgprintf("WID=%x WindowDeactivated\n", event.window_id); break; default: ASSERT_NOT_REACHED(); } @@ -126,6 +128,10 @@ int main(int, char**) terminal.paint(); } else if (event.type == GUI_Event::Type::KeyDown) { write(ptm_fd, &event.key.character, 1); + } else if (event.type == GUI_Event::Type::WindowActivated) { + terminal.set_in_active_window(true); + } else if (event.type == GUI_Event::Type::WindowDeactivated) { + terminal.set_in_active_window(false); } } } diff --git a/Userland/guitest.cpp b/Userland/guitest.cpp index 07d5de91888..e538fbf09aa 100644 --- a/Userland/guitest.cpp +++ b/Userland/guitest.cpp @@ -63,6 +63,8 @@ int main(int argc, char** argv) case GUI_Event::Type::MouseDown: dbgprintf("WID=%x MouseDown %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break; case GUI_Event::Type::MouseUp: dbgprintf("WID=%x MouseUp %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break; case GUI_Event::Type::MouseMove: dbgprintf("WID=%x MouseMove %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break; + case GUI_Event::Type::WindowActivated: dbgprintf("WID=%x WindowActivated\n", event.window_id); break; + case GUI_Event::Type::WindowDeactivated: dbgprintf("WID=%x WindowDeactivated\n", event.window_id); break; } if (event.type == GUI_Event::Type::MouseDown) { diff --git a/WindowServer/WSEvent.h b/WindowServer/WSEvent.h index 778dbd29ee7..702cd32efd9 100644 --- a/WindowServer/WSEvent.h +++ b/WindowServer/WSEvent.h @@ -18,6 +18,8 @@ static const char* WSEvent_names[] = { "Timer", "WM_Compose", "WM_Invalidate", + "WindowActivated", + "WindowDeactivated", }; class WSEvent { @@ -35,6 +37,8 @@ public: Timer, WM_Compose, WM_Invalidate, + WindowActivated, + WindowDeactivated, }; WSEvent() { } @@ -67,22 +71,6 @@ private: Rect m_rect; }; -class ShowEvent final : public WSEvent { -public: - ShowEvent() - : WSEvent(WSEvent::Show) - { - } -}; - -class HideEvent final : public WSEvent { -public: - HideEvent() - : WSEvent(WSEvent::Hide) - { - } -}; - enum class MouseButton : byte { None = 0, Left, @@ -142,10 +130,3 @@ private: Point m_position; MouseButton m_button { MouseButton::None }; }; - -class TimerEvent final : public WSEvent { -public: - TimerEvent() : WSEvent(WSEvent::Timer) { } - ~TimerEvent() { } -}; - diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index 72755d0aced..b3e986c3014 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -77,6 +77,12 @@ void WSWindow::event(WSEvent& event) case WSEvent::WM_Invalidate: WSWindowManager::the().invalidate(*this); return; + case WSEvent::WindowActivated: + gui_event.type = GUI_Event::Type::WindowActivated; + break; + case WSEvent::WindowDeactivated: + gui_event.type = GUI_Event::Type::WindowDeactivated; + break; } if (gui_event.type == GUI_Event::Type::Invalid) diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp index e0ab2d8d136..31e8cad2494 100644 --- a/WindowServer/WSWindowManager.cpp +++ b/WindowServer/WSWindowManager.cpp @@ -172,7 +172,7 @@ void WSWindowManager::addWindow(WSWindow& window) m_windows.set(&window); m_windows_in_order.append(&window); if (!activeWindow()) - setActiveWindow(&window); + set_active_window(&window); } void WSWindowManager::move_to_front(WSWindow& window) @@ -192,7 +192,7 @@ void WSWindowManager::removeWindow(WSWindow& window) m_windows.remove(&window); m_windows_in_order.remove(&window); if (!activeWindow() && !m_windows.is_empty()) - setActiveWindow(*m_windows.begin()); + set_active_window(*m_windows.begin()); } void WSWindowManager::notifyTitleChanged(WSWindow& window) @@ -253,7 +253,7 @@ void WSWindowManager::processMouseEvent(MouseEvent& event) if (titleBarRectForWindow(window->rect()).contains(event.position())) { if (event.type() == WSEvent::MouseDown) { move_to_front(*window); - setActiveWindow(window); + set_active_window(window); } handleTitleBarMouseEvent(*window, event); return; @@ -262,7 +262,7 @@ void WSWindowManager::processMouseEvent(MouseEvent& event) if (window->rect().contains(event.position())) { if (event.type() == WSEvent::MouseDown) { move_to_front(*window); - setActiveWindow(window); + set_active_window(window); } // FIXME: Re-use the existing event instead of crafting a new one? auto localEvent = make(event.type(), event.x() - window->rect().x(), event.y() - window->rect().y(), event.button()); @@ -342,8 +342,8 @@ void WSWindowManager::event(WSEvent& event) if (event.isKeyEvent()) { // FIXME: This is a good place to hook key events globally. :) - if (m_activeWindow) - return m_activeWindow->event(event); + if (m_active_window) + return m_active_window->event(event); return; } @@ -354,17 +354,21 @@ void WSWindowManager::event(WSEvent& event) } } -void WSWindowManager::setActiveWindow(WSWindow* window) +void WSWindowManager::set_active_window(WSWindow* window) { LOCKER(m_lock); - if (window == m_activeWindow.ptr()) + if (window == m_active_window.ptr()) return; - if (auto* previously_active_window = m_activeWindow.ptr()) + if (auto* previously_active_window = m_active_window.ptr()) { + WSEventLoop::the().post_event(previously_active_window, make(WSEvent::WindowDeactivated)); invalidate(*previously_active_window); - m_activeWindow = window->makeWeakPtr(); - if (m_activeWindow) - invalidate(*m_activeWindow); + } + m_active_window = window->makeWeakPtr(); + if (m_active_window) { + WSEventLoop::the().post_event(m_active_window.ptr(), make(WSEvent::WindowActivated)); + invalidate(*m_active_window); + } } void WSWindowManager::invalidate() diff --git a/WindowServer/WSWindowManager.h b/WindowServer/WSWindowManager.h index abfc432ee69..4a7d26d2467 100644 --- a/WindowServer/WSWindowManager.h +++ b/WindowServer/WSWindowManager.h @@ -25,7 +25,7 @@ public: void notifyTitleChanged(WSWindow&); void notifyRectChanged(WSWindow&, const Rect& oldRect, const Rect& newRect); - WSWindow* activeWindow() { return m_activeWindow.ptr(); } + WSWindow* activeWindow() { return m_active_window.ptr(); } void move_to_front(WSWindow&); @@ -45,7 +45,7 @@ private: void processMouseEvent(MouseEvent&); void handleTitleBarMouseEvent(WSWindow&, MouseEvent&); - void setActiveWindow(WSWindow*); + void set_active_window(WSWindow*); virtual void event(WSEvent&) override; @@ -64,7 +64,7 @@ private: HashTable m_windows; InlineLinkedList m_windows_in_order; - WeakPtr m_activeWindow; + WeakPtr m_active_window; WeakPtr m_dragWindow;