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