mirror of
https://github.com/johndoe6345789/SparkOS.git
synced 2026-04-24 13:34:56 +00:00
Implement Qt6 GUI with direct kernel interface, remove Unix user system
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
159
ARCHITECTURE.md
159
ARCHITECTURE.md
@@ -2,121 +2,88 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
SparkOS is designed as a minimal Linux distribution with a custom init system and a modular architecture that allows for future expansion.
|
SparkOS is a revolutionary operating system that uses the Linux kernel for hardware abstraction but ditches traditional Unix conventions. Instead of shells, users, and Unix utilities, SparkOS boots directly into a Qt6 GUI that interfaces with the kernel through standard Linux APIs.
|
||||||
|
|
||||||
## System Components
|
## Core Philosophy
|
||||||
|
|
||||||
### 1. Init System (`/sbin/init`)
|
1. **No Unix Baggage**: No user/group system, no shells, no Unix utilities by default
|
||||||
|
2. **Direct Kernel Interface**: GUI communicates directly with Linux kernel
|
||||||
|
3. **Network-First**: Networking is a primary interface, not an afterthought
|
||||||
|
4. **GUI-Only**: No CLI unless explicitly needed for debugging
|
||||||
|
5. **Linux for Drivers**: Leverage Linux's excellent hardware support
|
||||||
|
|
||||||
The init system is the first process started by the kernel (PID 1). It is responsible for:
|
## System Architecture
|
||||||
|
|
||||||
- **Mounting filesystems**: proc, sys, dev, tmp
|
|
||||||
- **Network initialization**: Bringing up wired networking via DHCP
|
|
||||||
- **Process management**: Spawning and respawning the shell
|
|
||||||
- **Signal handling**: Reaping zombie processes
|
|
||||||
- **System initialization**: Setting up the initial environment
|
|
||||||
|
|
||||||
**Implementation**: `src/init.c`
|
|
||||||
- Written in C for minimal overhead
|
|
||||||
- Statically linked for independence
|
|
||||||
- ~100 lines of clean, well-documented code
|
|
||||||
|
|
||||||
### 2. Root Filesystem
|
|
||||||
|
|
||||||
Follows the Filesystem Hierarchy Standard (FHS):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
/
|
Boot Sequence:
|
||||||
├── bin/ Essential user binaries (busybox with symlinks)
|
Hardware → UEFI/BIOS → GRUB → Linux Kernel → init (PID 1) → Qt6 GUI
|
||||||
├── sbin/ System binaries (init, mount, etc.)
|
|
||||||
├── etc/ System configuration files
|
|
||||||
├── proc/ Kernel process information (virtual)
|
|
||||||
├── sys/ Kernel system information (virtual)
|
|
||||||
├── dev/ Device files (virtual)
|
|
||||||
├── tmp/ Temporary files
|
|
||||||
├── usr/
|
|
||||||
│ ├── bin/ Non-essential user binaries
|
|
||||||
│ ├── sbin/ Non-essential system binaries
|
|
||||||
│ ├── lib/ Libraries for /usr/bin and /usr/sbin
|
|
||||||
│ └── lib64/ 64-bit libraries
|
|
||||||
├── var/ Variable data (logs, caches)
|
|
||||||
├── root/ Root user home directory
|
|
||||||
└── home/ User home directories
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Build System
|
Stack Layers:
|
||||||
|
┌──────────────────────────────────────────┐
|
||||||
**Makefile**: Main build orchestration
|
│ Qt6 GUI Application │ ← User Interface
|
||||||
- `make init`: Compile init system
|
│ (sparkos-gui executable) │
|
||||||
- `make install`: Install init to rootfs
|
├──────────────────────────────────────────┤
|
||||||
- `make image`: Create bootable image (requires root)
|
│ Custom Init System (PID 1) │ ← Process Manager
|
||||||
- `make clean`: Clean build artifacts
|
│ • Mounts filesystems │
|
||||||
|
│ • Spawns/respawns GUI │
|
||||||
**Scripts**:
|
│ • Reaps zombie processes │
|
||||||
- `scripts/build.sh`: Quick build for development
|
├──────────────────────────────────────────┤
|
||||||
- `scripts/setup_rootfs.sh`: Create rootfs structure
|
│ Linux Kernel │ ← Hardware Abstraction
|
||||||
- `scripts/create_image.sh`: Create dd-able disk image
|
│ • All device drivers │
|
||||||
|
│ • Framebuffer driver │
|
||||||
### 4. Boot Process
|
│ • Input device drivers │
|
||||||
|
│ • Network stack & drivers │
|
||||||
```
|
│ • File system support │
|
||||||
Hardware Power-On
|
├──────────────────────────────────────────┤
|
||||||
↓
|
│ Hardware │
|
||||||
BIOS/UEFI
|
│ • Display, GPU, Input │
|
||||||
↓
|
│ • Network adapters │
|
||||||
Bootloader (syslinux)
|
│ • Storage devices │
|
||||||
↓
|
└──────────────────────────────────────────┘
|
||||||
Linux Kernel (vmlinuz)
|
|
||||||
↓
|
|
||||||
Init System (/sbin/init) [PID 1]
|
|
||||||
↓
|
|
||||||
Mount filesystems
|
|
||||||
↓
|
|
||||||
Initialize network (/sbin/init-network)
|
|
||||||
↓
|
|
||||||
Spawn busybox sh shell
|
|
||||||
↓
|
|
||||||
User interaction
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Design Decisions
|
## Design Decisions
|
||||||
|
|
||||||
### Why Custom Init?
|
### Why Ditch Unix Conventions?
|
||||||
|
|
||||||
- **Simplicity**: No dependencies, easy to understand
|
Traditional Unix systems were designed for multi-user, time-sharing mainframes in the 1970s. Modern personal computing and embedded systems have different needs:
|
||||||
- **Control**: Full control over boot process
|
|
||||||
- **Size**: Minimal footprint (<1MB statically linked)
|
|
||||||
- **Learning**: Educational value for OS development
|
|
||||||
|
|
||||||
### Why Static Linking?
|
- **Single User**: Most devices have one user - authentication overhead is unnecessary
|
||||||
|
- **GUI Primary**: Modern users expect graphical interfaces, not command lines
|
||||||
|
- **Network Central**: Modern computing is network-centric, not file-centric
|
||||||
|
- **Direct Access**: Applications should talk directly to kernel, not through layers of abstraction
|
||||||
|
|
||||||
- **Independence**: No library dependencies
|
### Why Keep Linux Kernel?
|
||||||
- **Portability**: Works on any Linux system
|
|
||||||
- **Reliability**: No missing library issues
|
|
||||||
|
|
||||||
### Why Busybox?
|
- **Hardware Support**: Linux has exceptional driver support for modern hardware
|
||||||
|
- **Driver Abstraction**: Well-tested, stable hardware abstraction layer
|
||||||
|
- **Network Stack**: Robust, high-performance networking
|
||||||
|
- **File Systems**: Mature support for various filesystems
|
||||||
|
- **Security**: SELinux, namespaces, cgroups for isolation
|
||||||
|
- **Community**: Active development and security updates
|
||||||
|
|
||||||
- **Minimal**: Single binary provides dozens of utilities
|
### Why Qt6 GUI?
|
||||||
- **Small footprint**: Typically <1MB for full feature set
|
|
||||||
- **Efficient**: Less memory and storage overhead than full GNU coreutils
|
|
||||||
- **Standard**: De facto standard for embedded Linux systems
|
|
||||||
- **Networking**: Includes DHCP client (udhcpc), ping, wget, and network tools
|
|
||||||
|
|
||||||
### Networking Strategy
|
- **Cross-Platform**: Qt works on many platforms (future portability)
|
||||||
|
- **Framebuffer Support**: Can render directly to Linux framebuffer without X11/Wayland
|
||||||
|
- **Modern**: Native look and feel, hardware acceleration support
|
||||||
|
- **Complete**: Rich widget set, networking APIs, file I/O
|
||||||
|
- **Performant**: Efficient rendering and event handling
|
||||||
|
|
||||||
SparkOS uses a two-phase networking approach:
|
### Why No X11/Wayland?
|
||||||
|
|
||||||
**Phase 1: Bootstrap (Wired Only)**
|
- **Direct Rendering**: Qt can render directly to framebuffer (/dev/fb0)
|
||||||
- Wired networking configured via DHCP
|
- **Less Overhead**: No display server running in between
|
||||||
- Automatic interface detection (eth0, enp0s3, etc.)
|
- **Simpler**: Fewer processes, less memory usage
|
||||||
- DNS fallback to public servers (8.8.8.8, 1.1.1.1)
|
- **Embedded-Friendly**: Same approach used in embedded systems
|
||||||
- Enables git clone to install spark CLI
|
|
||||||
|
|
||||||
**Phase 2: Full Configuration (via spark CLI)**
|
### Why Network-First?
|
||||||
- WiFi configuration
|
|
||||||
- Advanced networking features
|
Modern computing is inherently networked. Instead of treating networking as an add-on:
|
||||||
- Custom DNS settings
|
- Network APIs exposed directly to GUI
|
||||||
- Network profiles
|
- Cloud storage as primary storage paradigm
|
||||||
|
- Web technologies integrated (future: embedded browser)
|
||||||
|
- Real-time updates and communication built-in
|
||||||
|
|
||||||
## Future Architecture
|
## Future Architecture
|
||||||
|
|
||||||
|
|||||||
20
Makefile
20
Makefile
@@ -7,16 +7,18 @@ DESTDIR = rootfs
|
|||||||
IMAGE = sparkos.img
|
IMAGE = sparkos.img
|
||||||
IMAGE_SIZE = 512M
|
IMAGE_SIZE = 512M
|
||||||
|
|
||||||
.PHONY: all clean init image image-docker help install docker-release
|
.PHONY: all clean init gui image image-docker help install docker-release
|
||||||
|
|
||||||
all: init
|
all: init gui
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "SparkOS Build System"
|
@echo "SparkOS Build System"
|
||||||
@echo "===================="
|
@echo "===================="
|
||||||
@echo "Targets:"
|
@echo "Targets:"
|
||||||
@echo " make init - Build the init system"
|
@echo " make init - Build the init system"
|
||||||
@echo " make install - Install init to rootfs"
|
@echo " make gui - Build the Qt6 GUI application"
|
||||||
|
@echo " make all - Build both init and GUI (default)"
|
||||||
|
@echo " make install - Install init and GUI to rootfs"
|
||||||
@echo " make image - Create bootable dd-able image (requires root)"
|
@echo " make image - Create bootable dd-able image (requires root)"
|
||||||
@echo " make image-docker - Create bootable image using Docker (no root required)"
|
@echo " make image-docker - Create bootable image using Docker (no root required)"
|
||||||
@echo " make docker-release - Build release package using Docker (no root required)"
|
@echo " make docker-release - Build release package using Docker (no root required)"
|
||||||
@@ -34,10 +36,20 @@ init: src/init.c
|
|||||||
$(CC) $(CFLAGS) -o init src/init.c
|
$(CC) $(CFLAGS) -o init src/init.c
|
||||||
@echo "Init system built successfully: ./init"
|
@echo "Init system built successfully: ./init"
|
||||||
|
|
||||||
install: init
|
gui:
|
||||||
|
@echo "Building SparkOS Qt6 GUI application..."
|
||||||
|
@mkdir -p build/gui
|
||||||
|
@cd build/gui && cmake ../../src/qt6-app -DCMAKE_INSTALL_PREFIX=$(DESTDIR)/usr
|
||||||
|
@cd build/gui && $(MAKE)
|
||||||
|
@echo "Qt6 GUI application built successfully: build/gui/sparkos-gui"
|
||||||
|
|
||||||
|
install: init gui
|
||||||
@echo "Installing init to rootfs..."
|
@echo "Installing init to rootfs..."
|
||||||
install -D -m 755 init $(DESTDIR)/sbin/init
|
install -D -m 755 init $(DESTDIR)/sbin/init
|
||||||
@echo "Init installed to $(DESTDIR)/sbin/init"
|
@echo "Init installed to $(DESTDIR)/sbin/init"
|
||||||
|
@echo "Installing Qt6 GUI application to rootfs..."
|
||||||
|
@cd build/gui && $(MAKE) install
|
||||||
|
@echo "GUI application installed to $(DESTDIR)/usr/bin/sparkos-gui"
|
||||||
|
|
||||||
image: install
|
image: install
|
||||||
@echo "Creating bootable image..."
|
@echo "Creating bootable image..."
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -1,16 +1,46 @@
|
|||||||
# SparkOS
|
# SparkOS
|
||||||
|
|
||||||
A minimal Linux distribution designed for simplicity and portability. SparkOS features:
|
A revolutionary operating system that ditches Unix conventions for a modern, network-first approach. SparkOS features:
|
||||||
|
|
||||||
- **Minimal footprint**: Barebones Linux system with busybox shell
|
- **Direct Kernel Interface**: Qt6 GUI communicates directly with Linux kernel, bypassing Unix layers
|
||||||
|
- **Linux Driver Layer**: All hardware abstraction handled by Linux kernel drivers
|
||||||
|
- **No Unix User System**: No users, groups, passwords, or authentication - direct boot to GUI
|
||||||
|
- **Network-First Architecture**: Built around networking as the primary paradigm
|
||||||
|
- **Qt6 Full-Screen GUI**: Modern graphical interface from boot
|
||||||
|
- **Minimal footprint**: Lean system with only essential components
|
||||||
- **Portable**: dd-able disk image for USB flash drives
|
- **Portable**: dd-able disk image for USB flash drives
|
||||||
- **Custom init**: Lightweight C init system
|
- **Custom init**: Lightweight C init system that launches GUI directly
|
||||||
- **Future-ready**: Designed to support Qt6/QML GUI and Wayland
|
- **Immutable base**: Read-only root filesystem with overlay for runtime data
|
||||||
- **Root elevation**: Uses sudo for privilege management
|
|
||||||
- **Bootstrap networking**: Wired networking with DHCP for initial setup
|
## Architecture
|
||||||
- Minimal installation by default: kernel, init system, busybox, git, and sudo
|
|
||||||
- DNS configured with fallback to public DNS servers (8.8.8.8, 1.1.1.1)
|
```
|
||||||
- WiFi and advanced networking configured later via spark CLI
|
┌─────────────────────────────────────┐
|
||||||
|
│ Qt6 GUI Application │
|
||||||
|
│ (Direct Framebuffer Rendering) │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↕
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Linux Kernel │
|
||||||
|
│ • Framebuffer (/dev/fb0) │
|
||||||
|
│ • Input devices (/dev/input/*) │
|
||||||
|
│ • Network stack │
|
||||||
|
│ • All hardware drivers │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↕
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Hardware │
|
||||||
|
│ • GPU, Display, Input devices │
|
||||||
|
│ • Network adapters │
|
||||||
|
│ • Storage, etc. │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Design Principles:**
|
||||||
|
- Linux kernel provides complete hardware abstraction and driver support
|
||||||
|
- Qt6 interfaces directly with kernel through /dev, /proc, /sys interfaces
|
||||||
|
- No intermediate Unix layers (no systemd, no user management, no shells by default)
|
||||||
|
- Network-first: networking capabilities exposed directly to GUI
|
||||||
|
|
||||||
## MVP Status
|
## MVP Status
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
root:x:0:
|
|
||||||
spark:x:1000:
|
|
||||||
sudo:x:27:spark
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
root:x:0:0:root:/root:/bin/sh
|
|
||||||
spark:x:1000:1000:SparkOS User:/home/spark:/bin/sh
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# SparkOS Sudoers Configuration
|
|
||||||
# Allow spark user to run any command without password
|
|
||||||
|
|
||||||
# Default settings
|
|
||||||
Defaults env_reset
|
|
||||||
Defaults secure_path="/bin:/sbin:/usr/bin:/usr/sbin"
|
|
||||||
|
|
||||||
# Root can run anything
|
|
||||||
root ALL=(ALL:ALL) ALL
|
|
||||||
|
|
||||||
# Spark user can run anything without password
|
|
||||||
spark ALL=(ALL:ALL) NOPASSWD: ALL
|
|
||||||
|
|
||||||
# Include sudoers.d directory
|
|
||||||
@includedir /etc/sudoers.d
|
|
||||||
85
src/init.c
85
src/init.c
@@ -12,12 +12,6 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// Default user configuration
|
|
||||||
#define SPARK_UID 1000
|
|
||||||
#define SPARK_GID 1000
|
|
||||||
#define SPARK_HOME "/home/spark"
|
|
||||||
#define SPARK_USER "spark"
|
|
||||||
|
|
||||||
static void signal_handler(int sig) {
|
static void signal_handler(int sig) {
|
||||||
if (sig == SIGCHLD) {
|
if (sig == SIGCHLD) {
|
||||||
// Reap zombie processes
|
// Reap zombie processes
|
||||||
@@ -25,6 +19,38 @@ static void signal_handler(int sig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spawn_gui() {
|
||||||
|
pid_t pid = fork();
|
||||||
|
|
||||||
|
if (pid < 0) {
|
||||||
|
perror("fork failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
// Child process - exec Qt6 GUI application as root (no user switching)
|
||||||
|
|
||||||
|
char *argv[] = {"/usr/bin/sparkos-gui", NULL};
|
||||||
|
char *envp[] = {
|
||||||
|
"HOME=/root",
|
||||||
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
|
||||||
|
"QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0",
|
||||||
|
"QT_QPA_FB_FORCE_FULLSCREEN=1",
|
||||||
|
"QT_QPA_FONTDIR=/usr/share/fonts",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
execve("/usr/bin/sparkos-gui", argv, envp);
|
||||||
|
|
||||||
|
perror("failed to exec GUI application");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent process - wait for GUI to exit
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void spawn_shell() {
|
static void spawn_shell() {
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
@@ -34,34 +60,17 @@ static void spawn_shell() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// Child process - exec shell as spark user
|
// Child process - exec shell as root (fallback only)
|
||||||
|
|
||||||
// Set user and group IDs to spark user
|
|
||||||
if (setgid(SPARK_GID) != 0) {
|
|
||||||
perror("setgid failed");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (setuid(SPARK_UID) != 0) {
|
|
||||||
perror("setuid failed");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *argv[] = {"/bin/sh", "-l", NULL};
|
char *argv[] = {"/bin/sh", "-l", NULL};
|
||||||
char *envp[] = {
|
char *envp[] = {
|
||||||
"HOME=" SPARK_HOME,
|
"HOME=/root",
|
||||||
"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
|
"PATH=/bin:/sbin:/usr/bin:/usr/sbin",
|
||||||
"TERM=linux",
|
"TERM=linux",
|
||||||
"PS1=SparkOS$ ",
|
"PS1=SparkOS# ",
|
||||||
"USER=" SPARK_USER,
|
|
||||||
"LOGNAME=" SPARK_USER,
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Change to home directory
|
|
||||||
if (chdir(SPARK_HOME) != 0) {
|
|
||||||
perror("chdir failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
execve("/bin/sh", argv, envp);
|
execve("/bin/sh", argv, envp);
|
||||||
|
|
||||||
perror("failed to exec shell");
|
perror("failed to exec shell");
|
||||||
@@ -107,9 +116,6 @@ int main(int argc, char *argv[]) {
|
|||||||
if (system("mkdir -p /tmp/overlay/var-upper /tmp/overlay/var-work 2>/dev/null") != 0) {
|
if (system("mkdir -p /tmp/overlay/var-upper /tmp/overlay/var-work 2>/dev/null") != 0) {
|
||||||
fprintf(stderr, "Warning: Failed to create overlay directories for /var\n");
|
fprintf(stderr, "Warning: Failed to create overlay directories for /var\n");
|
||||||
}
|
}
|
||||||
if (system("mkdir -p /tmp/overlay/home-upper /tmp/overlay/home-work 2>/dev/null") != 0) {
|
|
||||||
fprintf(stderr, "Warning: Failed to create overlay directories for /home/spark\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mount overlay on /var for logs and runtime data
|
// Mount overlay on /var for logs and runtime data
|
||||||
if (system("mount -t overlay overlay -o lowerdir=/var,upperdir=/tmp/overlay/var-upper,workdir=/tmp/overlay/var-work /var 2>/dev/null") != 0) {
|
if (system("mount -t overlay overlay -o lowerdir=/var,upperdir=/tmp/overlay/var-upper,workdir=/tmp/overlay/var-work /var 2>/dev/null") != 0) {
|
||||||
@@ -118,13 +124,6 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Overlay filesystem mounted on /var (base OS is immutable)\n");
|
printf("Overlay filesystem mounted on /var (base OS is immutable)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount overlay on /home/spark for user data
|
|
||||||
if (system("mount -t overlay overlay -o lowerdir=/home/spark,upperdir=/tmp/overlay/home-upper,workdir=/tmp/overlay/home-work /home/spark 2>/dev/null") != 0) {
|
|
||||||
fprintf(stderr, "Warning: Failed to mount overlay on /home/spark - home directory may be read-only\n");
|
|
||||||
} else {
|
|
||||||
printf("Overlay filesystem mounted on /home/spark (writable user home)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mount tmpfs on /run for runtime data
|
// Mount tmpfs on /run for runtime data
|
||||||
if (system("mkdir -p /run 2>/dev/null") == 0) {
|
if (system("mkdir -p /run 2>/dev/null") == 0) {
|
||||||
if (system("mount -t tmpfs tmpfs /run 2>/dev/null") != 0) {
|
if (system("mount -t tmpfs tmpfs /run 2>/dev/null") != 0) {
|
||||||
@@ -138,18 +137,20 @@ int main(int argc, char *argv[]) {
|
|||||||
fprintf(stderr, "Warning: Network initialization failed - check network interface availability\n");
|
fprintf(stderr, "Warning: Network initialization failed - check network interface availability\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Starting shell...\n");
|
printf("Starting Qt6 GUI application...\n");
|
||||||
printf("Welcome to SparkOS!\n");
|
printf("Welcome to SparkOS!\n");
|
||||||
printf("===================\n");
|
printf("===================\n");
|
||||||
printf("Base OS: Read-only (immutable)\n");
|
printf("Base OS: Read-only (immutable)\n");
|
||||||
printf("Writable: /tmp, /var (overlay), /home/spark (overlay), /run\n\n");
|
printf("Writable: /tmp, /var (overlay), /run\n");
|
||||||
|
printf("Mode: Qt6 GUI (Network-First Architecture)\n");
|
||||||
|
printf("No Users/Authentication - Direct Boot to GUI\n\n");
|
||||||
|
|
||||||
// Main loop - keep respawning shell
|
// Main loop - keep respawning GUI application
|
||||||
while (1) {
|
while (1) {
|
||||||
spawn_shell();
|
spawn_gui();
|
||||||
|
|
||||||
// If shell exits, ask if user wants to reboot
|
// If GUI exits, respawn after a short delay
|
||||||
printf("\nShell exited. Press Ctrl+Alt+Del to reboot or wait for new shell...\n");
|
printf("\nGUI application exited. Restarting in 2 seconds...\n");
|
||||||
sleep(2);
|
sleep(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/qt6-app/CMakeLists.txt
Normal file
42
src/qt6-app/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(sparkos-gui VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Set build type to Release if not specified
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find Qt6 packages
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui)
|
||||||
|
|
||||||
|
# Enable automatic MOC (Meta-Object Compiler)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
set(SOURCES
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create executable
|
||||||
|
add_executable(sparkos-gui ${SOURCES})
|
||||||
|
|
||||||
|
# Link Qt6 libraries
|
||||||
|
target_link_libraries(sparkos-gui PRIVATE
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Widgets
|
||||||
|
Qt6::Gui
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set properties for static linking if desired
|
||||||
|
# target_link_options(sparkos-gui PRIVATE -static-libgcc -static-libstdc++)
|
||||||
|
|
||||||
|
# Install target
|
||||||
|
install(TARGETS sparkos-gui
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
186
src/qt6-app/main.cpp
Normal file
186
src/qt6-app/main.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* SparkOS Qt6 GUI Application
|
||||||
|
* Direct kernel interface - bypassing Unix conventions
|
||||||
|
* Network-first, GUI-only operating system
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
class SparkOSMainWindow : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SparkOSMainWindow(QWidget *parent = nullptr) : QWidget(parent) {
|
||||||
|
setupUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void showSystemInfo() {
|
||||||
|
// Direct kernel interface through /proc and /sys
|
||||||
|
QString info = "SparkOS - Direct Kernel Interface\n";
|
||||||
|
info += "==================================\n\n";
|
||||||
|
|
||||||
|
// Read kernel version directly from /proc
|
||||||
|
QFile kernelFile("/proc/version");
|
||||||
|
if (kernelFile.open(QIODevice::ReadOnly)) {
|
||||||
|
info += "Kernel: " + QString(kernelFile.readLine()).trimmed() + "\n\n";
|
||||||
|
kernelFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read memory info directly from /proc
|
||||||
|
QFile meminfoFile("/proc/meminfo");
|
||||||
|
if (meminfoFile.open(QIODevice::ReadOnly)) {
|
||||||
|
info += "Memory Info:\n";
|
||||||
|
int lineCount = 0;
|
||||||
|
while (!meminfoFile.atEnd() && lineCount < 3) {
|
||||||
|
info += " " + QString(meminfoFile.readLine()).trimmed() + "\n";
|
||||||
|
lineCount++;
|
||||||
|
}
|
||||||
|
meminfoFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
info += "\n";
|
||||||
|
info += "Architecture: Network-First OS\n";
|
||||||
|
info += "No Unix user/group system\n";
|
||||||
|
info += "Direct Qt6 GUI to Kernel interface\n";
|
||||||
|
|
||||||
|
QTextEdit *infoDialog = new QTextEdit();
|
||||||
|
infoDialog->setReadOnly(true);
|
||||||
|
infoDialog->setPlainText(info);
|
||||||
|
infoDialog->setWindowTitle("System Information");
|
||||||
|
infoDialog->resize(600, 400);
|
||||||
|
infoDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI() {
|
||||||
|
// Set window properties
|
||||||
|
setWindowTitle("SparkOS");
|
||||||
|
|
||||||
|
// Create main layout
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||||
|
mainLayout->setAlignment(Qt::AlignCenter);
|
||||||
|
mainLayout->setSpacing(30);
|
||||||
|
|
||||||
|
// Create welcome label
|
||||||
|
QLabel *titleLabel = new QLabel("Welcome to SparkOS", this);
|
||||||
|
QFont titleFont;
|
||||||
|
titleFont.setPointSize(48);
|
||||||
|
titleFont.setBold(true);
|
||||||
|
titleLabel->setFont(titleFont);
|
||||||
|
titleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
titleLabel->setStyleSheet("color: #2196F3;");
|
||||||
|
|
||||||
|
// Create subtitle label
|
||||||
|
QLabel *subtitleLabel = new QLabel("Direct Kernel • Network-First • No Unix", this);
|
||||||
|
QFont subtitleFont;
|
||||||
|
subtitleFont.setPointSize(24);
|
||||||
|
subtitleLabel->setFont(subtitleFont);
|
||||||
|
subtitleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
subtitleLabel->setStyleSheet("color: #666;");
|
||||||
|
|
||||||
|
// Create status label
|
||||||
|
QLabel *statusLabel = new QLabel("✓ System Initialized • GUI Active", this);
|
||||||
|
QFont statusFont;
|
||||||
|
statusFont.setPointSize(16);
|
||||||
|
statusLabel->setFont(statusFont);
|
||||||
|
statusLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
statusLabel->setStyleSheet("color: #4CAF50;");
|
||||||
|
|
||||||
|
// Create info label
|
||||||
|
QLabel *infoLabel = new QLabel("Qt6 GUI ↔ Linux Kernel (Direct Interface)", this);
|
||||||
|
QFont infoFont;
|
||||||
|
infoFont.setPointSize(14);
|
||||||
|
infoLabel->setFont(infoFont);
|
||||||
|
infoLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
infoLabel->setStyleSheet("color: #999;");
|
||||||
|
|
||||||
|
// Create system info button
|
||||||
|
QPushButton *infoButton = new QPushButton("System Info", this);
|
||||||
|
infoButton->setMinimumSize(200, 60);
|
||||||
|
QFont buttonFont;
|
||||||
|
buttonFont.setPointSize(16);
|
||||||
|
infoButton->setFont(buttonFont);
|
||||||
|
infoButton->setStyleSheet(
|
||||||
|
"QPushButton {"
|
||||||
|
" background-color: #2196F3;"
|
||||||
|
" color: white;"
|
||||||
|
" border: none;"
|
||||||
|
" border-radius: 5px;"
|
||||||
|
" padding: 10px;"
|
||||||
|
"}"
|
||||||
|
"QPushButton:hover {"
|
||||||
|
" background-color: #1976D2;"
|
||||||
|
"}"
|
||||||
|
"QPushButton:pressed {"
|
||||||
|
" background-color: #0D47A1;"
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
connect(infoButton, &QPushButton::clicked, this, &SparkOSMainWindow::showSystemInfo);
|
||||||
|
|
||||||
|
// Create exit button
|
||||||
|
QPushButton *exitButton = new QPushButton("Power Off", this);
|
||||||
|
exitButton->setMinimumSize(200, 60);
|
||||||
|
exitButton->setFont(buttonFont);
|
||||||
|
exitButton->setStyleSheet(
|
||||||
|
"QPushButton {"
|
||||||
|
" background-color: #f44336;"
|
||||||
|
" color: white;"
|
||||||
|
" border: none;"
|
||||||
|
" border-radius: 5px;"
|
||||||
|
" padding: 10px;"
|
||||||
|
"}"
|
||||||
|
"QPushButton:hover {"
|
||||||
|
" background-color: #da190b;"
|
||||||
|
"}"
|
||||||
|
"QPushButton:pressed {"
|
||||||
|
" background-color: #a31408;"
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Connect exit button
|
||||||
|
connect(exitButton, &QPushButton::clicked, this, &QApplication::quit);
|
||||||
|
|
||||||
|
// Add widgets to layout
|
||||||
|
mainLayout->addStretch();
|
||||||
|
mainLayout->addWidget(titleLabel);
|
||||||
|
mainLayout->addWidget(subtitleLabel);
|
||||||
|
mainLayout->addSpacing(40);
|
||||||
|
mainLayout->addWidget(statusLabel);
|
||||||
|
mainLayout->addWidget(infoLabel);
|
||||||
|
mainLayout->addSpacing(40);
|
||||||
|
mainLayout->addWidget(infoButton, 0, Qt::AlignCenter);
|
||||||
|
mainLayout->addWidget(exitButton, 0, Qt::AlignCenter);
|
||||||
|
mainLayout->addStretch();
|
||||||
|
|
||||||
|
// Set background color
|
||||||
|
setStyleSheet("QWidget { background-color: #f5f5f5; }");
|
||||||
|
|
||||||
|
// Make fullscreen on Linux
|
||||||
|
showFullScreen();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
// Direct framebuffer rendering - no X11/Wayland server needed
|
||||||
|
// The Qt application interfaces directly with the Linux kernel framebuffer
|
||||||
|
qputenv("QT_QPA_PLATFORM", "linuxfb");
|
||||||
|
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
SparkOSMainWindow window;
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "main.moc"
|
||||||
Reference in New Issue
Block a user