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 {
initIDs()47         initIDs();
48     }
49 
initIDs()50     static native void initIDs();
51     @Override
create(WComponentPeer parent)52     native void create(WComponentPeer parent);
getOffset(int orient)53     native int getOffset(int orient);
54 
WScrollPanePeer(Component target)55     WScrollPanePeer(Component target) {
56         super(target);
57         scrollbarWidth = _getVScrollbarWidth();
58         scrollbarHeight = _getHScrollbarHeight();
59     }
60 
61     @Override
initialize()62     void initialize() {
63         super.initialize();
64         setInsets();
65         Insets i = getInsets();
66         setScrollPosition(-i.left,-i.top);
67     }
68 
69     @Override
setUnitIncrement(Adjustable adj, int p)70     public void setUnitIncrement(Adjustable adj, int p) {
71         // The unitIncrement is grabbed from the target as needed.
72     }
73 
setInsets()74     private native void setInsets();
75 
76     @Override
setScrollPosition(int x, int y)77     public synchronized native void setScrollPosition(int x, int y);
78 
79     @Override
getHScrollbarHeight()80     public int getHScrollbarHeight() {
81         return scrollbarHeight;
82     }
_getHScrollbarHeight()83     private native int _getHScrollbarHeight();
84 
85     @Override
getVScrollbarWidth()86     public int getVScrollbarWidth() {
87         return scrollbarWidth;
88     }
_getVScrollbarWidth()89     private native int _getVScrollbarWidth();
90 
getScrollOffset()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
childResized(int width, int height)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 
setSpans(int viewWidth, int viewHeight, int childWidth, int childHeight)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
setValue(Adjustable adj, int v)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 
getScrollChild()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      */
postScrollEvent(int orient, int type, int pos, boolean isAdjusting)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 {
ScrollEvent(Object source, Runnable runnable)166         ScrollEvent(Object source, Runnable runnable) {
167             super(source, runnable, 0L);
168         }
169 
170         @Override
coalesceEvents(PeerEvent newEvent)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 
Adjustor(int orient, int type, int pos, boolean isAdjusting)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
run()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 }
284