Repository: nvaccess/nvda

Issue:
NVDA throws a lot of errors during opening IntelliJ IDEA
### Steps to reproduce:
1. Go to jetbrains.com/idea to download and install IntelliJ IDEA Community Edition 2021.2.3;
2. After installation, follow the default settings and create a new project arbitrarily;
3. Exit IntelliJ IDEA;
4. Open IntelliJ IDEA again, it will take a while to load, press Windows + M to minimize to the desktop during this time;

### Actual behavior:
During the execution of step (4), you will receive a large number of errors from NVDA when you minimize to the desktop. The log snippet is as follows:

```
ERROR - queueHandler.flushQueue (09:19:24.473) - MainThread (16392):
Error in func event_stateChange
Traceback (most recent call last):
  File "queueHandler.pyc", line 55, in flushQueue
  File "JABHandler.pyc", line 709, in event_stateChange
  File "NVDAObjects\__init__.pyc", line 85, in __call__
  File "NVDAObjects\JAB\__init__.pyc", line 231, in __init__
  File "NVDAObjects\window\__init__.pyc", line 167, in __init__
ValueError: invalid or not specified window handle
```

IntelliJ IDEA will be opened after you receive dozens of errors.
### Expected behavior:
NVDA has no error messages and IntelliJ IDEA should open smoothly,.

### System configuration
#### NVDA installed/portable/running from source:
installed and portable

#### NVDA version:
NVDA2021.3 Beta2

#### Windows version:
Windows 10 21H1 (x64) build 19043.1288

#### Name and version of other software in use when reproducing the issue:
IntelliJ IDEA Community Edition 2021.2.3

#### Other information about your system:

- CPU: Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz 1.90 GHz
- RAM: 16.0 GB
- Disk: 512 GB SSD

### Other questions
#### Does the issue still occur after restarting your computer?
Yes
#### Have you tried any other versions of NVDA? If so, please report their behaviors.
The latest Alpha version can also be reproduced

#### If NVDA add-ons are disabled, is your problem still occurring?
Yes
#### Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?
Yes


Discussion:

Resolving patch:
diff --git a/source/JABHandler.py b/source/JABHandler.py
--- a/source/JABHandler.py
+++ b/source/JABHandler.py
@@ -691,47 +691,50 @@ def internal_hasFocus(sourceContext):
 	focus = api.getFocusObject()
 	if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == sourceContext:
 		return True
-	ancestors = api.getFocusAncestors()
-	for ancestor in reversed(ancestors):
-		if isinstance(ancestor, NVDAObjects.JAB.JAB) and ancestor.jabContext == sourceContext:
-			return True
-	return False
+	ancestors = reversed(api.getFocusAncestors())
+	return any((isinstance(x, NVDAObjects.JAB.JAB) and x.jabContext == sourceContext for x in ancestors))
 
 
 @AccessBridge_PropertyNameChangeFP
 def event_nameChange(vmID,event,source,oldVal,newVal):
-	jabContext=JABContext(vmID=vmID,accContext=source)
-	focus=api.getFocusObject()
-	if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext:
-		obj = focus
+	jabContext = JABContext(vmID=vmID, accContext=source)
+	if jabContext.hwnd:
+		focus = api.getFocusObject()
+		obj = focus if (
+			isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext
+		) else NVDAObjects.JAB.JAB(jabContext=jabContext)
+		if obj:
+			eventHandler.queueEvent("nameChange", obj)
 	else:
-		obj = NVDAObjects.JAB.JAB(jabContext=jabContext)
-	if obj:
-		eventHandler.queueEvent("nameChange", obj)
+		log.debugWarning("Unable to obtain window handle for accessible context")
 	bridgeDll.releaseJavaObject(vmID,event)
 
 @AccessBridge_PropertyDescriptionChangeFP
 def event_descriptionChange(vmID,event,source,oldVal,newVal):
-	jabContext=JABContext(vmID=vmID,accContext=source)
-	focus=api.getFocusObject()
-	if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext:
-		obj = focus
+	jabContext = JABContext(vmID=vmID, accContext=source)
+	if jabContext.hwnd:
+		focus = api.getFocusObject()
+		obj = focus if (
+			isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext
+		) else NVDAObjects.JAB.JAB(jabContext=jabContext)
+		if obj:
+			eventHandler.queueEvent("descriptionChange", obj)
 	else:
-		obj = NVDAObjects.JAB.JAB(jabContext=jabContext)
-	if obj:
-		eventHandler.queueEvent("descriptionChange", obj)
+		log.debugWarning("Unable to obtain window handle for accessible context")
 	bridgeDll.releaseJavaObject(vmID,event)
 
 @AccessBridge_PropertyValueChangeFP
 def event_valueChange(vmID,event,source,oldVal,newVal):
-	jabContext=JABContext(vmID=vmID,accContext=source)
-	focus=api.getFocusObject()
-	if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext:
-		obj = focus
+	jabContext = JABContext(vmID=vmID, accContext=source)
+	if jabContext.hwnd:
+		focus = api.getFocusObject()
+		obj = focus if (
+			isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext
+		) else NVDAObjects.JAB.JAB(jabContext=jabContext)
+		if obj:
+			eventHandler.queueEvent("valueChange", obj)
 	else:
-		obj = NVDAObjects.JAB.JAB(jabContext=jabContext)
-	if obj:
-		eventHandler.queueEvent("valueChange", obj)
+		log.debugWarning("Unable to obtain window handle for accessible context")
 	bridgeDll.releaseJavaObject(vmID,event)
 
 @AccessBridge_PropertyStateChangeFP
@@ -740,24 +743,25 @@ def internal_event_stateChange(vmID,event,source,oldState,newState):
 	bridgeDll.releaseJavaObject(vmID,event)
 
 def event_stateChange(vmID,accContext,oldState,newState):
-	jabContext=JABContext(vmID=vmID,accContext=accContext)
-	focus=api.getFocusObject()
+	jabContext = JABContext(vmID=vmID, accContext=accContext)
+	if not jabContext.hwnd:
+		log.debugWarning("Unable to obtain window handle for accessible context")
+		return
+	focus = api.getFocusObject()
 	#For broken tabs and menus, we need to watch for things being selected and pretend its a focus change
-	stateList=newState.split(',')
+	stateList = newState.split(',')
 	if "focused" in stateList or "selected" in stateList:
-		obj=NVDAObjects.JAB.JAB(jabContext=jabContext)
+		obj = NVDAObjects.JAB.JAB(jabContext=jabContext)
 		if not obj:
 			return
 		if focus!=obj and eventHandler.lastQueuedFocusObject!=obj and obj.role in (controlTypes.Role.MENUITEM,controlTypes.Role.TAB,controlTypes.Role.MENU):
 			eventHandler.queueEvent("gainFocus",obj)
 			return
-	if isinstance(focus,NVDAObjects.JAB.JAB) and focus.jabContext==jabContext:
-		obj=focus
-	else:
-		obj=NVDAObjects.JAB.JAB(jabContext=jabContext)
-		if not obj:
-			return
-	eventHandler.queueEvent("stateChange",obj)
+	obj = focus if (
+		isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext
+	) else NVDAObjects.JAB.JAB(jabContext=jabContext)
+	if obj:
+		eventHandler.queueEvent("stateChange", obj)
 
 @AccessBridge_PropertyCaretChangeFP
 def internal_event_caretChange(vmID, event,source,oldPos,newPos):
@@ -770,14 +774,16 @@ def internal_event_caretChange(vmID, event,source,oldPos,newPos):
 
 def event_caret(vmID, accContext, hwnd):
 	jabContext = JABContext(hwnd=hwnd, vmID=vmID, accContext=accContext)
-	focus = api.getFocusObject()
-	if isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext:
-		obj = focus
+	if jabContext.hwnd:
+		focus = api.getFocusObject()
+		obj = focus if (
+			isinstance(focus, NVDAObjects.JAB.JAB) and focus.jabContext == jabContext
+		) else NVDAObjects.JAB.JAB(jabContext=jabContext)
+		if obj:
+			eventHandler.queueEvent("caret", obj)
 	else:
-		obj = NVDAObjects.JAB.JAB(jabContext=jabContext)
-		if not obj:
-			return
-	eventHandler.queueEvent("caret", obj)
+		log.debugWarning("Unable to obtain window handle for accessible context")
+
 
 def event_enterJavaWindow(hwnd):
 	internalQueueFunction(enterJavaWindow_helper,hwnd)


Test patch: