summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-01-16 16:03:50 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-01-16 16:03:50 +0100
commitf7ca6d254d452e3524aaeaa1334ac041be3a1279 (patch)
tree165f54aa32eafbfd79003eb686770370f585c14d
parente655aebd70bb7d248c2f7be4a12d695ceec707a5 (diff)
downloadserenity-f7ca6d254d452e3524aaeaa1334ac041be3a1279.zip
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.
-rw-r--r--AK/Lock.h102
-rw-r--r--Kernel/GUIEventDevice.cpp (renamed from Widgets/GUIEventDevice.cpp)0
-rw-r--r--Kernel/GUIEventDevice.h (renamed from Widgets/GUIEventDevice.h)0
-rw-r--r--Kernel/Makefile25
-rw-r--r--Kernel/Process.cpp2
-rw-r--r--Kernel/Process.h7
-rw-r--r--Kernel/ProcessGUI.cpp32
-rw-r--r--Kernel/Scheduler.cpp2
-rw-r--r--Kernel/WindowServer.cpp22
-rw-r--r--Kernel/i386.h1
-rw-r--r--Kernel/init.cpp2
-rw-r--r--Widgets/FrameBuffer.cpp46
-rw-r--r--Widgets/FrameBuffer.h25
-rw-r--r--Widgets/GraphicsBitmap.cpp10
-rw-r--r--Widgets/Window.h1
-rw-r--r--WindowServer/.gitignore1
-rw-r--r--WindowServer/WSEvent.h151
-rw-r--r--WindowServer/WSEventLoop.cpp98
-rw-r--r--WindowServer/WSEventLoop.h40
-rw-r--r--WindowServer/WSEventReceiver.cpp10
-rw-r--r--WindowServer/WSEventReceiver.h13
-rw-r--r--WindowServer/WSFrameBuffer.cpp46
-rw-r--r--WindowServer/WSFrameBuffer.h25
-rw-r--r--WindowServer/WSScreen.cpp (renamed from Widgets/AbstractScreen.cpp)44
-rw-r--r--WindowServer/WSScreen.h (renamed from Widgets/AbstractScreen.h)16
-rw-r--r--WindowServer/WSWindow.cpp89
-rw-r--r--WindowServer/WSWindow.h55
-rw-r--r--WindowServer/WSWindowManager.cpp (renamed from Widgets/WindowManager.cpp)114
-rw-r--r--WindowServer/WSWindowManager.h (renamed from Widgets/WindowManager.h)61
-rw-r--r--WindowServer/main.cpp25
30 files changed, 757 insertions, 308 deletions
diff --git a/AK/Lock.h b/AK/Lock.h
index 229c072b39..93fe8f82c6 100644
--- a/AK/Lock.h
+++ b/AK/Lock.h
@@ -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;
-
diff --git a/Widgets/GUIEventDevice.cpp b/Kernel/GUIEventDevice.cpp
index 20ba6c917b..20ba6c917b 100644
--- a/Widgets/GUIEventDevice.cpp
+++ b/Kernel/GUIEventDevice.cpp
diff --git a/Widgets/GUIEventDevice.h b/Kernel/GUIEventDevice.h
index e98b208f05..e98b208f05 100644
--- a/Widgets/GUIEventDevice.h
+++ b/Kernel/GUIEventDevice.h
diff --git a/Kernel/Makefile b/Kernel/Makefile
index 149cffa46c..580a921618 100644
--- a/Kernel/Makefile
+++ b/Kernel/Makefile
@@ -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
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 8b7bd457ac..eee7fc70a7 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -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
diff --git a/Kernel/Process.h b/Kernel/Process.h
index 4e96a5328c..e79b37fa81 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -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;
diff --git a/Kernel/ProcessGUI.cpp b/Kernel/ProcessGUI.cpp
index 6801a9e86b..ff3ff76fc7 100644
--- a/Kernel/ProcessGUI.cpp
+++ b/Kernel/ProcessGUI.cpp
@@ -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;
}
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp
index 7bd8ee4d91..f8f546db1c 100644
--- a/Kernel/Scheduler.cpp
+++ b/Kernel/Scheduler.cpp
@@ -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
diff --git a/Kernel/WindowServer.cpp b/Kernel/WindowServer.cpp
deleted file mode 100644
index 674562ad7f..0000000000
--- a/Kernel/WindowServer.cpp
+++ /dev/null
@@ -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();
-}
diff --git a/Kernel/i386.h b/Kernel/i386.h
index eae96cbd5c..d48c7b481e 100644
--- a/Kernel/i386.h
+++ b/Kernel/i386.h
@@ -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()
{
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index 52a942ac8d..1a6ce48bb8 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -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"
diff --git a/Widgets/FrameBuffer.cpp b/Widgets/FrameBuffer.cpp
deleted file mode 100644
index dc93460a07..0000000000
--- a/Widgets/FrameBuffer.cpp
+++ /dev/null
@@ -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));
-}
diff --git a/Widgets/FrameBuffer.h b/Widgets/FrameBuffer.h
deleted file mode 100644
index c0758f19a6..0000000000
--- a/Widgets/FrameBuffer.h
+++ /dev/null
@@ -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 };
-};
-
diff --git a/Widgets/GraphicsBitmap.cpp b/Widgets/GraphicsBitmap.cpp
index 6fc98447f9..3dbc47cf47 100644
--- a/Widgets/GraphicsBitmap.cpp
+++ b/Widgets/GraphicsBitmap.cpp
@@ -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;
}
diff --git a/Widgets/Window.h b/Widgets/Window.h
index 3da05c3c97..1bbe354eb1 100644
--- a/Widgets/Window.h
+++ b/Widgets/Window.h
@@ -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;
diff --git a/WindowServer/.gitignore b/WindowServer/.gitignore
new file mode 100644
index 0000000000..5761abcfdf
--- /dev/null
+++ b/WindowServer/.gitignore
@@ -0,0 +1 @@
+*.o
diff --git a/WindowServer/WSEvent.h b/WindowServer/WSEvent.h
new file mode 100644
index 0000000000..778dbd29ee
--- /dev/null
+++ b/WindowServer/WSEvent.h
@@ -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() { }
+};
+
diff --git a/WindowServer/WSEventLoop.cpp b/WindowServer/WSEventLoop.cpp
new file mode 100644
index 0000000000..a6769a3510
--- /dev/null
+++ b/WindowServer/WSEventLoop.cpp
@@ -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;
+ }
+ }
+}
diff --git a/WindowServer/WSEventLoop.h b/WindowServer/WSEventLoop.h
new file mode 100644
index 0000000000..d461a6b52a
--- /dev/null
+++ b/WindowServer/WSEventLoop.h
@@ -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 };
+};
diff --git a/WindowServer/WSEventReceiver.cpp b/WindowServer/WSEventReceiver.cpp
new file mode 100644
index 0000000000..74e31e8906
--- /dev/null
+++ b/WindowServer/WSEventReceiver.cpp
@@ -0,0 +1,10 @@
+#include "WSEventReceiver.h"
+#include <AK/Assertions.h>
+
+WSEventReceiver::WSEventReceiver()
+{
+}
+
+WSEventReceiver::~WSEventReceiver()
+{
+}
diff --git a/WindowServer/WSEventReceiver.h b/WindowServer/WSEventReceiver.h
new file mode 100644
index 0000000000..1b81da7c2a
--- /dev/null
+++ b/WindowServer/WSEventReceiver.h
@@ -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;
+};
diff --git a/WindowServer/WSFrameBuffer.cpp b/WindowServer/WSFrameBuffer.cpp
new file mode 100644
index 0000000000..54ca0dc633
--- /dev/null
+++ b/WindowServer/WSFrameBuffer.cpp
@@ -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));
+}
diff --git a/WindowServer/WSFrameBuffer.h b/WindowServer/WSFrameBuffer.h
new file mode 100644
index 0000000000..8239fdfd9a
--- /dev/null
+++ b/WindowServer/WSFrameBuffer.h
@@ -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 };
+};
+
diff --git a/Widgets/AbstractScreen.cpp b/WindowServer/WSScreen.cpp
index 10993e6363..2276ff6f5d 100644
--- a/Widgets/AbstractScreen.cpp
+++ b/WindowServer/WSScreen.cpp
@@ -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));
}
diff --git a/Widgets/AbstractScreen.h b/WindowServer/WSScreen.h
index 444b1efcb3..0967bfcbb1 100644
--- a/Widgets/AbstractScreen.h
+++ b/WindowServer/WSScreen.h
@@ -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
diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp
new file mode 100644
index 0000000000..72755d0ace
--- /dev/null
+++ b/WindowServer/WSWindow.cpp
@@ -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));
+ }
+}
diff --git a/WindowServer/WSWindow.h b/WindowServer/WSWindow.h
new file mode 100644
index 0000000000..1e2b54fb2b
--- /dev/null
+++ b/WindowServer/WSWindow.h
@@ -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 };
+};
+
diff --git a/Widgets/WindowManager.cpp b/WindowServer/WSWindowManager.cpp
index 2b77912277..710eefea55 100644
--- a/Widgets/WindowManager.cpp
+++ b/WindowServer/WSWindowManager.cpp
@@ -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);
diff --git a/Widgets/WindowManager.h b/WindowServer/WSWindowManager.h
index a5277861f4..b6bf211ac2 100644
--- a/Widgets/WindowManager.h
+++ b/WindowServer/WSWindowManager.h
@@ -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&);
+
+ void setActiveWindow(WSWindow*);
- virtual void event(Event&) override;
+ 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;
};
diff --git a/WindowServer/main.cpp b/WindowServer/main.cpp
new file mode 100644
index 0000000000..827f8291e4
--- /dev/null
+++ b/WindowServer/main.cpp
@@ -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();
+}