1 /*
   2  * Copyright (c) 1996, 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 sun.awt.windows;
  26 
  27 import java.awt.*;
  28 import java.awt.peer.*;
  29 import sun.awt.AWTAccessor;
  30 import sun.awt.im.InputMethodManager;
  31 import java.security.AccessController;
  32 import sun.security.action.GetPropertyAction;
  33 
  34 class WFramePeer extends WWindowPeer implements FramePeer {
  35 
  36     static {
  37         initIDs();
  38     }
  39 
  40     // initialize JNI field and method IDs
  41     private static native void initIDs();
  42 
  43     // FramePeer implementation
  44     @Override
  45     public native void setState(int state);
  46     @Override
  47     public native int getState();
  48 
  49     // sync target and peer
  50     public void setExtendedState(int state) {
  51         AWTAccessor.getFrameAccessor().setExtendedState((Frame)target, state);
  52     }
  53     public int getExtendedState() {
  54         return AWTAccessor.getFrameAccessor().getExtendedState((Frame)target);
  55     }
  56 
  57     // Convenience methods to save us from trouble of extracting
  58     // Rectangle fields in native code.
  59     private native void setMaximizedBounds(int x, int y, int w, int h);
  60     private native void clearMaximizedBounds();
  61 
  62     private static final boolean keepOnMinimize = "true".equals(
  63         AccessController.doPrivileged(
  64             new GetPropertyAction(
  65             "sun.awt.keepWorkingSetOnMinimize")));
  66 
  67     @Override
  68     public void setMaximizedBounds(Rectangle b) {
  69         if (b == null) {
  70             clearMaximizedBounds();
  71         } else {
  72             Rectangle adjBounds = adjustMaximizedBounds(b);
  73             setMaximizedBounds(adjBounds.x, adjBounds.y, adjBounds.width, adjBounds.height);
  74         }
  75     }
  76 
  77     /**
  78      * The incoming bounds describe the maximized size and position of the
  79      * window on the monitor that displays the window. But the window manager
  80      * expects that the bounds are based on the size and position of the
  81      * primary monitor, even if the window ultimately maximizes onto a
  82      * secondary monitor. And the window manager adjusts these values to
  83      * compensate for differences between the primary monitor and the monitor
  84      * that displays the window.
  85      * The method translates the incoming bounds to the values acceptable
  86      * by the window manager. For more details, please refer to 6699851.
  87      */
  88     private Rectangle adjustMaximizedBounds(Rectangle b) {
  89         GraphicsConfiguration currentDevGC = getGraphicsConfiguration();
  90 
  91         GraphicsDevice primaryDev = GraphicsEnvironment
  92             .getLocalGraphicsEnvironment().getDefaultScreenDevice();
  93         GraphicsConfiguration primaryDevGC = primaryDev.getDefaultConfiguration();
  94 
  95         double scaleX = 1.0;
  96         double scaleY = 1.0;
  97 
  98         int ht = primaryDev.getDisplayMode().getHeight();
  99         int wt = primaryDev.getDisplayMode().getWidth();
 100 //        Rectangle fbc = currentDev.getFullScreenWindow().getBounds();
 101 
 102         if (currentDevGC != null && currentDevGC != primaryDevGC) {
 103             Rectangle currentDevBounds = currentDevGC.getBounds();
 104             Rectangle primaryDevBounds = primaryDevGC.getBounds();
 105 
 106             //scale the bounds for proper comparisions.
 107             scaleX = currentDevGC.getDefaultTransform().getScaleX();
 108             scaleY = currentDevGC.getDefaultTransform().getScaleY();
 109             currentDevBounds = scaleBounds(currentDevBounds, scaleX, scaleY);
 110             b = scaleBounds(b, scaleX, scaleY);
 111             Rectangle scaledPrimaryDevBounds = scaleBounds(primaryDevBounds, primaryDevGC.getDefaultTransform().getScaleX(),
 112                                             primaryDevGC.getDefaultTransform().getScaleY());
 113 
 114             //due to floating point operations, it could be possible in some
 115             //scenarios, that the width and height are slightly larger
 116             //than the maximum permissible values.
 117             if (b.width > currentDevBounds.width) {
 118                 b.width = currentDevBounds.width;
 119             }
 120 
 121             if (b.height > currentDevBounds.height) {
 122                 b.height = currentDevBounds.height;
 123             }
 124 
 125             //To maximize a window onto secondary screen, we still need to
 126             //provide the primary screen coordinates, and set the width
 127             //and height equal to primary screen bounds.
 128             if (scaledPrimaryDevBounds.width < currentDevBounds.width &&
 129                 b.width == currentDevBounds.width) {
 130                 b.width = primaryDevBounds.width;
 131             }
 132 
 133             if (scaledPrimaryDevBounds.height < currentDevBounds.height &&
 134                 b.height == currentDevBounds.height) {
 135                 b.height = primaryDevBounds.height;
 136             }
 137 
 138             if (b.x == currentDevBounds.x) {
 139                 b.x = primaryDevBounds.x;
 140             }
 141 
 142             if (b.y == currentDevBounds.y) {
 143                 b.y = primaryDevBounds.y;
 144             }
 145 
 146             return b;
 147         } else {
 148             scaleX = primaryDevGC.getDefaultTransform().getScaleX();
 149             scaleY = primaryDevGC.getDefaultTransform().getScaleY();
 150             return scaleBounds(b, scaleX, scaleY);
 151         }
 152     }
 153 
 154     private Rectangle scaleBounds(Rectangle source, double scaleX, double scaleY) {
 155         Rectangle res = (Rectangle)source.clone();
 156 
 157         if (scaleX > 1.0) {
 158             res.x = (int)(Math.ceil(source.x * scaleX));
 159             res.width =(int)(Math.ceil(source.width * scaleX));
 160         }
 161 
 162         if (scaleY > 1.0) {
 163             res.y = (int)(Math.ceil(source.y * scaleY));
 164             res.height = (int)(Math.ceil(source.height * scaleY));
 165         }
 166 
 167         return res;
 168     }
 169 
 170     @Override
 171     public boolean updateGraphicsData(GraphicsConfiguration gc) {
 172         boolean result = super.updateGraphicsData(gc);
 173         Rectangle bounds = AWTAccessor.getFrameAccessor().
 174                                getMaximizedBounds((Frame)target);
 175         if (bounds != null) {
 176             setMaximizedBounds(bounds);
 177         }
 178         return result;
 179     }
 180 
 181     @Override
 182     boolean isTargetUndecorated() {
 183         return ((Frame)target).isUndecorated();
 184     }
 185 
 186     @Override
 187     public void reshape(int x, int y, int width, int height) {
 188         if (((Frame)target).isUndecorated()) {
 189             super.reshape(x, y, width, height);
 190         } else {
 191             reshapeFrame(x, y, width, height);
 192         }
 193     }
 194 
 195     @Override
 196     public Dimension getMinimumSize() {
 197         Dimension d = new Dimension();
 198         if (!((Frame)target).isUndecorated()) {
 199             d.setSize(getSysMinWidth(), getSysMinHeight());
 200         }
 201         if (((Frame)target).getMenuBar() != null) {
 202             d.height += getSysMenuHeight();
 203         }
 204         return d;
 205     }
 206 
 207     // Note: Because this method calls resize(), which may be overridden
 208     // by client code, this method must not be executed on the toolkit
 209     // thread.
 210     @Override
 211     public void setMenuBar(MenuBar mb) {
 212         WMenuBarPeer mbPeer = (WMenuBarPeer) WToolkit.targetToPeer(mb);
 213         if (mbPeer != null) {
 214             if (mbPeer.framePeer != this) {
 215                 mb.removeNotify();
 216                 mb.addNotify();
 217                 mbPeer = (WMenuBarPeer) WToolkit.targetToPeer(mb);
 218                 if (mbPeer != null && mbPeer.framePeer != this) {
 219                     throw new IllegalStateException("Wrong parent peer");
 220                 }
 221             }
 222             if (mbPeer != null) {
 223                 addChildPeer(mbPeer);
 224             }
 225         }
 226         setMenuBar0(mbPeer);
 227         updateInsets(insets_);
 228     }
 229 
 230     // Note: Because this method calls resize(), which may be overridden
 231     // by client code, this method must not be executed on the toolkit
 232     // thread.
 233     private native void setMenuBar0(WMenuBarPeer mbPeer);
 234 
 235     // Toolkit & peer internals
 236 
 237     WFramePeer(Frame target) {
 238         super(target);
 239 
 240         InputMethodManager imm = InputMethodManager.getInstance();
 241         String menuString = imm.getTriggerMenuString();
 242         if (menuString != null)
 243         {
 244           pSetIMMOption(menuString);
 245         }
 246     }
 247 
 248     native void createAwtFrame(WComponentPeer parent);
 249     @Override
 250     void create(WComponentPeer parent) {
 251         preCreate(parent);
 252         createAwtFrame(parent);
 253     }
 254 
 255     @Override
 256     void initialize() {
 257         super.initialize();
 258 
 259         Frame target = (Frame)this.target;
 260 
 261         if (target.getTitle() != null) {
 262             setTitle(target.getTitle());
 263         }
 264         setResizable(target.isResizable());
 265         setState(target.getExtendedState());
 266     }
 267 
 268     private static native int getSysMenuHeight();
 269 
 270     native void pSetIMMOption(String option);
 271     void notifyIMMOptionChange(){
 272       InputMethodManager.getInstance().notifyChangeRequest((Component)target);
 273     }
 274 
 275     @Override
 276     public void setBoundsPrivate(int x, int y, int width, int height) {
 277         setBounds(x, y, width, height, SET_BOUNDS);
 278     }
 279     @Override
 280     public Rectangle getBoundsPrivate() {
 281         return getBounds();
 282     }
 283 
 284     // TODO: implement it in peers. WLightweightFramePeer may implement lw version.
 285     @Override
 286     public void emulateActivation(boolean activate) {
 287         synthesizeWmActivate(activate);
 288     }
 289 
 290     private native void synthesizeWmActivate(boolean activate);
 291 }