swiftbar / SwiftBar

Powerful macOS menu bar customization tool
https://swiftbar.app
MIT License
2.93k stars 92 forks source link

Update menu right when needed, rather than periodically #241

Closed fabiospampinato closed 2 years ago

fabiospampinato commented 2 years ago

Is it possible to update the menu right when the menubar item is clicked rather than periodically?

An example use case: I'd like to have something that lists all ejectable drives, so that I can eject them from there, the problem is I want the list to be up-to-date when I click on it, or it may show me old drives or not show me new ones, but I also don't want to update the menu every second as that would be wasteful since most seconds I won't be using that menu.

Is this implementable?

melonamin commented 2 years ago

Can you give me your eject drive script? I'll use it to test if this is reasonably doable

fabiospampinato commented 2 years ago

I haven't written it yet, I had an alfred workflow for doing that that I'd like to migrate to SwiftBar potentially.

For what is worth this is the code inside that workflow:

/* IMPORT */

const fs = require ( 'fs' ),
      ls = require ( 'ls' ),
      njds = require ( 'nodejs-disks' );

/* LIST */

const list = { items: [] },
      volumes = ls ( '/Volumes/*' );

njds.drives ( ( err, drives ) => {

  njds.drivesDetail ( drives, ( err, data ) => {

    for ( let {mountpoint, drive} of data ) {

      if ( !/^\/Volumes\//.test ( mountpoint ) ) continue;
      if ( /^\/Volumes\/BOOTCAMP/.test ( mountpoint ) ) continue;

      const volume = volumes.find ( volume => volume.full.startsWith ( mountpoint ) );

      if ( !volume ) continue;

      const pathParts = drive.match ( /(\/dev\/disk\d+)s\d+/ );

      list.items.push ({
        title: volume.name,
        arg: pathParts[1]
      });

    }

    fs.writeFileSync ( 'list.json', JSON.stringify ( list, undefined, 2 ) );

  });

});
melonamin commented 2 years ago

That will do, let me explore.

fabiospampinato commented 2 years ago

A simpler similar use case may just be having the current time with seconds in the menu, you want it to be accurate but you don't want to update it every second.

fabiospampinato commented 2 years ago

Coincidentally I have this issue also with a desktop app of mine, the menu is highly dynamic so it gets updated very often, but most of the times that's just performance thrown out of the window as the user isn't going to open the menu before it changes again.

If you can find a way to provide macOS with a "just in time" menu I'd be very interested in applying that to the desktop app as well.

melonamin commented 2 years ago

A simpler similar use case may just be having the current time with seconds in the menu, you want it to be accurate but you don't want to update it every second.

This is not a good test in case of SwiftBar. Currently menu updates as a whole, I don't track individual menu items and adding this would explode the complexity.

I've added a naive implementation - SwiftBar runs the script right after you click and before showing the menu, if script running long it adds an indicator next to the menubar item. It should work just fine in case of "lists all ejectable drives" plugin.

Check out the beta

xilopaint commented 2 years ago

Check out the beta

Please, add the application file to the releases page.

melonamin commented 2 years ago

done