1 /* 2 * Copyright (c) 2010, 2015, 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 package com.sun.glass.ui; 26 27 import com.sun.glass.events.MouseEvent; 28 import com.sun.glass.events.ViewEvent; 29 30 import java.lang.ref.WeakReference; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.Map; 34 35 public abstract class View { 36 37 public final static int GESTURE_NO_VALUE = Integer.MAX_VALUE; 38 public final static double GESTURE_NO_DOUBLE_VALUE = Double.NaN; 39 40 public final static byte IME_ATTR_INPUT = 0x00; 41 public final static byte IME_ATTR_TARGET_CONVERTED = 0x01; 42 public final static byte IME_ATTR_CONVERTED = 0x02; 43 public final static byte IME_ATTR_TARGET_NOTCONVERTED = 0x03; 44 public final static byte IME_ATTR_INPUT_ERROR = 0x04; 45 46 final static boolean accessible = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> { 47 String force = System.getProperty("glass.accessible.force"); 48 if (force != null) return Boolean.parseBoolean(force); 49 50 /* By default accessibility is enabled for Mac 10.9 or greater and Windows 7 or greater. */ 51 try { 52 String platform = Platform.determinePlatform(); 53 String major = System.getProperty("os.version").replaceFirst("(\\d+)\\.\\d+.*", "$1"); 54 String minor = System.getProperty("os.version").replaceFirst("\\d+\\.(\\d+).*", "$1"); 55 int v = Integer.parseInt(major) * 100 + Integer.parseInt(minor); 56 return (platform.equals(Platform.MAC) && v >= 1009) || 57 (platform.equals(Platform.WINDOWS) && v >= 601); 58 } catch (Exception e) { 59 return false; 60 } 61 }); 62 63 public static class EventHandler { 64 public void handleViewEvent(View view, long time, int type) { 65 } 66 public void handleKeyEvent(View view, long time, int action, 67 int keyCode, char[] keyChars, int modifiers) { 68 } 69 public void handleMenuEvent(View view, int x, int y, int xAbs, 70 int yAbs, boolean isKeyboardTrigger) { 71 } 72 public void handleMouseEvent(View view, long time, int type, int button, 73 int x, int y, int xAbs, int yAbs, 74 int modifiers, boolean isPopupTrigger, boolean isSynthesized) 75 { 76 } 77 78 /** 79 * A Scroll event handler. 80 * 81 * The lines argument: 82 * > 0 - a number of lines to scroll per each 1.0 of deltaY scroll amount 83 * == 0 - the scroll amount is in pixel units 84 * < 0 - the scrolling should be performed by pages. Each 1.0 of scroll amount 85 * corresponds to exactly one page of scrollable content. 86 * 87 * Similarly, the chars argument specifies the number of characters 88 * to scroll per 1.0 of the deltaX scrolling amount. 89 * If the parameter is zero, the deltaX represents the number of 90 * pixels to scroll. 91 * 92 * The defaultLines and defaultChars arguments contain the system-default 93 * values of lines and chars. This can be used by the app to compute 94 * the ratio of current settings and default settings and adjust the 95 * pixel values accordingly. 96 * 97 * Multiplers are used when an app receives a non-zero unit values (i.e. 98 * either the lines or chars are not zeroes), but wants instead get delta 99 * values in pixels. In this case the app needs to multiply the deltas 100 * on the provided multiplier parameter. 101 */ 102 public void handleScrollEvent(View view, long time, 103 int x, int y, int xAbs, int yAbs, 104 double deltaX, double deltaY, int modifiers, int lines, int chars, 105 int defaultLines, int defaultChars, 106 double xMultiplier, double yMultiplier) 107 { 108 } 109 110 public void handleInputMethodEvent(long time, String text, 111 int[] clauseBoundary, 112 int[] attrBoundary, byte[] attrValue, 113 int commitCount, int cursorPos) { 114 } 115 116 public double[] getInputMethodCandidatePos(int offset) { 117 return null; 118 } 119 120 public void handleDragStart(View view, int button, int x, int y, int xAbs, int yAbs, 121 ClipboardAssistance dropSourceAssistant) { 122 } 123 124 public void handleDragEnd(View view, int performedAction) { 125 } 126 127 public int handleDragEnter(View view, int x, int y, int xAbs, int yAbs, 128 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 129 return recommendedDropAction; 130 } 131 132 public int handleDragOver(View view, int x, int y, int xAbs, int yAbs, 133 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 134 return recommendedDropAction; 135 } 136 137 public void handleDragLeave(View view, ClipboardAssistance dropTargetAssistant) { 138 } 139 140 public int handleDragDrop(View view, int x, int y, int xAbs, int yAbs, 141 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 142 return Clipboard.ACTION_NONE; 143 } 144 145 /** 146 * Touch event handler. Called when touch event occures. 147 * Always followed with one ore more #handleNextTouchEvent() calls 148 * and a single #handleEndTouchEvent() call. 149 * 150 * @param isDirect if event reported by direct or indirect touch device; 151 * touch screen is an example of direct touch device and 152 * touch pad is an example of indirect one 153 * @param touchEventCount indicates number of #handleNextTouchEvent() calls 154 * that will follow this method call. 155 */ 156 public void handleBeginTouchEvent(View view, long time, int modifiers, 157 boolean isDirect, int touchEventCount) { 158 } 159 160 /** 161 * Touch event handler. Called for every touch point in some touch event. 162 * 163 * If the touch event has been emitted with direct touch device 164 * (touch screen) then x and y arguments designate touch point position 165 * relative to the top-left corner of the view and xAbs and yAbs 166 * arguments designate position relative to the top-left corner of the 167 * screen. Both positions are measured in pixels. 168 * 169 * If the touch event has been emitted with indirect touch device 170 * (touch pad) then x and y arguments designate normalized touch point 171 * position. It is measured between (0,0) and (10000,10000), where (0,0) 172 * is the top-left and (10000,10000) is the bottom-right position on 173 * the indirect touch input device (touch pad). xAbs and yAbs 174 * arguments are equal values of x and y arguments respectively. 175 * 176 * @see #handleBeginTouchEvent(com.sun.glass.ui.View, long, int, boolean, int) 177 * 178 * @param type touch event type. One of constants declared in 179 * #com.sun.glass.events.TouchEvent class. 180 * @param touchId touch point identifier; 181 * every touch point has its own unique identifier; 182 * the identifier remains the same across multiple calls of 183 * #handleNextTouchEvent method for the same touch point until 184 * it is not released. 185 * @param x the X coordinate of the touch point; 186 * @param y the Y coordinate of the touch point; 187 * @param xAbs absolute X coordinate of the touch point; 188 * @param yAbs absolute Y coordinate of the touch point; 189 */ 190 public void handleNextTouchEvent(View view, long time, int type, 191 long touchId, int x, int y, int xAbs, 192 int yAbs) { 193 } 194 195 /** 196 * Touch event handler. Called to notify that all #handleNextTouchEvent 197 * methods corresponding to some touch event have been called already. 198 * 199 * @see #handleBeginTouchEvent(com.sun.glass.ui.View, long, int, boolean, int) 200 */ 201 public void handleEndTouchEvent(View view, long time) { 202 } 203 204 /** 205 * Scroll gesture handler. 206 * 207 * If underlying system supports coordinates for gestures then x and y 208 * arguments designate gesture position relative to the top-left 209 * corner of the view and xAbs and yAbs designate gesture position 210 * relative to the top-left corner of the screen. For gestures emitted 211 * from direct touch input device (touch screen) positions are measured 212 * in pixels. For gestures emitted from indirect touch input device 213 * (touch pad) positions are normalized. For details of normalized 214 * touch input position see #handleBeginTouchEvent method. 215 * 216 * If underlying system doesn't support coordinates for gestures then 217 * x and y arguments designate mouse position relative to the top-left 218 * corner of the view and xAbs and yAbs designate mouse position 219 * relative to the top-left corner of the screen. Positions are measured 220 * in pixels. 221 * 222 * If gesture handler is called to notify end of gesture, i.e. value of 223 * type argument is equal to 224 * com.sun.glass.events.GestureEvent.GESTURE_FINISHED constant then 225 * x, y, xAbs and yAbs arguments may be set to View.GESTURE_NO_VALUE 226 * constant indicating no data is available. This is implementation 227 * specific behavior. 228 * 229 * Values of dx and dy arguments are always 0.0 if type argument 230 * is set to com.sun.glass.events.GestureEvent.GESTURE_FINISHED 231 * constant. 232 * 233 * For description of isDirect argument see #handleBeginTouchEvent 234 * method. 235 * 236 * @param type gesture state. One of constants declared in 237 * #com.sun.glass.events.GestureEvent class. 238 * @param isInertia if gesture is caused by inertia. 239 * @param touchCount number of touch points at 240 * the moment of gesture execution; it is always set to 241 * View.GESTURE_NO_VALUE constant if value of type argument is 242 * set to com.sun.glass.events.GestureEvent.GESTURE_FINISHED 243 * constant 244 * @param x the X coordinate of the gesture; 245 * @param y the Y coordinate of the gesture; 246 * @param xAbs absolute X coordinate of the gesture; 247 * @param yAbs absolute Y coordinate of the gesture; 248 * @param dx horizontal scroll delta. Positive if scrolling from 249 * left to right, non-positive otherwise 250 * @param dy vertical scroll delta. Positive if scrolling from 251 * up to down, non-positive otherwise 252 * @param totaldx total horizontal scroll calculated from all 253 * sequential scroll gestures, i.e. sum of all 'dx' values from 254 * previous sequential calls to this method 255 * @param totaldy total vertical scroll calculated from all 256 * sequential scroll gestures, i.e. sum of all 'dy' values from 257 * previous sequential calls to this method 258 * @param multiplierX the X multiplier 259 * @param multiplierY the Y multiplier 260 * 261 * Multiplers are used when an app receives a non-zero unit values (i.e. 262 * either the lines or chars are not zeroes), but wants instead get delta 263 * values in pixels. In this case the app needs to multiply the deltas 264 * on the provided multiplier parameter. 265 */ 266 public void handleScrollGestureEvent(View view, long time, int type, 267 int modifiers, boolean isDirect, 268 boolean isInertia, int touchCount, 269 int x, int y, int xAbs, int yAbs, 270 double dx, double dy, 271 double totaldx, double totaldy, 272 double multiplierX, double multiplierY) { 273 } 274 275 /** 276 * Zoom gesture handler. 277 * 278 * For description of isDirect argument see #handleBeginTouchEvent 279 * method. 280 * 281 * For description of isInertia argument see #handleScrollGestureEvent 282 * method. 283 * 284 * For description of type, x,y, xAbs and yAbs arguments 285 * see #handleBeginTouchEvent method. 286 * 287 * If underlying system doesn't support measurement of expansion value 288 * in zoom gestures then expansion and totalexpansion arguments are 289 * always set to View.GESTURE_NO_DOUBLE_VALUE. 290 * 291 * If type argument is set to 292 * com.sun.glass.events.GestureEvent.GESTURE_FINISHED constant value of 293 * scale argument is always set to View.GESTURE_NO_DOUBLE_VALUE constant 294 * and expansion argument is always 0.0. 295 * 296 * @param scale current zoom delta; the value is multiplicative 297 * and not additive. 298 * @param expansion current expansion delta. Measured in pixels on 299 * direct touch input devices and normalized values on indirect 300 * touch input devices. See #handleBeginTouchEvent for 301 * description of units of indirect touch input devices. 302 * @param totalscale total zoom calculated from all 303 * sequential zoom gestures, i.e. sum of all 'scale' values from 304 * previous sequential calls to this method 305 * @param totalexpansion total expansion calculated from all 306 * sequential zoom gestures, i.e. sum of all 'expansion' values 307 * from previous sequential calls of this method 308 */ 309 public void handleZoomGestureEvent(View view, long time, int type, 310 int modifiers, boolean isDirect, 311 boolean isInertia, int x, int y, 312 int xAbs, int yAbs, double scale, 313 double expansion, double totalscale, 314 double totalexpansion) { 315 } 316 317 /** 318 * Rotation gesture handler. 319 * 320 * For description of isDirect argument see #handleBeginTouchEvent 321 * method. 322 * 323 * For description of isInertia argument see #handleScrollGestureEvent 324 * method. 325 * 326 * For description of type, x,y, xAbs and yAbs arguments 327 * see #handleBeginTouchEvent method. 328 * 329 * @param dangle current angle delta in degrees. Positive for clockwise 330 * rotation 331 * @param totalangle total angle calculated from all 332 * sequential rotation gestures, i.e. sum of all 'dangle' values 333 * from previous sequential calls of this method 334 */ 335 public void handleRotateGestureEvent(View view, long time, int type, 336 int modifiers, boolean isDirect, 337 boolean isInertia, int x, int y, 338 int xAbs, int yAbs, double dangle, 339 double totalangle) { 340 } 341 342 /** 343 * Swipe gesture handler. 344 * 345 * For description of isDirect argument see #handleBeginTouchEvent 346 * method. 347 * 348 * For description of isInertia and touchCount arguments 349 * see #handleScrollGestureEvent method. 350 * 351 * For description of type, x,y, xAbs and yAbs arguments 352 * see #handleBeginTouchEvent method. 353 * 354 * @param dir gesture direction. 355 * One of constants defined in com.sun.glass.events.SwipeGesture 356 * class. 357 */ 358 public void handleSwipeGestureEvent(View view, long time, int type, 359 int modifiers, boolean isDirect, 360 boolean isInertia, int touchCount, 361 int dir, int x, int y, int xAbs, 362 int yAbs) { 363 } 364 365 public Accessible getSceneAccessible() { 366 return null; 367 } 368 } 369 370 public static long getMultiClickTime() { 371 Application.checkEventThread(); 372 return Application.GetApplication().staticView_getMultiClickTime(); 373 } 374 375 public static int getMultiClickMaxX() { 376 Application.checkEventThread(); 377 return Application.GetApplication().staticView_getMultiClickMaxX(); 378 } 379 380 public static int getMultiClickMaxY() { 381 Application.checkEventThread(); 382 return Application.GetApplication().staticView_getMultiClickMaxY(); 383 } 384 385 protected abstract void _enableInputMethodEvents(long ptr, boolean enable); 386 protected void _finishInputMethodComposition(long ptr) { 387 // Action needed only on Windows. 388 } 389 390 /* 391 Read by the checkNotClosed method which could be called from lock/unlock on render thread 392 */ 393 private volatile long ptr; // Native handle (NSView*, or internal structure pointer) 394 private Window window; // parent window 395 private EventHandler eventHandler; 396 397 private int width = -1; // not set 398 private int height = -1; // not set 399 400 private boolean isValid = false; // true between ViewEvent.Add & ViewEvent.REMOVE 401 private boolean isVisible = false; 402 private boolean inFullscreen = false; 403 404 static final public class Capability { 405 // we need these for native code 406 static final public int k3dKeyValue = 0; 407 static final public int kSyncKeyValue = 1; 408 static final public int k3dProjectionKeyValue = 2; 409 static final public int k3dProjectionAngleKeyValue = 3; 410 static final public int k3dDepthKeyValue = 4; 411 static final public int kHiDPIAwareKeyValue = 5; 412 413 static final public Object k3dKey = Integer.valueOf(k3dKeyValue); // value must be Boolean 414 static final public Object kSyncKey = Integer.valueOf(kSyncKeyValue); // value must be Boolean 415 static final public Object k3dProjectionKey = Integer.valueOf(k3dProjectionKeyValue); // value must be Boolean 416 static final public Object k3dProjectionAngleKey = Integer.valueOf(k3dProjectionAngleKeyValue); // value must be Float 417 static final public Object k3dDepthKey = Integer.valueOf(k3dDepthKeyValue); // value must be Integer(depth), where depth = 0, 4, 8, 16, 32etc 418 static final public Object kHiDPIAwareKey = Integer.valueOf(kHiDPIAwareKeyValue); // value must be Boolean; default = false (i.e. NOT HiDPI-aware) 419 } 420 421 422 protected abstract long _create(Map capabilities); 423 protected View() { 424 Application.checkEventThread(); 425 this.ptr = _create(Application.GetApplication().getDeviceDetails()); 426 if (this.ptr == 0L) { 427 throw new RuntimeException("could not create platform view"); 428 } 429 } 430 431 private void checkNotClosed() { 432 if (this.ptr == 0L) { 433 throw new IllegalStateException("The view has already been closed"); 434 } 435 } 436 437 public boolean isClosed() { 438 Application.checkEventThread(); 439 return this.ptr == 0L; 440 } 441 442 protected abstract long _getNativeView(long ptr); 443 /** 444 * On Windows ptr is a pointer to a native structure. 445 * However, for external clients of the API, a HWND has to be returned. 446 * Hence the native method. 447 */ 448 public long getNativeView() { 449 Application.checkEventThread(); 450 checkNotClosed(); 451 return _getNativeView(this.ptr); 452 } 453 454 /** Only used on Mac when run inside a plugin */ 455 public int getNativeRemoteLayerId(String serverName) { 456 Application.checkEventThread(); 457 throw new RuntimeException("This operation is not supported on this platform"); 458 } 459 460 public Window getWindow() { 461 Application.checkEventThread(); 462 return this.window; 463 } 464 465 protected abstract int _getX(long ptr); 466 /** X coordinate relative to the host (window or applet). */ 467 public int getX() { 468 Application.checkEventThread(); 469 checkNotClosed(); 470 return _getX(this.ptr); 471 } 472 473 protected abstract int _getY(long ptr); 474 /** Y coordinate relative to the host (window or applet). */ 475 public int getY() { 476 Application.checkEventThread(); 477 checkNotClosed(); 478 return _getY(this.ptr); 479 } 480 481 public int getWidth() { 482 Application.checkEventThread(); 483 return this.width; 484 } 485 486 public int getHeight() { 487 Application.checkEventThread(); 488 return this.height; 489 } 490 491 protected abstract void _setParent(long ptr, long parentPtr); 492 // Window calls the method from Window.setView() 493 // package private 494 void setWindow(Window window) { 495 Application.checkEventThread(); 496 checkNotClosed(); 497 this.window = window; 498 _setParent(this.ptr, window == null ? 0L : window.getNativeHandle()); 499 this.isValid = this.ptr != 0 && window != null; 500 } 501 502 // package private 503 void setVisible(boolean visible) { 504 this.isVisible = visible; 505 } 506 507 protected abstract boolean _close(long ptr); 508 public void close() { 509 Application.checkEventThread(); 510 if (this.ptr == 0) { 511 return; 512 } 513 if (isInFullscreen()) { 514 _exitFullscreen(this.ptr, false); 515 } 516 Window host = getWindow(); 517 if (host != null) { 518 host.setView(null); // will call this.setWindow(null) 519 } 520 this.isValid = false; 521 _close(this.ptr); 522 this.ptr = 0; 523 } 524 525 public EventHandler getEventHandler() { 526 Application.checkEventThread(); 527 return this.eventHandler; 528 } 529 530 public void setEventHandler(EventHandler eventHandler) { 531 Application.checkEventThread(); 532 this.eventHandler = eventHandler; 533 } 534 535 //-------- EVENTS --------// 536 537 private void handleViewEvent(long time, int type) { 538 if (this.eventHandler != null) { 539 this.eventHandler.handleViewEvent(this, time, type); 540 } 541 } 542 543 private void handleKeyEvent(long time, int action, 544 int keyCode, char[] keyChars, int modifiers) { 545 if (this.eventHandler != null) { 546 this.eventHandler.handleKeyEvent(this, time, action, keyCode, keyChars, modifiers); 547 } 548 } 549 550 private void handleMouseEvent(long time, int type, int button, int x, int y, 551 int xAbs, int yAbs, 552 int modifiers, boolean isPopupTrigger, 553 boolean isSynthesized) { 554 if (eventHandler != null) { 555 eventHandler.handleMouseEvent(this, time, type, button, x, y, xAbs, 556 yAbs, modifiers, 557 isPopupTrigger, isSynthesized); 558 } 559 } 560 561 private void handleMenuEvent(int x, int y, int xAbs, int yAbs, boolean isKeyboardTrigger) { 562 if (this.eventHandler != null) { 563 this.eventHandler.handleMenuEvent(this, x, y, xAbs, yAbs, isKeyboardTrigger); 564 } 565 } 566 567 public void handleBeginTouchEvent(View view, long time, int modifiers, 568 boolean isDirect, int touchEventCount) { 569 if (eventHandler != null) { 570 eventHandler.handleBeginTouchEvent(view, time, modifiers, isDirect, 571 touchEventCount); 572 } 573 } 574 575 public void handleNextTouchEvent(View view, long time, int type, 576 long touchId, int x, int y, int xAbs, 577 int yAbs) { 578 if (eventHandler != null) { 579 eventHandler.handleNextTouchEvent(view, time, type, touchId, x, y, xAbs, yAbs); 580 } 581 } 582 583 public void handleEndTouchEvent(View view, long time) { 584 if (eventHandler != null) { 585 eventHandler.handleEndTouchEvent(view, time); 586 } 587 } 588 589 public void handleScrollGestureEvent(View view, long time, int type, 590 int modifiers, boolean isDirect, 591 boolean isInertia, int touchCount, 592 int x, int y, int xAbs, int yAbs, 593 double dx, double dy, double totaldx, 594 double totaldy, double multiplierX, 595 double multiplierY) { 596 if (eventHandler != null) { 597 eventHandler.handleScrollGestureEvent(view, time, type, modifiers, isDirect, 598 isInertia, touchCount, x, y, xAbs, yAbs, 599 dx, dy, totaldx, totaldy, multiplierX, multiplierY); 600 } 601 } 602 603 public void handleZoomGestureEvent(View view, long time, int type, 604 int modifiers, boolean isDirect, 605 boolean isInertia, int originx, 606 int originy, int originxAbs, 607 int originyAbs, double scale, 608 double expansion, double totalscale, 609 double totalexpansion) { 610 if (eventHandler != null) { 611 eventHandler.handleZoomGestureEvent(view, time, type, modifiers, isDirect, 612 isInertia, originx, originy, originxAbs, 613 originyAbs, scale, expansion, totalscale, 614 totalexpansion); 615 } 616 } 617 618 public void handleRotateGestureEvent(View view, long time, int type, 619 int modifiers, boolean isDirect, 620 boolean isInertia, int originx, 621 int originy, int originxAbs, 622 int originyAbs, double dangle, 623 double totalangle) { 624 if (eventHandler != null) { 625 eventHandler.handleRotateGestureEvent(view, time, type, modifiers, isDirect, 626 isInertia, originx, originy, originxAbs, 627 originyAbs, dangle, totalangle); 628 } 629 } 630 631 public void handleSwipeGestureEvent(View view, long time, int type, 632 int modifiers, boolean isDirect, 633 boolean isInertia, int touchCount, 634 int dir, int originx, int originy, 635 int originxAbs, int originyAbs) { 636 if (eventHandler != null) { 637 eventHandler.handleSwipeGestureEvent(view, time, type, modifiers, isDirect, 638 isInertia, touchCount, dir, originx, 639 originy, originxAbs, originyAbs); 640 } 641 } 642 643 private void handleInputMethodEvent(long time, String text, int[] clauseBoundary, 644 int[] attrBoundary, byte[] attrValue, 645 int commitCount, int cursorPos) { 646 if (this.eventHandler != null) { 647 this.eventHandler.handleInputMethodEvent(time, text, clauseBoundary, 648 attrBoundary, attrValue, 649 commitCount, cursorPos); 650 } 651 } 652 653 public void enableInputMethodEvents(boolean enable) { 654 Application.checkEventThread(); 655 checkNotClosed(); 656 _enableInputMethodEvents(this.ptr, enable); 657 } 658 659 public void finishInputMethodComposition() { 660 Application.checkEventThread(); 661 checkNotClosed(); 662 _finishInputMethodComposition(this.ptr); 663 } 664 665 private double[] getInputMethodCandidatePos(int offset) { 666 if (this.eventHandler != null) { 667 return this.eventHandler.getInputMethodCandidatePos(offset); 668 } 669 return null; 670 } 671 672 private void handleDragStart(int button, int x, int y, int xAbs, int yAbs, 673 ClipboardAssistance dropSourceAssistant) { 674 if (this.eventHandler != null) { 675 this.eventHandler.handleDragStart(this, button, x, y, xAbs, yAbs, dropSourceAssistant); 676 } 677 } 678 679 private void handleDragEnd(int performedAction) { 680 if (this.eventHandler != null) { 681 this.eventHandler.handleDragEnd(this, performedAction); 682 } 683 } 684 685 private int handleDragEnter(int x, int y, int xAbs, int yAbs, 686 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 687 if (this.eventHandler != null) { 688 return this.eventHandler.handleDragEnter(this, x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 689 } else { 690 return recommendedDropAction; 691 } 692 } 693 694 private int handleDragOver(int x, int y, int xAbs, int yAbs, 695 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 696 if (this.eventHandler != null) { 697 return this.eventHandler.handleDragOver(this, x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 698 } else { 699 return recommendedDropAction; 700 } 701 } 702 703 private void handleDragLeave(ClipboardAssistance dropTargetAssistant) { 704 if (this.eventHandler != null) { 705 this.eventHandler.handleDragLeave(this, dropTargetAssistant); 706 } 707 } 708 709 private int handleDragDrop(int x, int y, int xAbs, int yAbs, 710 int recommendedDropAction, ClipboardAssistance dropTargetAssistant) { 711 if (this.eventHandler != null) { 712 return this.eventHandler.handleDragDrop(this, x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 713 } else { 714 return Clipboard.ACTION_NONE; 715 } 716 } 717 718 //-------- DRAWING --------// 719 protected abstract void _scheduleRepaint(long ptr); 720 /** marks native surface dirty, so the system itself will create repaint event 721 * */ 722 public void scheduleRepaint() { 723 Application.checkEventThread(); 724 checkNotClosed(); 725 _scheduleRepaint(this.ptr); 726 } 727 728 protected abstract void _begin(long ptr); 729 /** prepares to painting by locking native surface 730 * 731 * Called on the render thread 732 */ 733 public void lock() { 734 checkNotClosed(); 735 _begin(this.ptr); 736 } 737 738 protected abstract void _end(long ptr); 739 /** ends painting by unlocking native surface and flushing 740 * flushes surface (if flush == true) or discard it (flush == false) 741 * 742 * Called on the render thread 743 */ 744 public void unlock() { 745 checkNotClosed(); 746 _end(this.ptr); 747 } 748 749 protected abstract int _getNativeFrameBuffer(long ptr); 750 751 /** 752 * Called on the renderer thread and must be between lock and unlock 753 */ 754 public int getNativeFrameBuffer() { 755 return _getNativeFrameBuffer(this.ptr); 756 } 757 758 759 protected abstract void _uploadPixels(long ptr, Pixels pixels); 760 /** 761 * This method dumps the pixels on to the view. 762 * 763 * NOTE: On MS Windows calling this method is REQUIRED for 764 * transparent windows in order to update them. 765 */ 766 public void uploadPixels(Pixels pixels) { 767 Application.checkEventThread(); 768 checkNotClosed(); 769 lock(); 770 try { 771 _uploadPixels(this.ptr, pixels); 772 } finally { 773 unlock(); 774 } 775 } 776 777 778 //-------- FULLSCREEN --------// 779 780 protected abstract boolean _enterFullscreen(long ptr, boolean animate, boolean keepRatio, boolean hideCursor); 781 public boolean enterFullscreen(boolean animate, boolean keepRatio, boolean hideCursor) { 782 Application.checkEventThread(); 783 checkNotClosed(); 784 return _enterFullscreen(this.ptr, animate, keepRatio, hideCursor); 785 } 786 787 protected abstract void _exitFullscreen(long ptr, boolean animate); 788 public void exitFullscreen(boolean animate) { 789 Application.checkEventThread(); 790 checkNotClosed(); 791 _exitFullscreen(this.ptr, animate); 792 } 793 794 public boolean isInFullscreen() { 795 Application.checkEventThread(); 796 return this.inFullscreen; 797 } 798 799 public boolean toggleFullscreen(boolean animate, boolean keepRatio, boolean hideCursor) { 800 Application.checkEventThread(); 801 checkNotClosed(); 802 if (!this.inFullscreen) { 803 enterFullscreen(animate, keepRatio, hideCursor); 804 } else { 805 exitFullscreen(animate); 806 } 807 808 _scheduleRepaint(this.ptr); 809 810 return this.inFullscreen; 811 } 812 813 814 //-------- DELEGATE NOTIFICATIONS --------// 815 816 protected void notifyView(int type) { 817 //System.err.println(" notifyView: "+ViewEvent.getTypeString(type)+" on thread"+Thread.currentThread()); 818 if (type == ViewEvent.REPAINT) { 819 if (isValid) { 820 handleViewEvent(System.nanoTime(), type); 821 } 822 } 823 else 824 { 825 boolean synthesizeMOVE = false; 826 827 switch (type) { 828 case ViewEvent.REMOVE: 829 isValid = false; 830 synthesizeMOVE = true; 831 break; 832 case ViewEvent.ADD: 833 isValid = true; 834 synthesizeMOVE = true; 835 break; 836 case ViewEvent.FULLSCREEN_ENTER: 837 this.inFullscreen = true; 838 synthesizeMOVE = true; 839 if (getWindow() != null) { 840 getWindow().notifyFullscreen(true); 841 } 842 break; 843 case ViewEvent.FULLSCREEN_EXIT: 844 this.inFullscreen = false; 845 synthesizeMOVE = true; 846 if (getWindow() != null) { 847 getWindow().notifyFullscreen(false); 848 } 849 break; 850 case ViewEvent.MOVE: 851 case ViewEvent.RESIZE: 852 break; 853 default: 854 System.err.println("Unknown view event type: " + type); 855 return; 856 } 857 858 handleViewEvent(System.nanoTime(), type); 859 860 if (synthesizeMOVE) { 861 // Generate MOVE event to update current insets. Native code may 862 // send additional MOVE events when it detects insets change. 863 handleViewEvent(System.nanoTime(), ViewEvent.MOVE); 864 } 865 } 866 } 867 868 protected void notifyResize(int width, int height) { 869 if (this.width == width && this.height == height) { 870 return; 871 } 872 873 this.width = width; 874 this.height = height; 875 handleViewEvent(System.nanoTime(), ViewEvent.RESIZE); 876 } 877 878 /* 879 * x, y, width, heigth define the "dirty" rect 880 */ 881 protected void notifyRepaint(int x, int y, int width, int height) { 882 notifyView(ViewEvent.REPAINT); 883 } 884 885 886 // ------------ MENU EVENT HANDLING ----------------- 887 // protected void notifyMenu(int type, int button, int x, int y, int xAbs, int yAbs, int keyCode, char[] keyChars, int modifiers) { 888 protected void notifyMenu(int x, int y, int xAbs, int yAbs, boolean isKeyboardTrigger) { 889 handleMenuEvent(x, y, xAbs, yAbs, isKeyboardTrigger); 890 } 891 892 // ------------ MOUSE EVENTS HANDLING ----------------- 893 894 // Synchronized on the Main thread of the underlying native system 895 private static WeakReference<View> lastClickedView = null; 896 private static int lastClickedButton; 897 private static long lastClickedTime; 898 private static int lastClickedX, lastClickedY; 899 private static int clickCount; 900 private static boolean dragProcessed = false; 901 902 protected void notifyMouse(int type, int button, int x, int y, int xAbs, 903 int yAbs, int modifiers, boolean isPopupTrigger, 904 boolean isSynthesized) { 905 // gznote: optimize - only call for undecorated Windows! 906 if (this.window != null) { 907 // handled by window (programmatical move/resize) 908 if (this.window.handleMouseEvent(type, button, x, y, xAbs, yAbs)) { 909 // The evnet has been processed by Glass 910 return; 911 } 912 } 913 914 long now = System.nanoTime(); 915 if (type == MouseEvent.DOWN) { 916 View lastClickedView = View.lastClickedView == null ? null : View.lastClickedView.get(); 917 918 if (lastClickedView == this && 919 lastClickedButton == button && 920 (now - lastClickedTime) <= 1000000L*getMultiClickTime() && 921 Math.abs(x - lastClickedX) <= getMultiClickMaxX() && 922 Math.abs(y - lastClickedY) <= getMultiClickMaxY()) 923 { 924 clickCount++; 925 } else { 926 clickCount = 1; 927 928 View.lastClickedView = new WeakReference<View>(this); 929 lastClickedButton = button; 930 lastClickedX = x; 931 lastClickedY = y; 932 } 933 934 lastClickedTime = now; 935 } 936 937 handleMouseEvent(now, type, button, x, y, xAbs, yAbs, 938 modifiers, isPopupTrigger, isSynthesized); 939 940 if (type == MouseEvent.DRAG) { 941 // Send the handleDragStart() only once per a drag gesture 942 if (!dragProcessed) { 943 notifyDragStart(button, x, y, xAbs, yAbs); 944 dragProcessed = true; 945 } 946 } else { 947 dragProcessed = false; 948 } 949 } 950 951 // ------------- END OF MOUSE EVENTS ----------------- 952 953 protected void notifyScroll(int x, int y, int xAbs, int yAbs, 954 double deltaX, double deltaY, int modifiers, int lines, int chars, 955 int defaultLines, int defaultChars, 956 double xMultiplier, double yMultiplier) 957 { 958 if (this.eventHandler != null) { 959 this.eventHandler.handleScrollEvent(this, System.nanoTime(), 960 x, y, xAbs, yAbs, deltaX, deltaY, modifiers, lines, chars, 961 defaultLines, defaultChars, xMultiplier, yMultiplier); 962 } 963 } 964 965 protected void notifyKey(int type, int keyCode, char[] keyChars, int modifiers) { 966 handleKeyEvent(System.nanoTime(), type, keyCode, keyChars, modifiers); 967 } 968 969 protected void notifyInputMethod(String text, int[] clauseBoundary, 970 int[] attrBoundary, byte[] attrValue, 971 int committedTextLength, int caretPos, int visiblePos) { 972 handleInputMethodEvent(System.nanoTime(), text, clauseBoundary, 973 attrBoundary, attrValue, committedTextLength, caretPos); 974 } 975 976 protected double[] notifyInputMethodCandidatePosRequest(int offset) { 977 double[] ret = getInputMethodCandidatePos(offset); 978 if (ret == null) { 979 ret = new double[2]; 980 ret[0] = 0.0; 981 ret[1] = 0.0; 982 } 983 return ret; 984 } 985 986 private ClipboardAssistance dropSourceAssistant; 987 protected void notifyDragStart(int button, int x, int y, int xAbs, int yAbs) { 988 dropSourceAssistant = new ClipboardAssistance(Clipboard.DND) { 989 @Override public void actionPerformed(int performedAction) { 990 // on Windows called from DnD modal loop 991 // on Mac the View is the drag delegate and calls notifyDragEnd directly 992 notifyDragEnd(performedAction); 993 } 994 }; 995 //DnD loop is inside dropSourceAssistant.flush() 996 handleDragStart(button, x, y, xAbs, yAbs, dropSourceAssistant); 997 //utilize dropSourceAssistant if DnD was not started. 998 if (dropSourceAssistant != null) { 999 dropSourceAssistant.close(); 1000 dropSourceAssistant = null; 1001 } 1002 } 1003 1004 protected void notifyDragEnd(int performedAction) { 1005 handleDragEnd(performedAction); 1006 if (dropSourceAssistant != null) { 1007 dropSourceAssistant.close(); 1008 dropSourceAssistant = null; 1009 } 1010 } 1011 1012 ClipboardAssistance dropTargetAssistant; 1013 // callback for native code 1014 protected int notifyDragEnter(int x, int y, int xAbs, int yAbs, int recommendedDropAction) { 1015 dropTargetAssistant = new ClipboardAssistance(Clipboard.DND) { 1016 @Override public void flush() { 1017 throw new UnsupportedOperationException("Flush is forbidden from target!"); 1018 } 1019 }; 1020 return handleDragEnter(x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 1021 } 1022 1023 // callback for native code 1024 protected int notifyDragOver(int x, int y, int xAbs, int yAbs, int recommendedDropAction) { 1025 return handleDragOver(x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 1026 } 1027 1028 // callback for native code 1029 protected void notifyDragLeave() { 1030 handleDragLeave(dropTargetAssistant); 1031 dropTargetAssistant.close(); 1032 } 1033 1034 // callback for native code 1035 // gznote: should be renamed to notifyDragDrop/notifyDragPerformed to be consistent 1036 protected int notifyDragDrop(int x, int y, int xAbs, int yAbs, int recommendedDropAction) { 1037 int performedAction = handleDragDrop(x, y, xAbs, yAbs, recommendedDropAction, dropTargetAssistant); 1038 dropTargetAssistant.close(); 1039 return performedAction; 1040 } 1041 1042 public void notifyBeginTouchEvent(int modifiers, boolean isDirect, 1043 int touchEventCount) { 1044 handleBeginTouchEvent(this, System.nanoTime(), modifiers, isDirect, 1045 touchEventCount); 1046 } 1047 1048 public void notifyNextTouchEvent(int type, long touchId, int x, int y, 1049 int xAbs, int yAbs) { 1050 handleNextTouchEvent(this, System.nanoTime(), type, touchId, x, y, xAbs, 1051 yAbs); 1052 } 1053 1054 public void notifyEndTouchEvent() { 1055 handleEndTouchEvent(this, System.nanoTime()); 1056 } 1057 1058 public void notifyScrollGestureEvent(int type, int modifiers, 1059 boolean isDirect, boolean isInertia, 1060 int touchCount, int x, int y, int xAbs, 1061 int yAbs, double dx, double dy, 1062 double totaldx, double totaldy, 1063 double multiplierX, double multiplierY) { 1064 handleScrollGestureEvent(this, System.nanoTime(), type, modifiers, 1065 isDirect, isInertia, touchCount, x, y, xAbs, 1066 yAbs, dx, dy, totaldx, totaldy, multiplierX, multiplierY); 1067 } 1068 1069 public void notifyZoomGestureEvent(int type, int modifiers, boolean isDirect, 1070 boolean isInertia, int originx, 1071 int originy, int originxAbs, 1072 int originyAbs, double scale, 1073 double expansion, double totalscale, 1074 double totalexpansion) { 1075 handleZoomGestureEvent(this, System.nanoTime(), type, modifiers, 1076 isDirect, isInertia, originx, originy, originxAbs, 1077 originyAbs, scale, expansion, totalscale, 1078 totalexpansion); 1079 } 1080 1081 public void notifyRotateGestureEvent(int type, int modifiers, 1082 boolean isDirect, boolean isInertia, 1083 int originx, int originy, 1084 int originxAbs, int originyAbs, 1085 double dangle, double totalangle) { 1086 handleRotateGestureEvent(this, System.nanoTime(), type, modifiers, 1087 isDirect, isInertia, originx, originy, 1088 originxAbs, originyAbs, dangle, totalangle); 1089 } 1090 1091 public void notifySwipeGestureEvent(int type, int modifiers, 1092 boolean isDirect, boolean isInertia, 1093 int touchCount, int dir, int originx, 1094 int originy, int originxAbs, 1095 int originyAbs) { 1096 handleSwipeGestureEvent(this, System.nanoTime(), type, modifiers, 1097 isDirect, isInertia, touchCount, dir, originx, 1098 originy, originxAbs, originyAbs); 1099 } 1100 1101 /** 1102 * Returns the accessible object for the view. 1103 * This method is called by JNI code when the 1104 * platform requested the accessible peer for the view. 1105 * On Windows it happens on WM_GETOBJECT. 1106 * On Mac it happens on NSView#accessibilityAttributeNames. 1107 */ 1108 long getAccessible() { 1109 Application.checkEventThread(); 1110 checkNotClosed(); 1111 if (accessible) { 1112 Accessible acc = eventHandler.getSceneAccessible(); 1113 if (acc != null) { 1114 acc.setView(this); 1115 return acc.getNativeAccessible(); 1116 } 1117 } 1118 return 0L; 1119 } 1120 }