]> nyquistdev.net Git - dwm-config.git/commitdiff
launch applications in specific tags and monitor, with switchto rules
authorA-Larsen <austin.larsen@mailfence.com>
Tue, 13 Oct 2026 03:29:17 +0000 (23:29 -0400)
committerA-Larsen <austin.larsen@mailfence.com>
Tue, 13 Oct 2026 03:29:17 +0000 (23:29 -0400)
config.def.h
config.h
dwm
dwm.c
dwm.o

index f1b68b332f269e5373754b8effb9964fd5a6eb46..e283226c5286bb729588c0ea48461e52000eb968 100644 (file)
@@ -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} },
index f1b68b332f269e5373754b8effb9964fd5a6eb46..e283226c5286bb729588c0ea48461e52000eb968 100644 (file)
--- 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 cf10240c77303e17a64880dd83e8a2ced91bb34f..6eb49b0a3d16b1fb011d19b7d48b6db6323f3911 100755 (executable)
Binary files a/dwm and b/dwm differ
diff --git a/dwm.c b/dwm.c
index 61481373fae525f3c69a2cf468860ee8a9789f25..da8bafc6b4052763615a1796aa6ef23b6927aac3 100644 (file)
--- 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 0182daad0c01d382b96145c3af08ab3183c03ac1..b327e60b5c8ffe515482749232f07ea380221838 100644 (file)
Binary files a/dwm.o and b/dwm.o differ