Initial commit: SkyOS source code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-07-23 12:14:34 -04:00
commit e641720a3c
30 files changed
+5836

No files matched your search

+315
View File
@@ -0,0 +1,315 @@
#include "wm.h"
/* ── WM_STATE ICCCM helper ───────────────────────────────────────────── */
void client_set_wm_state(WM *wm, Client *c, long state) {
long data[2] = { state, None };
XChangeProperty(wm->dpy, c->win, wm->wm_state, wm->wm_state,
32, PropModeReplace, (unsigned char *)data, 2);
if (state == WM_STATE_ICONIC) {
XChangeProperty(wm->dpy, c->win, wm->net_wm_state, XA_ATOM,
32, PropModeReplace,
(unsigned char *)&wm->net_wm_state_hidden, 1);
} else {
XDeleteProperty(wm->dpy, c->win, wm->net_wm_state);
}
}
static void update_net_client_list(WM *wm) {
Atom net_client_list = XInternAtom(wm->dpy, "_NET_CLIENT_LIST", False);
int count = 0;
for (Client *c = wm->clients; c; c = c->next) count++;
Window *wins = calloc(count, sizeof(Window));
int i = 0;
for (Client *c = wm->clients; c; c = c->next) wins[i++] = c->win;
XChangeProperty(wm->dpy, wm->root, net_client_list, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)wins, count);
free(wins);
}
/* ── add / remove ────────────────────────────────────────────────────── */
/* smart placement: cascade from top-left, offset each window */
static void smart_place(WM *wm, Client *c) {
static int cascade_x = 40, cascade_y = 40;
int sw = DisplayWidth(wm->dpy, wm->screen);
int sh = DisplayHeight(wm->dpy, wm->screen);
/* reset cascade if it would go off-screen */
if (cascade_x + (int)c->w > sw - 40 || cascade_y + (int)c->h > sh - 40) {
cascade_x = 40;
cascade_y = 40;
}
c->x = cascade_x;
c->y = cascade_y;
cascade_x += 30;
cascade_y += 30;
}
Client *client_add(WM *wm, Window win) {
XWindowAttributes wa;
if (!XGetWindowAttributes(wm->dpy, win, &wa)) return NULL;
if (wa.override_redirect) return NULL;
if (client_find_by_win(wm, win)) return NULL;
Client *c = calloc(1, sizeof(Client));
c->win = win;
c->w = wa.width;
c->h = wa.height;
/* use application-requested position if non-zero, otherwise smart place */
if (wa.x == 0 && wa.y == 0) {
smart_place(wm, c);
} else {
c->x = wa.x;
c->y = wa.y;
}
/* never land behind deskbar (top-right panel ~180px wide) */
int sw = DisplayWidth(wm->dpy, wm->screen);
if (c->x + (int)c->w > sw - 185 && c->y < 200)
c->y = 40;
/* fetch title */
char *name = NULL;
Atom utf8 = XInternAtom(wm->dpy, "UTF8_STRING", False);
Atom net_wm = XInternAtom(wm->dpy, "_NET_WM_NAME", False);
{
Atom type; int fmt; unsigned long n, after;
unsigned char *data = NULL;
if (XGetWindowProperty(wm->dpy, win, net_wm, 0, 256, False,
utf8, &type, &fmt, &n, &after, &data)
== Success && data && n > 0) {
snprintf(c->title, 255, "%.*s", (int)n, data);
XFree(data);
} else {
if (data) XFree(data);
if (XFetchName(wm->dpy, win, &name) && name) {
strncpy(c->title, name, 255);
XFree(name);
} else {
strncpy(c->title, "Untitled", 255);
}
}
}
int fw = (int)c->w + BORDER_W * 2;
int fh = (int)c->h + TITLE_HEIGHT + BORDER_W;
XSetWindowAttributes swa;
swa.background_pixel = color_alloc(wm, COLOR_TITLE_INACTIVE);
swa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
| ButtonPressMask | ButtonReleaseMask
| PointerMotionMask | ExposureMask
| EnterWindowMask;
swa.override_redirect = False;
swa.cursor = wm->cur_normal;
c->frame = XCreateWindow(
wm->dpy, wm->root,
c->x, c->y, fw, fh, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWBackPixel | CWEventMask | CWOverrideRedirect | CWCursor,
&swa
);
XReparentWindow(wm->dpy, win, c->frame, BORDER_W, TITLE_HEIGHT);
XSelectInput(wm->dpy, win, PropertyChangeMask | FocusChangeMask);
c->next = wm->clients;
wm->clients = c;
XMapWindow(wm->dpy, c->frame);
XMapWindow(wm->dpy, win);
client_set_wm_state(wm, c, WM_STATE_NORMAL);
update_net_client_list(wm);
client_focus(wm, c);
return c;
}
void client_remove(WM *wm, Window win) {
Client *prev = NULL, *c = wm->clients;
while (c) {
if (c->win == win || c->frame == win) {
if (prev) prev->next = c->next;
else wm->clients = c->next;
if (wm->focused == c) {
wm->focused = wm->clients;
if (wm->focused) client_focus(wm, wm->focused);
else wm->focused = NULL;
}
XDestroyWindow(wm->dpy, c->frame);
free(c);
update_net_client_list(wm);
return;
}
prev = c; c = c->next;
}
}
/* ── lookup ──────────────────────────────────────────────────────────── */
Client *client_find_by_frame(WM *wm, Window frame) {
for (Client *c = wm->clients; c; c = c->next)
if (c->frame == frame) return c;
return NULL;
}
Client *client_find_by_win(WM *wm, Window win) {
for (Client *c = wm->clients; c; c = c->next)
if (c->win == win) return c;
return NULL;
}
/* ── focus / raise ───────────────────────────────────────────────────── */
void client_focus(WM *wm, Client *c) {
if (!c || c->minimized) return;
if (wm->focused && wm->focused != c) {
wm->focused->focused = 0;
frame_draw(wm, wm->focused);
}
wm->focused = c;
c->focused = 1;
XSetInputFocus(wm->dpy, c->win, RevertToPointerRoot, CurrentTime);
XRaiseWindow(wm->dpy, c->frame);
frame_draw(wm, c);
/* advertise active window */
Atom net_active = XInternAtom(wm->dpy, "_NET_ACTIVE_WINDOW", False);
XChangeProperty(wm->dpy, wm->root, net_active, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&c->win, 1);
}
void client_raise(WM *wm, Client *c) {
XRaiseWindow(wm->dpy, c->frame);
}
/* ── minimize / restore ──────────────────────────────────────────────── */
void client_minimize(WM *wm, Client *c) {
if (c->minimized) return;
if (c->maximized) client_unmaximize(wm, c);
c->minimized = 1;
c->focused = 0;
XUnmapWindow(wm->dpy, c->frame);
client_set_wm_state(wm, c, WM_STATE_ICONIC);
if (wm->focused == c) {
wm->focused = NULL;
for (Client *n = wm->clients; n; n = n->next) {
if (!n->minimized) { client_focus(wm, n); break; }
}
}
}
void client_restore(WM *wm, Client *c) {
if (!c->minimized) { client_focus(wm, c); return; }
c->minimized = 0;
XMapWindow(wm->dpy, c->frame);
client_set_wm_state(wm, c, WM_STATE_NORMAL);
client_focus(wm, c);
}
/* ── maximize / unmaximize ───────────────────────────────────────────── */
void client_maximize(WM *wm, Client *c) {
if (c->maximized || c->minimized) return;
/* save current geometry */
c->saved_x = c->x;
c->saved_y = c->y;
c->saved_w = c->w;
c->saved_h = c->h;
c->maximized = 1;
int sw = DisplayWidth(wm->dpy, wm->screen);
int sh = DisplayHeight(wm->dpy, wm->screen);
/* leave room for deskbar on the right */
int deskbar_w = 185;
int new_w = sw - deskbar_w - BORDER_W * 2;
int new_h = sh - TITLE_HEIGHT - BORDER_W;
c->x = 0; c->y = 0;
c->w = (unsigned)new_w;
c->h = (unsigned)new_h;
int fw = (int)c->w + BORDER_W * 2;
int fh = (int)c->h + TITLE_HEIGHT + BORDER_W;
XMoveResizeWindow(wm->dpy, c->frame, c->x, c->y, fw, fh);
XResizeWindow(wm->dpy, c->win, c->w, c->h);
/* advertise maximized state via EWMH */
Atom states[2] = { wm->net_wm_state_maximized_vert,
wm->net_wm_state_maximized_horz };
XChangeProperty(wm->dpy, c->win, wm->net_wm_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *)states, 2);
client_focus(wm, c);
frame_draw(wm, c);
}
void client_unmaximize(WM *wm, Client *c) {
if (!c->maximized) return;
c->maximized = 0;
c->x = c->saved_x;
c->y = c->saved_y;
c->w = c->saved_w;
c->h = c->saved_h;
int fw = (int)c->w + BORDER_W * 2;
int fh = (int)c->h + TITLE_HEIGHT + BORDER_W;
XMoveResizeWindow(wm->dpy, c->frame, c->x, c->y, fw, fh);
XResizeWindow(wm->dpy, c->win, c->w, c->h);
XDeleteProperty(wm->dpy, c->win, wm->net_wm_state);
client_focus(wm, c);
frame_draw(wm, c);
}
void client_toggle_maximize(WM *wm, Client *c) {
if (c->maximized) client_unmaximize(wm, c);
else client_maximize(wm, c);
}
/* ── edge snap ───────────────────────────────────────────────────────── */
void client_snap_left(WM *wm, Client *c) {
if (c->maximized) client_unmaximize(wm, c);
int sw = DisplayWidth(wm->dpy, wm->screen);
int sh = DisplayHeight(wm->dpy, wm->screen);
int deskbar_w = 185;
int half_w = (sw - deskbar_w) / 2;
c->x = 0;
c->y = 0;
c->w = (unsigned)(half_w - BORDER_W * 2);
c->h = (unsigned)(sh - TITLE_HEIGHT - BORDER_W);
int fw = (int)c->w + BORDER_W * 2;
int fh = (int)c->h + TITLE_HEIGHT + BORDER_W;
XMoveResizeWindow(wm->dpy, c->frame, c->x, c->y, fw, fh);
XResizeWindow(wm->dpy, c->win, c->w, c->h);
frame_draw(wm, c);
}
void client_snap_right(WM *wm, Client *c) {
if (c->maximized) client_unmaximize(wm, c);
int sw = DisplayWidth(wm->dpy, wm->screen);
int sh = DisplayHeight(wm->dpy, wm->screen);
int deskbar_w = 185;
int half_w = (sw - deskbar_w) / 2;
c->x = half_w;
c->y = 0;
c->w = (unsigned)(sw - deskbar_w - half_w - BORDER_W * 2);
c->h = (unsigned)(sh - TITLE_HEIGHT - BORDER_W);
int fw = (int)c->w + BORDER_W * 2;
int fh = (int)c->h + TITLE_HEIGHT + BORDER_W;
XMoveResizeWindow(wm->dpy, c->frame, c->x, c->y, fw, fh);
XResizeWindow(wm->dpy, c->win, c->w, c->h);
frame_draw(wm, c);
}