1 /* 2 * Copyright (c) 2010, 2013, 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.WindowEvent; 29 import com.sun.glass.ui.accessible.AccessibleRoot; 30 31 import java.util.Collections; 32 import java.util.LinkedList; 33 import java.util.List; 34 import java.util.Map; 35 36 public abstract class Window { 37 38 public static class EventHandler { 39 public void handleWindowEvent(Window window, long time, int type) { 40 } 41 42 /** 43 * Notifies a listener that the screen object for this Window instance 44 * has been updated. 45 * 46 * Note that while the old and new screen objects may be different, 47 * they can still represent the same physical screen. This can happen 48 * if e.g. only a certain parameter of the screen has been updated such 49 * as its scale factor. 50 * 51 * On some platforms when a window is moved to another physical screen 52 * an app can receive this event twice. One representing the physical 53 * screen change, and another - the display's parameters change. Note 54 * that sending two events instead of just one is platform-specific. 55 * 56 * The event handler can use the {@link Screen#getNativeScreen} method 57 * to determine if this is the same physical screen or not. If the 58 * native system always creates new native screen instances, there's no 59 * way for the app to distinguish between a real move to another screen 60 * or jsut a parameters update event. Since this is a somewhat rare 61 * event, an app is advised to always process it the same way. 62 * 63 * @see Window#getScreen 64 */ 65 public void handleScreenChangedEvent(Window window, long time, Screen oldScreen, Screen newScreen) { 66 } 67 } 68 69 // Native object handle (HWND, or NSWindow*, etc.) 70 private long ptr; 71 72 // 'Delegate window' ptr. Used in e.g. the Full Screen mode. 73 private volatile long delegatePtr = 0L; 74 75 // window list 76 static private final LinkedList<Window> visibleWindows = new LinkedList<Window>(); 77 // Return a list of all visible windows. Note that on platforms without a native window manager, 78 // this list will be sorted in proper z-order 79 static public synchronized List<Window> getWindows() { 80 Application.checkEventThread(); 81 return Collections.unmodifiableList(Window.visibleWindows); 82 } 83 84 // used by Lens Native 85 static private synchronized void add(Window window) { 86 Window.visibleWindows.add(window); 87 } 88 89 // used by Lens Native 90 static private synchronized void remove(Window window) { 91 Window.visibleWindows.remove(window); 92 } 93 94 // window style mask 95 96 // visual kind: mutually exclusive 97 public static final int UNTITLED = 0; 98 public static final int TITLED = 1 << 0; 99 public static final int TRANSPARENT = 1 << 1; 100 101 // functional type: mutually exclusive 102 /** 103 * Normal window. 104 * 105 * Usual top-level window. 106 */ 107 public static final int NORMAL = 0; 108 /** 109 * An utility window. 110 * 111 * Often used for floating toolbars. It has smaller than usual decorations 112 * and doesn't display a taskbar button. 113 */ 114 public static final int UTILITY = 1 << 2; 115 /** 116 * A popup window. 117 * 118 * Used to display popups (tooltips, popup menus, etc.) Note that by 119 * default it may display a task-bar button. To hide it the window must be 120 * owned. 121 */ 122 public static final int POPUP = 1 << 3; 123 124 // These affect window decorations as well as system menu actions, 125 // so applicable to both decorated and undecorated windows 126 public static final int CLOSABLE = 1 << 4; 127 public static final int MINIMIZABLE = 1 << 5; 128 public static final int MAXIMIZABLE = 1 << 6; 129 130 /** 131 * Indicates that the window trim will draw from right to left. 132 */ 133 public static final int RIGHT_TO_LEFT = 1 << 7; 134 135 /** 136 * Indicates that a window will have a client area textured the same way as the platform decorations 137 * and will not have a border between decorations and the client area. 138 * This is supported not on all platforms, the client should check if the feature is supported by using 139 * {@link com.sun.glass.ui.Application#supportsUnifiedWindows()} 140 */ 141 public static final int UNIFIED = 1 << 8; 142 143 final static private class State { 144 private static final int NORMAL = 1; 145 private static final int MINIMIZED = 2; 146 private static final int MAXIMIZED = 3; 147 } 148 149 /** 150 * Available window levels. 151 * 152 * Note that on some platforms both {@code FLOATING} and {@code TOPMOST} 153 * may represent the same window level. 154 * 155 * @see #setLevel 156 */ 157 public static final class Level { 158 private static final int _MIN = 1; 159 160 /** Normal window level. */ 161 public static final int NORMAL = 1; 162 163 /** A window level that is above all other NORMAL windows. */ 164 public static final int FLOATING = 2; 165 166 /** A very topmost window level. May cover system UI elements such as dock, taskbar, etc. */ 167 public static final int TOPMOST = 3; 168 169 private static final int _MAX = 3; 170 } 171 172 private final Window owner; 173 private final long parent; 174 private final int styleMask; 175 private final boolean isDecorated; 176 private boolean shouldStartUndecoratedMove = false; 177 178 private View view = null; 179 private Screen screen = null; 180 private MenuBar menubar = null; 181 private String title = ""; 182 private UndecoratedMoveResizeHelper helper = null; 183 184 private int state = State.NORMAL; 185 private int level = Level.NORMAL; 186 private int x = 0; 187 private int y = 0; 188 private int width = 0; 189 private int height = 0; 190 private float alpha = 1.0f; 191 192 // This is a workaround for RT-15970: as for embedded windows we don't 193 // receive any MOVE notifications from the native platform, we poll 194 // the window location on screen from timer and post synthetic events 195 // if it has changed 196 private Timer embeddedLocationTimer = null; 197 private int lastKnownEmbeddedX = 0; 198 private int lastKnownEmbeddedY = 0; 199 200 private volatile boolean isResizable = false; 201 private volatile boolean isVisible = false; 202 private volatile boolean isFocused = false; 203 private volatile boolean isFocusable = true; 204 private volatile boolean isModal = false; 205 206 // Indicates how many times setEnabled(false) has been called. 207 // A value of 0 means the window is enabled. 208 private volatile int disableCount = 0; 209 210 private int minimumWidth = 0, minimumHeight = 0; 211 private int maximumWidth = Integer.MAX_VALUE, maximumHeight = Integer.MAX_VALUE; 212 213 private EventHandler eventHandler; 214 215 protected abstract long _createWindow(long ownerPtr, long screenPtr, int mask); 216 protected Window(Window owner, Screen screen, int styleMask) { 217 Application.checkEventThread(); 218 switch (styleMask & (TITLED | TRANSPARENT)) { 219 case UNTITLED: 220 case TITLED: 221 case TRANSPARENT: 222 break; 223 default: 224 throw new RuntimeException("The visual kind should be UNTITLED, TITLED, or TRANSPARENT, but not a combination of these"); 225 } 226 switch (styleMask & (POPUP | UTILITY)) { 227 case NORMAL: 228 case POPUP: 229 case UTILITY: 230 break; 231 default: 232 throw new RuntimeException("The functional type should be NORMAL, POPUP, or UTILITY, but not a combination of these"); 233 } 234 235 if (((styleMask & UNIFIED) != 0) 236 && !Application.GetApplication().supportsUnifiedWindows()) { 237 styleMask &= ~UNIFIED; 238 } 239 240 if (((styleMask & TRANSPARENT) != 0) 241 && !Application.GetApplication().supportsTransparentWindows()) { 242 styleMask &= ~TRANSPARENT; 243 } 244 245 246 this.owner = owner; 247 this.parent = 0L; 248 this.styleMask = styleMask; 249 this.isDecorated = (this.styleMask & Window.TITLED) != 0; 250 251 this.screen = screen != null ? screen : Screen.getMainScreen(); 252 253 this.ptr = _createWindow(owner != null ? owner.getNativeHandle() : 0L, 254 this.screen.getNativeScreen(), this.styleMask); 255 if (this.ptr == 0L) { 256 throw new RuntimeException("could not create platform window"); 257 } 258 } 259 260 protected abstract long _createChildWindow(long parent); 261 /** 262 * Constructs a child window of the specified native parent window. 263 */ 264 protected Window(long parent) { 265 Application.checkEventThread(); 266 this.owner = null; 267 this.parent = parent; 268 this.styleMask = Window.UNTITLED; 269 this.isDecorated = false; 270 271 // Note: we can't always catch screen changes when parent is moved... 272 this.screen = null; // should infer from the parent 273 274 this.ptr = _createChildWindow(parent); 275 if (this.ptr == 0L) { 276 throw new RuntimeException("could not create platform window"); 277 } 278 } 279 280 public boolean isClosed() { 281 Application.checkEventThread(); 282 return this.ptr == 0L; 283 } 284 285 private void checkNotClosed() { 286 if (this.ptr == 0L) { 287 throw new IllegalStateException("The window has already been closed"); 288 } 289 } 290 291 protected abstract boolean _close(long ptr); 292 public void close() { 293 Application.checkEventThread(); 294 if (this.view != null) { 295 if (this.ptr != 0L) { 296 _setView(this.ptr, null); 297 } 298 this.view.setWindow(null); 299 this.view.close(); 300 this.view = null; 301 } 302 if (this.ptr != 0L) { 303 _close(this.ptr); 304 } 305 } 306 307 private boolean isChild() { 308 Application.checkEventThread(); 309 return this.parent != 0L; 310 } 311 312 /** This method returns "lowest-level" native window handle 313 * (HWND on Windows, NSWindow on Mac, X11 Window handle on linux-gtk etc.) 314 */ 315 public long getNativeWindow() { 316 Application.checkEventThread(); 317 checkNotClosed(); 318 return this.delegatePtr != 0L ? this.delegatePtr : this.ptr; 319 } 320 321 /** 322 * This method returns "higher-level" native window handle. 323 * glass-mat-lib-gtk GtkWindow.java returns GtkWindow pointer for example. 324 */ 325 public long getNativeHandle() { 326 Application.checkEventThread(); 327 return this.delegatePtr != 0L ? this.delegatePtr : this.ptr; 328 } 329 330 public Window getOwner() { 331 Application.checkEventThread(); 332 return this.owner; 333 } 334 335 public View getView() { 336 Application.checkEventThread(); 337 return this.view; 338 } 339 340 protected abstract boolean _setView(long ptr, View view); 341 public void setView(final View view) { 342 Application.checkEventThread(); 343 checkNotClosed(); 344 View oldView = getView(); 345 if (oldView == view) { 346 return; 347 } 348 349 if (oldView != null) { 350 oldView.setWindow(null); 351 } 352 if (view != null) { 353 Window host = view.getWindow(); 354 if (host != null) { 355 host.setView(null); 356 } 357 } 358 359 if (view != null && _setView(this.ptr, view)) { 360 this.view = view; 361 this.view.setWindow(this); 362 if (this.isDecorated == false) { 363 this.helper = new UndecoratedMoveResizeHelper(); 364 } 365 } else { 366 _setView(this.ptr, null); 367 this.view = null; 368 } 369 } 370 371 public Screen getScreen() { 372 Application.checkEventThread(); 373 return this.screen; 374 } 375 376 void setScreen(Screen screen) { 377 Application.checkEventThread(); 378 379 final Screen old = this.screen; 380 this.screen = screen; 381 382 if (this.eventHandler != null) { 383 //TODO: RT-31098 384 if (old != this.screen) { 385 this.eventHandler.handleScreenChangedEvent(this, System.nanoTime(), old, this.screen); 386 } 387 } 388 } 389 390 public int getStyleMask() { 391 Application.checkEventThread(); 392 return this.styleMask; 393 } 394 395 public MenuBar getMenuBar() { 396 Application.checkEventThread(); 397 return this.menubar; 398 } 399 400 protected abstract boolean _setMenubar(long ptr, long menubarPtr); 401 public void setMenuBar(final MenuBar menubar) { 402 Application.checkEventThread(); 403 checkNotClosed(); 404 if (_setMenubar(this.ptr, menubar.getNativeMenu())) { 405 this.menubar = menubar; 406 } 407 } 408 409 public boolean isDecorated() { 410 Application.checkEventThread(); 411 return this.isDecorated; 412 } 413 414 public boolean isMinimized() { 415 Application.checkEventThread(); 416 return (this.state == State.MINIMIZED); 417 } 418 419 protected abstract boolean _minimize(long ptr, boolean minimize); 420 public boolean minimize(final boolean minimize) { 421 Application.checkEventThread(); 422 checkNotClosed(); 423 _minimize(this.ptr, minimize); 424 //XXX: this is synchronous? On X11 this may not work 425 return isMinimized(); 426 } 427 428 public boolean isMaximized() { 429 Application.checkEventThread(); 430 return (this.state == State.MAXIMIZED); 431 } 432 433 protected abstract boolean _maximize(long ptr, boolean maximize, boolean wasMaximized); 434 public boolean maximize(final boolean maximize) { 435 Application.checkEventThread(); 436 checkNotClosed(); 437 _maximize(ptr, maximize, isMaximized()); 438 return isMaximized(); 439 } 440 441 protected abstract int _getEmbeddedX(long ptr); 442 protected abstract int _getEmbeddedY(long ptr); 443 444 private void checkScreenLocation() { 445 this.x = _getEmbeddedX(ptr); 446 this.y = _getEmbeddedY(ptr); 447 if ((this.x != lastKnownEmbeddedX) || (this.y != lastKnownEmbeddedY)) { 448 lastKnownEmbeddedX = this.x; 449 lastKnownEmbeddedY = this.y; 450 handleWindowEvent(System.nanoTime(), WindowEvent.MOVE); 451 } 452 } 453 454 public int getX() { 455 Application.checkEventThread(); 456 return this.x; 457 } 458 459 public int getY() { 460 Application.checkEventThread(); 461 return this.y; 462 } 463 464 public int getWidth() { 465 Application.checkEventThread(); 466 return this.width; 467 } 468 469 public int getHeight() { 470 Application.checkEventThread(); 471 return this.height; 472 } 473 474 protected abstract void _setBounds(long ptr, int x, int y, boolean xSet, boolean ySet, 475 int w, int h, int cw, int ch, 476 float xGravity, float yGravity); 477 478 /** 479 * Sets the window bounds to the specified values. 480 * 481 * Gravity values specify how to correct window location if only its size 482 * changes (for example when stage decorations are added). User initiated 483 * resizing should be ignored and must not influence window location through 484 * this mechanism. 485 * 486 * The corresponding correction formulas are: 487 * 488 * {@code x -= xGravity * deltaW} 489 * {@code y -= yGravity * deltaH} 490 * 491 * @param x the new window horizontal position, ignored if xSet is set to 492 * false 493 * @param y the new window vertical position, ignored if ySet is set to 494 * false 495 * @param xSet indicates whether the x parameter is valid 496 * @param ySet indicates whether the y parameter is valid 497 * @param w the new window width, ignored if set to -1 498 * @param h the new window height, ignored if set to -1 499 * @param cw the new window content width, ignored if set to -1 500 * @param ch the new window content height, ignored if set to -1 501 * @param xGravity the xGravity coefficient 502 * @param yGravity the yGravity coefficient 503 */ 504 public void setBounds(int x, int y, boolean xSet, boolean ySet, 505 int w, int h, int cw, int ch, 506 float xGravity, float yGravity) 507 { 508 Application.checkEventThread(); 509 checkNotClosed(); 510 _setBounds(ptr, x, y, xSet, ySet, w, h, cw, ch, xGravity, yGravity); 511 } 512 513 public void setPosition(int x, int y) { 514 Application.checkEventThread(); 515 setBounds(x, y, true, true, 0, 0, 0, 0, 0, 0); 516 } 517 518 public void setSize(int w, int h) { 519 Application.checkEventThread(); 520 setBounds(0, 0, false, false, w, h, 0, 0, 0, 0); 521 } 522 523 public void setContentSize(int cw, int ch) { 524 Application.checkEventThread(); 525 setBounds(0, 0, false, false, 0, 0, cw, ch, 0, 0); 526 } 527 528 public boolean isVisible() { 529 Application.checkEventThread(); 530 return this.isVisible; 531 } 532 533 /** 534 * Generates a ViewEvent.MOVE aka insets (might have) changed. 535 */ 536 private void synthesizeViewMoveEvent() { 537 final View view = getView(); 538 if (view != null) { 539 view.notifyView(com.sun.glass.events.ViewEvent.MOVE); 540 } 541 } 542 543 protected abstract boolean _setVisible(long ptr, boolean visible); 544 public void setVisible(final boolean visible) { 545 Application.checkEventThread(); 546 if (this.isVisible != visible) { 547 if (!visible) { 548 if (getView() != null) { 549 getView().setVisible(visible); 550 } 551 // Avoid native call if the window has been closed already 552 if (this.ptr != 0L) { 553 this.isVisible = _setVisible(this.ptr, visible); 554 } else { 555 this.isVisible = visible; 556 } 557 remove(this); 558 if (parent != 0) { 559 embeddedLocationTimer.stop(); 560 } 561 } else { 562 checkNotClosed(); 563 this.isVisible = _setVisible(this.ptr, visible); 564 565 if (getView() != null) { 566 getView().setVisible(this.isVisible); 567 } 568 add(this); 569 if (parent != 0) { 570 final Runnable checkRunnable = new Runnable() { 571 @Override 572 public void run() { 573 checkScreenLocation(); 574 } 575 }; 576 final Runnable timerRunnable = new Runnable() { 577 @Override 578 public void run() { 579 Application.invokeLater(checkRunnable); 580 } 581 }; 582 embeddedLocationTimer = 583 Application.GetApplication().createTimer(timerRunnable); 584 embeddedLocationTimer.start(16); 585 } 586 587 synthesizeViewMoveEvent(); 588 } 589 } 590 } 591 592 protected abstract boolean _setResizable(long ptr, boolean resizable); 593 public boolean setResizable(final boolean resizable) { 594 Application.checkEventThread(); 595 checkNotClosed(); 596 if (this.isResizable != resizable) { 597 if (_setResizable(this.ptr, resizable)) { 598 this.isResizable = resizable; 599 synthesizeViewMoveEvent(); 600 } 601 } 602 return isResizable; 603 } 604 605 public boolean isResizable() { 606 Application.checkEventThread(); 607 return this.isResizable; 608 } 609 610 public boolean isUnifiedWindow() { 611 //The UNIFIED flag is set only if it is supported 612 return (this.styleMask & Window.UNIFIED) != 0; 613 } 614 615 public boolean isTransparentWindow() { 616 //The TRANSPARENT flag is set only if it is supported 617 return (this.styleMask & Window.TRANSPARENT) != 0; 618 } 619 620 private static volatile Window focusedWindow = null; 621 public static Window getFocusedWindow() { 622 Application.checkEventThread(); 623 return Window.focusedWindow; 624 } 625 626 private static void setFocusedWindow(final Window window) { 627 Window.focusedWindow = window; 628 } 629 630 public boolean isFocused() { 631 Application.checkEventThread(); 632 return this.isFocused; 633 } 634 635 protected abstract boolean _requestFocus(long ptr, int event); 636 /** 637 * Requests or resigns focus on this window. 638 * 639 * If this is a top-level window (owned or not), then the only possible 640 * value for the {@code event} argument is WindowEvent.FOCUS_GAINED. 641 * Otherwise, if the window is a child window, the argument may be 642 * WindowEvent.FOCUS_LOST, FOCUS_GAINED, FOCUS_GAINED_FORWARD, or 643 * FOCUS_GAINED_BACKWARD. 644 * 645 * @param event one of WindowEvent.FOCUS_LOST, FOCUS_GAINED, FOCUS_GAINED_FORWARD, FOCUS_GAINED_BACKWARD 646 * 647 * @throws IllegalArgumentException if the argument value is invalid for this window 648 * 649 * @return {@code true} if the operation succeeded 650 */ 651 public boolean requestFocus(int event) { 652 Application.checkEventThread(); 653 checkNotClosed(); 654 655 if (!isChild() && event != WindowEvent.FOCUS_GAINED) { 656 throw new IllegalArgumentException("Invalid focus event ID for top-level window"); 657 } 658 659 if (isChild() && (event < WindowEvent._FOCUS_MIN || event > WindowEvent._FOCUS_MAX)) { 660 throw new IllegalArgumentException("Invalid focus event ID for child window"); 661 } 662 663 if (event == WindowEvent.FOCUS_LOST && !isFocused()) { 664 // Already unfocused, nothing to do 665 return true; 666 } 667 668 // At this point either A) the user requests focus for a focused or unfocused window, 669 // or B) the window is focused and the user requests FOCUS_LOST 670 if (!this.isFocusable) { 671 // It's obviously A). Fail. 672 return false; 673 } 674 675 return _requestFocus(this.ptr, event); 676 } 677 678 public boolean requestFocus() { 679 Application.checkEventThread(); 680 return requestFocus(WindowEvent.FOCUS_GAINED); 681 } 682 683 protected abstract void _setFocusable(long ptr, boolean isFocusable); 684 /** 685 * Sets whether this window is focusable. 686 * 687 * Clicking an unfocusable window doesn't activate it. 688 */ 689 public void setFocusable(final boolean isFocusable) { 690 Application.checkEventThread(); 691 checkNotClosed(); 692 this.isFocusable = isFocusable; 693 if (isEnabled()) { 694 _setFocusable(this.ptr, isFocusable); 695 } 696 } 697 698 protected abstract boolean _grabFocus(long ptr); 699 protected abstract void _ungrabFocus(long ptr); 700 /** 701 * Grabs focus on this window. 702 * 703 * All mouse clicks that occur in this window's client area or client-areas 704 * of any of its unfocusable owned windows are delivered as usual. Whenever 705 * a click occurs on another app's window (not related via the ownership 706 * relation with this one, or a focusable owned window), or on non-client 707 * area of any window (titlebar, etc.), or any third-party app's window, or 708 * native OS GUI (e.g. a taskbar), the grab is automatically reset, and the 709 * window that held the grab receives the FOCUS_UNGRAB event. 710 * 711 * Note that for this functionality to work correctly, the window must have 712 * a focus upon calling this method. All owned popup windows that should be 713 * operable during the grabbed focus state (e.g. nested popup menus) must 714 * be unfocusable (see {@link #setFocusable}). Clicking a focusable owned 715 * window will reset the grab due to a focus transfer. 716 * 717 * The click that occurs in another window and causes resetting of the grab 718 * may or may not be delivered to that other window depending on the native 719 * OS behavior. 720 * 721 * If any of the application's windows already holds the grab, it is reset 722 * prior to grabbing the focus for this window. The method may be called 723 * multiple times for one window. Subsequent calls do not affect the grab 724 * status unless it is reset between the calls, in which case the focus 725 * is grabbed again. 726 * 727 * Note that grabbing the focus on an application window may prevent 728 * delivering certain events to other applications until the grab is reset. 729 * Therefore, if the application has finished showing popup windows based 730 * on a user action (e.g. clicking a menu item), and doesn't require the 731 * grab any more, it should call the {@link #ungrabFocus} method. The 732 * FOCUS_UNGRAB event signals that the grab has been reset. 733 * 734 * A user event handler associated with a menu item must be invoked after 735 * resetting the grab. Otherwise, if a developer debugs the application and 736 * has installed a breakpoint in the event handler, the debugger may become 737 * unoperable due to events blocking for other applications on some 738 * platforms. 739 * 740 * @return {@code true} if the operation is successful 741 * @throws IllegalStateException if the window isn't focused currently 742 */ 743 public boolean grabFocus() { 744 Application.checkEventThread(); 745 checkNotClosed(); 746 747 if (!isFocused()) { 748 throw new IllegalStateException("The window must be focused when calling grabFocus()"); 749 } 750 751 return _grabFocus(this.ptr); 752 } 753 754 /** 755 * Manually ungrabs focus grabbed on this window previously. 756 * 757 * This method resets the grab, and forces sending of the FOCUS_UNGRAB 758 * event. It should be used when popup windows (such as menus) should be 759 * dismissed manually, e.g. when a user clicks a menu item which usually 760 * causes the menus to hide. 761 * 762 * @see #grabFocus 763 */ 764 public void ungrabFocus() { 765 Application.checkEventThread(); 766 checkNotClosed(); 767 _ungrabFocus(this.ptr); 768 } 769 770 public String getTitle() { 771 Application.checkEventThread(); 772 return this.title; 773 } 774 775 protected abstract boolean _setTitle(long ptr, String title); 776 public void setTitle(String title) { 777 Application.checkEventThread(); 778 checkNotClosed(); 779 if (title == null) { 780 title = ""; 781 } 782 if (!title.equals(this.title)) { 783 if (_setTitle(this.ptr, title)) { 784 this.title = title; 785 } 786 } 787 } 788 789 protected abstract void _setLevel(long ptr, int level); 790 /** 791 * Set the level of this window in the z-order. 792 * 793 * @param level one of the constants from {@link Window.Level} 794 * @see Window.Level 795 */ 796 public void setLevel(final int level) { 797 Application.checkEventThread(); 798 checkNotClosed(); 799 if (level < Level._MIN || level > Level._MAX) { 800 throw new IllegalArgumentException("Level should be in the range [" + Level._MIN + ".." + Level._MAX + "]"); 801 } 802 803 _setLevel(this.ptr, level); 804 805 this.level = level; 806 } 807 808 public int getLevel() { 809 Application.checkEventThread(); 810 return this.level; 811 } 812 813 private boolean isInFullscreen() { 814 final View view = getView(); 815 return view == null ? false : view.isInFullscreen(); 816 } 817 818 // Invoked from the View class before sending FULLSCREEN_ to the View.EventHandler 819 void notifyFullscreen(boolean entered) { 820 final float alpha = getAlpha(); 821 if (alpha < 1f) { 822 if (entered) { 823 // Reset alpha at native level 824 _setAlpha(this.ptr, 1f); 825 } else { 826 // restore the current opacity level 827 setAlpha(alpha); 828 } 829 } 830 } 831 832 protected abstract void _setAlpha(long ptr, float alpha); 833 /** 834 * Sets the uniform translucency level for this window. 835 * 836 * In the full screen mode the native window is always fully opaque. 837 * The requested opacity level is applied upon exiting the full screen 838 * mode only. 839 * 840 * @param alpha a value in the range [0..1f] (transparent..fully-opaque) 841 */ 842 public void setAlpha(final float alpha) { 843 Application.checkEventThread(); 844 checkNotClosed(); 845 if (alpha < 0f || alpha > 1f) { 846 throw new IllegalArgumentException("Alpha should be in the range [0f..1f]"); 847 } 848 849 this.alpha = alpha; 850 851 if (alpha < 1f && isInFullscreen()) { 852 return; 853 } 854 855 _setAlpha(this.ptr, this.alpha); 856 } 857 858 public float getAlpha() { 859 Application.checkEventThread(); 860 return this.alpha; 861 } 862 863 protected abstract boolean _setBackground(long ptr, float r, float g, float b); 864 /** 865 * Set the background of the window. 866 * 867 * In most cases the View covers the whole window, so the background color 868 * of the window is never seen by the user. However, a window w/o a view 869 * does display the background color in its content area. 870 * 871 * On some platforms setting the background color may produce flickering 872 * when painting the content area of the View (even though the View covers 873 * the whole window). Therefore it is recommended to set the background 874 * color to windows w/o views only. 875 */ 876 public boolean setBackground(final float r, final float g, final float b) { 877 Application.checkEventThread(); 878 checkNotClosed(); 879 return _setBackground(this.ptr, r, g, b); 880 } 881 882 public boolean isEnabled() { 883 Application.checkEventThread(); 884 return this.disableCount == 0; 885 } 886 887 protected abstract void _setEnabled(long ptr, boolean enabled); 888 /** 889 * Enables or disables the window. 890 * 891 * A disabled window is unfocusable by definition. 892 * Also, key or mouse events aren't generated for disabled windows. 893 * 894 * When a user tries to activate a disabled window, or the window gets 895 * accidentally brought to the top of the stacking order, the window 896 * generates the FOCUS_DISABLED window event. A Glass client should react 897 * to this event and bring the currently active modal blocker of the 898 * disabled window to top by calling blocker's minimize(false), toFront(), 899 * and requestFocus() methods. It may also 'blink' the blocker window to 900 * further attract user's attention. 901 * 902 * It's strongly recommended to process the FOCUS_DISABLED event 903 * synchronously and as fast as possible to avoid any possible visual and 904 * behavioral artifacts. Note that a disabled window may by no means gain 905 * the input focus. The purpose of this event is to make sure that the 906 * current modal blocker window is always visible to the user, and the user 907 * understands why he can't interact with a disabled window. 908 * 909 * The method supports nested calls. If you disable the window twice 910 * with two calls to setEnabled(false), you must call setEnabled(true) 911 * twice as well in order to enable it afterwards. This is to support 912 * 'nested' modal dialogs when one modal dialog opens another one. 913 */ 914 public void setEnabled(boolean enabled) { 915 Application.checkEventThread(); 916 checkNotClosed(); 917 if (!enabled) { 918 if (++this.disableCount > 1) { 919 // already disabled 920 return; 921 } 922 } else { 923 if (this.disableCount == 0) { 924 //should report a warning about an extra enable call ? 925 return; 926 } 927 if (--this.disableCount > 0) { 928 // not yet enabled 929 return; 930 } 931 } 932 933 //TODO: on Windows _setFocusable(this.ptr, isEnabled() ? this.isFocusable : false); 934 _setEnabled(this.ptr, isEnabled()); 935 } 936 937 public int getMinimumWidth() { 938 Application.checkEventThread(); 939 return this.minimumWidth; 940 } 941 942 public int getMinimumHeight() { 943 Application.checkEventThread(); 944 return this.minimumHeight; 945 } 946 947 public int getMaximumWidth() { 948 Application.checkEventThread(); 949 return this.maximumWidth; 950 } 951 952 public int getMaximumHeight() { 953 Application.checkEventThread(); 954 return this.maximumHeight; 955 } 956 957 protected abstract boolean _setMinimumSize(long ptr, int width, int height); 958 /** 959 * Sets the minimum size for this window. 960 * A value of zero indicates no restriction. 961 * If the native platform is unable to apply the constraints, 962 * the values returned by getMinimumWidth()/Height() won't change. 963 * 964 * @throws IllegalArgumentException if width or height < 0 965 */ 966 public void setMinimumSize(int width, int height) { 967 Application.checkEventThread(); 968 if (width < 0 || height < 0) { 969 throw new IllegalArgumentException("The width and height must be >= 0. Got: width=" + width + "; height=" + height); 970 } 971 checkNotClosed(); 972 if (_setMinimumSize(this.ptr, width, height)) { 973 this.minimumWidth = width; 974 this.minimumHeight = height; 975 } 976 } 977 978 protected abstract boolean _setMaximumSize(long ptr, int width, int height); 979 /** 980 * Sets the maximum size for this window. 981 * A value of {@code Integer.MAX_VALUE} indicates no restriction. 982 * If the native platform is unable to apply the constraints, 983 * the values returned by getMaximumWidth()/Height() won't change. 984 * 985 * @throws IllegalArgumentException if width or height < 0 986 */ 987 public void setMaximumSize(int width, int height) { 988 Application.checkEventThread(); 989 if (width < 0 || height < 0) { 990 throw new IllegalArgumentException("The width and height must be >= 0. Got: width=" + width + "; height=" + height); 991 } 992 checkNotClosed(); 993 if (_setMaximumSize(this.ptr, 994 // for easier handling in native: 995 width == Integer.MAX_VALUE ? -1 : width, 996 height == Integer.MAX_VALUE ? -1 : height)) 997 { 998 this.maximumWidth = width; 999 this.maximumHeight = height; 1000 } 1001 } 1002 1003 1004 protected abstract void _setIcon(long ptr, Pixels pixels); 1005 1006 // In the future we may want to pass a collection of Pixels, so that 1007 // the native platform could pick up the icon with the best dimensions 1008 public void setIcon(final Pixels pixels) { 1009 Application.checkEventThread(); 1010 checkNotClosed(); 1011 _setIcon(this.ptr, pixels); 1012 } 1013 1014 protected abstract void _setCursor(long ptr, Cursor cursor); 1015 1016 /** 1017 * Sets given cursor as the cursor for this window. 1018 * If the cursor is NONE, it is automatically hidden, 1019 * otherwise it is automatically shown. 1020 * @see Cursor#setVisible(boolean) 1021 */ 1022 public void setCursor(Cursor cursor) { 1023 Application.checkEventThread(); 1024 _setCursor(this.ptr, cursor); 1025 } 1026 1027 protected abstract void _toFront(long ptr); 1028 /** 1029 * Bring the window to front in the z-order. 1030 * This method DOES NOT activate the window. To make it active use 1031 * the requestFocus() method right after calling toFront(). 1032 */ 1033 public void toFront() { 1034 Application.checkEventThread(); 1035 checkNotClosed(); 1036 toFrontImpl(this, null); 1037 } 1038 1039 private void toFrontImpl(Window w, List<Window> list) { 1040 // for z-order stacking, pop the window 1041 // and push it on the end (closest Z) 1042 visibleWindows.remove(w); 1043 visibleWindows.add(w); 1044 _toFront(w.ptr); 1045 raiseOurOwnedWindows(w, list); 1046 } 1047 1048 private void raiseOurOwnedWindows(Window window, List<Window> list) { 1049 // owned windows should be maintained in front of the owner. 1050 if (list == null) { 1051 // get a single copy of the window list 1052 // copy is needed to avoid concurence issues with the iterator 1053 list = (List<Window>) Window.visibleWindows.clone(); 1054 } 1055 for(Window w: list) { 1056 if (window.equals(w.getOwner())) { 1057 toFrontImpl(w, list); 1058 } 1059 } 1060 } 1061 1062 protected abstract void _toBack(long ptr); 1063 /** 1064 * Send the window to the bottom of the stacking order. 1065 * This method may or may not de-focus this window 1066 * depending on the native platform. To make sure some other 1067 * window is activated, call requestFocus() on that other window. 1068 */ 1069 public void toBack() { 1070 Application.checkEventThread(); 1071 checkNotClosed(); 1072 // for z-order stacking, pop the window 1073 // and push it on the head (farthest Z) 1074 visibleWindows.remove(this); 1075 visibleWindows.addFirst(this); 1076 _toBack(this.ptr); 1077 } 1078 1079 // ***************************************************** 1080 // modality (prototype using native platform feature) 1081 // ***************************************************** 1082 protected abstract void _enterModal(long ptr); 1083 /** 1084 * Enter modal state blocking everything except our window. 1085 */ 1086 public void enterModal() { 1087 checkNotClosed(); 1088 if (this.isModal == false) { 1089 this.isModal = true; 1090 _enterModal(this.ptr); 1091 } 1092 } 1093 1094 protected abstract void _enterModalWithWindow(long dialog, long window); 1095 /** 1096 * Enter modal state only blocking the given window. 1097 * On Mac OS X this is done using a dialog sheet. 1098 */ 1099 public void enterModal(final Window window) { 1100 checkNotClosed(); 1101 if (this.isModal == false) { 1102 this.isModal = true; 1103 _enterModalWithWindow(this.ptr, window.getNativeHandle()); 1104 } 1105 } 1106 1107 protected abstract void _exitModal(long ptr); 1108 public void exitModal() { 1109 checkNotClosed(); 1110 if (this.isModal == true) { 1111 _exitModal(this.ptr); 1112 this.isModal = false; 1113 } 1114 } 1115 1116 public boolean isModal() { 1117 return this.isModal; 1118 } 1119 1120 /** Only used on Mac when run inside a plugin */ 1121 public void dispatchNpapiEvent(Map eventInfo) { 1122 Application.checkEventThread(); 1123 throw new RuntimeException("This operation is not supported on this platform"); 1124 } 1125 1126 public EventHandler getEventHandler() { 1127 Application.checkEventThread(); 1128 return eventHandler; 1129 } 1130 1131 public void setEventHandler(EventHandler eventHandler) { 1132 Application.checkEventThread(); 1133 this.eventHandler = eventHandler; 1134 } 1135 1136 /** 1137 * Enables unconditional start of window move operation when 1138 * mouse is dragged in the client area. 1139 */ 1140 public void setShouldStartUndecoratedMove(boolean v) { 1141 Application.checkEventThread(); 1142 this.shouldStartUndecoratedMove = v; 1143 } 1144 1145 // ***************************************************** 1146 // notification callbacks 1147 // ***************************************************** 1148 protected void notifyClose() { 1149 handleWindowEvent(System.nanoTime(), WindowEvent.CLOSE); 1150 } 1151 1152 protected void notifyDestroy() { 1153 // Mac is known to send multiple WillClose notifications for some reason 1154 if (this.ptr == 0) { 1155 return; 1156 } 1157 1158 handleWindowEvent(System.nanoTime(), WindowEvent.DESTROY); 1159 1160 this.ptr = 0; 1161 1162 // Do this after setting ptr to 0 to avoid a call to _setVisible() 1163 setVisible(false); 1164 } 1165 1166 protected void notifyMove(final int x, final int y) { 1167 this.x = x; 1168 this.y = y; 1169 handleWindowEvent(System.nanoTime(), WindowEvent.MOVE); 1170 } 1171 1172 protected void notifyMoveToAnotherScreen(long fromScreenPtr, long toScreenPtr) { 1173 setScreen(Screen.getScreenForPtr(toScreenPtr)); 1174 } 1175 1176 /** 1177 * type values: 1178 * - WindowEvent.RESIZE 1179 * - WindowEvent.MINIMIZE 1180 * - WindowEvent.MAXIMIZE 1181 * - WindowEvent.RESTORE 1182 */ 1183 protected void notifyResize(final int type, final int width, final int height) { 1184 if (type == WindowEvent.MINIMIZE) { 1185 this.state = State.MINIMIZED; 1186 } else { 1187 if (type == WindowEvent.MAXIMIZE) { 1188 this.state = State.MAXIMIZED; 1189 } else { // WindowEvent.RESIZE or WindowEvent.RESTORE 1190 this.state = State.NORMAL; 1191 } 1192 this.width = width; 1193 this.height = height; 1194 1195 // update moveRect/resizeRect 1196 if (this.helper != null){ 1197 this.helper.updateRectangles(); 1198 } 1199 } 1200 handleWindowEvent(System.nanoTime(), type); 1201 1202 /* 1203 * Send RESIZE notification as MAXIMIZE and RESTORE change the window size 1204 */ 1205 if (type == WindowEvent.MAXIMIZE || type == WindowEvent.RESTORE) { 1206 handleWindowEvent(System.nanoTime(), WindowEvent.RESIZE); 1207 } 1208 } 1209 1210 protected void notifyFocus(int event) { 1211 final boolean focused = event != WindowEvent.FOCUS_LOST; 1212 1213 if (this.isFocused != focused) { 1214 this.isFocused = focused; 1215 if (this.isFocused) { 1216 setFocusedWindow(this); 1217 } else { 1218 setFocusedWindow(null); 1219 } 1220 handleWindowEvent(System.nanoTime(), event); 1221 } 1222 } 1223 1224 protected void notifyFocusDisabled() { 1225 handleWindowEvent(System.nanoTime(), WindowEvent.FOCUS_DISABLED); 1226 } 1227 1228 protected void notifyFocusUngrab() { 1229 handleWindowEvent(System.nanoTime(), WindowEvent.FOCUS_UNGRAB); 1230 } 1231 1232 protected void notifyDelegatePtr(long ptr) { 1233 this.delegatePtr = ptr; 1234 } 1235 1236 protected void notifyInitAccessibility() { 1237 handleWindowEvent(System.nanoTime(), WindowEvent.INIT_ACCESSIBILITY); 1238 } 1239 1240 // ***************************************************** 1241 // window event handlers 1242 // ***************************************************** 1243 private void handleWindowEvent(long time, int type) { 1244 if (this.eventHandler != null) { 1245 this.eventHandler.handleWindowEvent(this, time, type); 1246 } 1247 } 1248 1249 /* 1250 * Notify the native code that the accessibilty tree has been built and is 1251 * ready for use. 1252 * 1253 * @param accRoot the Java side accessible root object. 1254 */ 1255 public void setAccessibilityInitIsComplete(AccessibleRoot accRoot) { 1256 Application.checkEventThread(); 1257 accRoot.setAccessibilityInitIsComplete(); 1258 } 1259 1260 // ***************************************************** 1261 // programmatical move/resize 1262 // ***************************************************** 1263 /** Sets "programmatical move" rectangle. 1264 * The rectangle is measured from top of the View: 1265 * width is View.width, height is size. 1266 * 1267 * throws RuntimeException for decorated window. 1268 */ 1269 public void setUndecoratedMoveRectangle(int size) { 1270 Application.checkEventThread(); 1271 if (this.isDecorated == true) { 1272 //throw new RuntimeException("setUndecoratedMoveRectangle is only valid for Undecorated Window"); 1273 System.err.println("Glass Window.setUndecoratedMoveRectangle is only valid for Undecorated Window. In the future this will be hard error."); 1274 Thread.dumpStack(); 1275 return; 1276 } 1277 1278 if (this.helper != null) { 1279 this.helper.setMoveRectangle(size); 1280 } 1281 } 1282 /** The method called only for undecorated windows 1283 * x, y: mouse coordinates (in View space). 1284 * 1285 * throws RuntimeException for decorated window. 1286 */ 1287 public boolean shouldStartUndecoratedMove(final int x, final int y) { 1288 Application.checkEventThread(); 1289 if (this.shouldStartUndecoratedMove == true) { 1290 return true; 1291 } 1292 if (this.isDecorated == true) { 1293 return false; 1294 } 1295 1296 if (this.helper != null) { 1297 return this.helper.shouldStartMove(x, y); 1298 } else { 1299 return false; 1300 } 1301 } 1302 1303 /** Sets "programmatical resize" rectangle. 1304 * The rectangle is measured from top of the View: 1305 * width is View.width, height is size. 1306 * 1307 * throws RuntimeException for decorated window. 1308 */ 1309 public void setUndecoratedResizeRectangle(int size) { 1310 Application.checkEventThread(); 1311 if ((this.isDecorated == true) || (this.isResizable == false)) { 1312 //throw new RuntimeException("setUndecoratedMoveRectangle is only valid for Undecorated Resizable Window"); 1313 System.err.println("Glass Window.setUndecoratedResizeRectangle is only valid for Undecorated Resizable Window. In the future this will be hard error."); 1314 Thread.dumpStack(); 1315 return; 1316 } 1317 1318 if (this.helper != null) { 1319 this.helper.setResizeRectangle(size); 1320 } 1321 } 1322 1323 /** The method called only for undecorated windows 1324 * x, y: mouse coordinates (in View space). 1325 * 1326 * throws RuntimeException for decorated window. 1327 */ 1328 public boolean shouldStartUndecoratedResize(final int x, final int y) { 1329 Application.checkEventThread(); 1330 if ((this.isDecorated == true) || (this.isResizable == false)) { 1331 return false; 1332 } 1333 1334 if (this.helper != null) { 1335 return this.helper.shouldStartResize(x, y); 1336 } else { 1337 return false; 1338 } 1339 } 1340 1341 /** Mouse event handler for processing programmatical resize/move 1342 * (for undecorated windows only). 1343 * Must be called by View. 1344 * x & y are View coordinates. 1345 * NOTE: it's package private! 1346 * @return true if the event is processed by the window, 1347 * false if it has to be delivered to the app 1348 */ 1349 boolean handleMouseEvent(int type, int button, int x, int y, int xAbs, int yAbs) { 1350 if (this.isDecorated == false) { 1351 return this.helper.handleMouseEvent(type, button, x, y, xAbs, yAbs); 1352 } 1353 return false; 1354 } 1355 1356 @Override 1357 public String toString() { 1358 Application.checkEventThread(); 1359 return "Window:"+"\n" 1360 + " ptr: " + getNativeWindow() + "\n" 1361 + " screen ptr: " + (screen != null ? screen.getNativeScreen() : "null") + "\n" 1362 + " isDecorated: " + isDecorated() + "\n" 1363 + " title: " + getTitle() + "\n" 1364 + " visible: " + isVisible() + "\n" 1365 + " focused: " + isFocused() + "\n" 1366 + " modal: " + isModal() + "\n" 1367 + " state: " + state + "\n" 1368 + " x: " + getX() + ", y: " + getY() + ", w: " + getWidth() + ", h: " + getHeight() + "\n" 1369 + ""; 1370 } 1371 1372 // "programmical" move/resize support for undecorated windows 1373 1374 static private class TrackingRectangle { 1375 int size = 0; 1376 int x = 0, y = 0, width = 0, height = 0; 1377 boolean contains(final int x, final int y) { 1378 return ((size > 0) && 1379 (x >= this.x) && (x < (this.x + this.width)) && 1380 (y >= this.y) && (y < (this.y + this.height))); 1381 } 1382 } 1383 1384 private class UndecoratedMoveResizeHelper { 1385 TrackingRectangle moveRect = null; 1386 TrackingRectangle resizeRect = null; 1387 1388 boolean inMove = false; // we are in "move" mode 1389 boolean inResize = false; // we are in "resize" mode 1390 1391 int startMouseX, startMouseY; // start mouse coords 1392 int startX, startY; // start window location (for move) 1393 int startWidth, startHeight; // start window size (for resize) 1394 1395 UndecoratedMoveResizeHelper() { 1396 this.moveRect = new TrackingRectangle(); 1397 this.resizeRect = new TrackingRectangle(); 1398 } 1399 1400 void setMoveRectangle(final int size) { 1401 this.moveRect.size = size; 1402 1403 this.moveRect.x = 0; 1404 this.moveRect.y = 0; 1405 this.moveRect.width = getWidth(); 1406 this.moveRect.height = this.moveRect.size; 1407 } 1408 1409 boolean shouldStartMove(final int x, final int y) { 1410 return this.moveRect.contains(x, y); 1411 } 1412 1413 boolean inMove() { 1414 return this.inMove; 1415 } 1416 1417 void startMove(final int x, final int y) { 1418 this.inMove = true; 1419 1420 this.startMouseX = x; 1421 this.startMouseY = y; 1422 1423 this.startX = getX(); 1424 this.startY = getY(); 1425 } 1426 1427 void deltaMove(final int x, final int y) { 1428 int deltaX = x - this.startMouseX; 1429 int deltaY = y - this.startMouseY; 1430 1431 setPosition(this.startX + deltaX, this.startY + deltaY); 1432 } 1433 1434 void stopMove() { 1435 this.inMove = false; 1436 } 1437 1438 void setResizeRectangle(final int size) { 1439 this.resizeRect.size = size; 1440 1441 // set the rect (bottom right corner of the Window) 1442 this.resizeRect.x = getWidth() - this.resizeRect.size; 1443 this.resizeRect.y = getHeight() - this.resizeRect.size; 1444 this.resizeRect.width = this.resizeRect.size; 1445 this.resizeRect.height = this.resizeRect.size; 1446 } 1447 1448 boolean shouldStartResize(final int x, final int y) { 1449 return this.resizeRect.contains(x, y); 1450 } 1451 1452 boolean inResize() { 1453 return this.inResize; 1454 } 1455 1456 void startResize(final int x, final int y) { 1457 this.inResize = true; 1458 1459 this.startMouseX = x; 1460 this.startMouseY = y; 1461 1462 this.startWidth = getWidth(); 1463 this.startHeight = getHeight(); 1464 } 1465 1466 void deltaResize(final int x, final int y) { 1467 int deltaX = x - this.startMouseX; 1468 int deltaY = y - this.startMouseY; 1469 1470 setSize(this.startWidth + deltaX, this.startHeight + deltaY); 1471 } 1472 1473 protected void stopResize() { 1474 this.inResize = false; 1475 } 1476 1477 void updateRectangles() { 1478 if (this.moveRect.size > 0) { 1479 setMoveRectangle(this.moveRect.size); 1480 } 1481 if (this.resizeRect.size > 0) { 1482 setResizeRectangle(this.resizeRect.size); 1483 } 1484 } 1485 1486 boolean handleMouseEvent(final int type, final int button, final int x, final int y, final int xAbs, final int yAbs) { 1487 switch (type) { 1488 case MouseEvent.DOWN: 1489 if (button == MouseEvent.BUTTON_LEFT) { 1490 if (shouldStartUndecoratedMove(x, y) == true) { 1491 startMove(xAbs, yAbs); 1492 return true; 1493 } else if (shouldStartUndecoratedResize(x, y) == true) { 1494 startResize(xAbs, yAbs); 1495 return true; 1496 } 1497 } 1498 break; 1499 1500 case MouseEvent.MOVE: 1501 case MouseEvent.DRAG: 1502 if (inMove() == true) { 1503 deltaMove(xAbs, yAbs); 1504 return true; 1505 } else if (inResize() == true) { 1506 deltaResize(xAbs, yAbs); 1507 return true; 1508 } 1509 break; 1510 1511 case MouseEvent.UP: 1512 boolean wasProcessed = inMove() || inResize(); 1513 stopResize(); 1514 stopMove(); 1515 return wasProcessed; 1516 } 1517 return false; 1518 } 1519 } 1520 1521 /** 1522 * Requests text input in form of native keyboard for text component 1523 * contained by this Window. Native text input component is drawn on the place 1524 * of JavaFX component to cover it completely and to provide native text editing 1525 * techniques. Any change of text is immediately reflected in JavaFX text component. 1526 * 1527 * @param text text to be shown in the native text input component 1528 * @param type type of text input component @see com.sun.javafx.scene.control.behavior.TextInputTypes 1529 * @param width width of JavaFX text input component 1530 * @param height height of JavaFX text input component 1531 * @param M standard transformation matrix for drawing the native text component derived from JavaFX component 1532 */ 1533 public void requestInput(String text, int type, double width, double height, 1534 double Mxx, double Mxy, double Mxz, double Mxt, 1535 double Myx, double Myy, double Myz, double Myt, 1536 double Mzx, double Mzy, double Mzz, double Mzt) { 1537 Application.checkEventThread(); 1538 _requestInput(this.ptr, text, type, width, height, 1539 Mxx, Mxy, Mxz, Mxt, 1540 Myx, Myy, Myz, Myt, 1541 Mzx, Mzy, Mzz, Mzt); 1542 } 1543 1544 /** 1545 * Native keyboard for text input is no longer necessary. 1546 * Keyboard will be hidden and native text input component too. 1547 */ 1548 public void releaseInput() { 1549 Application.checkEventThread(); 1550 _releaseInput(this.ptr); 1551 } 1552 1553 protected abstract void _requestInput(long ptr, String text, int type, double width, double height, 1554 double Mxx, double Mxy, double Mxz, double Mxt, 1555 double Myx, double Myy, double Myz, double Myt, 1556 double Mzx, double Mzy, double Mzz, double Mzt); 1557 1558 protected abstract void _releaseInput(long ptr); 1559 1560 }