1 /* 2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.awt.windows; 26 27 import java.awt.*; 28 import java.awt.event.AdjustmentEvent; 29 import java.awt.peer.ScrollPanePeer; 30 31 import sun.awt.AWTAccessor; 32 import sun.awt.AWTAccessor.ComponentAccessor; 33 import sun.awt.PeerEvent; 34 35 import sun.util.logging.PlatformLogger; 36 37 final class WScrollPanePeer extends WPanelPeer implements ScrollPanePeer { 38 39 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WScrollPanePeer"); 40 41 int scrollbarWidth; 42 int scrollbarHeight; 43 int prevx; 44 int prevy; 45 46 static { 47 initIDs(); 48 } 49 50 static native void initIDs(); 51 @Override 52 native void create(WComponentPeer parent); 53 native int getOffset(int orient); 54 55 WScrollPanePeer(Component target) { 56 super(target); 57 scrollbarWidth = _getVScrollbarWidth(); 58 scrollbarHeight = _getHScrollbarHeight(); 59 } 60 61 @Override 62 void initialize() { 63 super.initialize(); 64 setInsets(); 65 Insets i = getInsets(); 66 setScrollPosition(-i.left,-i.top); 67 } 68 69 @Override 70 public void setUnitIncrement(Adjustable adj, int p) { 71 // The unitIncrement is grabbed from the target as needed. 72 } 73 74 private native void setInsets(); 75 76 @Override 77 public synchronized native void setScrollPosition(int x, int y); 78 79 @Override 80 public int getHScrollbarHeight() { 81 return scrollbarHeight; 82 } 83 private native int _getHScrollbarHeight(); 84 85 @Override 86 public int getVScrollbarWidth() { 87 return scrollbarWidth; 88 } 89 private native int _getVScrollbarWidth(); 90 91 public Point getScrollOffset() { 92 int x = getOffset(Adjustable.HORIZONTAL); 93 int y = getOffset(Adjustable.VERTICAL); 94 return new Point(x, y); 95 } 96 97 /** 98 * The child component has been resized. The scrollbars must be 99 * updated with the new sizes. At the native level the sizes of 100 * the actual windows may not have changed yet, so the size 101 * information from the java-level is passed down and used. 102 */ 103 @Override 104 public void childResized(int width, int height) { 105 ScrollPane sp = (ScrollPane)target; 106 Dimension vs = sp.getSize(); 107 setSpans(vs.width, vs.height, width, height); 108 setInsets(); 109 } 110 111 synchronized native void setSpans(int viewWidth, int viewHeight, 112 int childWidth, int childHeight); 113 114 /** 115 * Called by ScrollPane's internal observer of the scrollpane's adjustables. 116 * This is called whenever a scroll position is changed in one 117 * of adjustables, whether it was modified externally or from the 118 * native scrollbars themselves. 119 */ 120 @Override 121 public void setValue(Adjustable adj, int v) { 122 Component c = getScrollChild(); 123 if (c == null) { 124 return; 125 } 126 127 Point p = c.getLocation(); 128 switch(adj.getOrientation()) { 129 case Adjustable.VERTICAL: 130 setScrollPosition(-(p.x), v); 131 break; 132 case Adjustable.HORIZONTAL: 133 setScrollPosition(v, -(p.y)); 134 break; 135 } 136 } 137 138 private Component getScrollChild() { 139 ScrollPane sp = (ScrollPane)target; 140 Component child = null; 141 try { 142 child = sp.getComponent(0); 143 } catch (ArrayIndexOutOfBoundsException e) { 144 // do nothing. in this case we return null 145 } 146 return child; 147 } 148 149 /* 150 * Called from Windows in response to WM_VSCROLL/WM_HSCROLL message 151 */ 152 private void postScrollEvent(int orient, int type, 153 int pos, boolean isAdjusting) 154 { 155 Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting); 156 WToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor)); 157 } 158 159 /* 160 * Event that executes on the Java dispatch thread to move the 161 * scroll bar thumbs and paint the exposed area in one synchronous 162 * operation. 163 */ 164 @SuppressWarnings("serial") // JDK-implementation class 165 class ScrollEvent extends PeerEvent { 166 ScrollEvent(Object source, Runnable runnable) { 167 super(source, runnable, 0L); 168 } 169 170 @Override 171 public PeerEvent coalesceEvents(PeerEvent newEvent) { 172 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 173 log.finest("ScrollEvent coalesced: " + newEvent); 174 } 175 if (newEvent instanceof ScrollEvent) { 176 return newEvent; 177 } 178 return null; 179 } 180 } 181 182 /* 183 * Runnable for the ScrollEvent that performs the adjustment. 184 */ 185 class Adjustor implements Runnable { 186 int orient; // selects scrollbar 187 int type; // adjustment type 188 int pos; // new position (only used for absolute) 189 boolean isAdjusting; // isAdjusting status 190 191 Adjustor(int orient, int type, int pos, boolean isAdjusting) { 192 this.orient = orient; 193 this.type = type; 194 this.pos = pos; 195 this.isAdjusting = isAdjusting; 196 } 197 198 @Override 199 public void run() { 200 if (getScrollChild() == null) { 201 return; 202 } 203 ScrollPane sp = (ScrollPane)WScrollPanePeer.this.target; 204 ScrollPaneAdjustable adj = null; 205 206 // ScrollPaneAdjustable made public in 1.4, but 207 // get[HV]Adjustable can't be declared to return 208 // ScrollPaneAdjustable because it would break backward 209 // compatibility -- hence the cast 210 211 if (orient == Adjustable.VERTICAL) { 212 adj = (ScrollPaneAdjustable)sp.getVAdjustable(); 213 } else if (orient == Adjustable.HORIZONTAL) { 214 adj = (ScrollPaneAdjustable)sp.getHAdjustable(); 215 } else { 216 if (log.isLoggable(PlatformLogger.Level.FINE)) { 217 log.fine("Assertion failed: unknown orient"); 218 } 219 } 220 221 if (adj == null) { 222 return; 223 } 224 225 int newpos = adj.getValue(); 226 switch (type) { 227 case AdjustmentEvent.UNIT_DECREMENT: 228 newpos -= adj.getUnitIncrement(); 229 break; 230 case AdjustmentEvent.UNIT_INCREMENT: 231 newpos += adj.getUnitIncrement(); 232 break; 233 case AdjustmentEvent.BLOCK_DECREMENT: 234 newpos -= adj.getBlockIncrement(); 235 break; 236 case AdjustmentEvent.BLOCK_INCREMENT: 237 newpos += adj.getBlockIncrement(); 238 break; 239 case AdjustmentEvent.TRACK: 240 newpos = this.pos; 241 break; 242 default: 243 if (log.isLoggable(PlatformLogger.Level.FINE)) { 244 log.fine("Assertion failed: unknown type"); 245 } 246 return; 247 } 248 249 // keep scroll position in acceptable range 250 newpos = Math.max(adj.getMinimum(), newpos); 251 newpos = Math.min(adj.getMaximum(), newpos); 252 253 // set value, this will synchronously fire an AdjustmentEvent 254 adj.setValueIsAdjusting(isAdjusting); 255 256 // Fix for 4075484 - consider type information when creating AdjustmentEvent 257 // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK 258 // Instead, we call private method setTypedValue of ScrollPaneAdjustable. 259 AWTAccessor.getScrollPaneAdjustableAccessor().setTypedValue(adj, 260 newpos, 261 type); 262 263 // Paint the exposed area right away. To do this - find 264 // the heavyweight ancestor of the scroll child. 265 Component hwAncestor = getScrollChild(); 266 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 267 while (hwAncestor != null 268 && !(acc.getPeer(hwAncestor) instanceof WComponentPeer)) 269 { 270 hwAncestor = hwAncestor.getParent(); 271 } 272 if (log.isLoggable(PlatformLogger.Level.FINE)) { 273 if (hwAncestor == null) { 274 log.fine("Assertion (hwAncestor != null) failed, " + 275 "couldn't find heavyweight ancestor of scroll pane child"); 276 } 277 } 278 WComponentPeer hwPeer = acc.getPeer(hwAncestor); 279 hwPeer.paintDamagedAreaImmediately(); 280 } 281 } 282 283 }