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