#ifndef WM_H #define WM_H #include #include #include #include #include #include #include #include #include #include #include #include #include /* ── 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 DESKBAR_W 200 /* must match DB_W in deskbar/include/deskbar.h */ #define TITLE_HEIGHT 28 /* macOS-style height */ #define TITLE_TAB_W 200 #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 #define SNAP_DIST 24 /* px from edge to trigger snap */ #define DBL_CLICK_MS 400 /* double-click threshold */ /* * 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 (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" #define FONT_MENU "Sans:size=10" /* ── drag mode ───────────────────────────────────────────────────────── */ typedef enum { DRAG_NONE, DRAG_MOVE, DRAG_RESIZE } DragMode; /* WM_STATE values (ICCCM) */ #define WM_STATE_NORMAL 1 #define WM_STATE_ICONIC 3 #define WM_STATE_WITHDRAWN 0 typedef struct Client { Window win; Window frame; int x, y; unsigned int w, h; int focused; int minimized; int maximized; int desktop; /* virtual desktop this window lives on */ int saved_x, saved_y; /* pre-maximize position */ unsigned saved_w, saved_h; /* pre-maximize size */ Time last_click_time; /* for double-click detection */ char title[256]; /* ICCCM WM_NORMAL_HINTS */ int min_w, min_h; /* PMinSize */ int inc_w, inc_h; /* PResizeInc — 0 means no constraint */ int base_w, base_h; /* PBaseSize — baseline for increment calc */ /* Exposé saved geometry */ int exp_x, exp_y; unsigned exp_w, exp_h; struct Client *next; } Client; typedef struct MenuItem { const char *label; const char *cmd; } MenuItem; typedef struct WM { Display *dpy; int screen; Window root; GC gc; Colormap cmap; Visual *visual; int depth; XftFont *font_title; XftFont *font_menu; Cursor cur_normal; Cursor cur_move; Cursor cur_resize; Client *clients; Client *focused; int cur_desktop; /* active virtual desktop (0-based) */ int hot_corner_last; /* last hot-corner zone (0=none,1-4) */ Atom wm_delete_window; Atom wm_protocols; Atom wm_state; Atom net_wm_name; Atom net_wm_state; Atom net_wm_state_hidden; Atom net_wm_state_maximized_vert; Atom net_wm_state_maximized_horz; Atom net_wm_desktop; Atom net_current_desktop; DragMode drag_mode; int drag_start_x, drag_start_y; int drag_win_x, drag_win_y; unsigned drag_win_w, drag_win_h; Window drag_frame; Window menu_win; int menu_visible; int menu_x, menu_y; int menu_hovered; /* Alt+Tab visual switcher */ Window swl_win; int swl_visible; int swl_idx; int swl_count; Window swl_wins[64]; char swl_titles[64][128]; int swl_mini[64]; /* 1 if corresponding entry is minimized */ /* Exposé window overview */ int expose_active; int expose_count; Window expose_wins[64]; /* frames shown in overview */ } WM; /* core */ void wm_init(WM *wm); void wm_run(WM *wm); void wm_cleanup(WM *wm); /* client */ Client *client_add(WM *wm, Window win); void client_remove(WM *wm, Window win); Client *client_find_by_frame(WM *wm, Window frame); Client *client_find_by_win(WM *wm, Window win); void client_focus(WM *wm, Client *c); void client_raise(WM *wm, Client *c); void client_minimize(WM *wm, Client *c); void client_restore(WM *wm, Client *c); void client_maximize(WM *wm, Client *c); void client_unmaximize(WM *wm, Client *c); void client_toggle_maximize(WM *wm, Client *c); void client_snap_left(WM *wm, Client *c); void client_snap_right(WM *wm, Client *c); void client_set_wm_state(WM *wm, Client *c, long state); void client_move_to_desktop(WM *wm, Client *c, int new_desk); /* drawing */ void frame_draw(WM *wm, Client *c); void frame_draw_buttons(WM *wm, Client *c); unsigned long color_alloc(WM *wm, unsigned long rgb); void xft_color(WM *wm, unsigned long rgb, XftColor *out); /* hit testing */ int frame_hit_resize(Client *c, int x, int y); int frame_hit_close(Client *c, int x, int y); int frame_hit_minimize(Client *c, int x, int y); int frame_hit_maximize(Client *c, int x, int y); /* menu */ void menu_show(WM *wm, int x, int y); void menu_hide(WM *wm); void menu_draw(WM *wm); void menu_click(WM *wm, int px, int py); int menu_item_at(int py); /* switcher */ void switcher_show(WM *wm); void switcher_next(WM *wm); void switcher_prev(WM *wm); void switcher_hide(WM *wm, int commit); void switcher_draw(WM *wm); /* exposé */ void expose_show(WM *wm); void expose_hide(WM *wm, Window selected_frame); /* events */ void on_map_request(WM *wm, XMapRequestEvent *e); void on_unmap_notify(WM *wm, XUnmapEvent *e); void on_destroy_notify(WM *wm, XDestroyWindowEvent *e); void on_expose(WM *wm, XExposeEvent *e); void on_button_press(WM *wm, XButtonEvent *e); void on_button_release(WM *wm, XButtonEvent *e); void on_motion_notify(WM *wm, XMotionEvent *e); void on_configure_request(WM *wm, XConfigureRequestEvent *e); void on_key_press(WM *wm, XKeyEvent *e); void on_enter_notify(WM *wm, XCrossingEvent *e); void on_client_message(WM *wm, XClientMessageEvent *e); void on_property_notify(WM *wm, XPropertyEvent *e); void on_key_release(WM *wm, XKeyEvent *e); #endif