1 /* 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 class ScrollEvent extends PeerEvent { 168 ScrollEvent(Object source, Runnable runnable) { 169 super(source, runnable, 0L); 170 } 171 172 @Override 173 public PeerEvent coalesceEvents(PeerEvent newEvent) { 174 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 175 log.finest("ScrollEvent coalesced: " + newEvent); 176 } 177 if (newEvent instanceof ScrollEvent) { 178 return newEvent; 179 } 180 return null; 181 } 182 } 183 184 /* 185 * Runnable for the ScrollEvent that performs the adjustment. 186 */ 187 class Adjustor implements Runnable { 188 int orient; // selects scrollbar 189 int type; // adjustment type 190 int pos; // new position (only used for absolute) 191 boolean isAdjusting; // isAdjusting status 192 193 Adjustor(int orient, int type, int pos, boolean isAdjusting) { 194 this.orient = orient; 195 this.type = type; 196 this.pos = pos; 197 this.isAdjusting = isAdjusting; 198 } 199 200 @Override 201 public void run() { 202 if (getScrollChild() == null) { 203 return; 204 } 205 ScrollPane sp = (ScrollPane)WScrollPanePeer.this.target; 206 ScrollPaneAdjustable adj = null; 207 208 // ScrollPaneAdjustable made public in 1.4, but 209 // get[HV]Adjustable can't be declared to return 210 // ScrollPaneAdjustable because it would break backward 211 // compatibility -- hence the cast 212 213 if (orient == Adjustable.VERTICAL) { 214 adj = (ScrollPaneAdjustable)sp.getVAdjustable(); 215 } else if (orient == Adjustable.HORIZONTAL) { 216 adj = (ScrollPaneAdjustable)sp.getHAdjustable(); 217 } else { 218 if (log.isLoggable(PlatformLogger.Level.FINE)) { 219 log.fine("Assertion failed: unknown orient"); 220 } 221 } 222 223 if (adj == null) { 224 return; 225 } 226 227 int newpos = adj.getValue(); 228 switch (type) { 229 case AdjustmentEvent.UNIT_DECREMENT: 230 newpos -= adj.getUnitIncrement(); 231 break; 232 case AdjustmentEvent.UNIT_INCREMENT: 233 newpos += adj.getUnitIncrement(); 234 break; 235 case AdjustmentEvent.BLOCK_DECREMENT: 236 newpos -= adj.getBlockIncrement(); 237 break; 238 case AdjustmentEvent.BLOCK_INCREMENT: 239 newpos += adj.getBlockIncrement(); 240 break; 241 case AdjustmentEvent.TRACK: 242 newpos = this.pos; 243 break; 244 default: 245 if (log.isLoggable(PlatformLogger.Level.FINE)) { 246 log.fine("Assertion failed: unknown type"); 247 } 248 return; 249 } 250 251 // keep scroll position in acceptable range 252 newpos = Math.max(adj.getMinimum(), newpos); 253 newpos = Math.min(adj.getMaximum(), newpos); 254 255 // set value, this will synchronously fire an AdjustmentEvent 256 adj.setValueIsAdjusting(isAdjusting); 257 258 // Fix for 4075484 - consider type information when creating AdjustmentEvent 259 // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK 260 // Instead, we call private method setTypedValue of ScrollPaneAdjustable. 261 AWTAccessor.getScrollPaneAdjustableAccessor().setTypedValue(adj, 262 newpos, 263 type); 264 265 // Paint the exposed area right away. To do this - find 266 // the heavyweight ancestor of the scroll child. 267 Component hwAncestor = getScrollChild(); 268 while (hwAncestor != null 269 && !(hwAncestor.getPeer() instanceof WComponentPeer)) 270 { 271 hwAncestor = hwAncestor.getParent(); 272 } 273 if (log.isLoggable(PlatformLogger.Level.FINE)) { 274 if (hwAncestor == null) { 275 log.fine("Assertion (hwAncestor != null) failed, " + 276 "couldn't find heavyweight ancestor of scroll pane child"); 277 } 278 } 279 WComponentPeer hwPeer = (WComponentPeer)hwAncestor.getPeer(); 280 hwPeer.paintDamagedAreaImmediately(); 281 } 282 } 283 284 }