#!/bin/sh # Hammerhead Openbox autostart - Zygaena marine-dark identity. # Idempotent: only launch a daemon if it isn't already running, so # `openbox --restart` doesn't spawn duplicate panels. running() { ps -ef | grep -v grep | grep -q "$1"; } running "[p]icom" || picom --backend xrender -b 2>/dev/null & # tint2 finds its config live via XDG_CONFIG_DIRS; conky does NOT honor # XDG_CONFIG_DIRS, so give it the system config path explicitly (stays live). running "[t]int2" || tint2 & running "[c]onky" || conky -c @@PREFIX@@/etc/xdg/conky/conky.conf & feh --bg-fill @@PREFIX@@/share/backgrounds/hammerhead.png 2>/dev/null & #!/bin/sh # Build script for hammerhead-desktop (Zygaena marine-dark branding config). # # No upstream tarball - all inputs are local files shipped alongside this # script in the port directory. The only compiled artifact is the cairo # wallpaper generator, built and run once here (its output PNG is what # actually ships - the generator binary itself is not installed). set -e PORTDIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH" # --- Step 1: build + run the wallpaper generator --- gcc "$PORTDIR/wallpaper-gen.c" $(pkg-config --cflags --libs cairo) -lm -o "$PORTDIR/wg" mkdir -p "$PKGDIR$PREFIX/share/backgrounds" "$PORTDIR/wg" "$PKGDIR$PREFIX/share/backgrounds/hammerhead.png" # --- Step 2: Openbox theme --- mkdir -p "$PKGDIR$PREFIX/share/themes/Hammerhead/openbox-3" cp "$PORTDIR/themerc" "$PKGDIR$PREFIX/share/themes/Hammerhead/openbox-3/themerc" # --- Step 3: tint2 panel config --- # Matches the existing tint2 port's own default install location # ($PREFIX/etc/xdg/tint2 - tint2's cmake build doesn't honor # --sysconfdir), and what the integration step's XDG_CONFIG_DIRS # ($PREFIX/etc/xdg) resolves against. mkdir -p "$PKGDIR$PREFIX/etc/xdg/tint2" cp "$PORTDIR/tint2rc" "$PKGDIR$PREFIX/etc/xdg/tint2/tint2rc" # --- Step 4: conky config --- mkdir -p "$PKGDIR$PREFIX/etc/xdg/conky" cp "$PORTDIR/conky.conf" "$PKGDIR$PREFIX/etc/xdg/conky/conky.conf" # --- Step 5: Openbox rc.xml + menu.xml --- mkdir -p "$PKGDIR$PREFIX/etc/xdg/openbox" cp "$PORTDIR/rc.xml" "$PKGDIR$PREFIX/etc/xdg/openbox/rc.xml" cp "$PORTDIR/menu.xml" "$PKGDIR$PREFIX/etc/xdg/openbox/menu.xml" # --- Step 6: autostart (substitute the real $PREFIX) --- sed "s#@@PREFIX@@#$PREFIX#g" "$PORTDIR/autostart" \ > "$PKGDIR$PREFIX/etc/xdg/openbox/autostart" chmod 755 "$PKGDIR$PREFIX/etc/xdg/openbox/autostart" # --- Step 7: screenshot tool (hh-grab XGetImage->PNG + hh-screenshot wrapper) --- # Bound to Print in rc.xml; saves to ~/Pictures/hh-.png. mkdir -p "$PKGDIR$PREFIX/bin" gcc "$PORTDIR/hh-grab.c" -I"$PREFIX/include" -L"$PREFIX/lib" -R"$PREFIX/lib" -lX11 -lpng \ -o "$PKGDIR$PREFIX/bin/hh-grab" install -m 755 "$PORTDIR/hh-screenshot" "$PKGDIR$PREFIX/bin/hh-screenshot" # --- Step 8: PDF/image launcher wrappers + branded welcome PDF --- gcc "$PORTDIR/pdf-gen.c" $(pkg-config --cflags --libs cairo) -o "$PORTDIR/pdfgen" mkdir -p "$PKGDIR$PREFIX/share/hammerhead" "$PORTDIR/pdfgen" "$PKGDIR$PREFIX/share/hammerhead/welcome.pdf" rm -f "$PORTDIR/pdfgen" install -m 755 "$PORTDIR/hh-pdf" "$PKGDIR$PREFIX/bin/hh-pdf" install -m 755 "$PORTDIR/hh-images" "$PKGDIR$PREFIX/bin/hh-images" # --- Step 9: Openbox pipemenus (Places, Recent Files) --- # GTK-free, POSIX-sh, pattern adapted from CrunchBang++'s # cbpp-places-pipemenu / cbpp-recent-files-pipemenu; referenced from # menu.xml via execute="hh-places-pipemenu" / "hh-recent-pipemenu". install -m 755 "$PORTDIR/hh-places-pipemenu" "$PKGDIR$PREFIX/bin/hh-places-pipemenu" install -m 755 "$PORTDIR/hh-recent-pipemenu" "$PKGDIR$PREFIX/bin/hh-recent-pipemenu" # --- Step 10: branded tint2 launcher icons + .desktop entries --- # The stock launcher was illegible: st ships no icon, xnedit's png was loose, # and hicolor had no index.theme so name-lookup failed. We ship our own cairo # glyphs and point each .desktop Icon= at an ABSOLUTE path, which tint2 loads # directly (no icon theme required). tint2rc references these three by path. gcc "$PORTDIR/icon-gen.c" $(pkg-config --cflags --libs cairo) -lm -o "$PORTDIR/ig" mkdir -p "$PKGDIR$PREFIX/share/hammerhead-desktop/launcher" "$PORTDIR/ig" "$PKGDIR$PREFIX/share/hammerhead-desktop/launcher" rm -f "$PKGDIR$PREFIX/share/hammerhead-desktop/launcher/preview.png" # review-only rm -f "$PORTDIR/ig" mkdir -p "$PKGDIR$PREFIX/share/applications" cp "$PORTDIR/hh-terminal.desktop" "$PORTDIR/hh-files.desktop" \ "$PORTDIR/hh-editor.desktop" "$PKGDIR$PREFIX/share/applications/" # Clean up the transient build helper - not shipped. rm -f "$PORTDIR/wg" # --- Step 11: /etc/skel/.xsession (Task 4b) --- # New users' home dirs are seeded from /etc/skel, so this makes a fresh # account's X session default to the Openbox desktop without any manual # ~/.xsession setup. mkdir -p "$PKGDIR/etc/skel" install -m 755 "$PORTDIR/dot-xsession" "$PKGDIR/etc/skel/.xsession" # --- Step 12: hh-desktop-init (per-user ~/.config seed, CBPP-style) --- # openbox-autostart only reads ~/.config or /etc/xdg (not our /usr/local/etc/xdg), # so the X session entrypoints call this to seed ~/.config on login for new AND # existing users (copy-if-missing). install -m 755 "$PORTDIR/hh-desktop-init" "$PKGDIR$PREFIX/bin/hh-desktop-init" -- Hammerhead conky config - Zygaena marine-dark identity -- Installed to $PREFIX/etc/xdg/conky/conky.conf -- Uses conky's native illumos/kstat stat backend (no ${exec} shellouts -- needed for cpu/mem/fs/net - see task brief). -- -- Typography/layout adapted from CrunchBang++'s signature right-side -- conky (github.com/CBPP/cbpp-configs, simon-weber/crunchbang-conf): -- monospace, right-aligned, uppercase section labels over hairline -- rules, compact bars. Restyled teal-on-dark instead of CBPP's grey/red, -- and kept our native kstat vars (no CBPP-style ${exec} shellouts). conky.config = { own_window = true, own_window_type = 'desktop', own_window_transparent = true, own_window_argb_visual = true, own_window_argb_value = 200, own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager', alignment = 'top_right', gap_x = 24, gap_y = 40, minimum_width = 260, maximum_width = 300, update_interval = 2.0, double_buffer = true, use_xft = true, font = 'monospace:size=9', default_color = 'cfe0e0', color1 = '1fb6b6', -- headings / accents color2 = '5a7575', -- muted / rules draw_shades = false, draw_outline = false, draw_borders = false, background = false, } conky.text = [[ ${alignr}${color1}${font monospace:bold:size=14}HAMMERHEAD${font}${color} ${alignr}${color2}${nodename}${color} ${alignr}${color2}${hr 1}${color} ${alignr}${color1}SYSTEM${color} ${alignr}uptime ${color1}${uptime}${color} ${alignr}load ${color1}${loadavg}${color} ${alignr}${color1}CPU${color} ${alignr}${cpu}%${color} ${alignr}${cpubar 6,220} ${alignr}${color1}MEMORY${color} ${alignr}${mem} / ${memmax}${color} ${alignr}${membar 6,220} ${alignr}${color1}DISK (/)${color} ${alignr}${fs_used /} / ${fs_size /}${color} ${alignr}${fs_bar 6,220 /} ${alignr}${color1}NETWORK${color} ${alignr}down ${color1}${downspeed}${color} / up ${color1}${upspeed}${color} ]] #!/bin/sh # Hammerhead default X session - launch the Openbox desktop. # # Put the Hammerhead desktop config (/usr/local/etc/xdg) on the XDG search # path so openbox/tint2/conky find the branded config without ~/.config. # (xdm's Xsession also sets this; repeated here so `startx`/xinit users, who # run ~/.xsession directly, get the branded desktop too.) export XDG_CONFIG_DIRS="/usr/local/etc/xdg:${XDG_CONFIG_DIRS:-/etc/xdg}" export XDG_DATA_DIRS="/usr/local/share:${XDG_DATA_DIRS:-/usr/share}" # Seed ~/.config so openbox-autostart (which only reads ~/.config or /etc/xdg) # runs our autostart -> tint2/conky/wallpaper. See hh-desktop-init. /usr/local/bin/hh-desktop-init exec /usr/local/bin/openbox-session #!/bin/sh # hh-desktop-init - point the user's openbox autostart at the LIVE system # autostart so desktop-config updates ALWAYS take, with no per-user copies to # go stale. Called from the X session entrypoint before openbox-session. # # Why only the autostart: openbox-autostart (run by openbox-session) reads only # /etc/xdg/openbox/autostart or ~/.config/openbox/autostart -- NOT # XDG_CONFIG_DIRS -- so the autostart is the single desktop file that must live # under ~/.config. Everything else resolves live from /usr/local/etc/xdg via # XDG_CONFIG_DIRS (set by the X session): openbox rc.xml/menu.xml and tint2rc; # conky is launched by the autostart with an explicit -c path. So none of those # need a per-user copy. # # We make ~/.config/openbox/autostart a SYMLINK to the system autostart (not a # copy), so a package update to the autostart is picked up with no re-seed. # A pre-existing non-symlink here is treated as legacy seeded state and migrated # to the symlink. SYS=/usr/local/etc/xdg/openbox/autostart CFG="${XDG_CONFIG_HOME:-$HOME/.config}/openbox" mkdir -p "$CFG" 2>/dev/null || exit 0 if [ "$(readlink "$CFG/autostart" 2>/dev/null)" != "$SYS" ]; then rm -f "$CFG/autostart" 2>/dev/null ln -sf "$SYS" "$CFG/autostart" 2>/dev/null fi exit 0 [Desktop Entry] Type=Application Name=Editor Comment=XNEdit text editor Exec=/usr/local/bin/xnc -tabbed %F Icon=/usr/local/share/hammerhead-desktop/launcher/editor.png Categories=Utility;TextEditor; Terminal=false [Desktop Entry] Type=Application Name=Files Comment=Xfe file manager Exec=xfe Icon=/usr/local/share/hammerhead-desktop/launcher/files.png Categories=System;FileManager; Terminal=false #include #include #include #include #include int main(int c,char**v){Display*d=XOpenDisplay(NULL);if(!d){fprintf(stderr,"no display\n");return 1;} Window r=DefaultRootWindow(d);XWindowAttributes g;XGetWindowAttributes(d,r,&g); XImage*im=XGetImage(d,r,0,0,g.width,g.height,AllPlanes,ZPixmap);if(!im)return 1; FILE*f=fopen(c>1?v[1]:"screenshot.png","wb");png_structp p=png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); png_infop i=png_create_info_struct(p);png_init_io(p,f);png_set_IHDR(p,i,g.width,g.height,8,PNG_COLOR_TYPE_RGB,0,0,0); png_write_info(p,i);png_bytep row=malloc(3*g.width);for(int y=0;y>16)&0xFF;row[3*x+1]=(px>>8)&0xFF;row[3*x+2]=px&0xFF;}png_write_row(p,row);} png_write_end(p,i);fclose(f);return 0;} #!/bin/sh mkdir -p "$HOME/Pictures" exec /usr/local/bin/feh --auto-zoom --scale-down --geometry 1000x720 "$HOME/Pictures" /usr/local/share/backgrounds #!/bin/sh [ -n "$1" ] && exec /usr/local/bin/mupdf-x11 "$@" exec /usr/local/bin/mupdf-x11 /usr/local/share/hammerhead/welcome.pdf #!/bin/sh # hh-places-pipemenu - Openbox "Places" pipe menu (GTK-free) # # Pattern adapted from CrunchBang++'s cbpp-places-pipemenu # (github.com/CBPP/cbpp-pipemenus, Copyright (C) 2010 John Crawley, # ported to #!++ by Ben Young) - same idea (walk a directory, XML-escape # names, emit an ) but rewritten small/flat for our # stack: no thunar/exo-open/geany, no recursive submenus. Every entry # opens in xfe; a matching terminal entry opens st in that directory. # # Usage: # in menu.xml. Invoked with no arguments; always lists $HOME's immediate # subdirectories (dotdirs skipped). # # NB: the shell, not bash - keep this POSIX sh / dash-fast per upstream. files="xfe" xml_escape() { # $1 -> escaped on stdout printf '%s' "$1" | sed \ -e 's/&/\&/g' \ -e 's//\>/g' \ -e 's/"/\"/g' } home="${HOME:-/root}" printf '\n' printf ' \n' printf ' %s %s\n' "$files" "$(xml_escape "$home")" printf ' \n' printf ' \n' printf ' st -d %s\n' "$(xml_escape "$home")" printf ' \n' printf ' \n' # Immediate subdirectories of $HOME, skipping dotdirs, alphabetical. for d in "$home"/*/; do [ -d "$d" ] || continue d="${d%/}" base="${d##*/}" case "$base" in .*) continue ;; esac label="$(xml_escape "$base")" path="$(xml_escape "$d")" printf ' \n' "$label" printf ' %s %s\n' "$files" "$path" printf ' \n' printf ' \n' "$label" printf ' st -d %s\n' "$path" printf ' \n' done printf '\n' #!/bin/sh # hh-recent-pipemenu - Openbox "Recent Files" pipe menu (GTK-free) # # Loosely modeled on CrunchBang++'s cbpp-recent-files-pipemenu # (github.com/CBPP/cbpp-pipemenus), but that one parses GTK's # ~/.local/share/recently-used.xbel, which nothing on Hammerhead writes # (no GTK). Instead: find(1) over $HOME for recently-modified # docs/images, opened with the matching viewer. # # Usage: max_entries=12 home="${HOME:-/root}" xml_escape() { printf '%s' "$1" | sed \ -e 's/&/\&/g' \ -e 's//\>/g' \ -e 's/"/\"/g' } viewer_for() { case "$1" in *.pdf) echo "hh-pdf" ;; *.png|*.jpg|*.jpeg|*.gif|*.bmp) echo "hh-images" ;; *) echo "xnedit" ;; esac } printf '\n' count=0 find "$home" -maxdepth 3 -type f \ \( -iname '*.pdf' -o -iname '*.txt' -o -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' \) \ -mtime -14 -print 2>/dev/null | while IFS= read -r f; do viewer="$(viewer_for "$f")" label="$(xml_escape "${f##*/}")" path="$(xml_escape "$f")" printf ' \n' "$label" printf ' %s %s\n' "$viewer" "$path" printf ' \n' count=$((count + 1)) [ "$count" -ge "$max_entries" ] && break done printf '\n' #!/bin/sh mkdir -p "$HOME/Pictures" exec /usr/local/bin/hh-grab "$HOME/Pictures/hh-$(date +%Y%m%d-%H%M%S).png" [Desktop Entry] Type=Application Name=Terminal Comment=st terminal emulator Exec=st Icon=/usr/local/share/hammerhead-desktop/launcher/terminal.png Categories=System;TerminalEmulator; Terminal=false /* * icon-gen.c - Zygaena marine-dark launcher icon generator. * * Renders three 48x48 ARGB launcher glyphs - terminal, files, editor - in * the Hammerhead teal palette (matching wallpaper-gen.c). tint2 loads these * by ABSOLUTE path (Icon=/usr/local/share/hammerhead-desktop/launcher/*.png), * so no freedesktop icon theme / hicolor index.theme is required - which is * exactly why the stock launcher was illegible (st shipped no icon, xnedit's * png was loose, hicolor had no index.theme). * * Build: gcc icon-gen.c $(pkg-config --cflags --libs cairo) -lm -o ig * Usage: ./ig /output/dir (writes terminal.png, files.png, editor.png, * and preview.png for design review) */ #include #include #include #define S 48 /* icon canvas size */ /* palette - matches wallpaper-gen.c */ #define TILE_R 0x12/255.0 #define TILE_G 0x2e/255.0 #define TILE_B 0x34/255.0 #define TEAL_R 0x1f/255.0 #define TEAL_G 0xb6/255.0 #define TEAL_B 0xb6/255.0 #define TEALBR_R 0x54/255.0 #define TEALBR_G 0xe0/255.0 #define TEALBR_B 0xe0/255.0 #define TEXT_R 0xcf/255.0 #define TEXT_G 0xe0/255.0 #define TEXT_B 0xe0/255.0 static void rrect(cairo_t *cr, double x, double y, double w, double h, double r) { cairo_new_sub_path(cr); cairo_arc(cr, x + w - r, y + r, r, -M_PI / 2, 0); cairo_arc(cr, x + w - r, y + h - r, r, 0, M_PI / 2); cairo_arc(cr, x + r, y + h - r, r, M_PI / 2, M_PI); cairo_arc(cr, x + r, y + r, r, M_PI, 3 * M_PI / 2); cairo_close_path(cr); } /* subtle elevated chip so the three icons read as one branded set */ static void tile(cairo_t *cr) { rrect(cr, 2.5, 2.5, S - 5, S - 5, 10); cairo_set_source_rgb(cr, TILE_R, TILE_G, TILE_B); cairo_fill_preserve(cr); cairo_set_source_rgba(cr, TEAL_R, TEAL_G, TEAL_B, 0.40); cairo_set_line_width(cr, 1.5); cairo_stroke(cr); } /* Terminal: a prompt chevron ">" plus a cursor underscore "_". */ static void draw_terminal(cairo_t *cr) { tile(cr); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); cairo_set_source_rgb(cr, TEALBR_R, TEALBR_G, TEALBR_B); cairo_set_line_width(cr, 4.4); cairo_move_to(cr, 15, 16); cairo_line_to(cr, 25, 24); cairo_line_to(cr, 15, 32); cairo_stroke(cr); cairo_set_source_rgb(cr, TEXT_R, TEXT_G, TEXT_B); cairo_set_line_width(cr, 4.0); cairo_move_to(cr, 27, 33); cairo_line_to(cr, 34, 33); cairo_stroke(cr); } /* Files: a two-tone manila folder (tab + body). */ static void draw_files(cairo_t *cr) { tile(cr); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); /* tab peeking above the body's top-left */ cairo_set_source_rgb(cr, TEAL_R, TEAL_G, TEAL_B); rrect(cr, 11, 14, 14, 8, 2.5); cairo_fill(cr); /* back body */ rrect(cr, 11, 18, 26, 17, 3); cairo_fill(cr); /* front pocket, lighter, slightly inset - gives the folder depth */ cairo_set_source_rgb(cr, TEALBR_R, TEALBR_G, TEALBR_B); rrect(cr, 13, 23, 22, 12, 2.5); cairo_fill(cr); } /* Editor: a pencil at 45 degrees (eraser, shaft, nib, tip). */ static void draw_editor(cairo_t *cr) { tile(cr); cairo_save(cr); cairo_translate(cr, 24, 24); cairo_rotate(cr, -M_PI / 4); double pw = 8, half = pw / 2; /* shaft */ cairo_set_source_rgb(cr, TEAL_R, TEAL_G, TEAL_B); rrect(cr, -half, -13, pw, 19, 1.5); cairo_fill(cr); /* eraser (top) */ cairo_set_source_rgb(cr, TEXT_R, TEXT_G, TEXT_B); rrect(cr, -half, -16.5, pw, 4, 1.2); cairo_fill(cr); /* nib (bottom), brighter teal */ cairo_set_source_rgb(cr, TEALBR_R, TEALBR_G, TEALBR_B); cairo_move_to(cr, -half, 6); cairo_line_to(cr, half, 6); cairo_line_to(cr, 0, 14); cairo_close_path(cr); cairo_fill(cr); /* graphite tip */ cairo_set_source_rgb(cr, TILE_R, TILE_G, TILE_B); cairo_move_to(cr, -2.2, 10.5); cairo_line_to(cr, 2.2, 10.5); cairo_line_to(cr, 0, 14); cairo_close_path(cr); cairo_fill(cr); cairo_restore(cr); } typedef void (*drawfn)(cairo_t *); static void emit(const char *dir, const char *name, drawfn fn) { char path[1024]; cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, S, S); cairo_t *cr = cairo_create(s); fn(cr); snprintf(path, sizeof path, "%s/%s", dir, name); cairo_surface_write_to_png(s, path); printf("wrote %s\n", path); cairo_destroy(cr); cairo_surface_destroy(s); } /* Review sheet: each glyph at 3x (detail) over the same glyph at 22px * (real launcher size) on a panel-tone strip, so legibility is judged at * the size it will actually render. */ static void emit_preview(const char *dir) { drawfn fns[3] = { draw_terminal, draw_files, draw_editor }; int cw = 160, W = cw * 3, H = 210; char path[1024]; cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, W, H); cairo_t *cr = cairo_create(s); cairo_set_source_rgb(cr, 0x0d / 255.0, 0x11 / 255.0, 0x17 / 255.0); cairo_paint(cr); for (int i = 0; i < 3; i++) { cairo_save(cr); cairo_translate(cr, i * cw + (cw - 144) / 2.0, 8); cairo_scale(cr, 144.0 / S, 144.0 / S); fns[i](cr); cairo_restore(cr); } /* panel strip */ cairo_set_source_rgb(cr, 0x0e / 255.0, 0x1c / 255.0, 0x1f / 255.0); cairo_rectangle(cr, 0, 168, W, 42); cairo_fill(cr); for (int i = 0; i < 3; i++) { cairo_save(cr); cairo_translate(cr, i * cw + (cw - 22) / 2.0, 178); cairo_scale(cr, 22.0 / S, 22.0 / S); fns[i](cr); cairo_restore(cr); } snprintf(path, sizeof path, "%s/preview.png", dir); cairo_surface_write_to_png(s, path); printf("wrote %s\n", path); cairo_destroy(cr); cairo_surface_destroy(s); } int main(int argc, char **argv) { const char *dir = (argc > 1) ? argv[1] : "."; emit(dir, "terminal.png", draw_terminal); emit(dir, "files.png", draw_files); emit(dir, "editor.png", draw_editor); emit_preview(dir); return 0; } xnedit st -e nvim xfe hh-images hh-pdf st st xfe dmenu_run pfexec /sbin/zygctl reboot Reboot the system? pfexec /sbin/zygctl poweroff Shut down the system? yes # hammerhead-desktop - Zygaena marine-dark desktop branding/config # (wallpaper, Openbox theme, tint2/conky configs, menu/keybinds, autostart) # # No upstream source - this port carries its own config files + a small # cairo program (wallpaper-gen.c) that renders the branded wallpaper PNG # at package-build time. See build.sh. [package] name = "hammerhead-desktop" version = "1.7.0" release = 1 description = "Zygaena marine-dark desktop branding: wallpaper, Openbox theme, tint2/conky configs, categorized menu w/ CBPP-style Places/Recent pipemenus + Shutdown/Reboot (pfexec zygctl), autostart" url = "https://git.sharkos.one/zygaena/hammerhead" license = "CDDL-1.0" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["openbox", "tint2", "conky", "picom", "feh", "dmenu", "st", "xfe", "mupdf", "xnedit", "cairo", "libpng"] build = ["cairo", "libpng"] [build] parallel = false #include #include int main(int c,char**v){ cairo_surface_t*s=cairo_pdf_surface_create(c>1?v[1]:"welcome.pdf",612,792); cairo_t*cr=cairo_create(s); cairo_set_source_rgb(cr,0.02,0.035,0.06); cairo_paint(cr); cairo_set_source_rgb(cr,0.12,0.71,0.71); cairo_rectangle(cr,0,0,612,8); cairo_fill(cr); cairo_select_font_face(cr,"sans",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr,40); cairo_set_source_rgb(cr,0.12,0.71,0.71); cairo_move_to(cr,60,120); cairo_show_text(cr,"HAMMERHEAD"); cairo_select_font_face(cr,"sans",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr,15); cairo_set_source_rgb(cr,0.55,0.68,0.68); cairo_move_to(cr,62,148); cairo_show_text(cr,"Zygaena Operating System"); const char*L[]={"Welcome to your Hammerhead desktop.","", "This document is displayed by mupdf, built from source for", "Hammerhead - a 64-bit illumos-derived OS with a modern GNU", "toolchain running an XLibre + Openbox desktop, all GTK-free.","", "Keys: Super+Return terminal Super+f files Super+e editor", " Super+Space launcher Right-click the desktop for the menu.",0}; cairo_set_font_size(cr,14); double y=210; for(int i=0;L[i];i++){cairo_set_source_rgb(cr,0.82,0.9,0.9);cairo_move_to(cr,60,y);cairo_show_text(cr,L[i]);y+=26;} cairo_show_page(cr); cairo_destroy(cr); cairo_surface_destroy(s); return 0;} 10 20 yes no yes Smart
yes
Hammerhead NLIMC yes no sans 9 Bold Normal sans 9 Normal Normal 4 1 1 2 3 4 500 st st xfe xnedit dmenu_run dmenu_run dmenu_run root-menu root-menu client-list-combined-menu hh-screenshot client-menu 0050%100% -0050%100% leftno rightno 1 2 leftno rightno 1 300 client-menu top bottom left right client-menu client-menu previous next client-list-combined-menu root-menu menu.xml 200 no 100 yes
# Hammerhead Openbox theme - Zygaena marine-dark identity # Installed to $PREFIX/share/themes/Hammerhead/openbox-3/themerc window.active.title.bg: flat solid window.active.title.bg.color: #12303a window.inactive.title.bg: flat solid window.inactive.title.bg.color: #0d1117 window.active.label.bg: parentrelative window.inactive.label.bg: parentrelative window.active.label.text.color: #cfe0e0 window.inactive.label.text.color: #5a7575 window.active.title.separator.color: #1fb6b6 window.inactive.title.separator.color: #0d1117 window.active.border.color: #1fb6b6 window.inactive.border.color: #0d1117 window.active.handle.bg: flat solid window.active.handle.bg.color: #12303a window.inactive.handle.bg: flat solid window.inactive.handle.bg.color: #0d1117 window.active.grip.bg: flat solid window.active.grip.bg.color: #1fb6b6 window.inactive.grip.bg: flat solid window.inactive.grip.bg.color: #0d1117 window.active.button.unpressed.bg: flat solid window.active.button.unpressed.bg.color: #12303a window.active.button.pressed.bg: flat solid window.active.button.pressed.bg.color: #1fb6b6 window.active.button.disabled.bg: flat solid window.active.button.disabled.bg.color: #0d1117 window.active.button.hover.bg: flat solid window.active.button.hover.bg.color: #3fd0d0 window.inactive.button.unpressed.bg: flat solid window.inactive.button.unpressed.bg.color: #0d1117 window.inactive.button.pressed.bg: flat solid window.inactive.button.pressed.bg.color: #1fb6b6 window.inactive.button.disabled.bg: flat solid window.inactive.button.disabled.bg.color: #0d1117 window.inactive.button.hover.bg: flat solid window.inactive.button.hover.bg.color: #3fd0d0 window.active.button.unpressed.image.color: #cfe0e0 window.active.button.pressed.image.color: #05080d window.active.button.disabled.image.color: #5a7575 window.active.button.hover.image.color: #05080d window.inactive.button.unpressed.image.color: #5a7575 window.inactive.button.pressed.image.color: #05080d window.inactive.button.disabled.image.color: #5a7575 window.inactive.button.hover.image.color: #05080d border.width: 2 padding.width: 2 padding.height: 2 window.client.padding.width: 0 window.handle.width: 6 window.label.text.justify: left menu.items.bg: flat solid menu.items.bg.color: #0d1117 menu.items.text.color: #cfe0e0 menu.items.disabled.text.color: #5a7575 menu.items.active.bg: flat solid menu.items.active.bg.color: #12303a menu.items.active.text.color: #3fd0d0 menu.border.color: #1fb6b6 menu.border.width: 1 menu.separator.color: #1fb6b6 menu.separator.padding.width: 6 menu.separator.padding.height: 3 menu.title.bg: flat solid menu.title.bg.color: #12303a menu.title.text.color: #cfe0e0 menu.title.text.justify: left osd.bg: flat solid osd.bg.color: #0d1117 osd.border.color: #1fb6b6 osd.border.width: 1 osd.label.bg: parentrelative osd.label.text.color: #cfe0e0 window.active.shadow: false window.inactive.shadow: false font: shadow=n font: place=ActiveWindow font: family=sans font: size=9 font: weight=bold font: slant=normal font: place=InactiveWindow font: family=sans font: size=9 font: weight=normal font: slant=normal font: place=MenuHeader font: family=sans font: size=9 font: weight=bold font: place=MenuItem font: family=sans font: size=9 font: weight=normal font: place=OnScreenDisplay font: family=sans font: size=9 font: weight=bold #--------------------------------------------- # Hammerhead tint2 panel - Zygaena marine-dark identity # Installed to $PREFIX/etc/xdg/tint2/tint2rc # # Layout adapted from CrunchBang++'s tint2rc (github.com/CBPP/cbpp-configs, # simon-weber/crunchbang-conf): bottom panel, left launcher block, centered # taskbar, right-hand systray + two-line clock, teal active-task highlight. # No battery/brightness applets (headless/Xvfb-safe). Restyled to our # marine-dark palette, not CBPP's grey. #--------------------------------------------- #------------------------------------- # Backgrounds # bg_color_0: panel background rounded = 0 border_width = 0 background_color = #0d1117 88 border_color = #1fb6b6 0 rounded = 3 border_width = 1 background_color = #12303a 100 border_color = #1fb6b6 70 rounded = 3 border_width = 0 background_color = #1fb6b6 25 border_color = #1fb6b6 0 rounded = 0 border_width = 0 background_color = #0d1117 0 border_color = #1fb6b6 0 #------------------------------------- # Panel panel_items = LTSC panel_size = 100% 30 panel_margin = 0 0 panel_padding = 6 0 8 panel_background_id = 1 panel_position = bottom center horizontal panel_layer = top panel_monitor = all autohide = 0 strut_policy = follow_size panel_dock = 0 wm_menu = 1 panel_window_name = tint2 disable_transparency = 0 mouse_effects = 1 #------------------------------------- # Launcher launcher_padding = 6 3 8 launcher_background_id = 4 launcher_icon_size = 22 launcher_icon_theme_override = 0 launcher_item_app = /usr/local/share/applications/hh-terminal.desktop launcher_item_app = /usr/local/share/applications/hh-files.desktop launcher_item_app = /usr/local/share/applications/hh-editor.desktop #------------------------------------- # Taskbar taskbar_mode = multi_desktop taskbar_hide_if_empty = 0 taskbar_padding = 4 2 4 taskbar_background_id = 0 taskbar_active_background_id = 0 taskbar_name = 1 taskbar_name_padding = 8 3 taskbar_name_background_id = 0 taskbar_name_active_background_id = 3 taskbar_name_font = sans bold 9 taskbar_name_font_color = #5a7575 100 taskbar_name_active_font_color = #1fb6b6 100 taskbar_distribute_size = 1 #------------------------------------- # Task task_text = 1 task_icon = 1 task_centered = 1 task_maximum_size = 180 28 task_padding = 6 2 task_background_id = 0 task_active_background_id = 2 task_urgent_background_id = 2 task_font = sans 9 task_font_color = #cfe0e0 100 task_active_font_color = #3fd0d0 100 task_urgent_font_color = #3fd0d0 100 task_tooltip = 1 #------------------------------------- # Clock (two-line, CBPP-style: time over date) time1_format = %H:%M time2_format = %a %d %b time1_font = sans bold 9 time2_font = sans 7 clock_font_color = #cfe0e0 100 clock_padding = 8 0 clock_background_id = 0 clock_tooltip = %A, %d %B %Y #------------------------------------- # System tray systray_padding = 4 2 8 systray_background_id = 0 systray_sort = ascending systray_icon_size = 18 systray_icon_asb = 100 0 0 #------------------------------------- # Tooltips tooltip_padding = 4 4 tooltip_show_timeout = 0.5 tooltip_hide_timeout = 0.1 tooltip_background_id = 1 tooltip_font_color = #cfe0e0 100 tooltip_font = sans 8 /* * wallpaper-gen.c - Zygaena marine-dark wallpaper generator. * * Renders a 1920x1080 PNG: deep-ocean vertical gradient, low-alpha * concentric sonar arcs from a lower-left origin, a low-alpha stylized * hammerhead-shark silhouette, and the HAMMERHEAD/ZYGAENA wordmark in * the lower-right corner. * * Build: gcc wallpaper-gen.c $(pkg-config --cflags --libs cairo) -lm -o wg * Usage: ./wg /path/to/output.png */ #include #include #include #define W 1920 #define H 1080 /* Zygaena marine-dark palette */ #define BG_TOP_R 0x05/255.0 #define BG_TOP_G 0x08/255.0 #define BG_TOP_B 0x0d/255.0 #define BG_BOT_R 0x0a/255.0 #define BG_BOT_G 0x27/255.0 #define BG_BOT_B 0x33/255.0 #define TEAL_R 0x1f/255.0 #define TEAL_G 0xb6/255.0 #define TEAL_B 0xb6/255.0 #define TEAL_BR_R 0x3f/255.0 #define TEAL_BR_G 0xd0/255.0 #define TEAL_BR_B 0xd0/255.0 #define MUTED_R 0x5a/255.0 #define MUTED_G 0x75/255.0 #define MUTED_B 0x75/255.0 static void draw_background(cairo_t *cr) { cairo_pattern_t *grad = cairo_pattern_create_linear(0, 0, 0, H); cairo_pattern_add_color_stop_rgb(grad, 0.0, BG_TOP_R, BG_TOP_G, BG_TOP_B); cairo_pattern_add_color_stop_rgb(grad, 1.0, BG_BOT_R, BG_BOT_G, BG_BOT_B); cairo_set_source(cr, grad); cairo_paint(cr); cairo_pattern_destroy(grad); } static void draw_sonar_arcs(cairo_t *cr) { /* Origin lower-left, off canvas a bit so rings sweep across the * bottom-left quadrant. */ double cx = -80, cy = H + 80; int rings = 5; double base_r = 260; double step_r = 220; for (int i = 0; i < rings; i++) { double alpha = 0.12 - (i * (0.06 / (rings - 1))); if (alpha < 0.06) alpha = 0.06; cairo_set_source_rgba(cr, TEAL_R, TEAL_G, TEAL_B, alpha); cairo_set_line_width(cr, 2.0); cairo_arc(cr, cx, cy, base_r + i * step_r, -M_PI / 2.2, 0.15); cairo_stroke(cr); } } /* * Stylized hammerhead-shark silhouette: a wide flattened "hammer" head * bar with an eye-dot at each end, a tapering dorsal body, and a * crescent tail - all in one low-alpha teal fill, large and off-center * (upper-left-of-center so it doesn't collide with the wordmark). */ static void draw_hammerhead_motif(cairo_t *cr) { double ox = 560, oy = 430; /* motif origin (center of the head bar) */ double scale = 1.55; cairo_save(cr); cairo_translate(cr, ox, oy); cairo_scale(cr, scale, scale); cairo_set_source_rgba(cr, TEAL_R, TEAL_G, TEAL_B, 0.10); /* Hammer head: a wide, slightly bowed bar. */ cairo_move_to(cr, -260, 0); cairo_curve_to(cr, -180, -34, 180, -34, 260, 0); cairo_curve_to(cr, 180, 34, -180, 34, -260, 0); cairo_close_path(cr); cairo_fill(cr); /* Tapering body/tail sweeping down-right from the head's center. */ cairo_move_to(cr, -40, 18); cairo_curve_to(cr, 120, 60, 260, 160, 360, 340); cairo_curve_to(cr, 380, 380, 340, 400, 300, 380); cairo_curve_to(cr, 220, 220, 90, 100, -40, 54); cairo_close_path(cr); cairo_fill(cr); /* Tail fluke. */ cairo_move_to(cr, 340, 320); cairo_curve_to(cr, 400, 330, 440, 300, 470, 250); cairo_curve_to(cr, 450, 310, 420, 360, 380, 400); cairo_curve_to(cr, 360, 370, 345, 345, 340, 320); cairo_close_path(cr); cairo_fill(cr); /* Eye-dots at each end of the hammer bar. */ cairo_arc(cr, -235, 0, 10, 0, 2 * M_PI); cairo_fill(cr); cairo_arc(cr, 235, 0, 10, 0, 2 * M_PI); cairo_fill(cr); cairo_restore(cr); } /* Draw text with manual letter-spacing (cairo toy text API has no * built-in tracking control). */ static void draw_tracked_text(cairo_t *cr, const char *s, double x, double y, double tracking) { cairo_text_extents_t ext; double cx = x; char buf[2] = {0, 0}; for (const char *p = s; *p; p++) { buf[0] = *p; cairo_text_extents(cr, buf, &ext); cairo_move_to(cr, cx, y); cairo_show_text(cr, buf); cx += ext.x_advance + tracking; } } static void draw_wordmark(cairo_t *cr) { cairo_text_extents_t ext; cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, 64); cairo_set_source_rgb(cr, TEAL_R, TEAL_G, TEAL_B); /* Measure full tracked width to right-align at x = W - 120. */ const char *word = "HAMMERHEAD"; double tracking = 8.0; double total_w = 0; char buf[2] = {0, 0}; for (const char *p = word; *p; p++) { buf[0] = *p; cairo_text_extents(cr, buf, &ext); total_w += ext.x_advance + tracking; } total_w -= tracking; double x = W - 120 - total_w; double y = H - 150; draw_tracked_text(cr, word, x, y, tracking); /* Subtitle */ cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 22); cairo_set_source_rgb(cr, MUTED_R, MUTED_G, MUTED_B); const char *sub = "ZYGAENA"; double sub_tracking = 6.0; double sub_w = 0; for (const char *p = sub; *p; p++) { buf[0] = *p; cairo_text_extents(cr, buf, &ext); sub_w += ext.x_advance + sub_tracking; } sub_w -= sub_tracking; draw_tracked_text(cr, sub, W - 120 - sub_w, y + 40, sub_tracking); } int main(int argc, char **argv) { const char *outpath = (argc > 1) ? argv[1] : "/tmp/hammerhead.png"; cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, W, H); cairo_t *cr = cairo_create(surface); draw_background(cr); draw_sonar_arcs(cr); draw_hammerhead_motif(cr); draw_wordmark(cr); cairo_status_t st = cairo_surface_write_to_png(surface, outpath); if (st != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "write_to_png failed: %s\n", cairo_status_to_string(st)); cairo_destroy(cr); cairo_surface_destroy(surface); return 1; } printf("wrote %s (%dx%d)\n", outpath, W, H); cairo_destroy(cr); cairo_surface_destroy(surface); return 0; }