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