[Implemented in 2.814] Improving dock badge energy efficiency

What no! I just said it should not be much faster than your existing solution - it just hides the CPU usage better :smiley:

But it sounds like it could get all the dock badges at once, or does that one call just end up taking all the CPU that the separate calls would have?

In the end it's also just looping over all of the items, that you could do with your existing script as well.

But let's see. I'll add it, then we can do some more tests :slight_smile:

Ahhh, I see now! Sorry, I was confused. Standing by to test inside BTT! :smile:

1 Like

I think it could be more efficient since the script is ran only once every N seconds, instead of having to do it for each button (like initial Apple Script).

I've made some performances experiments with top -pid $( /Applications/Utils/dock-notification-count > /dev/null & echo $! ) but can't really compare it to previous implementation :

Load Avg: 1.51, 1.91, 2.13  CPU usage: 3.53% user, 3.18% sys, 93.28% idle  SharedLibs: 228M resident, 45M data, 28M linkedit.
MemRegions: 151217 total, 5093M resident, 155M private, 2303M shared. PhysMem: 14G used (3177M wired), 1755M unused.
VM: 2662G vsize, 1298M framework vsize, 3739548(0) swapins, 4244583(0) swapouts.  Networks: packets: 1110609/1837M in, 1670440/1639M out.
Disks: 3592108/56G read, 1569031/39G written.

By the way, @GoldenChaos, when you said "they notoriously hog energy", how were you able to tell it ? By comparing BTT script usage from Activity Monitor with and without script enabled ?

1 Like

When dock badges were first implemented, they were all enabled by default. Users (including myself) suddenly noticed that our systems were getting one hour of battery life and constantly running at ~20-40% CPU at ridiculous temperatures. @Harrumph made a great post with CPU stats to verify: GoldenChaos-BTT Support and Feedback Thread

The underlying code for dock badges hasn't changed since then. We were unable to find a true solution, all we could do is turn on as few dock badges as possible by default, which led to the current default setup of apple-only apps being enabled.

The holy grail, naturally, is being able to support enabling all dock badges at once by default, eliminating the need for user configuration.

Oh okay I see, indeed it was huuuuge CPU and impact on battery !

So after two days of using it, I can confirm that I don't see any negative impact with my implementation. Still have ~8hours battery life, and CPU absolutely not affected (at least < 10% when doing nothing CPU-consuming).

Even if I add a TouchBar button for every app in my Dock, I'm pretty sure it won't affect performances as the only script running in these buttons is fetching the value from the BTT variable.

Could you try actually doing that (enabling every app) and see what happens? I'm curious...

I think it'll be less too, as only one script looks through the whole dock once and spits out a list which we can store somewhere.

Currently every badge digs into there every second, each making a new (request? i don't have professional knowledge here), added the very low efficiency of applescript too.

@AnthoPak, do you have the seperate exec method setup now or did you figure out how to use the one that spits out a list?

@GoldenChaos I've made the try creating a button for each app in my Dock, and as expected, I don't see any difference. Every new button only executes following script, which can't use too much CPU as it only fetch a variable value :

tell application "BetterTouchTool"
	set notificationBadgeApps to get_string_variable "notificationBadgeApps"
end tell

if (notificationBadgeApps contains "Mail") then
	return true
else
	return ""
end if

@yuuiko I'm currently using the implementation I've posted in #22. This is only calling the helper once, and then every button fetch the last response from the helper. So no need to re-run the helper for each button, therefore no performance issues.
The only thing I regret is not having the ability to create buttons on the fly based on helper response, which could be even better. In current implem, I have to create a button for every Dock app, and each one has to update every 10 seconds to see if app name is contained in saved variable.

BUT ! Something just came to my mind (again…), I could use the helper widget, and without saving the result in a var, use update_touch_bar_widget from BTT API to change buttons text, and therefore changing their visibility. This would avoid having each button updates every 10 seconds. I may try this when having some time :slight_smile:

1 Like

Interesting. I guess we’re all just waiting for @Andreas_Hegenberg :wink:

Will try myself sometime soon too.

i’m also eyeing the add_new_trigger function in btt’s documents :thinking:

Okay, I've finally found some time and implemented my above suggestion :smiley:

Works really well ! Only one script for an infinite number of apps :wink:
I even tried setting the refreshing time to 0.1s and don't see any performance issue, no difference in CPU usage :smiley: But of course 0.1 is useless, I'll stick with ~2s I think.
(EDIT : in fact i've just noticed that with 0.1s I got BetterTouchToolAppleScriptRunner going to ~5% CPU, whereas it almost always < 1% with 2s. But this performance change may mostly be related to widget update)

So basically, here is the process :

  • Create a widget for each app we want (in fact a button could be sufficient, but update_touch_bar_widget is, as it name suggests, made for widgets and not for classic buttons). I've set the refresh time of these widgets to 10000 (as I don't want them to refresh themselves)
  • Copy the UDID for every button, and add it to following helper widget script
  • Create the AppleScript helper widget that will update each button when needed, and this script :

UpdateDockBadgesButtons.scpt :

set udidRecords to {Mail:"EE7C0AF6-8406-4278-879F-593CFBCD1000", Messages:"0ECB327C-0CC9-4C12-B300-1BC7210F74B9", Franz:"7E02811B-73E3-458E-967A-9DFD11D101DB"} --All UDIDs from BTT widgets for apps that you are interested in notifications badges

set notificationBadgeApps to (do shell script "/Applications/Utils/dock-notification-count")

-- Can't make a loop here since I can't find a way to fetch records from udidRecords with variable…
checkAndUpdateCurrentBadgeStatusForApp("Mail", notificationBadgeApps, (get Mail of udidRecords))
checkAndUpdateCurrentBadgeStatusForApp("Messages", notificationBadgeApps, (get Messages of udidRecords))
checkAndUpdateCurrentBadgeStatusForApp("Franz", notificationBadgeApps, (get Franz of udidRecords))

return "" --hidden helper widget



on checkAndUpdateCurrentBadgeStatusForApp(appName, notificationBadgeApps, udid)
	if notificationBadgeApps contains appName then
		updateButtonWithUDID(udid, "show") --here we can try fetching badges count from notificationBadgeApps if we are interested in getting badge count, and replace true with count
	else
		updateButtonWithUDID(udid, "") --hide button
	end if
end checkAndUpdateCurrentBadgeStatusForApp


on updateButtonWithUDID(udidToUpdate, newText)
	tell application "BetterTouchTool"
		update_touch_bar_widget udidToUpdate text newText
	end tell
end updateButtonWithUDID

Still, creating buttons on the fly will be even better so we won't have to deal with UDIDs, but I've also looked into add_new_trigger and I don't think it could create a button. This could definitely be a great new feature.

1 Like

Personally I don't mind making a bunch of badges for every app, though being able to create and remove "virtual" buttons on-the-fly is something I've wanted for a while and would make the reminders/calendar/browser tabs groups behave a lot nicer. I might make a separate thread to request this feature, I know it's come up in the past and add_new_trigger isn't a good option for this because it creates permanent buttons.

@Andreas_Hegenberg any updates on this? :slight_smile:

@GoldenChaos @yuuiko
Next alpha later today will have a new apple script function that can be used like this:

tell application "BetterTouchTool"
	get_dock_badge_for "Calendar" update_interval 5
end tell

When an update interval is provided, BTT will internally refresh the badges for all apps every x seconds. In this case the "get_dock_badge_for" function calls are basically free, as they will just return the last cached value. This is the recommended way to do it, and the update_interval should not be too small.

If you need to refresh the cache immediately for some reason, you can leave the update_interval function out. Then BTT will immediately refresh all the dock badges and return the latest value.

tell application "BetterTouchTool"
	get_dock_badge_for "Calendar"
end tell

Instead of the app name you can also use its url (to make it independent from any language), e.g. file:///Applications/Google%20Chrome.app/

1 Like

Hope this works!!

Will these have a “don’t show when DND ON” function?

Otherwise a dnd variable would be great. A couple of my users are struggling with the badges always hiding and i’m not sure what’s causing it

The function just returns the current dock badge number for the requested app efficiently, what you do with it is up to you :slight_smile:

Ok, just added a variable for that. It's available via "SystemDoNotDisturbState" as a number variable.

how does it sense dnd? just curious :wink:

It reads the user defaults of the notificationcenterui

NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.notificationcenterui"];
BOOL dnd = [defaults boolForKey:@"doNotDisturb"];
1 Like