Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 15559

Summary: JAWS reads the parent window for dialog shells
Product: [Eclipse Project] Platform Reporter: Tod Creasey <Tod_Creasey>
Component: SWTAssignee: Veronika Irvine <veronika_irvine>
Status: RESOLVED FIXED QA Contact:
Severity: major    
Priority: P3 Keywords: accessibility, helpwanted
Version: 2.0   
Target Milestone: 2.0.1   
Hardware: PC   
OS: Windows 2000   
Whiteboard:
Bug Depends on:    
Bug Blocks: 15320, 15576, 20563    

Description Tod Creasey CLA 2002-05-08 13:42:34 EDT
JAWS has a feature that allows you to read the contents of a message box. If a 
message box pops you can hit Ins+B and it will read all of the widgets in the 
box.

In the Eclipse UI MessageBox (a window with a modal shell) this feature will 
read the contents of the window parenting the dialog rather than the dialog.

In other applications (like the Word Detect and Repair dialog) this will read 
all of the widgets in the dialog.
Comment 1 Nick Edgar CLA 2002-05-09 16:19:38 EDT
This is important for M6.
Comment 2 Randy Hudson CLA 2002-05-11 09:03:10 EDT
Isn't this the same as 15320?
Comment 3 Carolyn MacLeod CLA 2002-05-21 00:31:43 EDT
Deferred to fix pass 1
Comment 4 Tod Creasey CLA 2002-05-30 08:09:27 EDT
Using JAWS it is possible to read the dialog using the JAWS cursor (-) so it is 
not unreadable. The Ins+B functionality is an extra feature that we do not 
currently support that we should consider for later releases. It would likely 
require some sort of discussion with Freedom Scientific (the makers of JAWS).

What it is currently reading is the parent shell (the window) of the dialog - 
special support is required to read a dialog that is not a Windows system 
dialog.

If this change is to wide reaching and not a general solution this should be 
considered for a later release when we can get support specifically from 
Freedom Scientific for this function.
Comment 5 Carolyn MacLeod CLA 2002-05-30 17:35:48 EDT
Pasting the SWT code hacks into here so they are not lost.
Hacks are:
1) in Display
- add field TCHAR windowClass2
- in the init() method, after registering the "SWT_Window" windowClass, do this:
	// ===== TEMPORARY CODE - register a different window class for dialogs
	windowClass2 = new TCHAR (0, "SWT_Dialog", true);
	lpWndClass = new WNDCLASS ();
	// make sure we haven't already registered windowClass2
	if (OS.GetClassInfo (hInstance, windowClass2, lpWndClass)) {
		OS.UnregisterClass (windowClass2, hInstance);
	}
	// get class info from 32770 and use that to create the new class
	TCHAR WC_DIALOGCONTROL = new TCHAR (0, "#32770", true);
	lpWndClass = new WNDCLASS ();
	OS.GetClassInfo (0, WC_DIALOGCONTROL, lpWndClass);
	lpWndClass.hInstance = hInstance;
	// System.out.println("32770 style bits=" + Integer.toHexString
(lpWndClass.style));
	// FYI, the 32770 style bits were: 0x808 = CS_DBLCLKS | CS_SAVEBITS
	//lpWndClass.style &= ~(OS.CS_HREDRAW | OS.CS_VREDRAW);
	//lpWndClass.style |= OS.CS_BYTEALIGNWINDOW | OS.CS_DBLCLKS;
	//lpWndClass.lpfnWndProc = windowProc;
	//lpWndClass.hCursor = OS.LoadCursor (0, OS.IDC_ARROW);
	byteCount = windowClass2.length () * TCHAR.sizeof;
	lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
	OS.MoveMemory (lpszClassName, windowClass2, byteCount);
	lpWndClass.lpszClassName = lpszClassName;
	OS.RegisterClass (lpWndClass);
	// ===== END TEMP

1) in Shell
- add the following static initializer and methods:
// TEMPORARY CODE
static int DialogProc;
static TCHAR DialogClass;
static {
	DialogClass = new TCHAR (0, "#32770", true);
	WNDCLASS lpWndClass = new WNDCLASS ();
	OS.GetClassInfo (0, DialogClass, lpWndClass);
	DialogProc = lpWndClass.lpfnWndProc;
}

int callWindowProc (int msg, int wParam, int lParam) {
	if (handle == 0) return 0;
	if (true || parent == null) return OS.DefWindowProc (handle, msg, 
wParam, lParam);
	return OS.CallWindowProc (DialogProc, handle, msg, wParam, lParam);
}

TCHAR windowClass () {
//	if (parent != null) return DialogClass;
	if (parent != null) return getDisplay ().windowClass2;
	return getDisplay ().windowClass;
}
// END TEMP

Note that all of this is hacked code, and we were in the process of commenting 
out various bits of it and adding new bits to get everything to work. (i.e. 
tried using "#32770" for our dialogs (with/without registering), tried calling 
the DialogProc/WindowProc, etc.)  The proper code should probably do the right 
thing with the dialog proc.  The code that worked best for JAWS was to actually 
register a window class for our app with the name "#32770", but since we 
unregistered the system dialog class in the process, that is what broke the 
system dialogs.

Deferring this fix until 3.0 because it is too complex and scary to go in at 
this late time. When it goes in, test the following:
- do our custom dialogs look ok?
- does JAWS read the dialog's message label correctly?
- does JAWS INS+B read only the dialog, and not the background window?
- do system dialogs still work?
- does the fix work on Win2K, 98, NT, Me, XP, and CE?

The UI code hacks for org.eclipse.jface.dialogs.MessageDialog were to remove 
one layer of composite/layout from the dialogArea (i.e. the area containing the 
icon and message label). Reduction of layers in other dialog types should be 
considered on a case-by-case basis, seeing whether JAWS can read as much as 
possible. (JAWS has trouble reading past too many parent layers, so once the 
SWT fixes were in, the recommendation was to flatten the dialogs as much as 
possible).

Here is a little test case that helps with the initial testing, although 
Eclipse-in-Eclipse should be used for final testing.

import org.eclipse.swt.*;
import org.eclipse.swt.accessibility.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;

public class ShellOverrideTest {
	static Display display;
	static Shell shell;
	static Button flat, hallOfMirrors, partialHallOfMirrors, realDialog;
	static Shell dialog;
	static Label icon, message;
	static Button yes, no, cancel;
	static Accessible dialogAccessible;
	
	public static void main(String[] args) {
		display = new Display();
		shell = new Shell(display);
		shell.setText("This is the Shell");
		shell.setLayout(new GridLayout());
		Button button = new Button(shell, SWT.PUSH);
		button.setText("Dialog");
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (realDialog.getSelection()) {
					MessageBox box = new MessageBox (shell);
					box.setText("RealDialog");
					box.setMessage("This is the message");
					box.open ();
				}
				else openDialog();
			}
		});
		flat = new Button(shell, SWT.RADIO);
		flat.setText("Flat");
		flat.setSelection(true);
		hallOfMirrors = new Button(shell, SWT.RADIO);
		hallOfMirrors.setText("Hall of Mirrors");
		partialHallOfMirrors = new Button(shell, SWT.RADIO);
		partialHallOfMirrors.setText("Partial Hall of Mirrors");
		realDialog = new Button(shell, SWT.RADIO);
		realDialog.setText("Real Dialog");
		
		shell.setSize(400, 200);
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

	static void openDialog() {
		dialog = new Shell(shell, SWT.DIALOG_TRIM);
		int columns = partialHallOfMirrors.getSelection() ? 2 : 3;
		dialog.setLayout(new GridLayout(columns, false));
		dialog.setText("FakeDialog");

		Composite theParent = dialog;
		
		if (hallOfMirrors.getSelection()) {
			Composite composite = new Composite(dialog, SWT.BORDER);
			composite.setLayout(new FillLayout());
			Composite composite2 = new Composite(composite, 
SWT.BORDER);
			composite2.setLayout(new GridLayout(3, true));
			theParent = composite2;
		}
		
		if (partialHallOfMirrors.getSelection()) {
			Composite composite = new Composite(dialog, SWT.BORDER);
			composite.setLayout(new FillLayout());
			GridData data = new GridData(GridData.FILL_HORIZONTAL);
			data.horizontalSpan = 2;
			composite.setLayoutData(data);
			composite.setLayout(new GridLayout(3, true));
			theParent = composite;
		}

		Image image = new Image(display, 
ShellOverrideTest.class.getResourceAsStream("warning.gif"));
		icon = new Label(theParent, SWT.NONE);
		icon.setImage(image);
		
		message = new Label(theParent, SWT.WRAP);
		message.setText("This is the really really really long very 
long message Label.");
		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
		if (hallOfMirrors.getSelection()) data.horizontalSpan = 2;
		data.widthHint = 50;
		message.setLayoutData(data);

		yes = new Button(theParent, SWT.PUSH);
		yes.setText("&Yes");
		dialog.setDefaultButton(yes);
		yes.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));

		no = new Button(theParent, SWT.PUSH);
		no.setText("&No");
		no.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));

		cancel = new Button(theParent, SWT.PUSH);
		cancel.setText("&Cancel");
		cancel.setLayoutData(new GridData
(GridData.HORIZONTAL_ALIGN_FILL));
		cancel.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				dialog.close();
			}
		});

		dialog.pack();
		dialog.open();
	}
}
Comment 6 Carolyn MacLeod CLA 2002-05-30 17:38:50 EDT
*** Bug 15378 has been marked as a duplicate of this bug. ***
Comment 7 mojit CLA 2002-05-31 16:30:41 EDT
Using JAWS cursor is not an adequate solution for this problem. Can OTI provide 
a JAWS script fix for this problem?
Comment 8 Mike Wilson CLA 2002-06-01 10:31:32 EDT
No further work will be done on this until post R2.0. If you have a script to 
contribute we could consider including it.
Comment 9 Steve Northover CLA 2002-07-04 12:22:20 EDT
The "32770 Windows work" that CAR describes has been done.  I'm sorry but 
Eclipse will need to change the structure of it's dialogs so that JAWS will 
read them properly.  Tod understands what needs to be done and even had a pre-
2.0 hack that showed this kind of working.
Comment 10 Steve Northover CLA 2002-07-04 12:23:16 EDT
Changing to UI.
Comment 11 Nick Edgar CLA 2002-07-17 11:48:31 EDT
Bug 15320 and bug 15576 cover the UI issues with it not reading indirect 
children of the shell.
Closing this one and moving back to SWT since the problem with reading the 
parent window has been fixed in SWT.
Comment 12 Nick Edgar CLA 2002-07-17 12:00:41 EDT
Closing.
Comment 13 Veronika Irvine CLA 2002-08-21 15:24:02 EDT
Fixed in 2.0.1.