1 /* 2 * Copyright (c) 1996, 2020, 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 sun.awt.windows; 27 28 import java.awt.Component; 29 import java.awt.Dimension; 30 import java.awt.Frame; 31 import java.awt.GraphicsConfiguration; 32 import java.awt.MenuBar; 33 import java.awt.Rectangle; 34 import java.awt.peer.FramePeer; 35 import java.security.AccessController; 36 37 import sun.awt.AWTAccessor; 38 import sun.awt.im.InputMethodManager; 39 import sun.security.action.GetPropertyAction; 40 41 import static sun.java2d.SunGraphicsEnvironment.convertToDeviceSpace; 42 43 class WFramePeer extends WWindowPeer implements FramePeer { 44 45 static { 46 initIDs(); 47 } 48 49 // initialize JNI field and method IDs 50 private static native void initIDs(); 51 52 // FramePeer implementation 53 @Override 54 public native void setState(int state); 55 @Override 56 public native int getState(); 57 58 // sync target and peer 59 public void setExtendedState(int state) { 60 AWTAccessor.getFrameAccessor().setExtendedState((Frame)target, state); 61 } 62 public int getExtendedState() { 63 return AWTAccessor.getFrameAccessor().getExtendedState((Frame)target); 64 } 65 66 // Convenience methods to save us from trouble of extracting 67 // Rectangle fields in native code. 68 private native void setMaximizedBounds(int x, int y, int w, int h); 69 private native void clearMaximizedBounds(); 70 71 private static final boolean keepOnMinimize = "true".equals( 72 AccessController.doPrivileged( 73 new GetPropertyAction( 74 "sun.awt.keepWorkingSetOnMinimize"))); 75 76 @Override 77 public final void setMaximizedBounds(Rectangle b) { 78 if (b == null) { 79 clearMaximizedBounds(); 80 } else { 81 b = adjustMaximizedBounds(b); 82 setMaximizedBounds(b.x, b.y, b.width, b.height); 83 } 84 } 85 86 /** 87 * The incoming bounds describe the maximized size and position of the 88 * window in the virtual coordinate system. But the window manager expects 89 * that the bounds are based on the size of the primary monitor and 90 * position is based on the actual window monitor, even if the window 91 * ultimately maximizes onto a secondary monitor. And the window manager 92 * adjusts these values to compensate for differences between the primary 93 * monitor and the monitor that displays the window. 94 * <p> 95 * The method translates the incoming bounds to the values acceptable 96 * by the window manager. For more details, please refer to 6699851. 97 */ 98 private Rectangle adjustMaximizedBounds(Rectangle bounds) { 99 // All calculations should be done in the device space 100 bounds = convertToDeviceSpace(bounds); 101 102 GraphicsConfiguration gc = getGraphicsConfiguration(); 103 Rectangle currentDevBounds = convertToDeviceSpace(gc, gc.getBounds()); 104 // Prepare data for WM_GETMINMAXINFO message. 105 // ptMaxPosition should be in coordinate system of the current monitor, 106 // not the main monitor, or monitor on which we maximize the window. 107 bounds.x -= currentDevBounds.x; 108 bounds.y -= currentDevBounds.y; 109 // ptMaxSize will be used as-is if the size is smaller than the main 110 // monitor. If the size is larger than the main monitor then the 111 // window manager adjusts the size, like this: 112 // result = bounds.w + (current.w - main.w); =>> wrong size 113 // We can try to compensate for this adjustment like this: 114 // result = bounds.w - (current.w - main.w); 115 // but this can result to the size smaller than the main screen, so no 116 // adjustment will be done by the window manager =>> wrong size. 117 // So we skip compensation here and cut the adjustment on 118 // WM_WINDOWPOSCHANGING event. 119 // Note that the result does not depend on the monitor on which we 120 // maximize the window. 121 return bounds; 122 } 123 124 @Override 125 public boolean updateGraphicsData(GraphicsConfiguration gc) { 126 boolean result = super.updateGraphicsData(gc); 127 Rectangle bounds = AWTAccessor.getFrameAccessor(). 128 getMaximizedBounds((Frame)target); 129 if (bounds != null) { 130 setMaximizedBounds(bounds); 131 } 132 return result; 133 } 134 135 @Override 136 boolean isTargetUndecorated() { 137 return ((Frame)target).isUndecorated(); 138 } 139 140 @Override 141 public void reshape(int x, int y, int width, int height) { 142 if (((Frame)target).isUndecorated()) { 143 super.reshape(x, y, width, height); 144 } else { 145 reshapeFrame(x, y, width, height); 146 } 147 } 148 149 @Override 150 public Dimension getMinimumSize() { 151 Dimension d = new Dimension(); 152 if (!((Frame)target).isUndecorated()) { 153 d.setSize(getSysMinWidth(), getSysMinHeight()); 154 } 155 if (((Frame)target).getMenuBar() != null) { 156 d.height += getSysMenuHeight(); 157 } 158 return d; 159 } 160 161 // Note: Because this method calls resize(), which may be overridden 162 // by client code, this method must not be executed on the toolkit 163 // thread. 164 @Override 165 public void setMenuBar(MenuBar mb) { 166 WMenuBarPeer mbPeer = (WMenuBarPeer) WToolkit.targetToPeer(mb); 167 if (mbPeer != null) { 168 if (mbPeer.framePeer != this) { 169 mb.removeNotify(); 170 mb.addNotify(); 171 mbPeer = (WMenuBarPeer) WToolkit.targetToPeer(mb); 172 if (mbPeer != null && mbPeer.framePeer != this) { 173 throw new IllegalStateException("Wrong parent peer"); 174 } 175 } 176 if (mbPeer != null) { 177 addChildPeer(mbPeer); 178 } 179 } 180 setMenuBar0(mbPeer); 181 updateInsets(insets_); 182 } 183 184 // Note: Because this method calls resize(), which may be overridden 185 // by client code, this method must not be executed on the toolkit 186 // thread. 187 private native void setMenuBar0(WMenuBarPeer mbPeer); 188 189 // Toolkit & peer internals 190 191 WFramePeer(Frame target) { 192 super(target); 193 194 InputMethodManager imm = InputMethodManager.getInstance(); 195 String menuString = imm.getTriggerMenuString(); 196 if (menuString != null) 197 { 198 pSetIMMOption(menuString); 199 } 200 } 201 202 native void createAwtFrame(WComponentPeer parent); 203 @Override 204 void create(WComponentPeer parent) { 205 preCreate(parent); 206 createAwtFrame(parent); 207 } 208 209 @Override 210 void initialize() { 211 super.initialize(); 212 213 Frame target = (Frame)this.target; 214 215 if (target.getTitle() != null) { 216 setTitle(target.getTitle()); 217 } 218 setResizable(target.isResizable()); 219 setState(target.getExtendedState()); 220 } 221 222 private static native int getSysMenuHeight(); 223 224 native void pSetIMMOption(String option); 225 void notifyIMMOptionChange(){ 226 InputMethodManager.getInstance().notifyChangeRequest((Component)target); 227 } 228 229 @Override 230 public void setBoundsPrivate(int x, int y, int width, int height) { 231 setBounds(x, y, width, height, SET_BOUNDS); 232 } 233 @Override 234 public Rectangle getBoundsPrivate() { 235 return getBounds(); 236 } 237 238 // TODO: implement it in peers. WLightweightFramePeer may implement lw version. 239 @Override 240 public void emulateActivation(boolean activate) { 241 synthesizeWmActivate(activate); 242 } 243 244 private native void synthesizeWmActivate(boolean activate); 245 }