matryer / xbar

Put the output from any script or program into your macOS Menu Bar (the BitBar reboot)
https://xbarapp.com
MIT License
17.5k stars 642 forks source link

How to detect initial plugin loading #738

Open mlcampbe opened 3 years ago

mlcampbe commented 3 years ago

This is a follow up to https://github.com/matryer/xbar/issues/88 where I am trying to figure how to do some plugin initialization when the plugin is first loaded.

For example, when the plugin is first loaded I want to set the icon and menu dropdown text. Subsequent refreshes should not need to rebuild the icon/menu unless I detect that something has changed. For example.

1 - On initial load I want to set an icon to green 2 - On all subsequent refreshes I will retrieve some values to check if they have changed since the last execution. If there is no change then I just want to exit and leave the icon/menu the same. 3 - But if I detect changes I need to set the icon to red and change the menu text.

I've read the docs about plugin variables and I can read those but it appears they get reset each time the script executes and I don't see how to change them after the initial load. I also see something about xbar.config.json but it does not seem that anything I put into there is ever made available to my script.

Any ideas?

matryer commented 3 years ago

Hi @mlcampbe some people save a little file somewhere, and check for its existence to decide whether the plugin has been run before or not. xbar currently doesn't have a way to indicate that this is the first time a plugin has been run. Does that help?

mlcampbe commented 3 years ago

The problem with a "little file somewhere" is that it would be created the first time a plugin is ever loaded/run but that file would remain after xbar quits or the machine is restarted, etc.... therefore that can't be used to do plugin initialization for subsequent xbar startups.

I did do some tinkering last night and actually got something that did work as I had hoped. Ultimately that still did not help me though. I was under the assumption that if the script didn't print any output at all that the menu bar icon would not change and the menu details would not change either. However, it seems if the script produces no output it wipes out the menu portion which defeats my purpose. If you could somehow build a fix such that if the script sends no output that nothing is changed in the current display that would be great.

As for my fix I am using a bash script. In bash is the concept of the "parent PID" which is referenced by $PPID. Therefore when a script is run if you check the $PPID value it will be the pid of the xbar process itself since that is the parent to the script. Since xbar will get a new PID everytime it is run the $PPID value will be different as well. However, as long as xbar is not exited then $PPID will return the same value everytime the script is run. You can do something like this:

statusFile="/tmp/xbar-docked-status.$PPID"
if [ ! -f "${statusFile}" ]; then
  echo "isDocked=unknown" > ${statusFile}
  echo ":computer:"
  echo "---"
  echo "first line of menu"
  exit
else
  do real work here
fi

Here the statusFile variable will change everytime the xbar app is run and thus you can 1-time initializations (for example to build the icon and menu). The subsequent refreshes will see the statusFile exists since the $PPID is still the actual xbar app and skip to the "else" section to do the real work.

If the script refreshes produce no output I had hoped to avoid the overhead of rebuilding the icon & menu since nothing had changed. Unfortunately that wiped out my menu though and really negated the need to determine if it was the initial load of the plugin or not. If that was fixed I think this option might save some CPU cycles.

lasar commented 3 years ago

You could update the little tmp file every time your script runs. Then on the next run (or "next first run") you can check if the previous run was a minute ago or a day and act accordingly.

As for rebuilding the menu, that's a requirement at the moment, I think. If generating the full menu is CPU-intensive you could save the previous version in a file (perhaps the same tmp file discussed above) and just read it from there unless changes need to be made.

leaanthony commented 3 years ago

This is an interesting idea though, passing state back to the plugin.... if i'm not mistaken it would be backwards compatible as the args would be ignored by default

matryer commented 3 years ago

I'm not against adding XBAR_IS_FIRST_RUN_TODAY environment variable to indicate that it's the first time it's being run today (or, since the last restart). @leaanthony What do you think?

leaanthony commented 3 years ago

It's unclear to me if the requirement is first time of the day or first time whilst running.

lavgup commented 3 years ago

I'm currently in need of finding out whether it's the first run of the day. An environment variable for that would be fabulous.