macOS-style polish: fix seam, bidirectional Alt+Tab, minimized windows in switcher, rounded corners, deskbar context menu
Fix #1: Replace hardcoded 185px deskbar-offset in client.c and events.c with DESKBAR_W constant (200) to eliminate the 15px gap between the WM frame and deskbar edge. Fix #2: Add Shift+Alt+Tab reverse-direction support — grab Mod1+Shift+XK_Tab in wm.c, detect ShiftMask in events.c, and implement switcher_prev() in switcher.c. Fix #3: Include minimized windows in the Alt+Tab switcher. swl_populate() no longer skips minimized clients; swl_mini[] tracks state so switcher_draw() can dim them with bracketed titles and darker card backgrounds. Fix #4: Rewrite themes/picom.conf with macOS-inspired settings — 10px corner radius on normal windows, 8px on menus, soft downward shadow (radius 18, offset-y 8, opacity 0.35), smooth fading (step 0.08), no dock/tray rounding. Fix #5: Add per-app right-click context menu to the deskbar. Right-clicking an app row opens a popup with Raise / Minimize / Close actions (Close shown in red). Actions are sent as EWMH client messages (_NET_ACTIVE_WINDOW, WM_CHANGE_STATE+IconicState, _NET_CLOSE_WINDOW) with matching handlers added to the WM's on_client_message. Pointer grab closes the menu on any outside click.
This commit is contained in:
8 files changed
+311
-42
No files matched your search
+38
-5
@@ -33,7 +33,7 @@ static void check_snap(WM *wm, Client *c) {
|
||||
} else {
|
||||
client_snap_left(wm, c);
|
||||
}
|
||||
} else if (c->x + (int)(c->w + BORDER_W * 2) >= sw - 185 - SNAP_DIST) {
|
||||
} else if (c->x + (int)(c->w + BORDER_W * 2) >= sw - DESKBAR_W - SNAP_DIST) {
|
||||
client_snap_right(wm, c);
|
||||
} else if (c->y <= SNAP_DIST) {
|
||||
client_maximize(wm, c);
|
||||
@@ -95,10 +95,34 @@ void on_enter_notify(WM *wm, XCrossingEvent *e) {
|
||||
}
|
||||
|
||||
void on_client_message(WM *wm, XClientMessageEvent *e) {
|
||||
Atom net_active = XInternAtom(wm->dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
Atom net_active = XInternAtom(wm->dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
Atom net_close = XInternAtom(wm->dpy, "_NET_CLOSE_WINDOW", False);
|
||||
Atom wm_change_state = XInternAtom(wm->dpy, "WM_CHANGE_STATE", False);
|
||||
|
||||
if (e->message_type == net_active) {
|
||||
Client *c = client_find_by_win(wm, e->window);
|
||||
if (c) client_restore(wm, c);
|
||||
return;
|
||||
}
|
||||
if (e->message_type == net_close) {
|
||||
Client *c = client_find_by_win(wm, e->window);
|
||||
if (c) {
|
||||
XEvent ev = {0};
|
||||
ev.xclient.type = ClientMessage;
|
||||
ev.xclient.window = c->win;
|
||||
ev.xclient.message_type = wm->wm_protocols;
|
||||
ev.xclient.format = 32;
|
||||
ev.xclient.data.l[0] = wm->wm_delete_window;
|
||||
ev.xclient.data.l[1] = CurrentTime;
|
||||
XSendEvent(wm->dpy, c->win, False, NoEventMask, &ev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* WM_CHANGE_STATE IconicState → minimize */
|
||||
if (e->message_type == wm_change_state && e->data.l[0] == 3) {
|
||||
Client *c = client_find_by_win(wm, e->window);
|
||||
if (c && !c->minimized) client_minimize(wm, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,10 +287,19 @@ void on_key_press(WM *wm, XKeyEvent *e) {
|
||||
if ((e->state & Mod1Mask) && sym == XK_F4 && wm->focused)
|
||||
send_delete(wm, wm->focused->win);
|
||||
|
||||
/* Alt+Tab — visual switcher */
|
||||
/* Alt+Tab / Shift+Alt+Tab — visual switcher */
|
||||
if ((e->state & Mod1Mask) && sym == XK_Tab) {
|
||||
if (wm->swl_visible) switcher_next(wm);
|
||||
else if (wm->clients) switcher_show(wm);
|
||||
int backward = (e->state & ShiftMask) != 0;
|
||||
if (wm->swl_visible) {
|
||||
if (backward) switcher_prev(wm);
|
||||
else switcher_next(wm);
|
||||
} else if (wm->clients) {
|
||||
switcher_show(wm);
|
||||
if (backward && wm->swl_visible) {
|
||||
wm->swl_idx = wm->swl_count - 1;
|
||||
switcher_draw(wm);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user