I am using dwm (6.2) window manager and I found a bug which I would love to solve.
Window manager uses "master area" and "stack area" where windows are put:
It is possible to move window at the top of the "stack area" to the bottom of the "master area" using ALT + i. It is also possible to move windows from the bottom of the "master area" back to the top of "stack area" using ALT + d.
Now in this case, if I use ALT + i, layout changes and after the key combination there are two windows in the "master area":
I repeat it again and now there are three windows in the "master area":
I repeat it yet again and now there are three windows in the "master area" which has 100% width:
If I would at this point decide to return windows from the "master area" to the "stack area" I would start pressing ALT + d and windows would imediately return back to the "stack area". This works okay.
But I intentionaly make a mistake and instead press ALT + i again for example three more times. It looks like nothing happens...
But now if I try to return windows from the "master area" to the "stack area" I first need to press ALT + d three more times and nothing will happen! And then finaly, when I press ALT + d for the fourth time, window manager will return the first window from the bottom of the "master area" to the top of the "stack area".
So this is not well thought out and should be considered a bug...
There must be some sort of a counter in the source code which was incremented three more times by pressing ALT + i but it should not increase after all windows are already in the "master area".
In config.def.h
source file (www) there is a part of the code where keys are assigned. And here I can see that when user presses ALT + i function incnmaster()
is called and is passed an argument .i = +1
(I don't understand this argument).
static Key keys[] = {
/* modifier key function argument */
...
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
...
};
Key
is a structure inside dwm.c
source file (www):
typedef struct {
unsigned int mod;
KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
} Key;
Function incnmaster()
is defined in dwm.c
source file (www):
void
incnmaster(const Arg *arg)
{
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
arrange(selmon);
}
where arg
is a pointer to Arg
(Arg*
) which is a union (I don't quite understand how to deal with the argument .i = +1
):
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
selmon
is a structure Monitor
:
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
MAX
is defined in a separate source file util.h
(www) as:
#define MAX(A, B) ((A) > (B) ? (A) : (B))
and function arrange()
is defined like this:
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);
}
I don't think I have to dig any further...
Now I think I need to implement some sort of an if
sentantce in the C code to prevent selmon->nmaster
to increase too much, but I am a bit confused. Can anyone help?
Nobody answered before I could figure this one out myself. Problem is that Suckless team never implemented any kind of mechanism to count a number of opened windows (they call them clients). This is why I added a
int nclients;
member to structMonitor
:And then I made sure it is initialized to
0
at boot time by addingm->nclients = 0;
increatemon()
function which I guessed is ran at the beginning:Then I made sure that my counter
nclients
is increased when new window appears. I added++selmon->nclients;
andarrange(selmon);
(to be able to move clients to stack/master imediately after you close one of them) statement at the beginning of thespawn()
function:Counter should be decreased when window is closed. This is why I added a
--selmon->nclients;
andarrange(selmon);
(to be able to move clients to stack/master imediately after you close one of them) at the top of thekillclient()
function:Now that the counter was set up, I could use it to rewrite
incnmaster()
function like this:This solution partialy works. It only fails to work when I:
A. use
dmenu
dmenu
when started can (a) open a client or (b) do nothing. In case (a) everything works as expected, but in case (b)nmaster
andnclients
become out of sync again.So for example if I do scenario (b) once and use CTRL+i endless times, I will have to use CTRL+d once and nothing will happen, but if I use it once more one window is moved from master to stack area.
B. run any kind of windowed application from a terminal
It looks like DWM can't keep track of windows that are run from a terminal and treats them in a wrong way... In this case as well
nmaster
andnclients
become out of sync.Does anyone know if there is any other function besides
spawn
that is executed when any kind of window is opened?This is still not solved!