Compare commits
4 Commits
b01aa72f17
...
5c96a31cd8
Author | SHA1 | Date | |
---|---|---|---|
5c96a31cd8 | |||
07a1811102 | |||
8f170ff1f0 | |||
7076ff2f6b |
@ -45,8 +45,10 @@ endif()
|
|||||||
|
|
||||||
add_subdirectory(libluna)
|
add_subdirectory(libluna)
|
||||||
add_subdirectory(libos)
|
add_subdirectory(libos)
|
||||||
|
add_subdirectory(libui)
|
||||||
add_subdirectory(libc)
|
add_subdirectory(libc)
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
add_subdirectory(apps)
|
add_subdirectory(apps)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
add_subdirectory(shell)
|
add_subdirectory(shell)
|
||||||
|
add_subdirectory(wind)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Name=login
|
Name=login
|
||||||
Description=Start the command-line login program.
|
Description=Start the display server.
|
||||||
Command=/usr/bin/login
|
Command=/usr/bin/wind --user=selene
|
||||||
Restart=true
|
Restart=true
|
||||||
|
@ -43,8 +43,8 @@ static void process_mouse_event(u8 data)
|
|||||||
packet.buttons = 0;
|
packet.buttons = 0;
|
||||||
|
|
||||||
u8 flags = g_mouse_packet[0];
|
u8 flags = g_mouse_packet[0];
|
||||||
if (flags & PS2_MOUSE_X_SIGN) packet.xdelta = -packet.xdelta;
|
if (flags & PS2_MOUSE_X_SIGN) packet.xdelta = -(256 - packet.xdelta);
|
||||||
if (flags & PS2_MOUSE_Y_SIGN) packet.ydelta = -packet.ydelta;
|
if (flags & PS2_MOUSE_Y_SIGN) packet.ydelta = -(256 - packet.ydelta);
|
||||||
|
|
||||||
if (flags & PS2_MOUSE_MIDDLE_BTN) packet.buttons |= moon::MouseButton::Middle;
|
if (flags & PS2_MOUSE_MIDDLE_BTN) packet.buttons |= moon::MouseButton::Middle;
|
||||||
if (flags & PS2_MOUSE_RIGHT_BTN) packet.buttons |= moon::MouseButton::Right;
|
if (flags & PS2_MOUSE_RIGHT_BTN) packet.buttons |= moon::MouseButton::Right;
|
||||||
|
15
libui/CMakeLists.txt
Normal file
15
libui/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# The UI and graphics library for Luna.
|
||||||
|
|
||||||
|
file(GLOB HEADERS include/ui/*.h)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
${HEADERS}
|
||||||
|
src/Canvas.cpp
|
||||||
|
src/Color.cpp
|
||||||
|
src/Rect.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(ui ${SOURCES})
|
||||||
|
target_compile_options(ui PRIVATE ${COMMON_FLAGS})
|
||||||
|
target_include_directories(ui PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/)
|
||||||
|
target_include_directories(ui PUBLIC ${LUNA_BASE}/usr/include)
|
30
libui/include/ui/Canvas.h
Normal file
30
libui/include/ui/Canvas.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Result.h>
|
||||||
|
#include <luna/Types.h>
|
||||||
|
#include <ui/Color.h>
|
||||||
|
#include <ui/Point.h>
|
||||||
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A drawable surface.
|
||||||
|
*/
|
||||||
|
struct Canvas
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int stride;
|
||||||
|
u8* ptr;
|
||||||
|
|
||||||
|
static Canvas create(u8* ptr, int width, int height);
|
||||||
|
Result<Canvas> subcanvas(Point begin, int width, int height, bool clamp);
|
||||||
|
|
||||||
|
Rect rect()
|
||||||
|
{
|
||||||
|
return Rect { .begin = { 0, 0 }, .width = width, .height = height };
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill(Color color);
|
||||||
|
};
|
||||||
|
};
|
34
libui/include/ui/Color.h
Normal file
34
libui/include/ui/Color.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Types.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A 32-bit RGBA color.
|
||||||
|
*/
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
u32 raw;
|
||||||
|
u8 colors[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Color from_u32(u32 raw)
|
||||||
|
{
|
||||||
|
return Color { .raw = raw };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Color from_rgba(u8 red, u8 green, u8 blue, u8 alpha)
|
||||||
|
{
|
||||||
|
return Color { .colors = { blue, green, red, alpha } };
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Color from_rgb(u8 red, u8 green, u8 blue)
|
||||||
|
{
|
||||||
|
return from_rgba(red, green, blue, 0xff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Color WHITE = Color::from_rgb(0xff, 0xff, 0xff);
|
||||||
|
static constexpr Color BLACK = Color::from_rgb(0x00, 0x00, 0x00);
|
||||||
|
};
|
13
libui/include/ui/Point.h
Normal file
13
libui/include/ui/Point.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A point in 2D space.
|
||||||
|
*/
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
int x { 0 };
|
||||||
|
int y { 0 };
|
||||||
|
};
|
||||||
|
}
|
18
libui/include/ui/Rect.h
Normal file
18
libui/include/ui/Rect.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <ui/Point.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A simple rectangle.
|
||||||
|
*/
|
||||||
|
struct Rect
|
||||||
|
{
|
||||||
|
Point begin;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
bool contains(Point point);
|
||||||
|
Point normalize(Point point);
|
||||||
|
};
|
||||||
|
}
|
43
libui/src/Canvas.cpp
Normal file
43
libui/src/Canvas.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <ui/Canvas.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
Canvas Canvas::create(u8* ptr, int width, int height)
|
||||||
|
{
|
||||||
|
return Canvas { .width = width, .height = height, .stride = width, .ptr = ptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Canvas> Canvas::subcanvas(Point begin, int w, int h, bool clamp)
|
||||||
|
{
|
||||||
|
if (!clamp)
|
||||||
|
{
|
||||||
|
if (begin.x + w > width) return err(ERANGE);
|
||||||
|
if (begin.y + h > height) return err(ERANGE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (begin.x + w > width) w = width - begin.x;
|
||||||
|
if (begin.y + h > height) h = height - begin.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* p = ptr + begin.x * sizeof(Color) + (begin.y * sizeof(Color) * stride);
|
||||||
|
|
||||||
|
return Canvas { .width = w, .height = h, .stride = stride, .ptr = p };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::fill(Color color)
|
||||||
|
{
|
||||||
|
u8* p = ptr;
|
||||||
|
for (int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
u32* colorp = (u32*)p;
|
||||||
|
for (int j = 0; j < width; j++)
|
||||||
|
{
|
||||||
|
*colorp = color.raw;
|
||||||
|
colorp++;
|
||||||
|
}
|
||||||
|
p += stride * sizeof(Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
libui/src/Color.cpp
Normal file
0
libui/src/Color.cpp
Normal file
18
libui/src/Rect.cpp
Normal file
18
libui/src/Rect.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <ui/Rect.h>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
bool Rect::contains(Point point)
|
||||||
|
{
|
||||||
|
return point.x >= begin.x && point.y >= begin.y && point.x <= begin.x + width && point.y <= begin.y + height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point Rect::normalize(Point point)
|
||||||
|
{
|
||||||
|
if (point.x < begin.x) point.x = begin.x;
|
||||||
|
if (point.y < begin.y) point.y = begin.y;
|
||||||
|
if (point.x > begin.x + width) point.x = begin.x + width;
|
||||||
|
if (point.y > begin.y + height) point.y = begin.y + height;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
};
|
@ -8,10 +8,12 @@ cd $LUNA_ROOT
|
|||||||
mkdir -p $LUNA_BASE
|
mkdir -p $LUNA_BASE
|
||||||
mkdir -p $LUNA_BASE/usr/include
|
mkdir -p $LUNA_BASE/usr/include
|
||||||
mkdir -p $LUNA_BASE/usr/include/luna
|
mkdir -p $LUNA_BASE/usr/include/luna
|
||||||
|
mkdir -p $LUNA_BASE/usr/include/ui
|
||||||
mkdir -p $LUNA_BASE/usr/include/os
|
mkdir -p $LUNA_BASE/usr/include/os
|
||||||
mkdir -p $LUNA_BASE/usr/include/moon
|
mkdir -p $LUNA_BASE/usr/include/moon
|
||||||
|
|
||||||
cp --preserve=timestamps -RT libc/include/ $LUNA_BASE/usr/include
|
cp --preserve=timestamps -RT libc/include/ $LUNA_BASE/usr/include
|
||||||
cp --preserve=timestamps -RT libluna/include/luna/ $LUNA_BASE/usr/include/luna
|
cp --preserve=timestamps -RT libluna/include/luna/ $LUNA_BASE/usr/include/luna
|
||||||
|
cp --preserve=timestamps -RT libui/include/ui/ $LUNA_BASE/usr/include/ui
|
||||||
cp --preserve=timestamps -RT libos/include/os/ $LUNA_BASE/usr/include/os
|
cp --preserve=timestamps -RT libos/include/os/ $LUNA_BASE/usr/include/os
|
||||||
cp --preserve=timestamps -RT kernel/src/api/ $LUNA_BASE/usr/include/moon
|
cp --preserve=timestamps -RT kernel/src/api/ $LUNA_BASE/usr/include/moon
|
||||||
|
@ -4,7 +4,7 @@ source $(dirname $0)/env.sh
|
|||||||
|
|
||||||
cd $LUNA_ROOT
|
cd $LUNA_ROOT
|
||||||
|
|
||||||
FOLDERS=(kernel libc libos libluna apps shell tests)
|
FOLDERS=(kernel libc libos libui libluna apps shell tests)
|
||||||
|
|
||||||
SOURCES=($(find ${FOLDERS[@]} -type f -name "*.cpp"))
|
SOURCES=($(find ${FOLDERS[@]} -type f -name "*.cpp"))
|
||||||
SOURCES+=($(find ${FOLDERS[@]} -type f -name "*.h"))
|
SOURCES+=($(find ${FOLDERS[@]} -type f -name "*.h"))
|
||||||
|
14
wind/CMakeLists.txt
Normal file
14
wind/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
set(SOURCES
|
||||||
|
main.cpp
|
||||||
|
Screen.h
|
||||||
|
Screen.cpp
|
||||||
|
Mouse.h
|
||||||
|
Mouse.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(wind ${SOURCES})
|
||||||
|
target_compile_options(wind PRIVATE -Os ${COMMON_FLAGS} -Wno-write-strings)
|
||||||
|
add_dependencies(wind libc)
|
||||||
|
target_include_directories(wind PRIVATE ${LUNA_BASE}/usr/include ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
target_link_libraries(wind PRIVATE os ui)
|
||||||
|
install(TARGETS wind DESTINATION ${LUNA_BASE}/usr/bin)
|
21
wind/Mouse.cpp
Normal file
21
wind/Mouse.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "Mouse.h"
|
||||||
|
|
||||||
|
Mouse::Mouse(ui::Canvas& screen)
|
||||||
|
{
|
||||||
|
m_position.x = screen.width / 2;
|
||||||
|
m_position.y = screen.height / 2;
|
||||||
|
m_screen_rect = screen.rect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::draw(ui::Canvas& screen)
|
||||||
|
{
|
||||||
|
auto canvas = screen.subcanvas(m_position, 10, 10, true).release_value();
|
||||||
|
canvas.fill(ui::WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::move(const moon::MousePacket& packet)
|
||||||
|
{
|
||||||
|
m_position.x += packet.xdelta;
|
||||||
|
m_position.y -= packet.ydelta;
|
||||||
|
m_position = m_screen_rect.normalize(m_position);
|
||||||
|
}
|
18
wind/Mouse.h
Normal file
18
wind/Mouse.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Screen.h"
|
||||||
|
#include <moon/Mouse.h>
|
||||||
|
#include <ui/Canvas.h>
|
||||||
|
|
||||||
|
class Mouse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mouse(ui::Canvas& screen);
|
||||||
|
|
||||||
|
void move(const moon::MousePacket& packet);
|
||||||
|
|
||||||
|
void draw(ui::Canvas& screen);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ui::Point m_position;
|
||||||
|
ui::Rect m_screen_rect;
|
||||||
|
};
|
34
wind/Screen.cpp
Normal file
34
wind/Screen.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "Screen.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
Result<Screen> Screen::open()
|
||||||
|
{
|
||||||
|
int fd = ::open("/dev/fb0", O_RDWR | O_CLOEXEC);
|
||||||
|
if (fd < 0) return err(errno);
|
||||||
|
|
||||||
|
int width = ioctl(fd, FB_GET_WIDTH);
|
||||||
|
int height = ioctl(fd, FB_GET_HEIGHT);
|
||||||
|
|
||||||
|
void* p = mmap(nullptr, width * height * BYTES_PER_PIXEL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (p == MAP_FAILED)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return err(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen screen;
|
||||||
|
|
||||||
|
screen.m_canvas = ui::Canvas::create((u8*)p, width, height);
|
||||||
|
screen.m_size = width * height * BYTES_PER_PIXEL;
|
||||||
|
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::sync()
|
||||||
|
{
|
||||||
|
msync(m_canvas.ptr, size(), MS_SYNC);
|
||||||
|
}
|
27
wind/Screen.h
Normal file
27
wind/Screen.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/OwnedPtr.h>
|
||||||
|
#include <ui/Canvas.h>
|
||||||
|
|
||||||
|
constexpr int BYTES_PER_PIXEL = 4;
|
||||||
|
|
||||||
|
class Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Result<Screen> open();
|
||||||
|
|
||||||
|
ui::Canvas& canvas()
|
||||||
|
{
|
||||||
|
return m_canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ui::Canvas m_canvas;
|
||||||
|
int m_size;
|
||||||
|
};
|
98
wind/main.cpp
Normal file
98
wind/main.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "Mouse.h"
|
||||||
|
#include "Screen.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <moon/Keyboard.h>
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <os/File.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
Result<int> luna_main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
StringView socket_path = "/tmp/wind.sock";
|
||||||
|
StringView user;
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.add_description("The display server for Luna's graphical user interface."_sv);
|
||||||
|
parser.add_system_program_info("wind"_sv);
|
||||||
|
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
|
||||||
|
parser.add_value_argument(user, 'u', "user"_sv, "the user to run as"_sv);
|
||||||
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
if (geteuid() != 0)
|
||||||
|
{
|
||||||
|
os::eprintln("error: wind must be run as root to initialize resources, run with --user=<USERNAME> to drop "
|
||||||
|
"privileges afterwards");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
|
||||||
|
mouse->set_buffer(os::File::NotBuffered);
|
||||||
|
mouse->set_close_on_exec();
|
||||||
|
|
||||||
|
auto keyboard = TRY(os::File::open("/dev/kbd", os::File::ReadOnly));
|
||||||
|
keyboard->set_buffer(os::File::NotBuffered);
|
||||||
|
keyboard->set_close_on_exec();
|
||||||
|
|
||||||
|
auto screen = TRY(Screen::open());
|
||||||
|
|
||||||
|
Mouse mouse_pointer { screen.canvas() };
|
||||||
|
|
||||||
|
ioctl(STDIN_FILENO, TTYSETGFX, 1);
|
||||||
|
|
||||||
|
setpgid(0, 0);
|
||||||
|
|
||||||
|
int fd = open("/dev/null", O_RDONLY);
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
dup2(fd, STDIN_FILENO);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearenv();
|
||||||
|
|
||||||
|
if (!user.is_empty())
|
||||||
|
{
|
||||||
|
auto* pwd = getpwnam(user.chars());
|
||||||
|
if (pwd)
|
||||||
|
{
|
||||||
|
setgid(pwd->pw_gid);
|
||||||
|
setuid(pwd->pw_uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::Color background = ui::BLACK;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
struct pollfd fds[] = {
|
||||||
|
{ .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
|
||||||
|
{ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
int rc = poll(fds, 2, 1000);
|
||||||
|
if (!rc) continue;
|
||||||
|
if (rc < 0) { os::println("poll: error: %s", strerror(errno)); }
|
||||||
|
|
||||||
|
if (fds[0].revents & POLLIN)
|
||||||
|
{
|
||||||
|
moon::MousePacket packet;
|
||||||
|
TRY(mouse->read_typed(packet));
|
||||||
|
mouse_pointer.move(packet);
|
||||||
|
}
|
||||||
|
if (fds[1].revents & POLLIN)
|
||||||
|
{
|
||||||
|
moon::KeyboardPacket packet;
|
||||||
|
TRY(keyboard->read_typed(packet));
|
||||||
|
background = ui::Color::from_rgb(0x00, 0x00, packet.key * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.canvas().fill(background);
|
||||||
|
mouse_pointer.draw(screen.canvas());
|
||||||
|
screen.sync();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user