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