mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12: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 | ||||
|  |  | |||
|  | @ -43,7 +43,6 @@ | |||
|     __ERROR(EAFNOSUPPORT,   "Address family not supported") \ | ||||
|     __ERROR(EWHYTHO,        "Failed without setting an error code (Bug!)") \ | ||||
|     __ERROR(EBADWINDOW,     "Bad Window ID") \ | ||||
|     __ERROR(EBADWIDGET,     "Bad Widget ID") \ | ||||
| 
 | ||||
| enum __errno_values { | ||||
| #undef __ERROR | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <AK/printf.cpp> | ||||
| #include <Kernel/Syscall.h> | ||||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
|  | @ -225,6 +226,20 @@ void rewind(FILE* stream) | |||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
|  | @ -254,7 +269,7 @@ int printf(const char* fmt, ...) | |||
| { | ||||
|     va_list ap; | ||||
|     va_start(ap, fmt); | ||||
|     int ret = printfInternal(sys_putch, nullptr, fmt, ap); | ||||
|     int ret = printfInternal(stdout_putch, nullptr, fmt, ap); | ||||
|     va_end(ap); | ||||
|     return ret; | ||||
| } | ||||
|  |  | |||
|  | @ -54,6 +54,7 @@ int vfprintf(FILE*, const char* fmt, va_list); | |||
| int vsprintf(char* buffer, const char* fmt, va_list); | ||||
| int fprintf(FILE*, const char* fmt, ...); | ||||
| int printf(const char* fmt, ...); | ||||
| int sys_printf(const char* fmt, ...); | ||||
| int sprintf(char* buffer, const char* fmt, ...); | ||||
| int putchar(int ch); | ||||
| int putc(int ch, FILE*); | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
| int main(int argc, char** argv) | ||||
| { | ||||
|     GUI_CreateWindowParameters wparams; | ||||
|     wparams.rect = { 200, 200, 300, 200 }; | ||||
|     wparams.rect = { { 200, 200 }, { 300, 200 } }; | ||||
|     wparams.background_color = 0xffc0c0; | ||||
|     strcpy(wparams.title, "GUI test app"); | ||||
|     int window_id = syscall(SC_gui_create_window, &wparams); | ||||
|  | @ -20,28 +20,27 @@ int main(int argc, char** argv) | |||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     GUI_CreateWidgetParameters label_params; | ||||
|     label_params.type = GUI_WidgetType::Label; | ||||
|     label_params.rect = { 20, 20, 260, 20 }; | ||||
|     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"); | ||||
|     int fd = open("/dev/gui_events", O_RDONLY); | ||||
|     if (fd < 0) { | ||||
|         perror("open"); | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ public: | |||
| 
 | ||||
|     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 write(const byte* buffer, size_t bufferSize) = 0; | ||||
|  |  | |||
|  | @ -173,14 +173,14 @@ bool FileDescriptor::can_write() | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool FileDescriptor::has_data_available_for_reading() | ||||
| bool FileDescriptor::has_data_available_for_reading(Process& process) | ||||
| { | ||||
|     if (is_fifo()) { | ||||
|         ASSERT(fifo_direction() == FIFO::Reader); | ||||
|         return m_fifo->can_read(); | ||||
|     } | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| 
 | ||||
| #ifdef SERENITY | ||||
| class TTY; | ||||
| class Process; | ||||
| #endif | ||||
| 
 | ||||
| class FileDescriptor : public Retainable<FileDescriptor> { | ||||
|  | @ -27,7 +28,7 @@ public: | |||
|     ssize_t write(const byte* data, size_t); | ||||
|     int stat(Unix::stat*); | ||||
| 
 | ||||
|     bool has_data_available_for_reading(); | ||||
|     bool has_data_available_for_reading(Process&); | ||||
|     bool can_write(); | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,6 @@ public: | |||
| 
 | ||||
|     virtual ssize_t read(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; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,6 @@ public: | |||
| 
 | ||||
|     virtual ssize_t read(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 | ||||
| 
 | ||||
| bool RandomDevice::has_data_available_for_reading() const | ||||
| bool RandomDevice::has_data_available_for_reading(Process&) const | ||||
| { | ||||
|     return true; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,6 @@ public: | |||
| 
 | ||||
|     virtual ssize_t read(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; | ||||
| } | ||||
|  |  | |||
|  | @ -10,6 +10,6 @@ public: | |||
| 
 | ||||
|     virtual ssize_t read(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, | ||||
|         WindowBecameInactive, | ||||
|         WindowBecameActive, | ||||
|         FocusIn, | ||||
|         FocusOut, | ||||
|         WM_Compose, | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -82,7 +82,7 @@ void EventLoop::waitForEvent() | |||
|     bool prev_right_button = screen.right_mouse_button_pressed(); | ||||
|     int dx = 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]; | ||||
|         ssize_t nread = mouse.read((byte*)data, 3); | ||||
|         ASSERT(nread == 3); | ||||
|  | @ -90,7 +90,7 @@ void EventLoop::waitForEvent() | |||
|         bool right_button = data[0] & 2; | ||||
|         dx += data[1]; | ||||
|         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_right_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 "Label.h" | ||||
| #include "Button.h" | ||||
| #include "Process.h" | ||||
| 
 | ||||
| #if 0 | ||||
| void MsgBox(Window* owner, String&& text) | ||||
| { | ||||
|     Font& font = Font::defaultFont(); | ||||
|  | @ -33,7 +35,7 @@ void MsgBox(Window* owner, String&& text) | |||
|         buttonHeight | ||||
|     ); | ||||
| 
 | ||||
|     auto* window = new Window; | ||||
|     auto* window = new Window(*current, current->make_window_id()); | ||||
|     window->setTitle("MsgBox"); | ||||
|     window->setRect(windowRect); | ||||
|     auto* widget = new Widget; | ||||
|  | @ -56,4 +58,4 @@ void MsgBox(Window* owner, String&& text) | |||
|         button.window()->close(); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| #pragma once | ||||
| 
 | ||||
| class Rect; | ||||
| struct GUI_Point; | ||||
| 
 | ||||
| class Point { | ||||
| public: | ||||
|     Point() { } | ||||
|     Point(int x, int y) : m_x(x) , m_y(y) { } | ||||
|     Point(const GUI_Point&); | ||||
| 
 | ||||
|     int x() const { return m_x; } | ||||
|     int y() const { return m_y; } | ||||
|  | @ -37,6 +39,8 @@ public: | |||
|         return !(*this == other); | ||||
|     } | ||||
| 
 | ||||
|     operator GUI_Point() const; | ||||
| 
 | ||||
| private: | ||||
|     int m_x { 0 }; | ||||
|     int m_y { 0 }; | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| #include "Point.h" | ||||
| #include "Size.h" | ||||
| 
 | ||||
| struct GUI_Rect; | ||||
| 
 | ||||
| class Rect { | ||||
| public: | ||||
|     Rect() { } | ||||
|  | @ -16,6 +18,7 @@ public: | |||
|         , m_size(size) | ||||
|     { | ||||
|     } | ||||
|     Rect(const GUI_Rect&); | ||||
| 
 | ||||
|     bool is_empty() const | ||||
|     { | ||||
|  | @ -117,6 +120,8 @@ public: | |||
|     Point location() const { return m_location; } | ||||
|     Size size() const { return m_size; } | ||||
| 
 | ||||
|     operator GUI_Rect() const; | ||||
| 
 | ||||
|     bool operator==(const Rect& other) const | ||||
|     { | ||||
|         return m_location == other.m_location | ||||
|  |  | |||
|  | @ -1,9 +1,12 @@ | |||
| #pragma once | ||||
| 
 | ||||
| struct GUI_Size; | ||||
| 
 | ||||
| class Size { | ||||
| public: | ||||
|     Size() { } | ||||
|     Size(int w, int h) : m_width(w), m_height(h) { } | ||||
|     Size(const GUI_Size&); | ||||
| 
 | ||||
|     bool is_empty() const { return !m_width || !m_height; } | ||||
| 
 | ||||
|  | @ -19,6 +22,8 @@ public: | |||
|                m_height == other.m_height; | ||||
|     } | ||||
| 
 | ||||
|     operator GUI_Size() const; | ||||
| 
 | ||||
| private: | ||||
|     int m_width { 0 }; | ||||
|     int m_height { 0 }; | ||||
|  |  | |||
|  | @ -56,10 +56,7 @@ void Widget::event(Event& event) | |||
|     case Event::MouseMove: | ||||
|         return mouseMoveEvent(static_cast<MouseEvent&>(event)); | ||||
|     case Event::MouseDown: | ||||
|         if (auto* win = window()) { | ||||
|             // FIXME: if (acceptsFocus())
 | ||||
|             win->setFocusedWidget(this); | ||||
|         } | ||||
|         // FIXME: Focus self if needed.
 | ||||
|         return mouseDownEvent(static_cast<MouseEvent&>(event)); | ||||
|     case Event::MouseUp: | ||||
|         return mouseUpEvent(static_cast<MouseEvent&>(event)); | ||||
|  | @ -141,8 +138,7 @@ void Widget::setWindow(Window* window) | |||
| 
 | ||||
| bool Widget::isFocused() const | ||||
| { | ||||
|     if (auto* win = window()) | ||||
|         return win->isActive() &&  win->focusedWidget() == this; | ||||
|     // FIXME: Implement.
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|  | @ -150,8 +146,7 @@ void Widget::setFocus(bool focus) | |||
| { | ||||
|     if (focus == isFocused()) | ||||
|         return; | ||||
|     if (auto* win = window()) | ||||
|         win->setFocusedWidget(this); | ||||
|     // FIXME: Implement.
 | ||||
| } | ||||
| 
 | ||||
| void Widget::setFont(RetainPtr<Font>&& font) | ||||
|  |  | |||
|  | @ -3,31 +3,20 @@ | |||
| #include "Event.h" | ||||
| #include "EventLoop.h" | ||||
| #include "Widget.h" | ||||
| #include "Process.h" | ||||
| 
 | ||||
| Window::Window(Object* parent) | ||||
|     : Object(parent) | ||||
| Window::Window(Process& process, int window_id) | ||||
|     : m_process(process) | ||||
|     , m_window_id(window_id) | ||||
| { | ||||
|     WindowManager::the().addWindow(*this); | ||||
| } | ||||
| 
 | ||||
| Window::~Window() | ||||
| { | ||||
|     delete m_mainWidget; | ||||
|     m_mainWidget = nullptr; | ||||
|     if (parent()) | ||||
|         parent()->removeChild(*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) | ||||
| { | ||||
|     if (m_title == title) | ||||
|  | @ -58,51 +47,50 @@ void Window::update(const Rect& 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) | ||||
| { | ||||
|     if (event.isMouseEvent()) { | ||||
|         auto& me = static_cast<MouseEvent&>(event); | ||||
|         //printf("Window{%p}: %s %d,%d\n", this, me.name(), me.x(), me.y());
 | ||||
|         if (m_mainWidget) { | ||||
|             auto result = m_mainWidget->hitTest(me.x(), me.y()); | ||||
|             //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);
 | ||||
|             // FIXME: Re-use the existing event instead of crafting a new one?
 | ||||
|             auto localEvent = make<MouseEvent>(event.type(), result.localX, result.localY, me.button()); | ||||
|             return result.widget->event(*localEvent); | ||||
|         } | ||||
|         return Object::event(event); | ||||
|     GUI_Event gui_event; | ||||
|     gui_event.window_id = window_id(); | ||||
| 
 | ||||
|     switch (event.type()) { | ||||
|     case Event::Paint: | ||||
|         gui_event.type = GUI_Event::Type::Paint; | ||||
|         gui_event.paint.rect = static_cast<PaintEvent&>(event).rect(); | ||||
|         break; | ||||
|     case Event::MouseMove: | ||||
|         gui_event.type = GUI_Event::Type::MouseMove; | ||||
|         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()) { | ||||
|         auto& pe = static_cast<PaintEvent&>(event); | ||||
|         printf("Window[\"%s\"]: paintEvent %d,%d %dx%d\n", title().characters(), | ||||
|                 pe.rect().x(), | ||||
|                 pe.rect().y(), | ||||
|                 pe.rect().width(), | ||||
|                 pe.rect().height()); | ||||
|     if (gui_event.type == GUI_Event::Type::Invalid) | ||||
|         return; | ||||
| 
 | ||||
|         if (isBeingDragged()) { | ||||
|             // Ignore paint events during window drag.
 | ||||
|             return; | ||||
|         } | ||||
|         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); | ||||
|     { | ||||
|         LOCKER(m_process.gui_events_lock()); | ||||
|         m_process.gui_events().append(move(gui_event)); | ||||
|     } | ||||
| 
 | ||||
|     if (event.isKeyEvent()) { | ||||
|         if (m_focusedWidget) | ||||
|             return m_focusedWidget->event(event); | ||||
|         return Object::event(event); | ||||
|     } | ||||
| 
 | ||||
|     return Object::event(event); | ||||
| } | ||||
| 
 | ||||
| void Window::did_paint() | ||||
|  | @ -120,24 +108,6 @@ bool Window::isVisible() const | |||
|     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() | ||||
| { | ||||
|     WindowManager::the().removeWindow(*this); | ||||
|  |  | |||
|  | @ -7,13 +7,16 @@ | |||
| #include <AK/InlineLinkedList.h> | ||||
| #include <AK/WeakPtr.h> | ||||
| 
 | ||||
| class Process; | ||||
| class Widget; | ||||
| 
 | ||||
| class Window final : public Object, public InlineLinkedListNode<Window> { | ||||
| public: | ||||
|     explicit Window(Object* parent = nullptr); | ||||
|     Window(Process&, int window_id); | ||||
|     virtual ~Window() override; | ||||
| 
 | ||||
|     int window_id() const { return m_window_id; } | ||||
| 
 | ||||
|     String title() const { return m_title; } | ||||
|     void setTitle(String&&); | ||||
| 
 | ||||
|  | @ -30,11 +33,6 @@ public: | |||
|     void setPosition(const Point& position) { setRect({ 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; | ||||
| 
 | ||||
|     bool isBeingDragged() const { return m_isBeingDragged; } | ||||
|  | @ -45,10 +43,6 @@ public: | |||
| 
 | ||||
|     bool isActive() const; | ||||
| 
 | ||||
|     Widget* focusedWidget() { return m_focusedWidget.ptr(); } | ||||
|     const Widget* focusedWidget() const { return m_focusedWidget.ptr(); } | ||||
|     void setFocusedWidget(Widget*); | ||||
| 
 | ||||
|     bool isVisible() const; | ||||
| 
 | ||||
|     void close(); | ||||
|  | @ -65,11 +59,10 @@ public: | |||
| private: | ||||
|     String m_title; | ||||
|     Rect m_rect; | ||||
|     Widget* m_mainWidget { nullptr }; | ||||
|     bool m_isBeingDragged { false }; | ||||
| 
 | ||||
|     WeakPtr<Widget> m_focusedWidget; | ||||
| 
 | ||||
|     RetainPtr<GraphicsBitmap> m_backing; | ||||
|     Process& m_process; | ||||
|     int m_window_id { -1 }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling