Linux StatusNotifierItem hosts redraw the whole tray item on every Tray.setImage(), so cycling the 16 progress-animation frames made the icon flicker between a full and a partial ring. Show a single static running icon on Linux; Windows/macOS keep the animation. Also re-render the static stopped/running icons (light+dark, @2x) from vector sources at 24/48px so GNOME no longer upscales a 16px source.
|
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 635 B |
|
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 240 B After Width: | Height: | Size: 614 B |
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 307 B After Width: | Height: | Size: 650 B |
|
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 627 B |
|
Before Width: | Height: | Size: 530 B After Width: | Height: | Size: 1.3 KiB |
|
|
@ -251,15 +251,50 @@ test('initIndicator uses NativeImage for Linux tray creation and updates', () =>
|
|||
undefined,
|
||||
);
|
||||
|
||||
// On Linux the running icon stays static (no progress-animation frames) to
|
||||
// avoid StatusNotifierItem flicker (#4905).
|
||||
assert.equal(traySetImageCalls.at(-1).kind, 'native-image');
|
||||
assert.match(
|
||||
traySetImageCalls.at(-1).iconPath,
|
||||
/\/icons\/indicator\/running-anim-d\/3\.png$/,
|
||||
/\/icons\/indicator\/running-d\.png$/,
|
||||
);
|
||||
|
||||
beforeQuitHandler();
|
||||
});
|
||||
|
||||
test('non-Linux platforms keep the running progress animation', () => {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
configurable: true,
|
||||
value: 'darwin',
|
||||
});
|
||||
const { initIndicator } = loadIndicatorModule();
|
||||
|
||||
initIndicator({
|
||||
showApp: () => {},
|
||||
quitApp: () => {},
|
||||
ICONS_FOLDER: '/icons/',
|
||||
forceDarkTray: false,
|
||||
app: { on: () => {} },
|
||||
});
|
||||
|
||||
const currentTaskUpdated = ipcHandlers.get('CURRENT_TASK_UPDATED');
|
||||
currentTaskUpdated(
|
||||
{},
|
||||
{ id: 'T1', title: 'Task', timeSpent: 5 * 60000, timeEstimate: 25 * 60000 },
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
undefined,
|
||||
);
|
||||
|
||||
// macOS uses the black (`-l`) template icon and still animates progress.
|
||||
assert.match(
|
||||
traySetImageCalls.at(-1).iconPath,
|
||||
/\/icons\/indicator\/running-anim-l\/3\.png$/,
|
||||
);
|
||||
});
|
||||
|
||||
test('initIndicator falls back to icon path if NativeImage creation is empty', () => {
|
||||
nextNativeImageIsEmpty = true;
|
||||
const { initIndicator } = loadIndicatorModule();
|
||||
|
|
|
|||
|
|
@ -559,7 +559,12 @@ function createContextMenu(msg?: string): Menu {
|
|||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
function getRunningIconPath(progress?: number): string {
|
||||
const suf = shouldUseDarkColors ? '-d' : '-l';
|
||||
if (typeof progress === 'number' && progress > 0 && isFinite(progress)) {
|
||||
// Linux StatusNotifierItem hosts redraw the whole tray item on every
|
||||
// Tray.setImage(); cycling through the 16 progress-animation frames makes the
|
||||
// icon visibly flicker between a full and a partial ring (#4905). Show a single
|
||||
// static running icon there instead — elapsed/remaining time still shows in the
|
||||
// tray context-menu label (and the title/OS taskbar where the host supports it).
|
||||
if (!IS_LINUX && typeof progress === 'number' && progress > 0 && isFinite(progress)) {
|
||||
const f = Math.min(Math.round(progress * 15), 15);
|
||||
return DIR + `running-anim${suf}/${f || 0}.png`;
|
||||
}
|
||||
|
|
|
|||