I am trying to teach dwm to open appropriate application in each tag (www, files, music...). In dwm.c there is a function called view
that is responsible for tag switching.
void
view(const Arg *arg)
{
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
/* toggle sel tagset */
selmon->seltags ^= 1;
if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
// user specific edit
prepareTag(arg->ui);
focus(NULL);
arrange(selmon);
}
I have added a line where prepareTag
is called. This function has simple logic and do nothing else than a few verifications (is application already open?; what tag is it?) and the application spawn itself.
void
spawn(const Arg *arg)
{
if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
perror(" failed");
exit(EXIT_SUCCESS);
}
}
It works but the code goes asynchronously. The tag is changed and I see my wallpaper, than after ~20-50ms the application is started. It causes notable flicker. The problem is I have never worked with C and do not know the reason why the code work asynchronously. I have tried system
function instead of built-in spawn
but dwm do not catch applications open this way. I could probably use key binder and some BASHing but the way is quite dirty. Not to mention, I would like to have an ability to use mouse buttons to change tag.
In case someone need code base.
git clone https://git.suckless.org/dwm
If you read the manual for fork()
, you will realize the it creates a copy of the running process.
After the fork both the processes are independent of each other and may get scheduled in any order. This is the asynchronous behaviour you are seeing.
To get a synchronous behavior your parent process needs to wait till the forked process has completed (exits). This has be achieved using the wait()
system call.
You can modify your spawn
function as -
void
spawn(const Arg *arg)
{
if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
perror(" failed");
exit(EXIT_SUCCESS);
} else { // fork returns a non zero pid in the parent process. So the else branch will be taken only in the parent.
wait(NULL); // Wait for the child process to change state. In this case exit
}
}