mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 09:28:13 +00:00
WindowServer: Factor out compositing from WSWindowManager into WSCompositor.
This is far from finished and the two classes are awkwardly grabbing at each other's innards, but here's a first step in the right direction.
This commit is contained in:
parent
508007f1dd
commit
ad908f1395
11 changed files with 487 additions and 426 deletions
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
#ifdef __clang__
|
||||
|
|
|
@ -26,6 +26,7 @@ WINDOWSERVER_OBJS = \
|
|||
WSWindowFrame.o \
|
||||
WSButton.o \
|
||||
WSCPUMonitor.o \
|
||||
WSCompositor.o \
|
||||
main.o
|
||||
|
||||
APP = WindowServer
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
#include <SharedBuffer.h>
|
||||
#include <WindowServer/WSAPITypes.h>
|
||||
#include <WindowServer/WSClientConnection.h>
|
||||
#include <WindowServer/WSClipboard.h>
|
||||
#include <WindowServer/WSCompositor.h>
|
||||
#include <WindowServer/WSEventLoop.h>
|
||||
#include <WindowServer/WSMenuBar.h>
|
||||
#include <WindowServer/WSMenu.h>
|
||||
#include <WindowServer/WSMenuBar.h>
|
||||
#include <WindowServer/WSMenuItem.h>
|
||||
#include <WindowServer/WSScreen.h>
|
||||
#include <WindowServer/WSWindow.h>
|
||||
#include <WindowServer/WSWindowManager.h>
|
||||
#include <WindowServer/WSAPITypes.h>
|
||||
#include <WindowServer/WSClipboard.h>
|
||||
#include <WindowServer/WSScreen.h>
|
||||
#include <WindowServer/WSWindowSwitcher.h>
|
||||
#include <SharedBuffer.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
HashMap<int, WSClientConnection*>* s_connections;
|
||||
|
||||
|
@ -342,7 +343,7 @@ void WSClientConnection::handle_request(const WSAPISetWindowOpacityRequest& requ
|
|||
|
||||
void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request)
|
||||
{
|
||||
WSWindowManager::the().set_wallpaper(request.wallpaper(), [&] (bool success) {
|
||||
WSCompositor::the().set_wallpaper(request.wallpaper(), [&] (bool success) {
|
||||
WSAPI_ServerMessage response;
|
||||
response.type = WSAPI_ServerMessage::Type::DidSetWallpaper;
|
||||
response.value = success;
|
||||
|
@ -352,7 +353,7 @@ void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request)
|
|||
|
||||
void WSClientConnection::handle_request(const WSAPIGetWallpaperRequest&)
|
||||
{
|
||||
auto path = WSWindowManager::the().wallpaper_path();
|
||||
auto path = WSCompositor::the().wallpaper_path();
|
||||
WSAPI_ServerMessage response;
|
||||
response.type = WSAPI_ServerMessage::Type::DidGetWallpaper;
|
||||
ASSERT(path.length() < (int)sizeof(response.text));
|
||||
|
|
334
Servers/WindowServer/WSCompositor.cpp
Normal file
334
Servers/WindowServer/WSCompositor.cpp
Normal file
|
@ -0,0 +1,334 @@
|
|||
#include "WSCompositor.h"
|
||||
#include "WSEvent.h"
|
||||
#include "WSEventLoop.h"
|
||||
#include "WSScreen.h"
|
||||
#include "WSWindow.h"
|
||||
#include "WSWindowManager.h"
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/PNGLoader.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
|
||||
WSCompositor& WSCompositor::the()
|
||||
{
|
||||
static WSCompositor s_the;
|
||||
return s_the;
|
||||
}
|
||||
|
||||
WSCompositor::WSCompositor()
|
||||
{
|
||||
auto size = WSScreen::the().size();
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(0));
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(size.height()));
|
||||
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
|
||||
m_wallpaper_path = "/res/wallpapers/retro.rgb";
|
||||
m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 });
|
||||
}
|
||||
|
||||
void WSCompositor::event(CEvent& event)
|
||||
{
|
||||
if (event.type() == WSEvent::WM_DeferredCompose) {
|
||||
m_pending_compose_event = false;
|
||||
compose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WSCompositor::compose()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
|
||||
auto dirty_rects = move(m_dirty_rects);
|
||||
dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, WSScreen::the().rect()));
|
||||
dirty_rects.add(Rect::intersection(m_last_cursor_rect, WSScreen::the().rect()));
|
||||
dirty_rects.add(Rect::intersection(current_cursor_rect(), WSScreen::the().rect()));
|
||||
#ifdef DEBUG_COUNTERS
|
||||
dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.rects().size());
|
||||
#endif
|
||||
|
||||
auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) {
|
||||
auto window_frame_rect = window.frame().rect();
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (dirty_rect.intersects(window_frame_rect))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (wm.any_opaque_window_contains_rect(dirty_rect))
|
||||
continue;
|
||||
if (!m_wallpaper)
|
||||
m_back_painter->fill_rect(dirty_rect, wm.m_background_color);
|
||||
else
|
||||
m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect);
|
||||
}
|
||||
|
||||
auto compose_window = [&] (WSWindow& window) -> IterationDecision {
|
||||
if (!any_dirty_rect_intersects_window(window))
|
||||
return IterationDecision::Continue;
|
||||
PainterStateSaver saver(*m_back_painter);
|
||||
m_back_painter->add_clip_rect(window.frame().rect());
|
||||
RetainPtr<GraphicsBitmap> backing_store = window.backing_store();
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (wm.any_opaque_window_above_this_one_contains_rect(window, dirty_rect))
|
||||
continue;
|
||||
PainterStateSaver saver(*m_back_painter);
|
||||
m_back_painter->add_clip_rect(dirty_rect);
|
||||
if (!backing_store)
|
||||
m_back_painter->fill_rect(dirty_rect, window.background_color());
|
||||
if (!window.is_fullscreen())
|
||||
window.frame().paint(*m_back_painter);
|
||||
if (!backing_store)
|
||||
continue;
|
||||
Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect());
|
||||
if (dirty_rect_in_window_coordinates.is_empty())
|
||||
continue;
|
||||
dirty_rect_in_window_coordinates.move_by(-window.position());
|
||||
auto dst = window.position();
|
||||
dst.move_by(dirty_rect_in_window_coordinates.location());
|
||||
|
||||
m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity());
|
||||
|
||||
if (backing_store->width() < window.width()) {
|
||||
Rect right_fill_rect { window.x() + backing_store->width(), window.y(), window.width() - backing_store->width(), window.height() };
|
||||
m_back_painter->fill_rect(right_fill_rect, window.background_color());
|
||||
}
|
||||
|
||||
if (backing_store->height() < window.height()) {
|
||||
Rect bottom_fill_rect { window.x(), window.y() + backing_store->height(), window.width(), window.height() - backing_store->height() };
|
||||
m_back_painter->fill_rect(bottom_fill_rect, window.background_color());
|
||||
}
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
};
|
||||
|
||||
if (auto* fullscreen_window = wm.active_fullscreen_window()) {
|
||||
compose_window(*fullscreen_window);
|
||||
} else {
|
||||
wm.for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
|
||||
return compose_window(window);
|
||||
});
|
||||
|
||||
draw_geometry_label();
|
||||
draw_menubar();
|
||||
}
|
||||
|
||||
draw_cursor();
|
||||
|
||||
if (m_flash_flush) {
|
||||
for (auto& rect : dirty_rects.rects())
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
}
|
||||
|
||||
flip_buffers();
|
||||
for (auto& r : dirty_rects.rects())
|
||||
flush(r);
|
||||
}
|
||||
|
||||
void WSCompositor::flush(const Rect& a_rect)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, WSScreen::the().rect());
|
||||
|
||||
#ifdef DEBUG_COUNTERS
|
||||
dbgprintf("[WM] flush #%u (%d,%d %dx%d)\n", ++m_flush_count, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
#endif
|
||||
|
||||
const RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
|
||||
RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
|
||||
size_t pitch = m_back_bitmap->pitch();
|
||||
|
||||
for (int y = 0; y < rect.height(); ++y) {
|
||||
fast_dword_copy(back_ptr, front_ptr, rect.width());
|
||||
front_ptr = (const RGBA32*)((const byte*)front_ptr + pitch);
|
||||
back_ptr = (RGBA32*)((byte*)back_ptr + pitch);
|
||||
}
|
||||
}
|
||||
|
||||
void WSCompositor::invalidate()
|
||||
{
|
||||
m_dirty_rects.clear_with_capacity();
|
||||
invalidate(WSScreen::the().rect());
|
||||
}
|
||||
|
||||
void WSCompositor::invalidate(const Rect& a_rect)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, WSScreen::the().rect());
|
||||
if (rect.is_empty())
|
||||
return;
|
||||
|
||||
m_dirty_rects.add(rect);
|
||||
|
||||
if (!m_pending_compose_event) {
|
||||
WSEventLoop::the().post_event(*this, make<WSEvent>(WSEvent::WM_DeferredCompose));
|
||||
m_pending_compose_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool WSCompositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
|
||||
{
|
||||
struct Context {
|
||||
String path;
|
||||
RetainPtr<GraphicsBitmap> bitmap;
|
||||
Function<void(bool)> callback;
|
||||
};
|
||||
auto context = make<Context>();
|
||||
context->path = path;
|
||||
context->callback = move(callback);
|
||||
|
||||
int rc = create_thread([] (void* ctx) -> int {
|
||||
OwnPtr<Context> context((Context*)ctx);
|
||||
context->bitmap = load_png(context->path);
|
||||
if (!context->bitmap) {
|
||||
context->callback(false);
|
||||
exit_thread(0);
|
||||
return 0;
|
||||
}
|
||||
the().deferred_invoke([context = move(context)] (auto&) {
|
||||
the().finish_setting_wallpaper(context->path, *context->bitmap);
|
||||
context->callback(true);
|
||||
});
|
||||
exit_thread(0);
|
||||
return 0;
|
||||
}, context.leak_ptr());
|
||||
ASSERT(rc == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WSCompositor::finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&& bitmap)
|
||||
{
|
||||
m_wallpaper_path = path;
|
||||
m_wallpaper = move(bitmap);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void WSCompositor::flip_buffers()
|
||||
{
|
||||
swap(m_front_bitmap, m_back_bitmap);
|
||||
swap(m_front_painter, m_back_painter);
|
||||
int new_y_offset = m_buffers_are_flipped ? 0 : WSScreen::the().height();
|
||||
WSScreen::the().set_y_offset(new_y_offset);
|
||||
m_buffers_are_flipped = !m_buffers_are_flipped;
|
||||
}
|
||||
|
||||
void WSCompositor::set_resolution(int width, int height)
|
||||
{
|
||||
auto screen_rect = WSScreen::the().rect();
|
||||
if (screen_rect.width() == width && screen_rect.height() == height)
|
||||
return;
|
||||
m_wallpaper_path = { };
|
||||
m_wallpaper = nullptr;
|
||||
WSScreen::the().set_resolution(width, height);
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(0));
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(height));
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
m_buffers_are_flipped = false;
|
||||
invalidate();
|
||||
compose();
|
||||
}
|
||||
|
||||
Rect WSCompositor::current_cursor_rect() const
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
return { WSScreen::the().cursor_location().translated(-wm.active_cursor().hotspot()), wm.active_cursor().size() };
|
||||
}
|
||||
|
||||
void WSCompositor::invalidate_cursor()
|
||||
{
|
||||
invalidate(current_cursor_rect());
|
||||
}
|
||||
|
||||
void WSCompositor::draw_geometry_label()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
auto* window_being_moved_or_resized = wm.m_drag_window ? wm.m_drag_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr);
|
||||
if (!window_being_moved_or_resized) {
|
||||
m_last_geometry_label_rect = { };
|
||||
return;
|
||||
}
|
||||
auto geometry_string = window_being_moved_or_resized->rect().to_string();
|
||||
if (!window_being_moved_or_resized->size_increment().is_null()) {
|
||||
int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
|
||||
int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height();
|
||||
geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps);
|
||||
}
|
||||
auto geometry_label_rect = Rect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 };
|
||||
geometry_label_rect.center_within(window_being_moved_or_resized->rect());
|
||||
m_back_painter->fill_rect(geometry_label_rect, Color::LightGray);
|
||||
m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray);
|
||||
m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center);
|
||||
m_last_geometry_label_rect = geometry_label_rect;
|
||||
}
|
||||
|
||||
void WSCompositor::draw_cursor()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
Rect cursor_rect = current_cursor_rect();
|
||||
Color inner_color = Color::White;
|
||||
Color outer_color = Color::Black;
|
||||
if (WSScreen::the().mouse_button_state() & (unsigned)MouseButton::Left)
|
||||
swap(inner_color, outer_color);
|
||||
m_back_painter->blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect());
|
||||
m_last_cursor_rect = cursor_rect;
|
||||
}
|
||||
|
||||
void WSCompositor::draw_menubar()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
auto menubar_rect = wm.menubar_rect();
|
||||
|
||||
m_back_painter->fill_rect(menubar_rect, Color::LightGray);
|
||||
m_back_painter->draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray);
|
||||
int index = 0;
|
||||
wm.for_each_active_menubar_menu([&] (WSMenu& menu) {
|
||||
Color text_color = Color::Black;
|
||||
if (&menu == wm.current_menu()) {
|
||||
m_back_painter->fill_rect(menu.rect_in_menubar(), wm.menu_selection_color());
|
||||
text_color = Color::White;
|
||||
}
|
||||
m_back_painter->draw_text(
|
||||
menu.text_rect_in_menubar(),
|
||||
menu.name(),
|
||||
index == 1 ? wm.app_menu_font() : wm.menu_font(),
|
||||
TextAlignment::CenterLeft,
|
||||
text_color
|
||||
);
|
||||
++index;
|
||||
return true;
|
||||
});
|
||||
|
||||
int username_width = Font::default_bold_font().width(wm.m_username);
|
||||
Rect username_rect {
|
||||
menubar_rect.right() - wm.menubar_menu_margin() / 2 - Font::default_bold_font().width(wm.m_username),
|
||||
menubar_rect.y(),
|
||||
username_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
m_back_painter->draw_text(username_rect, wm.m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
time_t now = time(nullptr);
|
||||
auto* tm = localtime(&now);
|
||||
auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
int time_width = wm.font().width(time_text);
|
||||
Rect time_rect {
|
||||
username_rect.left() - wm.menubar_menu_margin() / 2 - time_width,
|
||||
menubar_rect.y(),
|
||||
time_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
|
||||
m_back_painter->draw_text(time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
Rect cpu_rect { time_rect.right() - wm.font().width(time_text) - wm.m_cpu_monitor.capacity() - 10, time_rect.y() + 1, wm.m_cpu_monitor.capacity(), time_rect.height() - 2 };
|
||||
wm.m_cpu_monitor.paint(*m_back_painter, cpu_rect);
|
||||
}
|
58
Servers/WindowServer/WSCompositor.h
Normal file
58
Servers/WindowServer/WSCompositor.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <LibCore/CObject.h>
|
||||
#include <SharedGraphics/DisjointRectSet.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
|
||||
class Painter;
|
||||
class WSCursor;
|
||||
|
||||
class WSCompositor final : public CObject {
|
||||
public:
|
||||
static WSCompositor& the();
|
||||
|
||||
void compose();
|
||||
void invalidate();
|
||||
void invalidate(const Rect&);
|
||||
|
||||
void set_resolution(int width, int height);
|
||||
|
||||
bool set_wallpaper(const String& path, Function<void(bool)>&& callback);
|
||||
String wallpaper_path() const { return m_wallpaper_path; }
|
||||
|
||||
void invalidate_cursor();
|
||||
Rect current_cursor_rect() const;
|
||||
|
||||
private:
|
||||
virtual void event(CEvent&) override;
|
||||
virtual const char* class_name() const override { return "WSCompositor"; }
|
||||
|
||||
WSCompositor();
|
||||
void flip_buffers();
|
||||
void flush(const Rect&);
|
||||
void draw_cursor();
|
||||
void draw_geometry_label();
|
||||
void draw_menubar();
|
||||
void finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&&);
|
||||
|
||||
unsigned m_compose_count { 0 };
|
||||
unsigned m_flush_count { 0 };
|
||||
bool m_pending_compose_event { false };
|
||||
bool m_flash_flush { false };
|
||||
bool m_buffers_are_flipped { false };
|
||||
|
||||
RetainPtr<GraphicsBitmap> m_front_bitmap;
|
||||
RetainPtr<GraphicsBitmap> m_back_bitmap;
|
||||
OwnPtr<Painter> m_back_painter;
|
||||
OwnPtr<Painter> m_front_painter;
|
||||
|
||||
DisjointRectSet m_dirty_rects;
|
||||
|
||||
Rect m_last_cursor_rect;
|
||||
Rect m_last_geometry_label_rect;
|
||||
|
||||
String m_wallpaper_path;
|
||||
RetainPtr<GraphicsBitmap> m_wallpaper;
|
||||
};
|
|
@ -1,11 +1,12 @@
|
|||
#include "WSScreen.h"
|
||||
#include "WSEventLoop.h"
|
||||
#include "WSCompositor.h"
|
||||
#include "WSEvent.h"
|
||||
#include "WSEventLoop.h"
|
||||
#include "WSScreen.h"
|
||||
#include "WSWindowManager.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static WSScreen* s_the;
|
||||
|
||||
|
@ -86,7 +87,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, int dz, unsigned buttons)
|
|||
}
|
||||
|
||||
if (m_cursor_location != prev_location)
|
||||
WSWindowManager::the().invalidate_cursor();
|
||||
WSCompositor::the().invalidate_cursor();
|
||||
}
|
||||
|
||||
void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/StylePainter.h>
|
||||
#include <WindowServer/WSButton.h>
|
||||
#include <WindowServer/WSCompositor.h>
|
||||
#include <WindowServer/WSEvent.h>
|
||||
#include <WindowServer/WSWindow.h>
|
||||
#include <WindowServer/WSWindowFrame.h>
|
||||
#include <WindowServer/WSWindowManager.h>
|
||||
#include <WindowServer/WSWindow.h>
|
||||
#include <WindowServer/WSEvent.h>
|
||||
#include <WindowServer/WSButton.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/StylePainter.h>
|
||||
|
||||
static const int window_titlebar_height = 19;
|
||||
|
||||
|
@ -294,7 +295,7 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event)
|
|||
int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3));
|
||||
int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3));
|
||||
wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]);
|
||||
wm.invalidate_cursor();
|
||||
WSCompositor::the().invalidate_cursor();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
#include "WSWindowManager.h"
|
||||
#include "WSWindow.h"
|
||||
#include "WSScreen.h"
|
||||
#include "WSCompositor.h"
|
||||
#include "WSEventLoop.h"
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <errno.h>
|
||||
#include "WSMenu.h"
|
||||
#include "WSMenuBar.h"
|
||||
#include "WSMenuItem.h"
|
||||
#include "WSScreen.h"
|
||||
#include "WSWindow.h"
|
||||
#include "WSWindowManager.h"
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/CTimer.h>
|
||||
#include <SharedGraphics/CharacterBitmap.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/PNGLoader.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/StylePainter.h>
|
||||
#include <WindowServer/WSAPITypes.h>
|
||||
#include <WindowServer/WSButton.h>
|
||||
#include <WindowServer/WSClientConnection.h>
|
||||
#include <unistd.h>
|
||||
#include <WindowServer/WSCursor.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <SharedGraphics/StylePainter.h>
|
||||
#include <SharedGraphics/PNGLoader.h>
|
||||
#include <WindowServer/WSCursor.h>
|
||||
#include <WindowServer/WSButton.h>
|
||||
#include <LibCore/CTimer.h>
|
||||
#include <WindowServer/WSAPITypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//#define DEBUG_COUNTERS
|
||||
//#define RESIZE_DEBUG
|
||||
|
@ -33,35 +34,18 @@ WSWindowManager& WSWindowManager::the()
|
|||
return *s_the;
|
||||
}
|
||||
|
||||
void WSWindowManager::flip_buffers()
|
||||
{
|
||||
swap(m_front_bitmap, m_back_bitmap);
|
||||
swap(m_front_painter, m_back_painter);
|
||||
int new_y_offset = m_buffers_are_flipped ? 0 : m_screen_rect.height();
|
||||
WSScreen::the().set_y_offset(new_y_offset);
|
||||
m_buffers_are_flipped = !m_buffers_are_flipped;
|
||||
}
|
||||
|
||||
WSWindowManager::WSWindowManager()
|
||||
: m_screen(WSScreen::the())
|
||||
, m_screen_rect(m_screen.rect())
|
||||
, m_flash_flush(false)
|
||||
{
|
||||
s_the = this;
|
||||
|
||||
#ifndef DEBUG_COUNTERS
|
||||
(void)m_compose_count;
|
||||
(void)m_flush_count;
|
||||
#endif
|
||||
auto size = m_screen_rect.size();
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(0));
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(size.height()));
|
||||
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
|
||||
m_front_painter->set_font(font());
|
||||
m_back_painter->set_font(font());
|
||||
m_arrow_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/arrow.png"), { 2, 2 });
|
||||
m_resize_horizontally_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-horizontal.png"));
|
||||
m_resize_vertically_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-vertical.png"));
|
||||
m_resize_diagonally_tlbr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-tlbr.png"));
|
||||
m_resize_diagonally_bltr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-bltr.png"));
|
||||
m_i_beam_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/i-beam.png"));
|
||||
m_disallowed_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/disallowed.png"));
|
||||
m_move_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/move.png"));
|
||||
|
||||
m_background_color = Color(50, 50, 50);
|
||||
m_active_window_border_color = Color(110, 34, 9);
|
||||
|
@ -77,18 +61,6 @@ WSWindowManager::WSWindowManager()
|
|||
m_highlight_window_border_color2 = Color::from_rgb(0xfabbbb);
|
||||
m_highlight_window_title_color = Color::White;
|
||||
|
||||
m_arrow_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/arrow.png"), { 2, 2 });
|
||||
m_resize_horizontally_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-horizontal.png"));
|
||||
m_resize_vertically_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-vertical.png"));
|
||||
m_resize_diagonally_tlbr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-tlbr.png"));
|
||||
m_resize_diagonally_bltr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-bltr.png"));
|
||||
m_i_beam_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/i-beam.png"));
|
||||
m_disallowed_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/disallowed.png"));
|
||||
m_move_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/move.png"));
|
||||
|
||||
m_wallpaper_path = "/res/wallpapers/retro.rgb";
|
||||
m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 });
|
||||
|
||||
m_username = getlogin();
|
||||
|
||||
m_menu_selection_color = Color::from_rgb(0x84351a);
|
||||
|
@ -173,7 +145,7 @@ WSWindowManager::WSWindowManager()
|
|||
});
|
||||
|
||||
invalidate();
|
||||
compose();
|
||||
WSCompositor::the().compose();
|
||||
}
|
||||
|
||||
WSWindowManager::~WSWindowManager()
|
||||
|
@ -205,72 +177,14 @@ void WSWindowManager::tick_clock()
|
|||
invalidate(menubar_rect());
|
||||
}
|
||||
|
||||
bool WSWindowManager::set_wallpaper(const String& path, Function<void(bool)>&& callback)
|
||||
{
|
||||
struct Context {
|
||||
String path;
|
||||
RetainPtr<GraphicsBitmap> bitmap;
|
||||
Function<void(bool)> callback;
|
||||
};
|
||||
auto context = make<Context>();
|
||||
context->path = path;
|
||||
context->callback = move(callback);
|
||||
|
||||
int rc = create_thread([] (void* ctx) -> int {
|
||||
OwnPtr<Context> context((Context*)ctx);
|
||||
context->bitmap = load_png(context->path);
|
||||
if (!context->bitmap) {
|
||||
context->callback(false);
|
||||
exit_thread(0);
|
||||
return 0;
|
||||
}
|
||||
the().deferred_invoke([context = move(context)] (auto&) {
|
||||
the().finish_setting_wallpaper(context->path, *context->bitmap);
|
||||
context->callback(true);
|
||||
});
|
||||
exit_thread(0);
|
||||
return 0;
|
||||
}, context.leak_ptr());
|
||||
ASSERT(rc == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WSWindowManager::finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&& bitmap)
|
||||
{
|
||||
m_wallpaper_path = path;
|
||||
m_wallpaper = move(bitmap);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void WSWindowManager::set_resolution(int width, int height)
|
||||
{
|
||||
if (m_screen_rect.width() == width && m_screen_rect.height() == height)
|
||||
return;
|
||||
m_wallpaper_path = { };
|
||||
m_wallpaper = nullptr;
|
||||
m_screen.set_resolution(width, height);
|
||||
m_screen_rect = m_screen.rect();
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(0));
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(height));
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
m_buffers_are_flipped = false;
|
||||
invalidate();
|
||||
compose();
|
||||
|
||||
WSCompositor::the().set_resolution(width, height);
|
||||
WSClientConnection::for_each_client([&] (WSClientConnection& client) {
|
||||
client.notify_about_new_screen_rect(m_screen_rect);
|
||||
client.notify_about_new_screen_rect(WSScreen::the().rect());
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void WSWindowManager::for_each_active_menubar_menu(Callback callback)
|
||||
{
|
||||
callback(*m_system_menu);
|
||||
if (m_current_menubar)
|
||||
m_current_menubar->for_each_menu(callback);
|
||||
}
|
||||
|
||||
int WSWindowManager::menubar_menu_margin() const
|
||||
{
|
||||
|
@ -315,8 +229,8 @@ void WSWindowManager::add_window(WSWindow& window)
|
|||
m_windows_in_order.append(&window);
|
||||
|
||||
if (window.is_fullscreen()) {
|
||||
WSEventLoop::the().post_event(window, make<WSResizeEvent>(window.rect(), m_screen_rect));
|
||||
window.set_rect(m_screen_rect);
|
||||
WSEventLoop::the().post_event(window, make<WSResizeEvent>(window.rect(), WSScreen::the().rect()));
|
||||
window.set_rect(WSScreen::the().rect());
|
||||
}
|
||||
|
||||
set_active_window(&window);
|
||||
|
@ -859,7 +773,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& hovere
|
|||
void WSWindowManager::clear_resize_candidate()
|
||||
{
|
||||
if (m_resize_candidate)
|
||||
invalidate_cursor();
|
||||
WSCompositor::the().invalidate_cursor();
|
||||
m_resize_candidate = nullptr;
|
||||
}
|
||||
|
||||
|
@ -915,167 +829,11 @@ bool WSWindowManager::any_opaque_window_above_this_one_contains_rect(const WSWin
|
|||
return found_containing_window;
|
||||
};
|
||||
|
||||
void WSWindowManager::compose()
|
||||
{
|
||||
auto dirty_rects = move(m_dirty_rects);
|
||||
dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, m_screen_rect));
|
||||
dirty_rects.add(Rect::intersection(m_last_cursor_rect, m_screen_rect));
|
||||
dirty_rects.add(Rect::intersection(current_cursor_rect(), m_screen_rect));
|
||||
#ifdef DEBUG_COUNTERS
|
||||
dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.rects().size());
|
||||
#endif
|
||||
|
||||
auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) {
|
||||
auto window_frame_rect = window.frame().rect();
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (dirty_rect.intersects(window_frame_rect))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (any_opaque_window_contains_rect(dirty_rect))
|
||||
continue;
|
||||
if (!m_wallpaper)
|
||||
m_back_painter->fill_rect(dirty_rect, m_background_color);
|
||||
else
|
||||
m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect);
|
||||
}
|
||||
|
||||
auto compose_window = [&] (WSWindow& window) -> IterationDecision {
|
||||
if (!any_dirty_rect_intersects_window(window))
|
||||
return IterationDecision::Continue;
|
||||
PainterStateSaver saver(*m_back_painter);
|
||||
m_back_painter->add_clip_rect(window.frame().rect());
|
||||
RetainPtr<GraphicsBitmap> backing_store = window.backing_store();
|
||||
for (auto& dirty_rect : dirty_rects.rects()) {
|
||||
if (any_opaque_window_above_this_one_contains_rect(window, dirty_rect))
|
||||
continue;
|
||||
PainterStateSaver saver(*m_back_painter);
|
||||
m_back_painter->add_clip_rect(dirty_rect);
|
||||
if (!backing_store)
|
||||
m_back_painter->fill_rect(dirty_rect, window.background_color());
|
||||
if (!window.is_fullscreen())
|
||||
window.frame().paint(*m_back_painter);
|
||||
if (!backing_store)
|
||||
continue;
|
||||
Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect());
|
||||
if (dirty_rect_in_window_coordinates.is_empty())
|
||||
continue;
|
||||
dirty_rect_in_window_coordinates.move_by(-window.position());
|
||||
auto dst = window.position();
|
||||
dst.move_by(dirty_rect_in_window_coordinates.location());
|
||||
|
||||
m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity());
|
||||
|
||||
if (backing_store->width() < window.width()) {
|
||||
Rect right_fill_rect { window.x() + backing_store->width(), window.y(), window.width() - backing_store->width(), window.height() };
|
||||
m_back_painter->fill_rect(right_fill_rect, window.background_color());
|
||||
}
|
||||
|
||||
if (backing_store->height() < window.height()) {
|
||||
Rect bottom_fill_rect { window.x(), window.y() + backing_store->height(), window.width(), window.height() - backing_store->height() };
|
||||
m_back_painter->fill_rect(bottom_fill_rect, window.background_color());
|
||||
}
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
};
|
||||
|
||||
if (auto* fullscreen_window = active_fullscreen_window()) {
|
||||
compose_window(*fullscreen_window);
|
||||
} else {
|
||||
for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
|
||||
return compose_window(window);
|
||||
});
|
||||
|
||||
draw_geometry_label();
|
||||
draw_menubar();
|
||||
}
|
||||
|
||||
draw_cursor();
|
||||
|
||||
if (m_flash_flush) {
|
||||
for (auto& rect : dirty_rects.rects())
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
}
|
||||
|
||||
flip_buffers();
|
||||
for (auto& r : dirty_rects.rects())
|
||||
flush(r);
|
||||
}
|
||||
|
||||
Rect WSWindowManager::current_cursor_rect() const
|
||||
{
|
||||
return { m_screen.cursor_location().translated(-active_cursor().hotspot()), active_cursor().size() };
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate_cursor()
|
||||
{
|
||||
invalidate(current_cursor_rect());
|
||||
}
|
||||
|
||||
Rect WSWindowManager::menubar_rect() const
|
||||
{
|
||||
if (active_fullscreen_window())
|
||||
return { };
|
||||
return { 0, 0, m_screen_rect.width(), 18 };
|
||||
}
|
||||
|
||||
void WSWindowManager::draw_menubar()
|
||||
{
|
||||
auto menubar_rect = this->menubar_rect();
|
||||
|
||||
m_back_painter->fill_rect(menubar_rect, Color::LightGray);
|
||||
m_back_painter->draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray);
|
||||
int index = 0;
|
||||
for_each_active_menubar_menu([&] (WSMenu& menu) {
|
||||
Color text_color = Color::Black;
|
||||
if (&menu == current_menu()) {
|
||||
m_back_painter->fill_rect(menu.rect_in_menubar(), menu_selection_color());
|
||||
text_color = Color::White;
|
||||
}
|
||||
m_back_painter->draw_text(
|
||||
menu.text_rect_in_menubar(),
|
||||
menu.name(),
|
||||
index == 1 ? app_menu_font() : menu_font(),
|
||||
TextAlignment::CenterLeft,
|
||||
text_color
|
||||
);
|
||||
++index;
|
||||
return true;
|
||||
});
|
||||
|
||||
int username_width = Font::default_bold_font().width(m_username);
|
||||
Rect username_rect {
|
||||
menubar_rect.right() - menubar_menu_margin() / 2 - Font::default_bold_font().width(m_username),
|
||||
menubar_rect.y(),
|
||||
username_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
m_back_painter->draw_text(username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
time_t now = time(nullptr);
|
||||
auto* tm = localtime(&now);
|
||||
auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
int time_width = font().width(time_text);
|
||||
Rect time_rect {
|
||||
username_rect.left() - menubar_menu_margin() / 2 - time_width,
|
||||
menubar_rect.y(),
|
||||
time_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
|
||||
m_back_painter->draw_text(time_rect, time_text, font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
Rect cpu_rect { time_rect.right() - font().width(time_text) - m_cpu_monitor.capacity() - 10, time_rect.y() + 1, m_cpu_monitor.capacity(), time_rect.height() - 2 };
|
||||
m_cpu_monitor.paint(*m_back_painter, cpu_rect);
|
||||
return { 0, 0, WSScreen::the().rect().width(), 18 };
|
||||
}
|
||||
|
||||
void WSWindowManager::draw_window_switcher()
|
||||
|
@ -1084,38 +842,6 @@ void WSWindowManager::draw_window_switcher()
|
|||
m_switcher.draw();
|
||||
}
|
||||
|
||||
void WSWindowManager::draw_geometry_label()
|
||||
{
|
||||
auto* window_being_moved_or_resized = m_drag_window ? m_drag_window.ptr() : (m_resize_window ? m_resize_window.ptr() : nullptr);
|
||||
if (!window_being_moved_or_resized) {
|
||||
m_last_geometry_label_rect = { };
|
||||
return;
|
||||
}
|
||||
auto geometry_string = window_being_moved_or_resized->rect().to_string();
|
||||
if (!window_being_moved_or_resized->size_increment().is_null()) {
|
||||
int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
|
||||
int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height();
|
||||
geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps);
|
||||
}
|
||||
auto geometry_label_rect = Rect { 0, 0, font().width(geometry_string) + 16, font().glyph_height() + 10 };
|
||||
geometry_label_rect.center_within(window_being_moved_or_resized->rect());
|
||||
m_back_painter->fill_rect(geometry_label_rect, Color::LightGray);
|
||||
m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray);
|
||||
m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center);
|
||||
m_last_geometry_label_rect = geometry_label_rect;
|
||||
}
|
||||
|
||||
void WSWindowManager::draw_cursor()
|
||||
{
|
||||
Rect cursor_rect = current_cursor_rect();
|
||||
Color inner_color = Color::White;
|
||||
Color outer_color = Color::Black;
|
||||
if (m_screen.mouse_button_state() & (unsigned)MouseButton::Left)
|
||||
swap(inner_color, outer_color);
|
||||
m_back_painter->blit(cursor_rect.location(), active_cursor().bitmap(), active_cursor().rect());
|
||||
m_last_cursor_rect = cursor_rect;
|
||||
}
|
||||
|
||||
void WSWindowManager::event(CEvent& event)
|
||||
{
|
||||
if (static_cast<WSEvent&>(event).is_mouse_event()) {
|
||||
|
@ -1140,12 +866,6 @@ void WSWindowManager::event(CEvent& event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (event.type() == WSEvent::WM_DeferredCompose) {
|
||||
m_pending_compose_event = false;
|
||||
compose();
|
||||
return;
|
||||
}
|
||||
|
||||
CObject::event(event);
|
||||
}
|
||||
|
||||
|
@ -1206,28 +926,12 @@ void WSWindowManager::set_hovered_window(WSWindow* window)
|
|||
|
||||
void WSWindowManager::invalidate()
|
||||
{
|
||||
m_dirty_rects.clear_with_capacity();
|
||||
invalidate(m_screen_rect);
|
||||
WSCompositor::the().invalidate();
|
||||
}
|
||||
|
||||
void WSWindowManager::recompose_immediately()
|
||||
void WSWindowManager::invalidate(const Rect& rect)
|
||||
{
|
||||
m_dirty_rects.clear_with_capacity();
|
||||
invalidate(m_screen_rect, false);
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate(const Rect& a_rect, bool should_schedule_compose_event)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, m_screen_rect);
|
||||
if (rect.is_empty())
|
||||
return;
|
||||
|
||||
m_dirty_rects.add(rect);
|
||||
|
||||
if (should_schedule_compose_event && !m_pending_compose_event) {
|
||||
WSEventLoop::the().post_event(*this, make<WSEvent>(WSEvent::WM_DeferredCompose));
|
||||
m_pending_compose_event = true;
|
||||
}
|
||||
WSCompositor::the().invalidate(rect);
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate(const WSWindow& window)
|
||||
|
@ -1249,25 +953,6 @@ void WSWindowManager::invalidate(const WSWindow& window, const Rect& rect)
|
|||
invalidate(inner_rect);
|
||||
}
|
||||
|
||||
void WSWindowManager::flush(const Rect& a_rect)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, m_screen_rect);
|
||||
|
||||
#ifdef DEBUG_COUNTERS
|
||||
dbgprintf("[WM] flush #%u (%d,%d %dx%d)\n", ++m_flush_count, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
#endif
|
||||
|
||||
const RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
|
||||
RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
|
||||
size_t pitch = m_back_bitmap->pitch();
|
||||
|
||||
for (int y = 0; y < rect.height(); ++y) {
|
||||
fast_dword_copy(back_ptr, front_ptr, rect.width());
|
||||
front_ptr = (const RGBA32*)((const byte*)front_ptr + pitch);
|
||||
back_ptr = (RGBA32*)((byte*)back_ptr + pitch);
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::close_menu(WSMenu& menu)
|
||||
{
|
||||
if (current_menu() == &menu)
|
||||
|
@ -1337,7 +1022,7 @@ void WSWindowManager::set_resize_candidate(WSWindow& window, ResizeDirection dir
|
|||
|
||||
Rect WSWindowManager::maximized_window_rect(const WSWindow& window) const
|
||||
{
|
||||
Rect rect = m_screen_rect;
|
||||
Rect rect = WSScreen::the().rect();
|
||||
|
||||
// Subtract window title bar (leaving the border)
|
||||
rect.set_y(rect.y() + window.frame().title_bar_rect().height());
|
||||
|
|
|
@ -31,6 +31,7 @@ class WSButton;
|
|||
enum class ResizeDirection { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft };
|
||||
|
||||
class WSWindowManager : public CObject {
|
||||
friend class WSCompositor;
|
||||
friend class WSWindowFrame;
|
||||
friend class WSWindowSwitcher;
|
||||
public:
|
||||
|
@ -57,7 +58,6 @@ public:
|
|||
|
||||
void move_to_front_and_make_active(WSWindow&);
|
||||
|
||||
void invalidate_cursor();
|
||||
void draw_cursor();
|
||||
void draw_menubar();
|
||||
void draw_window_switcher();
|
||||
|
@ -69,11 +69,20 @@ public:
|
|||
WSMenu* current_menu() { return m_current_menu.ptr(); }
|
||||
void set_current_menu(WSMenu*);
|
||||
|
||||
const WSCursor& active_cursor() const;
|
||||
const WSCursor& arrow_cursor() const { return *m_arrow_cursor; }
|
||||
const WSCursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; }
|
||||
const WSCursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; }
|
||||
const WSCursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; }
|
||||
const WSCursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; }
|
||||
const WSCursor& i_beam_cursor() const { return *m_i_beam_cursor; }
|
||||
const WSCursor& disallowed_cursor() const { return *m_disallowed_cursor; }
|
||||
const WSCursor& move_cursor() const { return *m_move_cursor; }
|
||||
|
||||
void invalidate(const WSWindow&);
|
||||
void invalidate(const WSWindow&, const Rect&);
|
||||
void invalidate(const Rect&, bool should_schedule_compose_event = true);
|
||||
void invalidate(const Rect&);
|
||||
void invalidate();
|
||||
void recompose_immediately();
|
||||
void flush(const Rect&);
|
||||
|
||||
const Font& font() const;
|
||||
|
@ -88,21 +97,6 @@ public:
|
|||
|
||||
void set_resolution(int width, int height);
|
||||
|
||||
bool set_wallpaper(const String& path, Function<void(bool)>&& callback);
|
||||
String wallpaper_path() const { return m_wallpaper_path; }
|
||||
|
||||
const WSCursor& active_cursor() const;
|
||||
Rect current_cursor_rect() const;
|
||||
|
||||
const WSCursor& arrow_cursor() const { return *m_arrow_cursor; }
|
||||
const WSCursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; }
|
||||
const WSCursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; }
|
||||
const WSCursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; }
|
||||
const WSCursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; }
|
||||
const WSCursor& i_beam_cursor() const { return *m_i_beam_cursor; }
|
||||
const WSCursor& disallowed_cursor() const { return *m_disallowed_cursor; }
|
||||
const WSCursor& move_cursor() const { return *m_move_cursor; }
|
||||
|
||||
void set_active_window(WSWindow*);
|
||||
void set_hovered_button(WSButton*);
|
||||
|
||||
|
@ -143,7 +137,15 @@ private:
|
|||
template<typename Callback> IterationDecision for_each_visible_window_from_back_to_front(Callback);
|
||||
template<typename Callback> void for_each_window_listening_to_wm_events(Callback);
|
||||
template<typename Callback> void for_each_window(Callback);
|
||||
template<typename Callback> void for_each_active_menubar_menu(Callback);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_active_menubar_menu(Callback callback)
|
||||
{
|
||||
callback(*m_system_menu);
|
||||
if (m_current_menubar)
|
||||
m_current_menubar->for_each_menu(callback);
|
||||
}
|
||||
|
||||
void close_current_menu();
|
||||
virtual void event(CEvent&) override;
|
||||
void compose();
|
||||
|
@ -154,10 +156,15 @@ private:
|
|||
void tell_wm_listener_about_window_icon(WSWindow& listener, WSWindow&);
|
||||
void tell_wm_listener_about_window_rect(WSWindow& listener, WSWindow&);
|
||||
void pick_new_active_window();
|
||||
void finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&&);
|
||||
|
||||
WSScreen& m_screen;
|
||||
Rect m_screen_rect;
|
||||
RetainPtr<WSCursor> m_arrow_cursor;
|
||||
RetainPtr<WSCursor> m_resize_horizontally_cursor;
|
||||
RetainPtr<WSCursor> m_resize_vertically_cursor;
|
||||
RetainPtr<WSCursor> m_resize_diagonally_tlbr_cursor;
|
||||
RetainPtr<WSCursor> m_resize_diagonally_bltr_cursor;
|
||||
RetainPtr<WSCursor> m_i_beam_cursor;
|
||||
RetainPtr<WSCursor> m_disallowed_cursor;
|
||||
RetainPtr<WSCursor> m_move_cursor;
|
||||
|
||||
Color m_background_color;
|
||||
Color m_active_window_border_color;
|
||||
|
@ -208,37 +215,6 @@ private:
|
|||
Point m_resize_origin;
|
||||
ResizeDirection m_resize_direction { ResizeDirection::None };
|
||||
|
||||
Rect m_last_cursor_rect;
|
||||
Rect m_last_geometry_label_rect;
|
||||
|
||||
unsigned m_compose_count { 0 };
|
||||
unsigned m_flush_count { 0 };
|
||||
|
||||
RetainPtr<GraphicsBitmap> m_front_bitmap;
|
||||
RetainPtr<GraphicsBitmap> m_back_bitmap;
|
||||
|
||||
DisjointRectSet m_dirty_rects;
|
||||
|
||||
bool m_pending_compose_event { false };
|
||||
|
||||
RetainPtr<WSCursor> m_arrow_cursor;
|
||||
RetainPtr<WSCursor> m_resize_horizontally_cursor;
|
||||
RetainPtr<WSCursor> m_resize_vertically_cursor;
|
||||
RetainPtr<WSCursor> m_resize_diagonally_tlbr_cursor;
|
||||
RetainPtr<WSCursor> m_resize_diagonally_bltr_cursor;
|
||||
RetainPtr<WSCursor> m_i_beam_cursor;
|
||||
RetainPtr<WSCursor> m_disallowed_cursor;
|
||||
RetainPtr<WSCursor> m_move_cursor;
|
||||
|
||||
OwnPtr<Painter> m_back_painter;
|
||||
OwnPtr<Painter> m_front_painter;
|
||||
|
||||
String m_wallpaper_path;
|
||||
RetainPtr<GraphicsBitmap> m_wallpaper;
|
||||
|
||||
bool m_flash_flush { false };
|
||||
bool m_buffers_are_flipped { false };
|
||||
|
||||
byte m_keyboard_modifiers { 0 };
|
||||
|
||||
OwnPtr<WSMenu> m_system_menu;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <WindowServer/WSWindowSwitcher.h>
|
||||
#include <WindowServer/WSWindowManager.h>
|
||||
#include <WindowServer/WSEvent.h>
|
||||
#include <WindowServer/WSScreen.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/StylePainter.h>
|
||||
|
||||
|
@ -130,7 +131,7 @@ void WSWindowSwitcher::refresh()
|
|||
int space_for_window_rect = 180;
|
||||
m_rect.set_width(thumbnail_width() + longest_title_width + space_for_window_rect + padding() * 2 + item_padding() * 2);
|
||||
m_rect.set_height(window_count * item_height() + padding() * 2);
|
||||
m_rect.center_within(wm.m_screen_rect);
|
||||
m_rect.center_within(WSScreen::the().rect());
|
||||
if (!m_switcher_window)
|
||||
m_switcher_window = make<WSWindow>(*this, WSWindowType::WindowSwitcher);
|
||||
m_switcher_window->set_rect(m_rect);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <WindowServer/WSScreen.h>
|
||||
#include <WindowServer/WSWindowManager.h>
|
||||
#include <WindowServer/WSEventLoop.h>
|
||||
#include <WindowServer/WSCompositor.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -18,6 +19,7 @@ int main(int, char**)
|
|||
|
||||
WSEventLoop loop;
|
||||
WSScreen screen(1024, 768);
|
||||
WSCompositor::the();
|
||||
WSWindowManager window_manager;
|
||||
|
||||
dbgprintf("Entering WindowServer main loop.\n");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue