1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.lwawt.macosx; 27 28 import sun.lwawt.LWWindowPeer; 29 30 import java.awt.*; 31 import java.beans.*; 32 import java.lang.reflect.Field; 33 import java.lang.reflect.InvocationTargetException; 34 import java.util.*; 35 import java.util.concurrent.Callable; 36 import sun.awt.AWTAccessor; 37 38 import javax.accessibility.*; 39 import javax.swing.*; 40 import sun.awt.AWTAccessor; 41 42 class CAccessibility implements PropertyChangeListener { 43 private static Set<String> ignoredRoles; 44 45 static { 46 // Need to load the native library for this code. 47 java.security.AccessController.doPrivileged( 48 new java.security.PrivilegedAction<Void>() { 49 public Void run() { 50 System.loadLibrary("awt"); 51 return null; 52 } 53 }); 54 } 55 56 static CAccessibility sAccessibility; 57 static synchronized CAccessibility getAccessibility(final String[] roles) { 58 if (sAccessibility != null) return sAccessibility; 59 sAccessibility = new CAccessibility(); 60 61 if (roles != null) { 62 ignoredRoles = new HashSet<String>(roles.length); 63 for (final String role : roles) ignoredRoles.add(role); 64 } else { 65 ignoredRoles = new HashSet<String>(); 66 } 67 68 return sAccessibility; 69 } 70 71 private CAccessibility() { 72 KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", this); 73 } 74 75 public void propertyChange(final PropertyChangeEvent evt) { 76 if (evt.getNewValue() == null) return; 77 focusChanged(); 78 } 79 80 private native void focusChanged(); 81 82 static <T> T invokeAndWait(final Callable<T> callable, final Component c) { 83 try { 84 return LWCToolkit.invokeAndWait(callable, c); 85 } catch (final Exception e) { e.printStackTrace(); } 86 return null; 87 } 88 89 static <T> T invokeAndWait(final Callable<T> callable, final Component c, final T defValue) { 90 T value = null; 91 try { 92 value = LWCToolkit.invokeAndWait(callable, c); 93 } catch (final Exception e) { e.printStackTrace(); } 94 95 return value != null ? value : defValue; 96 } 97 98 static void invokeLater(final Runnable runnable, final Component c) { 99 try { 100 LWCToolkit.invokeLater(runnable, c); 101 } catch (InvocationTargetException e) { e.printStackTrace(); } 102 } 103 104 public static String getAccessibleActionDescription(final AccessibleAction aa, final int index, final Component c) { 105 if (aa == null) return null; 106 107 return invokeAndWait(new Callable<String>() { 108 public String call() throws Exception { 109 return aa.getAccessibleActionDescription(index); 110 } 111 }, c); 112 } 113 114 public static void doAccessibleAction(final AccessibleAction aa, final int index, final Component c) { 115 // We make this an invokeLater because we don't need a reply. 116 if (aa == null) return; 117 118 invokeLater(new Runnable() { 119 public void run() { 120 aa.doAccessibleAction(index); 121 } 122 }, c); 123 } 124 125 public static Dimension getSize(final AccessibleComponent ac, final Component c) { 126 if (ac == null) return null; 127 128 return invokeAndWait(new Callable<Dimension>() { 129 public Dimension call() throws Exception { 130 return ac.getSize(); 131 } 132 }, c); 133 } 134 135 public static AccessibleSelection getAccessibleSelection(final AccessibleContext ac, final Component c) { 136 if (ac == null) return null; 137 138 return invokeAndWait(new Callable<AccessibleSelection>() { 139 public AccessibleSelection call() throws Exception { 140 return ac.getAccessibleSelection(); 141 } 142 }, c); 143 } 144 145 public static Accessible ax_getAccessibleSelection(final AccessibleContext ac, final int index, final Component c) { 146 if (ac == null) return null; 147 148 return invokeAndWait(new Callable<Accessible>() { 149 public Accessible call() throws Exception { 150 final AccessibleSelection as = ac.getAccessibleSelection(); 151 if (as == null) return null; 152 return as.getAccessibleSelection(index); 153 } 154 }, c); 155 } 156 157 // KCH - can we make this a postEvent? 158 public static void addAccessibleSelection(final AccessibleContext ac, final int index, final Component c) { 159 if (ac == null) return; 160 161 invokeLater(new Runnable() { 162 public void run() { 163 final AccessibleSelection as = ac.getAccessibleSelection(); 164 if (as == null) return; 165 as.addAccessibleSelection(index); 166 } 167 }, c); 168 } 169 170 public static AccessibleContext getAccessibleContext(final Accessible a, final Component c) { 171 if (a == null) return null; 172 173 return invokeAndWait(new Callable<AccessibleContext>() { 174 public AccessibleContext call() throws Exception { 175 return a.getAccessibleContext(); 176 } 177 }, c); 178 } 179 180 public static boolean isAccessibleChildSelected(final Accessible a, final int index, final Component c) { 181 if (a == null) return false; 182 183 return invokeAndWait(new Callable<Boolean>() { 184 public Boolean call() throws Exception { 185 final AccessibleContext ac = a.getAccessibleContext(); 186 if (ac == null) return Boolean.FALSE; 187 188 final AccessibleSelection as = ac.getAccessibleSelection(); 189 if (as == null) return Boolean.FALSE; 190 191 return as.isAccessibleChildSelected(index); 192 } 193 }, c, false); 194 } 195 196 public static AccessibleStateSet getAccessibleStateSet(final AccessibleContext ac, final Component c) { 197 if (ac == null) return null; 198 199 return invokeAndWait(new Callable<AccessibleStateSet>() { 200 public AccessibleStateSet call() throws Exception { 201 return ac.getAccessibleStateSet(); 202 } 203 }, c); 204 } 205 206 public static boolean contains(final AccessibleContext ac, final AccessibleState as, final Component c) { 207 if (ac == null || as == null) return false; 208 209 return invokeAndWait(new Callable<Boolean>() { 210 public Boolean call() throws Exception { 211 final AccessibleStateSet ass = ac.getAccessibleStateSet(); 212 if (ass == null) return null; 213 return ass.contains(as); 214 } 215 }, c, false); 216 } 217 218 static String getAccessibleRoleFor(final Accessible a) { 219 final AccessibleContext ac = a.getAccessibleContext(); 220 if (ac == null) return null; 221 222 final AccessibleRole role = ac.getAccessibleRole(); 223 return AWTAccessor.getAccessibleBundleAccessor().getKey(role); 224 } 225 226 public static String getAccessibleRole(final Accessible a, final Component c) { 227 if (a == null) return null; 228 229 return invokeAndWait(new Callable<String>() { 230 public String call() throws Exception { 231 final Accessible sa = CAccessible.getSwingAccessible(a); 232 final String role = getAccessibleRoleFor(a); 233 234 if (!"text".equals(role)) return role; 235 if (sa instanceof JTextArea || sa instanceof JEditorPane) { 236 return "textarea"; 237 } 238 return role; 239 } 240 }, c); 241 } 242 243 public static Point getLocationOnScreen(final AccessibleComponent ac, final Component c) { 244 if (ac == null) return null; 245 246 return invokeAndWait(new Callable<Point>() { 247 public Point call() throws Exception { 248 return ac.getLocationOnScreen(); 249 } 250 }, c); 251 } 252 253 public static int getCharCount(final AccessibleText at, final Component c) { 254 if (at == null) return 0; 255 256 return invokeAndWait(new Callable<Integer>() { 257 public Integer call() throws Exception { 258 return at.getCharCount(); 259 } 260 }, c, 0); 261 } 262 263 // Accessibility Threadsafety for JavaComponentAccessibility.m 264 public static Accessible getAccessibleParent(final Accessible a, final Component c) { 265 if (a == null) return null; 266 267 return invokeAndWait(new Callable<Accessible>() { 268 public Accessible call() throws Exception { 269 final AccessibleContext ac = a.getAccessibleContext(); 270 if (ac == null) return null; 271 return ac.getAccessibleParent(); 272 } 273 }, c); 274 } 275 276 public static int getAccessibleIndexInParent(final Accessible a, final Component c) { 277 if (a == null) return -1; 278 279 return invokeAndWait(new Callable<Integer>() { 280 public Integer call() throws Exception { 281 final AccessibleContext ac = a.getAccessibleContext(); 282 if (ac == null) return null; 283 return ac.getAccessibleIndexInParent(); 284 } 285 }, c, -1); 286 } 287 288 public static AccessibleComponent getAccessibleComponent(final Accessible a, final Component c) { 289 if (a == null) return null; 290 291 return invokeAndWait(new Callable<AccessibleComponent>() { 292 public AccessibleComponent call() throws Exception { 293 final AccessibleContext ac = a.getAccessibleContext(); 294 if (ac == null) return null; 295 return ac.getAccessibleComponent(); 296 } 297 }, c); 298 } 299 300 public static AccessibleValue getAccessibleValue(final Accessible a, final Component c) { 301 if (a == null) return null; 302 303 return invokeAndWait(new Callable<AccessibleValue>() { 304 public AccessibleValue call() throws Exception { 305 final AccessibleContext ac = a.getAccessibleContext(); 306 if (ac == null) return null; 307 308 AccessibleValue accessibleValue = ac.getAccessibleValue(); 309 return accessibleValue; 310 } 311 }, c); 312 } 313 314 public static String getAccessibleName(final Accessible a, final Component c) { 315 if (a == null) return null; 316 317 return invokeAndWait(new Callable<String>() { 318 public String call() throws Exception { 319 final AccessibleContext ac = a.getAccessibleContext(); 320 if (ac == null) return null; 321 322 final String accessibleName = ac.getAccessibleName(); 323 if (accessibleName == null) { 324 return ac.getAccessibleDescription(); 325 } 326 return accessibleName; 327 } 328 }, c); 329 } 330 331 public static AccessibleText getAccessibleText(final Accessible a, final Component c) { 332 if (a == null) return null; 333 334 return invokeAndWait(new Callable<AccessibleText>() { 335 public AccessibleText call() throws Exception { 336 final AccessibleContext ac = a.getAccessibleContext(); 337 if (ac == null) return null; 338 339 AccessibleText accessibleText = ac.getAccessibleText(); 340 return accessibleText; 341 } 342 }, c); 343 } 344 345 public static String getAccessibleDescription(final Accessible a, final Component c) { 346 if (a == null) return null; 347 348 return invokeAndWait(new Callable<String>() { 349 public String call() throws Exception { 350 final AccessibleContext ac = a.getAccessibleContext(); 351 if (ac == null) return null; 352 353 final String accessibleDescription = ac.getAccessibleDescription(); 354 if (accessibleDescription == null) { 355 if (c instanceof JComponent) { 356 String toolTipText = ((JComponent)c).getToolTipText(); 357 if (toolTipText != null) { 358 return toolTipText; 359 } 360 } 361 } 362 363 return accessibleDescription; 364 } 365 }, c); 366 } 367 368 public static boolean isFocusTraversable(final Accessible a, final Component c) { 369 if (a == null) return false; 370 371 return invokeAndWait(new Callable<Boolean>() { 372 public Boolean call() throws Exception { 373 final AccessibleContext ac = a.getAccessibleContext(); 374 if (ac == null) return null; 375 376 final AccessibleComponent aComp = ac.getAccessibleComponent(); 377 if (aComp == null) return null; 378 379 return aComp.isFocusTraversable(); 380 } 381 }, c, false); 382 } 383 384 public static Accessible accessibilityHitTest(final Container parent, final float hitPointX, final float hitPointY) { 385 return invokeAndWait(new Callable<Accessible>() { 386 public Accessible call() throws Exception { 387 final Point p = parent.getLocationOnScreen(); 388 389 // Make it into local coords 390 final Point localPoint = new Point((int)(hitPointX - p.getX()), (int)(hitPointY - p.getY())); 391 392 final Component component = parent.findComponentAt(localPoint); 393 if (component == null) return null; 394 395 final AccessibleContext axContext = component.getAccessibleContext(); 396 if (axContext == null) return null; 397 398 final AccessibleComponent axComponent = axContext.getAccessibleComponent(); 399 if (axComponent == null) return null; 400 401 final int numChildren = axContext.getAccessibleChildrenCount(); 402 if (numChildren > 0) { 403 // It has children, check to see which one is hit. 404 final Point p2 = axComponent.getLocationOnScreen(); 405 final Point localP2 = new Point((int)(hitPointX - p2.getX()), (int)(hitPointY - p2.getY())); 406 return CAccessible.getCAccessible(axComponent.getAccessibleAt(localP2)); 407 } 408 409 if (!(component instanceof Accessible)) return null; 410 return CAccessible.getCAccessible((Accessible)component); 411 } 412 }, parent); 413 } 414 415 public static AccessibleAction getAccessibleAction(final Accessible a, final Component c) { 416 if (a == null) return null; 417 418 return invokeAndWait(new Callable<AccessibleAction>() { 419 public AccessibleAction call() throws Exception { 420 final AccessibleContext ac = a.getAccessibleContext(); 421 if (ac == null) return null; 422 return ac.getAccessibleAction(); 423 } 424 }, c); 425 } 426 427 public static boolean isEnabled(final Accessible a, final Component c) { 428 if (a == null) return false; 429 430 return invokeAndWait(new Callable<Boolean>() { 431 public Boolean call() throws Exception { 432 final AccessibleContext ac = a.getAccessibleContext(); 433 if (ac == null) return null; 434 435 final AccessibleComponent aComp = ac.getAccessibleComponent(); 436 if (aComp == null) return null; 437 438 return aComp.isEnabled(); 439 } 440 }, c, false); 441 } 442 443 // KCH - can we make this a postEvent instead? 444 public static void requestFocus(final Accessible a, final Component c) { 445 if (a == null) return; 446 447 invokeLater(new Runnable() { 448 public void run() { 449 final AccessibleContext ac = a.getAccessibleContext(); 450 if (ac == null) return; 451 452 final AccessibleComponent aComp = ac.getAccessibleComponent(); 453 if (aComp == null) return; 454 455 aComp.requestFocus(); 456 } 457 }, c); 458 } 459 460 public static void requestSelection(final Accessible a, final Component c) { 461 if (a == null) return; 462 invokeLater(new Runnable() { 463 public void run() { 464 AccessibleContext ac = a.getAccessibleContext(); 465 if (ac == null) return; 466 int i = ac.getAccessibleIndexInParent(); 467 if (i == -1) return; 468 Accessible parent = ac.getAccessibleParent(); 469 AccessibleContext pac = parent.getAccessibleContext(); 470 if (pac == null) return; 471 AccessibleSelection as = pac.getAccessibleSelection(); 472 if (as == null) return; 473 as.addAccessibleSelection(i); 474 } 475 }, c); 476 } 477 478 public static Number getMaximumAccessibleValue(final Accessible a, final Component c) { 479 if (a == null) return null; 480 481 return invokeAndWait(new Callable<Number>() { 482 public Number call() throws Exception { 483 final AccessibleContext ac = a.getAccessibleContext(); 484 if (ac == null) return null; 485 486 final AccessibleValue av = ac.getAccessibleValue(); 487 if (av == null) return null; 488 489 return av.getMaximumAccessibleValue(); 490 } 491 }, c); 492 } 493 494 public static Number getMinimumAccessibleValue(final Accessible a, final Component c) { 495 if (a == null) return null; 496 497 return invokeAndWait(new Callable<Number>() { 498 public Number call() throws Exception { 499 final AccessibleContext ac = a.getAccessibleContext(); 500 if (ac == null) return null; 501 502 final AccessibleValue av = ac.getAccessibleValue(); 503 if (av == null) return null; 504 505 return av.getMinimumAccessibleValue(); 506 } 507 }, c); 508 } 509 510 public static String getAccessibleRoleDisplayString(final Accessible a, final Component c) { 511 if (a == null) return null; 512 513 return invokeAndWait(new Callable<String>() { 514 public String call() throws Exception { 515 final AccessibleContext ac = a.getAccessibleContext(); 516 if (ac == null) return null; 517 518 final AccessibleRole ar = ac.getAccessibleRole(); 519 if (ar == null) return null; 520 521 return ar.toDisplayString(); 522 } 523 }, c); 524 } 525 526 public static Number getCurrentAccessibleValue(final AccessibleValue av, final Component c) { 527 if (av == null) return null; 528 529 return invokeAndWait(new Callable<Number>() { 530 public Number call() throws Exception { 531 Number currentAccessibleValue = av.getCurrentAccessibleValue(); 532 return currentAccessibleValue; 533 } 534 }, c); 535 } 536 537 public static Accessible getFocusOwner(final Component c) { 538 return invokeAndWait(new Callable<Accessible>() { 539 public Accessible call() throws Exception { 540 Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); 541 if (c == null || !(c instanceof Accessible)) return null; 542 return CAccessible.getCAccessible((Accessible)c); 543 } 544 }, c); 545 } 546 547 public static boolean[] getInitialAttributeStates(final Accessible a, final Component c) { 548 final boolean[] ret = new boolean[7]; 549 if (a == null) return ret; 550 551 return invokeAndWait(new Callable<boolean[]>() { 552 public boolean[] call() throws Exception { 553 final AccessibleContext aContext = a.getAccessibleContext(); 554 if (aContext == null) return ret; 555 556 final AccessibleComponent aComponent = aContext.getAccessibleComponent(); 557 ret[0] = (aComponent != null); 558 ret[1] = ((aComponent != null) && (aComponent.isFocusTraversable())); 559 ret[2] = (aContext.getAccessibleValue() != null); 560 ret[3] = (aContext.getAccessibleText() != null); 561 562 final AccessibleStateSet aStateSet = aContext.getAccessibleStateSet(); 563 ret[4] = (aStateSet.contains(AccessibleState.HORIZONTAL) || aStateSet.contains(AccessibleState.VERTICAL)); 564 ret[5] = (aContext.getAccessibleName() != null); 565 ret[6] = (aContext.getAccessibleChildrenCount() > 0); 566 return ret; 567 } 568 }, c); 569 } 570 571 // Duplicated from JavaComponentAccessibility 572 // Note that values >=0 are indexes into the child array 573 static final int JAVA_AX_ALL_CHILDREN = -1; 574 static final int JAVA_AX_SELECTED_CHILDREN = -2; 575 static final int JAVA_AX_VISIBLE_CHILDREN = -3; 576 577 // Each child takes up two entries in the array: one for itself and one for its role 578 public static Object[] getChildrenAndRoles(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) { 579 if (a == null) return null; 580 return invokeAndWait(new Callable<Object[]>() { 581 public Object[] call() throws Exception { 582 ArrayList<Object> childrenAndRoles = new ArrayList<Object>(); 583 _addChildren(a, whichChildren, allowIgnored, childrenAndRoles); 584 585 /* In the case of fetching a selection, need to check to see if 586 * the active descendant is at the beginning of the list. If it 587 * is not it needs to be moved to the beginning of the list so 588 * VoiceOver will annouce it correctly. The list returned 589 * from Java is always in order from top to bottom, but when shift 590 * selecting downward (extending the list) or multi-selecting using 591 * the VO keys control+option+command+return the active descendant 592 * is not at the top of the list in the shift select down case and 593 * may not be in the multi select case. 594 */ 595 if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { 596 if (!childrenAndRoles.isEmpty()) { 597 AccessibleContext activeDescendantAC = 598 CAccessible.getActiveDescendant(a); 599 if (activeDescendantAC != null) { 600 String activeDescendantName = 601 activeDescendantAC.getAccessibleName(); 602 AccessibleRole activeDescendantRole = 603 activeDescendantAC.getAccessibleRole(); 604 // Move active descendant to front of list. 605 // List contains pairs of each selected item's 606 // Accessible and AccessibleRole. 607 ArrayList<Object> newArray = new ArrayList<Object>(); 608 int count = childrenAndRoles.size(); 609 Accessible currentAccessible = null; 610 AccessibleContext currentAC = null; 611 String currentName = null; 612 AccessibleRole currentRole = null; 613 for (int i = 0; i < count; i+=2) { 614 // Is this the active descendant? 615 currentAccessible = (Accessible)childrenAndRoles.get(i); 616 currentAC = currentAccessible.getAccessibleContext(); 617 currentName = currentAC.getAccessibleName(); 618 currentRole = (AccessibleRole)childrenAndRoles.get(i+1); 619 if ( currentName.equals(activeDescendantName) && 620 currentRole.equals(activeDescendantRole) ) { 621 newArray.add(0, currentAccessible); 622 newArray.add(1, currentRole); 623 } else { 624 newArray.add(currentAccessible); 625 newArray.add(currentRole); 626 } 627 } 628 childrenAndRoles = newArray; 629 } 630 } 631 } 632 633 if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) { 634 return childrenAndRoles.toArray(); 635 } 636 637 return new Object[] { childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1) }; 638 } 639 }, c); 640 } 641 642 private static AccessibleRole getAccessibleRoleForLabel(JLabel l, AccessibleRole fallback) { 643 String text = l.getText(); 644 if (text != null && text.length() > 0) { 645 return fallback; 646 } 647 Icon icon = l.getIcon(); 648 if (icon != null) { 649 return AccessibleRole.ICON; 650 } 651 return fallback; 652 } 653 654 private static AccessibleRole getAccessibleRole(Accessible a) { 655 AccessibleContext ac = a.getAccessibleContext(); 656 AccessibleRole role = ac.getAccessibleRole(); 657 Object component = CAccessible.getSwingAccessible(a); 658 if (role == null) return null; 659 String roleString = role.toString(); 660 if ("label".equals(roleString) && component instanceof JLabel) { 661 return getAccessibleRoleForLabel((JLabel) component, role); 662 } 663 return role; 664 } 665 666 667 // Either gets the immediate children of a, or recursively gets all unignored children of a 668 private static void _addChildren(final Accessible a, final int whichChildren, final boolean allowIgnored, final ArrayList<Object> childrenAndRoles) { 669 if (a == null) return; 670 671 final AccessibleContext ac = a.getAccessibleContext(); 672 if (ac == null) return; 673 674 final int numChildren = ac.getAccessibleChildrenCount(); 675 676 // each child takes up two entries in the array: itself, and its role 677 // so the array holds alternating Accessible and AccessibleRole objects 678 for (int i = 0; i < numChildren; i++) { 679 final Accessible child = ac.getAccessibleChild(i); 680 if (child == null) continue; 681 682 final AccessibleContext context = child.getAccessibleContext(); 683 if (context == null) continue; 684 685 if (whichChildren == JAVA_AX_VISIBLE_CHILDREN) { 686 if (!context.getAccessibleComponent().isVisible()) continue; 687 } else if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { 688 if (!ac.getAccessibleSelection().isAccessibleChildSelected(i)) continue; 689 } 690 691 if (!allowIgnored) { 692 final AccessibleRole role = context.getAccessibleRole(); 693 if (role != null && ignoredRoles != null && ignoredRoles.contains(roleKey(role))) { 694 // Get the child's unignored children. 695 _addChildren(child, whichChildren, false, childrenAndRoles); 696 } else { 697 childrenAndRoles.add(child); 698 childrenAndRoles.add(getAccessibleRole(child)); 699 } 700 } else { 701 childrenAndRoles.add(child); 702 childrenAndRoles.add(getAccessibleRole(child)); 703 } 704 705 // If there is an index, and we are beyond it, time to finish up 706 if ((whichChildren >= 0) && (childrenAndRoles.size() / 2) >= (whichChildren + 1)) { 707 return; 708 } 709 } 710 } 711 712 private static native String roleKey(AccessibleRole aRole); 713 714 public static Object[] getChildren(final Accessible a, final Component c) { 715 if (a == null) return null; 716 return invokeAndWait(new Callable<Object[]>() { 717 public Object[] call() throws Exception { 718 final AccessibleContext ac = a.getAccessibleContext(); 719 if (ac == null) return null; 720 721 final int numChildren = ac.getAccessibleChildrenCount(); 722 final Object[] children = new Object[numChildren]; 723 for (int i = 0; i < numChildren; i++) { 724 children[i] = ac.getAccessibleChild(i); 725 } 726 return children; 727 } 728 }, c); 729 } 730 731 /** 732 * @return AWTView ptr, a peer of the CPlatformView associated with the toplevel container of the Accessible, if any 733 */ 734 private static long getAWTView(Accessible a) { 735 Accessible ax = CAccessible.getSwingAccessible(a); 736 if (!(ax instanceof Component)) return 0; 737 738 return invokeAndWait(new Callable<Long>() { 739 public Long call() throws Exception { 740 Component cont = (Component) ax; 741 while (cont != null && !(cont instanceof Window)) { 742 cont = cont.getParent(); 743 } 744 if (cont != null) { 745 LWWindowPeer peer = (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(cont); 746 if (peer != null) { 747 return ((CPlatformWindow) peer.getPlatformWindow()).getContentView().getAWTView(); 748 } 749 } 750 return 0L; 751 } 752 }, (Component)ax); 753 } 754 }