Compare commits
15
Commits
e2e8c49a0a
...
main
No files matched your search
+1
-1
@@ -66,7 +66,7 @@ docker run \
|
||||
# ── rename with date tag ──────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "Step 3/3: Finalizing..."
|
||||
ISO="$(find "$DIST" -name "orionos*.iso" | head -1)"
|
||||
ISO="$(find "$DIST" -iname "*.iso" | head -1)"
|
||||
if [[ -z "$ISO" ]]; then
|
||||
echo "ERROR: ISO not found in $DIST — check the build output above."
|
||||
exit 1
|
||||
|
||||
+15
-15
@@ -152,8 +152,8 @@ progress 14 "Mounting partitions…"
|
||||
info "Mounting..."
|
||||
mount "$ROOT_PART" /mnt
|
||||
if [[ "$BOOT_MODE" == "uefi" ]]; then
|
||||
mkdir -p /mnt/boot/efi
|
||||
mount "$EFI_PART" /mnt/boot/efi
|
||||
mkdir -p /mnt/boot
|
||||
mount "$EFI_PART" /mnt/boot
|
||||
fi
|
||||
ok "Mounted."
|
||||
|
||||
@@ -197,9 +197,11 @@ info "Configuring system..."
|
||||
|
||||
arch-chroot /mnt /bin/bash -s "$HOSTNAME" "$USERNAME" "$PASSWORD" \
|
||||
"$BOOT_MODE" "$ROOT_PART" \
|
||||
"${TIMEZONE:-UTC}" "${KEYBOARD:-us}" \
|
||||
<<'CHROOT'
|
||||
HOSTNAME="$1"; USERNAME="$2"; PASSWORD="$3"
|
||||
BOOT_MODE="$4"; ROOT_PART="$5"
|
||||
TIMEZONE="${6:-UTC}"; KEYBOARD="${7:-us}"
|
||||
|
||||
# Hostname
|
||||
echo "$HOSTNAME" > /etc/hostname
|
||||
@@ -268,22 +270,20 @@ mkinitcpio -P
|
||||
|
||||
# Bootloader
|
||||
if [[ "$BOOT_MODE" == "uefi" ]]; then
|
||||
bootctl install 2>/dev/null || true
|
||||
bootctl --esp-path=/boot install 2>/dev/null || true
|
||||
ROOT_UUID="$(blkid -s UUID -o value "$ROOT_PART")"
|
||||
mkdir -p /boot/efi/loader/entries
|
||||
cat > /boot/efi/loader/loader.conf <<'LC'
|
||||
default skyos.conf
|
||||
mkdir -p /boot/loader/entries
|
||||
cat > /boot/loader/loader.conf <<'LC'
|
||||
default orionos.conf
|
||||
timeout 5
|
||||
editor no
|
||||
LC
|
||||
cat > /boot/efi/loader/entries/skyos.conf <<ENTRY
|
||||
title OrionOS
|
||||
linux /vmlinuz-linux
|
||||
initrd /amd-ucode.img
|
||||
initrd /intel-ucode.img
|
||||
initrd /initramfs-linux.img
|
||||
options root=UUID=${ROOT_UUID} rw quiet loglevel=3
|
||||
ENTRY
|
||||
# Build initrd lines — only include microcode if the image exists
|
||||
INITRD_LINES="initrd /initramfs-linux.img"
|
||||
[[ -f /boot/amd-ucode.img ]] && INITRD_LINES="initrd /amd-ucode.img\n${INITRD_LINES}"
|
||||
[[ -f /boot/intel-ucode.img ]] && INITRD_LINES="initrd /intel-ucode.img\n${INITRD_LINES}"
|
||||
printf "title OrionOS\nlinux /vmlinuz-linux\n%b\noptions root=UUID=%s rw quiet loglevel=3\n" \
|
||||
"$INITRD_LINES" "$ROOT_UUID" > /boot/loader/entries/orionos.conf
|
||||
else
|
||||
# Find the whole disk (strip trailing partition number)
|
||||
DISK="${ROOT_PART%[0-9]}"
|
||||
@@ -305,7 +305,7 @@ ok "System configured."
|
||||
progress 97 "Unmounting…"
|
||||
info "Unmounting..."
|
||||
sync
|
||||
[[ "$BOOT_MODE" == "uefi" ]] && umount /mnt/boot/efi 2>/dev/null || true
|
||||
[[ "$BOOT_MODE" == "uefi" ]] && umount /mnt/boot 2>/dev/null || true
|
||||
umount /mnt
|
||||
ok "Done."
|
||||
|
||||
|
||||
+30
-7
@@ -1,9 +1,13 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
# Disable pacman's alpm sandbox (seccomp-incompatible inside Docker/BuildKit)
|
||||
RUN echo "DisableSandbox" >> /etc/pacman.conf
|
||||
|
||||
# Update and install archiso + OrionOS build dependencies
|
||||
RUN pacman -Syu --noconfirm && \
|
||||
pacman -S --noconfirm \
|
||||
archiso \
|
||||
syslinux \
|
||||
base-devel \
|
||||
git \
|
||||
libx11 \
|
||||
@@ -11,6 +15,7 @@ RUN pacman -Syu --noconfirm && \
|
||||
libxfixes \
|
||||
libxext \
|
||||
libpng \
|
||||
imlib2 \
|
||||
dbus \
|
||||
pam \
|
||||
fontconfig \
|
||||
@@ -30,8 +35,24 @@ WORKDIR /build
|
||||
# Copy OrionOS source
|
||||
COPY . /build/orionos
|
||||
|
||||
# Build OrionOS components
|
||||
RUN cd /build/orionos && make 2>&1 | tail -20
|
||||
# Bootstrap boot loader configs from the installed archiso releng profile.
|
||||
# Copy only the .c32 binary modules — our repo provides syslinux.cfg.
|
||||
# efiboot/ is needed for systemd-boot UEFI; fall back to a minimal loader.conf.
|
||||
|
||||
RUN mkdir -p /build/orionos/iso/profile/syslinux && \
|
||||
cp /usr/share/archiso/configs/releng/syslinux/*.c32 \
|
||||
/build/orionos/iso/profile/syslinux/ 2>/dev/null || true && \
|
||||
if [ -d /usr/share/archiso/configs/releng/efiboot ]; then \
|
||||
cp -r /usr/share/archiso/configs/releng/efiboot \
|
||||
/build/orionos/iso/profile/; \
|
||||
else \
|
||||
mkdir -p /build/orionos/iso/profile/efiboot/loader/entries && \
|
||||
printf 'timeout 4\ndefault arch-*\n' \
|
||||
> /build/orionos/iso/profile/efiboot/loader/loader.conf; \
|
||||
fi
|
||||
|
||||
# Build OrionOS components (full output — no tail so errors are visible)
|
||||
RUN cd /build/orionos && make
|
||||
|
||||
# Install binaries into the staging root that archiso will include
|
||||
RUN cd /build/orionos && \
|
||||
@@ -44,6 +65,9 @@ RUN cd /build/orionos && \
|
||||
install -Dm755 orionshot/orionshot /build/orionos/iso/profile/airootfs/usr/local/bin/orionshot && \
|
||||
install -Dm755 orionclip/orionclip /build/orionos/iso/profile/airootfs/usr/local/bin/orionclip && \
|
||||
install -Dm755 orionpkg/orionpkg /build/orionos/iso/profile/airootfs/usr/local/bin/orionpkg && \
|
||||
install -Dm755 installer/orioninstall-gui /build/orionos/iso/profile/airootfs/usr/local/bin/orioninstall-gui && \
|
||||
install -Dm755 installer/orioninstall /build/orionos/iso/profile/airootfs/usr/local/bin/orioninstall && \
|
||||
mkdir -p /build/orionos/iso/profile/airootfs/usr/share/themes/ && \
|
||||
cp -r themes/OrionOS /build/orionos/iso/profile/airootfs/usr/share/themes/ && \
|
||||
install -Dm644 themes/picom.conf /build/orionos/iso/profile/airootfs/etc/orionos/picom.conf
|
||||
|
||||
@@ -53,10 +77,9 @@ RUN mkdir -p /build/orionos/iso/profile/airootfs/usr/share/orionos/wallpapers &&
|
||||
cp -f /build/orionos/themes/wallpapers/orionos-default.png \
|
||||
/build/orionos/iso/profile/airootfs/usr/share/orionos/wallpapers/ 2>/dev/null || true
|
||||
|
||||
# Build the ISO
|
||||
RUN mkarchiso -v \
|
||||
# Build the ISO at container runtime — mkarchiso needs --privileged (from docker run)
|
||||
# Output goes to /dist which build-iso.sh mounts from the host.
|
||||
CMD mkarchiso -v \
|
||||
-w /tmp/iso-work \
|
||||
-o /output \
|
||||
-o /dist \
|
||||
/build/orionos/iso/profile
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -0,0 +1,4 @@
|
||||
MODULES=(squashfs overlay)
|
||||
BINARIES=()
|
||||
FILES=()
|
||||
HOOKS=(base udev archiso block filesystems keyboard)
|
||||
@@ -0,0 +1,16 @@
|
||||
[options]
|
||||
HoldPkg = pacman glibc
|
||||
Architecture = auto
|
||||
CheckSpace
|
||||
ParallelDownloads = 5
|
||||
SigLevel = Required DatabaseOptional
|
||||
LocalFileSigLevel = Optional
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
@@ -0,0 +1,4 @@
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
Server = https://mirrors.mit.edu/archlinux/$repo/os/$arch
|
||||
@@ -0,0 +1,3 @@
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty --autologin root --noclear %I $TERM
|
||||
@@ -0,0 +1,3 @@
|
||||
if [[ -z $DISPLAY ]] && [[ $(tty) == /dev/tty1 ]]; then
|
||||
exec startx
|
||||
fi
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e -u
|
||||
|
||||
# Allow passwordless root login on the live system
|
||||
passwd -d root
|
||||
|
||||
# Enable networking on the live system
|
||||
systemctl enable NetworkManager
|
||||
systemctl enable wpa_supplicant
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/ash
|
||||
|
||||
archiso_mount_handler() {
|
||||
local _new_root="$1"
|
||||
local _uuid _label _basedir _dev _img _param
|
||||
|
||||
for _param in $(cat /proc/cmdline); do
|
||||
case "$_param" in
|
||||
archisosearchuuid=*) _uuid="${_param#archisosearchuuid=}" ;;
|
||||
archisolabel=*) _label="${_param#archisolabel=}" ;;
|
||||
archisobasedir=*) _basedir="${_param#archisobasedir=}" ;;
|
||||
esac
|
||||
done
|
||||
: "${_basedir:=arch}"
|
||||
|
||||
if [ -z "${_uuid}" ] && [ -z "${_label}" ]; then
|
||||
echo "archiso: neither archisosearchuuid nor archisolabel in kernel cmdline"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local _waited=0
|
||||
while [ "${_waited}" -lt 30 ]; do
|
||||
if [ -n "${_uuid}" ]; then
|
||||
_dev="$(blkid -l -o device -t UUID="${_uuid}" 2>/dev/null)"
|
||||
else
|
||||
_dev="$(blkid -l -o device -t LABEL="${_label}" 2>/dev/null)"
|
||||
fi
|
||||
[ -n "${_dev}" ] && break
|
||||
sleep 1
|
||||
_waited=$(( _waited + 1 ))
|
||||
done
|
||||
|
||||
if [ -z "${_dev}" ]; then
|
||||
echo "archiso: could not find boot medium (uuid=${_uuid} label=${_label})"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "archiso: found boot medium ${_dev}"
|
||||
|
||||
mkdir -p /run/archiso/bootmnt
|
||||
mount -r "${_dev}" /run/archiso/bootmnt || { echo "archiso: mount bootmnt failed"; return 1; }
|
||||
|
||||
_img="/run/archiso/bootmnt/${_basedir}/x86_64/airootfs.sfs"
|
||||
if [ ! -e "${_img}" ]; then
|
||||
echo "archiso: squashfs not found at ${_img}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p /run/archiso/airootfs
|
||||
mount -r -t squashfs "${_img}" /run/archiso/airootfs || { echo "archiso: squashfs mount failed"; return 1; }
|
||||
|
||||
mkdir -p /run/archiso/overlay
|
||||
mount -t tmpfs tmpfs -o mode=0755 /run/archiso/overlay
|
||||
mkdir -p /run/archiso/overlay/upper /run/archiso/overlay/work
|
||||
|
||||
mount -t overlay overlay \
|
||||
-o lowerdir=/run/archiso/airootfs,upperdir=/run/archiso/overlay/upper,workdir=/run/archiso/overlay/work \
|
||||
"${_new_root}" || { echo "archiso: overlay mount failed"; return 1; }
|
||||
|
||||
echo "archiso: live root mounted on ${_new_root}"
|
||||
}
|
||||
|
||||
run_hook() {
|
||||
mount_handler="archiso_mount_handler"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# mkinitcpio install script for the archiso live-boot hook.
|
||||
|
||||
build() {
|
||||
add_runscript
|
||||
add_binary blkid
|
||||
add_binary mount
|
||||
add_binary sleep
|
||||
add_module squashfs
|
||||
add_module overlay
|
||||
add_module isofs
|
||||
}
|
||||
|
||||
help() {
|
||||
cat <<HELPEOF
|
||||
Locates the live ISO by UUID, mounts the squashfs airootfs, and sets up
|
||||
a RAM-backed overlay as the writable root filesystem.
|
||||
HELPEOF
|
||||
}
|
||||
@@ -24,30 +24,45 @@ libxft
|
||||
libxfixes
|
||||
libxext
|
||||
libpng
|
||||
imlib2
|
||||
dbus
|
||||
libpam
|
||||
pam
|
||||
fontconfig
|
||||
freetype2
|
||||
syslinux
|
||||
|
||||
# Desktop utilities
|
||||
feh
|
||||
picom
|
||||
xterm
|
||||
libnotify
|
||||
pcmanfm
|
||||
mousepad
|
||||
arandr
|
||||
|
||||
# Audio
|
||||
alsa-utils
|
||||
pulseaudio
|
||||
|
||||
# Brightness
|
||||
light
|
||||
brightnessctl
|
||||
|
||||
# Media playback control
|
||||
playerctl
|
||||
|
||||
# Installer dependencies
|
||||
rsync
|
||||
parted
|
||||
arch-install-scripts
|
||||
grub
|
||||
efibootmgr
|
||||
dosfstools
|
||||
amd-ucode
|
||||
intel-ucode
|
||||
|
||||
# Arch tools
|
||||
archiso
|
||||
pacman-contrib
|
||||
pkexec
|
||||
polkit
|
||||
|
||||
# System tools
|
||||
@@ -63,6 +78,7 @@ gzip
|
||||
|
||||
# Network
|
||||
networkmanager
|
||||
wpa_supplicant
|
||||
dhcpcd
|
||||
|
||||
# Misc
|
||||
|
||||
+10
-3
@@ -3,12 +3,19 @@ HoldPkg = pacman glibc
|
||||
Architecture = auto
|
||||
CheckSpace
|
||||
ParallelDownloads = 5
|
||||
SigLevel = Never
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
@@ -9,8 +9,7 @@ iso_version="$(date +%Y.%m)"
|
||||
install_dir="arch"
|
||||
buildmodes=('iso')
|
||||
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito'
|
||||
'uefi-ia32.grub.esp' 'uefi-x64.grub.esp'
|
||||
'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito')
|
||||
'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito')
|
||||
arch="x86_64"
|
||||
pacman_conf="pacman.conf"
|
||||
airootfs_image_type="squashfs"
|
||||
@@ -18,5 +17,18 @@ airootfs_image_tool_options=('-comp' 'zstd' '-Xcompression-level' '15')
|
||||
file_permissions=(
|
||||
["/etc/orionos/xinitrc"]="0:0:755"
|
||||
["/root/.xinitrc"]="0:0:755"
|
||||
["/root/.bash_profile"]="0:0:644"
|
||||
["/etc/skel/.xinitrc"]="0:0:755"
|
||||
["/root/customize_airootfs.sh"]="0:0:755"
|
||||
["/usr/local/bin/orionwm"]="0:0:755"
|
||||
["/usr/local/bin/oriondeskbar"]="0:0:755"
|
||||
["/usr/local/bin/orionlauncher"]="0:0:755"
|
||||
["/usr/local/bin/orionwallpaper"]="0:0:755"
|
||||
["/usr/local/bin/orionnotify"]="0:0:755"
|
||||
["/usr/local/bin/orionlock"]="0:0:755"
|
||||
["/usr/local/bin/orionshot"]="0:0:755"
|
||||
["/usr/local/bin/orionclip"]="0:0:755"
|
||||
["/usr/local/bin/orionpkg"]="0:0:755"
|
||||
["/usr/local/bin/orioninstall"]="0:0:755"
|
||||
["/usr/local/bin/orioninstall-gui"]="0:0:755"
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
DEFAULT arch64
|
||||
TIMEOUT 50
|
||||
PROMPT 0
|
||||
|
||||
LABEL arch64
|
||||
LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
|
||||
INITRD /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
|
||||
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% rw
|
||||
+137
-97
@@ -11,51 +11,55 @@
|
||||
#include <unistd.h>
|
||||
|
||||
/* ── dimensions ─────────────────────────────────────────────────────── */
|
||||
#define WIN_W 580
|
||||
#define WIN_H 420
|
||||
#define HDR_H 50
|
||||
#define TAB_H 34
|
||||
#define CONTENT_Y (HDR_H + TAB_H)
|
||||
#define PAD 12
|
||||
#define CARD_W 96
|
||||
#define CARD_H 84
|
||||
#define CARD_GAP 8
|
||||
#define COLS 5
|
||||
#define ICON_SZ 38
|
||||
#define WIN_W 640
|
||||
#define WIN_H 490
|
||||
#define HDR_H 58
|
||||
#define PILLS_H 42
|
||||
#define CONTENT_Y (HDR_H + PILLS_H)
|
||||
#define FOOTER_H 28
|
||||
#define CARD_W 132
|
||||
#define CARD_H 106
|
||||
#define CARD_GAP 10
|
||||
#define COLS 4
|
||||
#define ICON_SZ 46
|
||||
#define PILL_GAP 8
|
||||
#define ROWS_VIS 3
|
||||
|
||||
#define GX0 ((WIN_W - (COLS * CARD_W + (COLS-1) * CARD_GAP)) / 2)
|
||||
#define GY0 (CONTENT_Y + PAD)
|
||||
#define ROWS_VIS 3 /* rows visible before scrolling */
|
||||
#define GY0 (CONTENT_Y + 12)
|
||||
#define MAX_APPS 256
|
||||
|
||||
/* ── palette ─────────────────────────────────────────────────────────── */
|
||||
#define C_BG 0x0E1220
|
||||
#define C_HDR 0x090C18
|
||||
#define C_BORDER 0x192236
|
||||
#define C_ACCENT 0x2258B0
|
||||
#define C_TAB_SEL 0x141E30
|
||||
#define C_CARD_HOV 0x131C2E
|
||||
#define C_CARD_BD 0x1E2E48
|
||||
#define C_SEARCH 0x131A28
|
||||
#define C_SEARCH_BD 0x1C2C44
|
||||
#define C_TEXT 0x8AAAC8
|
||||
#define C_TEXT_HOV 0xE8F0FF
|
||||
#define C_TEXT_DIM 0x344A62
|
||||
#define C_TAB_TXT 0x486070
|
||||
#define C_TAB_TSEL 0xA8C4E8
|
||||
#define C_SCROLL_BG 0x0C1020
|
||||
#define C_SCROLL_TH 0x1E3258
|
||||
#define C_BG 0x111318
|
||||
#define C_SURFACE 0x1A1D28
|
||||
#define C_SURFACE_HV 0x1F2335
|
||||
#define C_BORDER 0x252A42
|
||||
#define C_BORDER_HV 0x3A5490
|
||||
#define C_ACCENT 0x4B8FF0
|
||||
#define C_PILL_SEL 0x19305C
|
||||
#define C_PILL_BD 0x2A4480
|
||||
#define C_SRCH_BG 0x161820
|
||||
#define C_SRCH_BD 0x262C48
|
||||
#define C_TEXT 0xC0CFF0
|
||||
#define C_TEXT_HOV 0xEEF2FF
|
||||
#define C_TEXT_DIM 0x3A4068
|
||||
#define C_TEXT_CAT 0x586090
|
||||
#define C_TEXT_CAT_S 0x8AAEE8
|
||||
#define C_FOOTER_BG 0x0C0E14
|
||||
#define C_FOOTER_TXT 0x353C62
|
||||
#define C_SCROLL_BG 0x161820
|
||||
#define C_SCROLL_TH 0x2C3460
|
||||
|
||||
static const unsigned long ICON_BG[] = {
|
||||
0x1A4D88, 0x166C3C, 0x6C3018,
|
||||
0x4A1A80, 0x126070, 0x6C1A38,
|
||||
0x365218, 0x183460,
|
||||
0x1A3A88, 0x0F6040, 0x7A2820, 0x501A80,
|
||||
0x106070, 0x6A1A3A, 0x384C18, 0x1A3060,
|
||||
0x6A4010, 0x103A60,
|
||||
};
|
||||
#define NICON 8
|
||||
#define NICON 10
|
||||
|
||||
#define FONT_UI "Sans:size=9"
|
||||
#define FONT_LOGO "Sans:size=11:weight=bold"
|
||||
#define FONT_ICON "Sans:size=13:weight=bold"
|
||||
#define FONT_ICON "Sans:size=14:weight=bold"
|
||||
#define FONT_HINT "Sans:size=8"
|
||||
#define MAX_FLT 64
|
||||
|
||||
typedef struct { char name[64]; char cmd[256]; char cat[32]; char icon[64]; } App;
|
||||
@@ -171,18 +175,13 @@ static void load_apps(void) {
|
||||
load_desktop_dir(p);
|
||||
}
|
||||
|
||||
/* fallback if no .desktop files (dev environment, macOS, etc.) */
|
||||
if (NAPP == 0) {
|
||||
static const struct { const char *n, *c, *cat; } FB[] = {
|
||||
{ "Firefox", "firefox &", "Internet" },
|
||||
{ "Terminal", "alacritty &", "System" },
|
||||
{ "Files", "thunar &", "System" },
|
||||
{ "Terminal", "xterm &", "System" },
|
||||
{ "Files", "pcmanfm &", "System" },
|
||||
{ "Text Editor", "mousepad &", "System" },
|
||||
{ "Media", "mpv --player-operation-mode=pseudo-gui &", "Media" },
|
||||
{ "Images", "viewnior &", "Media" },
|
||||
{ "PDF Viewer", "evince &", "Office" },
|
||||
{ "System Mon", "xterm -e htop &", "System" },
|
||||
{ "Display", "arandr &", "Settings" },
|
||||
{ "Audio", "pavucontrol &", "Settings" },
|
||||
};
|
||||
for (int i = 0; i < (int)(sizeof(FB)/sizeof(FB[0])); i++) {
|
||||
snprintf(APPS[i].name, 64, "%s", FB[i].n);
|
||||
@@ -200,7 +199,7 @@ typedef struct {
|
||||
Display *dpy; int screen;
|
||||
Window root, win; GC gc;
|
||||
Colormap cmap; Visual *visual;
|
||||
XftFont *font_ui, *font_logo, *font_icon;
|
||||
XftFont *font_ui, *font_icon, *font_hint;
|
||||
int sel_cat, hov, scroll;
|
||||
char filter[MAX_FLT];
|
||||
int filter_len;
|
||||
@@ -261,28 +260,28 @@ static int nvis(L *l, int out[MAX_APPS]) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static void tab_layout(L *l, int widths[NCAT], int *total) {
|
||||
static void pill_layout(L *l, int widths[NCAT], int *total) {
|
||||
*total = 0;
|
||||
for (int i = 0; i < NCAT; i++) {
|
||||
XGlyphInfo e;
|
||||
XftTextExtentsUtf8(l->dpy, l->font_ui, (FcChar8*)CATS[i], strlen(CATS[i]), &e);
|
||||
widths[i] = (int)e.width + 22;
|
||||
widths[i] = (int)e.width + 24;
|
||||
*total += widths[i];
|
||||
}
|
||||
*total += (NCAT - 1) * PILL_GAP;
|
||||
}
|
||||
|
||||
static int tab_at(L *l, int x, int y) {
|
||||
if (y < HDR_H || y >= CONTENT_Y) return -1;
|
||||
int w[NCAT], total; tab_layout(l, w, &total);
|
||||
int w[NCAT], total; pill_layout(l, w, &total);
|
||||
int tx = (WIN_W - total) / 2;
|
||||
for (int i = 0; i < NCAT; i++) {
|
||||
if (x >= tx && x < tx + w[i]) return i;
|
||||
tx += w[i];
|
||||
tx += w[i] + PILL_GAP;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* card index within visible slice (adjusted for scroll) */
|
||||
static int card_at_vis(int x, int y) {
|
||||
if (y < CONTENT_Y) return -1;
|
||||
int lx = x - GX0, ly = y - GY0;
|
||||
@@ -332,60 +331,68 @@ found:;
|
||||
static void draw(L *l) {
|
||||
XftDraw *xd = XftDrawCreate(l->dpy, l->win, l->visual, l->cmap);
|
||||
|
||||
/* background */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BG));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, WIN_H);
|
||||
|
||||
/* header */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_HDR));
|
||||
/* ── header: search bar ─────────────────────────── */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, HDR_H);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, 2);
|
||||
|
||||
ds(l, xd, l->font_logo, C_ACCENT, 14, 13, "OrionOS");
|
||||
|
||||
/* search box */
|
||||
/* search input box */
|
||||
{
|
||||
int sx = 86, sy = 10, sw = WIN_W - 86 - 14, sh = 30;
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SEARCH));
|
||||
int sx = 16, sy = 11, sw = WIN_W - 32, sh = 36;
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SRCH_BG));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sx, sy, sw, sh);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SEARCH_BD));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, sx, sy, sw, sh);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l,
|
||||
l->filter_len > 0 ? C_BORDER_HV : C_SRCH_BD));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, sx, sy, sw - 1, sh - 1);
|
||||
|
||||
/* accent left bar when active */
|
||||
if (l->filter_len > 0) {
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sx, sy, 2, sh);
|
||||
}
|
||||
|
||||
if (l->filter_len == 0) {
|
||||
ds(l, xd, l->font_ui, C_TEXT_DIM, sx + 8, sy + 7, "Search apps...");
|
||||
ds(l, xd, l->font_ui, C_TEXT_DIM, sx + 12, sy + 10, "Search applications...");
|
||||
} else {
|
||||
char buf[MAX_FLT + 2];
|
||||
snprintf(buf, sizeof(buf), "%s|", l->filter);
|
||||
ds(l, xd, l->font_ui, C_TEXT_HOV, sx + 8, sy + 7, buf);
|
||||
snprintf(buf, sizeof(buf), "%s_", l->filter);
|
||||
ds(l, xd, l->font_ui, C_TEXT_HOV, sx + 12, sy + 10, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* header bottom separator */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||
XDrawLine(l->dpy, l->win, l->gc, 0, HDR_H, WIN_W, HDR_H);
|
||||
XDrawLine(l->dpy, l->win, l->gc, 0, HDR_H - 1, WIN_W, HDR_H - 1);
|
||||
|
||||
/* ── pills row ───────────────────────────────────── */
|
||||
int pw[NCAT], ptotal; pill_layout(l, pw, &ptotal);
|
||||
int px = (WIN_W - ptotal) / 2;
|
||||
int py = HDR_H + (PILLS_H - 24) / 2;
|
||||
|
||||
/* category tabs */
|
||||
int tw[NCAT], ttotal; tab_layout(l, tw, &ttotal);
|
||||
int tx = (WIN_W - ttotal) / 2;
|
||||
for (int i = 0; i < NCAT; i++) {
|
||||
if (i == l->sel_cat) {
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_TAB_SEL));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, tx, HDR_H + 1, tw[i], TAB_H - 1);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, tx + 5, HDR_H + TAB_H - 2, tw[i] - 10, 2);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_PILL_SEL));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, px, py, pw[i], 24);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_PILL_BD));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, px, py, pw[i] - 1, 23);
|
||||
ds_ctr(l, xd, l->font_ui, C_TEXT_CAT_S, px, py, pw[i], 24, CATS[i]);
|
||||
} else {
|
||||
ds_ctr(l, xd, l->font_ui, C_TEXT_CAT, px, py, pw[i], 24, CATS[i]);
|
||||
}
|
||||
ds_ctr(l, xd, l->font_ui,
|
||||
(i == l->sel_cat) ? C_TAB_TSEL : C_TAB_TXT,
|
||||
tx, HDR_H, tw[i], TAB_H, CATS[i]);
|
||||
tx += tw[i];
|
||||
px += pw[i] + PILL_GAP;
|
||||
}
|
||||
|
||||
/* pills bottom separator */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||
XDrawLine(l->dpy, l->win, l->gc, 0, CONTENT_Y, WIN_W, CONTENT_Y);
|
||||
XDrawLine(l->dpy, l->win, l->gc, 0, CONTENT_Y - 1, WIN_W, CONTENT_Y - 1);
|
||||
|
||||
/* app grid with scroll */
|
||||
/* ── app grid ────────────────────────────────────── */
|
||||
int vis[MAX_APPS];
|
||||
int nv = nvis(l, vis);
|
||||
|
||||
/* clamp scroll */
|
||||
int max_scroll = (nv - ROWS_VIS * COLS + COLS - 1) / COLS;
|
||||
if (max_scroll < 0) max_scroll = 0;
|
||||
if (l->scroll > max_scroll) l->scroll = max_scroll;
|
||||
@@ -395,7 +402,8 @@ static void draw(L *l) {
|
||||
|
||||
if (nv == 0) {
|
||||
ds_ctr(l, xd, l->font_ui, C_TEXT_DIM,
|
||||
0, CONTENT_Y, WIN_W, WIN_H - CONTENT_Y, "No apps found");
|
||||
0, CONTENT_Y, WIN_W, WIN_H - CONTENT_Y - FOOTER_H,
|
||||
"No matching apps");
|
||||
} else {
|
||||
for (int i = 0; i < ROWS_VIS * COLS; i++) {
|
||||
int vi = vis_start + i;
|
||||
@@ -406,18 +414,29 @@ static void draw(L *l) {
|
||||
int cy = GY0 + row * (CARD_H + CARD_GAP);
|
||||
int hover = (i == l->hov);
|
||||
|
||||
/* card background */
|
||||
if (hover) {
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_CARD_HOV));
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE_HV));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W, CARD_H);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_CARD_BD));
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER_HV));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W - 1, CARD_H - 1);
|
||||
/* accent top bar on hover */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, cx + 1, cy, CARD_W - 2, 2);
|
||||
} else {
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W, CARD_H);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W - 1, CARD_H - 1);
|
||||
}
|
||||
|
||||
int app_i = vis[vi];
|
||||
unsigned int h = 0;
|
||||
for (const char *p = APPS[app_i].name; *p; p++) h = h * 31 + (unsigned char)*p;
|
||||
|
||||
/* icon */
|
||||
int ix = cx + (CARD_W - ICON_SZ) / 2;
|
||||
int iy = cy + 10;
|
||||
int iy = cy + 14;
|
||||
int icon_rendered = 0;
|
||||
#ifdef HAVE_IMLIB2
|
||||
icon_rendered = render_icon(l, APPS[app_i].icon, ix, iy, ICON_SZ);
|
||||
@@ -425,34 +444,57 @@ static void draw(L *l) {
|
||||
if (!icon_rendered) {
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, ICON_BG[h % NICON]));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, ix, iy, ICON_SZ, ICON_SZ);
|
||||
/* 1px darker border on icon box */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, 0x000000));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, ix, iy, ICON_SZ - 1, ICON_SZ - 1);
|
||||
char letter[2] = { APPS[app_i].name[0], '\0' };
|
||||
if (letter[0] >= 'a' && letter[0] <= 'z') letter[0] -= 32;
|
||||
ds_ctr(l, xd, l->font_icon, 0xEAF0FF, ix, iy, ICON_SZ, ICON_SZ, letter);
|
||||
ds_ctr(l, xd, l->font_icon, 0xF0F4FF,
|
||||
ix, iy, ICON_SZ, ICON_SZ, letter);
|
||||
}
|
||||
|
||||
char lbl[14];
|
||||
snprintf(lbl, sizeof(lbl), "%.12s", APPS[app_i].name);
|
||||
/* label */
|
||||
char lbl[16];
|
||||
snprintf(lbl, sizeof(lbl), "%.14s", APPS[app_i].name);
|
||||
ds_ctr(l, xd, l->font_ui,
|
||||
hover ? C_TEXT_HOV : C_TEXT,
|
||||
cx, iy + ICON_SZ + 4, CARD_W, CARD_H - ICON_SZ - 18, lbl);
|
||||
cx, iy + ICON_SZ + 6, CARD_W, CARD_H - ICON_SZ - 24, lbl);
|
||||
}
|
||||
}
|
||||
|
||||
/* scrollbar */
|
||||
if (max_scroll > 0) {
|
||||
int sb_x = WIN_W - 8, sb_y = CONTENT_Y + 4;
|
||||
int sb_h = WIN_H - CONTENT_Y - 8;
|
||||
int sb_x = WIN_W - 6;
|
||||
int sb_y = CONTENT_Y + 4;
|
||||
int sb_h = WIN_H - CONTENT_Y - FOOTER_H - 8;
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_BG));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x, sb_y, 6, sb_h);
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x, sb_y, 4, sb_h);
|
||||
int total_rows = (nv + COLS - 1) / COLS;
|
||||
int thumb_h = sb_h * ROWS_VIS / total_rows;
|
||||
if (thumb_h < 12) thumb_h = 12;
|
||||
if (thumb_h < 10) thumb_h = 10;
|
||||
int thumb_y = sb_y + (sb_h - thumb_h) * l->scroll / max_scroll;
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_TH));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x + 1, thumb_y, 4, thumb_h);
|
||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x, thumb_y, 4, thumb_h);
|
||||
}
|
||||
|
||||
/* outer border */
|
||||
/* ── footer ──────────────────────────────────────── */
|
||||
int fy = WIN_H - FOOTER_H;
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_FOOTER_BG));
|
||||
XFillRectangle(l->dpy, l->win, l->gc, 0, fy, WIN_W, FOOTER_H);
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||
XDrawLine(l->dpy, l->win, l->gc, 0, fy, WIN_W, fy);
|
||||
|
||||
/* app count left, hints right */
|
||||
{
|
||||
char cnt[32];
|
||||
snprintf(cnt, sizeof(cnt), "%d apps", nv);
|
||||
ds(l, xd, l->font_hint, C_FOOTER_TXT, 14, fy + 7, cnt);
|
||||
ds_ctr(l, xd, l->font_hint, C_FOOTER_TXT,
|
||||
0, fy, WIN_W, FOOTER_H,
|
||||
"Return: launch Esc: close Type: filter");
|
||||
}
|
||||
|
||||
/* outer window border */
|
||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||
XDrawRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W - 1, WIN_H - 1);
|
||||
|
||||
@@ -482,7 +524,6 @@ static void on_key(L *l, XKeyEvent *e) {
|
||||
l->filter[--l->filter_len] = '\0';
|
||||
l->scroll = 0; l->hov = -1; draw(l); return;
|
||||
}
|
||||
/* page up/down for keyboard scroll */
|
||||
if (sym == XK_Prior) { l->scroll -= ROWS_VIS; if (l->scroll < 0) l->scroll = 0; draw(l); return; }
|
||||
if (sym == XK_Next) { l->scroll += ROWS_VIS; draw(l); return; }
|
||||
|
||||
@@ -510,11 +551,11 @@ int main(void) {
|
||||
l.visual = DefaultVisual(l.dpy, l.screen);
|
||||
|
||||
l.font_ui = XftFontOpenName(l.dpy, l.screen, FONT_UI);
|
||||
l.font_logo = XftFontOpenName(l.dpy, l.screen, FONT_LOGO);
|
||||
l.font_icon = XftFontOpenName(l.dpy, l.screen, FONT_ICON);
|
||||
l.font_hint = XftFontOpenName(l.dpy, l.screen, FONT_HINT);
|
||||
if (!l.font_ui) l.font_ui = XftFontOpenName(l.dpy, l.screen, "fixed:size=9");
|
||||
if (!l.font_logo) l.font_logo = l.font_ui;
|
||||
if (!l.font_icon) l.font_icon = l.font_ui;
|
||||
if (!l.font_hint) l.font_hint = l.font_ui;
|
||||
|
||||
int sw = DisplayWidth(l.dpy, l.screen);
|
||||
int sh = DisplayHeight(l.dpy, l.screen);
|
||||
@@ -544,14 +585,13 @@ int main(void) {
|
||||
if (e.xexpose.count == 0) draw(&l);
|
||||
break;
|
||||
case ButtonPress:
|
||||
{
|
||||
/* scroll wheel */
|
||||
if (e.xbutton.button == Button4) {
|
||||
l.scroll -= 1; if (l.scroll < 0) l.scroll = 0; draw(&l); break;
|
||||
}
|
||||
if (e.xbutton.button == Button5) {
|
||||
l.scroll += 1; draw(&l); break;
|
||||
}
|
||||
{
|
||||
int t = tab_at(&l, e.xbutton.x, e.xbutton.y);
|
||||
if (t >= 0) {
|
||||
l.sel_cat = t; l.scroll = 0; l.hov = -1; draw(&l);
|
||||
|
||||
+6
-7
@@ -6,19 +6,18 @@
|
||||
|
||||
static const MenuItem MENU_ITEMS[] = {
|
||||
{ "App Launcher", "orionlauncher &" },
|
||||
{ "Terminal", "alacritty &" },
|
||||
{ "File Manager", "rigel &" },
|
||||
{ "Text Editor", "quill &" },
|
||||
{ "Terminal", "xterm &" },
|
||||
{ "File Manager", "pcmanfm &" },
|
||||
{ "Text Editor", "mousepad &" },
|
||||
{ "──────────────────", NULL },
|
||||
{ "Web Browser", "firefox &" },
|
||||
{ "System Monitor", "alacritty -T 'System Monitor' -e htop &" },
|
||||
{ "Volume Control", "pavucontrol &" },
|
||||
{ "System Settings", "nebula &" },
|
||||
{ "System Monitor", "xterm -T 'System Monitor' -e htop &" },
|
||||
{ "Volume Control", "xterm -e alsamixer &" },
|
||||
{ "Software Updates", "orionpkg &" },
|
||||
{ "Display Settings", "arandr &" },
|
||||
{ "──────────────────", NULL },
|
||||
{ "Change Wallpaper", "orionwallpaper --reset &" },
|
||||
{ "Install OrionOS", "alacritty -e bash -c 'sudo orioninstall-gui 2>/dev/null || sudo orioninstall; exec bash' &" },
|
||||
{ "Install OrionOS", "pkexec orioninstall-gui &" },
|
||||
{ "──────────────────", NULL },
|
||||
{ "Restart OrionWM", "pkill orionwm; sleep 0.2; orionwm &" },
|
||||
{ "Quit OrionOS", "pkill orionwm" },
|
||||
|
||||
Reference in new issue
Block a user