diff --git a/Kernel/Process.h b/Kernel/Process.h index f84ca09fb7..45a0584338 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -42,6 +42,7 @@ struct DisplayInfo { class Process : public InlineLinkedListNode { friend class InlineLinkedListNode; + friend class WindowManager; // FIXME: Make a better API for allocate_region(). public: static Process* create_kernel_process(String&& name, void (*entry)()); static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector&& arguments = Vector(), Vector&& environment = Vector(), TTY* = nullptr); diff --git a/Widgets/CheckBox.cpp b/Widgets/CheckBox.cpp index c61b568372..8e36694245 100644 --- a/Widgets/CheckBox.cpp +++ b/Widgets/CheckBox.cpp @@ -78,8 +78,8 @@ void CheckBox::paintEvent(PaintEvent&) auto bitmap = CharacterBitmap::createFromASCII(isChecked() ? checkedBitmap : uncheckedBitmap, 11, 11); auto textRect = rect(); - textRect.setLeft(bitmap->width() + 4); - textRect.setTop(height() / 2 - font().glyphHeight() / 2); + textRect.set_left(bitmap->width() + 4); + textRect.set_top(height() / 2 - font().glyphHeight() / 2); Point bitmapPosition; bitmapPosition.setX(2); diff --git a/Widgets/GraphicsBitmap.cpp b/Widgets/GraphicsBitmap.cpp index abf8fe941f..6c7399c444 100644 --- a/Widgets/GraphicsBitmap.cpp +++ b/Widgets/GraphicsBitmap.cpp @@ -39,3 +39,8 @@ RGBA32* GraphicsBitmap::scanline(int y) return reinterpret_cast((((byte*)m_data) + (y * pitch))); } +const RGBA32* GraphicsBitmap::scanline(int y) const +{ + unsigned pitch = m_size.width() * sizeof(RGBA32); + return reinterpret_cast((((byte*)m_data) + (y * pitch))); +} diff --git a/Widgets/GraphicsBitmap.h b/Widgets/GraphicsBitmap.h index 4eb8aded17..19c271ad4a 100644 --- a/Widgets/GraphicsBitmap.h +++ b/Widgets/GraphicsBitmap.h @@ -12,6 +12,7 @@ public: ~GraphicsBitmap(); RGBA32* scanline(int y); + const RGBA32* scanline(int y) const; Size size() const { return m_size; } int width() const { return m_size.width(); } diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp index 2c4ee41686..4a7a5e0ea4 100644 --- a/Widgets/Painter.cpp +++ b/Widgets/Painter.cpp @@ -61,26 +61,6 @@ void Painter::drawRect(const Rect& rect, Color color) } } -void Painter::xorRect(const Rect& rect, Color color) -{ - Rect r = rect; - r.moveBy(m_translation); - - for (int y = max(r.top(), m_clipRect.top()); y < min(r.bottom(), m_clipRect.bottom()); ++y) { - auto* bits = m_target->scanline(y); - if (y == r.top() || y == (r.bottom() - 1)) { - for (int x = max(r.left(), m_clipRect.left()); x < min(r.right(), m_clipRect.right()); ++x) { - bits[x] ^= color.value(); - } - } else { - if (r.left() >= m_clipRect.left() && r.left() < m_clipRect.right()) - bits[r.left()] ^= color.value(); - if (r.right() >= m_clipRect.left() && r.right() < m_clipRect.right()) - bits[r.right() - 1] ^= color.value(); - } - } -} - void Painter::drawBitmap(const Point& p, const CharacterBitmap& bitmap, Color color) { Point point = p; @@ -215,3 +195,15 @@ void Painter::drawFocusRect(const Rect& rect) focusRect.setHeight(focusRect.height() - 2); drawRect(focusRect, Color(96, 96, 192)); } + +void Painter::blit(const Point& position, const GraphicsBitmap& source) +{ + Rect dst_rect(position, source.size()); + dst_rect.intersect(m_clipRect); + + for (int y = 0; y < dst_rect.height(); ++y) { + auto* dst_scanline = m_target->scanline(position.y() + y); + auto* src_scanline = source.scanline(y); + memcpy(dst_scanline + dst_rect.x(), src_scanline + (dst_rect.x() - position.x()), dst_rect.width() * 4); + } +} diff --git a/Widgets/Painter.h b/Widgets/Painter.h index 155f05f8a7..b7c3ff04e7 100644 --- a/Widgets/Painter.h +++ b/Widgets/Painter.h @@ -27,7 +27,7 @@ public: void drawFocusRect(const Rect&); - void xorRect(const Rect&, Color); + void blit(const Point&, const GraphicsBitmap&); const Font& font() const { return *m_font; } diff --git a/Widgets/Rect.cpp b/Widgets/Rect.cpp index fe7acb1629..fa4aa7aef9 100644 --- a/Widgets/Rect.cpp +++ b/Widgets/Rect.cpp @@ -1,5 +1,6 @@ #include "Rect.h" #include +#include "kstdio.h" void Rect::intersect(const Rect& other) { @@ -16,6 +17,8 @@ void Rect::intersect(const Rect& other) m_location.setX(l); m_location.setY(t); - m_size.setWidth(r - l); - m_size.setHeight(b - t); + m_size.setWidth((r - l) + 1); + m_size.setHeight((b - t) + 1); + + dbgprintf("intersection result: %d,%d %dx%d\n", x(), y(), width(), height()); } diff --git a/Widgets/Rect.h b/Widgets/Rect.h index 1d613f691e..301c891da1 100644 --- a/Widgets/Rect.h +++ b/Widgets/Rect.h @@ -76,18 +76,26 @@ public: int top() const { return y(); } int bottom() const { return y() + height() - 1; } - void setLeft(int left) + void set_left(int left) { - setWidth(x() - left); setX(left); } - void setTop(int top) + void set_top(int top) { - setHeight(y() - top); setY(top); } + void set_right(int right) + { + setWidth(right - x()); + } + + void set_bottom(int bottom) + { + setHeight(bottom - y()); + } + bool intersects(const Rect& other) const { return left() <= other.right() @@ -121,7 +129,7 @@ public: { Rect r(a); r.intersect(b); - return a; + return r; } private: diff --git a/Widgets/WindowManager.cpp b/Widgets/WindowManager.cpp index a2b5ff8274..a0c042f3c1 100644 --- a/Widgets/WindowManager.cpp +++ b/Widgets/WindowManager.cpp @@ -5,6 +5,8 @@ #include "AbstractScreen.h" #include "EventLoop.h" #include "FrameBuffer.h" +#include "Process.h" +#include "MemoryManager.h" static const int windowTitleBarHeight = 16; @@ -62,7 +64,10 @@ void WindowManager::initialize() WindowManager::WindowManager() { - m_root_bitmap = GraphicsBitmap::create_wrapper(FrameBuffer::the().rect().size(), FrameBuffer::the().scanline(0)); + auto size = FrameBuffer::the().rect().size(); + m_front_bitmap = GraphicsBitmap::create_wrapper(size, FrameBuffer::the().scanline(0)); + auto* region = current->allocate_region(LinearAddress(), size.width() * size.height() * 4, "back buffer", true, true, true); + m_back_bitmap = GraphicsBitmap::create_wrapper(FrameBuffer::the().rect().size(), (RGBA32*)region->linearAddress.get()); m_activeWindowBorderColor = Color(0, 64, 192); m_activeWindowTitleColor = Color::White; @@ -79,7 +84,7 @@ WindowManager::~WindowManager() void WindowManager::paintWindowFrame(Window& window) { - Painter p(*m_root_bitmap); + Painter p(*m_back_bitmap); //printf("[WM] paintWindowFrame {%p}, rect: %d,%d %dx%d\n", &window, window.rect().x(), window.rect().y(), window.rect().width(), window.rect().height()); @@ -95,17 +100,6 @@ void WindowManager::paintWindowFrame(Window& window) window.height() + 2 }; - if (!m_lastDragRect.is_empty()) { - p.xorRect(m_lastDragRect, Color::Red); - m_lastDragRect = Rect(); - } - - if (m_dragWindow.ptr() == &window) { - p.xorRect(outerRect, Color::Red); - m_lastDragRect = outerRect; - return; - } - auto titleColor = &window == activeWindow() ? m_activeWindowTitleColor : m_inactiveWindowTitleColor; auto borderColor = &window == activeWindow() ? m_activeWindowBorderColor : m_inactiveWindowBorderColor; @@ -195,12 +189,14 @@ void WindowManager::processMouseEvent(MouseEvent& event) if (event.type() == Event::MouseMove) { if (m_dragWindow) { + auto old_window_rect = m_dragWindow->rect(); Point pos = m_dragWindowOrigin; printf("[WM] Dragging [origin: %d,%d] now: %d,%d\n", m_dragOrigin.x(), m_dragOrigin.y(), event.x(), event.y()); pos.moveBy(event.x() - m_dragOrigin.x(), event.y() - m_dragOrigin.y()); m_dragWindow->setPositionWithoutRepaint(pos); - paintWindowFrame(*m_dragWindow); - FrameBuffer::the().flush(); + invalidate(outerRectForWindow(old_window_rect)); + invalidate(outerRectForWindow(m_dragWindow->rect())); + compose(); return; } } @@ -238,44 +234,41 @@ void WindowManager::compose() } return false; }; + Painter painter(*m_back_bitmap); { - Painter p(*m_root_bitmap); for (auto& r : m_invalidated_rects) { if (any_window_contains_rect(r)) continue; dbgprintf("Repaint root %d,%d %dx%d\n", r.x(), r.y(), r.width(), r.height()); - p.fillRect(r, Color(0, 72, 96)); + painter.fillRect(r, Color(0, 72, 96)); } } - auto& framebuffer = FrameBuffer::the(); for (auto* window = m_windows_in_order.head(); window; window = window->next()) { if (!window->backing()) continue; paintWindowFrame(*window); - if (m_dragWindow.ptr() == window) - continue; - framebuffer.blit(window->position(), *window->backing()); + painter.blit(window->position(), *window->backing()); } - framebuffer.flush(); - m_last_drawn_cursor_location = { -1, -1 }; redraw_cursor(); + for (auto& r : m_invalidated_rects) { + flush(r); + } m_invalidated_rects.clear(); } void WindowManager::redraw_cursor() { auto cursor_location = AbstractScreen::the().cursor_location(); - Painter painter(*m_root_bitmap); - painter.set_draw_op(Painter::DrawOp::Xor); + Painter painter(*m_front_bitmap); + Rect cursor_rect { cursor_location.x() - 10, cursor_location.y() - 10, 21, 21 }; + flush(m_last_cursor_rect); + flush(cursor_rect); auto draw_cross = [&painter] (const Point& p) { painter.drawLine({ p.x() - 10, p.y() }, { p.x() + 10, p.y() }, Color::Red); painter.drawLine({ p.x(), p.y() - 10 }, { p.x(), p.y() + 10 }, Color::Red); }; - if (cursor_location != m_last_drawn_cursor_location && m_last_drawn_cursor_location.x() != -1) - draw_cross(m_last_drawn_cursor_location); draw_cross(cursor_location); - m_last_drawn_cursor_location = cursor_location; - FrameBuffer::the().flush(); + m_last_cursor_rect = cursor_rect; } void WindowManager::event(Event& event) @@ -322,14 +315,26 @@ void WindowManager::invalidate() m_invalidated_rects.append(AbstractScreen::the().rect()); } -void WindowManager::invalidate(const Rect& rect) +void WindowManager::invalidate(const Rect& a_rect) { + // FIXME: This code is fugly. + Rect rect(a_rect); + auto screen_rect = AbstractScreen::the().rect(); + if (rect.left() < 0) + rect.set_left(0); + if (rect.top() < 0) + rect.set_top(0); + if (rect.right() > screen_rect.right()) + rect.set_right(screen_rect.right()); + if (rect.bottom() > screen_rect.bottom()) + rect.set_bottom(screen_rect.bottom()); if (rect.is_empty()) return; for (auto& r : m_invalidated_rects) { if (r.contains(rect)) return; } + m_invalidated_rects.append(rect); } @@ -337,3 +342,16 @@ void WindowManager::invalidate(const Window& window) { invalidate(outerRectForWindow(window.rect())); } + +void WindowManager::flush(const Rect& rect) +{ + auto& framebuffer = FrameBuffer::the(); + + for (int y = rect.top(); y <= rect.bottom(); ++y) { + auto* front_scanline = m_front_bitmap->scanline(y); + auto* back_scanline = m_back_bitmap->scanline(y); + memcpy(front_scanline + rect.x(), back_scanline + rect.x(), rect.width() * sizeof(RGBA32)); + } + + framebuffer.flush(); +} diff --git a/Widgets/WindowManager.h b/Widgets/WindowManager.h index d79e01ecb6..711c161b21 100644 --- a/Widgets/WindowManager.h +++ b/Widgets/WindowManager.h @@ -38,6 +38,7 @@ public: void invalidate(const Window&); void invalidate(const Rect&); void invalidate(); + void flush(const Rect&); private: WindowManager(); @@ -69,11 +70,12 @@ private: Rect m_dragStartRect; Rect m_dragEndRect; - Point m_last_drawn_cursor_location; + Rect m_last_cursor_rect; unsigned m_recompose_count { 0 }; - RetainPtr m_root_bitmap; + RetainPtr m_front_bitmap; + RetainPtr m_back_bitmap; Vector m_invalidated_rects; };