/* * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.awt.windows; import java.awt.*; import java.awt.event.AdjustmentEvent; import java.awt.peer.ScrollPanePeer; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.PeerEvent; import sun.util.logging.PlatformLogger; final class WScrollPanePeer extends WPanelPeer implements ScrollPanePeer { private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WScrollPanePeer"); int scrollbarWidth; int scrollbarHeight; int prevx; int prevy; static { initIDs(); } static native void initIDs(); @Override native void create(WComponentPeer parent); native int getOffset(int orient); WScrollPanePeer(Component target) { super(target); scrollbarWidth = _getVScrollbarWidth(); scrollbarHeight = _getHScrollbarHeight(); } @Override void initialize() { super.initialize(); setInsets(); Insets i = getInsets(); setScrollPosition(-i.left,-i.top); } @Override public void setUnitIncrement(Adjustable adj, int p) { // The unitIncrement is grabbed from the target as needed. } private native void setInsets(); @Override public synchronized native void setScrollPosition(int x, int y); @Override public int getHScrollbarHeight() { return scrollbarHeight; } private native int _getHScrollbarHeight(); @Override public int getVScrollbarWidth() { return scrollbarWidth; } private native int _getVScrollbarWidth(); public Point getScrollOffset() { int x = getOffset(Adjustable.HORIZONTAL); int y = getOffset(Adjustable.VERTICAL); return new Point(x, y); } /** * The child component has been resized. The scrollbars must be * updated with the new sizes. At the native level the sizes of * the actual windows may not have changed yet, so the size * information from the java-level is passed down and used. */ @Override public void childResized(int width, int height) { ScrollPane sp = (ScrollPane)target; Dimension vs = sp.getSize(); setSpans(vs.width, vs.height, width, height); setInsets(); } synchronized native void setSpans(int viewWidth, int viewHeight, int childWidth, int childHeight); /** * Called by ScrollPane's internal observer of the scrollpane's adjustables. * This is called whenever a scroll position is changed in one * of adjustables, whether it was modified externally or from the * native scrollbars themselves. */ @Override public void setValue(Adjustable adj, int v) { Component c = getScrollChild(); if (c == null) { return; } Point p = c.getLocation(); switch(adj.getOrientation()) { case Adjustable.VERTICAL: setScrollPosition(-(p.x), v); break; case Adjustable.HORIZONTAL: setScrollPosition(v, -(p.y)); break; } } private Component getScrollChild() { ScrollPane sp = (ScrollPane)target; Component child = null; try { child = sp.getComponent(0); } catch (ArrayIndexOutOfBoundsException e) { // do nothing. in this case we return null } return child; } /* * Called from Windows in response to WM_VSCROLL/WM_HSCROLL message */ private void postScrollEvent(int orient, int type, int pos, boolean isAdjusting) { Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting); WToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor)); } /* * Event that executes on the Java dispatch thread to move the * scroll bar thumbs and paint the exposed area in one synchronous * operation. */ @SuppressWarnings("serial") // JDK-implementation class class ScrollEvent extends PeerEvent { ScrollEvent(Object source, Runnable runnable) { super(source, runnable, 0L); } @Override public PeerEvent coalesceEvents(PeerEvent newEvent) { if (log.isLoggable(PlatformLogger.Level.FINEST)) { log.finest("ScrollEvent coalesced: " + newEvent); } if (newEvent instanceof ScrollEvent) { return newEvent; } return null; } } /* * Runnable for the ScrollEvent that performs the adjustment. */ class Adjustor implements Runnable { int orient; // selects scrollbar int type; // adjustment type int pos; // new position (only used for absolute) boolean isAdjusting; // isAdjusting status Adjustor(int orient, int type, int pos, boolean isAdjusting) { this.orient = orient; this.type = type; this.pos = pos; this.isAdjusting = isAdjusting; } @Override public void run() { if (getScrollChild() == null) { return; } ScrollPane sp = (ScrollPane)WScrollPanePeer.this.target; ScrollPaneAdjustable adj = null; // ScrollPaneAdjustable made public in 1.4, but // get[HV]Adjustable can't be declared to return // ScrollPaneAdjustable because it would break backward // compatibility -- hence the cast if (orient == Adjustable.VERTICAL) { adj = (ScrollPaneAdjustable)sp.getVAdjustable(); } else if (orient == Adjustable.HORIZONTAL) { adj = (ScrollPaneAdjustable)sp.getHAdjustable(); } else { if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine("Assertion failed: unknown orient"); } } if (adj == null) { return; } int newpos = adj.getValue(); switch (type) { case AdjustmentEvent.UNIT_DECREMENT: newpos -= adj.getUnitIncrement(); break; case AdjustmentEvent.UNIT_INCREMENT: newpos += adj.getUnitIncrement(); break; case AdjustmentEvent.BLOCK_DECREMENT: newpos -= adj.getBlockIncrement(); break; case AdjustmentEvent.BLOCK_INCREMENT: newpos += adj.getBlockIncrement(); break; case AdjustmentEvent.TRACK: newpos = this.pos; break; default: if (log.isLoggable(PlatformLogger.Level.FINE)) { log.fine("Assertion failed: unknown type"); } return; } // keep scroll position in acceptable range newpos = Math.max(adj.getMinimum(), newpos); newpos = Math.min(adj.getMaximum(), newpos); // set value, this will synchronously fire an AdjustmentEvent adj.setValueIsAdjusting(isAdjusting); // Fix for 4075484 - consider type information when creating AdjustmentEvent // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK // Instead, we call private method setTypedValue of ScrollPaneAdjustable. AWTAccessor.getScrollPaneAdjustableAccessor().setTypedValue(adj, newpos, type); // Paint the exposed area right away. To do this - find // the heavyweight ancestor of the scroll child. Component hwAncestor = getScrollChild(); final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); while (hwAncestor != null && !(acc.getPeer(hwAncestor) instanceof WComponentPeer)) { hwAncestor = hwAncestor.getParent(); } if (log.isLoggable(PlatformLogger.Level.FINE)) { if (hwAncestor == null) { log.fine("Assertion (hwAncestor != null) failed, " + "couldn't find heavyweight ancestor of scroll pane child"); } } WComponentPeer hwPeer = acc.getPeer(hwAncestor); hwPeer.paintDamagedAreaImmediately(); } } }