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