You are not logged in.
I have patched dwm a little bit and added a support for predefined application per tag. Its main goal is to open an application when switching to tag (e.g. terminal emulator for cli tag, or browser for www tag). The problem is when I am switching to another tag, dwm instantly shows my background and then the application is started. Since most applications are cli based, it takes not so long time and produce flicker. The goal is to simply sleep for 100-200 ms after an application is spawned and before the redraw process has started. For some reason sleep in function spawn work only when first application is spawned. Dwm does not wait for next ones. If I close last application, it workes again only for first execution. Obviously, I do not completely understand how multiple fork calls work. Please keep in mind, I am noob in C.
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]);
exit(EXIT_SUCCESS);
}
else {
sleep(1);
}
}git clone git://git.suckless.org/dwm
Last edited by damage (2019-02-07 19:56:19)
Offline
Sounds like dwm is no longer the parent process for subsequent spawn calls (your code?), but I'd also add some stdout to the sleep in case the sleep does not achieve what you want it to.
Online
No the real problem here is that the sleep is in the WM: the same process that switches to the new tag and responds to the client window's map request.
In other words, the default condition without the sleep was as follows:
1. Get key or other trigger to switch to 'www' tag
2. Spawn the browser client
3. Actually switch the tag (hide other windows)
4. Then browser client window gets mapped.
You didn't like the "flicker" between 3 and 4, so you added a sleep in the WM code right after 3. But the problem is, this also delays 4 (as the WM is what *actually* maps the browser window). So now you just have:
1. Get key or other trigger to switch to 'www' tag.
2. Spawn the browser client
3. Sleep for a short period
4. Actually switch the tag (hide other windows)
5. Map the browser window
The transition from 4 to 5 is no faster here than in the 3 to 4 without the sleep, you've just slowed down the entire process.
You need to change the approach/logic: you want the tag switch to wait until after the browser window has been mapped (in other words switch steps 3 and 4 from the first list, not just add a delay before they happen).
The best approach to do this really depends on many other factors of how you want it to work. But you'd likely need to detect tag switches that require the launching a new client, fork the new client, set some variable, then abort the tag switch; meanwhile you'd add code to the mapwindow function (or whatever it is called now) to detect whether the above-mentioned variable is set, and if so switch tags as needed.
Last edited by Trilby (2019-02-06 00:40:35)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Sounds like dwm is no longer the parent process for subsequent spawn calls (your code?), but I'd also add some stdout to the sleep in case the sleep does not achieve what you want it to.
Spawn function is completely suckless code, except else block I have added at the end. No, it seems that parent pid is constant value.
void
spawn(const Arg *arg)
{
fprintf(stderr, "pid1: %i\n", getpid());
if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
setsid();
fprintf(stderr, "pid2: %i\n", getpid());
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
exit(EXIT_SUCCESS);
}
else {
sleep(1);
fprintf(stderr, "pid3: %i\n", getpid());
}
}Note 3 fprintf calls. After 3 application has been spawned I see following output.
pid1: 5384
pid2: 5393
pid3: 5384
pid1: 5384
pid2: 5444
pid3: 5384
pid1: 5384
pid2: 5474
pid3: 5384Offline
Yeah, as Trilby already suggested the sleep is called, it just doesn't do what you want it to do.
I thought you had maybe patched dwm a bit more (and the "autospawn" invocation would the the critical patch to see)
Online
You need to change the approach/logic: you want the tag switch to wait until after the browser window has been mapped (in other words switch steps 3 and 4 from the first list, not just add a delay before they happen).
The best approach to do this really depends on many other factors of how you want it to work. But you'd likely need to detect tag switches that require the launching a new client, fork the new client, set some variable, then abort the tag switch; meanwhile you'd add code to the mapwindow function (or whatever it is called now) to detect whether the above-mentioned variable is set, and if so switch tags as needed.
I should have posted the full code, I think.
void
inittagapps(unsigned int tag)
{
Client *c;
unsigned int i;
for(c = selmon->clients; c; c = c->next) {
if(ISVISIBLE(c)) {
return;
}
}
for(i = 0; i < LENGTH(tagapps); i++) {
if(tag == 1 << tagapps[i].tag) {
spawn(&tagapps[i].arg);
fprintf(stderr, "pid: %i (%lu)\n", getpid(), (unsigned long) time(NULL));
sleep(3);
fprintf(stderr, "pid: %i (%lu)\n", getpid(), (unsigned long) time(NULL));
return;
}
}
}
void
view(const Arg *arg)
{
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
inittagapps(arg->ui);
focus(NULL);
arrange(selmon);
}There are 2 functions in view that are responsible for updating the screen: focus and arrange. View switches selected tag. There is also my inittagapps function which opens appropriate application. I remove all sleeps inside spawn and add one to inittagapps, as you can see. I have tested this code for a while. Dwm waits for not first application to be started, rather to new type of application. I did not see this because I was using one terminal emulator. When I changed default applications, I see that sleep function works but in manner I do not want to. It waits 3 seconds, then shows my background and then start the application. If, for instance, st is already spawned, the following instances cause no delay. You can see its output:
// st is spawned
pid: 10566 (1549464629)
pid: 10566 (1549464632)
// st is spawned
pid: 10566 (1549464633)
pid: 10566 (1549464633)
// chromium is spawned
pid: 10566 (1549464635)
pid: 10566 (1549464638)
// xfce4-terminal is spawned
pid: 10566 (1549464640)
pid: 10566 (1549464643)Last edited by damage (2019-02-06 15:11:16)
Offline
if(tag == 1 << tagapps[i].tag) {What is that supposed to do?
Also notice that every inittagapps() call will only spawn [0,1] tagapps.
The problem will indeed be that you (somehow) spawn several clients in a row, but dwm doesn't get to process events, thus won't start to map/manage them while you're sleeping (ie. see Trilby's comment)
If the "flicker" is more related to the mapping sequence, grabbing the server around the several maps might reduce that, but probably the best mitigation is a compositor.
Online
if(tag == 1 << tagapps[i].tag) {What is that supposed to do?
Also notice that every inittagapps() call will only spawn [0,1] tagapps.
The problem will indeed be that you (somehow) spawn several clients in a row, but dwm doesn't get to process events, thus won't start to map/manage them while you're sleeping (ie. see Trilby's comment)
If the "flicker" is more related to the mapping sequence, grabbing the server around the several maps might reduce that, but probably the best mitigation is a compositor.
It checks whether there is a default application in tagapps for selected tag. I have also "1", "2", and "3" tags for various applications.
static TagApp tagapps[] = {
{0, {.v = todocmd}},
{1, {.v = fmcmd}},
{2, {.v = clicmd}},
{3, {.v = editorcmd}},
{4, {.v = browsercmd}},
{5, {.v = mpcmd}},
};I think, I got what Trilby said. There is manage function which listen to X event. It calls XMapWindow, arrange and a lot more. I should dig into it. As he said, a flag might need to set when application is spawned, and if it is, do the sleep here.
Last edited by damage (2019-02-06 17:59:16)
Offline
For the records: you compare "tag" to 1, shifted tagapps[ i ].tag bytes to the left.
I don't know whether that makes sense, but eg. 1<<5 is 32.
Online
Seth, that bit shifting for tags is common in dwm. This is part of how dwm tags are different from other wm's workspaces: one can have many tags active at the same time. Tag variables are bit-fields representing each individual tag. So the first and third tag could be active at the same time and would be represented by a tag value of 5 (000101).
As for everything else, all the symptoms continue to support my initial hypothesis. The newly spawned programs will not show up on screen until DWM processes events - so if you make DWM sleep, it just delays the whole series of changes, but it doesn't change their order.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Seth, that bit shifting for tags is common in dwm. This is part of how dwm tags are different from other wm's workspaces: one can have many tags active at the same time. Tag variables are bit-fields representing each individual tag. So the first and third tag could be active at the same time and would be represented by a tag value of 5 (000101).
As for everything else, all the symptoms continue to support my initial hypothesis. The newly spawned programs will not show up on screen until DWM processes events - so if you make DWM sleep, it just delays the whole series of changes, but it doesn't change their order.
Okay, I did what you said. Now, when switching tags, a new application is spawned and then the function (view) returns. When dwm respond to X event, I actually switch to new tag. Unfortunately, terminal starts with 80x20 columns/lines and then the window fit all available screen space. It is how dwm handle it by default. You can see this setting the rule for application in rules array. Application will start in another tag and will not updated until you go to that tag. Insane. It is not noticeable when we run shell in terminal, but if there is a lot of text (vim or file manager) all this text are stretched to fit the window. Changing default window size does not help because my screen is bigger than 191 columns but smaller than 192.
Offline
Okay, I had to do manual resizing in manage function. The whole code looks ugly, but it works.
Offline