Compare commits
No commits in common. "a202ef1f348beb39f5ef3f5278e2652cbbd6d144" and "69a0600d4517a630d47c64d0e82c81768aaf434d" have entirely different histories.
a202ef1f34
...
69a0600d45
@ -40,6 +40,8 @@ luna_app(kill.cpp kill)
|
|||||||
luna_app(gol.cpp gol)
|
luna_app(gol.cpp gol)
|
||||||
luna_app(touch.cpp touch)
|
luna_app(touch.cpp touch)
|
||||||
luna_app(free.cpp free)
|
luna_app(free.cpp free)
|
||||||
|
luna_app(gclient.cpp gclient)
|
||||||
|
target_link_libraries(gclient PUBLIC ui)
|
||||||
luna_app(about.cpp about)
|
luna_app(about.cpp about)
|
||||||
target_link_libraries(about PUBLIC ui)
|
target_link_libraries(about PUBLIC ui)
|
||||||
luna_app(taskbar.cpp taskbar)
|
luna_app(taskbar.cpp taskbar)
|
||||||
|
67
apps/gclient.cpp
Normal file
67
apps/gclient.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <ui/App.h>
|
||||||
|
#include <ui/Layout.h>
|
||||||
|
|
||||||
|
struct ColorWidget : public ui::Widget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColorWidget(ui::Color first, ui::Color second) : m_color(first), m_first_color(first), m_second_color(second)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ui::EventResult> handle_mouse_move(ui::Point) override
|
||||||
|
{
|
||||||
|
auto old_color = m_color;
|
||||||
|
m_color = m_second_color;
|
||||||
|
return old_color.raw == m_second_color.raw ? ui::EventResult::DidNotHandle : ui::EventResult::DidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ui::EventResult> handle_mouse_leave() override
|
||||||
|
{
|
||||||
|
auto old_color = m_color;
|
||||||
|
m_color = m_first_color;
|
||||||
|
return old_color.raw == m_first_color.raw ? ui::EventResult::DidNotHandle : ui::EventResult::DidHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> draw(ui::Canvas& canvas) override
|
||||||
|
{
|
||||||
|
canvas.fill(m_color);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ui::Color m_color;
|
||||||
|
ui::Color m_first_color;
|
||||||
|
ui::Color m_second_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<int> luna_main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
ui::App app;
|
||||||
|
TRY(app.init(argc, argv));
|
||||||
|
|
||||||
|
auto* window = TRY(ui::Window::create(ui::Rect { 200, 200, 400, 300 }));
|
||||||
|
app.set_main_window(window);
|
||||||
|
|
||||||
|
window->set_title("Test Window");
|
||||||
|
window->set_background(ui::CYAN);
|
||||||
|
|
||||||
|
ui::HorizontalLayout layout;
|
||||||
|
window->set_main_widget(layout);
|
||||||
|
|
||||||
|
ColorWidget green(ui::GREEN, ui::WHITE);
|
||||||
|
layout.add_widget(green);
|
||||||
|
ColorWidget blue(ui::BLUE, ui::GRAY);
|
||||||
|
layout.add_widget(blue);
|
||||||
|
|
||||||
|
ui::VerticalLayout sublayout;
|
||||||
|
layout.add_widget(sublayout);
|
||||||
|
|
||||||
|
ColorWidget red(ui::RED, ui::CYAN);
|
||||||
|
sublayout.add_widget(red);
|
||||||
|
ColorWidget white(ui::WHITE, ui::GREEN);
|
||||||
|
sublayout.add_widget(white);
|
||||||
|
|
||||||
|
window->draw();
|
||||||
|
|
||||||
|
return app.run();
|
||||||
|
}
|
@ -339,13 +339,6 @@ static void mount_shmfs()
|
|||||||
if (chmod("/dev/shm", 01777) < 0) exit(255);
|
if (chmod("/dev/shm", 01777) < 0) exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mount_devpts()
|
|
||||||
{
|
|
||||||
if (mkdir("/dev/pts", 0755) < 0) exit(255);
|
|
||||||
|
|
||||||
if (mount("/dev/pts", "devpts", "devpts") < 0) exit(255);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<int> sysinit(StringView path)
|
Result<int> sysinit(StringView path)
|
||||||
{
|
{
|
||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
@ -366,7 +359,6 @@ Result<int> sysinit(StringView path)
|
|||||||
|
|
||||||
mount_tmpfs();
|
mount_tmpfs();
|
||||||
mount_shmfs();
|
mount_shmfs();
|
||||||
mount_devpts();
|
|
||||||
|
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
|
@ -31,18 +31,18 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
ui::HorizontalLayout layout(ui::AdjustHeight::Yes, ui::AdjustWidth::No);
|
ui::HorizontalLayout layout(ui::AdjustHeight::Yes, ui::AdjustWidth::No);
|
||||||
window->set_main_widget(layout);
|
window->set_main_widget(layout);
|
||||||
|
|
||||||
ui::Button term_button({ 0, 0, 50, 50 });
|
ui::Button start_button({ 0, 0, 50, 50 });
|
||||||
layout.add_widget(term_button);
|
layout.add_widget(start_button);
|
||||||
|
|
||||||
ui::Container term_container({ 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center);
|
ui::Container start_container({ 0, 0, 50, 50 }, ui::VerticalAlignment::Center, ui::HorizontalAlignment::Center);
|
||||||
term_button.set_widget(term_container);
|
start_button.set_widget(start_container);
|
||||||
term_button.set_action([] {
|
start_button.set_action([] {
|
||||||
StringView args[] = { "/usr/bin/terminal" };
|
StringView args[] = { "/usr/bin/gclient" };
|
||||||
os::Process::spawn("/usr/bin/terminal", Slice<StringView> { args, 1 }, false);
|
os::Process::spawn("/usr/bin/gclient", Slice<StringView> { args, 1 }, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto term_image = TRY(ui::ImageWidget::load("/usr/share/icons/32x32/app-terminal.tga"));
|
auto start_image = TRY(ui::ImageWidget::load("/usr/share/icons/32x32/start-icon.tga"));
|
||||||
term_container.set_widget(*term_image);
|
start_container.set_widget(*start_image);
|
||||||
|
|
||||||
ui::Button about_button({ 0, 0, 50, 50 });
|
ui::Button about_button({ 0, 0, 50, 50 });
|
||||||
layout.add_widget(about_button);
|
layout.add_widget(about_button);
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB |
BIN
base/usr/share/icons/32x32/start-icon.tga
Normal file
BIN
base/usr/share/icons/32x32/start-icon.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@ -57,8 +57,6 @@ set(SOURCES
|
|||||||
src/net/UnixSocket.cpp
|
src/net/UnixSocket.cpp
|
||||||
src/fs/tmpfs/FileSystem.cpp
|
src/fs/tmpfs/FileSystem.cpp
|
||||||
src/fs/tmpfs/Inode.cpp
|
src/fs/tmpfs/Inode.cpp
|
||||||
src/fs/devpts/FileSystem.cpp
|
|
||||||
src/fs/devpts/Inode.cpp
|
|
||||||
src/fs/ext2/FileSystem.cpp
|
src/fs/ext2/FileSystem.cpp
|
||||||
src/fs/ext2/Inode.cpp
|
src/fs/ext2/Inode.cpp
|
||||||
src/fs/devices/DeviceRegistry.cpp
|
src/fs/devices/DeviceRegistry.cpp
|
||||||
@ -71,9 +69,6 @@ set(SOURCES
|
|||||||
src/fs/devices/UARTDevice.cpp
|
src/fs/devices/UARTDevice.cpp
|
||||||
src/fs/devices/MouseDevice.cpp
|
src/fs/devices/MouseDevice.cpp
|
||||||
src/fs/devices/KeyboardDevice.cpp
|
src/fs/devices/KeyboardDevice.cpp
|
||||||
src/fs/devices/PTYMultiplexer.cpp
|
|
||||||
src/fs/devices/MasterPTY.cpp
|
|
||||||
src/fs/devices/SlavePTY.cpp
|
|
||||||
src/fs/InitRD.cpp
|
src/fs/InitRD.cpp
|
||||||
src/binfmt/ELF.cpp
|
src/binfmt/ELF.cpp
|
||||||
src/binfmt/BinaryFormat.cpp
|
src/binfmt/BinaryFormat.cpp
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "fs/devices/KeyboardDevice.h"
|
#include "fs/devices/KeyboardDevice.h"
|
||||||
#include "fs/devices/MouseDevice.h"
|
#include "fs/devices/MouseDevice.h"
|
||||||
#include "fs/devices/NullDevice.h"
|
#include "fs/devices/NullDevice.h"
|
||||||
#include "fs/devices/PTYMultiplexer.h"
|
|
||||||
#include "fs/devices/UARTDevice.h"
|
#include "fs/devices/UARTDevice.h"
|
||||||
#include "fs/devices/ZeroDevice.h"
|
#include "fs/devices/ZeroDevice.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
@ -93,12 +92,6 @@ namespace DeviceRegistry
|
|||||||
|
|
||||||
for (const auto& descriptor : g_available_devices) TRY(create_special_device_inode(fs, descriptor));
|
for (const auto& descriptor : g_available_devices) TRY(create_special_device_inode(fs, descriptor));
|
||||||
|
|
||||||
auto multiplexer = TRY(make_shared<PTYMultiplexer>());
|
|
||||||
multiplexer->set_fs(*fs);
|
|
||||||
multiplexer->set_inode_number(TRY(fs->allocate_inode_number()));
|
|
||||||
|
|
||||||
TRY(fs->root_inode()->add_entry(multiplexer, "ptmx"));
|
|
||||||
|
|
||||||
return fs;
|
return fs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ namespace DeviceRegistry
|
|||||||
DiskPartition = 5,
|
DiskPartition = 5,
|
||||||
Serial = 6,
|
Serial = 6,
|
||||||
Input = 7,
|
Input = 7,
|
||||||
Terminal = 8,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
#include "fs/devices/MasterPTY.h"
|
|
||||||
#include "Pledge.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
|
||||||
#include "fs/devices/PTYMultiplexer.h"
|
|
||||||
#include "fs/devpts/FileSystem.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
|
||||||
#include "thread/Scheduler.h"
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> MasterPTY::create_pair(int index)
|
|
||||||
{
|
|
||||||
auto master = TRY(make_shared<MasterPTY>());
|
|
||||||
auto slave = TRY(make_shared<SlavePTY>());
|
|
||||||
|
|
||||||
auto name = TRY(String::format("%d"_sv, index));
|
|
||||||
for (auto& fs : g_devpts_instances) { fs->root_inode()->add_entry(slave, name.chars()); }
|
|
||||||
slave->m_name = move(name);
|
|
||||||
|
|
||||||
master->m_metadata.mode = 0666;
|
|
||||||
master->m_index = index;
|
|
||||||
master->m_slave = slave;
|
|
||||||
master->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, 0);
|
|
||||||
master->m_settings.c_lflag = ECHO | ECHOE | ECHOCTL | ISIG | ICANON;
|
|
||||||
master->m_settings.c_cc[VEOF] = '\4';
|
|
||||||
master->m_settings.c_cc[VERASE] = '\b';
|
|
||||||
master->m_settings.c_cc[VINTR] = '\3';
|
|
||||||
master->m_settings.c_cc[VQUIT] = '\x1c';
|
|
||||||
master->m_window.ws_col = 80;
|
|
||||||
master->m_window.ws_row = 25;
|
|
||||||
|
|
||||||
slave->m_master = master.ptr();
|
|
||||||
slave->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, index + 1);
|
|
||||||
slave->m_metadata.uid = Scheduler::current()->auth.euid;
|
|
||||||
slave->m_metadata.gid = Scheduler::current()->auth.egid;
|
|
||||||
slave->m_metadata.mode = 0620;
|
|
||||||
|
|
||||||
return (SharedPtr<VFS::Inode>)master;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> MasterPTY::handle_background_process_group(bool can_succeed, int signo) const
|
|
||||||
{
|
|
||||||
if (!m_foreground_process_group.has_value()) return {};
|
|
||||||
|
|
||||||
auto foreground_pgrp = m_foreground_process_group.value();
|
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
|
||||||
if (current->pgid == foreground_pgrp) return {};
|
|
||||||
|
|
||||||
if ((current->signal_mask.get(signo - 1)) || (current->signal_handlers[signo - 1].sa_handler == SIG_IGN))
|
|
||||||
{
|
|
||||||
if (can_succeed) return {};
|
|
||||||
return err(EIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
current->send_signal(signo);
|
|
||||||
|
|
||||||
if (can_succeed) return err(EINTR);
|
|
||||||
return err(EIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> MasterPTY::read(u8* buf, usize, usize length) const
|
|
||||||
{
|
|
||||||
length = m_buffer.dequeue_data(buf, length);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> MasterPTY::write(const u8* buf, usize, usize length)
|
|
||||||
{
|
|
||||||
TRY(m_slave->m_buffer.append_data(buf, length));
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> MasterPTY::ioctl(int request, void* arg)
|
|
||||||
{
|
|
||||||
auto* current = Scheduler::current();
|
|
||||||
TRY(check_pledge(current, Promise::p_tty));
|
|
||||||
|
|
||||||
switch (request)
|
|
||||||
{
|
|
||||||
case TCGETS: {
|
|
||||||
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_settings) ? 0 : err(EFAULT);
|
|
||||||
}
|
|
||||||
case TCSETS: {
|
|
||||||
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_settings)) return err(EFAULT);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCSPGRP: {
|
|
||||||
pid_t pgid;
|
|
||||||
if (!MemoryManager::copy_from_user_typed((const pid_t*)arg, &pgid)) return err(EFAULT);
|
|
||||||
|
|
||||||
bool pgid_exists = false;
|
|
||||||
Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) {
|
|
||||||
pgid_exists = true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (!pgid_exists) return err(EPERM);
|
|
||||||
|
|
||||||
m_foreground_process_group = pgid;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCGPGRP: {
|
|
||||||
pid_t pgid = m_foreground_process_group.value_or((pid_t)next_thread_id());
|
|
||||||
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCGWINSZ: {
|
|
||||||
if (!MemoryManager::copy_to_user_typed((struct winsize*)arg, &m_window)) return err(EFAULT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCGPTN: {
|
|
||||||
if (!MemoryManager::copy_to_user_typed((int*)arg, &m_index)) return err(EFAULT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default: return err(EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MasterPTY::~MasterPTY()
|
|
||||||
{
|
|
||||||
m_slave->m_master = nullptr;
|
|
||||||
for (auto& fs : g_devpts_instances) { fs->root_inode()->remove_entry(m_slave->m_name.chars()); }
|
|
||||||
PTYMultiplexer::did_remove_pty(m_index);
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "fs/VFS.h"
|
|
||||||
#include "fs/devices/SlavePTY.h"
|
|
||||||
#include <bits/termios.h>
|
|
||||||
#include <luna/Buffer.h>
|
|
||||||
|
|
||||||
class MasterPTY : public VFS::DeviceInode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MasterPTY() = default;
|
|
||||||
|
|
||||||
static Result<SharedPtr<VFS::Inode>> create_pair(int index);
|
|
||||||
|
|
||||||
VFS::InodeType type() const override
|
|
||||||
{
|
|
||||||
return VFS::InodeType::CharacterDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> query_shared_memory(off_t, usize) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::FileSystem* fs() const override
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> read(u8* buf, usize offset, usize length) const override;
|
|
||||||
|
|
||||||
Result<usize> write(const u8* buf, usize offset, usize length) override;
|
|
||||||
|
|
||||||
Result<u64> ioctl(int request, void* arg) override;
|
|
||||||
|
|
||||||
Result<u64> isatty() const override
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
|
||||||
{
|
|
||||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
|
||||||
return err(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool will_block_if_read() const override
|
|
||||||
{
|
|
||||||
return m_buffer.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_link() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_unlink() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks--;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MasterPTY();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct termios m_settings;
|
|
||||||
mutable Buffer m_buffer;
|
|
||||||
SharedPtr<SlavePTY> m_slave;
|
|
||||||
mutable Option<pid_t> m_foreground_process_group;
|
|
||||||
struct winsize m_window;
|
|
||||||
|
|
||||||
Result<void> handle_background_process_group(bool can_succeed, int signo) const;
|
|
||||||
|
|
||||||
int m_index;
|
|
||||||
|
|
||||||
friend class SlavePTY;
|
|
||||||
};
|
|
@ -1,36 +0,0 @@
|
|||||||
#include "fs/devices/PTYMultiplexer.h"
|
|
||||||
|
|
||||||
Bitset<u64> PTYMultiplexer::m_available_indexes = 0;
|
|
||||||
|
|
||||||
PTYMultiplexer::PTYMultiplexer()
|
|
||||||
{
|
|
||||||
m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, 0);
|
|
||||||
m_metadata.mode = 0666;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> PTYMultiplexer::open()
|
|
||||||
{
|
|
||||||
int index = -1;
|
|
||||||
for (int i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
if (!m_available_indexes.get(i))
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
m_available_indexes.set(i, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index == -1) return err(ENOSPC);
|
|
||||||
|
|
||||||
return MasterPTY::create_pair(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PTYMultiplexer::init()
|
|
||||||
{
|
|
||||||
m_available_indexes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PTYMultiplexer::did_remove_pty(int index)
|
|
||||||
{
|
|
||||||
m_available_indexes.set(index, false);
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "fs/VFS.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
|
||||||
#include "fs/devices/MasterPTY.h"
|
|
||||||
#include <luna/Bitset.h>
|
|
||||||
|
|
||||||
class PTYMultiplexer : public VFS::DeviceInode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PTYMultiplexer();
|
|
||||||
|
|
||||||
VFS::InodeType type() const override
|
|
||||||
{
|
|
||||||
return VFS::InodeType::CharacterDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_fs(VFS::FileSystem& fs)
|
|
||||||
{
|
|
||||||
m_fs = &fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_inode_number(usize inum)
|
|
||||||
{
|
|
||||||
m_metadata.inum = inum;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> query_shared_memory(off_t, usize) override
|
|
||||||
{
|
|
||||||
unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> open() override;
|
|
||||||
|
|
||||||
VFS::FileSystem* fs() const override
|
|
||||||
{
|
|
||||||
return m_fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> read(u8*, usize, usize) const override
|
|
||||||
{
|
|
||||||
unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> write(const u8*, usize, usize) override
|
|
||||||
{
|
|
||||||
unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
|
||||||
{
|
|
||||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
|
||||||
return err(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool will_block_if_read() const override
|
|
||||||
{
|
|
||||||
unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_link() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_unlink() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
|
|
||||||
static void did_remove_pty(int index);
|
|
||||||
|
|
||||||
virtual ~PTYMultiplexer() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
VFS::FileSystem* m_fs;
|
|
||||||
|
|
||||||
static Bitset<u64> m_available_indexes;
|
|
||||||
};
|
|
@ -1,71 +0,0 @@
|
|||||||
#include "fs/devices/SlavePTY.h"
|
|
||||||
#include "Pledge.h"
|
|
||||||
#include "fs/devices/MasterPTY.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
|
||||||
#include "thread/Scheduler.h"
|
|
||||||
|
|
||||||
Result<usize> SlavePTY::read(u8* buf, usize, usize length) const
|
|
||||||
{
|
|
||||||
if (!m_master) return err(EIO);
|
|
||||||
|
|
||||||
TRY(m_master->handle_background_process_group(false, SIGTTIN));
|
|
||||||
|
|
||||||
length = m_buffer.dequeue_data(buf, length);
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> SlavePTY::write(const u8* buf, usize, usize length)
|
|
||||||
{
|
|
||||||
if (!m_master) return err(EIO);
|
|
||||||
|
|
||||||
if (m_master->m_settings.c_lflag & TOSTOP) TRY(m_master->handle_background_process_group(true, SIGTTOU));
|
|
||||||
|
|
||||||
TRY(m_master->m_buffer.append_data(buf, length));
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> SlavePTY::ioctl(int request, void* arg)
|
|
||||||
{
|
|
||||||
auto* current = Scheduler::current();
|
|
||||||
TRY(check_pledge(current, Promise::p_tty));
|
|
||||||
|
|
||||||
if (!m_master) return err(EIO);
|
|
||||||
|
|
||||||
switch (request)
|
|
||||||
{
|
|
||||||
case TCGETS: {
|
|
||||||
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_master->m_settings) ? 0 : err(EFAULT);
|
|
||||||
}
|
|
||||||
case TCSETS: {
|
|
||||||
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_master->m_settings)) return err(EFAULT);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCSPGRP: {
|
|
||||||
pid_t pgid;
|
|
||||||
if (!MemoryManager::copy_from_user_typed((const pid_t*)arg, &pgid)) return err(EFAULT);
|
|
||||||
|
|
||||||
bool pgid_exists = false;
|
|
||||||
Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) {
|
|
||||||
pgid_exists = true;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (!pgid_exists) return err(EPERM);
|
|
||||||
|
|
||||||
m_master->m_foreground_process_group = pgid;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCGPGRP: {
|
|
||||||
pid_t pgid = m_master->m_foreground_process_group.value_or((pid_t)next_thread_id());
|
|
||||||
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case TIOCGWINSZ: {
|
|
||||||
if (!MemoryManager::copy_to_user_typed((struct winsize*)arg, &m_master->m_window)) return err(EFAULT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default: return err(EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "fs/VFS.h"
|
|
||||||
#include <luna/Buffer.h>
|
|
||||||
#include <luna/String.h>
|
|
||||||
|
|
||||||
class MasterPTY;
|
|
||||||
|
|
||||||
class SlavePTY : public VFS::DeviceInode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SlavePTY() = default;
|
|
||||||
|
|
||||||
VFS::InodeType type() const override
|
|
||||||
{
|
|
||||||
return VFS::InodeType::CharacterDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> query_shared_memory(off_t, usize) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::FileSystem* fs() const override
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> read(u8* buf, usize offset, usize length) const override;
|
|
||||||
|
|
||||||
Result<usize> write(const u8* buf, usize offset, usize length) override;
|
|
||||||
|
|
||||||
Result<u64> ioctl(int request, void* arg) override;
|
|
||||||
|
|
||||||
Result<u64> isatty() const override
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
|
||||||
{
|
|
||||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
|
||||||
return err(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool will_block_if_read() const override
|
|
||||||
{
|
|
||||||
return m_buffer.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_link() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_unlink() override
|
|
||||||
{
|
|
||||||
m_metadata.nlinks--;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~SlavePTY() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable Buffer m_buffer;
|
|
||||||
|
|
||||||
MasterPTY* m_master;
|
|
||||||
String m_name;
|
|
||||||
|
|
||||||
friend class MasterPTY;
|
|
||||||
};
|
|
@ -1,62 +0,0 @@
|
|||||||
#include "fs/devpts/FileSystem.h"
|
|
||||||
#include "arch/Timer.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
|
||||||
#include "fs/devpts/Inode.h"
|
|
||||||
#include <luna/Alloc.h>
|
|
||||||
#include <luna/CString.h>
|
|
||||||
#include <luna/Ignore.h>
|
|
||||||
|
|
||||||
Vector<VFS::FileSystem*> g_devpts_instances;
|
|
||||||
|
|
||||||
namespace DevPTS
|
|
||||||
{
|
|
||||||
Result<SharedPtr<VFS::FileSystem>> FileSystem::create()
|
|
||||||
{
|
|
||||||
SharedPtr<FileSystem> fs = TRY(adopt_shared_if_nonnull(new (std::nothrow) FileSystem()));
|
|
||||||
SharedPtr<RootInode> root = TRY(make_shared<RootInode>());
|
|
||||||
|
|
||||||
TRY(root->add_entry(root, "."));
|
|
||||||
TRY(root->add_entry(root, ".."));
|
|
||||||
|
|
||||||
root->set_self(root, {});
|
|
||||||
root->set_fs(*fs, {});
|
|
||||||
root->set_inode_number();
|
|
||||||
root->m_metadata.mode = 0755;
|
|
||||||
root->m_metadata.atime = root->m_metadata.ctime = root->m_metadata.mtime = *Timer::realtime_clock();
|
|
||||||
fs->set_root(root);
|
|
||||||
|
|
||||||
TRY(g_devpts_instances.try_append(fs.ptr()));
|
|
||||||
|
|
||||||
return (SharedPtr<VFS::FileSystem>)fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> FileSystem::allocate_inode_number()
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystem::FileSystem()
|
|
||||||
{
|
|
||||||
m_host_device_id = DeviceRegistry::next_null_device_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> parent)
|
|
||||||
{
|
|
||||||
return m_root_inode->replace_entry(parent, "..");
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> FileSystem::reset_mount_dir()
|
|
||||||
{
|
|
||||||
return m_root_inode->replace_entry(m_root_inode, "..");
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileSystem::set_root(SharedPtr<VFS::Inode> root)
|
|
||||||
{
|
|
||||||
m_root_inode = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSystem::~FileSystem()
|
|
||||||
{
|
|
||||||
g_devpts_instances.remove_first_matching([this](VFS::FileSystem* ptr) { return ptr == this; });
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "fs/VFS.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
|
||||||
|
|
||||||
namespace DevPTS
|
|
||||||
{
|
|
||||||
class FileSystem : public VFS::FileSystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SharedPtr<VFS::Inode> root_inode() const override
|
|
||||||
{
|
|
||||||
return m_root_inode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_file_inode(mode_t) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode>, mode_t) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_device_inode(u32, u32, mode_t) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_symlink_inode(StringView) override
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<u64> allocate_inode_number() override;
|
|
||||||
|
|
||||||
Result<void> set_mount_dir(SharedPtr<VFS::Inode> parent) override;
|
|
||||||
|
|
||||||
Result<void> reset_mount_dir() override;
|
|
||||||
|
|
||||||
static Result<SharedPtr<VFS::FileSystem>> create();
|
|
||||||
|
|
||||||
dev_t host_device_id() const override
|
|
||||||
{
|
|
||||||
return m_host_device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~FileSystem();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FileSystem();
|
|
||||||
|
|
||||||
void set_root(SharedPtr<VFS::Inode> root);
|
|
||||||
|
|
||||||
SharedPtr<VFS::Inode> m_root_inode;
|
|
||||||
|
|
||||||
dev_t m_host_device_id;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extern Vector<VFS::FileSystem*> g_devpts_instances;
|
|
@ -1,78 +0,0 @@
|
|||||||
#include "fs/devpts/Inode.h"
|
|
||||||
|
|
||||||
namespace DevPTS
|
|
||||||
{
|
|
||||||
Result<SharedPtr<VFS::Inode>> RootInode::find(const char* name) const
|
|
||||||
{
|
|
||||||
for (const auto& entry : m_entries)
|
|
||||||
{
|
|
||||||
if (!strcmp(name, entry.name.chars())) return entry.inode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err(ENOENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> RootInode::replace_entry(SharedPtr<VFS::Inode> inode, const char* name)
|
|
||||||
{
|
|
||||||
for (auto& entry : m_entries)
|
|
||||||
{
|
|
||||||
if (!strcmp(name, entry.name.chars()))
|
|
||||||
{
|
|
||||||
entry.inode = inode;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err(ENOENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
Option<VFS::DirectoryEntry> RootInode::get(usize index) const
|
|
||||||
{
|
|
||||||
if (index >= m_entries.size()) return {};
|
|
||||||
|
|
||||||
return m_entries[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> RootInode::add_entry(SharedPtr<VFS::Inode> inode, const char* name)
|
|
||||||
{
|
|
||||||
if (find(name).has_value()) return err(EEXIST);
|
|
||||||
|
|
||||||
VFS::DirectoryEntry entry { inode, name };
|
|
||||||
|
|
||||||
TRY(m_entries.try_append(move(entry)));
|
|
||||||
|
|
||||||
inode->did_link();
|
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> RootInode::remove_entry(const char* name)
|
|
||||||
{
|
|
||||||
SharedPtr<VFS::Inode> inode = TRY(find(name));
|
|
||||||
|
|
||||||
if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY);
|
|
||||||
|
|
||||||
if (inode->is_mountpoint()) return err(EBUSY);
|
|
||||||
|
|
||||||
m_entries.remove_first_matching(
|
|
||||||
[&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); });
|
|
||||||
|
|
||||||
inode->did_unlink();
|
|
||||||
|
|
||||||
m_metadata.mtime = *Timer::realtime_clock();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> RootInode::create_file(const char*, mode_t)
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> RootInode::create_subdirectory(const char*, mode_t)
|
|
||||||
{
|
|
||||||
return err(ENOTSUP);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "fs/VFS.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
|
||||||
#include "fs/devpts/FileSystem.h"
|
|
||||||
|
|
||||||
namespace DevPTS
|
|
||||||
{
|
|
||||||
class RootInode : public VFS::Inode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RootInode() = default;
|
|
||||||
|
|
||||||
void set_fs(FileSystem& fs, Badge<FileSystem>)
|
|
||||||
{
|
|
||||||
m_fs = &fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_inode_number()
|
|
||||||
{
|
|
||||||
m_metadata.inum = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_self(SharedPtr<VFS::Inode> self, Badge<FileSystem>)
|
|
||||||
{
|
|
||||||
m_self = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> find(const char* name) const override;
|
|
||||||
Option<VFS::DirectoryEntry> get(usize index) const override;
|
|
||||||
|
|
||||||
Result<usize> read(u8*, usize, usize) const override
|
|
||||||
{
|
|
||||||
return err(EISDIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<usize> write(const u8*, usize, usize) override
|
|
||||||
{
|
|
||||||
return err(EISDIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
|
||||||
{
|
|
||||||
return err(EISDIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool will_block_if_read() const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::FileSystem* fs() const override
|
|
||||||
{
|
|
||||||
return m_fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
VFS::InodeType type() const override
|
|
||||||
{
|
|
||||||
return VFS::InodeType::Directory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_link() override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void did_unlink() override
|
|
||||||
{
|
|
||||||
m_self = {};
|
|
||||||
m_entries.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
usize entries() const override
|
|
||||||
{
|
|
||||||
return m_entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> remove_entry(const char* name) override;
|
|
||||||
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_file(const char* name, mode_t mode) override;
|
|
||||||
Result<SharedPtr<VFS::Inode>> create_subdirectory(const char* name, mode_t mode) override;
|
|
||||||
|
|
||||||
Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name);
|
|
||||||
Result<void> replace_entry(SharedPtr<VFS::Inode> inode, const char* name);
|
|
||||||
|
|
||||||
virtual ~RootInode() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
VFS::FileSystem* m_fs;
|
|
||||||
SharedPtr<VFS::Inode> m_self;
|
|
||||||
Vector<VFS::DirectoryEntry> m_entries;
|
|
||||||
|
|
||||||
friend class FileSystem;
|
|
||||||
};
|
|
||||||
}
|
|
@ -6,7 +6,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fs/InitRD.h"
|
#include "fs/InitRD.h"
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
#include "fs/devices/PTYMultiplexer.h"
|
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
@ -95,7 +94,6 @@ extern "C" [[noreturn]] void _start()
|
|||||||
|
|
||||||
Thread::init();
|
Thread::init();
|
||||||
Scheduler::init();
|
Scheduler::init();
|
||||||
PTYMultiplexer::init();
|
|
||||||
|
|
||||||
Scheduler::new_kernel_thread(init, "[kinit]");
|
Scheduler::new_kernel_thread(init, "[kinit]");
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "Pledge.h"
|
#include "Pledge.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "fs/devpts/FileSystem.h"
|
|
||||||
#include "fs/ext2/FileSystem.h"
|
#include "fs/ext2/FileSystem.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
@ -27,8 +26,6 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
|||||||
SharedPtr<VFS::FileSystem> fs;
|
SharedPtr<VFS::FileSystem> fs;
|
||||||
|
|
||||||
if (fstype.view() == "tmpfs") fs = TRY(TmpFS::FileSystem::create());
|
if (fstype.view() == "tmpfs") fs = TRY(TmpFS::FileSystem::create());
|
||||||
else if (fstype.view() == "devpts")
|
|
||||||
fs = TRY(DevPTS::FileSystem::create());
|
|
||||||
else if (fstype.view() == "devfs")
|
else if (fstype.view() == "devfs")
|
||||||
fs = TRY(DeviceRegistry::create_devfs_instance());
|
fs = TRY(DeviceRegistry::create_devfs_instance());
|
||||||
else if (fstype.view() == "ext2")
|
else if (fstype.view() == "ext2")
|
||||||
|
@ -45,6 +45,5 @@ struct winsize
|
|||||||
#define TIOCSPGRP 2
|
#define TIOCSPGRP 2
|
||||||
#define TIOCGPGRP 3
|
#define TIOCGPGRP 3
|
||||||
#define TIOCGWINSZ 4
|
#define TIOCGWINSZ 4
|
||||||
#define TIOCGPTN 5
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -148,18 +148,6 @@ extern "C"
|
|||||||
/* Create a unique file from a template string whose last 6 bytes must be XXXXXX. */
|
/* Create a unique file from a template string whose last 6 bytes must be XXXXXX. */
|
||||||
int mkstemp(char* _template);
|
int mkstemp(char* _template);
|
||||||
|
|
||||||
/* Create a new pseudoterminal pair. */
|
|
||||||
int posix_openpt(int flags);
|
|
||||||
|
|
||||||
/* Set the credentials of a pseudoterminal master. */
|
|
||||||
int grantpt(int fd);
|
|
||||||
|
|
||||||
/* Unlock a pseudoterminal master. */
|
|
||||||
int unlockpt(int fd);
|
|
||||||
|
|
||||||
/* Return the name of the slave associated with a pseudoterminal master. */
|
|
||||||
char* ptsname(int fd);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <bits/errno-return.h>
|
#include <bits/errno-return.h>
|
||||||
#include <bits/termios.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -8,10 +7,8 @@
|
|||||||
#include <luna/Sort.h>
|
#include <luna/Sort.h>
|
||||||
#include <luna/Utf8.h>
|
#include <luna/Utf8.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@ -303,31 +300,4 @@ extern "C"
|
|||||||
{
|
{
|
||||||
return strtod(str, nullptr);
|
return strtod(str, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int posix_openpt(int flags)
|
|
||||||
{
|
|
||||||
return open("/dev/ptmx", flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int grantpt(int)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int unlockpt(int)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ptsname(int fd)
|
|
||||||
{
|
|
||||||
static char buffer[4096];
|
|
||||||
|
|
||||||
int index;
|
|
||||||
if (ioctl(fd, TIOCGPTN, &index) < 0) return nullptr;
|
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "/dev/pts/%d", index);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ namespace ui
|
|||||||
Result<EventResult> handle_mouse_leave() override;
|
Result<EventResult> handle_mouse_leave() override;
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
Result<void> draw(Canvas& canvas) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -24,7 +24,6 @@ namespace ui
|
|||||||
Result<EventResult> handle_mouse_leave() override;
|
Result<EventResult> handle_mouse_leave() override;
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
Result<void> draw(Canvas& canvas) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <moon/Keyboard.h>
|
|
||||||
|
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
enum Modifier
|
|
||||||
{
|
|
||||||
Mod_Shift = (1 << 0),
|
|
||||||
Mod_Alt = (1 << 1),
|
|
||||||
Mod_Super = (1 << 2),
|
|
||||||
Mod_AltGr = (1 << 3),
|
|
||||||
Mod_Ctrl = (1 << 4)
|
|
||||||
};
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ namespace ui
|
|||||||
Result<EventResult> handle_mouse_leave() override;
|
Result<EventResult> handle_mouse_leave() override;
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
|
||||||
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
Result<void> draw(Canvas& canvas) override;
|
||||||
|
|
||||||
@ -56,7 +55,6 @@ namespace ui
|
|||||||
Result<EventResult> handle_mouse_leave() override;
|
Result<EventResult> handle_mouse_leave() override;
|
||||||
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_down(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
Result<EventResult> handle_mouse_up(Point position, int buttons) override;
|
||||||
Result<EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
|
||||||
|
|
||||||
Result<void> draw(Canvas& canvas) override;
|
Result<void> draw(Canvas& canvas) override;
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include <ui/Canvas.h>
|
#include <ui/Canvas.h>
|
||||||
#include <ui/Point.h>
|
#include <ui/Point.h>
|
||||||
#include <ui/Rect.h>
|
#include <ui/Rect.h>
|
||||||
#include <ui/ipc/Client.h>
|
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
@ -51,12 +50,6 @@ namespace ui
|
|||||||
return EventResult::DidNotHandle;
|
return EventResult::DidNotHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result<EventResult> handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
ignore(request);
|
|
||||||
return EventResult::DidNotHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result<void> draw(Canvas& canvas);
|
virtual Result<void> draw(Canvas& canvas);
|
||||||
|
|
||||||
void set_window(Window* window, Rect rect, Badge<Window>)
|
void set_window(Window* window, Rect rect, Badge<Window>)
|
||||||
|
@ -49,7 +49,6 @@ namespace ui
|
|||||||
Result<ui::EventResult> handle_mouse_leave();
|
Result<ui::EventResult> handle_mouse_leave();
|
||||||
Result<ui::EventResult> handle_mouse_move(ui::Point position);
|
Result<ui::EventResult> handle_mouse_move(ui::Point position);
|
||||||
Result<ui::EventResult> handle_mouse_buttons(ui::Point position, int buttons);
|
Result<ui::EventResult> handle_mouse_buttons(ui::Point position, int buttons);
|
||||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request);
|
|
||||||
|
|
||||||
int id() const
|
int id() const
|
||||||
{
|
{
|
||||||
|
@ -9,9 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <os/IPC.h>
|
#include <os/IPC.h>
|
||||||
#include <ui/Key.h>
|
|
||||||
#include <ui/Point.h>
|
#include <ui/Point.h>
|
||||||
#include <ui/Rect.h>
|
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
@ -22,8 +20,7 @@ namespace ui
|
|||||||
WINDOW_CLOSE_REQUEST_ID,
|
WINDOW_CLOSE_REQUEST_ID,
|
||||||
MOUSE_EVENT_REQUEST_ID,
|
MOUSE_EVENT_REQUEST_ID,
|
||||||
MOUSE_LEAVE_REQUEST_ID,
|
MOUSE_LEAVE_REQUEST_ID,
|
||||||
GET_SCREEN_RECT_RESPONSE_ID,
|
GET_SCREEN_RECT_RESPONSE_ID
|
||||||
KEY_EVENT_REQUEST_ID,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreateWindowResponse
|
struct CreateWindowResponse
|
||||||
@ -63,18 +60,4 @@ namespace ui
|
|||||||
|
|
||||||
Rect rect;
|
Rect rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KeyEventRequest
|
|
||||||
{
|
|
||||||
static constexpr u8 ID = KEY_EVENT_REQUEST_ID;
|
|
||||||
|
|
||||||
int window;
|
|
||||||
|
|
||||||
bool pressed;
|
|
||||||
|
|
||||||
char letter;
|
|
||||||
char key;
|
|
||||||
moon::KeyCode code;
|
|
||||||
int modifiers;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -132,14 +132,6 @@ namespace ui
|
|||||||
window->draw();
|
window->draw();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
case KEY_EVENT_REQUEST_ID: {
|
|
||||||
KeyEventRequest request;
|
|
||||||
READ_MESSAGE(request);
|
|
||||||
auto* window = find_window(request.window);
|
|
||||||
if (window->handle_key_event(request).value_or(ui::EventResult::DidNotHandle) == ui::EventResult::DidHandle)
|
|
||||||
window->draw();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
default: fail("Unexpected IPC request from server!");
|
default: fail("Unexpected IPC request from server!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,6 @@ namespace ui
|
|||||||
return m_child->handle_mouse_up(position, buttons);
|
return m_child->handle_mouse_up(position, buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<EventResult> Button::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
return m_child->handle_key_event(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Button::draw(Canvas& canvas)
|
Result<void> Button::draw(Canvas& canvas)
|
||||||
{
|
{
|
||||||
return m_child->draw(canvas);
|
return m_child->draw(canvas);
|
||||||
|
@ -47,11 +47,6 @@ namespace ui
|
|||||||
return ui::EventResult::DidNotHandle;
|
return ui::EventResult::DidNotHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<EventResult> Container::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
return m_widget->handle_key_event(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Container::draw(Canvas& canvas)
|
Result<void> Container::draw(Canvas& canvas)
|
||||||
{
|
{
|
||||||
auto rect = ui::Rect { m_widget->rect().pos.x - m_rect.pos.x, m_widget->rect().pos.y - m_rect.pos.y,
|
auto rect = ui::Rect { m_widget->rect().pos.x - m_rect.pos.x, m_widget->rect().pos.y - m_rect.pos.y,
|
||||||
|
@ -64,19 +64,6 @@ namespace ui
|
|||||||
return ui::EventResult::DidNotHandle;
|
return ui::EventResult::DidNotHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<EventResult> HorizontalLayout::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
EventResult result = ui::EventResult::DidNotHandle;
|
|
||||||
|
|
||||||
for (auto widget : m_widgets)
|
|
||||||
{
|
|
||||||
auto rc = TRY(widget->handle_key_event(request));
|
|
||||||
if (rc == ui::EventResult::DidHandle) result = rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> HorizontalLayout::draw(Canvas& canvas)
|
Result<void> HorizontalLayout::draw(Canvas& canvas)
|
||||||
{
|
{
|
||||||
for (auto widget : m_widgets)
|
for (auto widget : m_widgets)
|
||||||
@ -172,19 +159,6 @@ namespace ui
|
|||||||
return ui::EventResult::DidNotHandle;
|
return ui::EventResult::DidNotHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<EventResult> VerticalLayout::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
EventResult result = ui::EventResult::DidNotHandle;
|
|
||||||
|
|
||||||
for (auto widget : m_widgets)
|
|
||||||
{
|
|
||||||
auto rc = TRY(widget->handle_key_event(request));
|
|
||||||
if (rc == ui::EventResult::DidHandle) result = rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> VerticalLayout::draw(Canvas& canvas)
|
Result<void> VerticalLayout::draw(Canvas& canvas)
|
||||||
{
|
{
|
||||||
for (auto widget : m_widgets)
|
for (auto widget : m_widgets)
|
||||||
|
@ -114,10 +114,4 @@ namespace ui
|
|||||||
m_old_mouse_buttons = buttons;
|
m_old_mouse_buttons = buttons;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ui::EventResult> Window::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
if (!m_main_widget) return ui::EventResult::DidNotHandle;
|
|
||||||
return m_main_widget->handle_key_event(request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#include "TerminalWidget.h"
|
#include "TerminalWidget.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <luna/CType.h>
|
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/Process.h>
|
#include <os/Process.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ui/App.h>
|
#include <ui/App.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -44,164 +42,44 @@ Result<void> TerminalWidget::init(char* const* args)
|
|||||||
|
|
||||||
signal(SIGCHLD, sigchld_handler);
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
|
||||||
int fd = posix_openpt(O_RDWR | O_CLOEXEC);
|
int infds[2];
|
||||||
if (fd < 0) return err(errno);
|
int outfds[2];
|
||||||
|
|
||||||
grantpt(fd);
|
int result = pipe(infds);
|
||||||
unlockpt(fd);
|
if (result < 0) return err(errno);
|
||||||
|
|
||||||
|
result = pipe(outfds);
|
||||||
|
if (result < 0) return err(errno);
|
||||||
|
|
||||||
pid_t child = TRY(os::Process::fork());
|
pid_t child = TRY(os::Process::fork());
|
||||||
if (child == 0)
|
if (child == 0)
|
||||||
{
|
{
|
||||||
int ptsfd = open(ptsname(fd), O_RDWR);
|
dup2(infds[0], STDIN_FILENO);
|
||||||
|
dup2(outfds[1], STDOUT_FILENO);
|
||||||
|
dup2(outfds[1], STDERR_FILENO);
|
||||||
|
|
||||||
dup2(ptsfd, STDIN_FILENO);
|
close(infds[0]);
|
||||||
dup2(ptsfd, STDOUT_FILENO);
|
close(infds[1]);
|
||||||
dup2(ptsfd, STDERR_FILENO);
|
close(outfds[0]);
|
||||||
|
close(outfds[1]);
|
||||||
setpgid(0, 0);
|
|
||||||
tcsetpgrp(ptsfd, getpid());
|
|
||||||
|
|
||||||
close(ptsfd);
|
|
||||||
|
|
||||||
execv(args[0], args);
|
execv(args[0], args);
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pty = fd;
|
close(infds[0]);
|
||||||
|
close(outfds[1]);
|
||||||
|
|
||||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
m_write_fd = infds[1];
|
||||||
|
m_read_fd = outfds[0];
|
||||||
|
|
||||||
|
fcntl(m_read_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
m_child_pid = child;
|
m_child_pid = child;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ui::EventResult> TerminalWidget::handle_key_event(const ui::KeyEventRequest& request)
|
|
||||||
{
|
|
||||||
if (!request.pressed) return ui::EventResult::DidNotHandle;
|
|
||||||
|
|
||||||
query_termios();
|
|
||||||
|
|
||||||
bool is_special_character { false };
|
|
||||||
|
|
||||||
if (/*is_canonical()*/ true)
|
|
||||||
{
|
|
||||||
if (request.letter == m_settings.c_cc[VERASE])
|
|
||||||
{
|
|
||||||
auto maybe_char = m_line_buffer.try_pop();
|
|
||||||
if (maybe_char.has_value() && maybe_char.value())
|
|
||||||
{
|
|
||||||
if ((m_settings.c_lflag & ECHO) && (m_settings.c_lflag & ECHOE))
|
|
||||||
{
|
|
||||||
put_code_point(L'\b');
|
|
||||||
if (_iscntrl(maybe_char.value())) put_code_point(L'\b');
|
|
||||||
if (maybe_char.value() == '\t')
|
|
||||||
{
|
|
||||||
put_code_point(L'\b');
|
|
||||||
put_code_point(L'\b');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui::App::the().main_window()->draw();
|
|
||||||
return ui::EventResult::DidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_settings.c_lflag & ECHOE)) return ui::EventResult::DidHandle;
|
|
||||||
else
|
|
||||||
is_special_character = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.letter == m_settings.c_cc[VEOF])
|
|
||||||
{
|
|
||||||
write(m_pty, m_line_buffer.data(), m_line_buffer.size());
|
|
||||||
m_line_buffer.clear();
|
|
||||||
|
|
||||||
// FIXME: tell the kernel that process may read without blocking.
|
|
||||||
is_special_character = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_settings.c_lflag & ISIG)
|
|
||||||
{
|
|
||||||
if (request.letter == m_settings.c_cc[VINTR])
|
|
||||||
{
|
|
||||||
if (!(m_settings.c_lflag & NOFLSH)) m_line_buffer.clear();
|
|
||||||
|
|
||||||
// FIXME: Send SIGINT.
|
|
||||||
/*if (m_foreground_process_group.has_value())
|
|
||||||
{
|
|
||||||
Scheduler::for_each_in_process_group(m_foreground_process_group.value(), [](Thread* thread) {
|
|
||||||
thread->send_signal(SIGINT);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
is_special_character = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.letter == m_settings.c_cc[VQUIT])
|
|
||||||
{
|
|
||||||
if (!(m_settings.c_lflag & NOFLSH)) m_line_buffer.clear();
|
|
||||||
|
|
||||||
// FIXME: Send SIGINT.
|
|
||||||
/*if (m_foreground_process_group.has_value())
|
|
||||||
{
|
|
||||||
Scheduler::for_each_in_process_group(m_foreground_process_group.value(), [](Thread* thread) {
|
|
||||||
thread->send_signal(SIGQUIT);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
is_special_character = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_special_character)
|
|
||||||
{
|
|
||||||
if (/*is_canonical()*/ true)
|
|
||||||
{
|
|
||||||
m_line_buffer.try_append((u8)request.letter);
|
|
||||||
|
|
||||||
if (request.letter == '\n')
|
|
||||||
{
|
|
||||||
write(m_pty, m_line_buffer.data(), m_line_buffer.size());
|
|
||||||
m_line_buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
write(m_pty, &request.letter, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(m_settings.c_lflag & ECHO)) return ui::EventResult::DidHandle;
|
|
||||||
|
|
||||||
if (_iscntrl(request.letter))
|
|
||||||
{
|
|
||||||
if (m_settings.c_lflag & ECHOCTL)
|
|
||||||
{
|
|
||||||
bool should_echo = true;
|
|
||||||
if (request.letter == '\n' || request.letter == '\t' || request.letter == '\0' ||
|
|
||||||
request.letter == m_settings.c_cc[VEOF])
|
|
||||||
should_echo = false;
|
|
||||||
|
|
||||||
if (should_echo)
|
|
||||||
{
|
|
||||||
char caret_notation[3] = { '^', '\0', '\0' };
|
|
||||||
if (request.letter == 0x7f) caret_notation[1] = '?';
|
|
||||||
else
|
|
||||||
caret_notation[1] = request.letter + 0x40;
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) { putchar(caret_notation[i]); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
putchar(request.letter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
putchar(request.letter);
|
|
||||||
|
|
||||||
ui::App::the().main_window()->draw();
|
|
||||||
|
|
||||||
return ui::EventResult::DidHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> TerminalWidget::draw(ui::Canvas& canvas)
|
Result<void> TerminalWidget::draw(ui::Canvas& canvas)
|
||||||
{
|
{
|
||||||
canvas.fill((u32*)m_terminal_canvas.ptr, m_terminal_canvas.stride);
|
canvas.fill((u32*)m_terminal_canvas.ptr, m_terminal_canvas.stride);
|
||||||
@ -211,14 +89,14 @@ Result<void> TerminalWidget::draw(ui::Canvas& canvas)
|
|||||||
Result<void> TerminalWidget::process()
|
Result<void> TerminalWidget::process()
|
||||||
{
|
{
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
ssize_t nread = read(m_pty, buffer, BUFSIZ);
|
ssize_t nread = read(m_read_fd, buffer, BUFSIZ);
|
||||||
if (nread < 0)
|
if (nread < 0)
|
||||||
{
|
{
|
||||||
if (errno == EAGAIN) return {};
|
if (errno == EAGAIN) return {};
|
||||||
return err(errno);
|
return err(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_termios();
|
os::eprintln("terminal: read %zd characters, processing...", nread);
|
||||||
|
|
||||||
for (ssize_t i = 0; i < nread; i++) TRY(putchar(buffer[i]));
|
for (ssize_t i = 0; i < nread; i++) TRY(putchar(buffer[i]));
|
||||||
|
|
||||||
@ -227,11 +105,6 @@ Result<void> TerminalWidget::process()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::query_termios()
|
|
||||||
{
|
|
||||||
tcgetattr(m_pty, &m_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerminalWidget::draw_glyph(wchar_t c, int x, int y)
|
void TerminalWidget::draw_glyph(wchar_t c, int x, int y)
|
||||||
{
|
{
|
||||||
auto subcanvas = m_terminal_canvas.subcanvas({ x, y, m_font->width(), m_font->height() });
|
auto subcanvas = m_terminal_canvas.subcanvas({ x, y, m_font->width(), m_font->height() });
|
||||||
@ -241,7 +114,7 @@ void TerminalWidget::draw_glyph(wchar_t c, int x, int y)
|
|||||||
|
|
||||||
void TerminalWidget::erase_current_line()
|
void TerminalWidget::erase_current_line()
|
||||||
{
|
{
|
||||||
m_terminal_canvas.subcanvas({ 0, m_y_position, m_rect.width, m_font->height() }).fill(ui::BLACK);
|
m_terminal_canvas.subcanvas({ 0, m_y_position, m_rect.width, m_font->height() });
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::scroll()
|
void TerminalWidget::scroll()
|
||||||
@ -270,7 +143,7 @@ void TerminalWidget::next_char()
|
|||||||
|
|
||||||
void TerminalWidget::prev_char()
|
void TerminalWidget::prev_char()
|
||||||
{
|
{
|
||||||
m_x_position -= m_font->width();
|
m_y_position -= m_font->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::erase_current_char()
|
void TerminalWidget::erase_current_char()
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include <luna/Utf8.h>
|
#include <luna/Utf8.h>
|
||||||
#include <luna/Vector.h>
|
#include <luna/Vector.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <termios.h>
|
|
||||||
#include <ui/Font.h>
|
#include <ui/Font.h>
|
||||||
#include <ui/Widget.h>
|
#include <ui/Widget.h>
|
||||||
|
|
||||||
@ -12,8 +11,6 @@ class TerminalWidget : public ui::Widget
|
|||||||
public:
|
public:
|
||||||
Result<void> init(char* const* args);
|
Result<void> init(char* const* args);
|
||||||
|
|
||||||
Result<ui::EventResult> handle_key_event(const ui::KeyEventRequest& request) override;
|
|
||||||
|
|
||||||
Result<void> draw(ui::Canvas& canvas) override;
|
Result<void> draw(ui::Canvas& canvas) override;
|
||||||
|
|
||||||
Result<void> process();
|
Result<void> process();
|
||||||
@ -23,11 +20,10 @@ class TerminalWidget : public ui::Widget
|
|||||||
private:
|
private:
|
||||||
ui::Canvas m_terminal_canvas;
|
ui::Canvas m_terminal_canvas;
|
||||||
Vector<u8> m_line_buffer;
|
Vector<u8> m_line_buffer;
|
||||||
int m_pty;
|
int m_write_fd;
|
||||||
|
int m_read_fd;
|
||||||
pid_t m_child_pid;
|
pid_t m_child_pid;
|
||||||
|
|
||||||
struct termios m_settings;
|
|
||||||
|
|
||||||
SharedPtr<ui::Font> m_font;
|
SharedPtr<ui::Font> m_font;
|
||||||
SharedPtr<ui::Font> m_bold_font;
|
SharedPtr<ui::Font> m_bold_font;
|
||||||
|
|
||||||
@ -45,8 +41,6 @@ class TerminalWidget : public ui::Widget
|
|||||||
ui::Color m_foreground_color { ui::WHITE };
|
ui::Color m_foreground_color { ui::WHITE };
|
||||||
ui::Color m_background_color { ui::BLACK };
|
ui::Color m_background_color { ui::BLACK };
|
||||||
|
|
||||||
void query_termios();
|
|
||||||
|
|
||||||
Utf8StateDecoder m_decoder;
|
Utf8StateDecoder m_decoder;
|
||||||
Option<EscapeSequenceParser> m_escape_parser;
|
Option<EscapeSequenceParser> m_escape_parser;
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "TerminalWidget.h"
|
#include "TerminalWidget.h"
|
||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <ui/App.h>
|
#include <ui/App.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@ -9,7 +8,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
TRY(app.init(argc, argv));
|
TRY(app.init(argc, argv));
|
||||||
app.set_nonblocking();
|
app.set_nonblocking();
|
||||||
|
|
||||||
auto* window = TRY(ui::Window::create(ui::Rect { 150, 150, 640, 400 }));
|
auto* window = TRY(ui::Window::create(ui::Rect { 150, 150, 500, 300 }));
|
||||||
app.set_main_window(window);
|
app.set_main_window(window);
|
||||||
window->set_background(ui::BLACK);
|
window->set_background(ui::BLACK);
|
||||||
window->set_title("Terminal");
|
window->set_title("Terminal");
|
||||||
@ -17,16 +16,12 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
TerminalWidget terminal;
|
TerminalWidget terminal;
|
||||||
window->set_main_widget(terminal);
|
window->set_main_widget(terminal);
|
||||||
|
|
||||||
char* args[] = { "/bin/sh", nullptr };
|
char* args[] = { "/bin/sh", "-i", nullptr };
|
||||||
TRY(terminal.init(args));
|
TRY(terminal.init(args));
|
||||||
|
|
||||||
window->draw();
|
window->draw();
|
||||||
|
|
||||||
while (app.process_events())
|
while (app.process_events()) TRY(terminal.process());
|
||||||
{
|
|
||||||
TRY(terminal.process());
|
|
||||||
usleep(10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
terminal.quit();
|
terminal.quit();
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ set(SOURCES
|
|||||||
Window.cpp
|
Window.cpp
|
||||||
IPC.cpp
|
IPC.cpp
|
||||||
IPC.h
|
IPC.h
|
||||||
Keyboard.cpp
|
|
||||||
Keyboard.h
|
|
||||||
Client.h
|
Client.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "IPC.h"
|
#include "IPC.h"
|
||||||
#include "Mouse.h"
|
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include <luna/Alignment.h>
|
#include <luna/Alignment.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
@ -130,7 +129,6 @@ static Result<void> handle_close_window_message(Client& client)
|
|||||||
auto* window = client.windows[request.window];
|
auto* window = client.windows[request.window];
|
||||||
client.windows[request.window] = nullptr;
|
client.windows[request.window] = nullptr;
|
||||||
g_windows.remove(window);
|
g_windows.remove(window);
|
||||||
Mouse::the().window_did_close(window);
|
|
||||||
delete window;
|
delete window;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -1,305 +0,0 @@
|
|||||||
#include "Keyboard.h"
|
|
||||||
#include <luna/CType.h>
|
|
||||||
|
|
||||||
static const char table[] = {
|
|
||||||
// Function keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// System keys
|
|
||||||
'\x1b',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Modifier keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0', // or AltGr on some keyboards
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Navigation keys
|
|
||||||
'\t',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Editing keys
|
|
||||||
'\b',
|
|
||||||
'\n',
|
|
||||||
'\0',
|
|
||||||
'\x7f',
|
|
||||||
'\n',
|
|
||||||
// Lock keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Keypad keys
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9',
|
|
||||||
'.',
|
|
||||||
'+',
|
|
||||||
'-',
|
|
||||||
'*',
|
|
||||||
'/',
|
|
||||||
// Character keys (depending on keyboard layout), examples in US QWERTY
|
|
||||||
'`', // `
|
|
||||||
'1', // 1
|
|
||||||
'2', // 2
|
|
||||||
'3', // 3
|
|
||||||
'4', // 4
|
|
||||||
'5', // 5
|
|
||||||
'6', // 6
|
|
||||||
'7', // 7
|
|
||||||
'8', // 8
|
|
||||||
'9', // 9
|
|
||||||
'0', // 0
|
|
||||||
'-', // -
|
|
||||||
'=', // =
|
|
||||||
'q', // Q
|
|
||||||
'w', // W
|
|
||||||
'e', // E
|
|
||||||
'r', // R
|
|
||||||
't', // T
|
|
||||||
'y', // Y
|
|
||||||
'u', // U
|
|
||||||
'i', // I
|
|
||||||
'o', // O
|
|
||||||
'p', // P
|
|
||||||
'[', // [
|
|
||||||
']', // ]
|
|
||||||
'a', // A
|
|
||||||
's', // S
|
|
||||||
'd', // D
|
|
||||||
'f', // F
|
|
||||||
'g', // G
|
|
||||||
'h', // H
|
|
||||||
'j', // J
|
|
||||||
'k', // K
|
|
||||||
'l', // L
|
|
||||||
';', // ;
|
|
||||||
'\'', // '
|
|
||||||
'#', // #
|
|
||||||
'\\', // Backslash
|
|
||||||
'z', // Z
|
|
||||||
'x', // X
|
|
||||||
'c', // C
|
|
||||||
'v', // V
|
|
||||||
'b', // B
|
|
||||||
'n', // N
|
|
||||||
'm', // M
|
|
||||||
',', // ,
|
|
||||||
'.', // .
|
|
||||||
'/', // /
|
|
||||||
' ', // Space
|
|
||||||
// Unknown key
|
|
||||||
'\0',
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char shift_table[] = {
|
|
||||||
// Function keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// System keys
|
|
||||||
'\x1b',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Modifier keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0', // or AltGr on some keyboards
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Navigation keys
|
|
||||||
'\t',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Editing keys
|
|
||||||
'\b',
|
|
||||||
'\n',
|
|
||||||
'\0',
|
|
||||||
'\x7f',
|
|
||||||
'\n',
|
|
||||||
// Lock keys
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
'\0',
|
|
||||||
// Keypad keys
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9',
|
|
||||||
'.',
|
|
||||||
'+',
|
|
||||||
'-',
|
|
||||||
'*',
|
|
||||||
'/',
|
|
||||||
// Character keys (depending on keyboard layout), examples in US QWERTY
|
|
||||||
'~', // `
|
|
||||||
'!',
|
|
||||||
'@',
|
|
||||||
'#',
|
|
||||||
'$',
|
|
||||||
'%',
|
|
||||||
'^',
|
|
||||||
'&',
|
|
||||||
'*',
|
|
||||||
'(',
|
|
||||||
')',
|
|
||||||
'_',
|
|
||||||
'+',
|
|
||||||
'Q',
|
|
||||||
'W',
|
|
||||||
'E',
|
|
||||||
'R',
|
|
||||||
'T',
|
|
||||||
'Y',
|
|
||||||
'U',
|
|
||||||
'I',
|
|
||||||
'O',
|
|
||||||
'P',
|
|
||||||
'{',
|
|
||||||
'}',
|
|
||||||
'A',
|
|
||||||
'S',
|
|
||||||
'D',
|
|
||||||
'F',
|
|
||||||
'G',
|
|
||||||
'H',
|
|
||||||
'J',
|
|
||||||
'K',
|
|
||||||
'L',
|
|
||||||
':',
|
|
||||||
'"',
|
|
||||||
' ', // #
|
|
||||||
'|', // Backslash
|
|
||||||
'Z',
|
|
||||||
'X',
|
|
||||||
'C',
|
|
||||||
'V',
|
|
||||||
'B',
|
|
||||||
'N',
|
|
||||||
'M',
|
|
||||||
'<',
|
|
||||||
'>',
|
|
||||||
'?',
|
|
||||||
' ', // Space
|
|
||||||
// Unknown key
|
|
||||||
'\0',
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace wind::Keyboard
|
|
||||||
{
|
|
||||||
static bool g_caps_lock = false;
|
|
||||||
static bool g_right_shift = false;
|
|
||||||
static bool g_left_shift = false;
|
|
||||||
static bool g_right_control = false;
|
|
||||||
static bool g_left_control = false;
|
|
||||||
static bool g_altgr = false;
|
|
||||||
static bool g_alt = false;
|
|
||||||
static bool g_super = false;
|
|
||||||
|
|
||||||
ui::KeyEventRequest decode_keyboard_event(moon::KeyCode code, bool released)
|
|
||||||
{
|
|
||||||
ui::KeyEventRequest request;
|
|
||||||
request.code = code;
|
|
||||||
request.pressed = !released;
|
|
||||||
request.modifiers = 0;
|
|
||||||
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case moon::K_CapsLock:
|
|
||||||
if (!released) { g_caps_lock = !g_caps_lock; }
|
|
||||||
break;
|
|
||||||
case moon::K_RightShift: g_right_shift = !released; break;
|
|
||||||
case moon::K_LeftShift: g_left_shift = !released; break;
|
|
||||||
case moon::K_RightControl: g_right_control = !released; break;
|
|
||||||
case moon::K_LeftControl: g_left_control = !released; break;
|
|
||||||
case moon::K_RightAlt: g_altgr = !released; break;
|
|
||||||
case moon::K_LeftAlt: g_alt = !released; break;
|
|
||||||
case moon::K_Super: g_super = !released; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((g_caps_lock && !(g_left_shift || g_right_shift)) || (g_left_shift || g_right_shift))
|
|
||||||
{
|
|
||||||
request.modifiers |= ui::Mod_Shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_right_control || g_left_control) request.modifiers |= ui::Mod_Ctrl;
|
|
||||||
|
|
||||||
if (g_alt) request.modifiers |= ui::Mod_Alt;
|
|
||||||
if (g_altgr) request.modifiers |= ui::Mod_AltGr;
|
|
||||||
if (g_super) request.modifiers |= ui::Mod_Super;
|
|
||||||
|
|
||||||
request.key = table[code];
|
|
||||||
|
|
||||||
if (request.modifiers & ui::Mod_Ctrl)
|
|
||||||
{
|
|
||||||
char letter;
|
|
||||||
if (request.modifiers & ui::Mod_Shift) letter = shift_table[code];
|
|
||||||
else
|
|
||||||
letter = table[code];
|
|
||||||
if (_islower(letter)) letter = (char)_toupper(letter);
|
|
||||||
if (_isupper(letter)) letter = 0x40;
|
|
||||||
if (letter == '@') letter = 0x40;
|
|
||||||
if (letter > 'Z' && letter < '`') letter = 0x40;
|
|
||||||
if (letter == '?') letter = 0x7f;
|
|
||||||
request.letter = letter;
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.modifiers & ui::Mod_Shift) request.letter = shift_table[code];
|
|
||||||
else
|
|
||||||
request.letter = table[code];
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <ui/ipc/Client.h>
|
|
||||||
|
|
||||||
namespace wind
|
|
||||||
{
|
|
||||||
namespace Keyboard
|
|
||||||
{
|
|
||||||
ui::KeyEventRequest decode_keyboard_event(moon::KeyCode code, bool released);
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
static SharedPtr<ui::Image> g_mouse_cursor;
|
static SharedPtr<ui::Image> g_mouse_cursor;
|
||||||
|
|
||||||
static Mouse* s_mouse;
|
|
||||||
|
|
||||||
Mouse::Mouse(ui::Canvas& screen)
|
Mouse::Mouse(ui::Canvas& screen)
|
||||||
{
|
{
|
||||||
m_position.x = screen.width / 2;
|
m_position.x = screen.width / 2;
|
||||||
@ -16,14 +14,6 @@ Mouse::Mouse(ui::Canvas& screen)
|
|||||||
m_screen_rect = screen.rect();
|
m_screen_rect = screen.rect();
|
||||||
|
|
||||||
g_mouse_cursor = ui::Image::load("/usr/share/cursors/default.tga").value_or({});
|
g_mouse_cursor = ui::Image::load("/usr/share/cursors/default.tga").value_or({});
|
||||||
|
|
||||||
s_mouse = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mouse& Mouse::the()
|
|
||||||
{
|
|
||||||
check(s_mouse);
|
|
||||||
return *s_mouse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::draw(ui::Canvas& screen)
|
void Mouse::draw(ui::Canvas& screen)
|
||||||
@ -120,10 +110,3 @@ void Mouse::update(const moon::MousePacket& packet)
|
|||||||
m_active_window = new_active_window;
|
m_active_window = new_active_window;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::window_did_close(Window* window)
|
|
||||||
{
|
|
||||||
if (m_dragging_window == window) { m_dragging_window = nullptr; }
|
|
||||||
|
|
||||||
if (m_active_window == window) { m_active_window = nullptr; }
|
|
||||||
}
|
|
||||||
|
@ -13,10 +13,6 @@ class Mouse
|
|||||||
|
|
||||||
void draw(ui::Canvas& screen);
|
void draw(ui::Canvas& screen);
|
||||||
|
|
||||||
void window_did_close(Window* window);
|
|
||||||
|
|
||||||
static Mouse& the();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ui::Point m_position;
|
ui::Point m_position;
|
||||||
ui::Rect m_screen_rect;
|
ui::Rect m_screen_rect;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#define CLIENT_IMPLEMENTATION
|
#define CLIENT_IMPLEMENTATION
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "IPC.h"
|
#include "IPC.h"
|
||||||
#include "Keyboard.h"
|
|
||||||
#include "Mouse.h"
|
#include "Mouse.h"
|
||||||
#include "Screen.h"
|
#include "Screen.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
@ -156,14 +155,8 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
moon::KeyboardPacket packet;
|
moon::KeyboardPacket packet;
|
||||||
TRY(keyboard->read_typed(packet));
|
TRY(keyboard->read_typed(packet));
|
||||||
|
os::println("%s key %d", packet.released ? "Released" : "Pressed", packet.key);
|
||||||
if (!packet.released && packet.key == moon::K_Tab) debug(clients);
|
if (!packet.released && packet.key == moon::K_Tab) debug(clients);
|
||||||
auto request = wind::Keyboard::decode_keyboard_event((moon::KeyCode)packet.key, packet.released);
|
|
||||||
if (g_windows.last().has_value())
|
|
||||||
{
|
|
||||||
auto* window = g_windows.last().value();
|
|
||||||
request.window = window->id;
|
|
||||||
os::IPC::send_async(window->client->conn, request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (usize i = 0; i < clients.size(); i++)
|
for (usize i = 0; i < clients.size(); i++)
|
||||||
{
|
{
|
||||||
@ -179,7 +172,6 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
if (window)
|
if (window)
|
||||||
{
|
{
|
||||||
g_windows.remove(window);
|
g_windows.remove(window);
|
||||||
mouse_pointer.window_did_close(window);
|
|
||||||
delete window;
|
delete window;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user