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