mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 12:37:45 +00:00
Start refactoring the windowing system to use an event loop.
Userspace programs can now open /dev/gui_events and read a stream of GUI_Event structs one at a time. I was stuck on a stupid problem where we'd reenter Scheduler::yield() due to having one of the has_data_available_for_reading() implementations using locks.
This commit is contained in:
parent
b4da4e8fbd
commit
b0e3f73375
46 changed files with 283 additions and 292 deletions
|
@ -23,7 +23,7 @@ Console::~Console()
|
|||
{
|
||||
}
|
||||
|
||||
bool Console::has_data_available_for_reading() const
|
||||
bool Console::has_data_available_for_reading(Process&) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
Console();
|
||||
virtual ~Console() override;
|
||||
|
||||
virtual bool has_data_available_for_reading() const override;
|
||||
virtual bool has_data_available_for_reading(Process&) const override;
|
||||
virtual ssize_t read(byte* buffer, size_t size) override;
|
||||
virtual ssize_t write(const byte* data, size_t size) override;
|
||||
|
||||
|
|
|
@ -11,23 +11,60 @@ struct GUI_WindowFlags { enum {
|
|||
|
||||
typedef unsigned GUI_Color;
|
||||
|
||||
struct GUI_Point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct GUI_Size {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct GUI_Rect {
|
||||
GUI_Point location;
|
||||
GUI_Size size;
|
||||
};
|
||||
|
||||
struct GUI_CreateWindowParameters {
|
||||
Rect rect;
|
||||
GUI_Rect rect;
|
||||
Color background_color;
|
||||
unsigned flags { 0 };
|
||||
char title[128];
|
||||
};
|
||||
|
||||
enum class GUI_WidgetType : unsigned {
|
||||
Label,
|
||||
Button,
|
||||
enum class GUI_MouseButton : unsigned char {
|
||||
NoButton = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
Middle = 4,
|
||||
};
|
||||
|
||||
struct GUI_CreateWidgetParameters {
|
||||
GUI_WidgetType type;
|
||||
Rect rect;
|
||||
Color background_color;
|
||||
bool opaque { true };
|
||||
unsigned flags { 0 };
|
||||
char text[256];
|
||||
struct GUI_Event {
|
||||
enum Type : unsigned {
|
||||
Invalid,
|
||||
Paint,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseUp,
|
||||
};
|
||||
Type type { Invalid };
|
||||
int window_id { -1 };
|
||||
|
||||
union {
|
||||
struct {
|
||||
GUI_Rect rect;
|
||||
} paint;
|
||||
struct {
|
||||
GUI_Point position;
|
||||
GUI_MouseButton button;
|
||||
} mouse;
|
||||
};
|
||||
};
|
||||
|
||||
inline Rect::Rect(const GUI_Rect& r) : Rect(r.location, r.size) { }
|
||||
inline Point::Point(const GUI_Point& p) : Point(p.x, p.y) { }
|
||||
inline Size::Size(const GUI_Size& s) : Size(s.width, s.height) { }
|
||||
inline Rect::operator GUI_Rect() const { return { m_location, m_size }; }
|
||||
inline Point::operator GUI_Point() const { return { m_x, m_y }; }
|
||||
inline Size::operator GUI_Size() const { return { m_width, m_height }; }
|
||||
|
|
|
@ -114,7 +114,7 @@ Keyboard::~Keyboard()
|
|||
{
|
||||
}
|
||||
|
||||
bool Keyboard::has_data_available_for_reading() const
|
||||
bool Keyboard::has_data_available_for_reading(Process&) const
|
||||
{
|
||||
return !m_queue.is_empty();
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ private:
|
|||
// ^CharacterDevice
|
||||
virtual ssize_t read(byte* buffer, size_t) override;
|
||||
virtual ssize_t write(const byte* buffer, size_t) override;
|
||||
virtual bool has_data_available_for_reading() const override;
|
||||
virtual bool has_data_available_for_reading(Process&) const override;
|
||||
|
||||
void emit(byte);
|
||||
|
||||
|
|
|
@ -62,7 +62,8 @@ WIDGETS_OBJS = \
|
|||
../Widgets/ListBox.o \
|
||||
../Widgets/CheckBox.o \
|
||||
../Widgets/TextBox.o \
|
||||
../Widgets/AbstractScreen.o
|
||||
../Widgets/AbstractScreen.o \
|
||||
../Widgets/GUIEventDevice.o \
|
||||
|
||||
AK_OBJS = \
|
||||
../AK/String.o \
|
||||
|
|
|
@ -116,7 +116,7 @@ byte PS2MouseDevice::mouse_read()
|
|||
return IO::in8(0x60);
|
||||
}
|
||||
|
||||
bool PS2MouseDevice::has_data_available_for_reading() const
|
||||
bool PS2MouseDevice::has_data_available_for_reading(Process&) const
|
||||
{
|
||||
return !m_buffer.is_empty();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
static PS2MouseDevice& the();
|
||||
|
||||
// ^CharacterDevice
|
||||
virtual bool has_data_available_for_reading() const override;
|
||||
virtual bool has_data_available_for_reading(Process&) const override;
|
||||
virtual ssize_t read(byte* buffer, size_t) override;
|
||||
virtual ssize_t write(const byte* buffer, size_t) override;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Scheduler.h"
|
||||
#include "FIFO.h"
|
||||
#include "KSyms.h"
|
||||
#include <Widgets/Window.h>
|
||||
|
||||
//#define DEBUG_IO
|
||||
//#define TASK_DEBUG
|
||||
|
@ -1057,7 +1058,7 @@ ssize_t Process::sys$read(int fd, void* outbuf, size_t nread)
|
|||
if (!descriptor)
|
||||
return -EBADF;
|
||||
if (descriptor->is_blocking()) {
|
||||
if (!descriptor->has_data_available_for_reading()) {
|
||||
if (!descriptor->has_data_available_for_reading(*this)) {
|
||||
m_blocked_fd = fd;
|
||||
block(BlockedRead);
|
||||
sched_yield();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <AK/AKString.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <AK/Lock.h>
|
||||
|
||||
class FileDescriptor;
|
||||
class PageDirectory;
|
||||
|
@ -191,13 +192,12 @@ public:
|
|||
|
||||
int gui$create_window(const GUI_CreateWindowParameters*);
|
||||
int gui$destroy_window(int window_id);
|
||||
int gui$create_widget(int window_id, const GUI_CreateWidgetParameters*);
|
||||
int gui$destroy_widget(int widget_id);
|
||||
|
||||
DisplayInfo get_display_info();
|
||||
|
||||
static void initialize();
|
||||
static void initialize_gui_statics();
|
||||
int make_window_id();
|
||||
|
||||
void crash() NORETURN;
|
||||
static int reap(Process&) WARN_UNUSED_RESULT;
|
||||
|
@ -248,6 +248,9 @@ public:
|
|||
|
||||
bool is_root() const { return m_euid == 0; }
|
||||
|
||||
Vector<GUI_Event>& gui_events() { return m_gui_events; }
|
||||
SpinLock& gui_events_lock() { return m_gui_events_lock; }
|
||||
|
||||
private:
|
||||
friend class MemoryManager;
|
||||
friend class Scheduler;
|
||||
|
@ -342,8 +345,11 @@ private:
|
|||
|
||||
RetainPtr<Region> m_display_framebuffer_region;
|
||||
|
||||
Vector<WeakPtr<Window>> m_windows;
|
||||
Vector<WeakPtr<Widget>> m_widgets;
|
||||
HashMap<int, OwnPtr<Window>> m_windows;
|
||||
|
||||
Vector<GUI_Event> m_gui_events;
|
||||
SpinLock m_gui_events_lock;
|
||||
int m_next_window_id { 1 };
|
||||
};
|
||||
|
||||
extern Process* current;
|
||||
|
|
|
@ -22,6 +22,14 @@ void Process::initialize_gui_statics()
|
|||
new EventLoop;
|
||||
}
|
||||
|
||||
int Process::make_window_id()
|
||||
{
|
||||
int new_id = m_next_window_id++;
|
||||
while (!new_id || m_windows.contains(new_id))
|
||||
new_id = m_next_window_id++;
|
||||
return new_id;
|
||||
}
|
||||
|
||||
static void wait_for_gui_server()
|
||||
{
|
||||
// FIXME: Time out after a while and return an error.
|
||||
|
@ -37,28 +45,26 @@ int Process::gui$create_window(const GUI_CreateWindowParameters* user_params)
|
|||
return -EFAULT;
|
||||
|
||||
auto params = *user_params;
|
||||
Rect rect = params.rect;
|
||||
|
||||
if (params.rect.is_empty())
|
||||
if (rect.is_empty())
|
||||
return -EINVAL;
|
||||
|
||||
ProcessPagingScope scope(EventLoop::main().server_process());
|
||||
|
||||
auto* window = new Window;
|
||||
int window_id = make_window_id();
|
||||
if (!window_id)
|
||||
return -ENOMEM;
|
||||
|
||||
auto window = make<Window>(*this, window_id);
|
||||
if (!window)
|
||||
return -ENOMEM;
|
||||
|
||||
int window_id = m_windows.size();
|
||||
m_windows.append(window->makeWeakPtr());
|
||||
|
||||
window->setTitle(params.title);
|
||||
window->setRect(params.rect);
|
||||
window->setRect(rect);
|
||||
|
||||
auto* main_widget = new Widget;
|
||||
window->setMainWidget(main_widget);
|
||||
main_widget->setWindowRelativeRect({ 0, 0, params.rect.width(), params.rect.height() });
|
||||
main_widget->setBackgroundColor(params.background_color);
|
||||
main_widget->setFillWithBackgroundColor(true);
|
||||
dbgprintf("%s<%u> gui$create_window: %d with rect {%d,%d %dx%d}\n", name().characters(), pid(), window_id, params.rect.x(), params.rect.y(), params.rect.width(), params.rect.height());
|
||||
m_windows.set(window_id, move(window));
|
||||
dbgprintf("%s<%u> gui$create_window: %d with rect {%d,%d %dx%d}\n", name().characters(), pid(), window_id, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
|
||||
return window_id;
|
||||
}
|
||||
|
@ -70,65 +76,9 @@ int Process::gui$destroy_window(int window_id)
|
|||
return -EINVAL;
|
||||
if (window_id >= static_cast<int>(m_windows.size()))
|
||||
return -EBADWINDOW;
|
||||
auto* window = m_windows[window_id].ptr();
|
||||
if (!window)
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
window->deleteLater();
|
||||
m_windows.remove(window_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$create_widget(int window_id, const GUI_CreateWidgetParameters* user_params)
|
||||
{
|
||||
if (!validate_read_typed(user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (window_id >= static_cast<int>(m_windows.size()))
|
||||
return -EINVAL;
|
||||
if (!m_windows[window_id])
|
||||
return -EINVAL;
|
||||
auto& window = *m_windows[window_id];
|
||||
|
||||
auto params = *user_params;
|
||||
|
||||
if (params.rect.is_empty())
|
||||
return -EINVAL;
|
||||
|
||||
Widget* widget = nullptr;
|
||||
switch (params.type) {
|
||||
case GUI_WidgetType::Label:
|
||||
widget = new Label(window.mainWidget());
|
||||
static_cast<Label*>(widget)->setText(params.text);
|
||||
widget->setFillWithBackgroundColor(params.opaque);
|
||||
break;
|
||||
case GUI_WidgetType::Button:
|
||||
widget = new Button(window.mainWidget());
|
||||
static_cast<Button*>(widget)->setCaption(params.text);
|
||||
break;
|
||||
}
|
||||
|
||||
int widget_id = m_widgets.size();
|
||||
m_widgets.append(widget->makeWeakPtr());
|
||||
|
||||
widget->setWindowRelativeRect(params.rect);
|
||||
widget->setBackgroundColor(params.background_color);
|
||||
dbgprintf("%s<%u> gui$create_widget: %d with rect {%d,%d %dx%d}\n", name().characters(), pid(), widget_id, params.rect.x(), params.rect.y(), params.rect.width(), params.rect.height());
|
||||
|
||||
return window_id;
|
||||
}
|
||||
|
||||
int Process::gui$destroy_widget(int widget_id)
|
||||
{
|
||||
dbgprintf("%s<%u> gui$destroy_widget (widget_id=%d)\n", name().characters(), pid(), widget_id);
|
||||
if (widget_id < 0)
|
||||
return -EINVAL;
|
||||
if (widget_id >= static_cast<int>(m_widgets.size()))
|
||||
return -EBADWINDOW;
|
||||
auto* widget = m_widgets[widget_id].ptr();
|
||||
if (!widget)
|
||||
return -EBADWIDGET;
|
||||
widget->deleteLater();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ static const dword time_slice = 5; // *10 = 50ms
|
|||
|
||||
Process* current;
|
||||
static Process* s_colonel_process;
|
||||
static bool s_in_yield;
|
||||
|
||||
struct TaskRedirectionData {
|
||||
word selector;
|
||||
|
@ -51,7 +52,7 @@ bool Scheduler::pick_next()
|
|||
if (process.state() == Process::BlockedRead) {
|
||||
ASSERT(process.m_blocked_fd != -1);
|
||||
// FIXME: Block until the amount of data wanted is available.
|
||||
if (process.m_fds[process.m_blocked_fd].descriptor->has_data_available_for_reading())
|
||||
if (process.m_fds[process.m_blocked_fd].descriptor->has_data_available_for_reading(process))
|
||||
process.unblock();
|
||||
return true;
|
||||
}
|
||||
|
@ -142,6 +143,9 @@ bool Scheduler::pick_next()
|
|||
|
||||
bool Scheduler::yield()
|
||||
{
|
||||
ASSERT(!s_in_yield);
|
||||
s_in_yield = true;
|
||||
|
||||
if (!current) {
|
||||
kprintf("PANIC: sched_yield() with !current");
|
||||
HANG;
|
||||
|
@ -150,9 +154,12 @@ bool Scheduler::yield()
|
|||
//dbgprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
||||
|
||||
InterruptDisabler disabler;
|
||||
if (!pick_next())
|
||||
if (!pick_next()) {
|
||||
s_in_yield = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
s_in_yield = false;
|
||||
//dbgprintf("yield() jumping to new process: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
||||
switch_now();
|
||||
return 0;
|
||||
|
@ -271,6 +278,7 @@ void Scheduler::initialize()
|
|||
initialize_redirection();
|
||||
s_colonel_process = Process::create_kernel_process("colonel", nullptr);
|
||||
current = nullptr;
|
||||
s_in_yield = false;
|
||||
load_task_register(s_redirection.selector);
|
||||
}
|
||||
|
||||
|
|
|
@ -191,10 +191,6 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->gui$create_window((const GUI_CreateWindowParameters*)arg1);
|
||||
case Syscall::SC_gui_destroy_window:
|
||||
return current->gui$destroy_window((int)arg1);
|
||||
case Syscall::SC_gui_create_widget:
|
||||
return current->gui$create_widget((int)arg1, (const GUI_CreateWidgetParameters*)arg2);
|
||||
case Syscall::SC_gui_destroy_widget:
|
||||
return current->gui$destroy_widget((int)arg1);
|
||||
default:
|
||||
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -68,8 +68,6 @@
|
|||
__ENUMERATE_SYSCALL(sync) \
|
||||
__ENUMERATE_SYSCALL(gui_create_window) \
|
||||
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
||||
__ENUMERATE_SYSCALL(gui_create_widget) \
|
||||
__ENUMERATE_SYSCALL(gui_destroy_widget) \
|
||||
|
||||
namespace Syscall {
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ ssize_t TTY::write(const byte* buffer, size_t size)
|
|||
return size;
|
||||
}
|
||||
|
||||
bool TTY::has_data_available_for_reading() const
|
||||
bool TTY::has_data_available_for_reading(Process&) const
|
||||
{
|
||||
return !m_buffer.is_empty();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
|
||||
virtual ssize_t read(byte*, size_t) override;
|
||||
virtual ssize_t write(const byte*, size_t) override;
|
||||
virtual bool has_data_available_for_reading() const override;
|
||||
virtual bool has_data_available_for_reading(Process&) const override;
|
||||
virtual int ioctl(Process&, unsigned request, unsigned arg) override final;
|
||||
|
||||
virtual String tty_name() const = 0;
|
||||
|
|
|
@ -4,12 +4,6 @@
|
|||
#include <Widgets/FrameBuffer.h>
|
||||
#include <Widgets/WindowManager.h>
|
||||
#include <Widgets/EventLoop.h>
|
||||
#include <Widgets/MsgBox.h>
|
||||
#include <Widgets/TextBox.h>
|
||||
#include <Widgets/Label.h>
|
||||
#include <Widgets/ListBox.h>
|
||||
#include <Widgets/Button.h>
|
||||
#include <Widgets/CheckBox.h>
|
||||
#include <Widgets/Window.h>
|
||||
|
||||
void WindowComposer_main()
|
||||
|
@ -20,52 +14,7 @@ void WindowComposer_main()
|
|||
|
||||
FrameBuffer framebuffer((dword*)info.framebuffer, info.width, info.height);
|
||||
|
||||
MsgBox(nullptr, "Serenity Operating System");
|
||||
|
||||
{
|
||||
auto* widgetTestWindow = new Window;
|
||||
widgetTestWindow->setTitle("Widget test");
|
||||
widgetTestWindow->setRect({ 20, 40, 100, 180 });
|
||||
|
||||
auto* widgetTestWindowWidget = new Widget;
|
||||
widgetTestWindowWidget->setWindowRelativeRect({ 0, 0, 100, 100 });
|
||||
widgetTestWindow->setMainWidget(widgetTestWindowWidget);
|
||||
|
||||
auto* l = new Label(widgetTestWindowWidget);
|
||||
l->setWindowRelativeRect({ 0, 0, 100, 20 });
|
||||
l->setText("Label");
|
||||
|
||||
auto* b = new Button(widgetTestWindowWidget);
|
||||
b->setWindowRelativeRect({ 0, 20, 100, 20 });
|
||||
b->setCaption("Button");
|
||||
|
||||
b->onClick = [] (Button& button) {
|
||||
printf("Button %p clicked!\n", &button);
|
||||
};
|
||||
|
||||
auto* c = new CheckBox(widgetTestWindowWidget);
|
||||
c->setWindowRelativeRect({ 0, 40, 100, 20 });
|
||||
c->setCaption("CheckBox");
|
||||
|
||||
auto *lb = new ListBox(widgetTestWindowWidget);
|
||||
lb->setWindowRelativeRect({ 0, 60, 100, 100 });
|
||||
lb->addItem("This");
|
||||
lb->addItem("is");
|
||||
lb->addItem("a");
|
||||
lb->addItem("ListBox");
|
||||
|
||||
auto *tb = new TextBox(widgetTestWindowWidget);
|
||||
tb->setWindowRelativeRect({ 0, 160, 100, 20 });
|
||||
tb->setText("Hello!");
|
||||
tb->setFocus(true);
|
||||
|
||||
tb->onReturnPressed = [] (TextBox& textBox) {
|
||||
printf("TextBox %p return pressed: '%s'\n", &textBox, textBox.text().characters());
|
||||
MsgBox(nullptr, textBox.text());
|
||||
};
|
||||
|
||||
WindowManager::the().setActiveWindow(widgetTestWindow);
|
||||
}
|
||||
WindowManager::the();
|
||||
|
||||
dbgprintf("Entering WindowComposer main loop.\n");
|
||||
EventLoop::main().exec();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "IRQHandler.h"
|
||||
#include "PIC.h"
|
||||
|
||||
//#define PAGE_FAULT_DEBUG
|
||||
#define PAGE_FAULT_DEBUG
|
||||
|
||||
struct DescriptorTablePointer {
|
||||
word size;
|
||||
|
@ -34,7 +34,7 @@ word gdt_alloc_entry()
|
|||
|
||||
void gdt_free_entry(word entry)
|
||||
{
|
||||
s_gdt_freelist->unchecked_append(entry);
|
||||
s_gdt_freelist->append(entry);
|
||||
}
|
||||
|
||||
extern "C" void handle_irq();
|
||||
|
@ -325,7 +325,7 @@ void gdt_init()
|
|||
s_gdt_freelist = new Vector<word, KmallocEternalAllocator>();
|
||||
s_gdt_freelist->ensureCapacity(256);
|
||||
for (size_t i = s_gdtLength; i < 256; ++i)
|
||||
s_gdt_freelist->unchecked_append(i * 8);
|
||||
s_gdt_freelist->append(i * 8);
|
||||
|
||||
s_gdtLength = 256;
|
||||
s_gdtr.address = s_gdt;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <VirtualFileSystem/RandomDevice.h>
|
||||
#include <VirtualFileSystem/Ext2FileSystem.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <Widgets/GUIEventDevice.h>
|
||||
#include "MemoryManager.h"
|
||||
#include "ProcFileSystem.h"
|
||||
#include "RTC.h"
|
||||
|
@ -34,6 +35,7 @@ VirtualConsole* tty2;
|
|||
VirtualConsole* tty3;
|
||||
Keyboard* keyboard;
|
||||
PS2MouseDevice* ps2mouse;
|
||||
GUIEventDevice* gui_event_device;
|
||||
|
||||
#ifdef STRESS_TEST_SPAWNING
|
||||
static void spawn_stress() NORETURN;
|
||||
|
@ -75,6 +77,7 @@ static void init_stage2()
|
|||
|
||||
vfs->register_character_device(*keyboard);
|
||||
vfs->register_character_device(*ps2mouse);
|
||||
vfs->register_character_device(*gui_event_device);
|
||||
vfs->register_character_device(*tty0);
|
||||
vfs->register_character_device(*tty1);
|
||||
vfs->register_character_device(*tty2);
|
||||
|
@ -94,7 +97,7 @@ static void init_stage2()
|
|||
environment.append("TERM=ansi");
|
||||
|
||||
int error;
|
||||
Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
||||
//Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
||||
#ifdef SPAWN_GUI_TEST_APP
|
||||
Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
||||
#endif
|
||||
|
@ -132,6 +135,7 @@ void init()
|
|||
|
||||
keyboard = new Keyboard;
|
||||
ps2mouse = new PS2MouseDevice;
|
||||
gui_event_device = new GUIEventDevice;
|
||||
|
||||
VirtualConsole::initialize();
|
||||
tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer);
|
||||
|
|
|
@ -8,6 +8,8 @@ mknod mnt/dev/tty0 c 4 0
|
|||
mknod mnt/dev/tty1 c 4 1
|
||||
mknod mnt/dev/tty2 c 4 2
|
||||
mknod mnt/dev/tty3 c 4 3
|
||||
mknod mnt/dev/psaux c 10 1
|
||||
mknod mnt/dev/gui_events c 66 1
|
||||
cp -R ../Base/* mnt/
|
||||
cp -v ../Userland/sh mnt/bin/sh
|
||||
cp -v ../Userland/id mnt/bin/id
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue