Fork ElemetryOS with macOS-style window decorations

- Move traffic-light buttons to the LEFT side of titlebars (close/minimize/maximize)
  in macOS order, using fixed left-pad positions instead of right-edge offsets
- Adopt macOS dark-mode color palette: #3C3C3C active titlebar, #2C2C2C inactive,
  traffic-light colors #FF5F57/#FEBC2E/#28C840, near-black #1C1C1C desktop
- Center window title text in the titlebar (macOS style), clamped to avoid
  overlapping the left button cluster
- Thin 1px window borders replacing the original 3px beveled border
- macOS blue (#4A90D9) selection highlight in the context menu
- Neutral dark context menu (#2C2C2C) with subtle separators and text indent
- Update README to document the ElemetryOS macOS fork identity and design changes
This commit is contained in:
Claude committed 2026-08-30 19:40:11 +00:00
1 parent 4cda708cc2
commit 0d874617dd
4 files changed
+94 -89

No files matched your search

+38 -44
View File
@@ -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);
+15 -15
View File
@@ -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));
}