bakkeby/patches

[Bug] Scratchpad window always creates new tags when executed

adetabrani opened this issue ยท 18 comments

i'm trying to combine tagicons patch with scratchpads patch, i'm trying to make them compatible with each other, but i get a bug that makes the scratchpad window always create a new tag when executing, is there a way to prevent the creation of a new tag when executing scratchpad?

here is my repo to try it

simplescreenrecorder.webm

The way the scratchpads patch works is precisely by adding a new tag and enabling that tag in addition to your currently selected tag(s) to show the scratchpad.

This means that in every single place where you refer to e.g. c->tags you need to filter out these extra tags by applying SPTAGMASK (e.g. c->tags & SPTAGMASK).

In your specific case though this happens because in the drawbar function where the tags are drawn we loop through NUMTAGS which includes the scratchpads.

#define NUMTAGS					        (9 + LENGTH(scratchpads))

There are ways to work around this issue, but I would just want to say that there is a fair deal of hassle having to take into account these "hidden" tags for this scratchpads patch and I would much rather recommend the namedscratchpads patch as it is much easier to work with. I have a more bloated version of that patch named renamedscratchpads as well if that would be of interest.

thank you for the recommendation, how do I bind with other utilities (eg: ncmpcpp) on renamedscratchpads?

As with all scratchpad patches we need to have a client rule that matches the window and marks that client as a scratchpad.

ncmpcpp specifically is a terminal program, so this will need to be run in a terminal.

Many terminal applications, but not all, allow for the class and/or instance property of the window to be set via command line options. Using st for this example as it is easy for demonstration purposes.

Let's say that I have a script or alias that runs the following command to start ncmpcpp in a dedicated terminal.

st -c "thefancyncmpcppterminal" -e ncmpcpp

The -e flag executes the command that follows, i.e. the ncmpcpp program, while the -c flag sets the class of the window.

In the client rule we can now filter on the class of "thefancyncmpcppterminal" and mark that as a scratchpad.

Rule:

	/* class                         instance    title       tags mask     isfloating   monitor    scratch key */
	{ "thefancyncmpcppterminal",     NULL,       NULL,       0,            1,           -1,        'n'  },

Command:

static const char *ncmpcppcmd[] = {"n", "st", "-c", "thefancyncmpcppterminal", "-e", "ncmpcpp", NULL};

Keybindings:

	{ MODKEY,                       XK_n,      togglescratch,  {.v = ncmpcppcmd } },
	{ MODKEY|ShiftMask,             XK_n,      removescratch,  {.v = ncmpcppcmd } },
	{ MODKEY|ControlMask,           XK_n,      setscratch,     {.v = ncmpcppcmd } },

Personally I have found it easier to navigate the keybindings, command and rule if I use the same scratch key ("n") as the dedicated keybinding I am using (XK_n in this case).


The above example is intentionally more elaborate than it needs to be. This because it describes a more generic approach that can be used in more situations.

Quite strictly in this particular case you can get away with a command of:

static const char *ncmpcppcmd[] = {"n", "st", "-e", "ncmpcpp", NULL};

and a rule of:

	/* class    instance    title       tags mask     isfloating   monitor    scratch key */
	{ NULL,     NULL,       "ncmpcpp",  0,            1,           -1,        'n'  },

because the window title will be set to "ncmpcpp" when the terminal starts. That won't always be the case though.

Wow big thanks, I have a last question maybe this is not related, I tried bind st with lf (terminal file manager) as a scratchpad but it doesn't seem to work well, there just pops up a window like flicker.
I don't know if this is a bug in LF or Dwm or even only occurs on my OS (fedora 38), but this bug does not occur in similar utilities such as ranger, have you ever experienced this bug?

For more details, see the following video
simplescreenrecorder.webm

In the screenshot I only see the window title of "lfcd", so presumably you are running something like:
https://github.com/gokcehan/lf/blob/master/etc/lfcd.cmd

What is the command that you have set up?

In general though if you run a command that completes then that will terminate the terminal emulator as well.

E.g. this will run ls and immediately exit because the command finishes.

st -e ls

The same happens if you open a terminal emulator and it starts, say, bash and you run the exit command or press Ctrl+d then the shell process exits and thus the terminal emulator closes as well.

If you want the terminal to stay after the command is run then you will want to spawn a shell, run the command, then exec to another shell again.

st -e "bash" -c "ls; exec bash"

I use lfcd for added functionality so that I can exit the current directory when I exit lf
I've updated it back to lf for testing, I apologize in advance because my scripting skills are still amateur ๐Ÿ˜”

This is the rule script that I apply, I seem to have succeeded in bringing up the scratchpad but it doesn't access lf, it just brings up a regular terminal popup

static const char *lfcmd[] = {"l", "st", "-c", "lf; exec bash", "-e", "bash", NULL};

OK, so I run your command and it brings up a regular terminal.

$ st -c "lf; exec bash" -e "bash"

If I run xprop on that window I get this.

$ xprop | grep WM_CLASS
WM_CLASS(STRING) = "st", "lf; exec bash"

Do you see what is going on?

If you check the man page for st then we have that -e is the last argument, and anything that follows that are arguments for the command.

st ... [[-e] command [arguments...]]

So in your command you are setting the class to "lf; exec bash" because you pass the -c argument to st. If you pass it to the bash command then it works as expected.

$ st -e "bash" -c "lf; exec bash"
static const char *lfcmd[] = {"l", "st", "-e", "bash", "-c", "lf; exec bash", NULL};

now I can access lf, but the toggle function doesn't work, it keeps bringing up a new lf window when toggling, it looks like the rule I applied doesn't work

This is the rule I apply:

static const Rule rules[] = {
	/* xprop(1):
	 *	WM_CLASS(STRING) = instance, class
	 *	WM_NAME(STRING) = title
	 *	_NET_WM_WINDOW_TYPE(ATOM) = wintype
	 *  WM_WINDOW_ROLE(STRING) = role
	 */
	/* class             role             instance  title                wintype,          tags mask  switchtag   isfloating  alwaysontop isterminal noswallow  floatpos                monitor   scratch key */
	{ NULL,              NULL,            NULL,     NULL,                WTYPE "DIALOG",   0,         0,          1,          1,          0,         0,         NULL,                   -1,       0 },
	{ NULL,              NULL,            NULL,     NULL,                WTYPE "UTILITY",  0,         0,          1,          1,          0,         0,         NULL,                   -1,       0 },
	{ NULL,              NULL,            NULL,     NULL,                WTYPE "TOOLBAR",  0,         0,          1,          1,          0,         0,         NULL,                   -1,       0 },
	{ NULL,              NULL,            NULL,     NULL,                WTYPE "SPLASH",   0,         0,          1,          1,          0,         0,         NULL,                   -1,       0 },
	{ "St",              NULL,            NULL,     NULL,                NULL,             0,         0,          0,          0,          1,         0,         NULL,                   -1,       0 },
	{ "firefox",         NULL,            NULL,     NULL,                NULL,             2,         3,          0,          0,          0,         0,         NULL,                   -1,       0 },
	{ "firefox",         "Organizer",     NULL,     NULL,                NULL,             0,         0,          1,          0,          0,         0,         "50% 50% 2000W 1200H",  -1,       0 },
	{ NULL,              "pop-up",        NULL,     NULL,                NULL,             0,         0,          1,          1,          0,         0,         NULL,                   -1,       0 },
	{ NULL,              NULL,            NULL,     "Event Tester",      NULL,             0,         0,          0,          0,          0,         1,         NULL,                   -1,       0 },
	{ NULL,              NULL,            NULL,     "scratchpad",        NULL,             0,         0,          1,          0,          1,         0,         "50% 50% 2000W 1200H",  -1,       's' },
	{ "ncmpcppterm",     NULL,            NULL,     NULL,                NULL,             0,         0,          1,          0,          1,         0,         "50% 50% 2000W 1200H",  -1,       'n' },
	{ "lf; exec bash",   NULL,            NULL,     NULL,                NULL,             0,         0,          1,          0,          1,         0,         "50% 50% 2000W 1200H",  -1,       'l' },
};
simplescreenrecorder.webm

That's a bit funny though, sorry.

{ "lf; exec bash",   NULL,            NULL,     NULL,                NULL,             0,         0,          1,          0,          1,         0,         "50% 50% 2000W 1200H",  -1,       'l' },

^ the class was only like that because you passed the -c argument to st rather than bash.

Without it the class will be the default, e.g. st and instance of St.

You can pass another class to make it easier to identify in your rules. For example:

$ st -c "mylifeisbeautiful" -e "bash" -c "lf; exec bash"

I told you I'm very stupid when it comes to scripts ๐Ÿคฃ, ok now it's working normally, thank you very much for your help, I always look forward to the cool patches that will come to your repository

st -c "mylifeisbeautiful" -e "bash" -c "lf; exec bash"

hey I just noticed my lf preview script doesn't work with this command, how do I make the preview work?

This is the LF script that I implemented for the preview, link1 & link2

In general when a process spawn another process then the new process will inherit the environment variables of the parent process.

When you have, say, dwm spawn a new process then that process will inherit the environment that dwm lives in - and dwm again inherits that from whatever runs dwm, be that startx or a display manager.

As such we have that when spawning a scratchpad in this case the result may be different compared to when running the same command in a terminal because the latter will have more things set up, i.e. the starting conditions will be different.

I don't know exactly what is wrong in your case, but I see that the preview script depends on an environment variable FIFO_UEBERZUG

.config/lf/preview:4:  printf '{"action": "add", "identifier": "PREVIEW", "x": "%s", "y": "%s", "max_width": "%s", "max_height": "%s", "scaler": "contain", "path": "%s"}\n' "$4" "$5" "$(($2-1))" "$(($3-1))" "$1" > "$FIFO_UEBERZUG"

which is exported in bin/lfub

bin/lfub:18:	export FIFO_UEBERZUG="$HOME/.cache/lf/ueberzug-$$"

which in turn is run instead of lf because of this alias:

.zshrc:104:alias lf="lfub"

My guess is that this alias does not exist (we are running bash of course, not zsh) and plain lf is executed instead.

I think that you would need to try a few things, for example executing zsh instead of bash or running /full/path/to/bin/lfub instead of lf. If your bin directory is in your PATH environment variable (for the dwm process mind you) then you may get away with just running lfub.

thanks for the feedback, I think the script above will execute the alias too, in this case "lf=lfub" in my .zshrc, have replaced it with lfub and it works fine