1 /*
2  * Copyright (c) 1996, 2020, 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.AWTEvent;
28 import java.awt.AWTException;
29 import java.awt.BufferCapabilities;
30 import java.awt.Color;
31 import java.awt.Component;
32 import java.awt.Container;
33 import java.awt.Dimension;
34 import java.awt.Font;
35 import java.awt.FontMetrics;
36 import java.awt.Graphics;
37 import java.awt.GraphicsConfiguration;
38 import java.awt.GraphicsDevice;
39 import java.awt.Image;
40 import java.awt.Point;
41 import java.awt.Rectangle;
42 import java.awt.SystemColor;
43 import java.awt.Window;
44 import java.awt.dnd.DropTarget;
45 import java.awt.dnd.peer.DropTargetPeer;
46 import java.awt.event.FocusEvent;
47 import java.awt.event.InputEvent;
48 import java.awt.event.InvocationEvent;
49 import java.awt.event.KeyEvent;
50 import java.awt.event.MouseEvent;
51 import java.awt.event.MouseWheelEvent;
52 import java.awt.event.PaintEvent;
53 import java.awt.geom.AffineTransform;
54 import java.awt.image.BufferedImage;
55 import java.awt.image.ColorModel;
56 import java.awt.image.VolatileImage;
57 import java.awt.peer.ComponentPeer;
58 import java.awt.peer.ContainerPeer;
59 
60 import sun.awt.AWTAccessor;
61 import sun.awt.PaintEventDispatcher;
62 import sun.awt.RepaintArea;
63 import sun.awt.SunToolkit;
64 import sun.awt.Win32GraphicsConfig;
65 import sun.awt.Win32GraphicsEnvironment;
66 import sun.awt.event.IgnorePaintEvent;
67 import sun.awt.image.SunVolatileImage;
68 import sun.java2d.InvalidPipeException;
69 import sun.java2d.ScreenUpdateManager;
70 import sun.java2d.SurfaceData;
71 import sun.java2d.d3d.D3DSurfaceData;
72 import sun.java2d.opengl.OGLSurfaceData;
73 import sun.java2d.pipe.Region;
74 import sun.util.logging.PlatformLogger;
75 
76 public abstract class WComponentPeer extends WObjectPeer
77     implements ComponentPeer, DropTargetPeer
78 {
79     /**
80      * Handle to native window
81      */
82     protected volatile long hwnd;
83 
84     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WComponentPeer");
85     private static final PlatformLogger shapeLog = PlatformLogger.getLogger("sun.awt.windows.shape.WComponentPeer");
86     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.windows.focus.WComponentPeer");
87 
88     // ComponentPeer implementation
89     SurfaceData surfaceData;
90 
91     private RepaintArea paintArea;
92 
93     protected Win32GraphicsConfig winGraphicsConfig;
94 
95     boolean isLayouting = false;
96     boolean paintPending = false;
97     int     oldWidth = -1;
98     int     oldHeight = -1;
99     private int numBackBuffers = 0;
100     private VolatileImage backBuffer = null;
101     private BufferCapabilities backBufferCaps = null;
102 
103     // foreground, background and color are cached to avoid calling back
104     // into the Component.
105     private Color foreground;
106     private Color background;
107     private Font font;
108 
109     @Override
isObscured()110     public native boolean isObscured();
111     @Override
canDetermineObscurity()112     public boolean canDetermineObscurity() { return true; }
113 
114     // DropTarget support
115 
116     int nDropTargets;
117     long nativeDropTargetContext; // native pointer
118 
pShow()119     private synchronized native void pShow();
hide()120     synchronized native void hide();
enable()121     synchronized native void enable();
disable()122     synchronized native void disable();
123 
getHWnd()124     public long getHWnd() {
125         return hwnd;
126     }
127 
128     /* New 1.1 API */
129     @Override
getLocationOnScreen()130     public native Point getLocationOnScreen();
131 
132     /* New 1.1 API */
133     @Override
setVisible(boolean b)134     public void setVisible(boolean b) {
135         if (b) {
136             show();
137         } else {
138             hide();
139         }
140     }
141 
show()142     public void show() {
143         Dimension s = ((Component)target).getSize();
144         oldHeight = s.height;
145         oldWidth = s.width;
146         pShow();
147     }
148 
149     /* New 1.1 API */
150     @Override
setEnabled(boolean b)151     public void setEnabled(boolean b) {
152         if (b) {
153             enable();
154         } else {
155             disable();
156         }
157     }
158 
159     public int serialNum = 0;
160 
reshapeNoCheck(int x, int y, int width, int height)161     private native void reshapeNoCheck(int x, int y, int width, int height);
162 
163     /* New 1.1 API */
164     @Override
setBounds(int x, int y, int width, int height, int op)165     public void setBounds(int x, int y, int width, int height, int op) {
166         // Should set paintPending before reahape to prevent
167         // thread race between paint events
168         // Native components do redraw after resize
169         paintPending = (width != oldWidth) || (height != oldHeight);
170 
171         if ( (op & NO_EMBEDDED_CHECK) != 0 ) {
172             reshapeNoCheck(x, y, width, height);
173         } else {
174             reshape(x, y, width, height);
175         }
176         if ((width != oldWidth) || (height != oldHeight)) {
177             // Only recreate surfaceData if this setBounds is called
178             // for a resize; a simple move should not trigger a recreation
179             try {
180                 replaceSurfaceData();
181             } catch (InvalidPipeException e) {
182                 // REMIND : what do we do if our surface creation failed?
183             }
184             oldWidth = width;
185             oldHeight = height;
186         }
187 
188         serialNum++;
189     }
190 
191     /*
192      * Called from native code (on Toolkit thread) in order to
193      * dynamically layout the Container during resizing
194      */
dynamicallyLayoutContainer()195     void dynamicallyLayoutContainer() {
196         // If we got the WM_SIZING, this must be a Container, right?
197         // In fact, it must be the top-level Container.
198         if (log.isLoggable(PlatformLogger.Level.FINE)) {
199             Container parent = WToolkit.getNativeContainer((Component)target);
200             if (parent != null) {
201                 log.fine("Assertion (parent == null) failed");
202             }
203         }
204         final Container cont = (Container)target;
205 
206         WToolkit.executeOnEventHandlerThread(cont, new Runnable() {
207             @Override
208             public void run() {
209                 // Discarding old paint events doesn't seem to be necessary.
210                 cont.invalidate();
211                 cont.validate();
212 
213                 if (surfaceData instanceof D3DSurfaceData.D3DWindowSurfaceData ||
214                     surfaceData instanceof OGLSurfaceData)
215                 {
216                     // When OGL or D3D is enabled, it is necessary to
217                     // replace the SurfaceData for each dynamic layout
218                     // request so that the viewport stays in sync
219                     // with the window bounds.
220                     try {
221                         replaceSurfaceData();
222                     } catch (InvalidPipeException e) {
223                         // REMIND: this is unlikely to occur for OGL, but
224                         // what do we do if surface creation fails?
225                     }
226                 }
227 
228                 // Forcing a paint here doesn't seem to be necessary.
229                 // paintDamagedAreaImmediately();
230             }
231         });
232     }
233 
234     /*
235      * Paints any portion of the component that needs updating
236      * before the call returns (similar to the Win32 API UpdateWindow)
237      */
paintDamagedAreaImmediately()238     void paintDamagedAreaImmediately() {
239         // force Windows to send any pending WM_PAINT events so
240         // the damage area is updated on the Java side
241         updateWindow();
242         // make sure paint events are transferred to main event queue
243         // for coalescing
244         SunToolkit.flushPendingEvents();
245         // paint the damaged area
246         paintArea.paint(target, shouldClearRectBeforePaint());
247     }
248 
updateWindow()249     synchronized native void updateWindow();
250 
251     @Override
paint(Graphics g)252     public void paint(Graphics g) {
253         ((Component)target).paint(g);
254     }
255 
repaint(long tm, int x, int y, int width, int height)256     public void repaint(long tm, int x, int y, int width, int height) {
257     }
258 
259     private static final double BANDING_DIVISOR = 4.0;
createPrintedPixels(int srcX, int srcY, int srcW, int srcH, int alpha)260     private native int[] createPrintedPixels(int srcX, int srcY,
261                                              int srcW, int srcH,
262                                              int alpha);
263     @Override
print(Graphics g)264     public void print(Graphics g) {
265 
266         Component comp = (Component)target;
267 
268         // To conserve memory usage, we will band the image.
269 
270         int totalW = comp.getWidth();
271         int totalH = comp.getHeight();
272 
273         int hInc = (int)(totalH / BANDING_DIVISOR);
274         if (hInc == 0) {
275             hInc = totalH;
276         }
277 
278         for (int startY = 0; startY < totalH; startY += hInc) {
279             int endY = startY + hInc - 1;
280             if (endY >= totalH) {
281                 endY = totalH - 1;
282             }
283             int h = endY - startY + 1;
284 
285             Color bgColor = comp.getBackground();
286             int[] pix = createPrintedPixels(0, startY, totalW, h,
287                                             bgColor == null ? 255 : bgColor.getAlpha());
288             if (pix != null) {
289                 BufferedImage bim = new BufferedImage(totalW, h,
290                                               BufferedImage.TYPE_INT_ARGB);
291                 bim.setRGB(0, 0, totalW, h, pix, 0, totalW);
292                 g.drawImage(bim, 0, startY, null);
293                 bim.flush();
294             }
295         }
296 
297         comp.print(g);
298     }
299 
300     @Override
coalescePaintEvent(PaintEvent e)301     public void coalescePaintEvent(PaintEvent e) {
302         Rectangle r = e.getUpdateRect();
303         if (!(e instanceof IgnorePaintEvent)) {
304             paintArea.add(r, e.getID());
305         }
306 
307         if (log.isLoggable(PlatformLogger.Level.FINEST)) {
308             switch(e.getID()) {
309             case PaintEvent.UPDATE:
310                 log.finest("coalescePaintEvent: UPDATE: add: x = " +
311                     r.x + ", y = " + r.y + ", width = " + r.width + ", height = " + r.height);
312                 return;
313             case PaintEvent.PAINT:
314                 log.finest("coalescePaintEvent: PAINT: add: x = " +
315                     r.x + ", y = " + r.y + ", width = " + r.width + ", height = " + r.height);
316                 return;
317             }
318         }
319     }
320 
reshape(int x, int y, int width, int height)321     public synchronized native void reshape(int x, int y, int width, int height);
322 
323     // returns true if the event has been handled and shouldn't be propagated
324     // though handleEvent method chain - e.g. WTextFieldPeer returns true
325     // on handling '\n' to prevent it from being passed to native code
handleJavaKeyEvent(KeyEvent e)326     public boolean handleJavaKeyEvent(KeyEvent e) { return false; }
327 
handleJavaMouseEvent(MouseEvent e)328     public void handleJavaMouseEvent(MouseEvent e) {
329         switch (e.getID()) {
330           case MouseEvent.MOUSE_PRESSED:
331               // Note that Swing requests focus in its own mouse event handler.
332               if (target == e.getSource() &&
333                   !((Component)target).isFocusOwner() &&
334                   WKeyboardFocusManagerPeer.shouldFocusOnClick((Component)target))
335               {
336                   WKeyboardFocusManagerPeer.requestFocusFor((Component)target,
337                                                             FocusEvent.Cause.MOUSE_EVENT);
338               }
339               break;
340         }
341     }
342 
nativeHandleEvent(AWTEvent e)343     native void nativeHandleEvent(AWTEvent e);
344 
345     @Override
346     @SuppressWarnings("fallthrough")
handleEvent(AWTEvent e)347     public void handleEvent(AWTEvent e) {
348         int id = e.getID();
349 
350         if ((e instanceof InputEvent) && !((InputEvent)e).isConsumed() &&
351             ((Component)target).isEnabled())
352         {
353             if (e instanceof MouseEvent && !(e instanceof MouseWheelEvent)) {
354                 handleJavaMouseEvent((MouseEvent) e);
355             } else if (e instanceof KeyEvent) {
356                 if (handleJavaKeyEvent((KeyEvent)e)) {
357                     return;
358                 }
359             }
360         }
361 
362         switch(id) {
363             case PaintEvent.PAINT:
364                 // Got native painting
365                 paintPending = false;
366                 // Fallthrough to next statement
367             case PaintEvent.UPDATE:
368                 // Skip all painting while layouting and all UPDATEs
369                 // while waiting for native paint
370                 if (!isLayouting && ! paintPending) {
371                     paintArea.paint(target,shouldClearRectBeforePaint());
372                 }
373                 return;
374             case FocusEvent.FOCUS_LOST:
375             case FocusEvent.FOCUS_GAINED:
376                 handleJavaFocusEvent((FocusEvent)e);
377             default:
378             break;
379         }
380 
381         // Call the native code
382         nativeHandleEvent(e);
383     }
384 
handleJavaFocusEvent(FocusEvent fe)385     void handleJavaFocusEvent(FocusEvent fe) {
386         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
387             focusLog.finer(fe.toString());
388         }
389         setFocus(fe.getID() == FocusEvent.FOCUS_GAINED);
390     }
391 
setFocus(boolean doSetFocus)392     native void setFocus(boolean doSetFocus);
393 
394     @Override
getMinimumSize()395     public Dimension getMinimumSize() {
396         return ((Component)target).getSize();
397     }
398 
399     @Override
getPreferredSize()400     public Dimension getPreferredSize() {
401         return getMinimumSize();
402     }
403 
404     // Do nothing for heavyweight implementation
405     @Override
layout()406     public void layout() {}
407 
getBounds()408     public Rectangle getBounds() {
409         return ((Component)target).getBounds();
410     }
411 
412     @Override
isFocusable()413     public boolean isFocusable() {
414         return false;
415     }
416 
417     /*
418      * Return the GraphicsConfiguration associated with this peer, either
419      * the locally stored winGraphicsConfig, or that of the target Component.
420      */
421     @Override
getGraphicsConfiguration()422     public GraphicsConfiguration getGraphicsConfiguration() {
423         if (winGraphicsConfig != null) {
424             return winGraphicsConfig;
425         }
426         else {
427             // we don't need a treelock here, since
428             // Component.getGraphicsConfiguration() gets it itself.
429             return ((Component)target).getGraphicsConfiguration();
430         }
431     }
432 
getSurfaceData()433     public SurfaceData getSurfaceData() {
434         return surfaceData;
435     }
436 
437     /**
438      * Creates new surfaceData object and invalidates the previous
439      * surfaceData object.
440      * Replacing the surface data should never lock on any resources which are
441      * required by other threads which may have them and may require
442      * the tree-lock.
443      * This is a degenerate version of replaceSurfaceData(numBackBuffers), so
444      * just call that version with our current numBackBuffers.
445      */
replaceSurfaceData()446     public void replaceSurfaceData() {
447         replaceSurfaceData(this.numBackBuffers, this.backBufferCaps);
448     }
449 
createScreenSurface(boolean isResize)450     public void createScreenSurface(boolean isResize)
451     {
452         Win32GraphicsConfig gc = (Win32GraphicsConfig)getGraphicsConfiguration();
453         ScreenUpdateManager mgr = ScreenUpdateManager.getInstance();
454 
455         surfaceData = mgr.createScreenSurface(gc, this, numBackBuffers, isResize);
456     }
457 
458 
459     /**
460      * Multi-buffer version of replaceSurfaceData.  This version is called
461      * by createBuffers(), which needs to acquire the same locks in the same
462      * order, but also needs to perform additional functions inside the
463      * locks.
464      */
replaceSurfaceData(int newNumBackBuffers, BufferCapabilities caps)465     public void replaceSurfaceData(int newNumBackBuffers,
466                                    BufferCapabilities caps)
467     {
468         SurfaceData oldData = null;
469         VolatileImage oldBB = null;
470         synchronized(((Component)target).getTreeLock()) {
471             synchronized(this) {
472                 if (pData == 0) {
473                     return;
474                 }
475                 numBackBuffers = newNumBackBuffers;
476                 ScreenUpdateManager mgr = ScreenUpdateManager.getInstance();
477                 oldData = surfaceData;
478                 mgr.dropScreenSurface(oldData);
479                 createScreenSurface(true);
480                 if (oldData != null) {
481                     oldData.invalidate();
482                 }
483 
484                 oldBB = backBuffer;
485                 if (numBackBuffers > 0) {
486                     // set the caps first, they're used when creating the bb
487                     backBufferCaps = caps;
488                     Win32GraphicsConfig gc =
489                         (Win32GraphicsConfig)getGraphicsConfiguration();
490                     backBuffer = gc.createBackBuffer(this);
491                 } else if (backBuffer != null) {
492                     backBufferCaps = null;
493                     backBuffer = null;
494                 }
495             }
496         }
497         // it would be better to do this before we create new ones,
498         // but then we'd run into deadlock issues
499         if (oldData != null) {
500             oldData.flush();
501             // null out the old data to make it collected faster
502             oldData = null;
503         }
504         if (oldBB != null) {
505             oldBB.flush();
506             // null out the old data to make it collected faster
507             oldData = null;
508         }
509     }
510 
replaceSurfaceDataLater()511     public void replaceSurfaceDataLater() {
512         Runnable r = new Runnable() {
513             @Override
514             public void run() {
515                 // Shouldn't do anything if object is disposed in meanwhile
516                 // No need for sync as disposeAction in Window is performed
517                 // on EDT
518                 if (!isDisposed()) {
519                     try {
520                         replaceSurfaceData();
521                     } catch (InvalidPipeException e) {
522                         // REMIND : what do we do if our surface creation failed?
523                     }
524                 }
525             }
526         };
527         Component c = (Component)target;
528         // Fix 6255371.
529         if (!PaintEventDispatcher.getPaintEventDispatcher().queueSurfaceDataReplacing(c, r)) {
530             postEvent(new InvocationEvent(c, r));
531         }
532     }
533 
534     @Override
updateGraphicsData(GraphicsConfiguration gc)535     public boolean updateGraphicsData(GraphicsConfiguration gc) {
536         var old = getGraphicsConfiguration().getDefaultTransform();
537         winGraphicsConfig = (Win32GraphicsConfig)gc;
538         if (gc != null && !old.equals(gc.getDefaultTransform())) {
539             syncBounds(); // the bounds of the peer depend on the DPI
540         }
541         try {
542             replaceSurfaceData();
543         } catch (InvalidPipeException e) {
544             // REMIND : what do we do if our surface creation failed?
545         }
546         return false;
547     }
548 
549     /**
550      * Make sure that the native peer's coordinates are in sync with the target.
551      */
syncBounds()552     void syncBounds() {
553         Rectangle r = ((Component) target).getBounds();
554         setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
555     }
556 
557     //This will return null for Components not yet added to a Container
558     @Override
getColorModel()559     public ColorModel getColorModel() {
560         GraphicsConfiguration gc = getGraphicsConfiguration();
561         if (gc != null) {
562             return gc.getColorModel();
563         }
564         else {
565             return null;
566         }
567     }
568 
569     //This will return null for Components not yet added to a Container
getDeviceColorModel()570     public ColorModel getDeviceColorModel() {
571         Win32GraphicsConfig gc =
572             (Win32GraphicsConfig)getGraphicsConfiguration();
573         if (gc != null) {
574             return gc.getDeviceColorModel();
575         }
576         else {
577             return null;
578         }
579     }
580 
581     //Returns null for Components not yet added to a Container
getColorModel(int transparency)582     public ColorModel getColorModel(int transparency) {
583 //      return WToolkit.config.getColorModel(transparency);
584         GraphicsConfiguration gc = getGraphicsConfiguration();
585         if (gc != null) {
586             return gc.getColorModel(transparency);
587         }
588         else {
589             return null;
590         }
591     }
592 
593     // fallback default font object
594     static final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12);
595 
596     @Override
getGraphics()597     public Graphics getGraphics() {
598         if (isDisposed()) {
599             return null;
600         }
601 
602         Component target = (Component)getTarget();
603         Window window = SunToolkit.getContainingWindow(target);
604         if (window != null) {
605             final WWindowPeer wpeer = AWTAccessor.getComponentAccessor()
606                                                  .getPeer(window);
607             if (wpeer != null) {
608                 Graphics g = wpeer.getTranslucentGraphics();
609                 // getTranslucentGraphics() returns non-null value for non-opaque windows only
610                 if (g != null) {
611                     // Non-opaque windows do not support heavyweight children.
612                     // Redirect all painting to the Window's Graphics instead.
613                     // The caller is responsible for calling the
614                     // WindowPeer.updateWindow() after painting has finished.
615                     int x = 0, y = 0;
616                     for (Component c = target; c != window; c = c.getParent()) {
617                         x += c.getX();
618                         y += c.getY();
619                     }
620 
621                     g.translate(x, y);
622                     g.clipRect(0, 0, target.getWidth(), target.getHeight());
623 
624                     return g;
625                 }
626             }
627         }
628 
629         SurfaceData surfaceData = this.surfaceData;
630         if (surfaceData != null) {
631             /* Fix for bug 4746122. Color and Font shouldn't be null */
632             Color bgColor = background;
633             if (bgColor == null) {
634                 bgColor = SystemColor.window;
635             }
636             Color fgColor = foreground;
637             if (fgColor == null) {
638                 fgColor = SystemColor.windowText;
639             }
640             Font font = this.font;
641             if (font == null) {
642                 font = defaultFont;
643             }
644             ScreenUpdateManager mgr =
645                 ScreenUpdateManager.getInstance();
646             return mgr.createGraphics(surfaceData, this, fgColor,
647                                       bgColor, font);
648         }
649         return null;
650     }
651     @Override
getFontMetrics(Font font)652     public FontMetrics getFontMetrics(Font font) {
653         return WFontMetrics.getFontMetrics(font);
654     }
655 
_dispose()656     private synchronized native void _dispose();
657     @Override
disposeImpl()658     protected void disposeImpl() {
659         SurfaceData oldData = surfaceData;
660         surfaceData = null;
661         ScreenUpdateManager.getInstance().dropScreenSurface(oldData);
662         oldData.invalidate();
663         // remove from updater before calling targetDisposedPeer
664         WToolkit.targetDisposedPeer(target, this);
665         _dispose();
666     }
667 
disposeLater()668     public void disposeLater() {
669         postEvent(new InvocationEvent(target, new Runnable() {
670             @Override
671             public void run() {
672                 dispose();
673             }
674         }));
675     }
676 
677     @Override
setForeground(Color c)678     public synchronized void setForeground(Color c) {
679         foreground = c;
680         _setForeground(c.getRGB());
681     }
682 
683     @Override
setBackground(Color c)684     public synchronized void setBackground(Color c) {
685         background = c;
686         _setBackground(c.getRGB());
687     }
688 
689     /**
690      * This method is intentionally not synchronized as it is called while
691      * holding other locks.
692      *
693      * @see sun.java2d.d3d.D3DScreenUpdateManager#validate
694      */
getBackgroundNoSync()695     public Color getBackgroundNoSync() {
696         return background;
697     }
698 
_setForeground(int rgb)699     private native void _setForeground(int rgb);
_setBackground(int rgb)700     private native void _setBackground(int rgb);
701 
702     @Override
setFont(Font f)703     public synchronized void setFont(Font f) {
704         font = f;
705         _setFont(f);
706     }
_setFont(Font f)707     synchronized native void _setFont(Font f);
708     @Override
updateCursorImmediately()709     public void updateCursorImmediately() {
710         WGlobalCursorManager.getCursorManager().updateCursorImmediately();
711     }
712 
713     // TODO: consider moving it to KeyboardFocusManagerPeerImpl
714     @Override
requestFocus(Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time, FocusEvent.Cause cause)715     public boolean requestFocus(Component lightweightChild, boolean temporary,
716                                 boolean focusedWindowChangeAllowed, long time,
717                                 FocusEvent.Cause cause)
718     {
719         if (WKeyboardFocusManagerPeer.
720             processSynchronousLightweightTransfer((Component)target, lightweightChild, temporary,
721                                                   focusedWindowChangeAllowed, time))
722         {
723             return true;
724         }
725 
726         int result = WKeyboardFocusManagerPeer
727             .shouldNativelyFocusHeavyweight((Component)target, lightweightChild,
728                                             temporary, focusedWindowChangeAllowed,
729                                             time, cause);
730 
731         switch (result) {
732           case WKeyboardFocusManagerPeer.SNFH_FAILURE:
733               return false;
734           case WKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:
735               if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
736                   focusLog.finer("Proceeding with request to " + lightweightChild + " in " + target);
737               }
738               Window parentWindow = SunToolkit.getContainingWindow((Component)target);
739               if (parentWindow == null) {
740                   return rejectFocusRequestHelper("WARNING: Parent window is null");
741               }
742               final WWindowPeer wpeer = AWTAccessor.getComponentAccessor()
743                                                    .getPeer(parentWindow);
744               if (wpeer == null) {
745                   return rejectFocusRequestHelper("WARNING: Parent window's peer is null");
746               }
747               boolean res = wpeer.requestWindowFocus(cause);
748 
749               if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
750                   focusLog.finer("Requested window focus: " + res);
751               }
752               // If parent window can be made focused and has been made focused(synchronously)
753               // then we can proceed with children, otherwise we retreat.
754               if (!(res && parentWindow.isFocused())) {
755                   return rejectFocusRequestHelper("Waiting for asynchronous processing of the request");
756               }
757               return WKeyboardFocusManagerPeer.deliverFocus(lightweightChild,
758                                                             (Component)target,
759                                                             temporary,
760                                                             focusedWindowChangeAllowed,
761                                                             time, cause);
762 
763           case WKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:
764               // Either lightweight or excessive request - all events are generated.
765               return true;
766         }
767         return false;
768     }
769 
rejectFocusRequestHelper(String logMsg)770     private boolean rejectFocusRequestHelper(String logMsg) {
771         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
772             focusLog.finer(logMsg);
773         }
774         WKeyboardFocusManagerPeer.removeLastFocusRequest((Component)target);
775         return false;
776     }
777 
778     @Override
createImage(int width, int height)779     public Image createImage(int width, int height) {
780         Win32GraphicsConfig gc =
781             (Win32GraphicsConfig)getGraphicsConfiguration();
782         return gc.createAcceleratedImage((Component)target, width, height);
783     }
784 
785     @Override
createVolatileImage(int width, int height)786     public VolatileImage createVolatileImage(int width, int height) {
787         return new SunVolatileImage((Component)target, width, height);
788     }
789 
790     // Object overrides
791 
toString()792     public String toString() {
793         return getClass().getName() + "[" + target + "]";
794     }
795 
796     // Toolkit & peer internals
797 
798     private int updateX1, updateY1, updateX2, updateY2;
799 
WComponentPeer(Component target)800     WComponentPeer(Component target) {
801         this.target = target;
802         this.paintArea = new RepaintArea();
803         create(getNativeParent());
804         // fix for 5088782: check if window object is created successfully
805         checkCreation();
806 
807         createScreenSurface(false);
808         initialize();
809         start();  // Initialize enable/disable state, turn on callbacks
810     }
create(WComponentPeer parent)811     abstract void create(WComponentPeer parent);
812 
813     /**
814      * Gets the native parent of this peer. We use the term "parent" explicitly,
815      * because we override the method in top-level window peer implementations.
816      *
817      * @return the parent container/owner of this peer.
818      */
getNativeParent()819     WComponentPeer getNativeParent() {
820         Container parent = SunToolkit.getNativeContainer((Component) target);
821         return (WComponentPeer) WToolkit.targetToPeer(parent);
822     }
823 
checkCreation()824     protected void checkCreation()
825     {
826         if ((hwnd == 0) || (pData == 0))
827         {
828             if (createError != null)
829             {
830                 throw createError;
831             }
832             else
833             {
834                 throw new InternalError("couldn't create component peer");
835             }
836         }
837     }
838 
start()839     synchronized native void start();
840 
initialize()841     void initialize() {
842         if (((Component)target).isVisible()) {
843             show();  // the wnd starts hidden
844         }
845         Color fg = ((Component)target).getForeground();
846         if (fg != null) {
847             setForeground(fg);
848         }
849         // Set background color in C++, to avoid inheriting a parent's color.
850         Font  f = ((Component)target).getFont();
851         if (f != null) {
852             setFont(f);
853         }
854         if (! ((Component)target).isEnabled()) {
855             disable();
856         }
857         Rectangle r = ((Component)target).getBounds();
858         setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
859     }
860 
861     // Callbacks for window-system events to the frame
862 
863     // Invoke a update() method call on the target
handleRepaint(int x, int y, int w, int h)864     void handleRepaint(int x, int y, int w, int h) {
865         // Repaints are posted from updateClient now...
866     }
867 
868     // Invoke a paint() method call on the target, after clearing the
869     // damaged area.
handleExpose(int x, int y, int w, int h)870     void handleExpose(int x, int y, int w, int h) {
871         // Bug ID 4081126 & 4129709 - can't do the clearRect() here,
872         // since it interferes with the java thread working in the
873         // same window on multi-processor NT machines.
874 
875         postPaintIfNecessary(x, y, w, h);
876     }
877 
878     /* Invoke a paint() method call on the target, without clearing the
879      * damaged area.  This is normally called by a native control after
880      * it has painted itself.
881      *
882      * NOTE: This is called on the privileged toolkit thread. Do not
883      *       call directly into user code using this thread!
884      */
handlePaint(int x, int y, int w, int h)885     public void handlePaint(int x, int y, int w, int h) {
886         postPaintIfNecessary(x, y, w, h);
887     }
888 
postPaintIfNecessary(int x, int y, int w, int h)889     private void postPaintIfNecessary(int x, int y, int w, int h) {
890         if ( !AWTAccessor.getComponentAccessor().getIgnoreRepaint( (Component) target) ) {
891             PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
892                 createPaintEvent((Component)target, x, y, w, h);
893             if (event != null) {
894                 postEvent(event);
895             }
896         }
897     }
898 
899     /*
900      * Post an event. Queue it for execution by the callback thread.
901      */
postEvent(AWTEvent event)902     void postEvent(AWTEvent event) {
903         preprocessPostEvent(event);
904         WToolkit.postEvent(WToolkit.targetToAppContext(target), event);
905     }
906 
preprocessPostEvent(AWTEvent event)907     void preprocessPostEvent(AWTEvent event) {}
908 
909     // Routines to support deferred window positioning.
beginLayout()910     public void beginLayout() {
911         // Skip all painting till endLayout
912         isLayouting = true;
913     }
914 
endLayout()915     public void endLayout() {
916         if(!paintArea.isEmpty() && !paintPending &&
917             !((Component)target).getIgnoreRepaint()) {
918             // if not waiting for native painting repaint damaged area
919             postEvent(new PaintEvent((Component)target, PaintEvent.PAINT,
920                           new Rectangle()));
921         }
922         isLayouting = false;
923     }
924 
beginValidate()925     public native void beginValidate();
endValidate()926     public native void endValidate();
927 
928     /**
929      * register a DropTarget with this native peer
930      */
931 
932     @Override
addDropTarget(DropTarget dt)933     public synchronized void addDropTarget(DropTarget dt) {
934         if (nDropTargets == 0) {
935             nativeDropTargetContext = addNativeDropTarget();
936         }
937         nDropTargets++;
938     }
939 
940     /**
941      * unregister a DropTarget with this native peer
942      */
943 
944     @Override
removeDropTarget(DropTarget dt)945     public synchronized void removeDropTarget(DropTarget dt) {
946         nDropTargets--;
947         if (nDropTargets == 0) {
948             removeNativeDropTarget();
949             nativeDropTargetContext = 0;
950         }
951     }
952 
953     /**
954      * add the native peer's AwtDropTarget COM object
955      * @return reference to AwtDropTarget object
956      */
957 
addNativeDropTarget()958     native long addNativeDropTarget();
959 
960     /**
961      * remove the native peer's AwtDropTarget COM object
962      */
963 
removeNativeDropTarget()964     native void removeNativeDropTarget();
nativeHandlesWheelScrolling()965     native boolean nativeHandlesWheelScrolling();
966 
967     @Override
handlesWheelScrolling()968     public boolean handlesWheelScrolling() {
969         // should this be cached?
970         return nativeHandlesWheelScrolling();
971     }
972 
973     // Returns true if we are inside begin/endLayout and
974     // are waiting for native painting
isPaintPending()975     public boolean isPaintPending() {
976         return paintPending && isLayouting;
977     }
978 
979     /**
980      * The following multibuffering-related methods delegate to our
981      * associated GraphicsConfig (Win or WGL) to handle the appropriate
982      * native windowing system specific actions.
983      */
984 
985     @Override
createBuffers(int numBuffers, BufferCapabilities caps)986     public void createBuffers(int numBuffers, BufferCapabilities caps)
987         throws AWTException
988     {
989         Win32GraphicsConfig gc =
990             (Win32GraphicsConfig)getGraphicsConfiguration();
991         gc.assertOperationSupported((Component)target, numBuffers, caps);
992 
993         // Re-create the primary surface with the new number of back buffers
994         try {
995             replaceSurfaceData(numBuffers - 1, caps);
996         } catch (InvalidPipeException e) {
997             throw new AWTException(e.getMessage());
998         }
999     }
1000 
1001     @Override
destroyBuffers()1002     public void destroyBuffers() {
1003         replaceSurfaceData(0, null);
1004     }
1005 
1006     @Override
flip(int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction)1007     public void flip(int x1, int y1, int x2, int y2,
1008                                   BufferCapabilities.FlipContents flipAction)
1009     {
1010         VolatileImage backBuffer = this.backBuffer;
1011         if (backBuffer == null) {
1012             throw new IllegalStateException("Buffers have not been created");
1013         }
1014         Win32GraphicsConfig gc =
1015             (Win32GraphicsConfig)getGraphicsConfiguration();
1016         gc.flip(this, (Component)target, backBuffer, x1, y1, x2, y2, flipAction);
1017     }
1018 
1019     @Override
getBackBuffer()1020     public synchronized Image getBackBuffer() {
1021         Image backBuffer = this.backBuffer;
1022         if (backBuffer == null) {
1023             throw new IllegalStateException("Buffers have not been created");
1024         }
1025         return backBuffer;
1026     }
getBackBufferCaps()1027     public BufferCapabilities getBackBufferCaps() {
1028         return backBufferCaps;
1029     }
getBackBuffersNum()1030     public int getBackBuffersNum() {
1031         return numBackBuffers;
1032     }
1033 
1034     /* override and return false on components that DO NOT require
1035        a clearRect() before painting (i.e. native components) */
shouldClearRectBeforePaint()1036     public boolean shouldClearRectBeforePaint() {
1037         return true;
1038     }
1039 
pSetParent(ComponentPeer newNativeParent)1040     native void pSetParent(ComponentPeer newNativeParent);
1041 
1042     /**
1043      * @see java.awt.peer.ComponentPeer#reparent
1044      */
1045     @Override
reparent(ContainerPeer newNativeParent)1046     public void reparent(ContainerPeer newNativeParent) {
1047         pSetParent(newNativeParent);
1048     }
1049 
1050     /**
1051      * @see java.awt.peer.ComponentPeer#isReparentSupported
1052      */
1053     @Override
isReparentSupported()1054     public boolean isReparentSupported() {
1055         return true;
1056     }
1057 
setBoundsOperation(int operation)1058     public void setBoundsOperation(int operation) {
1059     }
1060 
1061     private volatile boolean isAccelCapable = true;
1062 
1063     /**
1064      * Returns whether this component is capable of being hw accelerated.
1065      * More specifically, whether rendering to this component or a
1066      * BufferStrategy's back-buffer for this component can be hw accelerated.
1067      *
1068      * Conditions which could prevent hw acceleration include the toplevel
1069      * window containing this component being
1070      * {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
1071      * PERPIXEL_TRANSLUCENT}.
1072      *
1073      * Another condition is if Xor paint mode was detected when rendering
1074      * to an on-screen accelerated surface associated with this peer.
1075      * in this case both on- and off-screen acceleration for this peer is
1076      * disabled.
1077      *
1078      * @return {@code true} if this component is capable of being hw
1079      * accelerated, {@code false} otherwise
1080      * @see GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT
1081      */
isAccelCapable()1082     public boolean isAccelCapable() {
1083         if (!isAccelCapable ||
1084             !isContainingTopLevelAccelCapable((Component)target))
1085         {
1086             return false;
1087         }
1088 
1089         boolean isTranslucent =
1090             SunToolkit.isContainingTopLevelTranslucent((Component)target);
1091         // D3D/OGL and translucent windows interacted poorly in Windows XP;
1092         // these problems are no longer present in Vista
1093         return !isTranslucent || Win32GraphicsEnvironment.isVistaOS();
1094     }
1095 
1096     /**
1097      * Disables acceleration for this peer.
1098      */
disableAcceleration()1099     public void disableAcceleration() {
1100         isAccelCapable = false;
1101     }
1102 
1103 
setRectangularShape(int lox, int loy, int hix, int hiy, Region region)1104     native void setRectangularShape(int lox, int loy, int hix, int hiy,
1105                      Region region);
1106 
1107 
1108     // REMIND: Temp workaround for issues with using HW acceleration
1109     // in the browser on Vista when DWM is enabled.
1110     // @return true if the toplevel container is not an EmbeddedFrame or
1111     // if this EmbeddedFrame is acceleration capable, false otherwise
isContainingTopLevelAccelCapable(Component c)1112     private static final boolean isContainingTopLevelAccelCapable(Component c) {
1113         while (c != null && !(c instanceof WEmbeddedFrame)) {
1114             c = c.getParent();
1115         }
1116         if (c == null) {
1117             return true;
1118         }
1119         final WEmbeddedFramePeer peer = AWTAccessor.getComponentAccessor()
1120                                                    .getPeer(c);
1121         return peer.isAccelCapable();
1122     }
1123 
1124     /**
1125      * Applies the shape to the native component window.
1126      * @since 1.7
1127      */
1128     @Override
applyShape(Region shape)1129     public void applyShape(Region shape) {
1130         if (shapeLog.isLoggable(PlatformLogger.Level.FINER)) {
1131             shapeLog.finer("*** INFO: Setting shape: PEER: " + this
1132                             + "; TARGET: " + target
1133                             + "; SHAPE: " + shape);
1134         }
1135 
1136         if (shape != null) {
1137             AffineTransform tx = winGraphicsConfig.getDefaultTransform();
1138             double scaleX = tx.getScaleX();
1139             double scaleY = tx.getScaleY();
1140             if (scaleX != 1 || scaleY != 1) {
1141                 shape = shape.getScaledRegion(scaleX, scaleY);
1142             }
1143             setRectangularShape(shape.getLoX(), shape.getLoY(), shape.getHiX(), shape.getHiY(),
1144                     (shape.isRectangular() ? null : shape));
1145         } else {
1146             setRectangularShape(0, 0, 0, 0, null);
1147         }
1148     }
1149 
1150     /**
1151      * Lowers this component at the bottom of the above component. If the above parameter
1152      * is null then the method places this component at the top of the Z-order.
1153      */
1154     @Override
setZOrder(ComponentPeer above)1155     public void setZOrder(ComponentPeer above) {
1156         long aboveHWND = (above != null) ? ((WComponentPeer)above).getHWnd() : 0;
1157 
1158         setZOrder(aboveHWND);
1159     }
1160 
setZOrder(long above)1161     private native void setZOrder(long above);
1162 
isLightweightFramePeer()1163     public boolean isLightweightFramePeer() {
1164         return false;
1165     }
1166 }
1167