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