mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 00:48:11 +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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
Console();
|
Console();
|
||||||
virtual ~Console() override;
|
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 read(byte* buffer, size_t size) override;
|
||||||
virtual ssize_t write(const byte* data, 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;
|
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 {
|
struct GUI_CreateWindowParameters {
|
||||||
Rect rect;
|
GUI_Rect rect;
|
||||||
Color background_color;
|
Color background_color;
|
||||||
unsigned flags { 0 };
|
unsigned flags { 0 };
|
||||||
char title[128];
|
char title[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class GUI_WidgetType : unsigned {
|
enum class GUI_MouseButton : unsigned char {
|
||||||
Label,
|
NoButton = 0,
|
||||||
Button,
|
Left = 1,
|
||||||
|
Right = 2,
|
||||||
|
Middle = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GUI_CreateWidgetParameters {
|
struct GUI_Event {
|
||||||
GUI_WidgetType type;
|
enum Type : unsigned {
|
||||||
Rect rect;
|
Invalid,
|
||||||
Color background_color;
|
Paint,
|
||||||
bool opaque { true };
|
MouseMove,
|
||||||
unsigned flags { 0 };
|
MouseDown,
|
||||||
char text[256];
|
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();
|
return !m_queue.is_empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ private:
|
||||||
// ^CharacterDevice
|
// ^CharacterDevice
|
||||||
virtual ssize_t read(byte* buffer, size_t) override;
|
virtual ssize_t read(byte* buffer, size_t) override;
|
||||||
virtual ssize_t write(const 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);
|
void emit(byte);
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ WIDGETS_OBJS = \
|
||||||
../Widgets/ListBox.o \
|
../Widgets/ListBox.o \
|
||||||
../Widgets/CheckBox.o \
|
../Widgets/CheckBox.o \
|
||||||
../Widgets/TextBox.o \
|
../Widgets/TextBox.o \
|
||||||
../Widgets/AbstractScreen.o
|
../Widgets/AbstractScreen.o \
|
||||||
|
../Widgets/GUIEventDevice.o \
|
||||||
|
|
||||||
AK_OBJS = \
|
AK_OBJS = \
|
||||||
../AK/String.o \
|
../AK/String.o \
|
||||||
|
|
|
@ -116,7 +116,7 @@ byte PS2MouseDevice::mouse_read()
|
||||||
return IO::in8(0x60);
|
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();
|
return !m_buffer.is_empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
static PS2MouseDevice& the();
|
static PS2MouseDevice& the();
|
||||||
|
|
||||||
// ^CharacterDevice
|
// ^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 read(byte* buffer, size_t) override;
|
||||||
virtual ssize_t write(const byte* buffer, size_t) override;
|
virtual ssize_t write(const byte* buffer, size_t) override;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Scheduler.h"
|
#include "Scheduler.h"
|
||||||
#include "FIFO.h"
|
#include "FIFO.h"
|
||||||
#include "KSyms.h"
|
#include "KSyms.h"
|
||||||
|
#include <Widgets/Window.h>
|
||||||
|
|
||||||
//#define DEBUG_IO
|
//#define DEBUG_IO
|
||||||
//#define TASK_DEBUG
|
//#define TASK_DEBUG
|
||||||
|
@ -1057,7 +1058,7 @@ ssize_t Process::sys$read(int fd, void* outbuf, size_t nread)
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
if (descriptor->is_blocking()) {
|
if (descriptor->is_blocking()) {
|
||||||
if (!descriptor->has_data_available_for_reading()) {
|
if (!descriptor->has_data_available_for_reading(*this)) {
|
||||||
m_blocked_fd = fd;
|
m_blocked_fd = fd;
|
||||||
block(BlockedRead);
|
block(BlockedRead);
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/WeakPtr.h>
|
#include <AK/WeakPtr.h>
|
||||||
|
#include <AK/Lock.h>
|
||||||
|
|
||||||
class FileDescriptor;
|
class FileDescriptor;
|
||||||
class PageDirectory;
|
class PageDirectory;
|
||||||
|
@ -191,13 +192,12 @@ public:
|
||||||
|
|
||||||
int gui$create_window(const GUI_CreateWindowParameters*);
|
int gui$create_window(const GUI_CreateWindowParameters*);
|
||||||
int gui$destroy_window(int window_id);
|
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();
|
DisplayInfo get_display_info();
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
static void initialize_gui_statics();
|
static void initialize_gui_statics();
|
||||||
|
int make_window_id();
|
||||||
|
|
||||||
void crash() NORETURN;
|
void crash() NORETURN;
|
||||||
static int reap(Process&) WARN_UNUSED_RESULT;
|
static int reap(Process&) WARN_UNUSED_RESULT;
|
||||||
|
@ -248,6 +248,9 @@ public:
|
||||||
|
|
||||||
bool is_root() const { return m_euid == 0; }
|
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:
|
private:
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
friend class Scheduler;
|
friend class Scheduler;
|
||||||
|
@ -342,8 +345,11 @@ private:
|
||||||
|
|
||||||
RetainPtr<Region> m_display_framebuffer_region;
|
RetainPtr<Region> m_display_framebuffer_region;
|
||||||
|
|
||||||
Vector<WeakPtr<Window>> m_windows;
|
HashMap<int, OwnPtr<Window>> m_windows;
|
||||||
Vector<WeakPtr<Widget>> m_widgets;
|
|
||||||
|
Vector<GUI_Event> m_gui_events;
|
||||||
|
SpinLock m_gui_events_lock;
|
||||||
|
int m_next_window_id { 1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Process* current;
|
extern Process* current;
|
||||||
|
|
|
@ -22,6 +22,14 @@ void Process::initialize_gui_statics()
|
||||||
new EventLoop;
|
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()
|
static void wait_for_gui_server()
|
||||||
{
|
{
|
||||||
// FIXME: Time out after a while and return an error.
|
// 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;
|
return -EFAULT;
|
||||||
|
|
||||||
auto params = *user_params;
|
auto params = *user_params;
|
||||||
|
Rect rect = params.rect;
|
||||||
|
|
||||||
if (params.rect.is_empty())
|
if (rect.is_empty())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ProcessPagingScope scope(EventLoop::main().server_process());
|
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)
|
if (!window)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
int window_id = m_windows.size();
|
|
||||||
m_windows.append(window->makeWeakPtr());
|
|
||||||
|
|
||||||
window->setTitle(params.title);
|
window->setTitle(params.title);
|
||||||
window->setRect(params.rect);
|
window->setRect(rect);
|
||||||
|
|
||||||
auto* main_widget = new Widget;
|
m_windows.set(window_id, move(window));
|
||||||
window->setMainWidget(main_widget);
|
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());
|
||||||
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());
|
|
||||||
|
|
||||||
return window_id;
|
return window_id;
|
||||||
}
|
}
|
||||||
|
@ -70,65 +76,9 @@ int Process::gui$destroy_window(int window_id)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (window_id >= static_cast<int>(m_windows.size()))
|
if (window_id >= static_cast<int>(m_windows.size()))
|
||||||
return -EBADWINDOW;
|
return -EBADWINDOW;
|
||||||
auto* window = m_windows[window_id].ptr();
|
auto it = m_windows.find(window_id);
|
||||||
if (!window)
|
if (it == m_windows.end())
|
||||||
return -EBADWINDOW;
|
return -EBADWINDOW;
|
||||||
window->deleteLater();
|
m_windows.remove(window_id);
|
||||||
return 0;
|
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;
|
Process* current;
|
||||||
static Process* s_colonel_process;
|
static Process* s_colonel_process;
|
||||||
|
static bool s_in_yield;
|
||||||
|
|
||||||
struct TaskRedirectionData {
|
struct TaskRedirectionData {
|
||||||
word selector;
|
word selector;
|
||||||
|
@ -51,7 +52,7 @@ bool Scheduler::pick_next()
|
||||||
if (process.state() == Process::BlockedRead) {
|
if (process.state() == Process::BlockedRead) {
|
||||||
ASSERT(process.m_blocked_fd != -1);
|
ASSERT(process.m_blocked_fd != -1);
|
||||||
// FIXME: Block until the amount of data wanted is available.
|
// 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();
|
process.unblock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +143,9 @@ bool Scheduler::pick_next()
|
||||||
|
|
||||||
bool Scheduler::yield()
|
bool Scheduler::yield()
|
||||||
{
|
{
|
||||||
|
ASSERT(!s_in_yield);
|
||||||
|
s_in_yield = true;
|
||||||
|
|
||||||
if (!current) {
|
if (!current) {
|
||||||
kprintf("PANIC: sched_yield() with !current");
|
kprintf("PANIC: sched_yield() with !current");
|
||||||
HANG;
|
HANG;
|
||||||
|
@ -150,9 +154,12 @@ bool Scheduler::yield()
|
||||||
//dbgprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
//dbgprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
||||||
|
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
if (!pick_next())
|
if (!pick_next()) {
|
||||||
|
s_in_yield = false;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_in_yield = false;
|
||||||
//dbgprintf("yield() jumping to new process: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
//dbgprintf("yield() jumping to new process: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
||||||
switch_now();
|
switch_now();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -271,6 +278,7 @@ void Scheduler::initialize()
|
||||||
initialize_redirection();
|
initialize_redirection();
|
||||||
s_colonel_process = Process::create_kernel_process("colonel", nullptr);
|
s_colonel_process = Process::create_kernel_process("colonel", nullptr);
|
||||||
current = nullptr;
|
current = nullptr;
|
||||||
|
s_in_yield = false;
|
||||||
load_task_register(s_redirection.selector);
|
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);
|
return current->gui$create_window((const GUI_CreateWindowParameters*)arg1);
|
||||||
case Syscall::SC_gui_destroy_window:
|
case Syscall::SC_gui_destroy_window:
|
||||||
return current->gui$destroy_window((int)arg1);
|
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:
|
default:
|
||||||
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -68,8 +68,6 @@
|
||||||
__ENUMERATE_SYSCALL(sync) \
|
__ENUMERATE_SYSCALL(sync) \
|
||||||
__ENUMERATE_SYSCALL(gui_create_window) \
|
__ENUMERATE_SYSCALL(gui_create_window) \
|
||||||
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
||||||
__ENUMERATE_SYSCALL(gui_create_widget) \
|
|
||||||
__ENUMERATE_SYSCALL(gui_destroy_widget) \
|
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ ssize_t TTY::write(const byte* buffer, size_t size)
|
||||||
return 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();
|
return !m_buffer.is_empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
|
|
||||||
virtual ssize_t read(byte*, size_t) override;
|
virtual ssize_t read(byte*, size_t) override;
|
||||||
virtual ssize_t write(const 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 int ioctl(Process&, unsigned request, unsigned arg) override final;
|
||||||
|
|
||||||
virtual String tty_name() const = 0;
|
virtual String tty_name() const = 0;
|
||||||
|
|
|
@ -4,12 +4,6 @@
|
||||||
#include <Widgets/FrameBuffer.h>
|
#include <Widgets/FrameBuffer.h>
|
||||||
#include <Widgets/WindowManager.h>
|
#include <Widgets/WindowManager.h>
|
||||||
#include <Widgets/EventLoop.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>
|
#include <Widgets/Window.h>
|
||||||
|
|
||||||
void WindowComposer_main()
|
void WindowComposer_main()
|
||||||
|
@ -20,52 +14,7 @@ void WindowComposer_main()
|
||||||
|
|
||||||
FrameBuffer framebuffer((dword*)info.framebuffer, info.width, info.height);
|
FrameBuffer framebuffer((dword*)info.framebuffer, info.width, info.height);
|
||||||
|
|
||||||
MsgBox(nullptr, "Serenity Operating System");
|
WindowManager::the();
|
||||||
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbgprintf("Entering WindowComposer main loop.\n");
|
dbgprintf("Entering WindowComposer main loop.\n");
|
||||||
EventLoop::main().exec();
|
EventLoop::main().exec();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "IRQHandler.h"
|
#include "IRQHandler.h"
|
||||||
#include "PIC.h"
|
#include "PIC.h"
|
||||||
|
|
||||||
//#define PAGE_FAULT_DEBUG
|
#define PAGE_FAULT_DEBUG
|
||||||
|
|
||||||
struct DescriptorTablePointer {
|
struct DescriptorTablePointer {
|
||||||
word size;
|
word size;
|
||||||
|
@ -34,7 +34,7 @@ word gdt_alloc_entry()
|
||||||
|
|
||||||
void gdt_free_entry(word entry)
|
void gdt_free_entry(word entry)
|
||||||
{
|
{
|
||||||
s_gdt_freelist->unchecked_append(entry);
|
s_gdt_freelist->append(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void handle_irq();
|
extern "C" void handle_irq();
|
||||||
|
@ -325,7 +325,7 @@ void gdt_init()
|
||||||
s_gdt_freelist = new Vector<word, KmallocEternalAllocator>();
|
s_gdt_freelist = new Vector<word, KmallocEternalAllocator>();
|
||||||
s_gdt_freelist->ensureCapacity(256);
|
s_gdt_freelist->ensureCapacity(256);
|
||||||
for (size_t i = s_gdtLength; i < 256; ++i)
|
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_gdtLength = 256;
|
||||||
s_gdtr.address = s_gdt;
|
s_gdtr.address = s_gdt;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <VirtualFileSystem/RandomDevice.h>
|
#include <VirtualFileSystem/RandomDevice.h>
|
||||||
#include <VirtualFileSystem/Ext2FileSystem.h>
|
#include <VirtualFileSystem/Ext2FileSystem.h>
|
||||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||||
|
#include <Widgets/GUIEventDevice.h>
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
#include "ProcFileSystem.h"
|
#include "ProcFileSystem.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
|
@ -34,6 +35,7 @@ VirtualConsole* tty2;
|
||||||
VirtualConsole* tty3;
|
VirtualConsole* tty3;
|
||||||
Keyboard* keyboard;
|
Keyboard* keyboard;
|
||||||
PS2MouseDevice* ps2mouse;
|
PS2MouseDevice* ps2mouse;
|
||||||
|
GUIEventDevice* gui_event_device;
|
||||||
|
|
||||||
#ifdef STRESS_TEST_SPAWNING
|
#ifdef STRESS_TEST_SPAWNING
|
||||||
static void spawn_stress() NORETURN;
|
static void spawn_stress() NORETURN;
|
||||||
|
@ -75,6 +77,7 @@ static void init_stage2()
|
||||||
|
|
||||||
vfs->register_character_device(*keyboard);
|
vfs->register_character_device(*keyboard);
|
||||||
vfs->register_character_device(*ps2mouse);
|
vfs->register_character_device(*ps2mouse);
|
||||||
|
vfs->register_character_device(*gui_event_device);
|
||||||
vfs->register_character_device(*tty0);
|
vfs->register_character_device(*tty0);
|
||||||
vfs->register_character_device(*tty1);
|
vfs->register_character_device(*tty1);
|
||||||
vfs->register_character_device(*tty2);
|
vfs->register_character_device(*tty2);
|
||||||
|
@ -94,7 +97,7 @@ static void init_stage2()
|
||||||
environment.append("TERM=ansi");
|
environment.append("TERM=ansi");
|
||||||
|
|
||||||
int error;
|
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
|
#ifdef SPAWN_GUI_TEST_APP
|
||||||
Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -132,6 +135,7 @@ void init()
|
||||||
|
|
||||||
keyboard = new Keyboard;
|
keyboard = new Keyboard;
|
||||||
ps2mouse = new PS2MouseDevice;
|
ps2mouse = new PS2MouseDevice;
|
||||||
|
gui_event_device = new GUIEventDevice;
|
||||||
|
|
||||||
VirtualConsole::initialize();
|
VirtualConsole::initialize();
|
||||||
tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer);
|
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/tty1 c 4 1
|
||||||
mknod mnt/dev/tty2 c 4 2
|
mknod mnt/dev/tty2 c 4 2
|
||||||
mknod mnt/dev/tty3 c 4 3
|
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 -R ../Base/* mnt/
|
||||||
cp -v ../Userland/sh mnt/bin/sh
|
cp -v ../Userland/sh mnt/bin/sh
|
||||||
cp -v ../Userland/id mnt/bin/id
|
cp -v ../Userland/id mnt/bin/id
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
__ERROR(EAFNOSUPPORT, "Address family not supported") \
|
__ERROR(EAFNOSUPPORT, "Address family not supported") \
|
||||||
__ERROR(EWHYTHO, "Failed without setting an error code (Bug!)") \
|
__ERROR(EWHYTHO, "Failed without setting an error code (Bug!)") \
|
||||||
__ERROR(EBADWINDOW, "Bad Window ID") \
|
__ERROR(EBADWINDOW, "Bad Window ID") \
|
||||||
__ERROR(EBADWIDGET, "Bad Widget ID") \
|
|
||||||
|
|
||||||
enum __errno_values {
|
enum __errno_values {
|
||||||
#undef __ERROR
|
#undef __ERROR
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <AK/printf.cpp>
|
#include <AK/printf.cpp>
|
||||||
|
#include <Kernel/Syscall.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
@ -225,6 +226,20 @@ void rewind(FILE* stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sys_putch(char*&, char ch)
|
static void sys_putch(char*&, char ch)
|
||||||
|
{
|
||||||
|
syscall(SC_putch, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_printf(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int ret = printfInternal(sys_putch, nullptr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stdout_putch(char*&, char ch)
|
||||||
{
|
{
|
||||||
putchar(ch);
|
putchar(ch);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +269,7 @@ int printf(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
int ret = printfInternal(sys_putch, nullptr, fmt, ap);
|
int ret = printfInternal(stdout_putch, nullptr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ int vfprintf(FILE*, const char* fmt, va_list);
|
||||||
int vsprintf(char* buffer, const char* fmt, va_list);
|
int vsprintf(char* buffer, const char* fmt, va_list);
|
||||||
int fprintf(FILE*, const char* fmt, ...);
|
int fprintf(FILE*, const char* fmt, ...);
|
||||||
int printf(const char* fmt, ...);
|
int printf(const char* fmt, ...);
|
||||||
|
int sys_printf(const char* fmt, ...);
|
||||||
int sprintf(char* buffer, const char* fmt, ...);
|
int sprintf(char* buffer, const char* fmt, ...);
|
||||||
int putchar(int ch);
|
int putchar(int ch);
|
||||||
int putc(int ch, FILE*);
|
int putc(int ch, FILE*);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
GUI_CreateWindowParameters wparams;
|
GUI_CreateWindowParameters wparams;
|
||||||
wparams.rect = { 200, 200, 300, 200 };
|
wparams.rect = { { 200, 200 }, { 300, 200 } };
|
||||||
wparams.background_color = 0xffc0c0;
|
wparams.background_color = 0xffc0c0;
|
||||||
strcpy(wparams.title, "GUI test app");
|
strcpy(wparams.title, "GUI test app");
|
||||||
int window_id = syscall(SC_gui_create_window, &wparams);
|
int window_id = syscall(SC_gui_create_window, &wparams);
|
||||||
|
@ -20,28 +20,27 @@ int main(int argc, char** argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI_CreateWidgetParameters label_params;
|
int fd = open("/dev/gui_events", O_RDONLY);
|
||||||
label_params.type = GUI_WidgetType::Label;
|
if (fd < 0) {
|
||||||
label_params.rect = { 20, 20, 260, 20 };
|
perror("open");
|
||||||
label_params.opaque = false;
|
|
||||||
strcpy(label_params.text, "Hello World!");
|
|
||||||
int label_id = syscall(SC_gui_create_widget, window_id, &label_params);
|
|
||||||
if (label_id < 0) {
|
|
||||||
perror("gui_create_widget");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUI_CreateWidgetParameters button_params;
|
|
||||||
button_params.type = GUI_WidgetType::Button;
|
|
||||||
button_params.rect = { 60, 60, 120, 20 };
|
|
||||||
strcpy(button_params.text, "I'm a button!");
|
|
||||||
int button_id = syscall(SC_gui_create_widget, window_id, &button_params);
|
|
||||||
if (button_id < 0) {
|
|
||||||
perror("gui_create_widget");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
GUI_Event event;
|
||||||
|
ssize_t nread = read(fd, &event, sizeof(event));
|
||||||
|
if (nread < 0) {
|
||||||
|
perror("read");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
assert(nread == sizeof(event));
|
||||||
|
switch (event.type) {
|
||||||
|
case GUI_Event::Type::Paint: sys_printf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
|
||||||
|
case GUI_Event::Type::MouseDown: sys_printf("WID=%x MouseDown %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
|
case GUI_Event::Type::MouseUp: sys_printf("WID=%x MouseUp %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
|
case GUI_Event::Type::MouseMove: sys_printf("WID=%x MouseMove %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y); break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
|
|
||||||
RetainPtr<FileDescriptor> open(int options);
|
RetainPtr<FileDescriptor> open(int options);
|
||||||
|
|
||||||
virtual bool has_data_available_for_reading() const = 0;
|
virtual bool has_data_available_for_reading(Process&) const = 0;
|
||||||
|
|
||||||
virtual ssize_t read(byte* buffer, size_t bufferSize) = 0;
|
virtual ssize_t read(byte* buffer, size_t bufferSize) = 0;
|
||||||
virtual ssize_t write(const byte* buffer, size_t bufferSize) = 0;
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) = 0;
|
||||||
|
|
|
@ -173,14 +173,14 @@ bool FileDescriptor::can_write()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileDescriptor::has_data_available_for_reading()
|
bool FileDescriptor::has_data_available_for_reading(Process& process)
|
||||||
{
|
{
|
||||||
if (is_fifo()) {
|
if (is_fifo()) {
|
||||||
ASSERT(fifo_direction() == FIFO::Reader);
|
ASSERT(fifo_direction() == FIFO::Reader);
|
||||||
return m_fifo->can_read();
|
return m_fifo->can_read();
|
||||||
}
|
}
|
||||||
if (m_vnode->isCharacterDevice())
|
if (m_vnode->isCharacterDevice())
|
||||||
return m_vnode->characterDevice()->has_data_available_for_reading();
|
return m_vnode->characterDevice()->has_data_available_for_reading(process);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
class TTY;
|
class TTY;
|
||||||
|
class Process;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class FileDescriptor : public Retainable<FileDescriptor> {
|
class FileDescriptor : public Retainable<FileDescriptor> {
|
||||||
|
@ -27,7 +28,7 @@ public:
|
||||||
ssize_t write(const byte* data, size_t);
|
ssize_t write(const byte* data, size_t);
|
||||||
int stat(Unix::stat*);
|
int stat(Unix::stat*);
|
||||||
|
|
||||||
bool has_data_available_for_reading();
|
bool has_data_available_for_reading(Process&);
|
||||||
bool can_write();
|
bool can_write();
|
||||||
|
|
||||||
ssize_t get_dir_entries(byte* buffer, size_t);
|
ssize_t get_dir_entries(byte* buffer, size_t);
|
||||||
|
|
|
@ -13,7 +13,7 @@ FullDevice::~FullDevice()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FullDevice::has_data_available_for_reading() const
|
bool FullDevice::has_data_available_for_reading(Process&) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ public:
|
||||||
|
|
||||||
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
||||||
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
||||||
virtual bool has_data_available_for_reading() const override;
|
virtual bool has_data_available_for_reading(Process&) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ NullDevice::~NullDevice()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NullDevice::has_data_available_for_reading() const
|
bool NullDevice::has_data_available_for_reading(Process&) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ public:
|
||||||
|
|
||||||
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
||||||
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
||||||
virtual bool has_data_available_for_reading() const override;
|
virtual bool has_data_available_for_reading(Process&) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ static void mysrand(unsigned seed)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool RandomDevice::has_data_available_for_reading() const
|
bool RandomDevice::has_data_available_for_reading(Process&) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ public:
|
||||||
|
|
||||||
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
||||||
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
||||||
virtual bool has_data_available_for_reading() const override;
|
virtual bool has_data_available_for_reading(Process&) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ ZeroDevice::~ZeroDevice()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZeroDevice::has_data_available_for_reading() const
|
bool ZeroDevice::has_data_available_for_reading(Process&) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ public:
|
||||||
|
|
||||||
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
||||||
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
||||||
virtual bool has_data_available_for_reading() const override;
|
virtual bool has_data_available_for_reading(Process&) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ public:
|
||||||
DeferredDestroy,
|
DeferredDestroy,
|
||||||
WindowBecameInactive,
|
WindowBecameInactive,
|
||||||
WindowBecameActive,
|
WindowBecameActive,
|
||||||
FocusIn,
|
|
||||||
FocusOut,
|
|
||||||
WM_Compose,
|
WM_Compose,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ void EventLoop::waitForEvent()
|
||||||
bool prev_right_button = screen.right_mouse_button_pressed();
|
bool prev_right_button = screen.right_mouse_button_pressed();
|
||||||
int dx = 0;
|
int dx = 0;
|
||||||
int dy = 0;
|
int dy = 0;
|
||||||
while (mouse.has_data_available_for_reading()) {
|
while (mouse.has_data_available_for_reading(*m_server_process)) {
|
||||||
signed_byte data[3];
|
signed_byte data[3];
|
||||||
ssize_t nread = mouse.read((byte*)data, 3);
|
ssize_t nread = mouse.read((byte*)data, 3);
|
||||||
ASSERT(nread == 3);
|
ASSERT(nread == 3);
|
||||||
|
@ -90,7 +90,7 @@ void EventLoop::waitForEvent()
|
||||||
bool right_button = data[0] & 2;
|
bool right_button = data[0] & 2;
|
||||||
dx += data[1];
|
dx += data[1];
|
||||||
dy += -data[2];
|
dy += -data[2];
|
||||||
if (left_button != prev_left_button || right_button != prev_right_button || !mouse.has_data_available_for_reading()) {
|
if (left_button != prev_left_button || right_button != prev_right_button || !mouse.has_data_available_for_reading(*m_server_process)) {
|
||||||
prev_left_button = left_button;
|
prev_left_button = left_button;
|
||||||
prev_right_button = right_button;
|
prev_right_button = right_button;
|
||||||
screen.on_receive_mouse_data(dx, dy, left_button, right_button);
|
screen.on_receive_mouse_data(dx, dy, left_button, right_button);
|
||||||
|
|
38
Widgets/GUIEventDevice.cpp
Normal file
38
Widgets/GUIEventDevice.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "GUIEventDevice.h"
|
||||||
|
#include <Kernel/Process.h>
|
||||||
|
#include <AK/Lock.h>
|
||||||
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
|
//#define GUIEVENTDEVICE_DEBUG
|
||||||
|
|
||||||
|
GUIEventDevice::GUIEventDevice()
|
||||||
|
: CharacterDevice(66, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GUIEventDevice::~GUIEventDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIEventDevice::has_data_available_for_reading(Process& process) const
|
||||||
|
{
|
||||||
|
return !process.gui_events().is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t GUIEventDevice::read(byte* buffer, size_t size)
|
||||||
|
{
|
||||||
|
#ifdef GUIEVENTDEVICE_DEBUG
|
||||||
|
dbgprintf("GUIEventDevice::read(): %s<%u>, size=%u, sizeof(GUI_Event)=%u\n", current->name().characters(), current->pid(), size, sizeof(GUI_Event));
|
||||||
|
#endif
|
||||||
|
if (current->gui_events().is_empty())
|
||||||
|
return 0;
|
||||||
|
LOCKER(current->gui_events_lock());
|
||||||
|
ASSERT(size == sizeof(GUI_Event));
|
||||||
|
*reinterpret_cast<GUI_Event*>(buffer) = current->gui_events().take_first();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t GUIEventDevice::write(const byte*, size_t)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
14
Widgets/GUIEventDevice.h
Normal file
14
Widgets/GUIEventDevice.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <VirtualFileSystem/CharacterDevice.h>
|
||||||
|
|
||||||
|
class GUIEventDevice final : public CharacterDevice {
|
||||||
|
public:
|
||||||
|
GUIEventDevice();
|
||||||
|
virtual ~GUIEventDevice() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool has_data_available_for_reading(Process&) const override;
|
||||||
|
virtual ssize_t read(byte* buffer, size_t bufferSize) override;
|
||||||
|
virtual ssize_t write(const byte* buffer, size_t bufferSize) override;
|
||||||
|
};
|
|
@ -4,7 +4,9 @@
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "Label.h"
|
#include "Label.h"
|
||||||
#include "Button.h"
|
#include "Button.h"
|
||||||
|
#include "Process.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
void MsgBox(Window* owner, String&& text)
|
void MsgBox(Window* owner, String&& text)
|
||||||
{
|
{
|
||||||
Font& font = Font::defaultFont();
|
Font& font = Font::defaultFont();
|
||||||
|
@ -33,7 +35,7 @@ void MsgBox(Window* owner, String&& text)
|
||||||
buttonHeight
|
buttonHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
auto* window = new Window;
|
auto* window = new Window(*current, current->make_window_id());
|
||||||
window->setTitle("MsgBox");
|
window->setTitle("MsgBox");
|
||||||
window->setRect(windowRect);
|
window->setRect(windowRect);
|
||||||
auto* widget = new Widget;
|
auto* widget = new Widget;
|
||||||
|
@ -56,4 +58,4 @@ void MsgBox(Window* owner, String&& text)
|
||||||
button.window()->close();
|
button.window()->close();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class Rect;
|
class Rect;
|
||||||
|
struct GUI_Point;
|
||||||
|
|
||||||
class Point {
|
class Point {
|
||||||
public:
|
public:
|
||||||
Point() { }
|
Point() { }
|
||||||
Point(int x, int y) : m_x(x) , m_y(y) { }
|
Point(int x, int y) : m_x(x) , m_y(y) { }
|
||||||
|
Point(const GUI_Point&);
|
||||||
|
|
||||||
int x() const { return m_x; }
|
int x() const { return m_x; }
|
||||||
int y() const { return m_y; }
|
int y() const { return m_y; }
|
||||||
|
@ -37,6 +39,8 @@ public:
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator GUI_Point() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_x { 0 };
|
int m_x { 0 };
|
||||||
int m_y { 0 };
|
int m_y { 0 };
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "Point.h"
|
#include "Point.h"
|
||||||
#include "Size.h"
|
#include "Size.h"
|
||||||
|
|
||||||
|
struct GUI_Rect;
|
||||||
|
|
||||||
class Rect {
|
class Rect {
|
||||||
public:
|
public:
|
||||||
Rect() { }
|
Rect() { }
|
||||||
|
@ -16,6 +18,7 @@ public:
|
||||||
, m_size(size)
|
, m_size(size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Rect(const GUI_Rect&);
|
||||||
|
|
||||||
bool is_empty() const
|
bool is_empty() const
|
||||||
{
|
{
|
||||||
|
@ -117,6 +120,8 @@ public:
|
||||||
Point location() const { return m_location; }
|
Point location() const { return m_location; }
|
||||||
Size size() const { return m_size; }
|
Size size() const { return m_size; }
|
||||||
|
|
||||||
|
operator GUI_Rect() const;
|
||||||
|
|
||||||
bool operator==(const Rect& other) const
|
bool operator==(const Rect& other) const
|
||||||
{
|
{
|
||||||
return m_location == other.m_location
|
return m_location == other.m_location
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
struct GUI_Size;
|
||||||
|
|
||||||
class Size {
|
class Size {
|
||||||
public:
|
public:
|
||||||
Size() { }
|
Size() { }
|
||||||
Size(int w, int h) : m_width(w), m_height(h) { }
|
Size(int w, int h) : m_width(w), m_height(h) { }
|
||||||
|
Size(const GUI_Size&);
|
||||||
|
|
||||||
bool is_empty() const { return !m_width || !m_height; }
|
bool is_empty() const { return !m_width || !m_height; }
|
||||||
|
|
||||||
|
@ -19,6 +22,8 @@ public:
|
||||||
m_height == other.m_height;
|
m_height == other.m_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator GUI_Size() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_width { 0 };
|
int m_width { 0 };
|
||||||
int m_height { 0 };
|
int m_height { 0 };
|
||||||
|
|
|
@ -56,10 +56,7 @@ void Widget::event(Event& event)
|
||||||
case Event::MouseMove:
|
case Event::MouseMove:
|
||||||
return mouseMoveEvent(static_cast<MouseEvent&>(event));
|
return mouseMoveEvent(static_cast<MouseEvent&>(event));
|
||||||
case Event::MouseDown:
|
case Event::MouseDown:
|
||||||
if (auto* win = window()) {
|
// FIXME: Focus self if needed.
|
||||||
// FIXME: if (acceptsFocus())
|
|
||||||
win->setFocusedWidget(this);
|
|
||||||
}
|
|
||||||
return mouseDownEvent(static_cast<MouseEvent&>(event));
|
return mouseDownEvent(static_cast<MouseEvent&>(event));
|
||||||
case Event::MouseUp:
|
case Event::MouseUp:
|
||||||
return mouseUpEvent(static_cast<MouseEvent&>(event));
|
return mouseUpEvent(static_cast<MouseEvent&>(event));
|
||||||
|
@ -141,8 +138,7 @@ void Widget::setWindow(Window* window)
|
||||||
|
|
||||||
bool Widget::isFocused() const
|
bool Widget::isFocused() const
|
||||||
{
|
{
|
||||||
if (auto* win = window())
|
// FIXME: Implement.
|
||||||
return win->isActive() && win->focusedWidget() == this;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +146,7 @@ void Widget::setFocus(bool focus)
|
||||||
{
|
{
|
||||||
if (focus == isFocused())
|
if (focus == isFocused())
|
||||||
return;
|
return;
|
||||||
if (auto* win = window())
|
// FIXME: Implement.
|
||||||
win->setFocusedWidget(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::setFont(RetainPtr<Font>&& font)
|
void Widget::setFont(RetainPtr<Font>&& font)
|
||||||
|
|
|
@ -3,31 +3,20 @@
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "EventLoop.h"
|
#include "EventLoop.h"
|
||||||
#include "Widget.h"
|
#include "Widget.h"
|
||||||
|
#include "Process.h"
|
||||||
|
|
||||||
Window::Window(Object* parent)
|
Window::Window(Process& process, int window_id)
|
||||||
: Object(parent)
|
: m_process(process)
|
||||||
|
, m_window_id(window_id)
|
||||||
{
|
{
|
||||||
WindowManager::the().addWindow(*this);
|
WindowManager::the().addWindow(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::~Window()
|
Window::~Window()
|
||||||
{
|
{
|
||||||
delete m_mainWidget;
|
|
||||||
m_mainWidget = nullptr;
|
|
||||||
if (parent())
|
|
||||||
parent()->removeChild(*this);
|
|
||||||
WindowManager::the().removeWindow(*this);
|
WindowManager::the().removeWindow(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::setMainWidget(Widget* widget)
|
|
||||||
{
|
|
||||||
if (m_mainWidget == widget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_mainWidget = widget;
|
|
||||||
widget->setWindow(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::setTitle(String&& title)
|
void Window::setTitle(String&& title)
|
||||||
{
|
{
|
||||||
if (m_title == title)
|
if (m_title == title)
|
||||||
|
@ -58,51 +47,50 @@ void Window::update(const Rect& rect)
|
||||||
EventLoop::main().postEvent(this, make<PaintEvent>(rect));
|
EventLoop::main().postEvent(this, make<PaintEvent>(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 Window::event(Event& event)
|
void Window::event(Event& event)
|
||||||
{
|
{
|
||||||
if (event.isMouseEvent()) {
|
GUI_Event gui_event;
|
||||||
auto& me = static_cast<MouseEvent&>(event);
|
gui_event.window_id = window_id();
|
||||||
//printf("Window{%p}: %s %d,%d\n", this, me.name(), me.x(), me.y());
|
|
||||||
if (m_mainWidget) {
|
switch (event.type()) {
|
||||||
auto result = m_mainWidget->hitTest(me.x(), me.y());
|
case Event::Paint:
|
||||||
//printf("hit test for %d,%d found: %s{%p} %d,%d\n", me.x(), me.y(), result.widget->class_name(), result.widget, result.localX, result.localY);
|
gui_event.type = GUI_Event::Type::Paint;
|
||||||
// FIXME: Re-use the existing event instead of crafting a new one?
|
gui_event.paint.rect = static_cast<PaintEvent&>(event).rect();
|
||||||
auto localEvent = make<MouseEvent>(event.type(), result.localX, result.localY, me.button());
|
break;
|
||||||
return result.widget->event(*localEvent);
|
case Event::MouseMove:
|
||||||
}
|
gui_event.type = GUI_Event::Type::MouseMove;
|
||||||
return Object::event(event);
|
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
|
||||||
|
break;
|
||||||
|
case Event::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 Event::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.isPaintEvent()) {
|
if (gui_event.type == GUI_Event::Type::Invalid)
|
||||||
auto& pe = static_cast<PaintEvent&>(event);
|
return;
|
||||||
printf("Window[\"%s\"]: paintEvent %d,%d %dx%d\n", title().characters(),
|
|
||||||
pe.rect().x(),
|
|
||||||
pe.rect().y(),
|
|
||||||
pe.rect().width(),
|
|
||||||
pe.rect().height());
|
|
||||||
|
|
||||||
if (isBeingDragged()) {
|
{
|
||||||
// Ignore paint events during window drag.
|
LOCKER(m_process.gui_events_lock());
|
||||||
return;
|
m_process.gui_events().append(move(gui_event));
|
||||||
}
|
|
||||||
if (m_mainWidget) {
|
|
||||||
if (pe.rect().is_empty())
|
|
||||||
m_mainWidget->event(*make<PaintEvent>(m_mainWidget->rect()));
|
|
||||||
else
|
|
||||||
m_mainWidget->event(event);
|
|
||||||
WindowManager::the().did_paint(*this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return Object::event(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.isKeyEvent()) {
|
|
||||||
if (m_focusedWidget)
|
|
||||||
return m_focusedWidget->event(event);
|
|
||||||
return Object::event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object::event(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::did_paint()
|
void Window::did_paint()
|
||||||
|
@ -120,24 +108,6 @@ bool Window::isVisible() const
|
||||||
return WindowManager::the().isVisible(const_cast<Window&>(*this));
|
return WindowManager::the().isVisible(const_cast<Window&>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::setFocusedWidget(Widget* widget)
|
|
||||||
{
|
|
||||||
if (m_focusedWidget.ptr() == widget)
|
|
||||||
return;
|
|
||||||
auto* previously_focused_widget = m_focusedWidget.ptr();
|
|
||||||
if (!widget)
|
|
||||||
m_focusedWidget = nullptr;
|
|
||||||
else {
|
|
||||||
m_focusedWidget = widget->makeWeakPtr();
|
|
||||||
m_focusedWidget->update();
|
|
||||||
EventLoop::main().postEvent(m_focusedWidget.ptr(), make<Event>(Event::FocusIn));
|
|
||||||
}
|
|
||||||
if (previously_focused_widget) {
|
|
||||||
previously_focused_widget->update();
|
|
||||||
EventLoop::main().postEvent(previously_focused_widget, make<Event>(Event::FocusOut));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::close()
|
void Window::close()
|
||||||
{
|
{
|
||||||
WindowManager::the().removeWindow(*this);
|
WindowManager::the().removeWindow(*this);
|
||||||
|
|
|
@ -7,13 +7,16 @@
|
||||||
#include <AK/InlineLinkedList.h>
|
#include <AK/InlineLinkedList.h>
|
||||||
#include <AK/WeakPtr.h>
|
#include <AK/WeakPtr.h>
|
||||||
|
|
||||||
|
class Process;
|
||||||
class Widget;
|
class Widget;
|
||||||
|
|
||||||
class Window final : public Object, public InlineLinkedListNode<Window> {
|
class Window final : public Object, public InlineLinkedListNode<Window> {
|
||||||
public:
|
public:
|
||||||
explicit Window(Object* parent = nullptr);
|
Window(Process&, int window_id);
|
||||||
virtual ~Window() override;
|
virtual ~Window() override;
|
||||||
|
|
||||||
|
int window_id() const { return m_window_id; }
|
||||||
|
|
||||||
String title() const { return m_title; }
|
String title() const { return m_title; }
|
||||||
void setTitle(String&&);
|
void setTitle(String&&);
|
||||||
|
|
||||||
|
@ -30,11 +33,6 @@ public:
|
||||||
void setPosition(const Point& position) { setRect({ position.x(), position.y(), width(), height() }); }
|
void setPosition(const Point& position) { setRect({ position.x(), position.y(), width(), height() }); }
|
||||||
void setPositionWithoutRepaint(const Point& position) { setRectWithoutRepaint({ position.x(), position.y(), width(), height() }); }
|
void setPositionWithoutRepaint(const Point& position) { setRectWithoutRepaint({ position.x(), position.y(), width(), height() }); }
|
||||||
|
|
||||||
Widget* mainWidget() { return m_mainWidget; }
|
|
||||||
const Widget* mainWidget() const { return m_mainWidget; }
|
|
||||||
|
|
||||||
void setMainWidget(Widget*);
|
|
||||||
|
|
||||||
virtual void event(Event&) override;
|
virtual void event(Event&) override;
|
||||||
|
|
||||||
bool isBeingDragged() const { return m_isBeingDragged; }
|
bool isBeingDragged() const { return m_isBeingDragged; }
|
||||||
|
@ -45,10 +43,6 @@ public:
|
||||||
|
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
|
|
||||||
Widget* focusedWidget() { return m_focusedWidget.ptr(); }
|
|
||||||
const Widget* focusedWidget() const { return m_focusedWidget.ptr(); }
|
|
||||||
void setFocusedWidget(Widget*);
|
|
||||||
|
|
||||||
bool isVisible() const;
|
bool isVisible() const;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
@ -65,11 +59,10 @@ public:
|
||||||
private:
|
private:
|
||||||
String m_title;
|
String m_title;
|
||||||
Rect m_rect;
|
Rect m_rect;
|
||||||
Widget* m_mainWidget { nullptr };
|
|
||||||
bool m_isBeingDragged { false };
|
bool m_isBeingDragged { false };
|
||||||
|
|
||||||
WeakPtr<Widget> m_focusedWidget;
|
|
||||||
|
|
||||||
RetainPtr<GraphicsBitmap> m_backing;
|
RetainPtr<GraphicsBitmap> m_backing;
|
||||||
|
Process& m_process;
|
||||||
|
int m_window_id { -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue