1 /*
   2  * Copyright (c) 2012, 2014, 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 
  26 package com.sun.glass.ui.monocle;
  27 
  28 import com.sun.glass.events.MouseEvent;
  29 import com.sun.glass.events.ViewEvent;
  30 import com.sun.glass.events.WindowEvent;
  31 import com.sun.glass.ui.Application;
  32 import com.sun.glass.ui.Cursor;
  33 import com.sun.glass.ui.Pixels;
  34 import com.sun.glass.ui.Screen;
  35 import com.sun.glass.ui.View;
  36 import com.sun.glass.ui.Window;
  37 
  38 
  39 final class MonocleWindow extends Window {
  40 
  41 
  42     private static final int STATE_NORMAL = 0;
  43     private static final int STATE_MINIMIZED = 1;
  44     private static final int STATE_MAXIMIZED = 2;
  45     private static final int STATE_FULLSCREEN = 3;
  46 
  47     private int id;
  48     private int state;
  49     private int cachedX, cachedY, cachedW, cachedH;
  50     private int minW, minH;
  51     private int maxW = -1;
  52     private int maxH = -1;
  53 
  54     MonocleWindow(Window owner, Screen screen, int styleMask) {
  55         super(owner, screen, styleMask);
  56     }
  57 
  58     MonocleWindow(long parent) {
  59         super(parent);
  60     }
  61 
  62     @Override
  63     protected void _toFront(long ptr) {
  64         MonocleWindowManager.getInstance().toFront(this);
  65     }
  66 
  67     @Override
  68     protected void _toBack(long ptr) {
  69         MonocleWindowManager.getInstance().toBack(this);
  70 
  71     }
  72 
  73     /**
  74      *
  75      * w/h is the total window width/height including all its
  76      * decorations (e.g. title bar). cw/ch is the "client", or
  77      * interior width/height. Negative values for w/h/cw/ch are
  78      * treated as "not set". For example: setBounds(x, y, xSet,
  79      * ySet, 800, 600, -1, -1) will make the window 800x600 pixels.
  80      * The client area available for drawing will be smaller, e.g.
  81      * 792x580 - it depends on the window decorations on different
  82      * platforms. setBounds(x, y, xSet, ySet, -1, -1, 800, 600) will
  83      * make the window client size to be 800x600 pixels. The area
  84      * for drawing (FX scene size) will be exactly 800x600, but the
  85      * total window size including decorations will be slightly
  86      * bigger. For undecorated windows w/h and cw/ch are obviously
  87      * the same.
  88      *
  89      * As this is a void function the native code should trigger an
  90      * event to notify the system on actual change
  91      *
  92      */
  93     @Override
  94     protected void _setBounds(long nativeWindowPointer,
  95                               int x, int y, boolean xSet, boolean ySet,
  96                               int w, int h, int cw, int ch,
  97                               float xGravity, float yGravity) {
  98         int width;
  99         int height;
 100 
 101         if (w > 0) {
 102             //window width surpass window content width (cw)
 103             width = w;
 104         } else if (cw > 0) {
 105             //content width changed
 106             width = cw;
 107         } else {
 108             //no explicit request to change width, get default
 109             width = getWidth();
 110         }
 111 
 112         if (h > 0) {
 113             //window height surpass window content height(ch)
 114             height = h;
 115         } else if (cw > 0) {
 116             //content height changed
 117             height = ch;
 118         } else {
 119             //no explicit request to change height, get default
 120             height = getHeight();
 121         }
 122         if (!xSet) {
 123             x = getX();
 124         }
 125         if (!ySet) {
 126             y = getY();
 127         }
 128         if (maxW >= 0) {
 129             width = Math.min(width, maxW);
 130         }
 131         if (maxH >= 0) {
 132             height = Math.min(height, maxH);
 133         }
 134         width = Math.max(width, minW);
 135         height = Math.max(height, minH);
 136 
 137         notifyResizeAndMove(x, y, width, height);
 138     }
 139 
 140     private void notifyResizeAndMove(int x, int y, int width, int height) {
 141         MonocleView view = (MonocleView) getView();
 142         boolean repaintView = false;
 143 
 144         if (getWidth() != width || getHeight() != height) {
 145             notifyResize(WindowEvent.RESIZE, width, height);
 146             if (view != null) {
 147                 view.notifyResize(width, height);
 148                 repaintView = true;
 149             }
 150         }
 151         if (getX() != x || getY() != y) {
 152             notifyMove(x, y);
 153             if (view != null) {
 154                 repaintView = true;
 155             }
 156         }
 157         if (repaintView) {
 158             view.notifyRepaint();
 159         }
 160     }
 161 
 162     //creates the native window
 163     @Override
 164     protected long _createWindow(long NativeWindow, long NativeScreen,
 165                                  int mask) {
 166         id = MonocleWindowManager.getInstance().addWindow(this);
 167         return id;
 168     }
 169 
 170     @Override
 171     protected long _createChildWindow(long parent) {
 172         throw new UnsupportedOperationException();
 173     }
 174 
 175     @Override
 176     protected boolean _close(long nativeWindowPointer) {
 177         return MonocleWindowManager.getInstance().closeWindow(this);
 178     }
 179 
 180     @Override
 181     protected boolean _setView(long nativeWindowPointer, View view) {
 182         boolean result = true;
 183         if (view != null) {
 184             // the system assumes a resize notification to set the View
 185             // sizes and to get the Scene to layout correctly.
 186             ((MonocleView)view).notifyResize(getWidth(), getHeight());
 187         }
 188         return result;
 189     }
 190 
 191     /**
 192      * Returns the handle used to create a rendering context in Prism
 193      */
 194     @Override
 195     public long getNativeWindow() {
 196         return id;
 197     }
 198 
 199     @Override
 200     protected boolean _setMenubar(long ptr, long menubarPtr) {
 201         return true;
 202     }
 203 
 204     @Override
 205     protected boolean _minimize(long nativeWindowPointer, boolean minimize) {
 206         int x = getX();
 207         int y = getY();
 208         int width = getWidth();
 209         int height = getHeight();
 210         if (minimize && !(state == STATE_MINIMIZED)) {
 211             state = STATE_MINIMIZED;
 212             cachedX = x;
 213             cachedY = y;
 214             cachedW = width;
 215             cachedH = height;
 216             // remove the window from the list of visible windows in the
 217             // superclass
 218             remove(this);
 219             notifyResize(WindowEvent.MINIMIZE, width, height);
 220 
 221         } else if (!minimize && state == STATE_MINIMIZED) {
 222             state = STATE_NORMAL;
 223             x = cachedX;
 224             y = cachedY;
 225             width = cachedW;
 226             height = cachedH;
 227             // this call will add the window back into the visible list of
 228             // windows in the superclass
 229             add(this);
 230             notifyResize(WindowEvent.RESTORE, width, height);
 231         }
 232         return true;
 233     }
 234 
 235     @Override
 236     protected boolean _maximize(long nativeWindowPointer, boolean maximize,
 237                                 boolean wasMaximized) {
 238         NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen();
 239         int x = getX();
 240         int y = getY();
 241         int width = getWidth();
 242         int height = getHeight();
 243         if (maximize && !wasMaximized) {
 244             if (state == STATE_NORMAL) {
 245                 cachedX = x;
 246                 cachedY = y;
 247                 cachedW = width;
 248                 cachedH = height;
 249             }
 250             if (maxW >= 0) {
 251                 width = maxW;
 252                 x = Math.min(x, screen.getWidth() - width);
 253             } else {
 254                 x = 0;
 255                 width = screen.getWidth();
 256             }
 257             if (maxH >= 0) {
 258                 height = maxH;
 259                 y = Math.min(y, screen.getHeight() - height);
 260             } else {
 261                 y = 0;
 262                 height = screen.getHeight();
 263             }
 264             state = STATE_MAXIMIZED;
 265         } else if (!maximize && wasMaximized) {
 266             x = cachedX;
 267             y = cachedY;
 268             width = cachedW;
 269             height = cachedH;
 270             state = STATE_NORMAL;
 271         }
 272         notifyResizeAndMove(x, y, width, height);
 273         return true;
 274     }
 275 
 276     void setFullScreen(boolean fullscreen) {
 277         NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen();
 278         int x = getX();
 279         int y = getY();
 280         int width = getWidth();
 281         int height = getHeight();
 282         if (fullscreen) {
 283             if (state == STATE_NORMAL) {
 284                 cachedX = x;
 285                 cachedY = y;
 286                 cachedW = width;
 287                 cachedH = height;
 288             }
 289             x = 0;
 290             y = 0;
 291             width = screen.getWidth();
 292             height = screen.getHeight();
 293             MonocleView view = (MonocleView) getView();
 294             if (view != null) {
 295                 view.notifyView(ViewEvent.FULLSCREEN_ENTER);
 296             }
 297             state = STATE_FULLSCREEN;
 298         } else {
 299             x = cachedX;
 300             y = cachedY;
 301             width = cachedW;
 302             height = cachedH;
 303             MonocleView view = (MonocleView) getView();
 304             if (view != null) {
 305                 view.notifyView(ViewEvent.FULLSCREEN_EXIT);
 306             }
 307             state = STATE_NORMAL;
 308         }
 309         notifyResizeAndMove(x, y, width, height);
 310     }
 311 
 312     private float cachedAlpha = 1;
 313     @Override
 314     protected boolean _setVisible(long ptr, boolean visible) {
 315         if (visible) {
 316             setAlpha(cachedAlpha);
 317         } else {
 318             cachedAlpha = getAlpha();
 319             setAlpha(0);
 320         }
 321 
 322         return true;
 323     }
 324 
 325     @Override
 326     protected boolean _setResizable(long ptr, boolean resizable){
 327         return true;
 328     }
 329 
 330     @Override
 331     protected boolean _requestFocus(long ptr, int event) {
 332         return MonocleWindowManager.getInstance().requestFocus(this);
 333     }
 334 
 335     @Override
 336     protected void _setFocusable(long ptr, boolean isFocusable){}
 337 
 338     @Override
 339     protected boolean _setTitle(long ptr, String title) {
 340         return true;
 341     }
 342 
 343     @Override
 344     protected void _setLevel(long ptr, int level) {}
 345 
 346     @Override
 347     protected void _setAlpha(long ptr, float alpha) {}
 348 
 349     @Override
 350     protected boolean _setBackground(long ptr, float r, float g, float b) {
 351         return true;
 352     }
 353 
 354     @Override
 355     protected void _setEnabled(long ptr, boolean enabled){
 356         if (!enabled &&
 357             (this == MonocleWindowManager.getInstance().getFocusedWindow())) {
 358             MonocleView view = (MonocleView)getView();
 359             try {
 360                 view.notifyMouse(MouseEvent.EXIT, MouseEvent.BUTTON_NONE,
 361                         0, 0, 0, 0, 0, false, false);
 362             } catch (RuntimeException e) {
 363                 Application.reportException(e);
 364             }
 365         }
 366     }
 367 
 368     @Override
 369     protected boolean _setMinimumSize(long ptr, int width, int height) {
 370         minW = width;
 371         minH = height;
 372         return true;
 373     }
 374 
 375     @Override
 376     protected boolean _setMaximumSize(long ptr, int width, int height) {
 377         maxW = width;
 378         maxH = height;
 379         return true;
 380     }
 381 
 382     @Override
 383     protected void _setIcon(long ptr, Pixels pixels){}
 384 
 385     @Override
 386     protected boolean _grabFocus(long ptr) {
 387         return MonocleWindowManager.getInstance().grabFocus(this);
 388     }
 389 
 390     @Override
 391     protected void _ungrabFocus(long ptr) {
 392         MonocleWindowManager.getInstance().ungrabFocus(this);
 393     }
 394 
 395     /**
 396      * The functions below are used when the platform support modality natively.
 397      * Currently only GTK is using it. This functionality is disabled by
 398      * default. In order to enable it this class need to override Window::
 399      * supportsPlatformModality() to return true.
 400      *
 401      */
 402     @Override
 403     protected void _enterModal(long ptr) {
 404         throw new UnsupportedOperationException();
 405     }
 406 
 407     @Override
 408     protected void _enterModalWithWindow(long dialog, long window) {
 409         throw new UnsupportedOperationException();
 410     }
 411 
 412     @Override
 413     protected void _exitModal(long ptr) {
 414         throw new UnsupportedOperationException();
 415     }
 416 
 417     @Override
 418     protected void notifyClose() {
 419         super.notifyClose();
 420         close();
 421     }
 422 
 423     @Override
 424     protected void notifyDestroy() {
 425         super.notifyDestroy();
 426         MonocleWindowManager.getInstance().repaintAll();
 427     }
 428 
 429     @Override
 430     protected void notifyFocus(int event) {
 431         super.notifyFocus(event);
 432     }
 433 
 434     protected void _notifyFocusUngrab() {
 435         notifyFocusUngrab();
 436     }
 437 
 438     void _notifyFocusDisabled() {
 439         notifyFocusDisabled();
 440     }
 441 
 442     //**************************************************************
 443 
 444     @Override protected void _setCursor(long ptr, Cursor cursor) {
 445         ((MonocleCursor) cursor).applyCursor();
 446     }
 447 
 448     @Override protected int _getEmbeddedX(long ptr) {
 449         return 0;
 450     }
 451     @Override protected int _getEmbeddedY(long ptr) {
 452         return 0;
 453     }
 454 
 455     @Override
 456     protected void _requestInput(long ptr, String text, int type, double width, double height,
 457                                  double Mxx, double Mxy, double Mxz, double Mxt,
 458                                  double Myx, double Myy, double Myz, double Myt,
 459                                  double Mzx, double Mzy, double Mzz, double Mzt) {
 460         throw new UnsupportedOperationException("Not supported yet.");
 461     }
 462 
 463     @Override
 464     protected void _releaseInput(long ptr) {
 465         throw new UnsupportedOperationException("Not supported yet.");
 466     }
 467 
 468 }