mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:37:34 +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:
parent
e655aebd70
commit
f7ca6d254d
30 changed files with 757 additions and 308 deletions
1
WindowServer/.gitignore
vendored
Normal file
1
WindowServer/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.o
|
151
WindowServer/WSEvent.h
Normal file
151
WindowServer/WSEvent.h
Normal 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() { }
|
||||
};
|
||||
|
98
WindowServer/WSEventLoop.cpp
Normal file
98
WindowServer/WSEventLoop.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
40
WindowServer/WSEventLoop.h
Normal file
40
WindowServer/WSEventLoop.h
Normal 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 };
|
||||
};
|
10
WindowServer/WSEventReceiver.cpp
Normal file
10
WindowServer/WSEventReceiver.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "WSEventReceiver.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
WSEventReceiver::WSEventReceiver()
|
||||
{
|
||||
}
|
||||
|
||||
WSEventReceiver::~WSEventReceiver()
|
||||
{
|
||||
}
|
13
WindowServer/WSEventReceiver.h
Normal file
13
WindowServer/WSEventReceiver.h
Normal 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;
|
||||
};
|
46
WindowServer/WSFrameBuffer.cpp
Normal file
46
WindowServer/WSFrameBuffer.cpp
Normal 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));
|
||||
}
|
25
WindowServer/WSFrameBuffer.h
Normal file
25
WindowServer/WSFrameBuffer.h
Normal 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 };
|
||||
};
|
||||
|
117
WindowServer/WSScreen.cpp
Normal file
117
WindowServer/WSScreen.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include "WSScreen.h"
|
||||
#include "WSEventLoop.h"
|
||||
#include "WSEvent.h"
|
||||
#include "WSWindowManager.h"
|
||||
#include <AK/Assertions.h>
|
||||
|
||||
static WSScreen* s_the;
|
||||
|
||||
void WSScreen::initialize()
|
||||
{
|
||||
s_the = nullptr;
|
||||
}
|
||||
|
||||
WSScreen& WSScreen::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
WSScreen::WSScreen(unsigned width, unsigned height)
|
||||
: m_width(width)
|
||||
, m_height(height)
|
||||
{
|
||||
ASSERT(!s_the);
|
||||
s_the = this;
|
||||
|
||||
m_cursor_location = rect().center();
|
||||
|
||||
Keyboard::the().set_client(this);
|
||||
}
|
||||
|
||||
WSScreen::~WSScreen()
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
m_cursor_location.constrain(rect());
|
||||
if (m_cursor_location.x() >= width())
|
||||
m_cursor_location.setX(width() - 1);
|
||||
if (m_cursor_location.y() >= height())
|
||||
m_cursor_location.setY(height() - 1);
|
||||
if (m_cursor_location != prev_location) {
|
||||
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 ? 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 ? 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)
|
||||
WSWindowManager::the().draw_cursor();
|
||||
}
|
||||
|
||||
void WSScreen::on_key_pressed(Keyboard::Key key)
|
||||
{
|
||||
auto event = make<KeyEvent>(WSEvent::KeyDown, 0);
|
||||
int key_code = 0;
|
||||
|
||||
switch (key.character) {
|
||||
case 8: key_code = KeyboardKey::Backspace; break;
|
||||
case 10: key_code = KeyboardKey::Return; break;
|
||||
}
|
||||
event->m_key = key_code;
|
||||
|
||||
if (key.character) {
|
||||
char buf[] = { 0, 0 };
|
||||
char& ch = buf[0];
|
||||
ch = key.character;
|
||||
if (key.shift()) {
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
ch &= ~0x20;
|
||||
} else {
|
||||
switch (ch) {
|
||||
case '1': ch = '!'; break;
|
||||
case '2': ch = '@'; break;
|
||||
case '3': ch = '#'; break;
|
||||
case '4': ch = '$'; break;
|
||||
case '5': ch = '%'; break;
|
||||
case '6': ch = '^'; break;
|
||||
case '7': ch = '&'; break;
|
||||
case '8': ch = '*'; break;
|
||||
case '9': ch = '('; break;
|
||||
case '0': ch = ')'; break;
|
||||
case '-': ch = '_'; break;
|
||||
case '=': ch = '+'; break;
|
||||
case '`': ch = '~'; break;
|
||||
case ',': ch = '<'; break;
|
||||
case '.': ch = '>'; break;
|
||||
case '/': ch = '?'; break;
|
||||
case '[': ch = '{'; break;
|
||||
case ']': ch = '}'; break;
|
||||
case '\\': ch = '|'; break;
|
||||
case '\'': ch = '"'; break;
|
||||
case ';': ch = ':'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
event->m_text = buf;
|
||||
}
|
||||
|
||||
event->m_shift = key.shift();
|
||||
event->m_ctrl = key.ctrl();
|
||||
event->m_alt = key.alt();
|
||||
|
||||
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
|
||||
}
|
41
WindowServer/WSScreen.h
Normal file
41
WindowServer/WSScreen.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <Widgets/Rect.h>
|
||||
#include <Widgets/Size.h>
|
||||
#include <Kernel/Keyboard.h>
|
||||
|
||||
class WSScreen : public KeyboardClient {
|
||||
public:
|
||||
virtual ~WSScreen();
|
||||
|
||||
int width() const { return m_width; }
|
||||
int height() const { return m_height; }
|
||||
|
||||
static WSScreen& the();
|
||||
|
||||
Size size() const { return { width(), height() }; }
|
||||
Rect rect() const { return { 0, 0, width(), height() }; }
|
||||
|
||||
static void initialize();
|
||||
|
||||
Point cursor_location() const { return m_cursor_location; }
|
||||
bool left_mouse_button_pressed() const { return m_left_mouse_button_pressed; }
|
||||
bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; }
|
||||
|
||||
void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button);
|
||||
|
||||
protected:
|
||||
WSScreen(unsigned width, unsigned height);
|
||||
|
||||
private:
|
||||
// ^KeyboardClient
|
||||
virtual void on_key_pressed(Keyboard::Key) final;
|
||||
|
||||
int m_width { 0 };
|
||||
int m_height { 0 };
|
||||
|
||||
Point m_cursor_location;
|
||||
bool m_left_mouse_button_pressed { false };
|
||||
bool m_right_mouse_button_pressed { false };
|
||||
};
|
||||
|
89
WindowServer/WSWindow.cpp
Normal file
89
WindowServer/WSWindow.cpp
Normal 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
55
WindowServer/WSWindow.h
Normal 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 };
|
||||
};
|
||||
|
403
WindowServer/WSWindowManager.cpp
Normal file
403
WindowServer/WSWindowManager.cpp
Normal file
|
@ -0,0 +1,403 @@
|
|||
#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
|
||||
|
||||
static const int windowTitleBarHeight = 16;
|
||||
|
||||
static inline Rect titleBarRectForWindow(const Rect& window)
|
||||
{
|
||||
return {
|
||||
window.x() - 1,
|
||||
window.y() - windowTitleBarHeight,
|
||||
window.width() + 2,
|
||||
windowTitleBarHeight
|
||||
};
|
||||
}
|
||||
|
||||
static inline Rect titleBarTitleRectForWindow(const Rect& window)
|
||||
{
|
||||
auto titleBarRect = titleBarRectForWindow(window);
|
||||
return {
|
||||
titleBarRect.x() + 2,
|
||||
titleBarRect.y(),
|
||||
titleBarRect.width() - 4,
|
||||
titleBarRect.height()
|
||||
};
|
||||
}
|
||||
|
||||
static inline Rect borderRectForWindow(const Rect& window)
|
||||
{
|
||||
auto titleBarRect = titleBarRectForWindow(window);
|
||||
return { titleBarRect.x() - 1,
|
||||
titleBarRect.y() - 1,
|
||||
titleBarRect.width() + 2,
|
||||
windowTitleBarHeight + window.height() + 3
|
||||
};
|
||||
}
|
||||
|
||||
static inline Rect outerRectForWindow(const Rect& window)
|
||||
{
|
||||
auto rect = borderRectForWindow(window);
|
||||
rect.inflate(2, 2);
|
||||
return rect;
|
||||
}
|
||||
|
||||
static WSWindowManager* s_the_window_manager;
|
||||
|
||||
WSWindowManager& WSWindowManager::the()
|
||||
{
|
||||
if (!s_the_window_manager)
|
||||
s_the_window_manager = new WSWindowManager;
|
||||
return *s_the_window_manager;
|
||||
}
|
||||
|
||||
void WSWindowManager::initialize()
|
||||
{
|
||||
s_the_window_manager = nullptr;
|
||||
}
|
||||
|
||||
static const char* cursor_bitmap_inner_ascii = {
|
||||
" # "
|
||||
" ## "
|
||||
" ### "
|
||||
" #### "
|
||||
" ##### "
|
||||
" ###### "
|
||||
" ####### "
|
||||
" ######## "
|
||||
" ######### "
|
||||
" ########## "
|
||||
" ###### "
|
||||
" ## ## "
|
||||
" # ## "
|
||||
" ## "
|
||||
" ## "
|
||||
" ## "
|
||||
" "
|
||||
};
|
||||
|
||||
static const char* cursor_bitmap_outer_ascii = {
|
||||
"## "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# # "
|
||||
"# #### "
|
||||
"# ## # "
|
||||
"# # # # "
|
||||
"## # # "
|
||||
" # # "
|
||||
" # # "
|
||||
" ## "
|
||||
};
|
||||
|
||||
WSWindowManager::WSWindowManager()
|
||||
: m_framebuffer(WSFrameBuffer::the())
|
||||
, m_screen_rect(m_framebuffer.rect())
|
||||
{
|
||||
auto size = m_screen_rect.size();
|
||||
m_front_bitmap = GraphicsBitmap::create_wrapper(size, m_framebuffer.scanline(0));
|
||||
auto* region = current->allocate_region(LinearAddress(), size.width() * size.height() * sizeof(RGBA32), "BackBitmap", true, true, true);
|
||||
m_back_bitmap = GraphicsBitmap::create_wrapper(m_screen_rect.size(), (RGBA32*)region->linearAddress.get());
|
||||
|
||||
m_front_painter = make<Painter>(*m_front_bitmap);
|
||||
m_back_painter = make<Painter>(*m_back_bitmap);
|
||||
|
||||
m_activeWindowBorderColor = Color(0, 64, 192);
|
||||
m_activeWindowTitleColor = Color::White;
|
||||
|
||||
m_inactiveWindowBorderColor = Color(64, 64, 64);
|
||||
m_inactiveWindowTitleColor = Color::White;
|
||||
|
||||
m_cursor_bitmap_inner = CharacterBitmap::createFromASCII(cursor_bitmap_inner_ascii, 12, 17);
|
||||
m_cursor_bitmap_outer = CharacterBitmap::createFromASCII(cursor_bitmap_outer_ascii, 12, 17);
|
||||
|
||||
invalidate();
|
||||
compose();
|
||||
}
|
||||
|
||||
WSWindowManager::~WSWindowManager()
|
||||
{
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
auto titleBarRect = titleBarRectForWindow(window.rect());
|
||||
auto titleBarTitleRect = titleBarTitleRectForWindow(window.rect());
|
||||
auto outerRect = outerRectForWindow(window.rect());
|
||||
auto borderRect = borderRectForWindow(window.rect());
|
||||
|
||||
Rect inner_border_rect {
|
||||
window.x() - 1,
|
||||
window.y() - 1,
|
||||
window.width() + 2,
|
||||
window.height() + 2
|
||||
};
|
||||
|
||||
auto titleColor = &window == activeWindow() ? m_activeWindowTitleColor : m_inactiveWindowTitleColor;
|
||||
auto borderColor = &window == activeWindow() ? m_activeWindowBorderColor : m_inactiveWindowBorderColor;
|
||||
|
||||
m_back_painter->draw_rect(borderRect, Color::MidGray);
|
||||
m_back_painter->draw_rect(outerRect, borderColor);
|
||||
m_back_painter->fill_rect(titleBarRect, borderColor);
|
||||
m_back_painter->draw_rect(inner_border_rect, borderColor);
|
||||
m_back_painter->draw_text(titleBarTitleRect, window.title(), Painter::TextAlignment::CenterLeft, titleColor);
|
||||
}
|
||||
|
||||
void WSWindowManager::addWindow(WSWindow& window)
|
||||
{
|
||||
m_windows.set(&window);
|
||||
m_windows_in_order.append(&window);
|
||||
if (!activeWindow())
|
||||
setActiveWindow(&window);
|
||||
}
|
||||
|
||||
void WSWindowManager::move_to_front(WSWindow& window)
|
||||
{
|
||||
m_windows_in_order.remove(&window);
|
||||
m_windows_in_order.append(&window);
|
||||
}
|
||||
|
||||
void WSWindowManager::removeWindow(WSWindow& window)
|
||||
{
|
||||
if (!m_windows.contains(&window))
|
||||
return;
|
||||
|
||||
invalidate(window);
|
||||
m_windows.remove(&window);
|
||||
m_windows_in_order.remove(&window);
|
||||
if (!activeWindow() && !m_windows.is_empty())
|
||||
setActiveWindow(*m_windows.begin());
|
||||
}
|
||||
|
||||
void WSWindowManager::notifyTitleChanged(WSWindow& window)
|
||||
{
|
||||
printf("[WM] WSWindow{%p} title set to '%s'\n", &window, window.title().characters());
|
||||
}
|
||||
|
||||
void WSWindowManager::notifyRectChanged(WSWindow& window, const Rect& old_rect, const Rect& new_rect)
|
||||
{
|
||||
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 WSWindowManager::handleTitleBarMouseEvent(WSWindow& window, MouseEvent& event)
|
||||
{
|
||||
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();
|
||||
m_dragStartRect = outerRectForWindow(window.rect());
|
||||
window.set_is_being_dragged(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::processMouseEvent(MouseEvent& event)
|
||||
{
|
||||
if (event.type() == WSEvent::MouseUp && event.button() == MouseButton::Left) {
|
||||
if (m_dragWindow) {
|
||||
printf("[WM] Finish dragging WSWindow{%p}\n", m_dragWindow.ptr());
|
||||
invalidate(m_dragStartRect);
|
||||
invalidate(*m_dragWindow);
|
||||
m_dragWindow->set_is_being_dragged(false);
|
||||
m_dragEndRect = outerRectForWindow(m_dragWindow->rect());
|
||||
m_dragWindow = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type() == WSEvent::MouseMove) {
|
||||
if (m_dragWindow) {
|
||||
auto old_window_rect = m_dragWindow->rect();
|
||||
Point pos = m_dragWindowOrigin;
|
||||
printf("[WM] Dragging [origin: %d,%d] now: %d,%d\n", m_dragOrigin.x(), m_dragOrigin.y(), event.x(), event.y());
|
||||
pos.moveBy(event.x() - m_dragOrigin.x(), event.y() - m_dragOrigin.y());
|
||||
m_dragWindow->set_position_without_repaint(pos);
|
||||
invalidate(outerRectForWindow(old_window_rect));
|
||||
invalidate(outerRectForWindow(m_dragWindow->rect()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
|
||||
if (titleBarRectForWindow(window->rect()).contains(event.position())) {
|
||||
if (event.type() == WSEvent::MouseDown) {
|
||||
move_to_front(*window);
|
||||
setActiveWindow(window);
|
||||
}
|
||||
handleTitleBarMouseEvent(*window, event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->rect().contains(event.position())) {
|
||||
if (event.type() == WSEvent::MouseDown) {
|
||||
move_to_front(*window);
|
||||
setActiveWindow(window);
|
||||
}
|
||||
// FIXME: Re-use the existing event instead of crafting a new one?
|
||||
auto localEvent = make<MouseEvent>(event.type(), event.x() - window->rect().x(), event.y() - window->rect().y(), event.button());
|
||||
window->event(*localEvent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::compose()
|
||||
{
|
||||
auto invalidated_rects = move(m_invalidated_rects);
|
||||
printf("[WM] compose #%u (%u rects)\n", ++m_recompose_count, invalidated_rects.size());
|
||||
|
||||
dbgprintf("kmalloc stats: alloc:%u free:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_sum_eternal);
|
||||
|
||||
auto any_window_contains_rect = [this] (const Rect& r) {
|
||||
for (auto* window = m_windows_in_order.head(); window; window = window->next()) {
|
||||
if (outerRectForWindow(window->rect()).contains(r))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto& r : invalidated_rects) {
|
||||
if (any_window_contains_rect(r))
|
||||
continue;
|
||||
//dbgprintf("Repaint root %d,%d %dx%d\n", r.x(), r.y(), r.width(), r.height());
|
||||
m_back_painter->fill_rect(r, Color(0, 72, 96));
|
||||
}
|
||||
for (auto* window = m_windows_in_order.head(); window; window = window->next()) {
|
||||
if (!window->backing())
|
||||
continue;
|
||||
paintWindowFrame(*window);
|
||||
m_back_painter->blit(window->position(), *window->backing());
|
||||
}
|
||||
for (auto& r : invalidated_rects)
|
||||
flush(r);
|
||||
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));
|
||||
Color inner_color = Color::White;
|
||||
Color outer_color = Color::Black;
|
||||
if (m_framebuffer.left_mouse_button_pressed())
|
||||
swap(inner_color, outer_color);
|
||||
m_front_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_inner, inner_color);
|
||||
m_front_painter->draw_bitmap(cursor_location, *m_cursor_bitmap_outer, outer_color);
|
||||
m_last_cursor_rect = cursor_rect;
|
||||
}
|
||||
|
||||
void WSWindowManager::event(WSEvent& event)
|
||||
{
|
||||
ASSERT_INTERRUPTS_ENABLED();
|
||||
LOCKER(m_lock);
|
||||
if (event.isMouseEvent())
|
||||
return processMouseEvent(static_cast<MouseEvent&>(event));
|
||||
|
||||
if (event.isKeyEvent()) {
|
||||
// FIXME: This is a good place to hook key events globally. :)
|
||||
if (m_activeWindow)
|
||||
return m_activeWindow->event(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type() == WSEvent::WM_Compose) {
|
||||
m_pending_compose_event = false;
|
||||
compose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::setActiveWindow(WSWindow* window)
|
||||
{
|
||||
if (window == m_activeWindow.ptr())
|
||||
return;
|
||||
|
||||
if (auto* previously_active_window = m_activeWindow.ptr())
|
||||
invalidate(*previously_active_window);
|
||||
m_activeWindow = window->makeWeakPtr();
|
||||
if (m_activeWindow)
|
||||
invalidate(*m_activeWindow);
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate()
|
||||
{
|
||||
m_invalidated_rects.clear_with_capacity();
|
||||
m_invalidated_rects.append(m_screen_rect);
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate(const Rect& a_rect)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, m_screen_rect);
|
||||
if (rect.is_empty())
|
||||
return;
|
||||
|
||||
for (auto& r : m_invalidated_rects) {
|
||||
if (r.contains(rect))
|
||||
return;
|
||||
if (r.intersects(rect)) {
|
||||
// Unite with the existing dirty rect.
|
||||
// FIXME: It would be much nicer to compute the exact rects needing repaint.
|
||||
r = r.united(rect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_invalidated_rects.append(rect);
|
||||
|
||||
if (!m_pending_compose_event) {
|
||||
ASSERT_INTERRUPTS_ENABLED();
|
||||
WSEventLoop::the().post_event(this, make<WSEvent>(WSEvent::WM_Compose));
|
||||
m_pending_compose_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::invalidate(const WSWindow& window)
|
||||
{
|
||||
ASSERT_INTERRUPTS_ENABLED();
|
||||
LOCKER(m_lock);
|
||||
invalidate(outerRectForWindow(window.rect()));
|
||||
}
|
||||
|
||||
void WSWindowManager::flush(const Rect& a_rect)
|
||||
{
|
||||
auto rect = Rect::intersection(a_rect, m_screen_rect);
|
||||
|
||||
RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
|
||||
const RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
|
||||
size_t pitch = m_back_bitmap->pitch();
|
||||
|
||||
#ifdef DEBUG_FLUSH_YELLOW
|
||||
m_front_painter->fill_rect(rect, Color::Yellow);
|
||||
#endif
|
||||
|
||||
for (int y = 0; y < rect.height(); ++y) {
|
||||
fast_dword_copy(front_ptr, back_ptr, rect.width());
|
||||
front_ptr = (RGBA32*)((byte*)front_ptr + pitch);
|
||||
back_ptr = (const RGBA32*)((const byte*)back_ptr + pitch);
|
||||
}
|
||||
}
|
95
WindowServer/WSWindowManager.h
Normal file
95
WindowServer/WSWindowManager.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#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 WSFrameBuffer;
|
||||
class MouseEvent;
|
||||
class PaintEvent;
|
||||
class WSWindow;
|
||||
class CharacterBitmap;
|
||||
class GraphicsBitmap;
|
||||
|
||||
class WSWindowManager : public WSEventReceiver {
|
||||
public:
|
||||
static WSWindowManager& the();
|
||||
void addWindow(WSWindow&);
|
||||
void removeWindow(WSWindow&);
|
||||
|
||||
void notifyTitleChanged(WSWindow&);
|
||||
void notifyRectChanged(WSWindow&, const Rect& oldRect, const Rect& newRect);
|
||||
|
||||
WSWindow* activeWindow() { return m_activeWindow.ptr(); }
|
||||
|
||||
void move_to_front(WSWindow&);
|
||||
|
||||
static void initialize();
|
||||
|
||||
void draw_cursor();
|
||||
|
||||
void invalidate(const WSWindow&);
|
||||
void invalidate(const Rect&);
|
||||
void invalidate();
|
||||
void flush(const Rect&);
|
||||
|
||||
private:
|
||||
WSWindowManager();
|
||||
virtual ~WSWindowManager() override;
|
||||
|
||||
void processMouseEvent(MouseEvent&);
|
||||
void handleTitleBarMouseEvent(WSWindow&, MouseEvent&);
|
||||
|
||||
void setActiveWindow(WSWindow*);
|
||||
|
||||
virtual void event(WSEvent&) override;
|
||||
|
||||
void compose();
|
||||
void paintWindowFrame(WSWindow&);
|
||||
|
||||
WSFrameBuffer& m_framebuffer;
|
||||
Rect m_screen_rect;
|
||||
|
||||
Color m_activeWindowBorderColor;
|
||||
Color m_activeWindowTitleColor;
|
||||
|
||||
Color m_inactiveWindowBorderColor;
|
||||
Color m_inactiveWindowTitleColor;
|
||||
|
||||
HashTable<WSWindow*> m_windows;
|
||||
InlineLinkedList<WSWindow> m_windows_in_order;
|
||||
|
||||
WeakPtr<WSWindow> m_activeWindow;
|
||||
|
||||
WeakPtr<WSWindow> m_dragWindow;
|
||||
|
||||
Point m_dragOrigin;
|
||||
Point m_dragWindowOrigin;
|
||||
Rect m_lastDragRect;
|
||||
Rect m_dragStartRect;
|
||||
Rect m_dragEndRect;
|
||||
|
||||
Rect m_last_cursor_rect;
|
||||
|
||||
unsigned m_recompose_count { 0 };
|
||||
|
||||
RetainPtr<GraphicsBitmap> m_front_bitmap;
|
||||
RetainPtr<GraphicsBitmap> m_back_bitmap;
|
||||
|
||||
Vector<Rect> m_invalidated_rects;
|
||||
|
||||
bool m_pending_compose_event { false };
|
||||
|
||||
RetainPtr<CharacterBitmap> m_cursor_bitmap_inner;
|
||||
RetainPtr<CharacterBitmap> m_cursor_bitmap_outer;
|
||||
|
||||
OwnPtr<Painter> m_back_painter;
|
||||
OwnPtr<Painter> m_front_painter;
|
||||
|
||||
mutable SpinLock m_lock;
|
||||
};
|
25
WindowServer/main.cpp
Normal file
25
WindowServer/main.cpp
Normal 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();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue