bakkeby / patches

Collection of patches for dwm, st and dmenu
286 stars 30 forks source link

cfacts monitorules #46

Closed apprehensions closed 2 years ago

apprehensions commented 2 years ago

is it currently possible to add monitor specific cfacts like how there is an mfact value in monitorrules?

bakkeby commented 2 years ago

No that doesn't make much sense (to me at least).

The monitor factor (mfact) controls how much space is assigned to the master stack compared to the slave stack, and this is on a per-monitor basis.

The client factor (cfact) controls how much space is assigned to a client compared to other clients in the same area (master or stack) - provided that the layout supports cfacts of course.

You could set up client rules to set a specific window's cfact value when it starts and this is relatively straightforward to do.

The way you are wording it though suggests that you want a single client to have a different cfact value depending on which monitor it is shown?

apprehensions commented 2 years ago

the only reason i requested for something like this, is to achieve tiling similar to this: (automatically)

______
|     |
|_____|
|     |
|     |
|     |
|_____|

for reference, i have a secondary vertical monitor and having horizontal windows is terrible. i have achieved vertical tiling via the mfact in the monitorrules patch.

bakkeby commented 2 years ago

I use a different layouts on my vertical monitor, bottomstack being one example. Then incrementing nmaster if need be.

apprehensions commented 2 years ago

Then incrementing nmaster if need be.

______
|     |
|     |
|_____|
|     |
|     |
|_____|

is the layout i get when incrementing nmaster.

bakkeby commented 2 years ago

Yes that depends on the layout of course.

If you have clients that intentionally start on that monitor and you want to use cfacts then you could just add setting of cfacts to the client rules.

apprehensions commented 2 years ago

Sorry for the late response, but how would I do that?

bakkeby commented 2 years ago

Adding a new rule option is pretty straightforward. You just have three things to change - the Rule struct in dwm.c adding the new field, the applyrules function taking that new field into account and finally the rules array setting the new field in config.h.

You can use this as an example: https://github.com/bakkeby/patches/blob/master/dwm/dwm-respectsizehintsrule-6.3.diff

If you don't figure it out then I can try to whip something tomorrow.

apprehensions commented 2 years ago

is this good?

diff --git a/config.def.h b/config.def.h
index 5b0cfde..c715af2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,9 +26,9 @@ static const Rule rules[] = {
     *  WM_CLASS(STRING) = instance, class
     *  WM_NAME(STRING) = title
     */
-   /* class      instance    title       tags mask     isfloating   monitor */
-   { "Gimp",     NULL,       NULL,       0,            1,           -1 },
-   { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
+   /* class      instance    title       tags mask  cfact      isfloating   monitor */
+   { "Gimp",     NULL,       NULL,       0,         0.00,      1,           -1 },
+   { "Firefox",  NULL,       NULL,       1 << 8,    0.10,      0,           -1 },
 };

 /* layout(s) */
diff --git a/dwm.c b/dwm.c
index dde5e74..c02573c 100644
--- a/dwm.c
+++ b/dwm.c
@@ -138,6 +138,7 @@ typedef struct {
    const char *instance;
    const char *title;
    unsigned int tags;
+   float cfact;
    int isfloating;
    int monitor;
 } Rule;
@@ -300,6 +301,7 @@ applyrules(Client *c)
        && (!r->class || strstr(class, r->class))
        && (!r->instance || strstr(instance, r->instance)))
        {
+           c->cfact = r->cfact;
            c->isfloating = r->isfloating;
            c->tags |= r->tags;
            for (m = mons; m && m->num != r->monitor; m = m->next);

btw, how do i know the place of the rules? i plan to patch this and the respectsizehints and swallow. what is the order?

bakkeby commented 2 years ago

btw, how do i know the place of the rules?

This is pretty straightforward. If you compare

@@ -138,6 +138,7 @@ typedef struct {
    const char *instance;
    const char *title;
    unsigned int tags;
+   float cfact;
    int isfloating;
    int monitor;
 } Rule;

with the placement in the rules section

@@ -26,9 +26,9 @@ static const Rule rules[] = {
     *  WM_CLASS(STRING) = instance, class
     *  WM_NAME(STRING) = title
     */
-   /* class      instance    title       tags mask     isfloating   monitor */
-   { "Gimp",     NULL,       NULL,       0,            1,           -1 },
-   { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
+   /* class      instance    title       tags mask  cfact      isfloating   monitor */
+   { "Gimp",     NULL,       NULL,       0,         0.00,      1,           -1 },
+   { "Firefox",  NULL,       NULL,       1 << 8,    0.10,      0,           -1 },
 };

The "columns" of the rules array follow that of the Rule struct (as in the cfact value is between tags and isfloating), which means that you control the order by where you place the new field in that Rule struct.

bakkeby commented 2 years ago

As for

is this good?

this is how you would do it in most cases.

In this particular case however you may want to take into account the boundaries of cfact values, e.g.

So in applyrules when taking the cfacts into account you may want to consider making a call to setcfact instead of setting that cfacts value directly. This way you'd use a positive or negative value in the cfact to adjust it. Potentially that is more intuitive as well.

@@ -300,6 +301,7 @@ applyrules(Client *c)
        && (!r->class || strstr(class, r->class))
        && (!r->instance || strstr(instance, r->instance)))
        {
+           setcfact(&((Arg) { .f = r->cfact }));
            c->isfloating = r->isfloating;
            c->tags |= r->tags;
            for (m = mons; m && m->num != r->monitor; m = m->next);

As-is if you open gimp on an empty tag then dwm will likely crash due to division by 0 as the sum of client cfact values would be 0 and the cfacts patch divides by that.

    for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
        if (i < m->nmaster) {
-           h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+           h = (m->wh - my) * (c->cfact / mfacts);
            resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
            if (my + HEIGHT(c) < m->wh)
                my += HEIGHT(c);
apprehensions commented 2 years ago

Thank you.

apprehensions commented 2 years ago

But just as a seperate question: Isn't a layout possible where there would only be horizontal clients?

bakkeby commented 2 years ago

Isn't a layout possible where there would only be horizontal clients?

Most certainly. The easiest way to achieve this is to just set nmaster to 0 for the tile layout. If you wanted to hardcode that then you could just make a copy of the tile function and delete all the parts related to nmaster (that is easier than you might think).