diff --git a/README.md b/README.md index d92df6d..b1b84b3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,22 @@ -# OrionOS +# OrionOS — ElemetryOS macOS Fork -A BeOS-inspired Linux desktop built from scratch in C. Custom window manager, panel, app launcher, settings panel, package manager, and graphical installer — all running on Arch Linux, shipped as a bootable ISO. +A macOS-inspired Linux desktop forked from ElemetryOS, built from scratch in C. Custom window manager, panel, app launcher, settings panel, package manager, and graphical installer — all running on Arch Linux, shipped as a bootable ISO. --- ## What it is -OrionOS is a complete desktop environment built on X11/Xlib with a dark navy aesthetic. It ships as a bootable ISO you can try live or install to disk. Every shell component is written in native C with no toolkit dependency — just Xlib and Xft. +OrionOS is a complete desktop environment built on X11/Xlib with a macOS dark-mode aesthetic. It ships as a bootable ISO you can try live or install to disk. Every shell component is written in native C with no toolkit dependency — just Xlib and Xft. + +### macOS design language + +This fork re-skins the window manager with macOS design conventions: + +- **Traffic-light buttons on the left** — close (red), minimize (yellow), maximize (green), just like macOS +- **macOS dark-mode palette** — near-black desktop, `#3C3C3C` active titlebars, `#2C2C2C` inactive +- **Centered window titles** — title text centered in the titlebar, macOS-style +- **Thin 1 px borders** — minimal window chrome, no thick bevels +- **macOS blue selection** (`#4A90D9`) in context menus and snap overlays ### Components diff --git a/wm/include/wm.h b/wm/include/wm.h index 9cf7fee..5a1ea43 100644 --- a/wm/include/wm.h +++ b/wm/include/wm.h @@ -12,28 +12,29 @@ #include #include -/* ── palette (modern dark) ───────────────────────────────────────────── */ -#define COLOR_TITLE_ACTIVE 0x1E4D78 /* deep blue active title bar */ -#define COLOR_TITLE_INACTIVE 0x252830 /* dark grey inactive */ -#define COLOR_TITLE_TEXT_ACT 0xE8EEF8 /* near-white active text */ -#define COLOR_TITLE_TEXT_INACT 0x5C6070 /* dimmed inactive text */ -#define COLOR_BORDER_LIGHT 0x3A6898 /* blue-grey highlight */ -#define COLOR_BORDER_DARK 0x0C1018 /* near-black shadow */ -#define COLOR_CLOSE_BTN 0xCC3333 /* red close */ -#define COLOR_MAXIMIZE_BTN 0x2E8B44 /* green maximize */ -#define COLOR_MINIMIZE_BTN 0xBB8820 /* amber minimize */ -#define COLOR_CLOSE_BTN_HOV 0xFF5050 -#define COLOR_MAXIMIZE_BTN_HOV 0x44CC66 -#define COLOR_MINIMIZE_BTN_HOV 0xFFBB30 -#define COLOR_BG 0x1A2840 /* desktop background */ -#define COLOR_SNAP_OVERLAY 0x3A6898 /* snap highlight (unused, placeholder) */ +/* ── palette (macOS dark mode) ───────────────────────────────────────── */ +#define COLOR_TITLE_ACTIVE 0x3C3C3C /* macOS dark titlebar */ +#define COLOR_TITLE_INACTIVE 0x2C2C2C /* inactive, slightly darker */ +#define COLOR_TITLE_TEXT_ACT 0xFFFFFF /* white active text */ +#define COLOR_TITLE_TEXT_INACT 0x686868 /* dimmed inactive text */ +#define COLOR_BORDER_LIGHT 0x505050 /* subtle border highlight */ +#define COLOR_BORDER_DARK 0x1C1C1C /* near-black shadow */ +#define COLOR_CLOSE_BTN 0xFF5F57 /* macOS traffic-light red */ +#define COLOR_MAXIMIZE_BTN 0x28C840 /* macOS traffic-light green */ +#define COLOR_MINIMIZE_BTN 0xFEBC2E /* macOS traffic-light yellow */ +#define COLOR_CLOSE_BTN_HOV 0xFF3B30 +#define COLOR_MAXIMIZE_BTN_HOV 0x34C759 +#define COLOR_MINIMIZE_BTN_HOV 0xFFCC00 +#define COLOR_BG 0x1C1C1C /* near-black desktop */ +#define COLOR_SNAP_OVERLAY 0x4A90D9 /* macOS blue snap highlight */ /* ── geometry ────────────────────────────────────────────────────────── */ -#define TITLE_HEIGHT 28 /* taller for modern look */ +#define TITLE_HEIGHT 28 /* macOS-style height */ #define TITLE_TAB_W 200 -#define BORDER_W 3 -#define BTN_SIZE 14 -#define BTN_MARGIN 5 +#define BORDER_W 1 /* thin 1px macOS-style border */ +#define BTN_SIZE 12 /* macOS traffic-light diameter */ +#define BTN_MARGIN 8 /* spacing between traffic lights */ +#define BTN_LEFT_PAD 10 /* left edge → first button */ #define RESIZE_GRIP 12 #define MIN_WIN_W 120 #define MIN_WIN_H 60 @@ -41,15 +42,15 @@ #define DBL_CLICK_MS 400 /* double-click threshold */ /* - * Three buttons on right side (left to right): minimize, maximize, close - * close = fw - BTN_SIZE - BTN_MARGIN - BORDER_W - * max = close - BTN_SIZE - BTN_MARGIN - 2 - * min = max - BTN_SIZE - BTN_MARGIN - 2 + * macOS-style: three traffic-light buttons on LEFT side + * close = BTN_LEFT_PAD + * minimize = BTN_LEFT_PAD + BTN_SIZE + BTN_MARGIN + * maximize = BTN_LEFT_PAD + (BTN_SIZE + BTN_MARGIN) * 2 */ -#define BTN_CLOSE_X(fw) ((fw) - BTN_SIZE - BTN_MARGIN - BORDER_W) -#define BTN_MAX_X(fw) ((fw) - BTN_SIZE*2 - BTN_MARGIN*2 - BORDER_W - 2) -#define BTN_MIN_X(fw) ((fw) - BTN_SIZE*3 - BTN_MARGIN*3 - BORDER_W - 4) -#define BTN_Y (((TITLE_HEIGHT) - BTN_SIZE) / 2) +#define BTN_CLOSE_X (BTN_LEFT_PAD) +#define BTN_MIN_X (BTN_LEFT_PAD + BTN_SIZE + BTN_MARGIN) +#define BTN_MAX_X (BTN_LEFT_PAD + (BTN_SIZE + BTN_MARGIN) * 2) +#define BTN_Y (((TITLE_HEIGHT) - BTN_SIZE) / 2) /* ── fonts ───────────────────────────────────────────────────────────── */ #define FONT_TITLE "Sans:size=9:weight=bold" diff --git a/wm/src/draw.c b/wm/src/draw.c index 2ac307c..9feb32b 100644 --- a/wm/src/draw.c +++ b/wm/src/draw.c @@ -1,33 +1,30 @@ #include "wm.h" /* - * Frame layout (3 buttons on right): + * Frame layout — macOS style, traffic-light buttons on LEFT: * - * ┌─[Title______________]──────[_][□][X]─┐ <- TITLE_HEIGHT - * │ content │ - * │ [grip]────┘ + * ┌─[●][●][●]──── Title (centered) ────────┐ <- TITLE_HEIGHT + * │ content │ + * │ [grip]──────┘ */ /* ── hit tests ───────────────────────────────────────────────────────── */ int frame_hit_close(Client *c, int x, int y) { - int fw = (int)c->w + BORDER_W * 2; - int bx = BTN_CLOSE_X(fw); - return (x >= bx && x <= bx + BTN_SIZE && + (void)c; + return (x >= BTN_CLOSE_X && x <= BTN_CLOSE_X + BTN_SIZE && y >= BTN_Y && y <= BTN_Y + BTN_SIZE); } int frame_hit_maximize(Client *c, int x, int y) { - int fw = (int)c->w + BORDER_W * 2; - int bx = BTN_MAX_X(fw); - return (x >= bx && x <= bx + BTN_SIZE && + (void)c; + return (x >= BTN_MAX_X && x <= BTN_MAX_X + BTN_SIZE && y >= BTN_Y && y <= BTN_Y + BTN_SIZE); } int frame_hit_minimize(Client *c, int x, int y) { - int fw = (int)c->w + BORDER_W * 2; - int bx = BTN_MIN_X(fw); - return (x >= bx && x <= bx + BTN_SIZE && + (void)c; + return (x >= BTN_MIN_X && x <= BTN_MIN_X + BTN_SIZE && y >= BTN_Y && y <= BTN_Y + BTN_SIZE); } @@ -70,13 +67,14 @@ static void draw_circle_btn(WM *wm, Drawable d, int bx, int by, } void frame_draw_buttons(WM *wm, Client *c) { - int fw = (int)c->w + BORDER_W * 2; - draw_circle_btn(wm, c->frame, BTN_CLOSE_X(fw), BTN_Y, + /* macOS order left-to-right: close, minimize, maximize */ + draw_circle_btn(wm, c->frame, BTN_CLOSE_X, BTN_Y, color_alloc(wm, COLOR_CLOSE_BTN), 'X'); - draw_circle_btn(wm, c->frame, BTN_MAX_X(fw), BTN_Y, - color_alloc(wm, COLOR_MAXIMIZE_BTN), 'O'); - draw_circle_btn(wm, c->frame, BTN_MIN_X(fw), BTN_Y, + draw_circle_btn(wm, c->frame, BTN_MIN_X, BTN_Y, color_alloc(wm, COLOR_MINIMIZE_BTN), '_'); + draw_circle_btn(wm, c->frame, BTN_MAX_X, BTN_Y, + color_alloc(wm, COLOR_MAXIMIZE_BTN), 'O'); + (void)c; } /* ── resize grip ─────────────────────────────────────────────────────── */ @@ -101,7 +99,6 @@ void frame_draw(WM *wm, Client *c) { int fw = (int)c->w + BORDER_W * 2; int fh = (int)c->h + TITLE_HEIGHT + BORDER_W; - unsigned long col_light = color_alloc(wm, COLOR_BORDER_LIGHT); unsigned long col_dark = color_alloc(wm, COLOR_BORDER_DARK); /* title bar background */ @@ -110,45 +107,42 @@ void frame_draw(WM *wm, Client *c) { XSetForeground(wm->dpy, wm->gc, col_title); XFillRectangle(wm->dpy, c->frame, wm->gc, 0, 0, fw, TITLE_HEIGHT); - /* subtle gradient effect: lighter top strip (2px) */ - if (c->focused) { - unsigned long lighter = color_alloc(wm, 0x2A6098); - XSetForeground(wm->dpy, wm->gc, lighter); - XFillRectangle(wm->dpy, c->frame, wm->gc, 0, 0, fw, 2); - } - - /* client area background strip (below title) */ + /* thin borders (1px, macOS style) */ XSetForeground(wm->dpy, wm->gc, col_dark); XFillRectangle(wm->dpy, c->frame, wm->gc, 0, TITLE_HEIGHT, BORDER_W, fh - TITLE_HEIGHT); XFillRectangle(wm->dpy, c->frame, wm->gc, fw - BORDER_W, TITLE_HEIGHT, BORDER_W, fh - TITLE_HEIGHT); XFillRectangle(wm->dpy, c->frame, wm->gc, 0, fh - BORDER_W, fw, BORDER_W); - /* outer bevel */ - XSetForeground(wm->dpy, wm->gc, col_light); - XDrawLine(wm->dpy, c->frame, wm->gc, 0, 0, fw - 1, 0); - XDrawLine(wm->dpy, c->frame, wm->gc, 0, 0, 0, fh - 1); - XSetForeground(wm->dpy, wm->gc, col_dark); - XDrawLine(wm->dpy, c->frame, wm->gc, fw-1, 0, fw-1, fh-1); - XDrawLine(wm->dpy, c->frame, wm->gc, 0, fh-1, fw-1, fh-1); - - /* thin separator line under title */ - XSetForeground(wm->dpy, wm->gc, col_dark); + /* subtle 1px separator under titlebar */ + unsigned long col_sep = color_alloc(wm, 0x1A1A1A); + XSetForeground(wm->dpy, wm->gc, col_sep); XDrawLine(wm->dpy, c->frame, wm->gc, 0, TITLE_HEIGHT - 1, fw - 1, TITLE_HEIGHT - 1); - /* title text */ - int btn_area = BTN_SIZE * 3 + BTN_MARGIN * 3 + BORDER_W + 8; - int text_max_w = fw - BORDER_W * 2 - btn_area - 8; - if (text_max_w < 10) text_max_w = 10; - + /* centered title text (macOS style) */ XftDraw *xd = XftDrawCreate(wm->dpy, c->frame, wm->visual, wm->cmap); if (xd) { XftColor col_text; xft_color(wm, c->focused ? COLOR_TITLE_TEXT_ACT : COLOR_TITLE_TEXT_INACT, &col_text); - XRectangle clip = { BORDER_W + 4, 1, (unsigned short)text_max_w, TITLE_HEIGHT - 2 }; + + XGlyphInfo ext; + XftTextExtentsUtf8(wm->dpy, wm->font_title, + (const FcChar8 *)c->title, strlen(c->title), &ext); + + /* center in the full title bar */ + int tx = (fw - ext.width) / 2; + /* clamp so text doesn't overlap the left buttons */ + int left_btn_end = BTN_MAX_X + BTN_SIZE + 6; + if (tx < left_btn_end) tx = left_btn_end; + + int text_max_w = fw - tx - 8; + if (text_max_w < 10) text_max_w = 10; + + XRectangle clip = { (short)tx, 1, (unsigned short)text_max_w, TITLE_HEIGHT - 2 }; XftDrawSetClipRectangles(xd, 0, 0, &clip, 1); + int ty = (TITLE_HEIGHT + wm->font_title->ascent - wm->font_title->descent) / 2; XftDrawStringUtf8(xd, &col_text, wm->font_title, - BORDER_W + 6, ty, + tx, ty, (const FcChar8 *)c->title, strlen(c->title)); XftColorFree(wm->dpy, wm->visual, wm->cmap, &col_text); XftDrawDestroy(xd); diff --git a/wm/src/menu.c b/wm/src/menu.c index 91db61e..f73555b 100644 --- a/wm/src/menu.c +++ b/wm/src/menu.c @@ -1,7 +1,7 @@ #include "wm.h" -#define MENU_ITEM_H 24 -#define MENU_W 220 +#define MENU_ITEM_H 26 +#define MENU_W 230 #define MENU_PADDING 5 static const MenuItem MENU_ITEMS[] = { @@ -51,7 +51,7 @@ void menu_show(WM *wm, int x, int y) { XSetWindowAttributes swa; swa.override_redirect = True; - swa.background_pixel = color_alloc(wm, 0x1C2030); /* dark menu bg */ + swa.background_pixel = color_alloc(wm, 0x2C2C2C); /* macOS dark menu bg */ swa.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask; @@ -65,8 +65,8 @@ void menu_show(WM *wm, int x, int y) { &swa ); - /* 1px accent border */ - XSetWindowBorder(wm->dpy, wm->menu_win, color_alloc(wm, COLOR_BORDER_LIGHT)); + /* subtle 1px border (macOS-like) */ + XSetWindowBorder(wm->dpy, wm->menu_win, color_alloc(wm, 0x505050)); XMapRaised(wm->dpy, wm->menu_win); wm->menu_visible = 1; @@ -110,29 +110,29 @@ void menu_draw(WM *wm) { if (!xd) return; XftColor col_normal, col_hover_bg, col_hover_text, col_sep; - xft_color(wm, 0xC8D4E8, &col_normal); /* light text on dark bg */ - xft_color(wm, 0x2060A0, &col_hover_bg); /* blue highlight */ - xft_color(wm, 0xF0F4FF, &col_hover_text); - xft_color(wm, 0x303848, &col_sep); + xft_color(wm, 0xE8E8E8, &col_normal); /* macOS light menu text */ + xft_color(wm, 0x4A90D9, &col_hover_bg); /* macOS blue selection */ + xft_color(wm, 0xFFFFFF, &col_hover_text); + xft_color(wm, 0x444444, &col_sep); /* clear background */ - XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x1C2030)); + XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x2C2C2C)); XFillRectangle(wm->dpy, wm->menu_win, wm->gc, 0, 0, MENU_W, menu_height()); for (int i = 0; i < MENU_COUNT; i++) { int iy = item_y(i); if (is_separator(i)) { - XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x2A3040)); + XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x3C3C3C)); XDrawLine(wm->dpy, wm->menu_win, wm->gc, 8, iy + 4, MENU_W - 8, iy + 4); continue; } - /* hover highlight */ + /* hover highlight — macOS blue selection pill */ if (i == wm->menu_hovered && wm->menu_hovered >= 0) { - XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x4A6888)); + XSetForeground(wm->dpy, wm->gc, color_alloc(wm, 0x4A90D9)); XFillRectangle(wm->dpy, wm->menu_win, wm->gc, - 2, iy, MENU_W - 4, MENU_ITEM_H); + 4, iy + 1, MENU_W - 8, MENU_ITEM_H - 2); } XftColor *tc = (i == wm->menu_hovered) ? &col_hover_text : &col_normal; @@ -142,7 +142,7 @@ void menu_draw(WM *wm) { strlen(MENU_ITEMS[i].label), &ext); int ty = iy + (MENU_ITEM_H - ext.height) / 2 + ext.height - ext.y; XftDrawStringUtf8(xd, tc, wm->font_menu, - MENU_PADDING + 4, ty, + MENU_PADDING + 10, ty, (const FcChar8 *)MENU_ITEMS[i].label, strlen(MENU_ITEMS[i].label)); }