mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:22:45 +00:00 
			
		
		
		
	Move WindowServer to userspace.
This is a monster patch that required changing a whole bunch of things. There are performance and stability issues all over the place, but it works. Pretty cool, I have to admit :^)
This commit is contained in:
		
							parent
							
								
									0b1b21d622
								
							
						
					
					
						commit
						640360e958
					
				
					 41 changed files with 325 additions and 463 deletions
				
			
		|  | @ -95,9 +95,9 @@ Region* BochsVGADevice::mmap(Process& process, LinearAddress preferred_laddr, si | ||||||
|         0, |         0, | ||||||
|         "BochsVGA Framebuffer", |         "BochsVGA Framebuffer", | ||||||
|         true, true); |         true, true); | ||||||
|     kprintf("BochsVGA: %s(%u) created Region{%p} for framebuffer P%x\n", |     kprintf("BochsVGA: %s(%u) created Region{%p} with size %u for framebuffer P%x with laddr L%x\n", | ||||||
|             process.name().characters(), process.pid(), |             process.name().characters(), process.pid(), | ||||||
|             region, framebuffer_address().as_ptr()); |             region, region->size(), framebuffer_address().as_ptr(), region->laddr().get()); | ||||||
|     ASSERT(region); |     ASSERT(region); | ||||||
|     return region; |     return region; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include <Kernel/Socket.h> | #include <Kernel/Socket.h> | ||||||
| #include <Kernel/Process.h> | #include <Kernel/Process.h> | ||||||
| #include <Kernel/BlockDevice.h> | #include <Kernel/BlockDevice.h> | ||||||
|  | #include <Kernel/MemoryManager.h> | ||||||
| 
 | 
 | ||||||
| RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& inode) | RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& inode) | ||||||
| { | { | ||||||
|  | @ -54,6 +55,10 @@ FileDescriptor::FileDescriptor(RetainPtr<Socket>&& socket, SocketRole role) | ||||||
| 
 | 
 | ||||||
| FileDescriptor::~FileDescriptor() | FileDescriptor::~FileDescriptor() | ||||||
| { | { | ||||||
|  |     if (m_socket) { | ||||||
|  |         m_socket->close(m_socket_role); | ||||||
|  |         m_socket = nullptr; | ||||||
|  |     } | ||||||
|     if (m_device) { |     if (m_device) { | ||||||
|         m_device->close(); |         m_device->close(); | ||||||
|         m_device = nullptr; |         m_device = nullptr; | ||||||
|  | @ -364,6 +369,7 @@ Region* FileDescriptor::mmap(Process& process, LinearAddress laddr, size_t offse | ||||||
|     // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
 |     // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
 | ||||||
|     ASSERT(laddr.as_ptr() == nullptr); |     ASSERT(laddr.as_ptr() == nullptr); | ||||||
|     auto* region = process.allocate_file_backed_region(LinearAddress(), size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); |     auto* region = process.allocate_file_backed_region(LinearAddress(), size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); | ||||||
|  |     region->page_in(); | ||||||
|     return region; |     return region; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -108,3 +108,20 @@ enum KeyCode : byte { | ||||||
|     Key_Tilde, |     Key_Tilde, | ||||||
|     Key_Backtick, |     Key_Backtick, | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | enum KeyModifier { | ||||||
|  |     Mod_Alt = 0x01, | ||||||
|  |     Mod_Ctrl = 0x02, | ||||||
|  |     Mod_Shift = 0x04, | ||||||
|  |     Is_Press = 0x80, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct KeyEvent { | ||||||
|  |     KeyCode key { Key_Invalid }; | ||||||
|  |     byte character { 0 }; | ||||||
|  |     byte flags { 0 }; | ||||||
|  |     bool alt() const { return flags & Mod_Alt; } | ||||||
|  |     bool ctrl() const { return flags & Mod_Ctrl; } | ||||||
|  |     bool shift() const { return flags & Mod_Shift; } | ||||||
|  |     bool is_press() const { return flags & Is_Press; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @ -12,22 +12,7 @@ class KeyboardClient; | ||||||
| class Keyboard final : public IRQHandler, public CharacterDevice { | class Keyboard final : public IRQHandler, public CharacterDevice { | ||||||
|     AK_MAKE_ETERNAL |     AK_MAKE_ETERNAL | ||||||
| public: | public: | ||||||
|     enum Modifier { |     using Event = KeyEvent; | ||||||
|         Mod_Alt = 0x01, |  | ||||||
|         Mod_Ctrl = 0x02, |  | ||||||
|         Mod_Shift = 0x04, |  | ||||||
|         Is_Press = 0x80, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct Event { |  | ||||||
|         KeyCode key { Key_Invalid }; |  | ||||||
|         byte character { 0 }; |  | ||||||
|         byte flags { 0 }; |  | ||||||
|         bool alt() const { return flags & Mod_Alt; } |  | ||||||
|         bool ctrl() const { return flags & Mod_Ctrl; } |  | ||||||
|         bool shift() const { return flags & Mod_Shift; } |  | ||||||
|         bool is_press() const { return flags & Is_Press; } |  | ||||||
|     }; |  | ||||||
| 
 | 
 | ||||||
|     [[gnu::pure]] static Keyboard& the(); |     [[gnu::pure]] static Keyboard& the(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -106,37 +106,54 @@ bool LocalSocket::connect(const sockaddr* address, socklen_t address_size, int& | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void LocalSocket::close(SocketRole role) | ||||||
|  | { | ||||||
|  |     if (role == SocketRole::Accepted) | ||||||
|  |         m_server_closed = true; | ||||||
|  |     else if (role == SocketRole::Connected) | ||||||
|  |         m_client_closed = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool LocalSocket::can_read(SocketRole role) const | bool LocalSocket::can_read(SocketRole role) const | ||||||
| { | { | ||||||
|     if (m_bound && is_listening()) |     if (m_bound && is_listening()) | ||||||
|         return can_accept(); |         return can_accept(); | ||||||
| 
 | 
 | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return !m_for_server.is_empty(); |         return m_client_closed || !m_for_server.is_empty(); | ||||||
|     else |     else if (role == SocketRole::Connected) | ||||||
|         return !m_for_client.is_empty(); |         return m_server_closed || !m_for_client.is_empty(); | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size) | ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size) | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return m_for_server.read(buffer, size); |         return m_for_server.read(buffer, size); | ||||||
|     else |     else if (role == SocketRole::Connected) | ||||||
|         return m_for_client.read(buffer, size); |         return m_for_client.read(buffer, size); | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size) | ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size) | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) { | ||||||
|  |         if (m_client_closed) | ||||||
|  |             return -EPIPE; | ||||||
|         return m_for_client.write(data, size); |         return m_for_client.write(data, size); | ||||||
|     else |     } else if (role == SocketRole::Connected) { | ||||||
|  |         if (m_client_closed) | ||||||
|  |             return -EPIPE; | ||||||
|         return m_for_server.write(data, size); |         return m_for_server.write(data, size); | ||||||
|  |     } | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LocalSocket::can_write(SocketRole role) const | bool LocalSocket::can_write(SocketRole role) const | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return m_for_client.bytes_in_write_buffer() < 4096; |         return m_client_closed || m_for_client.bytes_in_write_buffer() < 4096; | ||||||
|     else |     else if (role == SocketRole::Connected) | ||||||
|         return m_for_server.bytes_in_write_buffer() < 4096; |         return m_server_closed || m_for_server.bytes_in_write_buffer() < 4096; | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ public: | ||||||
|     virtual bool bind(const sockaddr*, socklen_t, int& error) override; |     virtual bool bind(const sockaddr*, socklen_t, int& error) override; | ||||||
|     virtual bool connect(const sockaddr*, socklen_t, int& error) override; |     virtual bool connect(const sockaddr*, socklen_t, int& error) override; | ||||||
|     virtual bool get_address(sockaddr*, socklen_t*) override; |     virtual bool get_address(sockaddr*, socklen_t*) override; | ||||||
| 
 |     virtual void close(SocketRole) override; | ||||||
|     virtual bool can_read(SocketRole) const override; |     virtual bool can_read(SocketRole) const override; | ||||||
|     virtual ssize_t read(SocketRole, byte*, size_t) override; |     virtual ssize_t read(SocketRole, byte*, size_t) override; | ||||||
|     virtual ssize_t write(SocketRole, const byte*, size_t) override; |     virtual ssize_t write(SocketRole, const byte*, size_t) override; | ||||||
|  | @ -27,6 +27,8 @@ private: | ||||||
|     RetainPtr<LocalSocket> m_peer; |     RetainPtr<LocalSocket> m_peer; | ||||||
| 
 | 
 | ||||||
|     bool m_bound { false }; |     bool m_bound { false }; | ||||||
|  |     bool m_server_closed { false }; | ||||||
|  |     bool m_client_closed { false }; | ||||||
|     sockaddr_un m_address; |     sockaddr_un m_address; | ||||||
| 
 | 
 | ||||||
|     DoubleBuffer m_for_client; |     DoubleBuffer m_for_client; | ||||||
|  |  | ||||||
|  | @ -51,26 +51,6 @@ VFS_OBJS = \ | ||||||
|     FileDescriptor.o \
 |     FileDescriptor.o \
 | ||||||
|     SyntheticFileSystem.o |     SyntheticFileSystem.o | ||||||
| 
 | 
 | ||||||
| SHAREDGRAPHICS_OBJS = \
 |  | ||||||
|     ../SharedGraphics/Rect.o \
 |  | ||||||
|     ../SharedGraphics/Painter.o \
 |  | ||||||
|     ../SharedGraphics/Font.o \
 |  | ||||||
|     ../SharedGraphics/Color.o \
 |  | ||||||
|     ../SharedGraphics/CharacterBitmap.o \
 |  | ||||||
|     ../SharedGraphics/GraphicsBitmap.o |  | ||||||
| 
 |  | ||||||
| WINDOWSERVER_OBJS = \
 |  | ||||||
|     ../WindowServer/WSMessageReceiver.o \
 |  | ||||||
|     ../WindowServer/WSMessageLoop.o \
 |  | ||||||
|     ../WindowServer/WSWindow.o \
 |  | ||||||
|     ../WindowServer/WSWindowManager.o \
 |  | ||||||
|     ../WindowServer/WSScreen.o \
 |  | ||||||
|     ../WindowServer/WSMenuBar.o \
 |  | ||||||
|     ../WindowServer/WSMenu.o \
 |  | ||||||
|     ../WindowServer/WSMenuItem.o \
 |  | ||||||
|     ../WindowServer/WSClientConnection.o \
 |  | ||||||
|     ../WindowServer/main.o |  | ||||||
| 
 |  | ||||||
| AK_OBJS = \
 | AK_OBJS = \
 | ||||||
|     ../AK/String.o \
 |     ../AK/String.o \
 | ||||||
|     ../AK/StringImpl.o \
 |     ../AK/StringImpl.o \
 | ||||||
|  | @ -78,7 +58,7 @@ AK_OBJS = \ | ||||||
|     ../AK/FileSystemPath.o \
 |     ../AK/FileSystemPath.o \
 | ||||||
|     ../AK/StdLibExtras.o |     ../AK/StdLibExtras.o | ||||||
| 
 | 
 | ||||||
| OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(WINDOWSERVER_OBJS) $(SHAREDGRAPHICS_OBJS) | OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) | ||||||
| 
 | 
 | ||||||
| NASM = nasm | NASM = nasm | ||||||
| KERNEL = kernel | KERNEL = kernel | ||||||
|  | @ -89,7 +69,7 @@ STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc | ||||||
| KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident -fno-builtin | KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident -fno-builtin | ||||||
| WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough | WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough | ||||||
| FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic | FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic | ||||||
| OPTIMIZATION_FLAGS = -Oz -fno-asynchronous-unwind-tables -fno-omit-frame-pointer | OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables -fno-omit-frame-pointer | ||||||
| INCLUDE_FLAGS = -I.. -I. | INCLUDE_FLAGS = -I.. -I. | ||||||
| #SUGGEST_FLAGS = -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override #-Wsuggest-attribute=noreturn 
 | #SUGGEST_FLAGS = -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override #-Wsuggest-attribute=noreturn 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -581,9 +581,12 @@ bool MemoryManager::validate_user_write(const Process& process, LinearAddress la | ||||||
| 
 | 
 | ||||||
| RetainPtr<Region> Region::clone() | RetainPtr<Region> Region::clone() | ||||||
| { | { | ||||||
|     InterruptDisabler disabler; |  | ||||||
| 
 |  | ||||||
|     if (m_shared || (m_readable && !m_writable)) { |     if (m_shared || (m_readable && !m_writable)) { | ||||||
|  |         dbgprintf("%s<%u> Region::clone(): sharing %s (L%x)\n", | ||||||
|  |                   current->name().characters(), | ||||||
|  |                   current->pid(), | ||||||
|  |                   m_name.characters(), | ||||||
|  |                   laddr().get()); | ||||||
|         // Create a new region backed by the same VMObject.
 |         // Create a new region backed by the same VMObject.
 | ||||||
|         return adopt(*new Region(laddr(), size(), m_vmo.copy_ref(), m_offset_in_vmo, String(m_name), m_readable, m_writable)); |         return adopt(*new Region(laddr(), size(), m_vmo.copy_ref(), m_offset_in_vmo, String(m_name), m_readable, m_writable)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -142,6 +142,7 @@ public: | ||||||
|     const VMObject& vmo() const { return *m_vmo; } |     const VMObject& vmo() const { return *m_vmo; } | ||||||
|     VMObject& vmo() { return *m_vmo; } |     VMObject& vmo() { return *m_vmo; } | ||||||
| 
 | 
 | ||||||
|  |     bool is_shared() const { return m_shared; } | ||||||
|     void set_shared(bool shared) { m_shared = shared; } |     void set_shared(bool shared) { m_shared = shared; } | ||||||
| 
 | 
 | ||||||
|     bool is_bitmap() const { return m_is_bitmap; } |     bool is_bitmap() const { return m_is_bitmap; } | ||||||
|  |  | ||||||
|  | @ -18,16 +18,17 @@ | ||||||
| #include "Scheduler.h" | #include "Scheduler.h" | ||||||
| #include "FIFO.h" | #include "FIFO.h" | ||||||
| #include "KSyms.h" | #include "KSyms.h" | ||||||
| #include <WindowServer/WSMessageLoop.h> |  | ||||||
| #include <Kernel/Socket.h> | #include <Kernel/Socket.h> | ||||||
| #include "MasterPTY.h" | #include "MasterPTY.h" | ||||||
| #include "elf.h" | #include "elf.h" | ||||||
|  | #include <AK/StringBuilder.h> | ||||||
| 
 | 
 | ||||||
| //#define DEBUG_IO
 | //#define DEBUG_IO
 | ||||||
| //#define TASK_DEBUG
 | //#define TASK_DEBUG
 | ||||||
| //#define FORK_DEBUG
 | //#define FORK_DEBUG
 | ||||||
| #define SIGNAL_DEBUG | #define SIGNAL_DEBUG | ||||||
| #define MAX_PROCESS_GIDS 32 | #define MAX_PROCESS_GIDS 32 | ||||||
|  | //#define SHARED_BUFFER_DEBUG
 | ||||||
| 
 | 
 | ||||||
| static const dword default_kernel_stack_size = 16384; | static const dword default_kernel_stack_size = 16384; | ||||||
| static const dword default_userspace_stack_size = 65536; | static const dword default_userspace_stack_size = 65536; | ||||||
|  | @ -49,7 +50,6 @@ void Process::initialize() | ||||||
|     s_hostname = new String("courage"); |     s_hostname = new String("courage"); | ||||||
|     s_hostname_lock = new Lock; |     s_hostname_lock = new Lock; | ||||||
|     Scheduler::initialize(); |     Scheduler::initialize(); | ||||||
|     new WSMessageLoop; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Vector<pid_t> Process::all_pids() | Vector<pid_t> Process::all_pids() | ||||||
|  | @ -167,11 +167,11 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params) | ||||||
|     if ((dword)addr & ~PAGE_MASK) |     if ((dword)addr & ~PAGE_MASK) | ||||||
|         return (void*)-EINVAL; |         return (void*)-EINVAL; | ||||||
|     if (flags & MAP_ANONYMOUS) { |     if (flags & MAP_ANONYMOUS) { | ||||||
|         // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae.
 |         auto* region = allocate_region(LinearAddress((dword)addr), size, "mmap", prot & PROT_READ, prot & PROT_WRITE, false); | ||||||
|         ASSERT(addr == nullptr); |  | ||||||
|         auto* region = allocate_region(LinearAddress(), size, "mmap", prot & PROT_READ, prot & PROT_WRITE, false); |  | ||||||
|         if (!region) |         if (!region) | ||||||
|             return (void*)-ENOMEM; |             return (void*)-ENOMEM; | ||||||
|  |         if (flags & MAP_SHARED) | ||||||
|  |             region->set_shared(true); | ||||||
|         return region->laddr().as_ptr(); |         return region->laddr().as_ptr(); | ||||||
|     } |     } | ||||||
|     if (offset & ~PAGE_MASK) |     if (offset & ~PAGE_MASK) | ||||||
|  | @ -184,6 +184,8 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params) | ||||||
|     auto* region = descriptor->mmap(*this, LinearAddress((dword)addr), offset, size, prot); |     auto* region = descriptor->mmap(*this, LinearAddress((dword)addr), offset, size, prot); | ||||||
|     if (!region) |     if (!region) | ||||||
|         return (void*)-ENOMEM; |         return (void*)-ENOMEM; | ||||||
|  |     if (flags & MAP_SHARED) | ||||||
|  |         region->set_shared(true); | ||||||
|     return region->laddr().as_ptr(); |     return region->laddr().as_ptr(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -191,9 +193,9 @@ int Process::sys$munmap(void* addr, size_t size) | ||||||
| { | { | ||||||
|     auto* region = region_from_range(LinearAddress((dword)addr), size); |     auto* region = region_from_range(LinearAddress((dword)addr), size); | ||||||
|     if (!region) |     if (!region) | ||||||
|         return -1; |         return -EINVAL; | ||||||
|     if (!deallocate_region(*region)) |     if (!deallocate_region(*region)) | ||||||
|         return -1; |         return -EINVAL; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -2136,9 +2138,6 @@ void Process::finalize() | ||||||
| { | { | ||||||
|     ASSERT(current == g_finalizer); |     ASSERT(current == g_finalizer); | ||||||
| 
 | 
 | ||||||
|     if (WSMessageLoop::the().running()) |  | ||||||
|         WSMessageLoop::the().notify_client_died(gui_client_id()); |  | ||||||
| 
 |  | ||||||
|     m_fds.clear(); |     m_fds.clear(); | ||||||
|     m_tty = nullptr; |     m_tty = nullptr; | ||||||
|     disown_all_shared_buffers(); |     disown_all_shared_buffers(); | ||||||
|  | @ -2367,13 +2366,17 @@ struct SharedBuffer { | ||||||
|     { |     { | ||||||
|         if (m_pid1 == process.pid()) { |         if (m_pid1 == process.pid()) { | ||||||
|             ++m_pid1_retain_count; |             ++m_pid1_retain_count; | ||||||
|             if (!m_pid1_region) |             if (!m_pid1_region) { | ||||||
|                 m_pid1_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true); |                 m_pid1_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true); | ||||||
|  |                 m_pid1_region->set_shared(true); | ||||||
|  |             } | ||||||
|             return m_pid1_region->laddr().as_ptr(); |             return m_pid1_region->laddr().as_ptr(); | ||||||
|         } else if (m_pid2 == process.pid()) { |         } else if (m_pid2 == process.pid()) { | ||||||
|             ++m_pid2_retain_count; |             ++m_pid2_retain_count; | ||||||
|             if (!m_pid2_region) |             if (!m_pid2_region) { | ||||||
|                 m_pid2_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true); |                 m_pid2_region = process.allocate_region_with_vmo(LinearAddress(), size(), m_vmo.copy_ref(), 0, "SharedBuffer", true, true); | ||||||
|  |                 m_pid2_region->set_shared(true); | ||||||
|  |             } | ||||||
|             return m_pid2_region->laddr().as_ptr(); |             return m_pid2_region->laddr().as_ptr(); | ||||||
|         } |         } | ||||||
|         return nullptr; |         return nullptr; | ||||||
|  | @ -2445,7 +2448,9 @@ void SharedBuffer::destroy_if_unused() | ||||||
| { | { | ||||||
|     if (!m_pid1_retain_count && !m_pid2_retain_count) { |     if (!m_pid1_retain_count && !m_pid2_retain_count) { | ||||||
|         LOCKER(shared_buffers().lock()); |         LOCKER(shared_buffers().lock()); | ||||||
|         kprintf("Destroying unused SharedBuffer{%p} (pid1: %d, pid2: %d)\n", this, m_pid1, m_pid2); | #ifdef SHARED_BUFFER_DEBUG | ||||||
|  |         dbgprintf("Destroying unused SharedBuffer{%p} (pid1: %d, pid2: %d)\n", this, m_pid1, m_pid2); | ||||||
|  | #endif | ||||||
|         shared_buffers().resource().remove(m_shared_buffer_id); |         shared_buffers().resource().remove(m_shared_buffer_id); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -2474,7 +2479,11 @@ int Process::sys$create_shared_buffer(pid_t peer_pid, size_t size, void** buffer | ||||||
|     int shared_buffer_id = ++s_next_shared_buffer_id; |     int shared_buffer_id = ++s_next_shared_buffer_id; | ||||||
|     auto shared_buffer = make<SharedBuffer>(m_pid, peer_pid, size); |     auto shared_buffer = make<SharedBuffer>(m_pid, peer_pid, size); | ||||||
|     shared_buffer->m_pid1_region = allocate_region_with_vmo(LinearAddress(), shared_buffer->size(), shared_buffer->m_vmo.copy_ref(), 0, "SharedBuffer", true, true); |     shared_buffer->m_pid1_region = allocate_region_with_vmo(LinearAddress(), shared_buffer->size(), shared_buffer->m_vmo.copy_ref(), 0, "SharedBuffer", true, true); | ||||||
|  |     shared_buffer->m_pid1_region->set_shared(true); | ||||||
|     *buffer = shared_buffer->m_pid1_region->laddr().as_ptr(); |     *buffer = shared_buffer->m_pid1_region->laddr().as_ptr(); | ||||||
|  | #ifdef SHARED_BUFFER_DEBUG | ||||||
|  |     dbgprintf("%s(%u): Created shared buffer %d (%u bytes, vmo is %u) for sharing with %d\n", name().characters(), pid(),shared_buffer_id, size, shared_buffer->size(), peer_pid); | ||||||
|  | #endif | ||||||
|     shared_buffers().resource().set(shared_buffer_id, move(shared_buffer)); |     shared_buffers().resource().set(shared_buffer_id, move(shared_buffer)); | ||||||
|     return shared_buffer_id; |     return shared_buffer_id; | ||||||
| } | } | ||||||
|  | @ -2486,6 +2495,9 @@ int Process::sys$release_shared_buffer(int shared_buffer_id) | ||||||
|     if (it == shared_buffers().resource().end()) |     if (it == shared_buffers().resource().end()) | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|     auto& shared_buffer = *(*it).value; |     auto& shared_buffer = *(*it).value; | ||||||
|  | #ifdef SHARED_BUFFER_DEBUG | ||||||
|  |     dbgprintf("%s(%u): Releasing shared buffer %d\n", name().characters(), pid(), shared_buffer_id); | ||||||
|  | #endif | ||||||
|     shared_buffer.release(*this); |     shared_buffer.release(*this); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | @ -2499,5 +2511,8 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id) | ||||||
|     auto& shared_buffer = *(*it).value; |     auto& shared_buffer = *(*it).value; | ||||||
|     if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid) |     if (shared_buffer.pid1() != m_pid && shared_buffer.pid2() != m_pid) | ||||||
|         return (void*)-EINVAL; |         return (void*)-EINVAL; | ||||||
|  | #ifdef SHARED_BUFFER_DEBUG | ||||||
|  |     dbgprintf("%s(%u): Retaining shared buffer %d\n", name().characters(), pid(), shared_buffer_id); | ||||||
|  | #endif | ||||||
|     return shared_buffer.retain(*this); |     return shared_buffer.retain(*this); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -48,9 +48,6 @@ struct DisplayInfo { | ||||||
| 
 | 
 | ||||||
| class Process : public InlineLinkedListNode<Process>, public Weakable<Process> { | class Process : public InlineLinkedListNode<Process>, public Weakable<Process> { | ||||||
|     friend class InlineLinkedListNode<Process>; |     friend class InlineLinkedListNode<Process>; | ||||||
|     friend class WSWindowManager; // FIXME: Make a better API for allocate_region().
 |  | ||||||
|     friend class GraphicsBitmap; // FIXME: Make a better API for allocate_region().
 |  | ||||||
|     friend class Font; //FIXME: This is beyond gross.
 |  | ||||||
| public: | public: | ||||||
|     static Process* create_kernel_process(String&& name, void (*entry)()); |     static Process* create_kernel_process(String&& name, void (*entry)()); | ||||||
|     static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr); |     static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr); | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ public: | ||||||
|     virtual bool connect(const sockaddr*, socklen_t, int& error) = 0; |     virtual bool connect(const sockaddr*, socklen_t, int& error) = 0; | ||||||
|     virtual bool get_address(sockaddr*, socklen_t*) = 0; |     virtual bool get_address(sockaddr*, socklen_t*) = 0; | ||||||
|     virtual bool is_local() const { return false; } |     virtual bool is_local() const { return false; } | ||||||
| 
 |     virtual void close(SocketRole) = 0; | ||||||
|     virtual bool can_read(SocketRole) const = 0; |     virtual bool can_read(SocketRole) const = 0; | ||||||
|     virtual ssize_t read(SocketRole, byte*, size_t) = 0; |     virtual ssize_t read(SocketRole, byte*, size_t) = 0; | ||||||
|     virtual ssize_t write(SocketRole, const byte*, size_t) = 0; |     virtual ssize_t write(SocketRole, const byte*, size_t) = 0; | ||||||
|  |  | ||||||
|  | @ -25,9 +25,9 @@ | ||||||
| #include "BochsVGADevice.h" | #include "BochsVGADevice.h" | ||||||
| 
 | 
 | ||||||
| //#define SPAWN_GUITEST
 | //#define SPAWN_GUITEST
 | ||||||
| #define SPAWN_LAUNCHER | //#define SPAWN_LAUNCHER
 | ||||||
| //#define SPAWN_GUITEST2
 | //#define SPAWN_GUITEST2
 | ||||||
| #define SPAWN_FILE_MANAGER | //#define SPAWN_FILE_MANAGER
 | ||||||
| //#define SPAWN_FONTEDITOR
 | //#define SPAWN_FONTEDITOR
 | ||||||
| //#define SPAWN_MULTIPLE_SHELLS
 | //#define SPAWN_MULTIPLE_SHELLS
 | ||||||
| //#define STRESS_TEST_SPAWNING
 | //#define STRESS_TEST_SPAWNING
 | ||||||
|  | @ -101,6 +101,10 @@ VFS* vfs; | ||||||
| 
 | 
 | ||||||
|     int error; |     int error; | ||||||
| 
 | 
 | ||||||
|  |     Process::create_user_process("/bin/WindowServer", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0); | ||||||
|  |     if (error != 0) { | ||||||
|  |         dbgprintf("error: %d\n", 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);
 | ||||||
|     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0); |     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0); | ||||||
| #ifdef SPAWN_GUITEST | #ifdef SPAWN_GUITEST | ||||||
|  | @ -128,9 +132,6 @@ VFS* vfs; | ||||||
|     Process::create_kernel_process("spawn_stress", spawn_stress); |     Process::create_kernel_process("spawn_stress", spawn_stress); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     extern void WindowServer_main(); |  | ||||||
|     Process::create_kernel_process("WindowServer", WindowServer_main); |  | ||||||
| 
 |  | ||||||
|     current->sys$exit(0); |     current->sys$exit(0); | ||||||
|     ASSERT_NOT_REACHED(); |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ $make_cmd -C ../LibGUI clean && \ | ||||||
| $make_cmd -C ../LibGUI && \ | $make_cmd -C ../LibGUI && \ | ||||||
| $make_cmd -C ../Userland clean && \ | $make_cmd -C ../Userland clean && \ | ||||||
| $make_cmd -C ../Userland && \ | $make_cmd -C ../Userland && \ | ||||||
|  | $make_cmd -C ../WindowServer clean && \ | ||||||
|  | $make_cmd -C ../WindowServer && \ | ||||||
| $make_cmd -C ../Applications/Terminal clean && \ | $make_cmd -C ../Applications/Terminal clean && \ | ||||||
| $make_cmd -C ../Applications/Terminal && \ | $make_cmd -C ../Applications/Terminal && \ | ||||||
| $make_cmd -C ../Applications/FontEditor clean && \ | $make_cmd -C ../Applications/FontEditor clean && \ | ||||||
|  |  | ||||||
|  | @ -69,6 +69,7 @@ cp -v ../Applications/Launcher/Launcher mnt/bin/Launcher | ||||||
| cp -v ../Applications/Clock/Clock mnt/bin/Clock | cp -v ../Applications/Clock/Clock mnt/bin/Clock | ||||||
| cp -v ../Applications/FileManager/FileManager mnt/bin/FileManager | cp -v ../Applications/FileManager/FileManager mnt/bin/FileManager | ||||||
| cp -v ../Applications/About/About mnt/bin/About | cp -v ../Applications/About/About mnt/bin/About | ||||||
|  | cp -v ../WindowServer/WindowServer mnt/bin/WindowServer | ||||||
| cp -v kernel.map mnt/ | cp -v kernel.map mnt/ | ||||||
| sh sync-local.sh | sh sync-local.sh | ||||||
| umount mnt | umount mnt | ||||||
|  |  | ||||||
|  | @ -57,7 +57,7 @@ STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc | ||||||
| LIBC_FLAGS = -ffreestanding -fno-stack-protector -fno-ident | LIBC_FLAGS = -ffreestanding -fno-stack-protector -fno-ident | ||||||
| WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough | WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough | ||||||
| FLAVOR_FLAGS = -fomit-frame-pointer -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic | FLAVOR_FLAGS = -fomit-frame-pointer -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic | ||||||
| OPTIMIZATION_FLAGS = -O2 -fno-asynchronous-unwind-tables | OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables | ||||||
| INCLUDE_FLAGS = -I.. -I. | INCLUDE_FLAGS = -I.. -I. | ||||||
| 
 | 
 | ||||||
| DEFINES = -DSERENITY -DUSERLAND -DSANITIZE_PTRS | DEFINES = -DSERENITY -DUSERLAND -DSANITIZE_PTRS | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ | ||||||
|     __ERROR(EWHYTHO,        "Failed without setting an error code (Bug!)") \ |     __ERROR(EWHYTHO,        "Failed without setting an error code (Bug!)") \ | ||||||
|     __ERROR(ENOTEMPTY,      "Directory not empty") \ |     __ERROR(ENOTEMPTY,      "Directory not empty") \ | ||||||
|     __ERROR(ECONNREFUSED,   "Connection refused") \ |     __ERROR(ECONNREFUSED,   "Connection refused") \ | ||||||
|  |     __ERROR(EMAXERRNO,      "The highest errno +1 :^)") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| enum __errno_values { | enum __errno_values { | ||||||
|  |  | ||||||
|  | @ -357,7 +357,11 @@ int create_shared_buffer(pid_t peer_pid, size_t size, void** buffer) | ||||||
| void* get_shared_buffer(int shared_buffer_id) | void* get_shared_buffer(int shared_buffer_id) | ||||||
| { | { | ||||||
|     int rc = syscall(SC_get_shared_buffer, shared_buffer_id); |     int rc = syscall(SC_get_shared_buffer, shared_buffer_id); | ||||||
|     __RETURN_WITH_ERRNO(rc, (void*)rc, (void*)-1); |     if (rc < 0 && -rc < EMAXERRNO) { | ||||||
|  |         errno = -rc; | ||||||
|  |         return (void*)-1; | ||||||
|  |     } | ||||||
|  |     return (void*)rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int release_shared_buffer(int shared_buffer_id) | int release_shared_buffer(int shared_buffer_id) | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ GEventLoop::GEventLoop() | ||||||
|     address.sun_family = AF_LOCAL; |     address.sun_family = AF_LOCAL; | ||||||
|     strcpy(address.sun_path, "/wsportal"); |     strcpy(address.sun_path, "/wsportal"); | ||||||
| 
 | 
 | ||||||
|     int retries = 10; |     int retries = 1000; | ||||||
|     int rc = 0; |     int rc = 0; | ||||||
|     while (retries) { |     while (retries) { | ||||||
|         rc = connect(m_event_fd, (const sockaddr*)&address, sizeof(address)); |         rc = connect(m_event_fd, (const sockaddr*)&address, sizeof(address)); | ||||||
|  | @ -53,6 +53,7 @@ GEventLoop::GEventLoop() | ||||||
|     if (rc < 0) { |     if (rc < 0) { | ||||||
|         ASSERT_NOT_REACHED(); |         ASSERT_NOT_REACHED(); | ||||||
|     } |     } | ||||||
|  |     dbgprintf("(%u) GEventLoop constructed :)\n", getpid()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GEventLoop::~GEventLoop() | GEventLoop::~GEventLoop() | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ | ||||||
| #include <SharedGraphics/GraphicsBitmap.h> | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
| #include <SharedGraphics/Painter.h> | #include <SharedGraphics/Painter.h> | ||||||
| 
 | 
 | ||||||
|  | #include <unistd.h> | ||||||
|  | 
 | ||||||
| GWidget::GWidget(GWidget* parent) | GWidget::GWidget(GWidget* parent) | ||||||
|     : GObject(parent) |     : GObject(parent) | ||||||
| { | { | ||||||
|  | @ -72,7 +74,9 @@ void GWidget::handle_paint_event(GPaintEvent& event) | ||||||
|         Painter painter(*this); |         Painter painter(*this); | ||||||
|         painter.fill_rect(event.rect(), background_color()); |         painter.fill_rect(event.rect(), background_color()); | ||||||
|     } |     } | ||||||
|  |     dbgprintf("GWidget{%p} handle_paint_event %s before calling paint_event()\n", this, event.rect().to_string().characters()); | ||||||
|     paint_event(event); |     paint_event(event); | ||||||
|  |     dbgprintf("GWidget{%p} handle_paint_event %s after calling paint_event()\n", this, event.rect().to_string().characters()); | ||||||
|     for (auto* ch : children()) { |     for (auto* ch : children()) { | ||||||
|         auto* child = (GWidget*)ch; |         auto* child = (GWidget*)ch; | ||||||
|         if (child->relative_rect().intersects(event.rect())) { |         if (child->relative_rect().intersects(event.rect())) { | ||||||
|  |  | ||||||
|  | @ -3,20 +3,11 @@ | ||||||
| #include <AK/BufferStream.h> | #include <AK/BufferStream.h> | ||||||
| #include <AK/StdLibExtras.h> | #include <AK/StdLibExtras.h> | ||||||
| 
 | 
 | ||||||
| #ifdef KERNEL |  | ||||||
| #include <Kernel/Process.h> |  | ||||||
| #include <Kernel/MemoryManager.h> |  | ||||||
| #include <Kernel/FileDescriptor.h> |  | ||||||
| #include <Kernel/VirtualFileSystem.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef USERLAND |  | ||||||
| #include <LibC/unistd.h> | #include <LibC/unistd.h> | ||||||
| #include <LibC/stdio.h> | #include <LibC/stdio.h> | ||||||
| #include <LibC/fcntl.h> | #include <LibC/fcntl.h> | ||||||
| #include <LibC/errno.h> | #include <LibC/errno.h> | ||||||
| #include <LibC/mman.h> | #include <LibC/mman.h> | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| static const byte error_glyph_width = 8; | static const byte error_glyph_width = 8; | ||||||
| static const byte error_glyph_height = 10; | static const byte error_glyph_height = 10; | ||||||
|  | @ -54,19 +45,7 @@ Font& Font::default_font() | ||||||
| { | { | ||||||
|     static const char* default_font_path = "/res/fonts/LizaRegular8x10.font"; |     static const char* default_font_path = "/res/fonts/LizaRegular8x10.font"; | ||||||
|     if (!s_default_font) { |     if (!s_default_font) { | ||||||
| #ifdef USERLAND |  | ||||||
|         s_default_font = Font::load_from_file(default_font_path).leak_ref(); |         s_default_font = Font::load_from_file(default_font_path).leak_ref(); | ||||||
| #else |  | ||||||
|         int error; |  | ||||||
|         auto descriptor = VFS::the().open(default_font_path, error, 0, 0, *VFS::the().root_inode()); |  | ||||||
|         if (!descriptor) { |  | ||||||
|             kprintf("Failed to open default font (%s)\n", default_font_path); |  | ||||||
|             ASSERT_NOT_REACHED(); |  | ||||||
|         } |  | ||||||
|         auto* region = current->allocate_file_backed_region(LinearAddress(), font_file_size(10), descriptor->inode(), "default_font", /*readable*/true, /*writable*/false); |  | ||||||
|         ASSERT(region); |  | ||||||
|         s_default_font = Font::load_from_memory(region->laddr().as_ptr()).leak_ref(); |  | ||||||
| #endif |  | ||||||
|         ASSERT(s_default_font); |         ASSERT(s_default_font); | ||||||
|     } |     } | ||||||
|     return *s_default_font; |     return *s_default_font; | ||||||
|  | @ -76,19 +55,7 @@ Font& Font::default_bold_font() | ||||||
| { | { | ||||||
|     static const char* default_bold_font_path = "/res/fonts/LizaBold8x10.font"; |     static const char* default_bold_font_path = "/res/fonts/LizaBold8x10.font"; | ||||||
|     if (!s_default_bold_font) { |     if (!s_default_bold_font) { | ||||||
| #ifdef USERLAND |  | ||||||
|         s_default_bold_font = Font::load_from_file(default_bold_font_path).leak_ref(); |         s_default_bold_font = Font::load_from_file(default_bold_font_path).leak_ref(); | ||||||
| #else |  | ||||||
|         int error; |  | ||||||
|         auto descriptor = VFS::the().open(default_bold_font_path, error, 0, 0, *VFS::the().root_inode()); |  | ||||||
|         if (!descriptor) { |  | ||||||
|             kprintf("Failed to open default bold font (%s)\n", default_bold_font_path); |  | ||||||
|             ASSERT_NOT_REACHED(); |  | ||||||
|         } |  | ||||||
|         auto* region = current->allocate_file_backed_region(LinearAddress(), font_file_size(10), descriptor->inode(), "default_bold_font", /*readable*/true, /*writable*/false); |  | ||||||
|         ASSERT(region); |  | ||||||
|         s_default_bold_font = Font::load_from_memory(region->laddr().as_ptr()).leak_ref(); |  | ||||||
| #endif |  | ||||||
|         ASSERT(s_default_bold_font); |         ASSERT(s_default_bold_font); | ||||||
|     } |     } | ||||||
|     return *s_default_bold_font; |     return *s_default_bold_font; | ||||||
|  | @ -116,6 +83,10 @@ Font::Font(const String& name, unsigned* rows, byte glyph_width, byte glyph_heig | ||||||
| 
 | 
 | ||||||
| Font::~Font() | Font::~Font() | ||||||
| { | { | ||||||
|  |     if (m_mmap_ptr) { | ||||||
|  |         int rc = munmap(m_mmap_ptr, 4096 * 3); | ||||||
|  |         ASSERT(rc == 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RetainPtr<Font> Font::load_from_memory(const byte* data) | RetainPtr<Font> Font::load_from_memory(const byte* data) | ||||||
|  | @ -134,7 +105,6 @@ RetainPtr<Font> Font::load_from_memory(const byte* data) | ||||||
|     return adopt(*new Font(String(header.name), rows, header.glyph_width, header.glyph_height)); |     return adopt(*new Font(String(header.name), rows, header.glyph_width, header.glyph_height)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef USERLAND |  | ||||||
| RetainPtr<Font> Font::load_from_file(const String& path) | RetainPtr<Font> Font::load_from_file(const String& path) | ||||||
| { | { | ||||||
|     int fd = open(path.characters(), O_RDONLY, 0644); |     int fd = open(path.characters(), O_RDONLY, 0644); | ||||||
|  | @ -152,6 +122,7 @@ RetainPtr<Font> Font::load_from_file(const String& path) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto font = load_from_memory(mapped_file); |     auto font = load_from_memory(mapped_file); | ||||||
|  |     font->m_mmap_ptr = mapped_file; | ||||||
| 
 | 
 | ||||||
|     int rc = close(fd); |     int rc = close(fd); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
|  | @ -189,4 +160,3 @@ bool Font::write_to_file(const String& path) | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | @ -47,10 +47,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     static RetainPtr<Font> load_from_memory(const byte*); |     static RetainPtr<Font> load_from_memory(const byte*); | ||||||
| 
 | 
 | ||||||
| #ifdef USERLAND |  | ||||||
|     static RetainPtr<Font> load_from_file(const String& path); |     static RetainPtr<Font> load_from_file(const String& path); | ||||||
|     bool write_to_file(const String& path); |     bool write_to_file(const String& path); | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     ~Font(); |     ~Font(); | ||||||
| 
 | 
 | ||||||
|  | @ -69,6 +67,7 @@ private: | ||||||
|     String m_name; |     String m_name; | ||||||
| 
 | 
 | ||||||
|     unsigned* m_rows { nullptr }; |     unsigned* m_rows { nullptr }; | ||||||
|  |     void* m_mmap_ptr { nullptr }; | ||||||
| 
 | 
 | ||||||
|     RetainPtr<CharacterBitmap> m_error_bitmap; |     RetainPtr<CharacterBitmap> m_error_bitmap; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,18 +1,9 @@ | ||||||
| #include "GraphicsBitmap.h" | #include "GraphicsBitmap.h" | ||||||
| 
 |  | ||||||
| #ifdef KERNEL |  | ||||||
| #include <Kernel/Process.h> |  | ||||||
| #include <Kernel/MemoryManager.h> |  | ||||||
| #include <WindowServer/WSMessageLoop.h> |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef USERLAND |  | ||||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| RetainPtr<GraphicsBitmap> GraphicsBitmap::create(const Size& size) | RetainPtr<GraphicsBitmap> GraphicsBitmap::create(const Size& size) | ||||||
| { | { | ||||||
|  | @ -23,18 +14,9 @@ GraphicsBitmap::GraphicsBitmap(const Size& size) | ||||||
|     : m_size(size) |     : m_size(size) | ||||||
|     , m_pitch(size.width() * sizeof(RGBA32)) |     , m_pitch(size.width() * sizeof(RGBA32)) | ||||||
| { | { | ||||||
| #ifdef KERNEL |     m_data = (RGBA32*)mmap(nullptr, size.area() * sizeof(RGBA32), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); | ||||||
|     Syscall::SC_mmap_params params; |  | ||||||
|     memset(¶ms, 0, sizeof(params)); |  | ||||||
|     params.fd = 0; |  | ||||||
|     params.prot = PROT_READ | PROT_WRITE; |  | ||||||
|     params.flags = MAP_ANONYMOUS | MAP_PRIVATE; |  | ||||||
|     params.size = size.area() * sizeof(RGBA32); |  | ||||||
|     params.offset = 0; |  | ||||||
|     m_data = (RGBA32*)current->sys$mmap(¶ms); |  | ||||||
|     ASSERT(m_data && m_data != (void*)-1); |     ASSERT(m_data && m_data != (void*)-1); | ||||||
|     m_mmaped = true; |     m_mmaped = true; | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RetainPtr<GraphicsBitmap> GraphicsBitmap::create_wrapper(const Size& size, RGBA32* data) | RetainPtr<GraphicsBitmap> GraphicsBitmap::create_wrapper(const Size& size, RGBA32* data) | ||||||
|  | @ -44,8 +26,6 @@ RetainPtr<GraphicsBitmap> GraphicsBitmap::create_wrapper(const Size& size, RGBA3 | ||||||
| 
 | 
 | ||||||
| RetainPtr<GraphicsBitmap> GraphicsBitmap::load_from_file(const String& path, const Size& size) | RetainPtr<GraphicsBitmap> GraphicsBitmap::load_from_file(const String& path, const Size& size) | ||||||
| { | { | ||||||
|     RGBA32* mapped_data = nullptr; |  | ||||||
| #ifdef USERLAND |  | ||||||
|     int fd = open(path.characters(), O_RDONLY, 0644); |     int fd = open(path.characters(), O_RDONLY, 0644); | ||||||
|     if (fd < 0) { |     if (fd < 0) { | ||||||
|         dbgprintf("open(%s) got fd=%d, failed: %s\n", path.characters(), fd, strerror(errno)); |         dbgprintf("open(%s) got fd=%d, failed: %s\n", path.characters(), fd, strerror(errno)); | ||||||
|  | @ -53,35 +33,17 @@ RetainPtr<GraphicsBitmap> GraphicsBitmap::load_from_file(const String& path, con | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     mapped_data = (RGBA32*)mmap(nullptr, size.area() * 4, PROT_READ, MAP_SHARED, fd, 0); |     auto* mapped_data = (RGBA32*)mmap(nullptr, size.area() * 4, PROT_READ, MAP_SHARED, fd, 0); | ||||||
|     if (mapped_data == MAP_FAILED) { |     if (mapped_data == MAP_FAILED) { | ||||||
|         int rc = close(fd); |         int rc = close(fd); | ||||||
|         ASSERT(rc == 0); |         ASSERT(rc == 0); | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| #else |  | ||||||
|     int error; |  | ||||||
|     auto descriptor = VFS::the().open(path, error, 0, 0, *VFS::the().root_inode()); |  | ||||||
|     if (!descriptor) { |  | ||||||
|         kprintf("Failed to load GraphicsBitmap from file (%s)\n", path.characters()); |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
|     auto* region = WSMessageLoop::the().server_process().allocate_file_backed_region(LinearAddress(), size.area() * 4, descriptor->inode(), ".rgb file", /*readable*/true, /*writable*/false); |  | ||||||
|     mapped_data = (RGBA32*)region->laddr().get(); |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| #ifdef USERLAND |  | ||||||
|     int rc = close(fd); |     int rc = close(fd); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
| #endif |  | ||||||
|     auto bitmap = create_wrapper(size, mapped_data); |     auto bitmap = create_wrapper(size, mapped_data); | ||||||
| #ifdef KERNEL |  | ||||||
|     bitmap->m_server_region = region; |  | ||||||
| #else |  | ||||||
|     bitmap->m_mmaped = true; |     bitmap->m_mmaped = true; | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     return bitmap; |     return bitmap; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -95,11 +57,7 @@ GraphicsBitmap::GraphicsBitmap(const Size& size, RGBA32* data) | ||||||
| RetainPtr<GraphicsBitmap> GraphicsBitmap::create_with_shared_buffer(int shared_buffer_id, const Size& size, RGBA32* data) | RetainPtr<GraphicsBitmap> GraphicsBitmap::create_with_shared_buffer(int shared_buffer_id, const Size& size, RGBA32* data) | ||||||
| { | { | ||||||
|     if (!data) { |     if (!data) { | ||||||
| #ifdef KERNEL |  | ||||||
|         void* shared_buffer = current->sys$get_shared_buffer(shared_buffer_id); |  | ||||||
| #else |  | ||||||
|         void* shared_buffer = get_shared_buffer(shared_buffer_id); |         void* shared_buffer = get_shared_buffer(shared_buffer_id); | ||||||
| #endif |  | ||||||
|         if (!shared_buffer || shared_buffer == (void*)-1) |         if (!shared_buffer || shared_buffer == (void*)-1) | ||||||
|             return nullptr; |             return nullptr; | ||||||
|         data = (RGBA32*)shared_buffer; |         data = (RGBA32*)shared_buffer; | ||||||
|  | @ -118,20 +76,11 @@ GraphicsBitmap::GraphicsBitmap(int shared_buffer_id, const Size& size, RGBA32* d | ||||||
| GraphicsBitmap::~GraphicsBitmap() | GraphicsBitmap::~GraphicsBitmap() | ||||||
| { | { | ||||||
|     if (m_mmaped) { |     if (m_mmaped) { | ||||||
| #ifdef KERNEL |  | ||||||
|         int rc = current->sys$munmap(m_data, m_size.area() * 4); |  | ||||||
| #else |  | ||||||
|         int rc = munmap(m_data, m_size.area() * 4); |         int rc = munmap(m_data, m_size.area() * 4); | ||||||
| #endif |  | ||||||
|         ASSERT(rc == 0); |         ASSERT(rc == 0); | ||||||
|     } |     } | ||||||
|     if (m_shared_buffer_id != -1) { |     if (m_shared_buffer_id != -1) { | ||||||
|         int rc; |         int rc = release_shared_buffer(m_shared_buffer_id); | ||||||
| #ifdef KERNEL |  | ||||||
|         rc = current->sys$release_shared_buffer(m_shared_buffer_id); |  | ||||||
| #else |  | ||||||
|         rc = release_shared_buffer(m_shared_buffer_id); |  | ||||||
| #endif |  | ||||||
|         ASSERT(rc == 0); |         ASSERT(rc == 0); | ||||||
|     } |     } | ||||||
|     m_data = nullptr; |     m_data = nullptr; | ||||||
|  |  | ||||||
|  | @ -7,8 +7,6 @@ | ||||||
| #include <AK/RetainPtr.h> | #include <AK/RetainPtr.h> | ||||||
| #include <AK/AKString.h> | #include <AK/AKString.h> | ||||||
| 
 | 
 | ||||||
| class Region; |  | ||||||
| 
 |  | ||||||
| class GraphicsBitmap : public Retainable<GraphicsBitmap> { | class GraphicsBitmap : public Retainable<GraphicsBitmap> { | ||||||
| public: | public: | ||||||
|     static RetainPtr<GraphicsBitmap> create(const Size&); |     static RetainPtr<GraphicsBitmap> create(const Size&); | ||||||
|  | @ -25,17 +23,10 @@ public: | ||||||
|     int width() const { return m_size.width(); } |     int width() const { return m_size.width(); } | ||||||
|     int height() const { return m_size.height(); } |     int height() const { return m_size.height(); } | ||||||
|     size_t pitch() const { return m_pitch; } |     size_t pitch() const { return m_pitch; } | ||||||
| 
 |  | ||||||
| #ifdef KERNEL |  | ||||||
|     Region* server_region() { return m_server_region; } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     int shared_buffer_id() const { return m_shared_buffer_id; } |     int shared_buffer_id() const { return m_shared_buffer_id; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| #ifdef KERNEL |  | ||||||
|     GraphicsBitmap(const Size&); |     GraphicsBitmap(const Size&); | ||||||
| #endif |  | ||||||
|     GraphicsBitmap(const Size&, RGBA32*); |     GraphicsBitmap(const Size&, RGBA32*); | ||||||
|     GraphicsBitmap(int shared_buffer_id, const Size&, RGBA32*); |     GraphicsBitmap(int shared_buffer_id, const Size&, RGBA32*); | ||||||
| 
 | 
 | ||||||
|  | @ -44,10 +35,6 @@ private: | ||||||
|     size_t m_pitch { 0 }; |     size_t m_pitch { 0 }; | ||||||
|     bool m_mmaped { false }; |     bool m_mmaped { false }; | ||||||
|     int m_shared_buffer_id { -1 }; |     int m_shared_buffer_id { -1 }; | ||||||
| 
 |  | ||||||
| #ifdef KERNEL |  | ||||||
|     Region* m_server_region { nullptr }; |  | ||||||
| #endif |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| inline RGBA32* GraphicsBitmap::scanline(int y) | inline RGBA32* GraphicsBitmap::scanline(int y) | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| #include <AK/Assertions.h> | #include <AK/Assertions.h> | ||||||
| #include <AK/StdLibExtras.h> | #include <AK/StdLibExtras.h> | ||||||
| 
 | 
 | ||||||
| #ifdef USERLAND | #ifdef LIBGUI | ||||||
| #include <LibGUI/GWidget.h> | #include <LibGUI/GWidget.h> | ||||||
| #include <LibGUI/GWindow.h> | #include <LibGUI/GWindow.h> | ||||||
| #include <LibGUI/GEventLoop.h> | #include <LibGUI/GEventLoop.h> | ||||||
|  | @ -22,7 +22,7 @@ Painter::Painter(GraphicsBitmap& bitmap) | ||||||
|     m_clip_rect = { { 0, 0 }, bitmap.size() }; |     m_clip_rect = { { 0, 0 }, bitmap.size() }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef USERLAND | #ifdef LIBGUI | ||||||
| Painter::Painter(GWidget& widget) | Painter::Painter(GWidget& widget) | ||||||
|     : m_font(&widget.font()) |     : m_font(&widget.font()) | ||||||
| { | { | ||||||
|  | @ -30,7 +30,6 @@ Painter::Painter(GWidget& widget) | ||||||
|     request.type = WSAPI_ClientMessage::Type::GetWindowBackingStore; |     request.type = WSAPI_ClientMessage::Type::GetWindowBackingStore; | ||||||
|     request.window_id = widget.window()->window_id(); |     request.window_id = widget.window()->window_id(); | ||||||
|     auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::DidGetWindowBackingStore); |     auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::DidGetWindowBackingStore); | ||||||
|     m_backing_store_id = response.backing.backing_store_id; |  | ||||||
| 
 | 
 | ||||||
|     m_target = GraphicsBitmap::create_with_shared_buffer(response.backing.shared_buffer_id, response.backing.size); |     m_target = GraphicsBitmap::create_with_shared_buffer(response.backing.shared_buffer_id, response.backing.size); | ||||||
|     ASSERT(m_target); |     ASSERT(m_target); | ||||||
|  | @ -50,15 +49,7 @@ Painter::Painter(GWidget& widget) | ||||||
| 
 | 
 | ||||||
| Painter::~Painter() | Painter::~Painter() | ||||||
| { | { | ||||||
| #ifdef USERLAND |  | ||||||
|     m_target = nullptr; |     m_target = nullptr; | ||||||
|     if (m_backing_store_id) { |  | ||||||
|         WSAPI_ClientMessage request; |  | ||||||
|         request.type = WSAPI_ClientMessage::Type::ReleaseWindowBackingStore; |  | ||||||
|         request.backing.backing_store_id = m_backing_store_id; |  | ||||||
|         GEventLoop::main().post_message_to_server(request); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Painter::fill_rect_with_draw_op(const Rect& a_rect, Color color) | void Painter::fill_rect_with_draw_op(const Rect& a_rect, Color color) | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ class GlyphBitmap; | ||||||
| class GraphicsBitmap; | class GraphicsBitmap; | ||||||
| class Font; | class Font; | ||||||
| 
 | 
 | ||||||
| #ifndef KERNEL | #ifdef USERLAND | ||||||
| class GWidget; | class GWidget; | ||||||
| class GWindow; | class GWindow; | ||||||
| #endif | #endif | ||||||
|  | @ -20,7 +20,7 @@ enum class TextAlignment { TopLeft, CenterLeft, Center, CenterRight }; | ||||||
| 
 | 
 | ||||||
| class Painter { | class Painter { | ||||||
| public: | public: | ||||||
| #ifndef KERNEL | #ifdef USERLAND | ||||||
|     explicit Painter(GWidget&); |     explicit Painter(GWidget&); | ||||||
| #endif | #endif | ||||||
|     explicit Painter(GraphicsBitmap&); |     explicit Painter(GraphicsBitmap&); | ||||||
|  | @ -63,9 +63,8 @@ private: | ||||||
|     Point m_translation; |     Point m_translation; | ||||||
|     Rect m_clip_rect; |     Rect m_clip_rect; | ||||||
|     RetainPtr<GraphicsBitmap> m_target; |     RetainPtr<GraphicsBitmap> m_target; | ||||||
| #ifndef KERNEL | #ifdef LIBGUI | ||||||
|     GWindow* m_window { nullptr }; |     GWindow* m_window { nullptr }; | ||||||
|     void* m_backing_store_id { nullptr }; |  | ||||||
| #endif | #endif | ||||||
|     DrawOp m_draw_op { DrawOp::Copy }; |     DrawOp m_draw_op { DrawOp::Copy }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								WindowServer/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								WindowServer/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,2 +1,3 @@ | ||||||
| *.o | *.o | ||||||
| *.d | *.d | ||||||
|  | WindowServer | ||||||
|  |  | ||||||
							
								
								
									
										52
									
								
								WindowServer/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								WindowServer/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | SHAREDGRAPHICS_OBJS = \
 | ||||||
|  |     ../SharedGraphics/Painter.o \
 | ||||||
|  |     ../SharedGraphics/Font.o \
 | ||||||
|  |     ../SharedGraphics/Rect.o \
 | ||||||
|  |     ../SharedGraphics/GraphicsBitmap.o \
 | ||||||
|  |     ../SharedGraphics/CharacterBitmap.o \
 | ||||||
|  |     ../SharedGraphics/Color.o | ||||||
|  | 
 | ||||||
|  | WINDOWSERVER_OBJS = \
 | ||||||
|  |     WSMessageReceiver.o \
 | ||||||
|  |     WSMessageLoop.o \
 | ||||||
|  |     WSWindow.o \
 | ||||||
|  |     WSWindowManager.o \
 | ||||||
|  |     WSScreen.o \
 | ||||||
|  |     WSMenuBar.o \
 | ||||||
|  |     WSMenu.o \
 | ||||||
|  |     WSMenuItem.o \
 | ||||||
|  |     WSClientConnection.o \
 | ||||||
|  |     main.o | ||||||
|  | 
 | ||||||
|  | APP = WindowServer | ||||||
|  | OBJS = $(SHAREDGRAPHICS_OBJS) $(WINDOWSERVER_OBJS) | ||||||
|  | 
 | ||||||
|  | ARCH_FLAGS = | ||||||
|  | STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc | ||||||
|  | USERLAND_FLAGS = -ffreestanding -fno-stack-protector -fno-ident | ||||||
|  | WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough | ||||||
|  | FLAVOR_FLAGS = -march=i386 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic | ||||||
|  | OPTIMIZATION_FLAGS = -Oz -fno-asynchronous-unwind-tables | ||||||
|  | INCLUDE_FLAGS = -I.. -I. -I../LibC | ||||||
|  | 
 | ||||||
|  | DEFINES = -DSERENITY -DSANITIZE_PTRS -DUSERLAND | ||||||
|  | 
 | ||||||
|  | CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(USERLAND_FLAGS) $(FLAVOR_FLAGS) $(ARCH_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES) | ||||||
|  | CXX = clang | ||||||
|  | LD = ld | ||||||
|  | AR = ar | ||||||
|  | LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections | ||||||
|  | 
 | ||||||
|  | all: $(APP) | ||||||
|  | 
 | ||||||
|  | $(APP): $(OBJS) | ||||||
|  | 	$(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../LibC/LibC.a | ||||||
|  | 
 | ||||||
|  | .cpp.o: | ||||||
|  | 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< | ||||||
|  | 
 | ||||||
|  | -include $(OBJS:%.o=%.d) | ||||||
|  | 
 | ||||||
|  | clean: | ||||||
|  | 	@echo "CLEAN"; rm -f $(APPS) $(OBJS) *.d | ||||||
|  | 
 | ||||||
|  | @ -34,7 +34,6 @@ struct WSAPI_WindowParameters { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct WSAPI_WindowBackingStoreInfo { | struct WSAPI_WindowBackingStoreInfo { | ||||||
|     void* backing_store_id; |  | ||||||
|     WSAPI_Size size; |     WSAPI_Size size; | ||||||
|     size_t bpp; |     size_t bpp; | ||||||
|     size_t pitch; |     size_t pitch; | ||||||
|  | @ -114,7 +113,6 @@ struct WSAPI_ServerMessage { | ||||||
|             unsigned identifier; |             unsigned identifier; | ||||||
|         } menu; |         } menu; | ||||||
|         struct { |         struct { | ||||||
|             void* backing_store_id; |  | ||||||
|             WSAPI_Size size; |             WSAPI_Size size; | ||||||
|             size_t bpp; |             size_t bpp; | ||||||
|             size_t pitch; |             size_t pitch; | ||||||
|  | @ -143,7 +141,6 @@ struct WSAPI_ClientMessage { | ||||||
|         InvalidateRect, |         InvalidateRect, | ||||||
|         DidFinishPainting, |         DidFinishPainting, | ||||||
|         GetWindowBackingStore, |         GetWindowBackingStore, | ||||||
|         ReleaseWindowBackingStore, |  | ||||||
|         SetGlobalCursorTracking, |         SetGlobalCursorTracking, | ||||||
|     }; |     }; | ||||||
|     Type type { Invalid }; |     Type type { Invalid }; | ||||||
|  | @ -161,9 +158,6 @@ struct WSAPI_ClientMessage { | ||||||
|         struct { |         struct { | ||||||
|             WSAPI_Rect rect; |             WSAPI_Rect rect; | ||||||
|         } window; |         } window; | ||||||
|         struct { |  | ||||||
|             void* backing_store_id; |  | ||||||
|         } backing; |  | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,16 +6,18 @@ | ||||||
| #include <WindowServer/WSWindow.h> | #include <WindowServer/WSWindow.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSAPITypes.h> | #include <WindowServer/WSAPITypes.h> | ||||||
| #include <Kernel/Process.h> | #include <sys/ioctl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| Lockable<HashMap<int, WSClientConnection*>>* s_connections; | HashMap<int, WSClientConnection*>* s_connections; | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback) | void WSClientConnection::for_each_client(Function<void(WSClientConnection&)> callback) | ||||||
| { | { | ||||||
|     if (!s_connections) |     if (!s_connections) | ||||||
|         return; |         return; | ||||||
|     LOCKER(s_connections->lock()); |     for (auto& it : *s_connections) { | ||||||
|     for (auto& it : s_connections->resource()) { |  | ||||||
|         callback(*it.value); |         callback(*it.value); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -24,36 +26,29 @@ WSClientConnection* WSClientConnection::from_client_id(int client_id) | ||||||
| { | { | ||||||
|     if (!s_connections) |     if (!s_connections) | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     LOCKER(s_connections->lock()); |     auto it = s_connections->find(client_id); | ||||||
|     auto it = s_connections->resource().find(client_id); |     if (it == s_connections->end()) | ||||||
|     if (it == s_connections->resource().end()) |  | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     return (*it).value; |     return (*it).value; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WSClientConnection* WSClientConnection::ensure_for_client_id(int client_id) |  | ||||||
| { |  | ||||||
|     if (auto* client = from_client_id(client_id)) |  | ||||||
|         return client; |  | ||||||
|     return new WSClientConnection(client_id); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| WSClientConnection::WSClientConnection(int fd) | WSClientConnection::WSClientConnection(int fd) | ||||||
|     : m_fd(fd) |     : m_fd(fd) | ||||||
| { | { | ||||||
|     int rc = current->sys$ioctl(m_fd, 413, (int)&m_pid); |     static int s_next_client_id = 0; | ||||||
|  |     m_client_id = ++s_next_client_id; | ||||||
|  | 
 | ||||||
|  |     int rc = ioctl(m_fd, 413, (int)&m_pid); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
| 
 | 
 | ||||||
|     if (!s_connections) |     if (!s_connections) | ||||||
|         s_connections = new Lockable<HashMap<int, WSClientConnection*>>; |         s_connections = new HashMap<int, WSClientConnection*>; | ||||||
|     LOCKER(s_connections->lock()); |     s_connections->set(m_client_id, this); | ||||||
|     s_connections->resource().set(m_client_id, this); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WSClientConnection::~WSClientConnection() | WSClientConnection::~WSClientConnection() | ||||||
| { | { | ||||||
|     LOCKER(s_connections->lock()); |     s_connections->remove(m_client_id); | ||||||
|     s_connections->resource().remove(m_client_id); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::post_error(const String& error_message) | void WSClientConnection::post_error(const String& error_message) | ||||||
|  | @ -69,14 +64,23 @@ void WSClientConnection::post_error(const String& error_message) | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::post_message(const WSAPI_ServerMessage& message) | void WSClientConnection::post_message(const WSAPI_ServerMessage& message) | ||||||
| { | { | ||||||
|     int nwritten = WSMessageLoop::the().server_process().sys$write(m_fd, &message, sizeof(message)); |     int nwritten = write(m_fd, &message, sizeof(message)); | ||||||
|  |     if (nwritten < 0) { | ||||||
|  |         if (errno == EPIPE) { | ||||||
|  |             dbgprintf("WSClientConnection::post_message: Disconnected from peer.\n"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         perror("WSClientConnection::post_message write"); | ||||||
|  |         ASSERT_NOT_REACHED(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ASSERT(nwritten == sizeof(message)); |     ASSERT(nwritten == sizeof(message)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| RetainPtr<GraphicsBitmap> WSClientConnection::create_bitmap(const Size& size) | RetainPtr<GraphicsBitmap> WSClientConnection::create_shared_bitmap(const Size& size) | ||||||
| { | { | ||||||
|     RGBA32* buffer; |     RGBA32* buffer; | ||||||
|     int shared_buffer_id = current->sys$create_shared_buffer(m_pid, size.area() * sizeof(RGBA32), (void**)&buffer); |     int shared_buffer_id = create_shared_buffer(m_pid, size.area() * sizeof(RGBA32), (void**)&buffer); | ||||||
|     ASSERT(shared_buffer_id >= 0); |     ASSERT(shared_buffer_id >= 0); | ||||||
|     ASSERT(buffer); |     ASSERT(buffer); | ||||||
|     ASSERT(buffer != (void*)-1); |     ASSERT(buffer != (void*)-1); | ||||||
|  | @ -352,13 +356,9 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque | ||||||
|     auto& window = *(*it).value; |     auto& window = *(*it).value; | ||||||
|     auto* backing_store = window.backing(); |     auto* backing_store = window.backing(); | ||||||
| 
 | 
 | ||||||
|     // FIXME: It shouldn't work this way!
 |  | ||||||
|     backing_store->retain(); |  | ||||||
| 
 |  | ||||||
|     WSAPI_ServerMessage response; |     WSAPI_ServerMessage response; | ||||||
|     response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore; |     response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore; | ||||||
|     response.window_id = window_id; |     response.window_id = window_id; | ||||||
|     response.backing.backing_store_id = backing_store; |  | ||||||
|     response.backing.bpp = sizeof(RGBA32); |     response.backing.bpp = sizeof(RGBA32); | ||||||
|     response.backing.pitch = backing_store->pitch(); |     response.backing.pitch = backing_store->pitch(); | ||||||
|     response.backing.size = backing_store->size(); |     response.backing.size = backing_store->size(); | ||||||
|  | @ -366,14 +366,6 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque | ||||||
|     WSMessageLoop::the().post_message_to_client(request.client_id(), response); |     WSMessageLoop::the().post_message_to_client(request.client_id(), response); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::handle_request(WSAPIReleaseWindowBackingStoreRequest& request) |  | ||||||
| { |  | ||||||
|     int backing_store_id = request.backing_store_id(); |  | ||||||
|     // FIXME: It shouldn't work this way!
 |  | ||||||
|     auto* backing_store = (GraphicsBitmap*)backing_store_id; |  | ||||||
|     backing_store->release(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request) | void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request) | ||||||
| { | { | ||||||
|     int window_id = request.window_id(); |     int window_id = request.window_id(); | ||||||
|  | @ -423,8 +415,6 @@ void WSClientConnection::on_request(WSAPIClientRequest& request) | ||||||
|         return handle_request(static_cast<WSAPIDidFinishPaintingNotification&>(request)); |         return handle_request(static_cast<WSAPIDidFinishPaintingNotification&>(request)); | ||||||
|     case WSMessage::APIGetWindowBackingStoreRequest: |     case WSMessage::APIGetWindowBackingStoreRequest: | ||||||
|         return handle_request(static_cast<WSAPIGetWindowBackingStoreRequest&>(request)); |         return handle_request(static_cast<WSAPIGetWindowBackingStoreRequest&>(request)); | ||||||
|     case WSMessage::APIReleaseWindowBackingStoreRequest: |  | ||||||
|         return handle_request(static_cast<WSAPIReleaseWindowBackingStoreRequest&>(request)); |  | ||||||
|     case WSMessage::APISetGlobalCursorTrackingRequest: |     case WSMessage::APISetGlobalCursorTrackingRequest: | ||||||
|         return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request)); |         return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request)); | ||||||
|     default: |     default: | ||||||
|  |  | ||||||
|  | @ -19,11 +19,10 @@ public: | ||||||
|     virtual ~WSClientConnection() override; |     virtual ~WSClientConnection() override; | ||||||
| 
 | 
 | ||||||
|     static WSClientConnection* from_client_id(int client_id); |     static WSClientConnection* from_client_id(int client_id); | ||||||
|     static WSClientConnection* ensure_for_client_id(int client_id); |  | ||||||
|     static void for_each_client(Function<void(WSClientConnection&)>); |     static void for_each_client(Function<void(WSClientConnection&)>); | ||||||
| 
 | 
 | ||||||
|     void post_message(const WSAPI_ServerMessage&); |     void post_message(const WSAPI_ServerMessage&); | ||||||
|     RetainPtr<GraphicsBitmap> create_bitmap(const Size&); |     RetainPtr<GraphicsBitmap> create_shared_bitmap(const Size&); | ||||||
| 
 | 
 | ||||||
|     int client_id() const { return m_client_id; } |     int client_id() const { return m_client_id; } | ||||||
|     WSMenuBar* app_menubar() { return m_app_menubar.ptr(); } |     WSMenuBar* app_menubar() { return m_app_menubar.ptr(); } | ||||||
|  | @ -52,7 +51,6 @@ private: | ||||||
|     void handle_request(WSAPIInvalidateRectRequest&); |     void handle_request(WSAPIInvalidateRectRequest&); | ||||||
|     void handle_request(WSAPIDidFinishPaintingNotification&); |     void handle_request(WSAPIDidFinishPaintingNotification&); | ||||||
|     void handle_request(WSAPIGetWindowBackingStoreRequest&); |     void handle_request(WSAPIGetWindowBackingStoreRequest&); | ||||||
|     void handle_request(WSAPIReleaseWindowBackingStoreRequest&); |  | ||||||
|     void handle_request(WSAPISetGlobalCursorTrackingRequest&); |     void handle_request(WSAPISetGlobalCursorTrackingRequest&); | ||||||
| 
 | 
 | ||||||
|     void post_error(const String&); |     void post_error(const String&); | ||||||
|  |  | ||||||
|  | @ -38,7 +38,6 @@ public: | ||||||
|         APIInvalidateRectRequest, |         APIInvalidateRectRequest, | ||||||
|         APIDidFinishPaintingNotification, |         APIDidFinishPaintingNotification, | ||||||
|         APIGetWindowBackingStoreRequest, |         APIGetWindowBackingStoreRequest, | ||||||
|         APIReleaseWindowBackingStoreRequest, |  | ||||||
|         APISetGlobalCursorTrackingRequest, |         APISetGlobalCursorTrackingRequest, | ||||||
|         __End_API_Client_Requests, |         __End_API_Client_Requests, | ||||||
|     }; |     }; | ||||||
|  | @ -353,20 +352,6 @@ private: | ||||||
|     int m_window_id { 0 }; |     int m_window_id { 0 }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class WSAPIReleaseWindowBackingStoreRequest final : public WSAPIClientRequest { |  | ||||||
| public: |  | ||||||
|     explicit WSAPIReleaseWindowBackingStoreRequest(int client_id, int backing_store_id) |  | ||||||
|         : WSAPIClientRequest(WSMessage::APIReleaseWindowBackingStoreRequest, client_id) |  | ||||||
|         , m_backing_store_id(backing_store_id) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     int backing_store_id() const { return m_backing_store_id; } |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     int m_backing_store_id { 0 }; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class WSAPIDidFinishPaintingNotification final : public WSAPIClientRequest { | class WSAPIDidFinishPaintingNotification final : public WSAPIClientRequest { | ||||||
| public: | public: | ||||||
|     explicit WSAPIDidFinishPaintingNotification(int client_id, int window_id, const Rect& rect) |     explicit WSAPIDidFinishPaintingNotification(int client_id, int window_id, const Rect& rect) | ||||||
|  |  | ||||||
|  | @ -4,18 +4,21 @@ | ||||||
| #include "WSWindowManager.h" | #include "WSWindowManager.h" | ||||||
| #include "WSScreen.h" | #include "WSScreen.h" | ||||||
| #include <WindowServer/WSClientConnection.h> | #include <WindowServer/WSClientConnection.h> | ||||||
| #include "PS2MouseDevice.h" | #include <Kernel/KeyCode.h> | ||||||
| #include <Kernel/Keyboard.h> |  | ||||||
| #include <WindowServer/WSAPITypes.h> | #include <WindowServer/WSAPITypes.h> | ||||||
| #include <AK/Bitmap.h> | #include <unistd.h> | ||||||
| #include "Process.h" | #include <time.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <sys/select.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <errno.h> | ||||||
| 
 | 
 | ||||||
| //#define WSEVENTLOOP_DEBUG
 | //#define WSEVENTLOOP_DEBUG
 | ||||||
| 
 | 
 | ||||||
| static WSMessageLoop* s_the; | static WSMessageLoop* s_the; | ||||||
| 
 | 
 | ||||||
| WSMessageLoop::WSMessageLoop() | WSMessageLoop::WSMessageLoop() | ||||||
|     : m_lock("WSMessageLoop") |  | ||||||
| { | { | ||||||
|     if (!s_the) |     if (!s_the) | ||||||
|         s_the = this; |         s_the = this; | ||||||
|  | @ -33,21 +36,19 @@ WSMessageLoop& WSMessageLoop::the() | ||||||
| 
 | 
 | ||||||
| int WSMessageLoop::exec() | int WSMessageLoop::exec() | ||||||
| { | { | ||||||
|     ASSERT(m_server_process == current); |     m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC); | ||||||
|  |     m_mouse_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK | O_CLOEXEC); | ||||||
| 
 | 
 | ||||||
|     m_keyboard_fd = m_server_process->sys$open("/dev/keyboard", O_RDONLY); |     unlink("/wsportal"); | ||||||
|     m_mouse_fd = m_server_process->sys$open("/dev/psaux", O_RDONLY); |  | ||||||
| 
 | 
 | ||||||
|     m_server_process->sys$unlink("/wsportal"); |     m_server_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | ||||||
| 
 |  | ||||||
|     m_server_fd = m_server_process->sys$socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0); |  | ||||||
|     ASSERT(m_server_fd >= 0); |     ASSERT(m_server_fd >= 0); | ||||||
|     sockaddr_un address; |     sockaddr_un address; | ||||||
|     address.sun_family = AF_LOCAL; |     address.sun_family = AF_LOCAL; | ||||||
|     strcpy(address.sun_path, "/wsportal"); |     strcpy(address.sun_path, "/wsportal"); | ||||||
|     int rc = m_server_process->sys$bind(m_server_fd, (const sockaddr*)&address, sizeof(address)); |     int rc = bind(m_server_fd, (const sockaddr*)&address, sizeof(address)); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
|     rc = m_server_process->sys$listen(m_server_fd, 5); |     rc = listen(m_server_fd, 5); | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
| 
 | 
 | ||||||
|     ASSERT(m_keyboard_fd >= 0); |     ASSERT(m_keyboard_fd >= 0); | ||||||
|  | @ -56,13 +57,7 @@ int WSMessageLoop::exec() | ||||||
|     m_running = true; |     m_running = true; | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         wait_for_message(); |         wait_for_message(); | ||||||
| 
 |         Vector<QueuedMessage> messages = move(m_queued_messages); | ||||||
|         Vector<QueuedMessage> messages; |  | ||||||
|         { |  | ||||||
|             ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|             LOCKER(m_lock); |  | ||||||
|             messages = move(m_queued_messages); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         for (auto& queued_message : messages) { |         for (auto& queued_message : messages) { | ||||||
|             auto* receiver = queued_message.receiver; |             auto* receiver = queued_message.receiver; | ||||||
|  | @ -81,12 +76,6 @@ int WSMessageLoop::exec() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Process* WSMessageLoop::process_from_client_id(int client_id) |  | ||||||
| { |  | ||||||
|     // FIXME: This shouldn't work this way lol.
 |  | ||||||
|     return (Process*)client_id; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSMessageLoop::post_message_to_client(int client_id, const WSAPI_ServerMessage& message) | void WSMessageLoop::post_message_to_client(int client_id, const WSAPI_ServerMessage& message) | ||||||
| { | { | ||||||
|     auto* client = WSClientConnection::from_client_id(client_id); |     auto* client = WSClientConnection::from_client_id(client_id); | ||||||
|  | @ -97,53 +86,16 @@ void WSMessageLoop::post_message_to_client(int client_id, const WSAPI_ServerMess | ||||||
| 
 | 
 | ||||||
| void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&& message) | void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&& message) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
| #ifdef WSEVENTLOOP_DEBUG | #ifdef WSEVENTLOOP_DEBUG | ||||||
|     dbgprintf("WSMessageLoop::post_message: {%u} << receiver=%p, message=%p (type=%u)\n", m_queued_messages.size(), receiver, message.ptr(), message->type()); |     dbgprintf("WSMessageLoop::post_message: {%u} << receiver=%p, message=%p (type=%u)\n", m_queued_messages.size(), receiver, message.ptr(), message->type()); | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| #if 0 |  | ||||||
|     if (message->type() == WSMessage::WM_ClientFinishedPaint) { |  | ||||||
|         auto& invalidation_message = static_cast<WSClientFinishedPaintMessage&>(*message); |  | ||||||
|         for (auto& queued_message : m_queued_messages) { |  | ||||||
|             if (receiver == queued_message.receiver && queued_message.message->type() == WSMessage::WM_ClientFinishedPaint) { |  | ||||||
|                 auto& queued_invalidation_message = static_cast<WSClientFinishedPaintMessage&>(*queued_message.message); |  | ||||||
|                 if (queued_invalidation_message.rect().is_empty() || queued_invalidation_message.rect().contains(invalidation_message.rect())) { |  | ||||||
| #ifdef WSEVENTLOOP_DEBUG |  | ||||||
|                     dbgprintf("Swallow WM_ClientFinishedPaint\n"); |  | ||||||
| #endif |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (message->type() == WSMessage::WM_ClientWantsToPaint) { |  | ||||||
|         auto& invalidation_message = static_cast<WSClientWantsToPaintMessage&>(*message); |  | ||||||
|         for (auto& queued_message : m_queued_messages) { |  | ||||||
|             if (receiver == queued_message.receiver && queued_message.message->type() == WSMessage::WM_ClientWantsToPaint) { |  | ||||||
|                 auto& queued_invalidation_message = static_cast<WSClientWantsToPaintMessage&>(*queued_message.message); |  | ||||||
|                 if (queued_invalidation_message.rect().is_empty() || queued_invalidation_message.rect().contains(invalidation_message.rect())) { |  | ||||||
| #ifdef WSEVENTLOOP_DEBUG |  | ||||||
|                     dbgprintf("Swallow WM_ClientWantsToPaint\n"); |  | ||||||
| #endif |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     m_queued_messages.append({ receiver, move(message) }); |     m_queued_messages.append({ receiver, move(message) }); | ||||||
| 
 |  | ||||||
|     if (current != m_server_process) |  | ||||||
|         m_server_process->request_wakeup(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSMessageLoop::Timer::reload() | void WSMessageLoop::Timer::reload() | ||||||
| { | { | ||||||
|     struct timeval now; |     struct timeval now; | ||||||
|     current->sys$gettimeofday(&now); |     gettimeofday(&now, nullptr); | ||||||
|     next_fire_time = { |     next_fire_time = { | ||||||
|         now.tv_sec + (interval / 1000), |         now.tv_sec + (interval / 1000), | ||||||
|         now.tv_usec + (interval % 1000) |         now.tv_usec + (interval % 1000) | ||||||
|  | @ -174,28 +126,22 @@ int WSMessageLoop::stop_timer(int timer_id) | ||||||
| void WSMessageLoop::wait_for_message() | void WSMessageLoop::wait_for_message() | ||||||
| { | { | ||||||
|     fd_set rfds; |     fd_set rfds; | ||||||
|     memset(&rfds, 0, sizeof(rfds)); |     FD_ZERO(&rfds); | ||||||
|     auto bitmap = Bitmap::wrap((byte*)&rfds, FD_SETSIZE); |  | ||||||
|     int max_fd = 0; |     int max_fd = 0; | ||||||
|     auto add_fd_to_set = [&max_fd] (int fd, auto& bitmap) { |     auto add_fd_to_set = [&max_fd] (int fd, auto& set) { | ||||||
|         bitmap.set(fd, true); |         FD_SET(fd, &set); | ||||||
|         if (fd > max_fd) |         if (fd > max_fd) | ||||||
|             max_fd = fd; |             max_fd = fd; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     add_fd_to_set(m_keyboard_fd, bitmap); |     add_fd_to_set(m_keyboard_fd, rfds); | ||||||
|     add_fd_to_set(m_mouse_fd, bitmap); |     add_fd_to_set(m_mouse_fd, rfds); | ||||||
|     add_fd_to_set(m_server_fd, bitmap); |     add_fd_to_set(m_server_fd, rfds); | ||||||
| 
 | 
 | ||||||
|     WSClientConnection::for_each_client([&] (WSClientConnection& client) { |     WSClientConnection::for_each_client([&] (WSClientConnection& client) { | ||||||
|         add_fd_to_set(client.fd(), bitmap); |         add_fd_to_set(client.fd(), rfds); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     Syscall::SC_select_params params; |  | ||||||
|     params.nfds = max_fd + 1; |  | ||||||
|     params.readfds = &rfds; |  | ||||||
|     params.writefds = nullptr; |  | ||||||
|     params.exceptfds = nullptr; |  | ||||||
|     struct timeval timeout = { 0, 0 }; |     struct timeval timeout = { 0, 0 }; | ||||||
|     bool had_any_timer = false; |     bool had_any_timer = false; | ||||||
| 
 | 
 | ||||||
|  | @ -210,19 +156,13 @@ void WSMessageLoop::wait_for_message() | ||||||
|             timeout = timer.next_fire_time; |             timeout = timer.next_fire_time; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (m_timers.is_empty() && m_queued_messages.is_empty()) |     int rc = select(max_fd + 1, &rfds, nullptr, nullptr, m_timers.is_empty() && m_queued_messages.is_empty() ? nullptr : &timeout); | ||||||
|         params.timeout = nullptr; |  | ||||||
|     else |  | ||||||
|         params.timeout = &timeout; |  | ||||||
| 
 |  | ||||||
|     int rc = m_server_process->sys$select(¶ms); |  | ||||||
|     memory_barrier(); |  | ||||||
|     if (rc < 0) { |     if (rc < 0) { | ||||||
|         ASSERT_NOT_REACHED(); |         ASSERT_NOT_REACHED(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     struct timeval now; |     struct timeval now; | ||||||
|     current->sys$gettimeofday(&now); |     gettimeofday(&now, nullptr); | ||||||
|     for (auto& it : m_timers) { |     for (auto& it : m_timers) { | ||||||
|         auto& timer = *it.value; |         auto& timer = *it.value; | ||||||
|         if (now.tv_sec > timer.next_fire_time.tv_sec || (now.tv_sec == timer.next_fire_time.tv_sec && now.tv_usec > timer.next_fire_time.tv_usec)) { |         if (now.tv_sec > timer.next_fire_time.tv_sec || (now.tv_sec == timer.next_fire_time.tv_sec && now.tv_usec > timer.next_fire_time.tv_usec)) { | ||||||
|  | @ -231,30 +171,37 @@ void WSMessageLoop::wait_for_message() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (bitmap.get(m_keyboard_fd)) |     if (FD_ISSET(m_keyboard_fd, &rfds)) | ||||||
|         drain_keyboard(); |         drain_keyboard(); | ||||||
|     if (bitmap.get(m_mouse_fd)) |     if (FD_ISSET(m_mouse_fd, &rfds)) | ||||||
|         drain_mouse(); |         drain_mouse(); | ||||||
|     if (bitmap.get(m_server_fd)) { |     if (FD_ISSET(m_server_fd, &rfds)) { | ||||||
|         sockaddr_un address; |         sockaddr_un address; | ||||||
|         socklen_t address_size = sizeof(address); |         socklen_t address_size = sizeof(address); | ||||||
|         int client_fd = m_server_process->sys$accept(m_server_fd, (sockaddr*)&address, &address_size); |         int client_fd = accept(m_server_fd, (sockaddr*)&address, &address_size); | ||||||
|         kprintf("accept() returned fd=%d, address=%s\n", client_fd, address.sun_path); |         dbgprintf("accept() returned fd=%d, address=%s\n", client_fd, address.sun_path); | ||||||
|  |         ASSERT(client_fd >= 0); | ||||||
|         new WSClientConnection(client_fd); |         new WSClientConnection(client_fd); | ||||||
|     } |     } | ||||||
|     WSClientConnection::for_each_client([&] (WSClientConnection& client) { |     WSClientConnection::for_each_client([&] (WSClientConnection& client) { | ||||||
|         if (bitmap.get(client.fd())) { |         if (!FD_ISSET(client.fd(), &rfds)) | ||||||
|             for (;;) { |             return; | ||||||
|                 WSAPI_ClientMessage message; |         unsigned messages_received = 0; | ||||||
|                 // FIXME: Don't go one message at a time, that's so much context switching, oof.
 |         for (;;) { | ||||||
|                 ssize_t nread = m_server_process->sys$read(client.fd(), &message, sizeof(WSAPI_ClientMessage)); |             WSAPI_ClientMessage message; | ||||||
|                 if (nread == 0) |             // FIXME: Don't go one message at a time, that's so much context switching, oof.
 | ||||||
|                     break; |             ssize_t nread = read(client.fd(), &message, sizeof(WSAPI_ClientMessage)); | ||||||
|                 if (nread < 0) { |             if (nread == 0) { | ||||||
|                     ASSERT_NOT_REACHED(); |                 if (!messages_received) | ||||||
|                 } |                     notify_client_disconnected(client.client_id()); | ||||||
|                 on_receive_from_client(client.client_id(), message); |                 break; | ||||||
|             } |             } | ||||||
|  |             if (nread < 0) { | ||||||
|  |                 perror("read"); | ||||||
|  |                 ASSERT_NOT_REACHED(); | ||||||
|  |             } | ||||||
|  |             on_receive_from_client(client.client_id(), message); | ||||||
|  |             ++messages_received; | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  | @ -262,14 +209,17 @@ void WSMessageLoop::wait_for_message() | ||||||
| void WSMessageLoop::drain_mouse() | void WSMessageLoop::drain_mouse() | ||||||
| { | { | ||||||
|     auto& screen = WSScreen::the(); |     auto& screen = WSScreen::the(); | ||||||
|     auto& mouse = PS2MouseDevice::the(); |  | ||||||
|     bool prev_left_button = screen.left_mouse_button_pressed(); |     bool prev_left_button = screen.left_mouse_button_pressed(); | ||||||
|     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.can_read(*m_server_process)) { |     bool left_button = prev_left_button; | ||||||
|  |     bool right_button = prev_right_button; | ||||||
|  |     for (;;) { | ||||||
|         byte data[3]; |         byte data[3]; | ||||||
|         ssize_t nread = mouse.read(*m_server_process, (byte*)data, sizeof(data)); |         ssize_t nread = read(m_mouse_fd, data, sizeof(data)); | ||||||
|  |         if (nread == 0) | ||||||
|  |             break; | ||||||
|         ASSERT(nread == sizeof(data)); |         ASSERT(nread == sizeof(data)); | ||||||
|         bool left_button = data[0] & 1; |         bool left_button = data[0] & 1; | ||||||
|         bool right_button = data[0] & 2; |         bool right_button = data[0] & 2; | ||||||
|  | @ -290,7 +240,7 @@ void WSMessageLoop::drain_mouse() | ||||||
| 
 | 
 | ||||||
|         dx += x; |         dx += x; | ||||||
|         dy += -y; |         dy += -y; | ||||||
|         if (left_button != prev_left_button || right_button != prev_right_button || !mouse.can_read(*m_server_process)) { |         if (left_button != prev_left_button || right_button != prev_right_button) { | ||||||
|             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); | ||||||
|  | @ -298,23 +248,26 @@ void WSMessageLoop::drain_mouse() | ||||||
|             dy = 0; |             dy = 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     if (dx || dy) { | ||||||
|  |         screen.on_receive_mouse_data(dx, dy, left_button, right_button); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSMessageLoop::drain_keyboard() | void WSMessageLoop::drain_keyboard() | ||||||
| { | { | ||||||
|     auto& screen = WSScreen::the(); |     auto& screen = WSScreen::the(); | ||||||
|     auto& keyboard = Keyboard::the(); |     for (;;) { | ||||||
|     while (keyboard.can_read(*m_server_process)) { |         KeyEvent event; | ||||||
|         Keyboard::Event event; |         ssize_t nread = read(m_keyboard_fd, (byte*)&event, sizeof(KeyEvent)); | ||||||
|         ssize_t nread = keyboard.read(*m_server_process, (byte*)&event, sizeof(Keyboard::Event)); |         if (nread == 0) | ||||||
|         ASSERT(nread == sizeof(Keyboard::Event)); |             break; | ||||||
|  |         ASSERT(nread == sizeof(KeyEvent)); | ||||||
|         screen.on_receive_keyboard_data(event); |         screen.on_receive_keyboard_data(event); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSMessageLoop::notify_client_died(int client_id) | void WSMessageLoop::notify_client_disconnected(int client_id) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto* client = WSClientConnection::from_client_id(client_id); |     auto* client = WSClientConnection::from_client_id(client_id); | ||||||
|     if (!client) |     if (!client) | ||||||
|         return; |         return; | ||||||
|  | @ -323,12 +276,14 @@ void WSMessageLoop::notify_client_died(int client_id) | ||||||
| 
 | 
 | ||||||
| void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessage& message) | void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessage& message) | ||||||
| { | { | ||||||
|  | #if 0 | ||||||
|     // FIXME: This should not be necessary.. why is this necessary?
 |     // FIXME: This should not be necessary.. why is this necessary?
 | ||||||
|     while (!running()) |     while (!running()) | ||||||
|         Scheduler::yield(); |         sched_yield(); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     LOCKER(m_lock); |     WSClientConnection* client = WSClientConnection::from_client_id(client_id); | ||||||
|     WSClientConnection* client = WSClientConnection::ensure_for_client_id(client_id); |     ASSERT(client); | ||||||
|     switch (message.type) { |     switch (message.type) { | ||||||
|     case WSAPI_ClientMessage::Type::CreateMenubar: |     case WSAPI_ClientMessage::Type::CreateMenubar: | ||||||
|         post_message(client, make<WSAPICreateMenubarRequest>(client_id)); |         post_message(client, make<WSAPICreateMenubarRequest>(client_id)); | ||||||
|  | @ -383,9 +338,6 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess | ||||||
|     case WSAPI_ClientMessage::Type::GetWindowBackingStore: |     case WSAPI_ClientMessage::Type::GetWindowBackingStore: | ||||||
|         post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); |         post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); | ||||||
|         break; |         break; | ||||||
|     case WSAPI_ClientMessage::Type::ReleaseWindowBackingStore: |  | ||||||
|         post_message(client, make<WSAPIReleaseWindowBackingStoreRequest>(client_id, (int)message.backing.backing_store_id)); |  | ||||||
|         break; |  | ||||||
|     case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: |     case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: | ||||||
|         post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value)); |         post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value)); | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
|  | @ -1,14 +1,12 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "WSMessage.h" | #include "WSMessage.h" | ||||||
| #include <AK/Lock.h> |  | ||||||
| #include <AK/HashMap.h> | #include <AK/HashMap.h> | ||||||
| #include <AK/OwnPtr.h> | #include <AK/OwnPtr.h> | ||||||
| #include <AK/Vector.h> | #include <AK/Vector.h> | ||||||
| #include <AK/Function.h> | #include <AK/Function.h> | ||||||
| 
 | 
 | ||||||
| class WSMessageReceiver; | class WSMessageReceiver; | ||||||
| class Process; |  | ||||||
| struct WSAPI_ClientMessage; | struct WSAPI_ClientMessage; | ||||||
| struct WSAPI_ServerMessage; | struct WSAPI_ServerMessage; | ||||||
| 
 | 
 | ||||||
|  | @ -24,9 +22,6 @@ public: | ||||||
|     static WSMessageLoop& the(); |     static WSMessageLoop& the(); | ||||||
| 
 | 
 | ||||||
|     bool running() const { return m_running; } |     bool running() const { return m_running; } | ||||||
|     Process& server_process() { return *m_server_process; } |  | ||||||
| 
 |  | ||||||
|     void set_server_process(Process& process) { m_server_process = &process; } |  | ||||||
| 
 | 
 | ||||||
|     int start_timer(int ms, Function<void()>&&); |     int start_timer(int ms, Function<void()>&&); | ||||||
|     int stop_timer(int timer_id); |     int stop_timer(int timer_id); | ||||||
|  | @ -34,23 +29,19 @@ public: | ||||||
|     void post_message_to_client(int client_id, const WSAPI_ServerMessage&); |     void post_message_to_client(int client_id, const WSAPI_ServerMessage&); | ||||||
|     void on_receive_from_client(int client_id, const WSAPI_ClientMessage&); |     void on_receive_from_client(int client_id, const WSAPI_ClientMessage&); | ||||||
| 
 | 
 | ||||||
|     static Process* process_from_client_id(int client_id); |     void notify_client_disconnected(int client_id); | ||||||
|     void notify_client_died(int client_id); |  | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void wait_for_message(); |     void wait_for_message(); | ||||||
|     void drain_mouse(); |     void drain_mouse(); | ||||||
|     void drain_keyboard(); |     void drain_keyboard(); | ||||||
| 
 | 
 | ||||||
|     Lock m_lock; |  | ||||||
| 
 |  | ||||||
|     struct QueuedMessage { |     struct QueuedMessage { | ||||||
|         WSMessageReceiver* receiver { nullptr }; |         WSMessageReceiver* receiver { nullptr }; | ||||||
|         OwnPtr<WSMessage> message; |         OwnPtr<WSMessage> message; | ||||||
|     }; |     }; | ||||||
|     Vector<QueuedMessage> m_queued_messages; |     Vector<QueuedMessage> m_queued_messages; | ||||||
| 
 | 
 | ||||||
|     Process* m_server_process { nullptr }; |  | ||||||
|     bool m_running { false }; |     bool m_running { false }; | ||||||
| 
 | 
 | ||||||
|     int m_keyboard_fd { -1 }; |     int m_keyboard_fd { -1 }; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| #include "WSMessageReceiver.h" | #include "WSMessageReceiver.h" | ||||||
| #include <AK/Assertions.h> |  | ||||||
| 
 | 
 | ||||||
| WSMessageReceiver::WSMessageReceiver() | WSMessageReceiver::WSMessageReceiver() | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| #include "WSMessageLoop.h" | #include "WSMessageLoop.h" | ||||||
| #include "WSMessage.h" | #include "WSMessage.h" | ||||||
| #include "WSWindowManager.h" | #include "WSWindowManager.h" | ||||||
| #include <AK/Assertions.h> |  | ||||||
| 
 | 
 | ||||||
| static WSScreen* s_the; | static WSScreen* s_the; | ||||||
| 
 | 
 | ||||||
|  | @ -61,7 +60,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ | ||||||
|         WSWindowManager::the().invalidate_cursor(); |         WSWindowManager::the().invalidate_cursor(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSScreen::on_receive_keyboard_data(Keyboard::Event kernel_event) | void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event) | ||||||
| { | { | ||||||
|     auto message = make<WSKeyEvent>(kernel_event.is_press() ? WSMessage::KeyDown : WSMessage::KeyUp, kernel_event.key, kernel_event.character); |     auto message = make<WSKeyEvent>(kernel_event.is_press() ? WSMessage::KeyDown : WSMessage::KeyUp, kernel_event.key, kernel_event.character); | ||||||
|     message->m_shift = kernel_event.shift(); |     message->m_shift = kernel_event.shift(); | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| #include <SharedGraphics/Rect.h> | #include <SharedGraphics/Rect.h> | ||||||
| #include <SharedGraphics/Size.h> | #include <SharedGraphics/Size.h> | ||||||
| #include <SharedGraphics/Color.h> | #include <SharedGraphics/Color.h> | ||||||
| #include <Kernel/Keyboard.h> | #include <Kernel/KeyCode.h> | ||||||
| 
 | 
 | ||||||
| class WSScreen { | class WSScreen { | ||||||
| public: | public: | ||||||
|  | @ -26,7 +26,7 @@ public: | ||||||
|     bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; } |     bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; } | ||||||
| 
 | 
 | ||||||
|     void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button); |     void on_receive_mouse_data(int dx, int dy, bool left_button, bool right_button); | ||||||
|     void on_receive_keyboard_data(Keyboard::Event); |     void on_receive_keyboard_data(KeyEvent); | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     WSScreen(unsigned width, unsigned height); |     WSScreen(unsigned width, unsigned height); | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ void WSWindow::set_rect(const Rect& rect) | ||||||
|         if (m_menu) |         if (m_menu) | ||||||
|             m_backing = GraphicsBitmap::create(m_rect.size()); |             m_backing = GraphicsBitmap::create(m_rect.size()); | ||||||
|         else if (client) |         else if (client) | ||||||
|             m_backing = client->create_bitmap(m_rect.size()); |             m_backing = client->create_shared_bitmap(m_rect.size()); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|     WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); |     WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); | ||||||
|  |  | ||||||
|  | @ -2,8 +2,6 @@ | ||||||
| #include "WSWindow.h" | #include "WSWindow.h" | ||||||
| #include "WSScreen.h" | #include "WSScreen.h" | ||||||
| #include "WSMessageLoop.h" | #include "WSMessageLoop.h" | ||||||
| #include "Process.h" |  | ||||||
| #include "MemoryManager.h" |  | ||||||
| #include <SharedGraphics/Font.h> | #include <SharedGraphics/Font.h> | ||||||
| #include <SharedGraphics/Painter.h> | #include <SharedGraphics/Painter.h> | ||||||
| #include <SharedGraphics/CharacterBitmap.h> | #include <SharedGraphics/CharacterBitmap.h> | ||||||
|  | @ -13,6 +11,9 @@ | ||||||
| #include "WSMenuBar.h" | #include "WSMenuBar.h" | ||||||
| #include "WSMenuItem.h" | #include "WSMenuItem.h" | ||||||
| #include <WindowServer/WSClientConnection.h> | #include <WindowServer/WSClientConnection.h> | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #ifdef KERNEL | #ifdef KERNEL | ||||||
| #include <Kernel/ProcFS.h> | #include <Kernel/ProcFS.h> | ||||||
|  | @ -79,8 +80,7 @@ static WSWindowManager* s_the; | ||||||
| 
 | 
 | ||||||
| WSWindowManager& WSWindowManager::the() | WSWindowManager& WSWindowManager::the() | ||||||
| { | { | ||||||
|     if (!s_the) |     ASSERT(s_the); | ||||||
|         s_the = new WSWindowManager; |  | ||||||
|     return *s_the; |     return *s_the; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -130,7 +130,7 @@ void WSWindowManager::flip_buffers() | ||||||
|     swap(m_front_painter, m_back_painter); |     swap(m_front_painter, m_back_painter); | ||||||
|     if (m_framebuffer_fd != -1) { |     if (m_framebuffer_fd != -1) { | ||||||
|         int new_y_offset = m_buffers_are_flipped ? 0 : m_screen_rect.height(); |         int new_y_offset = m_buffers_are_flipped ? 0 : m_screen_rect.height(); | ||||||
|         int rc = current->sys$ioctl(m_framebuffer_fd, 1982, new_y_offset); |         int rc = ioctl(m_framebuffer_fd, 1982, new_y_offset); | ||||||
|         ASSERT(rc == 0); |         ASSERT(rc == 0); | ||||||
|     } |     } | ||||||
|     m_buffers_are_flipped = !m_buffers_are_flipped; |     m_buffers_are_flipped = !m_buffers_are_flipped; | ||||||
|  | @ -139,9 +139,10 @@ void WSWindowManager::flip_buffers() | ||||||
| WSWindowManager::WSWindowManager() | WSWindowManager::WSWindowManager() | ||||||
|     : m_screen(WSScreen::the()) |     : m_screen(WSScreen::the()) | ||||||
|     , m_screen_rect(m_screen.rect()) |     , m_screen_rect(m_screen.rect()) | ||||||
|     , m_lock("WSWindowManager") |  | ||||||
|     , m_flash_flush(false) |     , m_flash_flush(false) | ||||||
| { | { | ||||||
|  |     s_the = this; | ||||||
|  | 
 | ||||||
| #ifndef DEBUG_COUNTERS | #ifndef DEBUG_COUNTERS | ||||||
|     (void)m_compose_count; |     (void)m_compose_count; | ||||||
|     (void)m_flush_count; |     (void)m_flush_count; | ||||||
|  | @ -172,17 +173,13 @@ WSWindowManager::WSWindowManager() | ||||||
|     m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17); |     m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17); | ||||||
|     m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17); |     m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17); | ||||||
| 
 | 
 | ||||||
|     { |     m_wallpaper_path = "/res/wallpapers/cool.rgb"; | ||||||
|         LOCKER(m_wallpaper_path.lock()); |     m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path, m_screen_rect.size()); | ||||||
|         m_wallpaper_path.resource() = "/res/wallpapers/cool.rgb"; |  | ||||||
|         m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path.resource(), m_screen_rect.size()); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
| #ifdef KERNEL | #ifdef KERNEL | ||||||
|     ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush); |     ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush); | ||||||
|     ProcFS::the().add_sys_string("wm_wallpaper", m_wallpaper_path, [this] { |     ProcFS::the().add_sys_string("wm_wallpaper", m_wallpaper_path, [this] { | ||||||
|         LOCKER(m_wallpaper_path.lock()); |         m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path, m_screen_rect.size()); | ||||||
|         m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path.resource(), m_screen_rect.size()); |  | ||||||
|         invalidate(m_screen_rect); |         invalidate(m_screen_rect); | ||||||
|     }); |     }); | ||||||
| #endif | #endif | ||||||
|  | @ -201,25 +198,31 @@ WSWindowManager::WSWindowManager() | ||||||
|         m_system_menu->add_item(make<WSMenuItem>(4, "About...")); |         m_system_menu->add_item(make<WSMenuItem>(4, "About...")); | ||||||
|         m_system_menu->on_item_activation = [] (WSMenuItem& item) { |         m_system_menu->on_item_activation = [] (WSMenuItem& item) { | ||||||
|             if (item.identifier() == 0) { |             if (item.identifier() == 0) { | ||||||
|                 int error; |                 if (fork() == 0) { | ||||||
|                 Process::create_user_process("/bin/Terminal", 100, 100, 0, error); |                     execl("/bin/Terminal", "/bin/Terminal", nullptr); | ||||||
|  |                     ASSERT_NOT_REACHED(); | ||||||
|  |                 } | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (item.identifier() == 4) { |             if (item.identifier() == 4) { | ||||||
|                 int error; |                 if (fork() == 0) { | ||||||
|                 Process::create_user_process("/bin/About", 100, 100, 0, error); |                     execl("/bin/About", "/bin/About", nullptr); | ||||||
|  |                     ASSERT_NOT_REACHED(); | ||||||
|  |                 } | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             kprintf("WSMenu 1 item activated: '%s'\n", item.text().characters()); |             dbgprintf("WSMenu 1 item activated: '%s'\n", item.text().characters()); | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // NOTE: This ensures that the system menu has the correct dimensions.
 |     // NOTE: This ensures that the system menu has the correct dimensions.
 | ||||||
|     set_current_menubar(nullptr); |     set_current_menubar(nullptr); | ||||||
| 
 | 
 | ||||||
|  | #if 0 | ||||||
|     WSMessageLoop::the().start_timer(300, [this] { |     WSMessageLoop::the().start_timer(300, [this] { | ||||||
|         invalidate(menubar_rect()); |         invalidate(menubar_rect()); | ||||||
|     }); |     }); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     invalidate(); |     invalidate(); | ||||||
|     compose(); |     compose(); | ||||||
|  | @ -244,7 +247,6 @@ int WSWindowManager::menubar_menu_margin() const | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::set_current_menubar(WSMenuBar* menubar) | void WSWindowManager::set_current_menubar(WSMenuBar* menubar) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (menubar) |     if (menubar) | ||||||
|         m_current_menubar = menubar->make_weak_ptr(); |         m_current_menubar = menubar->make_weak_ptr(); | ||||||
|     else |     else | ||||||
|  | @ -279,7 +281,6 @@ static const int s_close_button_bitmap_height = 9; | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::paint_window_frame(WSWindow& window) | void WSWindowManager::paint_window_frame(WSWindow& window) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     //printf("[WM] paint_window_frame {%p}, rect: %d,%d %dx%d\n", &window, window.rect().x(), window.rect().y(), window.rect().width(), window.rect().height());
 |     //printf("[WM] paint_window_frame {%p}, rect: %d,%d %dx%d\n", &window, window.rect().x(), window.rect().y(), window.rect().width(), window.rect().height());
 | ||||||
| 
 | 
 | ||||||
|     if (window.type() == WSWindowType::Menu) { |     if (window.type() == WSWindowType::Menu) { | ||||||
|  | @ -357,7 +358,6 @@ void WSWindowManager::paint_window_frame(WSWindow& window) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::add_window(WSWindow& window) | void WSWindowManager::add_window(WSWindow& window) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     m_windows.set(&window); |     m_windows.set(&window); | ||||||
|     m_windows_in_order.append(&window); |     m_windows_in_order.append(&window); | ||||||
|     if (!active_window()) |     if (!active_window()) | ||||||
|  | @ -366,7 +366,6 @@ void WSWindowManager::add_window(WSWindow& window) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::move_to_front(WSWindow& window) | void WSWindowManager::move_to_front(WSWindow& window) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (m_windows_in_order.tail() != &window) |     if (m_windows_in_order.tail() != &window) | ||||||
|         invalidate(window); |         invalidate(window); | ||||||
|     m_windows_in_order.remove(&window); |     m_windows_in_order.remove(&window); | ||||||
|  | @ -375,7 +374,6 @@ void WSWindowManager::move_to_front(WSWindow& window) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::remove_window(WSWindow& window) | void WSWindowManager::remove_window(WSWindow& window) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (!m_windows.contains(&window)) |     if (!m_windows.contains(&window)) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|  | @ -395,7 +393,6 @@ void WSWindowManager::notify_title_changed(WSWindow& window) | ||||||
| void WSWindowManager::notify_rect_changed(WSWindow& window, const Rect& old_rect, const Rect& new_rect) | void WSWindowManager::notify_rect_changed(WSWindow& window, const Rect& old_rect, const Rect& new_rect) | ||||||
| { | { | ||||||
|     printf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height()); |     printf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height()); | ||||||
|     ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|     invalidate(outer_window_rect(old_rect)); |     invalidate(outer_window_rect(old_rect)); | ||||||
|     invalidate(outer_window_rect(new_rect)); |     invalidate(outer_window_rect(new_rect)); | ||||||
| } | } | ||||||
|  | @ -469,7 +466,6 @@ void WSWindowManager::handle_close_button_mouse_event(WSWindow& window, WSMouseE | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::process_mouse_event(WSMouseEvent& event) | void WSWindowManager::process_mouse_event(WSMouseEvent& event) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (event.type() == WSMessage::MouseUp && event.button() == MouseButton::Left) { |     if (event.type() == WSMessage::MouseUp && event.button() == MouseButton::Left) { | ||||||
|         if (m_drag_window) { |         if (m_drag_window) { | ||||||
| #ifdef DRAG_DEBUG | #ifdef DRAG_DEBUG | ||||||
|  | @ -597,14 +593,12 @@ IterationDecision WSWindowManager::for_each_visible_window_from_front_to_back(Ca | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::compose() | void WSWindowManager::compose() | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto dirty_rects = move(m_dirty_rects); |     auto dirty_rects = move(m_dirty_rects); | ||||||
|     auto cursor_location = m_screen.cursor_location(); |     auto cursor_location = m_screen.cursor_location(); | ||||||
|     dirty_rects.append(m_last_cursor_rect); |     dirty_rects.append(m_last_cursor_rect); | ||||||
|     dirty_rects.append({ cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }); |     dirty_rects.append({ cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }); | ||||||
| #ifdef DEBUG_COUNTERS | #ifdef DEBUG_COUNTERS | ||||||
|     dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.size()); |     dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.size()); | ||||||
|     dbgprintf("kmalloc stats: alloc:%u free:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_sum_eternal); |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     auto any_window_contains_rect = [this] (const Rect& r) { |     auto any_window_contains_rect = [this] (const Rect& r) { | ||||||
|  | @ -630,7 +624,6 @@ void WSWindowManager::compose() | ||||||
|         if (any_window_contains_rect(dirty_rect)) { |         if (any_window_contains_rect(dirty_rect)) { | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         LOCKER(m_wallpaper_path.lock()); |  | ||||||
|         if (!m_wallpaper) |         if (!m_wallpaper) | ||||||
|             m_back_painter->fill_rect(dirty_rect, m_background_color); |             m_back_painter->fill_rect(dirty_rect, m_background_color); | ||||||
|         else |         else | ||||||
|  | @ -663,7 +656,7 @@ void WSWindowManager::compose() | ||||||
|     draw_menubar(); |     draw_menubar(); | ||||||
|     draw_cursor(); |     draw_cursor(); | ||||||
| 
 | 
 | ||||||
|     if (m_flash_flush.lock_and_copy()) { |     if (m_flash_flush) { | ||||||
|         for (auto& rect : dirty_rects) |         for (auto& rect : dirty_rects) | ||||||
|             m_front_painter->fill_rect(rect, Color::Yellow); |             m_front_painter->fill_rect(rect, Color::Yellow); | ||||||
|     } |     } | ||||||
|  | @ -675,7 +668,6 @@ void WSWindowManager::compose() | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate_cursor() | void WSWindowManager::invalidate_cursor() | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto cursor_location = m_screen.cursor_location(); |     auto cursor_location = m_screen.cursor_location(); | ||||||
|     Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }; |     Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }; | ||||||
|     invalidate(cursor_rect); |     invalidate(cursor_rect); | ||||||
|  | @ -711,8 +703,6 @@ void WSWindowManager::draw_menubar() | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::draw_cursor() | void WSWindowManager::draw_cursor() | ||||||
| { | { | ||||||
|     ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto cursor_location = m_screen.cursor_location(); |     auto cursor_location = m_screen.cursor_location(); | ||||||
|     Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }; |     Rect cursor_rect { cursor_location.x(), cursor_location.y(), (int)m_cursor_bitmap_inner->width(), (int)m_cursor_bitmap_inner->height() }; | ||||||
|     Color inner_color = Color::White; |     Color inner_color = Color::White; | ||||||
|  | @ -726,8 +716,6 @@ void WSWindowManager::draw_cursor() | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::on_message(WSMessage& message) | void WSWindowManager::on_message(WSMessage& message) | ||||||
| { | { | ||||||
|     ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (message.is_mouse_event()) |     if (message.is_mouse_event()) | ||||||
|         return process_mouse_event(static_cast<WSMouseEvent&>(message)); |         return process_mouse_event(static_cast<WSMouseEvent&>(message)); | ||||||
| 
 | 
 | ||||||
|  | @ -747,7 +735,6 @@ void WSWindowManager::on_message(WSMessage& message) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::set_active_window(WSWindow* window) | void WSWindowManager::set_active_window(WSWindow* window) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (window->type() == WSWindowType::Menu) { |     if (window->type() == WSWindowType::Menu) { | ||||||
|         dbgprintf("WSWindowManager: Attempted to make a menu window active.\n"); |         dbgprintf("WSWindowManager: Attempted to make a menu window active.\n"); | ||||||
|         return; |         return; | ||||||
|  | @ -777,14 +764,12 @@ void WSWindowManager::set_active_window(WSWindow* window) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate() | void WSWindowManager::invalidate() | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     m_dirty_rects.clear_with_capacity(); |     m_dirty_rects.clear_with_capacity(); | ||||||
|     invalidate(m_screen_rect); |     invalidate(m_screen_rect); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate(const Rect& a_rect) | void WSWindowManager::invalidate(const Rect& a_rect) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto rect = Rect::intersection(a_rect, m_screen_rect); |     auto rect = Rect::intersection(a_rect, m_screen_rect); | ||||||
|     if (rect.is_empty()) |     if (rect.is_empty()) | ||||||
|         return; |         return; | ||||||
|  | @ -803,7 +788,6 @@ void WSWindowManager::invalidate(const Rect& a_rect) | ||||||
|     m_dirty_rects.append(rect); |     m_dirty_rects.append(rect); | ||||||
| 
 | 
 | ||||||
|     if (!m_pending_compose_event) { |     if (!m_pending_compose_event) { | ||||||
|         ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|         WSMessageLoop::the().post_message(this, make<WSMessage>(WSMessage::WM_DeferredCompose)); |         WSMessageLoop::the().post_message(this, make<WSMessage>(WSMessage::WM_DeferredCompose)); | ||||||
|         m_pending_compose_event = true; |         m_pending_compose_event = true; | ||||||
|     } |     } | ||||||
|  | @ -811,8 +795,6 @@ void WSWindowManager::invalidate(const Rect& a_rect) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate(const WSWindow& window) | void WSWindowManager::invalidate(const WSWindow& window) | ||||||
| { | { | ||||||
|     ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|     LOCKER(m_lock); |  | ||||||
|     invalidate(outer_window_rect(window.rect())); |     invalidate(outer_window_rect(window.rect())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -822,8 +804,6 @@ void WSWindowManager::invalidate(const WSWindow& window, const Rect& rect) | ||||||
|         invalidate(window); |         invalidate(window); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     ASSERT_INTERRUPTS_ENABLED(); |  | ||||||
|     LOCKER(m_lock); |  | ||||||
|     auto outer_rect = outer_window_rect(window.rect()); |     auto outer_rect = outer_window_rect(window.rect()); | ||||||
|     auto inner_rect = rect; |     auto inner_rect = rect; | ||||||
|     inner_rect.move_by(window.position()); |     inner_rect.move_by(window.position()); | ||||||
|  | @ -853,14 +833,12 @@ void WSWindowManager::flush(const Rect& a_rect) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::close_menu(WSMenu& menu) | void WSWindowManager::close_menu(WSMenu& menu) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (current_menu() == &menu) |     if (current_menu() == &menu) | ||||||
|         close_current_menu(); |         close_current_menu(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::close_menubar(WSMenuBar& menubar) | void WSWindowManager::close_menubar(WSMenuBar& menubar) | ||||||
| { | { | ||||||
|     LOCKER(m_lock); |  | ||||||
|     if (current_menubar() == &menubar) |     if (current_menubar() == &menubar) | ||||||
|         set_current_menubar(nullptr); |         set_current_menubar(nullptr); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ | ||||||
| #include <AK/HashTable.h> | #include <AK/HashTable.h> | ||||||
| #include <AK/InlineLinkedList.h> | #include <AK/InlineLinkedList.h> | ||||||
| #include <AK/WeakPtr.h> | #include <AK/WeakPtr.h> | ||||||
| #include <AK/Lock.h> |  | ||||||
| #include <AK/HashMap.h> | #include <AK/HashMap.h> | ||||||
| #include "WSMessageReceiver.h" | #include "WSMessageReceiver.h" | ||||||
| #include "WSMenuBar.h" | #include "WSMenuBar.h" | ||||||
|  | @ -27,6 +26,10 @@ enum class IterationDecision { Continue, Abort }; | ||||||
| class WSWindowManager : public WSMessageReceiver { | class WSWindowManager : public WSMessageReceiver { | ||||||
| public: | public: | ||||||
|     static WSWindowManager& the(); |     static WSWindowManager& the(); | ||||||
|  | 
 | ||||||
|  |     WSWindowManager(); | ||||||
|  |     virtual ~WSWindowManager() override; | ||||||
|  | 
 | ||||||
|     void add_window(WSWindow&); |     void add_window(WSWindow&); | ||||||
|     void remove_window(WSWindow&); |     void remove_window(WSWindow&); | ||||||
| 
 | 
 | ||||||
|  | @ -67,9 +70,6 @@ public: | ||||||
|     void set_framebuffer_fd(int fd) { m_framebuffer_fd = fd; } |     void set_framebuffer_fd(int fd) { m_framebuffer_fd = fd; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     WSWindowManager(); |  | ||||||
|     virtual ~WSWindowManager() override; |  | ||||||
| 
 |  | ||||||
|     void process_mouse_event(WSMouseEvent&); |     void process_mouse_event(WSMouseEvent&); | ||||||
|     void handle_menu_mouse_event(WSMenu&, WSMouseEvent&); |     void handle_menu_mouse_event(WSMenu&, WSMouseEvent&); | ||||||
|     void handle_menubar_mouse_event(WSMouseEvent&); |     void handle_menubar_mouse_event(WSMouseEvent&); | ||||||
|  | @ -139,12 +139,10 @@ private: | ||||||
| 
 | 
 | ||||||
|     RetainPtr<Font> m_font; |     RetainPtr<Font> m_font; | ||||||
| 
 | 
 | ||||||
|     Lockable<String> m_wallpaper_path; |     String m_wallpaper_path; | ||||||
|     RetainPtr<GraphicsBitmap> m_wallpaper; |     RetainPtr<GraphicsBitmap> m_wallpaper; | ||||||
| 
 | 
 | ||||||
|     mutable Lock m_lock; |     bool m_flash_flush { false }; | ||||||
| 
 |  | ||||||
|     Lockable<bool> m_flash_flush; |  | ||||||
|     bool m_buffers_are_flipped { false }; |     bool m_buffers_are_flipped { false }; | ||||||
| 
 | 
 | ||||||
|     OwnPtr<WSMenu> m_system_menu; |     OwnPtr<WSMenu> m_system_menu; | ||||||
|  |  | ||||||
|  | @ -1,19 +1,19 @@ | ||||||
| #include "Process.h" |  | ||||||
| #include <SharedGraphics/Font.h> | #include <SharedGraphics/Font.h> | ||||||
| #include <WindowServer/WSScreen.h> | #include <WindowServer/WSScreen.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSMessageLoop.h> | #include <WindowServer/WSMessageLoop.h> | ||||||
| #include <WindowServer/WSWindow.h> | #include <WindowServer/WSWindow.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | #include <sys/mman.h> | ||||||
| 
 | 
 | ||||||
| // NOTE: This actually runs as a kernel process.
 | int main(int, char**) | ||||||
| //       I'd like to change this eventually.
 |  | ||||||
| 
 |  | ||||||
| void WindowServer_main() |  | ||||||
| { | { | ||||||
|     WSMessageLoop::the().set_server_process(*current); |     dbgprintf("WindowServer starting...\n"); | ||||||
|     current->set_priority(Process::HighPriority); |     WSMessageLoop loop; | ||||||
| 
 | 
 | ||||||
|     int bxvga_fd = current->sys$open("/dev/bxvga", O_RDWR); |     int bxvga_fd = open("/dev/bxvga", O_RDWR); | ||||||
|     ASSERT(bxvga_fd >= 0); |     ASSERT(bxvga_fd >= 0); | ||||||
| 
 | 
 | ||||||
|     struct BXVGAResolution { |     struct BXVGAResolution { | ||||||
|  | @ -21,24 +21,17 @@ void WindowServer_main() | ||||||
|         int height; |         int height; | ||||||
|     }; |     }; | ||||||
|     BXVGAResolution resolution { 1024, 768 }; |     BXVGAResolution resolution { 1024, 768 }; | ||||||
| 
 |     int rc = ioctl(bxvga_fd, 1985, (int)&resolution); | ||||||
|     int rc = current->sys$ioctl(bxvga_fd, 1985, (int)&resolution); |  | ||||||
|     ASSERT(rc == 0); |     ASSERT(rc == 0); | ||||||
| 
 | 
 | ||||||
|     Syscall::SC_mmap_params params; |     size_t framebuffer_size_in_bytes = resolution.width * resolution.height * sizeof(RGBA32) * 2; | ||||||
|     memset(¶ms, 0, sizeof(params)); |     void* framebuffer = mmap(nullptr, framebuffer_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, bxvga_fd, 0); | ||||||
|     params.fd = bxvga_fd; |  | ||||||
|     params.prot = PROT_READ | PROT_WRITE; |  | ||||||
|     params.flags = MAP_SHARED; |  | ||||||
|     params.size = resolution.width * resolution.height * sizeof(RGBA32) * 2; |  | ||||||
|     params.offset = 0; |  | ||||||
|     kprintf("Calling sys$mmap in WS\n"); |  | ||||||
|     void* framebuffer = current->sys$mmap(¶ms); |  | ||||||
|     ASSERT(framebuffer && framebuffer != (void*)-1); |     ASSERT(framebuffer && framebuffer != (void*)-1); | ||||||
| 
 | 
 | ||||||
|     WSScreen screen((dword*)framebuffer, resolution.width, resolution.height); |     WSScreen screen((dword*)framebuffer, resolution.width, resolution.height); | ||||||
| 
 | 
 | ||||||
|     WSWindowManager::the().set_framebuffer_fd(bxvga_fd); |     WSWindowManager window_manager; | ||||||
|  |     window_manager.set_framebuffer_fd(bxvga_fd); | ||||||
| 
 | 
 | ||||||
|     dbgprintf("Entering WindowServer main loop.\n"); |     dbgprintf("Entering WindowServer main loop.\n"); | ||||||
|     WSMessageLoop::the().exec(); |     WSMessageLoop::the().exec(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling