LukeSmithxyz / dwmblocks

My status bar: my build of the modular dwmblocks
GNU General Public License v2.0
430 stars 368 forks source link

Wrong signals for button events #77

Closed zoomyboy closed 2 years ago

zoomyboy commented 3 years ago

I applied the latest patch to my dwm build, but the buttonhandler event is not executed for whatever reason.

Then, I figuered out that the following code in the latest dwm patch is grabbing the statussig: https://dwm.suckless.org/patches/statuscmd/dwm-statuscmd-20210405-67d76bd.diff

void
sigstatusbar(const Arg *arg)
{
    union sigval sv;

    if (!statussig)
        return;
    sv.sival_int = arg->i;
    if ((statuspid = getstatusbarpid()) <= 0)
        return;

    sigqueue(statuspid, SIGRTMIN+statussig, sv);
}

If I change this SIGRTMIN+statussig to 10, it works fine. It seems that this is not compatible with the way the dwmblocks works, because dwmblocks is always listening to the same signal no matter which "module" is actually clicked:

    sa.sa_sigaction = buttonhandler;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGUSR1, &sa, NULL);
    struct sigaction sigchld_action = {
        .sa_handler = SIG_DFL,
        .sa_flags = SA_NOCLDWAIT
    };
    sigaction(SIGCHLD, &sigchld_action, NULL);

Does enyone have this issue as well and can help me out?

simplepad commented 3 years ago

I have the same issue, seems like something's wrong with dwmblocks setting the $BLOCK_BUTTON env variable because when it runs the scripts the variable does not exist.

simplepad commented 3 years ago

@zoomyboy Ok, I finally got it to work. Looks like in the new version of dwm patch, it only does sigqueue(statuspid, SIGRTMIN+statussig, sv);, but this signal is caught by dwmblocks' sighandler which only updates the block and does not use the info of pressed buttons passed by dwm in sv.sival_int. This is the changes I made for it to work: (Changed lines have comments on them, two in each file)

  1. dwm.c

    void
    sigstatusbar(const Arg *arg)
    {
    union sigval sv;
    
    if (!statussig)
        return;
    sv.sival_int = arg->i | ((SIGRTMIN+statussig) << 3);   // This line
    if ((statuspid = getstatusbarpid()) <= 0)
        return;
    
    sigqueue(statuspid, SIGUSR1, sv);  // And this line
    }
  2. dwmblocks.c
    void buttonhandler(int sig, siginfo_t *si, void *ucontext)
    {
    char button[2] = {'0' + (si->si_value.sival_int & 7), '\0'};  // This line
    pid_t process_id = getpid();
    sig = (si->si_value.sival_int >> 3) - 34;   // And this line
    if (fork() == 0)
    {
        const Block *current;
        for (int i = 0; i < LENGTH(blocks); i++)
        {
            current = blocks + i;
            if (current->signal == sig)
                break;
        }
        char shcmd[1024];
        sprintf(shcmd,"%s && kill -%d %d", current->command, current->signal+34,process_id);
        char *command[] = { "/bin/sh", "-c", shcmd, NULL };
        setenv("BLOCK_BUTTON", button, 1);
        setsid();
        execvp(command[0], command);
        exit(EXIT_SUCCESS);
    }
    }

    After that I recompiled dwm and dwmblocks and now it works.

Now when dwm sends a signal to dwmblocks, it encodes the block number and the button in one integer, with the button number being the 3 least significant bits (so for up to 8 possible buttons) and the block number being all the other bits. This all has to be done because buttonhandler is used by only one signal (SIGUSR1) so the block number needs to share space with button number as I do not know any other way to circumvent this. Would be better if Luke or someone else with experience looked at this one.

zoomyboy commented 3 years ago

I got it working as wel, because I just copied the modified buttonhandler from @LukeSmithxyz modified version of dwm.

However, you're actually modifying the 3rd party code (from an dwmblocks view). Can't you just leave the original dwm plugin as-is and catch both the click and the usual update event in one single function inside dwmblocks?