From: A-Larsen Date: Tue, 13 Oct 2026 03:29:17 +0000 (-0400) Subject: launch applications in specific tags and monitor, with switchto rules X-Git-Url: https://nyquistdev.net/git/?a=commitdiff_plain;h=522abcc2b661893c3c346ec97cbd49dc3a6b9464;p=dwm-config.git launch applications in specific tags and monitor, with switchto rules --- diff --git a/config.def.h b/config.def.h index f1b68b3..e283226 100644 --- a/config.def.h +++ b/config.def.h @@ -45,9 +45,11 @@ const unsigned int calc_width = 312; const unsigned int calc_height = 570; const int xephyr_width = 450; /* Set your desired pixel width */ -const float centered_height = .95; -// const float centered_width = .65; -const float centered_width = .75; +// const float centered_height = .95; +// const float centered_width = .75; +/* centered_width and centered_height per monitor */ +static const float centered_width[] = { 0.75, 0.60 }; +static const float centered_height[] = { 0.95, 0.95 }; static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, @@ -70,6 +72,22 @@ static const char *colors[][3] = { static char tags[][MAX_TAGNAME_LEN] = { "1\0", "2\0", "3\0", "4\0", "5\0"}; +/* layout(s) */ +static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + { "|M|", centeredmaster }, + // { ">M>", centeredfloatingmaster }, +}; + static const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class @@ -77,32 +95,32 @@ static const Rule rules[] = { */ // Keep ffplay floating a and in all tags for facecam script // last tag is for calendar - /* class instance title tags mask isfloating isCentered isSidePanel monitor resize hint*/ + /* class instance title tags mask isfloating isCentered isSidePanel monitor resize hint layout switchto*/ // - { NULL, NULL, NULL, 0, 1, 1, 0, -1, 0 }, - { NULL, NULL, "facecam", (1<<4)-1, 0, 0, 1, -1, 1, }, - // { "SpeedCrunch", NULL, "calculator", 0, 1, 0, 0, -1, 0, }, - { "SpeedCrunch", NULL, "calculator", 0, 0, 0, 1, -1, 0, }, - //{ "SpeedCrunch", NULL, "SpeedCrunch", 0, 0, 0, 0, -1, 1, }, - { NULL, NULL, "youtube-upload", (1<<9)-1, 1, 0, 0, -1, 0, }, - { NULL, NULL, "Calendar", 0, 0, 0, 0, -1, 0, }, - { "Xephyr", NULL, NULL, 0, 0, 0, 1, -1, 0, }, - { "Brave-browser", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Alacritty", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Zathura", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "steam", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "steam", NULL, "Friends List", 0, 0, 0, 1, -1, 1, }, - { "steam", NULL, "Steam Settings", 0, 1, 0, 0, -1, 0, }, - { "Gimp", NULL, "Open Image", 0, 1, 1, 0, -1, 0, }, - { "Gimp", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "discord", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Blender", NULL,"Blender File View", 0, 1, 1, 0, -1, 0 }, - { "Blender", NULL,"Blender Render", 0, 0, 0, 1, -1, 0 }, - { "Blender", NULL, NULL, 0, 0, 1, 0, -1, 0 }, - { NULL, NULL, "note", 0, 1, 0, 0, -1, 0, }, - { NULL, NULL, "pulsemixer", (1<<9)-1, 1, 0, 0, -1, 0, }, - { NULL, NULL, "htop", (1<<9)-1, 1, 0, 0, -1, 0, }, - // { NULL, NULL, NULL, 0, 0, 1, 0, -1 }, + { NULL, NULL, NULL, 0, 1, 1, 0, -1, 0, NULL, 0}, + { NULL, NULL, "facecam", (1<<4)-1, 0, 0, 1, 1, 1, NULL, 0}, + // { "SpeedCrunch", NULL, "calculator", 0, 1, 0, 0, -1, 0, NULL, 0}, + { "SpeedCrunch", NULL, "calculator", 0, 0, 0, 1, 1, 0, NULL, 1}, + //{ "SpeedCrunch", NULL, "SpeedCrunch", 0, 0, 0, 0, -1, 1, NULL, 0}, + { NULL, NULL, "youtube-upload", (1<<9)-1, 1, 0, 0, -1, 0, NULL, 0}, + { NULL, NULL, "Calendar", 0, 0, 0, 0, 1, 0, NULL, 1}, + { "Xephyr", NULL, NULL, 0, 0, 0, 1, 1, 0, NULL, 1}, + { "Brave-browser", NULL, NULL, 1<<0, 0, 1, 0, 1, 0, NULL, 1}, + { "Alacritty", NULL, NULL, 1<<0, 0, 1, 0, 0, 0, NULL, 1}, + { "Zathura", NULL, NULL, 1<<0, 0, 1, 0, 1, 0, &layouts[2], 1}, + { "steam", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 0}, + { "steam", NULL, "Friends List", 1<<1, 0, 0, 1, 1, 1, NULL, 0}, + { "steam", NULL, "Steam Settings", 0, 1, 0, 0, 0, 0, NULL, 0}, + { "Gimp", NULL, "Open Image", 1<<1, 1, 1, 0, 0, 0, &layouts[2], 1}, + { "Gimp", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 1}, + { "discord", NULL, NULL, 1<<1, 0, 1, 0, 1, 0, &layouts[2], 0}, + { "Blender", NULL,"Blender File View", 1<<1, 1, 1, 0, 0, 0, &layouts[2], 1}, + { "Blender", NULL,"Blender Render", 1<<1, 0, 0, 1, 0, 0, &layouts[2], 1}, + { "Blender", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 1}, + { NULL, NULL, "note", 0, 1, 0, 0, -1, 0, NULL, 0}, + { NULL, NULL, "pulsemixer", (1<<9)-1, 1, 0, 0, 1, 0, NULL, 1}, + { NULL, NULL, "htop", (1<<9)-1, 1, 0, 0, 1, 0, NULL, 1}, + // { NULL, NULL, NULL, 0, 0, 1, 0, -1 }, // there is a possibility to need a terminal in misc tag as well.. // { NULL, NULL, "Alacritty", 1 << 0, 0, -1 }, @@ -113,22 +131,6 @@ static const Rule rules[] = { // { "KeePassXC", NULL, NULL, 1 << 4, 0, -1 }, }; -/* layout(s) */ -static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ -static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ -static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ - -static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, - { "|M|", centeredmaster }, - // { ">M>", centeredfloatingmaster }, -}; - const char * geticon(char *class) { @@ -166,7 +168,6 @@ static const char *volupcmd[] = { "/usr/local/bin/dwm_volume_up", NULL }; static const char *voldowncmd[] = { "/usr/local/bin/dwm_volume_down", NULL }; static const char *volmutecmd[] = { "/usr/local/bin/dwm_volume_mute", NULL }; static const char *mixercmd[] = { "/usr/local/bin/dwm-term-toggle", "pulsemixer", NULL }; -static const char *calccmd[] = { "/usr/local/bin/dwm-speedcrunch-toggle", NULL }; static const char *calc_mcw_cmd[] = { "/usr/local/bin/dwm-speedcrunch-move", "cw", NULL }; static const char *calc_mccw_cmd[] = { "/usr/local/bin/dwm-speedcrunch-move", "ccw", NULL }; static const char *facecamcmd[] = { "/usr/local/bin/facecam", NULL }; @@ -192,9 +193,9 @@ static const Key keys[] = { { MODKEY, XK_F3, spawn, {.v = volupcmd } }, { MODKEY, XK_F4, spawn, {.v = volmutecmd } }, { MODKEY|ShiftMask, XK_m, spawn, {.v = cpucmd } }, - { MODKEY|ShiftMask, XK_e, spawn, {.v = calccmd } }, - { MODKEY, XK_e, spawn, {.v = calc_mccw_cmd } }, - { MODKEY|ControlMask, XK_e, spawn, {.v = calc_mcw_cmd } }, + // { MODKEY, XK_e, spawn, {.v = calc_mccw_cmd } }, + // { MODKEY|ControlMask, XK_e, spawn, {.v = calc_mcw_cmd } }, + { MODKEY, XK_o, focuscalculator, {0} }, { MODKEY|ShiftMask, XK_f, spawn, {.v = facecamcmd } }, { MODKEY|ShiftMask, XK_b, spawn, {.v = brightnesscmd} }, { MODKEY|ShiftMask, XK_p, spawn, {.v = calendarcmd} }, diff --git a/config.h b/config.h index f1b68b3..e283226 100644 --- a/config.h +++ b/config.h @@ -45,9 +45,11 @@ const unsigned int calc_width = 312; const unsigned int calc_height = 570; const int xephyr_width = 450; /* Set your desired pixel width */ -const float centered_height = .95; -// const float centered_width = .65; -const float centered_width = .75; +// const float centered_height = .95; +// const float centered_width = .75; +/* centered_width and centered_height per monitor */ +static const float centered_width[] = { 0.75, 0.60 }; +static const float centered_height[] = { 0.95, 0.95 }; static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, @@ -70,6 +72,22 @@ static const char *colors[][3] = { static char tags[][MAX_TAGNAME_LEN] = { "1\0", "2\0", "3\0", "4\0", "5\0"}; +/* layout(s) */ +static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + { "|M|", centeredmaster }, + // { ">M>", centeredfloatingmaster }, +}; + static const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class @@ -77,32 +95,32 @@ static const Rule rules[] = { */ // Keep ffplay floating a and in all tags for facecam script // last tag is for calendar - /* class instance title tags mask isfloating isCentered isSidePanel monitor resize hint*/ + /* class instance title tags mask isfloating isCentered isSidePanel monitor resize hint layout switchto*/ // - { NULL, NULL, NULL, 0, 1, 1, 0, -1, 0 }, - { NULL, NULL, "facecam", (1<<4)-1, 0, 0, 1, -1, 1, }, - // { "SpeedCrunch", NULL, "calculator", 0, 1, 0, 0, -1, 0, }, - { "SpeedCrunch", NULL, "calculator", 0, 0, 0, 1, -1, 0, }, - //{ "SpeedCrunch", NULL, "SpeedCrunch", 0, 0, 0, 0, -1, 1, }, - { NULL, NULL, "youtube-upload", (1<<9)-1, 1, 0, 0, -1, 0, }, - { NULL, NULL, "Calendar", 0, 0, 0, 0, -1, 0, }, - { "Xephyr", NULL, NULL, 0, 0, 0, 1, -1, 0, }, - { "Brave-browser", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Alacritty", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Zathura", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "steam", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "steam", NULL, "Friends List", 0, 0, 0, 1, -1, 1, }, - { "steam", NULL, "Steam Settings", 0, 1, 0, 0, -1, 0, }, - { "Gimp", NULL, "Open Image", 0, 1, 1, 0, -1, 0, }, - { "Gimp", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "discord", NULL, NULL, 0, 0, 1, 0, -1, 0, }, - { "Blender", NULL,"Blender File View", 0, 1, 1, 0, -1, 0 }, - { "Blender", NULL,"Blender Render", 0, 0, 0, 1, -1, 0 }, - { "Blender", NULL, NULL, 0, 0, 1, 0, -1, 0 }, - { NULL, NULL, "note", 0, 1, 0, 0, -1, 0, }, - { NULL, NULL, "pulsemixer", (1<<9)-1, 1, 0, 0, -1, 0, }, - { NULL, NULL, "htop", (1<<9)-1, 1, 0, 0, -1, 0, }, - // { NULL, NULL, NULL, 0, 0, 1, 0, -1 }, + { NULL, NULL, NULL, 0, 1, 1, 0, -1, 0, NULL, 0}, + { NULL, NULL, "facecam", (1<<4)-1, 0, 0, 1, 1, 1, NULL, 0}, + // { "SpeedCrunch", NULL, "calculator", 0, 1, 0, 0, -1, 0, NULL, 0}, + { "SpeedCrunch", NULL, "calculator", 0, 0, 0, 1, 1, 0, NULL, 1}, + //{ "SpeedCrunch", NULL, "SpeedCrunch", 0, 0, 0, 0, -1, 1, NULL, 0}, + { NULL, NULL, "youtube-upload", (1<<9)-1, 1, 0, 0, -1, 0, NULL, 0}, + { NULL, NULL, "Calendar", 0, 0, 0, 0, 1, 0, NULL, 1}, + { "Xephyr", NULL, NULL, 0, 0, 0, 1, 1, 0, NULL, 1}, + { "Brave-browser", NULL, NULL, 1<<0, 0, 1, 0, 1, 0, NULL, 1}, + { "Alacritty", NULL, NULL, 1<<0, 0, 1, 0, 0, 0, NULL, 1}, + { "Zathura", NULL, NULL, 1<<0, 0, 1, 0, 1, 0, &layouts[2], 1}, + { "steam", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 0}, + { "steam", NULL, "Friends List", 1<<1, 0, 0, 1, 1, 1, NULL, 0}, + { "steam", NULL, "Steam Settings", 0, 1, 0, 0, 0, 0, NULL, 0}, + { "Gimp", NULL, "Open Image", 1<<1, 1, 1, 0, 0, 0, &layouts[2], 1}, + { "Gimp", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 1}, + { "discord", NULL, NULL, 1<<1, 0, 1, 0, 1, 0, &layouts[2], 0}, + { "Blender", NULL,"Blender File View", 1<<1, 1, 1, 0, 0, 0, &layouts[2], 1}, + { "Blender", NULL,"Blender Render", 1<<1, 0, 0, 1, 0, 0, &layouts[2], 1}, + { "Blender", NULL, NULL, 1<<1, 0, 1, 0, 0, 0, &layouts[2], 1}, + { NULL, NULL, "note", 0, 1, 0, 0, -1, 0, NULL, 0}, + { NULL, NULL, "pulsemixer", (1<<9)-1, 1, 0, 0, 1, 0, NULL, 1}, + { NULL, NULL, "htop", (1<<9)-1, 1, 0, 0, 1, 0, NULL, 1}, + // { NULL, NULL, NULL, 0, 0, 1, 0, -1 }, // there is a possibility to need a terminal in misc tag as well.. // { NULL, NULL, "Alacritty", 1 << 0, 0, -1 }, @@ -113,22 +131,6 @@ static const Rule rules[] = { // { "KeePassXC", NULL, NULL, 1 << 4, 0, -1 }, }; -/* layout(s) */ -static const float mfact = 0.50; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ -static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ -static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ -static const int refreshrate = 120; /* refresh rate (per second) for client move/resize */ - -static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, - { "|M|", centeredmaster }, - // { ">M>", centeredfloatingmaster }, -}; - const char * geticon(char *class) { @@ -166,7 +168,6 @@ static const char *volupcmd[] = { "/usr/local/bin/dwm_volume_up", NULL }; static const char *voldowncmd[] = { "/usr/local/bin/dwm_volume_down", NULL }; static const char *volmutecmd[] = { "/usr/local/bin/dwm_volume_mute", NULL }; static const char *mixercmd[] = { "/usr/local/bin/dwm-term-toggle", "pulsemixer", NULL }; -static const char *calccmd[] = { "/usr/local/bin/dwm-speedcrunch-toggle", NULL }; static const char *calc_mcw_cmd[] = { "/usr/local/bin/dwm-speedcrunch-move", "cw", NULL }; static const char *calc_mccw_cmd[] = { "/usr/local/bin/dwm-speedcrunch-move", "ccw", NULL }; static const char *facecamcmd[] = { "/usr/local/bin/facecam", NULL }; @@ -192,9 +193,9 @@ static const Key keys[] = { { MODKEY, XK_F3, spawn, {.v = volupcmd } }, { MODKEY, XK_F4, spawn, {.v = volmutecmd } }, { MODKEY|ShiftMask, XK_m, spawn, {.v = cpucmd } }, - { MODKEY|ShiftMask, XK_e, spawn, {.v = calccmd } }, - { MODKEY, XK_e, spawn, {.v = calc_mccw_cmd } }, - { MODKEY|ControlMask, XK_e, spawn, {.v = calc_mcw_cmd } }, + // { MODKEY, XK_e, spawn, {.v = calc_mccw_cmd } }, + // { MODKEY|ControlMask, XK_e, spawn, {.v = calc_mcw_cmd } }, + { MODKEY, XK_o, focuscalculator, {0} }, { MODKEY|ShiftMask, XK_f, spawn, {.v = facecamcmd } }, { MODKEY|ShiftMask, XK_b, spawn, {.v = brightnesscmd} }, { MODKEY|ShiftMask, XK_p, spawn, {.v = calendarcmd} }, diff --git a/dwm b/dwm index cf10240..6eb49b0 100755 Binary files a/dwm and b/dwm differ diff --git a/dwm.c b/dwm.c index 6148137..da8bafc 100644 --- a/dwm.c +++ b/dwm.c @@ -97,7 +97,9 @@ struct Client { int bw, oldbw; int isPopup; unsigned int tags; - int isfixed, iscentered, isfloating, isSidePanel, isurgent, neverfocus, oldstate, isfullscreen, resizehints; + int isfixed, iscentered, isfloating, isSidePanel, isurgent, neverfocus, + oldstate, isfullscreen, resizehints, explicit_tags, explicit_monitor, + switchto; Client *next; Client *snext; Monitor *mon; @@ -153,11 +155,12 @@ typedef struct { int isSidePanel; int monitor; int resizehints; + const Layout *layout; + int switchto; } Rule; unsigned char one_window = 0; /* function declarations */ -static void setopacity(Client *c, double opacity); static void applyrules(Client *c); static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); static void arrange(Monitor *m); @@ -256,6 +259,8 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); static void centeredmaster(Monitor *m); static void centeredfloatingmaster(Monitor *m); +static void update_alacritty_opacity(Monitor *m); +static void focuscalculator(const Arg *arg); /* variables */ static const char broken[] = "broken"; @@ -283,26 +288,6 @@ getcenteredbox(Monitor *m, unsigned int n, int *bx, int *by, int *bw, int *bh) } } -void -update_alacritty_opacity(Monitor *m) -{ - static double last_opacity = -1.0; - if (!m || !m->lt[m->sellt]) - return; - - double target_opacity = (m->lt[m->sellt]->arrange == monocle) ? 1.0 : 0.93; - - /* Only send IPC message if opacity state changed to prevent unnecessary commands */ - if (target_opacity != last_opacity) { - char cmd[128]; - snprintf(cmd, sizeof(cmd), - "alacritty msg config \"window.opacity=%.2f\" >/dev/null 2>&1 &", - target_opacity); - system(cmd); - last_opacity = target_opacity; - } -} - static void get_layout_box(Monitor *m, unsigned int force_centered, unsigned int *out_nt, int *bx, int *by, int *bw, int *bh) { @@ -774,10 +759,19 @@ applyrules(Client *c) && (!r->instance || strstr(instance, r->instance))) { c->isfloating = r->isfloating; + + /* --- UPDATE: Track explicit tag assignment --- */ + if (r->tags) { + c->tags |= r->tags; + c->explicit_tags = 1; + } + /* ------------------------------------------- */ + c->tags |= r->tags; c->resizehints = r->resizehints; c->iscentered = r->iscentered; c->isSidePanel = r->isSidePanel; + c->switchto = r->switchto; /* --- THE PERMANENT FIX --- */ /* If this is the calculator, force the dimensions NOW. @@ -793,8 +787,32 @@ applyrules(Client *c) /* ------------------------- */ for (m = mons; m && m->num != r->monitor; m = m->next); - if (m) + if (m) { c->mon = m; + if (r->monitor != -1) + c->explicit_monitor = 1; + } + + /* --- PER-TAG LAYOUT RULE --- */ + if (r->layout) { + Monitor *tm = c->mon; + unsigned int target_tags = r->tags ? r->tags : c->tags; + + /* Update the pertag layout index for every tag targeted by this rule */ + for (int t = 0; t < LENGTH(tags); t++) { + if (target_tags & (1 << t)) { + int tag_idx = t + 1; /* pertag uses 1-based indexing */ + tm->pertag->ltidxs[tag_idx][0] = (Layout *)r->layout; + tm->pertag->ltidxs[tag_idx][1] = (Layout *)r->layout; + } + } + + /* If the monitor is currently viewing that tag, update the active layout immediately */ + if (tm->pertag->curtag > 0 && (target_tags & (1 << (tm->pertag->curtag - 1)))) { + tm->lt[tm->sellt] = tm->pertag->ltidxs[tm->pertag->curtag][tm->sellt]; + strncpy(tm->ltsymbol, tm->lt[tm->sellt]->symbol, sizeof tm->ltsymbol); + } + } } } @@ -873,39 +891,21 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) return *x != c->x || *y != c->y || *w != c->w || *h != c->h; } -// void -// arrange(Monitor *m) -// { -// if (m) -// showhide(m->stack); -// else for (m = mons; m; m = m->next) -// showhide(m->stack); -// if (m) { -// arrangemon(m); -// restack(m); -// } else for (m = mons; m; m = m->next) -// arrangemon(m); -// } - void arrange(Monitor *m) { if (m) showhide(m->stack); - else - for (m = mons; m; m = m->next) - showhide(m->stack); - - /* Update global Alacritty opacity based on active layout */ - update_alacritty_opacity(m ? m : selmon); - + else for (m = mons; m; m = m->next) + showhide(m->stack); if (m) { arrangemon(m); restack(m); - } else { - for (m = mons; m; m = m->next) - arrangemon(m); - } + update_alacritty_opacity(m); + } else for (m = mons; m; m = m->next) { + arrangemon(m); + update_alacritty_opacity(m); + } } void @@ -1198,30 +1198,81 @@ configurerequest(XEvent *e) // return m; // } +// Monitor * +// createmon(void) +// { +// Monitor *m; +// unsigned int i; + +// m = ecalloc(1, sizeof(Monitor)); +// m->tagset[0] = m->tagset[1] = 1; +// m->mfact = mfact; +// m->hfact = centered_height; +// m->cwfact = centered_width; +// // m->center_mfact = center_mfact; +// m->nmaster = nmaster; +// m->showbar = showbar; +// m->topbar = topbar; +// m->lt[0] = &layouts[0]; +// m->lt[1] = &layouts[1 % LENGTH(layouts)]; +// strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + +// m->pertag = ecalloc(1, sizeof(Pertag)); +// m->pertag->curtag = m->pertag->prevtag = 1; + +// /* Ensure this is large enough to hold all tags */ +// m->tags = ecalloc(LENGTH(tags), sizeof(char *)); + +// for (i = 0; i <= LENGTH(tags); i++) { +// m->pertag->nmasters[i] = m->nmaster; +// m->pertag->mfacts[i] = m->mfact; +// m->pertag->ltidxs[i][0] = m->lt[0]; +// m->pertag->ltidxs[i][1] = m->lt[1]; +// m->pertag->sellts[i] = m->sellt; +// m->pertag->showbars[i] = m->showbar; + +// /* INITIALIZE FOCUS HISTORY */ +// m->pertag->selclients[i] = NULL; + +// /* SAFETY: Only allocate/copy tags for valid tag indices (0 to LENGTH-1) */ +// if (i < LENGTH(tags)) { +// m->tags[i] = ecalloc(1, sizeof(char) * (MAX_TAGNAME_LEN + 1)); +// strncpy(m->tags[i], tags[i], MAX_TAGNAME_LEN); +// } +// } + +// return m; +// } + Monitor * createmon(void) { - Monitor *m; - unsigned int i; + Monitor *m, *tm; + unsigned int i, mon_idx = 0; + + /* Count existing monitors to get index for new monitor */ + for (tm = mons; tm; tm = tm->next) + mon_idx++; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; m->mfact = mfact; - m->hfact = centered_height; - m->cwfact = centered_width; - // m->center_mfact = center_mfact; + + /* Set per-monitor centered float values with fallback to index 0 */ + m->cwfact = (mon_idx < LENGTH(centered_width)) ? centered_width[mon_idx] : centered_width[0]; + m->hfact = (mon_idx < LENGTH(centered_height)) ? centered_height[mon_idx] : centered_height[0]; + m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); - + m->pertag = ecalloc(1, sizeof(Pertag)); m->pertag->curtag = m->pertag->prevtag = 1; - /* Ensure this is large enough to hold all tags */ - m->tags = ecalloc(LENGTH(tags), sizeof(char *)); + m->tags = ecalloc(LENGTH(tags), sizeof(char *)); for (i = 0; i <= LENGTH(tags); i++) { m->pertag->nmasters[i] = m->nmaster; @@ -1231,10 +1282,8 @@ createmon(void) m->pertag->sellts[i] = m->sellt; m->pertag->showbars[i] = m->showbar; - /* INITIALIZE FOCUS HISTORY */ m->pertag->selclients[i] = NULL; - /* SAFETY: Only allocate/copy tags for valid tag indices (0 to LENGTH-1) */ if (i < LENGTH(tags)) { m->tags[i] = ecalloc(1, sizeof(char) * (MAX_TAGNAME_LEN + 1)); strncpy(m->tags[i], tags[i], MAX_TAGNAME_LEN); @@ -1820,7 +1869,8 @@ focusstack(const Arg *arg) { Client *c = NULL, *i; /* Helper to check if a window should be skipped in navigation */ - #define ISSKIPPABLE(X) (X->resizehints && (!X->name || strcmp(X->name, "calculator") != 0)) + // #define ISSKIPPABLE(X) (X->resizehints && (!X->name || strcmp(X->name, "calculator") != 0)) + #define ISSKIPPABLE(X) ((X)->resizehints || ((X)->name && strstr((X)->name, "calculator") != NULL)) if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) return; @@ -2241,8 +2291,36 @@ manage(Window w, XWindowAttributes *wa) } else { c->mon = selmon; applyrules(c); + /* 2. Apply Rules & Hardcoded Dimensions */ + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + } + // /* --- NEW: AUTO-SWITCH TAG ON LAUNCH --- */ + // if (c->explicit_tags && !(c->tags & c->mon->tagset[c->mon->seltags])) { + // Monitor *oldselmon = selmon; + // selmon = c->mon; + // view(&(Arg){ .ui = c->tags }); + // selmon = oldselmon; + // } + // /* ------------------------------------- */ + // + /* --- AUTO-SWITCH MONITOR AND TAG ON LAUNCH --- */ + + if (c->switchto && (c->explicit_monitor || c->explicit_tags)) { + selmon = c->mon; + if (c->explicit_tags && !(c->tags & selmon->tagset[selmon->seltags])) { + view(&(Arg){ .ui = c->tags }); + } + } + /* --------------------------------------------- */ + /* 3. Geometric Constraints */ if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) c->x = c->mon->wx + c->mon->ww - WIDTH(c); @@ -2868,6 +2946,7 @@ setlayout(const Arg *arg) arrange(selmon); else drawbar(selmon); + } void @@ -2963,6 +3042,7 @@ setup(void) netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + netatom[NetWMOpacity] = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False); /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); @@ -3033,8 +3113,9 @@ spawn(const Arg *arg) { struct sigaction sa; - if (arg->v == dmenucmd) + if (arg->v == dmenucmd) dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); @@ -4102,15 +4183,257 @@ main(int argc, char *argv[]) return EXIT_SUCCESS; } #include "movestack.c" + +// void +// update_alacritty_opacity(Monitor *m) +// { +// double target_opacity = (m->lt[m->sellt]->arrange == monocle) ? 1.0 : 0.93; + +// if (!m) +// m = selmon; /* Fallback to currently focused monitor */ + +// for (Client *c = m->clients; c; c = c->next) { +// if (ISVISIBLE(c)) { +// Window win_id = c->win; + +// char cmd[128]; +// snprintf(cmd, sizeof(cmd), +// "alacritty msg config -w %lu \"window.opacity=%.2f\" >/dev/null 2>&1 &", +// win_id, target_opacity); +// system(cmd); +// } +// } +// } + +// void +// update_alacritty_opacity(Monitor *m) +// { +// /* Fix 2: Fallback to selmon BEFORE accessing properties */ +// if (!m) +// m = selmon; + +// if (!m || !m->lt[m->sellt]) +// return; + +// double target_opacity = (m->lt[m->sellt]->arrange == monocle) ? 1.0 : 0.93; + +// for (Client *c = m->clients; c; c = c->next) { +// /* Fix 3: Ensure window belongs to Alacritty before sending command */ +// if (ISVISIBLE(c) && c->class && strstr(c->class, "Alacritty")) { +// Window win_id = c->win; + +// char cmd[128]; +// snprintf(cmd, sizeof(cmd), +// "alacritty msg config -w %lu \"window.opacity=%.2f\" >/dev/null 2>&1 &", +// (unsigned long)win_id, target_opacity); +// system(cmd); +// } +// } +// } + +// void +// update_alacritty_opacity(Monitor *m) +// { +// if (!m) +// m = selmon; + +// if (!m || !m->lt[m->sellt]) +// return; + +// /* Check if any visible window is actually Alacritty before firing IPC */ +// int has_alacritty = 0; +// for (Client *c = m->clients; c; c = c->next) { +// if (ISVISIBLE(c) && c->class && strstr(c->class, "Alacritty")) { +// has_alacritty = 1; +// break; +// } +// } + +// if (!has_alacritty) +// return; + +// double target_opacity = (m->lt[m->sellt]->arrange == monocle) ? 1.0 : 0.93; + +// char cmd[128]; +// snprintf(cmd, sizeof(cmd), +// "alacritty msg config \"window.opacity=%.2f\" >/dev/null 2>&1 &", +// target_opacity); +// system(cmd); +// } + void setopacity(Client *c, double opacity) { - if (!c) - return; - unsigned long opa = (unsigned long)(opacity * 0xffffffff); - if (opacity >= 1.0) + if (opacity >= 1.0) { XDeleteProperty(dpy, c->win, netatom[NetWMOpacity]); - else - XChangeProperty(dpy, c->win, netatom[NetWMOpacity], XA_CARDINAL, 32, - PropModeReplace, (unsigned char *)&opa, 1); + } else { + unsigned int opa = (unsigned int)(opacity * 0xffffffff); + XChangeProperty(dpy, c->win, netatom[NetWMOpacity], XA_CARDINAL, + 32, PropModeReplace, (unsigned char *)&opa, 1); + } +} + +void +update_alacritty_opacity(Monitor *m) +{ + if (!m) + m = selmon; + + if (!m || !m->lt[m->sellt]) + return; + + double target_opacity = (m->lt[m->sellt]->arrange == monocle) ? 1.0 : 0.93; + + for (Client *c = m->clients; c; c = c->next) { + /* strcasestr handles case variations like "alacritty" or "Alacritty" */ + if (ISVISIBLE(c) && c->class && strcasestr(c->class, "alacritty")) { + setopacity(c, target_opacity); + } + } +} +// void +// focuscalculator(const Arg *arg) +// { +// Client *c; +// for (c = selmon->clients; c; c = c->next) { +// if (ISVISIBLE(c) && c->name && strstr(c->name, "calculator")) { +// focus(c); +// restack(selmon); +// return; +// } +// } +// } + +// void +// focuscalculator(const Arg *arg) +// { +// static Client *prev_focus = NULL; +// Client *c, *calc = NULL; + +// /* Find the calculator window */ +// for (c = selmon->clients; c; c = c->next) { +// if (ISVISIBLE(c) && c->name && strstr(c->name, "calculator")) { +// calc = c; +// break; +// } +// } + +// if (!calc) +// return; + +// /* If calculator is currently focused, return to previous window */ +// if (selmon->sel == calc) { +// int valid = 0; +// for (c = selmon->clients; c; c = c->next) { +// if (c == prev_focus) { +// valid = 1; +// break; +// } +// } +// if (valid && ISVISIBLE(prev_focus)) { +// focus(prev_focus); +// restack(selmon); +// } +// } else { +// /* Save currently focused window and focus calculator */ +// prev_focus = selmon->sel; +// focus(calc); +// restack(selmon); +// } +// } + +// void +// focuscalculator(const Arg *arg) +// { +// static Client *prev_focus = NULL; +// Client *c, *calc = NULL; +// static const char *speedcrunch_cmd[] = { "/usr/local/bin/dwm-speedcrunch-toggle", NULL }; + +// /* Find the calculator window */ +// for (c = selmon->clients; c; c = c->next) { +// if (ISVISIBLE(c) && c->name && +// (strstr(c->name, "calculator") || strstr(c->name, "SpeedCrunch") || strstr(c->name, "speedcrunch"))) { +// calc = c; +// break; +// } +// } + +// /* If calculator is not found, launch speedcrunch */ +// if (!calc) { +// spawn(&(Arg){ .v = speedcrunch_cmd }); +// return; +// } + +// /* If calculator is currently focused, return to previous window */ +// if (selmon->sel == calc) { +// int valid = 0; +// for (c = selmon->clients; c; c = c->next) { +// if (c == prev_focus) { +// valid = 1; +// break; +// } +// } +// if (valid && ISVISIBLE(prev_focus)) { +// focus(prev_focus); +// restack(selmon); +// } +// } else { +// /* Save currently focused window and focus calculator */ +// prev_focus = selmon->sel; +// focus(calc); +// restack(selmon); +// } +// } + +void +focuscalculator(const Arg *arg) +{ + static Client *prev_focus = NULL; + Client *c, *calc = NULL; + static const char *speedcrunch_cmd[] = { "/usr/local/bin/dwm-speedcrunch-toggle", NULL }; + + /* Find the calculator window */ + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c) && c->name && + (strstr(c->name, "calculator") || strstr(c->name, "SpeedCrunch") || strstr(c->name, "speedcrunch"))) { + calc = c; + break; + } + } + + /* If calculator is not found, save current active window and launch speedcrunch */ + if (!calc) { + prev_focus = selmon->sel; + spawn(&(Arg){ .v = speedcrunch_cmd }); + return; + } + + /* If calculator is currently focused, return to previous window */ + if (selmon->sel == calc) { + int valid = 0; + for (c = selmon->clients; c; c = c->next) { + if (c == prev_focus) { + valid = 1; + break; + } + } + if (valid && ISVISIBLE(prev_focus)) { + focus(prev_focus); + restack(selmon); + } else { + /* Fallback to first non-calculator visible client if prev_focus was closed */ + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c) && c != calc) { + focus(c); + restack(selmon); + break; + } + } + } + } else { + /* Save currently focused window and focus calculator */ + prev_focus = selmon->sel; + focus(calc); + restack(selmon); + } } diff --git a/dwm.o b/dwm.o index 0182daa..b327e60 100644 Binary files a/dwm.o and b/dwm.o differ