New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set foreground object rather than desktop object when initializing object cache #14301
Conversation
d072829
to
22eff08
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, happy with the approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetForegroundWindow will have to continuously polled to ensure it is not NULL. This polling should be allowed to take as long as it needs... E.g. 10, 20 seconds... the setting of these objects can not fail.
Though this situation is extremely rare, and most likely will correct itself within a second or two.
23effc4
to
ba8c418
Compare
See test results for failed build of commit dbca3e5488 |
source/core.py
Outdated
foregroundHWND = winUser.getForegroundWindow() | ||
_hasWarned = False | ||
WARN_AFTER_SECS = 5 | ||
MAX_WAIT_TIME_SECS = 20 | ||
POLL_INTERVAL_SECS = 0.1 | ||
waitForForegroundHWND_startTime = time.time() | ||
|
||
while not foregroundHWND: | ||
# The foreground window can be NULL in certain circumstances, | ||
# such as when a window is losing activation. | ||
# This should not remain the case for an extended period of time. | ||
|
||
_timeElapsed = time.time() - waitForForegroundHWND_startTime | ||
if ( | ||
not _hasWarned | ||
and _timeElapsed > WARN_AFTER_SECS | ||
): | ||
_hasWarned = True | ||
# Allow for braille / speech to be understood before exiting. | ||
# Unfortunately we cannot block with a dialog as NVDA cannot read dialogs yet. | ||
ui.message(_( | ||
# Translators: Message when NVDA is having an issue starting up | ||
"NVDA is failing to fetch the foreground window. " | ||
"If this continues, NVDA will quit starting in %d seconds." % (MAX_WAIT_TIME_SECS - WARN_AFTER_SECS) | ||
)) | ||
|
||
if _timeElapsed > MAX_WAIT_TIME_SECS: | ||
log.critical("NVDA could not fetch the foreground window. Exiting NVDA.") | ||
# Raising exception here causes core.main to exit and NVDA to fail to start | ||
raise NVDANotInitializedError("Could not fetch foreground window") | ||
|
||
log.debugWarning("Foreground window not found, fetching again") | ||
time.sleep(POLL_INTERVAL_SECS) | ||
foregroundHWND = winUser.getForegroundWindow() | ||
|
||
return foregroundHWND |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like I didn't hit submit on this comment.
I want to make sure all the paths here are tested. Doing so manually will be difficult. I think this could be easier to read and unit testable if the polling algorithm was decoupled from the condition and outcomes.
Suggestion:
# The foreground window can be NULL in certain circumstances,
# such as when a window is losing activation.
# This should not remain the case for an extended period of time.
WARN_AFTER_SECS = 5
MAX_WAIT_TIME_SECS = 20
POLL_INTERVAL_SECS = 0.1
success, foregroundHWND = pollForCondition(
condition=lambda: bool(winUser.getForegroundWindow()),
maxWait=WARN_AFTER_SECS,
intervalSeconds=POLL_INTERVAL_SECS
)
if not success:
ui.message(_(
# Translators: Message when NVDA is having an issue starting up
"NVDA is failing to fetch the foreground window. "
"If this continues, NVDA will quit starting in %d seconds." % (MAX_WAIT_TIME_SECS - WARN_AFTER_SECS)
))
success, foregroundHWND = pollForCondition(
condition=lambda: bool(winUser.getForegroundWindow()),
maxWait=MAX_WAIT_TIME_SECS - WARN_AFTER_SECS,
intervalSeconds=POLL_INTERVAL_SECS
)
if not success:
log.critical("NVDA could not fetch the foreground window. Exiting NVDA.")
# Raising exception here causes core.main to exit and NVDA to fail to start
raise NVDANotInitializedError("Could not fetch foreground window")
return foregroundHWND
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have implemented something similar
See test results for failed build of commit c7522f8c27 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rewritten the testing suite
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good @seanbudd
Summary of the issue: #14301 moved an api import from core.main as it was otherwise unused #14050 introduced a usage of api to core.main to beta This means that api was used without being imported on beta and master. Description of user facing changes None Description of development approach Fix import error
Summary of the issue: During NVDA initialization, the api module is used to set initial object caches. These api functions check if an object is behind the lock screen when Windows is locked before setting the cache. Until #14301, the api module initialised the object caches to the desktop object. When NVDA started on the lock screen, it failed to set the desktop object due to the added security checks. Now the object caches are initialised to the foreground window, to avoid leaking insecure information. Unfortunately, setting those object caches causes side-effects, which may rely on uninitialized dependencies. Description of user facing changes None Description of development approach Revert to setting initial object caches to the desktop object. Ensure security failures are not raised when initialising caches by ignoring the windows lock state.
Summary of the issue: Due to intermittent system test failures, #14284 increased the polling interval used in blockUntilConditionMet. When writing unit tests for blockUntilConditionMet in #14301, a bug was picked up. This bug caused blockUntilConditionMet to spin for longer than expected and potentially caused system tests to fail. This bug was fixed with a new implementation of blockUntilConditionMet. Description of user facing changes For devs, system tests should be faster (todo: estimate from build?) Description of development approach Lower default polling interval
Link to issue number:
None
Summary of the issue:
This regression was introduced in 2022.3.1
If NVDA starts on the lock screen (such as when starting your device), NVDA fails to cache the desktop object as the focus object, mouse object, etc. as it is from below the lock screen.
This causes NVDA to not function correctly after sign-in, such as the inability to use
nvda+q
.Description of user facing changes
Fixes severe regression with using NVDA after sign-in, if NVDA starts on the lock screen.
Description of development approach
Cache the foreground window when NVDA starts up, rather than the desktop object.
This window should be accessible from the lock screen when NVDA starts on the lock screen.
The
setDesktopObject
should continue to cached the desktop object as usual, as security code has not been implemented to prevent this from being set to insecure objects.Creates a generic function
blockUntilConditionMet
, to wait for the foreground window to be fetched successfully.Unit testing discovered a bug with the system test implementation of
blockUntilConditionMet
. This has now been fixed.Testing strategy:
Using a try build tested the following steps:
nvda+q
opens the quit dialog)Unit tests have been added for
blockUntilConditionMet
.Known issues with pull request:
None
Change log entries:
Code Review Checklist: