/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.runtime.swt.internal.os.win32;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.actf.accservice.core.AccessibleConstants;
import org.eclipse.actf.accservice.core.win32.msaa.InitializationException;
import org.eclipse.actf.accservice.core.win32.msaa.MsaaAccessibilityService;
import org.eclipse.actf.accservice.core.win32.msaa.MsaaAccessible;
import org.eclipse.actf.accservice.core.win32.msaa.MsaaLibraryManager;
import org.eclipse.actf.accservice.core.win32.msaa.MsaaWindowService;
import org.eclipse.swt.widgets.Display;
import com.windowtester.runtime.swt.internal.finder.ShellFinder;
import com.windowtester.runtime.swt.internal.os.IAccessibleComponent;
import com.windowtester.runtime.swt.internal.os.IAccessibleWindow;
import com.windowtester.runtime.swt.internal.os.IWindowService;
import com.windowtester.runtime.swt.internal.os.InvalidComponentException;
/**
* A window service for Win32.
*/
public class Win32WindowService implements IWindowService {
private static MsaaWindowService msaaWindowService;
private static MsaaAccessibilityService accService;
static class AccessibleWindow implements IAccessibleWindow {
private final String name;
private boolean inProcess;
private String role;
private final MsaaAccessible element;
public AccessibleWindow(MsaaAccessible element) throws InvalidComponentException {
this.element = element;
this.name = element.getAccessibleName();
}
/* (non-Javadoc)
* @see acc.spike.IAccessibleWindow#getName()
*/
public String getName() {
return name;
}
public static AccessibleWindow forHandle(Integer windowHandle) {
int pid = msaaWindowService.getProcessId(windowHandle);
MsaaAccessible element;
try {
element = accService.createAccessibleElement(windowHandle, null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
if (element == null)
return null; //TODO: consider null object here...
try {
return new AccessibleWindow(element).inProcess(pid == getCurrentPID()).withRole(element.getAccessibleRole());
} catch (Exception e) {
e.printStackTrace();
}
// TODO Auto-generated method stub
return null;
}
private AccessibleWindow inProcess(boolean inProcess) {
this.inProcess = inProcess;
return this;
}
/* (non-Javadoc)
* @see acc.spike.IAccessibleWindow#inProcess()
*/
public boolean inProcess() {
return inProcess;
}
public String getAccessibleRole() {
return role;
}
public String getAccessibleName() throws InvalidComponentException {
return getName();
}
public IAccessibleComponent[] getAccessibleChildren() throws InvalidComponentException {
return element.getAccessibleChildren();
}
private AccessibleWindow withRole(String role) {
this.role = role;
return this;
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.internal.os.IAccessibleWindow#close()
*/
public void close() {
try {
IAccessibleComponent title = MsaaAccessibleHelper.getTitleBar(element);
if (title == null)
return; // throw exception?
IAccessibleComponent[] children = title.getAccessibleChildren();
((MsaaAccessible)children[children.length-1]).doDefaultAction();
} catch (InvalidComponentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String toString() {
return "Window: " + getName() + " " + " - in process: " + inProcess + ", with role: " + role;
}
}
public Win32WindowService() throws InitializationException {
MsaaLibraryManager.load();
createMsaaWindowService();
createMsaaAccService();
}
private static void createMsaaAccService() throws InitializationException {
if (accService == null)
accService = new MsaaAccessibilityService();
}
private static void createMsaaWindowService() throws InitializationException {
if (msaaWindowService == null)
msaaWindowService = new MsaaWindowService();
}
public Integer[] getTopLevelWindowHandles() {
int[] hwnds = MsaaWindowService.internalGetWindowsList();
if (hwnds == null) {
hwnds = new int[0];
}
Integer[] objList = new Integer [hwnds.length];
for (int i=0; i< hwnds.length; i++) {
objList[i]= new Integer( hwnds[i]);
}
return objList;
}
public IAccessibleWindow[] getTopLevelWindows() {
Integer[] handles = getTopLevelWindowHandles();
List windows = new ArrayList();
for (int i = 0; i < handles.length; i++) {
AccessibleWindow window = AccessibleWindow.forHandle(handles[i]);
if (window != null)
windows.add(window);
}
return (IAccessibleWindow[]) windows.toArray(new IAccessibleWindow[]{});
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.internal.os.IWindowService#getDialogs()
*/
public IAccessibleWindow[] getNativeDialogs() {
IAccessibleWindow[] windows = getTopLevelWindows();
List dialogs = new ArrayList();
for (int i = 0; i < windows.length; i++) {
IAccessibleWindow window = windows[i];
if (isNativeDialog(window))
dialogs.add(window);
}
return (IAccessibleWindow[]) dialogs.toArray(new IAccessibleWindow[]{});
}
private boolean isNativeDialog(IAccessibleWindow window) {
return window != null && window.inProcess() && hasDialogRole(window) && inNativeContext();
}
private boolean hasDialogRole(IAccessibleWindow window) {
try {
return AccessibleConstants.ROLE_DIALOG.equals(window.getAccessibleRole());
} catch (InvalidComponentException e) {
return false;
}
}
private boolean inNativeContext() {
/*
* This may not be the best way to do this... but it appears that we can detect the native case
* when the display returns no active shells...
*/
return ShellFinder.getActiveShell(Display.getDefault()) == null;
}
public static int getCurrentPID() {
return msaaWindowService.getCurrentProcessId();
}
public static int getPID(Object windowHandle) {
return msaaWindowService.getProcessId(windowHandle);
}
}