Skip to content

Foobar2000: implement a custom status bar routine to fix playback status commands#11087

Closed
josephsl wants to merge 6 commits into
nvaccess:masterfrom
josephsl:i11082foobar2000StatusBar
Closed

Foobar2000: implement a custom status bar routine to fix playback status commands#11087
josephsl wants to merge 6 commits into
nvaccess:masterfrom
josephsl:i11082foobar2000StatusBar

Conversation

@josephsl

@josephsl josephsl commented May 1, 2020

Copy link
Copy Markdown
Contributor

Hi,

This is a follow-up to #9792:

Link to issue number:

Fixes #11082

Summary of the issue:

In Foobar2000 with NVDA alpha.20080 and later (with custom status bar commit), NVDA says 'no track playing" when trying to obtain elpased time, total time, and remaining time for a playing track.

Description of how this pull request fixes the issue:

Implemented a custom status bar fetcher for Foobar2000 that uses windowUtils.findDescendentWindow to retrieve the status bar for the foreground object.

Testing performed:

Tested with Foobar2000 with latest alpha and with app module changes applied through this PR.

Known issues with pull request:

None

Change log entry:

None, as it is a follow-up to a change in alpha

josephsl added 3 commits May 1, 2020 16:07
… errors when obtaining playing duration. Re nvaccess#11082.

NVDA now lets app module classes define customer retriever for status bars. However, Foobar2000 uses 'statusBar' as a variable name, causing status bar retriever to fail. This leads to NVDA announcing 'no track is playing' when trying to obtain track information (elapsed time, for example). This is now resolved by defining Foobar2000 specific status bar retriever, utilizing windowUtils.findDescendantWindow and returning the resulting status bar object if one is found.
@JulienCochuyt

Copy link
Copy Markdown
Contributor

All apologies for missing this impact.

@josephsl,
Thanks for taking care of cleaning my mess.
While renaming the statusBar attribute in appModules.fooBar2000.AppModule to something like statusBarObj would have been enough to fix #11082, I understand how your approach is more efficient than the default api.getStatusBar.
Still, I would advocate for the following changes to this PR:

  • Add a comment clarifying that the technique used is not a replacement for the failing standard one, but rather an optimization.
  • Fallback to raising NotImplementedError rather than returning None: This way, if a foobar2000 plug-in displays a status bar which does not have the class name "ATL:msctls_statusbar32", its content could still be read. Or do you know for sure such a scenario is unlikely to happen? (I'm only a seldom user of foobar2000, and unaware of the diversity of its plug-ins.)

@josephsl

josephsl commented May 2, 2020 via email

Copy link
Copy Markdown
Contributor Author

@lukaszgo1 lukaszgo1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly worried about performance here. Previously the status bar object was fetched once and then stored as an attribute of the appModule instance, whereas now it is fetched each time when one of the time requesting scripts is executed

Comment thread source/appModules/foobar2000.py Outdated
# Copyright (C) 2009-2018 NV Access Limited, Aleksey Sadovoy, James Teh, Joseph Lee, Tuukka Ojala
# Copyright (C) 2009-2020 NV Access Limited, Aleksey Sadovoy, James Teh, Joseph Lee, Tuukka Ojala
# This file may be used under the terms of the GNU General Public License, version 2 or later.
# For more details see: https://www.gnu.org/licenses/gpl-2.0.htmlimport appModuleHandler

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clean-up this line while at it?

@josephsl

josephsl commented May 2, 2020

Copy link
Copy Markdown
Contributor Author

Hi,

Copyright header: I need cleanup reasons, as all I did there is update the copyright header (we will need to go through files again to do copyright header management at some point).

As for performance and previous implementation: it was done that way for consistency with what Julian wrote.

There is an issue that was present in old and current implementations that will require a separate PR to fix: NVDA will get wrong status bar if something other than the playlist gets focused when NVDA starts. This is caused by gain focus event caching the "active" status bar from anywhere as long as status bar isn't defined. The ideal solution is either using Foobar2000 API to announce playback time, or locating the status bar object from Foobar2000's main window handle. Resolving that issue means there is no need for this PR, or better yet, modifying the PR to account for changes introduced in recent alpha snapshots along with a better solution for #11082.

Thanks.

@lukaszgo1

Copy link
Copy Markdown
Contributor

The line says:
# For more details see: https://www.gnu.org/licenses/gpl-2.0.htmlimport appModuleHandler

I don't think import appModuleHandler should be there :-)

@josephsl

josephsl commented May 2, 2020 via email

Copy link
Copy Markdown
Contributor Author

Comment thread source/appModules/foobar2000.py
@josephsl

josephsl commented May 4, 2020 via email

Copy link
Copy Markdown
Contributor Author

@AppVeyorBot

Copy link
Copy Markdown

See test results for failed build of commit abd6889864


def _get_statusBar(self):
# #11082: retrieve status bar handle and resulting NVDA object from playlist window.
# If only default status bar routine is used to assign status bar object,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean that calling api.getStatusBar() from here leads to a recursion error? That's true, and was a concern when reviewing #9792. In the end I decided that any future work could split that function to break the recursion.

This is really a tangent to what I was trying to ask. The way that this works is different from api.getStatusBar(), is there a reason? In api.getStatusBar() we hit test 1 pixel up from the bottom of the foreground object and walk up the tree looking for the statusbar role. This implementation enumerates all child windows of the ForegroundObject looking for this particular class name.

@josephsl

josephsl commented May 7, 2020 via email

Copy link
Copy Markdown
Contributor Author

@feerrenrut

Copy link
Copy Markdown
Contributor

and to better detect status bar from main window

But can you explain why this approach is better?

@josephsl

josephsl commented May 8, 2020

Copy link
Copy Markdown
Contributor Author

Hi,

The biggest advantage is looking at status bar that is located somewhere other than bottom left. So far, Foobar2000 does not exhibit this (I know several apps such as GoldWave that exhibit this case).

After thinking about this, I think it would be best to go with renaming the attribute (option 1) due to 2020.2 beta preparation. I'll submit a different PR that should resolve this (and an advice for future committers: when adding or changing class attributes, be sure to check everywhere in the source code (or relevant sections) to make sure this kind of regression is minimized).

Thanks.

@josephsl josephsl closed this May 8, 2020
@josephsl josephsl deleted the i11082foobar2000StatusBar branch May 8, 2020 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Alpha-20080 has broken NVDA's time-oriented functions in Foobar2000

5 participants