1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:38:11 +00:00

Tear out or duplicate what's unique for WindowServer from Widgets.

This turned into a huge refactoring that somehow also includes
making locks recursive/reentrant.
This commit is contained in:
Andreas Kling 2019-01-16 16:03:50 +01:00
parent e655aebd70
commit f7ca6d254d
30 changed files with 757 additions and 308 deletions

102
AK/Lock.h
View file

@ -2,13 +2,14 @@
#include "Assertions.h"
#include "Types.h"
#ifdef SERENITY
#include "i386.h"
int sched_yield();
#else
#include <sched.h>
typedef int InterruptDisabler;
class Process;
extern Process* current;
#ifndef KERNEL
#error This thing is kernel-only right now.
#endif
//#define DEBUG_LOCKS
@ -30,70 +31,75 @@ static inline dword CAS(volatile dword* mem, dword newval, dword oldval)
return ret;
}
// FIXME: Rename to YieldingLock?
// FIXME: Rename to YieldingLock? RecursiveLock? Maybe just Lock?
class SpinLock {
public:
SpinLock() { }
~SpinLock() { }
ALWAYS_INLINE void lock(const char* func = nullptr)
{
(void)func;
#ifdef DEBUG_LOCKS
{
InterruptDisabler dis;
log_try_lock(func);
}
#endif
for (;;) {
if (CAS(&m_lock, 1, 0) == 0) {
#ifdef DEBUG_LOCKS
InterruptDisabler dis;
log_locked(func);
#endif
return;
}
sched_yield();
}
}
void lock();
void unlock();
ALWAYS_INLINE void unlock(const char* func = nullptr)
{
(void)func;
// barrier();
ASSERT(m_lock);
m_lock = 0;
#ifdef DEBUG_LOCKS
InterruptDisabler dis;
log_unlocked(func);
#endif
}
void init()
{
m_lock = 0;
}
const Process* holder() const { return m_holder; }
private:
volatile dword m_lock { 0 };
dword m_level { 0 };
Process* m_holder { nullptr };
};
class Locker {
public:
ALWAYS_INLINE explicit Locker(SpinLock& l, const char* func) : m_lock(l), m_func(func) { lock(); }
ALWAYS_INLINE explicit Locker(SpinLock& l) : m_lock(l) { lock(); }
ALWAYS_INLINE ~Locker() { unlock(); }
ALWAYS_INLINE void unlock() { m_lock.unlock(m_func); }
ALWAYS_INLINE void lock() { m_lock.lock(m_func); }
ALWAYS_INLINE void unlock() { m_lock.unlock(); }
ALWAYS_INLINE void lock() { m_lock.lock(); }
private:
SpinLock& m_lock;
const char* m_func { nullptr };
};
#define LOCKER(lock) Locker locker(lock, __FUNCTION__)
inline void SpinLock::lock()
{
for (;;) {
if (CAS(&m_lock, 1, 0) == 0) {
if (!m_holder || m_holder == current) {
m_holder = current;
++m_level;
memory_barrier();
m_lock = 0;
return;
}
m_lock = 0;
}
sched_yield();
}
}
inline void SpinLock::unlock()
{
for (;;) {
if (CAS(&m_lock, 1, 0) == 0) {
ASSERT(m_holder == current);
ASSERT(m_level);
--m_level;
if (m_level) {
memory_barrier();
m_lock = 0;
return;
}
m_holder = nullptr;
memory_barrier();
m_lock = 0;
return;
}
sched_yield();
}
}
#define LOCKER(lock) Locker locker(lock)
}
using AK::SpinLock;
using AK::Locker;

View file

@ -30,7 +30,7 @@ KERNEL_OBJS = \
ELFLoader.o \
KSyms.o \
PS2MouseDevice.o \
WindowServer.o
GUIEventDevice.o
VFS_OBJS = \
../VirtualFileSystem/DiskDevice.o \
@ -46,21 +46,20 @@ VFS_OBJS = \
../VirtualFileSystem/FileDescriptor.o \
../VirtualFileSystem/SyntheticFileSystem.o
WIDGETS_OBJS = \
../Widgets/Window.o \
../Widgets/Painter.o \
../Widgets/WindowManager.o \
../Widgets/FrameBuffer.o \
../Widgets/GraphicsBitmap.o \
../Widgets/Object.o \
WINDOWSERVER_OBJS = \
../Widgets/Rect.o \
../Widgets/Widget.o \
../Widgets/Painter.o \
../Widgets/Font.o \
../Widgets/Color.o \
../Widgets/CharacterBitmap.o \
../Widgets/EventLoop.o \
../Widgets/AbstractScreen.o \
../Widgets/GUIEventDevice.o \
../Widgets/GraphicsBitmap.o \
../WindowServer/WSEventReceiver.o \
../WindowServer/WSEventLoop.o \
../WindowServer/WSWindow.o \
../WindowServer/WSWindowManager.o \
../WindowServer/WSFrameBuffer.o \
../WindowServer/WSScreen.o \
../WindowServer/main.o
AK_OBJS = \
../AK/String.o \
@ -68,7 +67,7 @@ AK_OBJS = \
../AK/StringBuilder.o \
../AK/FileSystemPath.o
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(WIDGETS_OBJS)
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(WINDOWSERVER_OBJS)
NASM = nasm
KERNEL = kernel

View file

@ -18,7 +18,7 @@
#include "Scheduler.h"
#include "FIFO.h"
#include "KSyms.h"
#include <Widgets/Window.h>
#include <WindowServer/WSWindow.h>
#include "MasterPTY.h"
//#define DEBUG_IO

View file

@ -19,8 +19,7 @@ class PageDirectory;
class Region;
class VMObject;
class Zone;
class Window;
class Widget;
class WSWindow;
#define COOL_GLOBALS
#ifdef COOL_GLOBALS
@ -47,7 +46,7 @@ struct DisplayInfo {
class Process : public InlineLinkedListNode<Process> {
friend class InlineLinkedListNode<Process>;
friend class WindowManager; // FIXME: Make a better API for allocate_region().
friend class WSWindowManager; // FIXME: Make a better API for allocate_region().
friend class GraphicsBitmap; // FIXME: Make a better API for allocate_region().
public:
static Process* create_kernel_process(String&& name, void (*entry)());
@ -353,7 +352,7 @@ private:
RetainPtr<Region> m_display_framebuffer_region;
HashMap<int, OwnPtr<Window>> m_windows;
HashMap<int, OwnPtr<WSWindow>> m_windows;
Vector<GUI_Event> m_gui_events;
SpinLock m_gui_events_lock;

View file

@ -1,25 +1,22 @@
#include "Process.h"
#include "MemoryManager.h"
#include <LibC/errno_numbers.h>
#include <Widgets/AbstractScreen.h>
#include <Widgets/FrameBuffer.h>
#include <Widgets/EventLoop.h>
#include <Widgets/Font.h>
#include <Widgets/Button.h>
#include <Widgets/Label.h>
#include <Widgets/Widget.h>
#include <Widgets/Window.h>
#include <Widgets/WindowManager.h>
#include <WindowServer/WSScreen.h>
#include <WindowServer/WSFrameBuffer.h>
#include <WindowServer/WSEventLoop.h>
#include <WindowServer/WSWindow.h>
#include <WindowServer/WSWindowManager.h>
void Process::initialize_gui_statics()
{
Font::initialize();
FrameBuffer::initialize();
EventLoop::initialize();
WindowManager::initialize();
AbstractScreen::initialize();
WSFrameBuffer::initialize();
WSEventLoop::initialize();
WSWindowManager::initialize();
WSScreen::initialize();
new EventLoop;
new WSEventLoop;
}
int Process::make_window_id()
@ -36,7 +33,7 @@ int Process::make_window_id()
static void wait_for_gui_server()
{
// FIXME: Time out after a while and return an error.
while (!EventLoop::main().running())
while (!WSEventLoop::the().running())
sleep(10);
}
@ -53,13 +50,13 @@ int Process::gui$create_window(const GUI_CreateWindowParameters* user_params)
if (rect.is_empty())
return -EINVAL;
ProcessPagingScope scope(EventLoop::main().server_process());
ProcessPagingScope scope(WSEventLoop::the().server_process());
int window_id = make_window_id();
if (!window_id)
return -ENOMEM;
auto window = make<Window>(*this, window_id);
auto window = make<WSWindow>(*this, window_id);
if (!window)
return -ENOMEM;
@ -113,7 +110,6 @@ int Process::gui$invalidate_window(int window_id)
auto& window = *(*it).value;
// FIXME: This should queue up a message that the window server process can read.
// Poking into its data structures is not good.
InterruptDisabler disabler;
WindowManager::the().invalidate(window);
WSEventLoop::the().post_event(&window, make<WSEvent>(WSEvent::WM_Invalidate));
return 0;
}

View file

@ -133,7 +133,7 @@ bool Scheduler::pick_next()
for (auto* process = g_processes->head(); process; process = process->next()) {
//if (process->state() == Process::BlockedWait || process->state() == Process::BlockedSleep)
// continue;
dbgprintf("% 12s %s(%u) @ %w:%x\n", toString(process->state()), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
dbgprintf("[K%x] % 12s %s(%u) @ %w:%x\n", process, toString(process->state()), process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
}
#endif

View file

@ -1,22 +0,0 @@
#include "Process.h"
#include <Widgets/Font.h>
#include <Widgets/FrameBuffer.h>
#include <Widgets/WindowManager.h>
#include <Widgets/EventLoop.h>
#include <Widgets/Window.h>
void WindowServer_main()
{
auto info = current->get_display_info();
dbgprintf("Screen is %ux%ux%ubpp\n", info.width, info.height, info.bpp);
FrameBuffer framebuffer((dword*)info.framebuffer, info.width, info.height);
WindowManager::the();
dbgprintf("Entering WindowServer main loop.\n");
EventLoop::main().exec();
ASSERT_NOT_REACHED();
}

View file

@ -81,6 +81,7 @@ void write_gdt_entry(word selector, Descriptor&);
#define cli() asm volatile("cli")
#define sti() asm volatile("sti")
#define memory_barrier() asm volatile ("" ::: "memory")
static inline dword cpu_flags()
{

View file

@ -15,7 +15,7 @@
#include <VirtualFileSystem/RandomDevice.h>
#include <VirtualFileSystem/Ext2FileSystem.h>
#include <VirtualFileSystem/VirtualFileSystem.h>
#include <Widgets/GUIEventDevice.h>
#include "GUIEventDevice.h"
#include "MemoryManager.h"
#include "ProcFileSystem.h"
#include "RTC.h"

View file

@ -1,46 +0,0 @@
#include "FrameBuffer.h"
#include "GraphicsBitmap.h"
#include <AK/Assertions.h>
FrameBuffer* s_the;
void FrameBuffer::initialize()
{
s_the = nullptr;
}
FrameBuffer& FrameBuffer::the()
{
ASSERT(s_the);
return *s_the;
}
FrameBuffer::FrameBuffer(unsigned width, unsigned height)
: AbstractScreen(width, height)
{
ASSERT(!s_the);
s_the = this;
}
FrameBuffer::FrameBuffer(RGBA32* data, unsigned width, unsigned height)
: AbstractScreen(width, height)
, m_data(data)
{
ASSERT(!s_the);
s_the = this;
}
FrameBuffer::~FrameBuffer()
{
}
void FrameBuffer::show()
{
}
RGBA32* FrameBuffer::scanline(int y)
{
unsigned pitch = sizeof(RGBA32) * width();
return reinterpret_cast<RGBA32*>(((byte*)m_data) + (y * pitch));
}

View file

@ -1,25 +0,0 @@
#pragma once
#include "AbstractScreen.h"
#include "Color.h"
class GraphicsBitmap;
class FrameBuffer final : public AbstractScreen {
public:
FrameBuffer(unsigned width, unsigned height);
FrameBuffer(RGBA32*, unsigned width, unsigned height);
virtual ~FrameBuffer() override;
void show();
static FrameBuffer& the();
RGBA32* scanline(int y);
static void initialize();
private:
RGBA32* m_data { nullptr };
};

View file

@ -1,10 +1,10 @@
#include "GraphicsBitmap.h"
#include "EventLoop.h"
#include <AK/kmalloc.h>
#ifdef KERNEL
#include "Process.h"
#include "MemoryManager.h"
#include <Kernel/Process.h>
#include <Kernel/MemoryManager.h>
#include <WindowServer/WSEventLoop.h>
#endif
#ifdef KERNEL
@ -24,7 +24,7 @@ GraphicsBitmap::GraphicsBitmap(Process& process, const Size& size)
m_client_region->commit(process);
{
auto& server = EventLoop::main().server_process();
auto& server = WSEventLoop::the().server_process();
ProcessInspectionHandle composer_handle(server);
m_server_region = server.allocate_region_with_vmo(LinearAddress(), size_in_bytes, move(vmo), 0, "GraphicsBitmap (shared)", true, true);
}
@ -50,7 +50,7 @@ GraphicsBitmap::~GraphicsBitmap()
if (m_client_region)
m_client_process->deallocate_region(*m_client_region);
if (m_server_region)
EventLoop::main().server_process().deallocate_region(*m_server_region);
WSEventLoop::the().server_process().deallocate_region(*m_server_region);
#endif
m_data = nullptr;
}

View file

@ -28,7 +28,6 @@ public:
void set_rect_without_repaint(const Rect& rect) { m_rect = rect; }
Point position() const { return m_rect.location(); }
void set_position(const Point& position) { set_rect({ position.x(), position.y(), width(), height() }); }
void set_position_without_repaint(const Point& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); }
virtual void event(Event&) override;

1
WindowServer/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.o

151
WindowServer/WSEvent.h Normal file
View file

@ -0,0 +1,151 @@
#pragma once
#include <Widgets/Point.h>
#include <Widgets/Rect.h>
#include <AK/AKString.h>
#include <AK/Types.h>
static const char* WSEvent_names[] = {
"Invalid",
"Show",
"Hide",
"Paint",
"MouseMove",
"MouseDown",
"MouseUp",
"KeyDown",
"KeyUp",
"Timer",
"WM_Compose",
"WM_Invalidate",
};
class WSEvent {
public:
enum Type {
Invalid = 0,
Show,
Hide,
Paint,
MouseMove,
MouseDown,
MouseUp,
KeyDown,
KeyUp,
Timer,
WM_Compose,
WM_Invalidate,
};
WSEvent() { }
explicit WSEvent(Type type) : m_type(type) { }
virtual ~WSEvent() { }
Type type() const { return m_type; }
const char* name() const { return WSEvent_names[(unsigned)m_type]; }
bool isMouseEvent() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; }
bool isKeyEvent() const { return m_type == KeyUp || m_type == KeyDown; }
bool isPaintEvent() const { return m_type == Paint; }
private:
Type m_type { Invalid };
};
class PaintEvent final : public WSEvent {
public:
explicit PaintEvent(const Rect& rect = Rect())
: WSEvent(WSEvent::Paint)
, m_rect(rect)
{
}
const Rect& rect() const { return m_rect; }
private:
friend class WSWindowManager;
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,
Middle,
Right,
};
enum KeyboardKey {
Invalid,
LeftArrow,
RightArrow,
UpArrow,
DownArrow,
Backspace,
Return,
};
class KeyEvent final : public WSEvent {
public:
KeyEvent(Type type, int key)
: WSEvent(type)
, m_key(key)
{
}
int key() const { return m_key; }
bool ctrl() const { return m_ctrl; }
bool alt() const { return m_alt; }
bool shift() const { return m_shift; }
String text() const { return m_text; }
private:
friend class WSEventLoop;
friend class WSScreen;
int m_key { 0 };
bool m_ctrl { false };
bool m_alt { false };
bool m_shift { false };
String m_text;
};
class MouseEvent final : public WSEvent {
public:
MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
: WSEvent(type)
, m_position(x, y)
, m_button(button)
{
}
Point position() const { return m_position; }
int x() const { return m_position.x(); }
int y() const { return m_position.y(); }
MouseButton button() const { return m_button; }
private:
Point m_position;
MouseButton m_button { MouseButton::None };
};
class TimerEvent final : public WSEvent {
public:
TimerEvent() : WSEvent(WSEvent::Timer) { }
~TimerEvent() { }
};

View file

@ -0,0 +1,98 @@
#include "WSEventLoop.h"
#include "WSEvent.h"
#include "WSEventReceiver.h"
#include "WSWindowManager.h"
#include "WSScreen.h"
#include "PS2MouseDevice.h"
#include "Scheduler.h"
//#define WSEVENTLOOP_DEBUG
static WSEventLoop* s_the;
void WSEventLoop::initialize()
{
s_the = nullptr;
}
WSEventLoop::WSEventLoop()
{
if (!s_the)
s_the = this;
}
WSEventLoop::~WSEventLoop()
{
}
WSEventLoop& WSEventLoop::the()
{
ASSERT(s_the);
return *s_the;
}
int WSEventLoop::exec()
{
m_server_process = current;
m_running = true;
for (;;) {
if (m_queued_events.is_empty())
waitForEvent();
Vector<QueuedEvent> events;
{
LOCKER(m_lock);
events = move(m_queued_events);
}
for (auto& queued_event : events) {
auto* receiver = queued_event.receiver;
auto& event = *queued_event.event;
#ifdef WSEVENTLOOP_DEBUG
dbgprintf("WSEventLoop: receiver{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
#endif
if (!receiver) {
dbgprintf("WSEvent type %u with no receiver :(\n", event.type());
ASSERT_NOT_REACHED();
return 1;
} else {
receiver->event(event);
}
}
}
}
void WSEventLoop::post_event(WSEventReceiver* receiver, OwnPtr<WSEvent>&& event)
{
//ASSERT_INTERRUPTS_ENABLED();
LOCKER(m_lock);
#ifdef WSEVENTLOOP_DEBUG
dbgprintf("WSEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
#endif
m_queued_events.append({ receiver, move(event) });
}
void WSEventLoop::waitForEvent()
{
auto& mouse = PS2MouseDevice::the();
auto& screen = WSScreen::the();
bool prev_left_button = screen.left_mouse_button_pressed();
bool prev_right_button = screen.right_mouse_button_pressed();
int dx = 0;
int dy = 0;
while (mouse.can_read(*m_server_process)) {
signed_byte data[3];
ssize_t nread = mouse.read(*m_server_process, (byte*)data, 3);
ASSERT(nread == 3);
bool left_button = data[0] & 1;
bool right_button = data[0] & 2;
dx += data[1];
dy += -data[2];
if (left_button != prev_left_button || right_button != prev_right_button || !mouse.can_read(*m_server_process)) {
prev_left_button = left_button;
prev_right_button = right_button;
screen.on_receive_mouse_data(dx, dy, left_button, right_button);
dx = 0;
dy = 0;
}
}
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "WSEvent.h"
#include <AK/Lock.h>
#include <AK/OwnPtr.h>
#include <AK/Vector.h>
class WSEventReceiver;
class Process;
class WSEventLoop {
public:
WSEventLoop();
~WSEventLoop();
int exec();
void post_event(WSEventReceiver* receiver, OwnPtr<WSEvent>&&);
static WSEventLoop& the();
static void initialize();
bool running() const { return m_running; }
Process& server_process() { return *m_server_process; }
private:
void waitForEvent();
SpinLock m_lock;
struct QueuedEvent {
WSEventReceiver* receiver { nullptr };
OwnPtr<WSEvent> event;
};
Vector<QueuedEvent> m_queued_events;
Process* m_server_process { nullptr };
bool m_running { false };
};

View file

@ -0,0 +1,10 @@
#include "WSEventReceiver.h"
#include <AK/Assertions.h>
WSEventReceiver::WSEventReceiver()
{
}
WSEventReceiver::~WSEventReceiver()
{
}

View file

@ -0,0 +1,13 @@
#pragma once
#include <AK/Weakable.h>
class WSEvent;
class WSEventReceiver : public Weakable<WSEventReceiver> {
public:
WSEventReceiver();
virtual ~WSEventReceiver();
virtual void event(WSEvent&) = 0;
};

View file

@ -0,0 +1,46 @@
#include "WSFrameBuffer.h"
#include <Widgets/GraphicsBitmap.h>
#include <AK/Assertions.h>
WSFrameBuffer* s_the;
void WSFrameBuffer::initialize()
{
s_the = nullptr;
}
WSFrameBuffer& WSFrameBuffer::the()
{
ASSERT(s_the);
return *s_the;
}
WSFrameBuffer::WSFrameBuffer(unsigned width, unsigned height)
: WSScreen(width, height)
{
ASSERT(!s_the);
s_the = this;
}
WSFrameBuffer::WSFrameBuffer(RGBA32* data, unsigned width, unsigned height)
: WSScreen(width, height)
, m_data(data)
{
ASSERT(!s_the);
s_the = this;
}
WSFrameBuffer::~WSFrameBuffer()
{
}
void WSFrameBuffer::show()
{
}
RGBA32* WSFrameBuffer::scanline(int y)
{
unsigned pitch = sizeof(RGBA32) * width();
return reinterpret_cast<RGBA32*>(((byte*)m_data) + (y * pitch));
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "WSScreen.h"
#include <Widgets/Color.h>
class GraphicsBitmap;
class WSFrameBuffer final : public WSScreen {
public:
WSFrameBuffer(unsigned width, unsigned height);
WSFrameBuffer(RGBA32*, unsigned width, unsigned height);
virtual ~WSFrameBuffer() override;
void show();
static WSFrameBuffer& the();
RGBA32* scanline(int y);
static void initialize();
private:
RGBA32* m_data { nullptr };
};

View file

@ -1,26 +1,24 @@
#include "AbstractScreen.h"
#include "EventLoop.h"
#include "Event.h"
#include "Widget.h"
#include "WindowManager.h"
#include "WSScreen.h"
#include "WSEventLoop.h"
#include "WSEvent.h"
#include "WSWindowManager.h"
#include <AK/Assertions.h>
static AbstractScreen* s_the;
static WSScreen* s_the;
void AbstractScreen::initialize()
void WSScreen::initialize()
{
s_the = nullptr;
}
AbstractScreen& AbstractScreen::the()
WSScreen& WSScreen::the()
{
ASSERT(s_the);
return *s_the;
}
AbstractScreen::AbstractScreen(unsigned width, unsigned height)
: Object(nullptr)
, m_width(width)
WSScreen::WSScreen(unsigned width, unsigned height)
: m_width(width)
, m_height(height)
{
ASSERT(!s_the);
@ -31,11 +29,11 @@ AbstractScreen::AbstractScreen(unsigned width, unsigned height)
Keyboard::the().set_client(this);
}
AbstractScreen::~AbstractScreen()
WSScreen::~WSScreen()
{
}
void AbstractScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button)
void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button)
{
auto prev_location = m_cursor_location;
m_cursor_location.moveBy(dx, dy);
@ -45,28 +43,28 @@ void AbstractScreen::on_receive_mouse_data(int dx, int dy, bool left_button, boo
if (m_cursor_location.y() >= height())
m_cursor_location.setY(height() - 1);
if (m_cursor_location != prev_location) {
auto event = make<MouseEvent>(Event::MouseMove, m_cursor_location.x(), m_cursor_location.y());
EventLoop::main().postEvent(&WindowManager::the(), move(event));
auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location.x(), m_cursor_location.y());
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
bool prev_left_button = m_left_mouse_button_pressed;
bool prev_right_button = m_right_mouse_button_pressed;
m_left_mouse_button_pressed = left_button;
m_right_mouse_button_pressed = right_button;
if (prev_left_button != left_button) {
auto event = make<MouseEvent>(left_button ? Event::MouseDown : Event::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left);
EventLoop::main().postEvent(&WindowManager::the(), move(event));
auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left);
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
if (prev_right_button != right_button) {
auto event = make<MouseEvent>(right_button ? Event::MouseDown : Event::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right);
EventLoop::main().postEvent(&WindowManager::the(), move(event));
auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right);
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
if (m_cursor_location != prev_location || prev_left_button != left_button)
WindowManager::the().draw_cursor();
WSWindowManager::the().draw_cursor();
}
void AbstractScreen::on_key_pressed(Keyboard::Key key)
void WSScreen::on_key_pressed(Keyboard::Key key)
{
auto event = make<KeyEvent>(Event::KeyDown, 0);
auto event = make<KeyEvent>(WSEvent::KeyDown, 0);
int key_code = 0;
switch (key.character) {
@ -115,5 +113,5 @@ void AbstractScreen::on_key_pressed(Keyboard::Key key)
event->m_ctrl = key.ctrl();
event->m_alt = key.alt();
EventLoop::main().postEvent(&WindowManager::the(), move(event));
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}

View file

@ -1,19 +1,17 @@
#pragma once
#include "Object.h"
#include "Rect.h"
#include "Size.h"
#include "Keyboard.h"
#include "PS2MouseDevice.h"
#include <Widgets/Rect.h>
#include <Widgets/Size.h>
#include <Kernel/Keyboard.h>
class AbstractScreen : public Object, public KeyboardClient {
class WSScreen : public KeyboardClient {
public:
virtual ~AbstractScreen();
virtual ~WSScreen();
int width() const { return m_width; }
int height() const { return m_height; }
static AbstractScreen& the();
static WSScreen& the();
Size size() const { return { width(), height() }; }
Rect rect() const { return { 0, 0, width(), height() }; }
@ -27,7 +25,7 @@ public:
void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button);
protected:
AbstractScreen(unsigned width, unsigned height);
WSScreen(unsigned width, unsigned height);
private:
// ^KeyboardClient

89
WindowServer/WSWindow.cpp Normal file
View file

@ -0,0 +1,89 @@
#include "WSWindow.h"
#include "WSWindowManager.h"
#include "WSEvent.h"
#include "WSEventLoop.h"
#include "Process.h"
WSWindow::WSWindow(Process& process, int window_id)
: m_process(process)
, m_window_id(window_id)
{
WSWindowManager::the().addWindow(*this);
}
WSWindow::~WSWindow()
{
WSWindowManager::the().removeWindow(*this);
}
void WSWindow::set_title(String&& title)
{
if (m_title == title)
return;
m_title = move(title);
WSWindowManager::the().notifyTitleChanged(*this);
}
void WSWindow::set_rect(const Rect& rect)
{
if (m_rect == rect)
return;
auto oldRect = m_rect;
m_rect = rect;
m_backing = GraphicsBitmap::create(m_process, m_rect.size());
WSWindowManager::the().notifyRectChanged(*this, oldRect, m_rect);
}
// FIXME: Just use the same types.
static GUI_MouseButton to_api(MouseButton button)
{
switch (button) {
case MouseButton::None: return GUI_MouseButton::NoButton;
case MouseButton::Left: return GUI_MouseButton::Left;
case MouseButton::Right: return GUI_MouseButton::Right;
case MouseButton::Middle: return GUI_MouseButton::Middle;
}
}
void WSWindow::event(WSEvent& event)
{
GUI_Event gui_event;
gui_event.window_id = window_id();
switch (event.type()) {
case WSEvent::Paint:
gui_event.type = GUI_Event::Type::Paint;
gui_event.paint.rect = static_cast<PaintEvent&>(event).rect();
break;
case WSEvent::MouseMove:
gui_event.type = GUI_Event::Type::MouseMove;
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
break;
case WSEvent::MouseDown:
gui_event.type = GUI_Event::Type::MouseDown;
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
break;
case WSEvent::MouseUp:
gui_event.type = GUI_Event::Type::MouseUp;
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
break;
case WSEvent::KeyDown:
gui_event.type = GUI_Event::Type::KeyDown;
gui_event.key.character = static_cast<KeyEvent&>(event).text()[0];
break;
case WSEvent::WM_Invalidate:
WSWindowManager::the().invalidate(*this);
return;
}
if (gui_event.type == GUI_Event::Type::Invalid)
return;
{
LOCKER(m_process.gui_events_lock());
m_process.gui_events().append(move(gui_event));
}
}

55
WindowServer/WSWindow.h Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#include <Widgets/Rect.h>
#include <Widgets/GraphicsBitmap.h>
#include <AK/AKString.h>
#include <AK/InlineLinkedList.h>
#include "WSEventReceiver.h"
class Process;
class WSWindow final : public WSEventReceiver, public InlineLinkedListNode<WSWindow> {
public:
WSWindow(Process&, int window_id);
virtual ~WSWindow() override;
int window_id() const { return m_window_id; }
String title() const { return m_title; }
void set_title(String&&);
int x() const { return m_rect.x(); }
int y() const { return m_rect.y(); }
int width() const { return m_rect.width(); }
int height() const { return m_rect.height(); }
const Rect& rect() const { return m_rect; }
void set_rect(const Rect&);
void set_rect_without_repaint(const Rect& rect) { m_rect = rect; }
Point position() const { return m_rect.location(); }
void set_position(const Point& position) { set_rect({ position.x(), position.y(), width(), height() }); }
void set_position_without_repaint(const Point& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); }
virtual void event(WSEvent&) override;
bool is_being_dragged() const { return m_is_being_dragged; }
void set_is_being_dragged(bool b) { m_is_being_dragged = b; }
GraphicsBitmap* backing() { return m_backing.ptr(); }
// For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
WSWindow* m_next { nullptr };
WSWindow* m_prev { nullptr };
private:
String m_title;
Rect m_rect;
bool m_is_being_dragged { false };
RetainPtr<GraphicsBitmap> m_backing;
Process& m_process;
int m_window_id { -1 };
};

View file

@ -1,12 +1,13 @@
#include "WindowManager.h"
#include "Painter.h"
#include "Widget.h"
#include "Window.h"
#include "AbstractScreen.h"
#include "EventLoop.h"
#include "FrameBuffer.h"
#include "WSWindowManager.h"
#include "WSWindow.h"
#include "WSScreen.h"
#include "WSEventLoop.h"
#include "WSFrameBuffer.h"
#include "Process.h"
#include "MemoryManager.h"
#include <Widgets/Painter.h>
#include <Widgets/CharacterBitmap.h>
#include <AK/StdLibExtras.h>
//#define DEBUG_FLUSH_YELLOW
@ -50,16 +51,16 @@ static inline Rect outerRectForWindow(const Rect& window)
return rect;
}
static WindowManager* s_the_window_manager;
static WSWindowManager* s_the_window_manager;
WindowManager& WindowManager::the()
WSWindowManager& WSWindowManager::the()
{
if (!s_the_window_manager)
s_the_window_manager = new WindowManager;
s_the_window_manager = new WSWindowManager;
return *s_the_window_manager;
}
void WindowManager::initialize()
void WSWindowManager::initialize()
{
s_the_window_manager = nullptr;
}
@ -104,8 +105,8 @@ static const char* cursor_bitmap_outer_ascii = {
" ## "
};
WindowManager::WindowManager()
: m_framebuffer(FrameBuffer::the())
WSWindowManager::WSWindowManager()
: m_framebuffer(WSFrameBuffer::the())
, m_screen_rect(m_framebuffer.rect())
{
auto size = m_screen_rect.size();
@ -129,11 +130,11 @@ WindowManager::WindowManager()
compose();
}
WindowManager::~WindowManager()
WSWindowManager::~WSWindowManager()
{
}
void WindowManager::paintWindowFrame(Window& window)
void WSWindowManager::paintWindowFrame(WSWindow& window)
{
//printf("[WM] paintWindowFrame {%p}, rect: %d,%d %dx%d\n", &window, window.rect().x(), window.rect().y(), window.rect().width(), window.rect().height());
@ -159,7 +160,7 @@ void WindowManager::paintWindowFrame(Window& window)
m_back_painter->draw_text(titleBarTitleRect, window.title(), Painter::TextAlignment::CenterLeft, titleColor);
}
void WindowManager::addWindow(Window& window)
void WSWindowManager::addWindow(WSWindow& window)
{
m_windows.set(&window);
m_windows_in_order.append(&window);
@ -167,18 +168,13 @@ void WindowManager::addWindow(Window& window)
setActiveWindow(&window);
}
void WindowManager::move_to_front(Window& window)
void WSWindowManager::move_to_front(WSWindow& window)
{
m_windows_in_order.remove(&window);
m_windows_in_order.append(&window);
}
void WindowManager::did_paint(Window& window)
{
invalidate(window);
}
void WindowManager::removeWindow(Window& window)
void WSWindowManager::removeWindow(WSWindow& window)
{
if (!m_windows.contains(&window))
return;
@ -190,22 +186,24 @@ void WindowManager::removeWindow(Window& window)
setActiveWindow(*m_windows.begin());
}
void WindowManager::notifyTitleChanged(Window& window)
void WSWindowManager::notifyTitleChanged(WSWindow& window)
{
printf("[WM] Window{%p} title set to '%s'\n", &window, window.title().characters());
printf("[WM] WSWindow{%p} title set to '%s'\n", &window, window.title().characters());
}
void WindowManager::notifyRectChanged(Window& window, const Rect& old_rect, const Rect& new_rect)
void WSWindowManager::notifyRectChanged(WSWindow& window, const Rect& old_rect, const Rect& new_rect)
{
printf("[WM] Window %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height());
printf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height());
ASSERT_INTERRUPTS_ENABLED();
LOCKER(m_lock);
invalidate(outerRectForWindow(old_rect));
invalidate(outerRectForWindow(new_rect));
}
void WindowManager::handleTitleBarMouseEvent(Window& window, MouseEvent& event)
void WSWindowManager::handleTitleBarMouseEvent(WSWindow& window, MouseEvent& event)
{
if (event.type() == Event::MouseDown && event.button() == MouseButton::Left) {
printf("[WM] Begin dragging Window{%p}\n", &window);
if (event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) {
printf("[WM] Begin dragging WSWindow{%p}\n", &window);
m_dragWindow = window.makeWeakPtr();;
m_dragOrigin = event.position();
m_dragWindowOrigin = window.position();
@ -215,11 +213,11 @@ void WindowManager::handleTitleBarMouseEvent(Window& window, MouseEvent& event)
}
}
void WindowManager::processMouseEvent(MouseEvent& event)
void WSWindowManager::processMouseEvent(MouseEvent& event)
{
if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
if (event.type() == WSEvent::MouseUp && event.button() == MouseButton::Left) {
if (m_dragWindow) {
printf("[WM] Finish dragging Window{%p}\n", m_dragWindow.ptr());
printf("[WM] Finish dragging WSWindow{%p}\n", m_dragWindow.ptr());
invalidate(m_dragStartRect);
invalidate(*m_dragWindow);
m_dragWindow->set_is_being_dragged(false);
@ -229,7 +227,7 @@ void WindowManager::processMouseEvent(MouseEvent& event)
}
}
if (event.type() == Event::MouseMove) {
if (event.type() == WSEvent::MouseMove) {
if (m_dragWindow) {
auto old_window_rect = m_dragWindow->rect();
Point pos = m_dragWindowOrigin;
@ -244,7 +242,7 @@ void WindowManager::processMouseEvent(MouseEvent& event)
for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
if (titleBarRectForWindow(window->rect()).contains(event.position())) {
if (event.type() == Event::MouseDown) {
if (event.type() == WSEvent::MouseDown) {
move_to_front(*window);
setActiveWindow(window);
}
@ -253,7 +251,7 @@ void WindowManager::processMouseEvent(MouseEvent& event)
}
if (window->rect().contains(event.position())) {
if (event.type() == Event::MouseDown) {
if (event.type() == WSEvent::MouseDown) {
move_to_front(*window);
setActiveWindow(window);
}
@ -265,7 +263,7 @@ void WindowManager::processMouseEvent(MouseEvent& event)
}
}
void WindowManager::compose()
void WSWindowManager::compose()
{
auto invalidated_rects = move(m_invalidated_rects);
printf("[WM] compose #%u (%u rects)\n", ++m_recompose_count, invalidated_rects.size());
@ -297,8 +295,10 @@ void WindowManager::compose()
draw_cursor();
}
void WindowManager::draw_cursor()
void WSWindowManager::draw_cursor()
{
ASSERT_INTERRUPTS_ENABLED();
LOCKER(m_lock);
auto cursor_location = m_framebuffer.cursor_location();
Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() };
flush(m_last_cursor_rect.united(cursor_rect));
@ -311,8 +311,10 @@ void WindowManager::draw_cursor()
m_last_cursor_rect = cursor_rect;
}
void WindowManager::event(Event& event)
void WSWindowManager::event(WSEvent& event)
{
ASSERT_INTERRUPTS_ENABLED();
LOCKER(m_lock);
if (event.isMouseEvent())
return processMouseEvent(static_cast<MouseEvent&>(event));
@ -320,46 +322,35 @@ void WindowManager::event(Event& event)
// FIXME: This is a good place to hook key events globally. :)
if (m_activeWindow)
return m_activeWindow->event(event);
return Object::event(event);
return;
}
if (event.type() == Event::WM_Compose) {
if (event.type() == WSEvent::WM_Compose) {
m_pending_compose_event = false;
compose();
return;
}
return Object::event(event);
}
void WindowManager::setActiveWindow(Window* window)
void WSWindowManager::setActiveWindow(WSWindow* window)
{
if (window == m_activeWindow.ptr())
return;
if (auto* previously_active_window = m_activeWindow.ptr()) {
if (auto* previously_active_window = m_activeWindow.ptr())
invalidate(*previously_active_window);
EventLoop::main().postEvent(previously_active_window, make<Event>(Event::WindowBecameInactive));
}
m_activeWindow = window->makeWeakPtr();
if (m_activeWindow) {
if (m_activeWindow)
invalidate(*m_activeWindow);
EventLoop::main().postEvent(m_activeWindow.ptr(), make<Event>(Event::WindowBecameActive));
}
}
bool WindowManager::isVisible(Window& window) const
{
return m_windows.contains(&window);
}
void WindowManager::invalidate()
void WSWindowManager::invalidate()
{
m_invalidated_rects.clear_with_capacity();
m_invalidated_rects.append(m_screen_rect);
}
void WindowManager::invalidate(const Rect& a_rect)
void WSWindowManager::invalidate(const Rect& a_rect)
{
auto rect = Rect::intersection(a_rect, m_screen_rect);
if (rect.is_empty())
@ -379,17 +370,20 @@ void WindowManager::invalidate(const Rect& a_rect)
m_invalidated_rects.append(rect);
if (!m_pending_compose_event) {
EventLoop::main().postEvent(this, make<Event>(Event::WM_Compose));
ASSERT_INTERRUPTS_ENABLED();
WSEventLoop::the().post_event(this, make<WSEvent>(WSEvent::WM_Compose));
m_pending_compose_event = true;
}
}
void WindowManager::invalidate(const Window& window)
void WSWindowManager::invalidate(const WSWindow& window)
{
ASSERT_INTERRUPTS_ENABLED();
LOCKER(m_lock);
invalidate(outerRectForWindow(window.rect()));
}
void WindowManager::flush(const Rect& a_rect)
void WSWindowManager::flush(const Rect& a_rect)
{
auto rect = Rect::intersection(a_rect, m_screen_rect);

View file

@ -1,61 +1,58 @@
#pragma once
#include "Object.h"
#include "Rect.h"
#include "Color.h"
#include "Painter.h"
#include <Widgets/Rect.h>
#include <Widgets/Color.h>
#include <Widgets/Painter.h>
#include <AK/HashTable.h>
#include <AK/InlineLinkedList.h>
#include <AK/WeakPtr.h>
#include <AK/Lock.h>
#include "WSEventReceiver.h"
class FrameBuffer;
class WSFrameBuffer;
class MouseEvent;
class PaintEvent;
class Widget;
class Window;
class WSWindow;
class CharacterBitmap;
class GraphicsBitmap;
class WindowManager : public Object {
class WSWindowManager : public WSEventReceiver {
public:
static WindowManager& the();
void addWindow(Window&);
void removeWindow(Window&);
static WSWindowManager& the();
void addWindow(WSWindow&);
void removeWindow(WSWindow&);
void notifyTitleChanged(Window&);
void notifyRectChanged(Window&, const Rect& oldRect, const Rect& newRect);
void notifyTitleChanged(WSWindow&);
void notifyRectChanged(WSWindow&, const Rect& oldRect, const Rect& newRect);
Window* activeWindow() { return m_activeWindow.ptr(); }
void setActiveWindow(Window*);
WSWindow* activeWindow() { return m_activeWindow.ptr(); }
bool isVisible(Window&) const;
void did_paint(Window&);
void move_to_front(Window&);
void move_to_front(WSWindow&);
static void initialize();
void draw_cursor();
void invalidate(const Window&);
void invalidate(const WSWindow&);
void invalidate(const Rect&);
void invalidate();
void flush(const Rect&);
private:
WindowManager();
virtual ~WindowManager() override;
WSWindowManager();
virtual ~WSWindowManager() override;
void processMouseEvent(MouseEvent&);
void handleTitleBarMouseEvent(Window&, MouseEvent&);
void handleTitleBarMouseEvent(WSWindow&, MouseEvent&);
virtual void event(Event&) override;
void setActiveWindow(WSWindow*);
virtual void event(WSEvent&) override;
void compose();
void paintWindowFrame(Window&);
void paintWindowFrame(WSWindow&);
FrameBuffer& m_framebuffer;
WSFrameBuffer& m_framebuffer;
Rect m_screen_rect;
Color m_activeWindowBorderColor;
@ -64,12 +61,12 @@ private:
Color m_inactiveWindowBorderColor;
Color m_inactiveWindowTitleColor;
HashTable<Window*> m_windows;
InlineLinkedList<Window> m_windows_in_order;
HashTable<WSWindow*> m_windows;
InlineLinkedList<WSWindow> m_windows_in_order;
WeakPtr<Window> m_activeWindow;
WeakPtr<WSWindow> m_activeWindow;
WeakPtr<Window> m_dragWindow;
WeakPtr<WSWindow> m_dragWindow;
Point m_dragOrigin;
Point m_dragWindowOrigin;
@ -93,4 +90,6 @@ private:
OwnPtr<Painter> m_back_painter;
OwnPtr<Painter> m_front_painter;
mutable SpinLock m_lock;
};

25
WindowServer/main.cpp Normal file
View file

@ -0,0 +1,25 @@
#include "Process.h"
#include <Widgets/Font.h>
#include <WindowServer/WSFrameBuffer.h>
#include <WindowServer/WSWindowManager.h>
#include <WindowServer/WSEventLoop.h>
#include <WindowServer/WSWindow.h>
// NOTE: This actually runs as a kernel process.
// I'd like to change this eventually.
void WindowServer_main()
{
auto info = current->get_display_info();
dbgprintf("Screen is %ux%ux%ubpp\n", info.width, info.height, info.bpp);
WSFrameBuffer framebuffer((dword*)info.framebuffer, info.width, info.height);
WSWindowManager::the();
dbgprintf("Entering WindowServer main loop.\n");
WSEventLoop::the().exec();
ASSERT_NOT_REACHED();
}