/* * This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com> * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) */ /* * @(#)WComponentPeer.java 1.137 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package sun.awt.windows; import java.awt.*; import java.awt.peer.*; import java.awt.image.MemoryImageSource; import java.awt.image.WritableRaster; import java.awt.image.VolatileImage; import sun.awt.RepaintArea; import sun.awt.AppContext; import sun.awt.image.ImageRepresentation; import sun.awt.image.OffScreenImage; import java.awt.image.BufferedImage; import java.awt.image.ImageProducer; import java.awt.image.ImageObserver; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.event.PaintEvent; import sun.awt.Win32GraphicsConfig; import sun.awt.Win32GraphicsDevice; import sun.java2d.InvalidPipeException; import sun.java2d.SunGraphics2D; import sun.awt.DisplayChangedListener; import java.awt.dnd.DropTarget; import java.awt.dnd.peer.DropTargetPeer; import sun.awt.DebugHelper; public abstract class WComponentPeer extends WObjectPeer implements ComponentPeer, DropTargetPeer, DisplayChangedListener { private static final boolean ddoffscreen = ddoffscreen(); static { wheelInit(); } private static boolean ddoffscreen() { String ddoffscreenProp = (String)java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("sun.java2d.ddoffscreen")); if (ddoffscreenProp != null) { if (ddoffscreenProp.equals("true") || ddoffscreenProp.equals("t")) return true; if (ddoffscreenProp.equals("false") || ddoffscreenProp.equals("f")) System.out.println("Disabling offscreen DirectDraw acceleration"); } return false; } // Only actually does stuff if running on 95 native static void wheelInit(); // ComponentPeer implementation Win32SurfaceData surfaceData; private RepaintArea paintArea; protected Win32GraphicsConfig winGraphicsConfig; boolean isLayouting = false; boolean paintPending = false; int oldWidth = -1; int oldHeight = -1; private int numBackBuffers = 0; private Win32BackBuffer backBuffer = null; public native boolean isObscured(); public boolean canDetermineObscurity() { return true; } // DropTarget support int nDropTargets; long nativeDropTargetContext; // native pointer public synchronized native void pShow(); public synchronized native void hide(); public synchronized native void enable(); public synchronized native void disable(); /* New 1.1 API */ public native Point getLocationOnScreen(); /* New 1.1 API */ public void setVisible(boolean b) { if (b) { show(); } else { hide(); } } public void show() { Dimension s = ((Component)target).getSize(); oldHeight = s.height; oldWidth = s.width; pShow(); } /* New 1.1 API */ public void setEnabled(boolean b) { if (b) { enable(); } else { disable(); } } public int serialNum = 0; /* New 1.1 API */ public void setBounds(int x, int y, int width, int height) { // Should set paintPending before reahape to prevent // thread race between paint events // Native components do redraw after resize paintPending = (width != oldWidth) || (height != oldHeight); reshape(x, y, width, height); if ((width != oldWidth) || (height != oldHeight)) { // Only recreate surfaceData if this setBounds is called // for a resize; a simple move should not trigger a recreation try { replaceSurfaceData(); } catch (InvalidPipeException e) { // REMIND : what do we do if our surface creation failed? } oldWidth = width; oldHeight = height; } serialNum++; } /* * Called from native code (on Toolkit thread) in order to * dynamically layout the Container during resizing */ void dynamicallyLayoutContainer() { // If we got the WM_SIZING, this must be a Container, right? // In fact, it must be the top-level Container. final Container cont = (Container)target; WToolkit.executeOnEventHandlerThread(cont, new Runnable() { public void run() { // Discarding old paint events doesn't seem to be necessary. cont.invalidate(); cont.validate(); // Forcing a paint here doesn't seem to be necessary. // paintDamagedAreaImmediately(); } }); } /* * Paints any portion of the component that needs updating * before the call returns (similar to the Win32 API UpdateWindow) */ void paintDamagedAreaImmediately() { // force Windows to send any pending WM_PAINT events so // the damage area is updated on the Java side updateWindow(); // make sure paint events are transferred to main event queue // for coalescing WToolkit.getWToolkit().flushPendingEvents(); // paint the damaged area paintArea.paint(target, shouldClearRectBeforePaint()); } native synchronized void updateWindow(); public void paint(Graphics g) { ((Component)target).paint(g); } public void repaint(long tm, int x, int y, int width, int height) { } private static final double BANDING_DIVISOR = 4.0; private native int[] createPrintedPixels(int srcX, int srcY, int srcW, int srcH); public void print(Graphics g) { Component comp = (Component)target; // To conserve memory usage, we will band the image. int totalW = comp.getWidth(); int totalH = comp.getHeight(); int hInc = (int)(totalH / BANDING_DIVISOR); for (int startY = 0; startY < totalH; startY += hInc) { int endY = startY + hInc - 1; if (endY >= totalH) { endY = totalH - 1; } int h = endY - startY + 1; int[] pix = createPrintedPixels(0, startY, totalW, h); if (pix != null) { BufferedImage bim = new BufferedImage(totalW, h, BufferedImage.TYPE_INT_RGB); bim.setRGB(0, 0, totalW, h, pix, 0, totalW); g.drawImage(bim, 0, startY, null); bim.flush(); } } comp.print(g); } public void coalescePaintEvent(PaintEvent e) { Rectangle r = e.getUpdateRect(); paintArea.add(r, e.getID()); } public synchronized native void reshape(int x, int y, int width, int height); native void nativeHandleEvent(AWTEvent e); public void handleEvent(AWTEvent e) { int id = e.getID(); switch(id) { case PaintEvent.PAINT: // Got native painting paintPending = false; // Fallthrough to next statement case PaintEvent.UPDATE: // Skip all painting while layouting and all UPDATEs // while waiting for native paint if (!isLayouting && ! paintPending) { paintArea.paint(target,shouldClearRectBeforePaint()); } return; default: break; } // Call the native code nativeHandleEvent(e); } public Dimension getMinimumSize() { return ((Component)target).getSize(); } public Dimension getPreferredSize() { return getMinimumSize(); } public Rectangle getBounds() { return ((Component)target).getBounds(); } public boolean isFocusable() { return false; } /* * Return the GraphicsConfiguration associated with this peer, either * the locally stored winGraphicsConfig, or that of the target Component. */ public GraphicsConfiguration getGraphicsConfiguration() { if (winGraphicsConfig != null) { return winGraphicsConfig; } else { // we don't need a treelock here, since // Component.getGraphicsConfiguration() gets it itself. return ((Component)target).getGraphicsConfiguration(); } } public Win32SurfaceData getSurfaceData() { return surfaceData; } /** * Creates new surfaceData object and invalidates the previous * surfaceData object. * Replacing the surface data should never lock on any resources which are * required by other threads which may have them and may require * the tree-lock. */ public void replaceSurfaceData() { synchronized(((Component)target).getTreeLock()) { synchronized(this) { if (pData == 0) { return; } Win32SurfaceData oldData = surfaceData; surfaceData = Win32SurfaceData.createData(this, numBackBuffers); if (oldData != null) { oldData.invalidate(); } createBackBuffer(); } } } public void replaceSurfaceDataLater() { EventQueue.invokeLater(new Runnable() { public void run() { try { replaceSurfaceData(); } catch (InvalidPipeException e) { // REMIND : what do we do if our surface creation failed? } } }); } /** * From the DisplayChangedListener interface. * * Called after a change in the display mode. This event * triggers replacing the surfaceData object (since that object * reflects the current display depth information, which has * just changed). */ public void displayChanged() { try { replaceSurfaceData(); } catch (InvalidPipeException e) { // REMIND : what do we do if our surface creation failed? } } /** * Part of the DisplayChangedListener interface: components * do not need to react to this event */ public void paletteChanged() { } //This will return null for Components not yet added to a Container public ColorModel getColorModel() { GraphicsConfiguration gc = getGraphicsConfiguration(); if (gc != null) { return gc.getColorModel(); } else { return null; } } //This will return null for Components not yet added to a Container public ColorModel getDeviceColorModel() { Win32GraphicsConfig gc = (Win32GraphicsConfig)getGraphicsConfiguration(); if (gc != null) { return gc.getDeviceColorModel(); } else { return null; } } //Returns null for Components not yet added to a Container public ColorModel getColorModel(int transparency) { // return WToolkit.config.getColorModel(transparency); GraphicsConfiguration gc = getGraphicsConfiguration(); if (gc != null) { return gc.getColorModel(transparency); } else { return null; } } public java.awt.Toolkit getToolkit() { return Toolkit.getDefaultToolkit(); } // fallback default font object final static Font defaultFont = new Font("Dialog", Font.PLAIN, 12); public synchronized Graphics getGraphics() { if (!isDisposed()) { Component target = (Component) this.target; /* Fix for bug 4746122. Color and Font shouldn't be null */ Color bgColor = target.getBackground(); if (bgColor == null) { bgColor = SystemColor.window; } Color fgColor = target.getForeground(); if (fgColor == null) { fgColor = SystemColor.windowText; } Font font = target.getFont(); if (font == null) { font = defaultFont; } return new SunGraphics2D(surfaceData, fgColor, bgColor, font); } return null; } public FontMetrics getFontMetrics(Font font) { return WFontMetrics.getFontMetrics(font); } private synchronized native void _dispose(); protected void disposeImpl() { Win32SurfaceData oldData = surfaceData; surfaceData = null; oldData.invalidate(); // remove from updater before calling targetDisposedPeer WToolkit.targetDisposedPeer(target, this); _dispose(); } public synchronized void setForeground(Color c) {_setForeground(c.getRGB());} public synchronized void setBackground(Color c) {_setBackground(c.getRGB());} public native void _setForeground(int rgb); public native void _setBackground(int rgb); public synchronized native void setFont(Font f); public final void updateCursorImmediately() { WGlobalCursorManager.getCursorManager().updateCursorImmediately(); } native static boolean processSynchronousLightweightTransfer(Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time); public boolean requestFocus (Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time) { if (processSynchronousLightweightTransfer((Component)target, lightweightChild, temporary, focusedWindowChangeAllowed, time)) { return true; } else { return _requestFocus(lightweightChild, temporary, focusedWindowChangeAllowed, time); } } public native boolean _requestFocus (Component lightweightChild, boolean temporary, boolean focusedWindowChangeAllowed, long time); public Image createImage(ImageProducer producer) { return new WImage(producer); } public Image createImage(int width, int height) { if (ddoffscreen) { return (Image)createVolatileImage(width, height); } else { ColorModel model = getColorModel(Transparency.OPAQUE); WritableRaster wr = model.createCompatibleWritableRaster(width, height); return new Win32OffScreenImage((Component)target, model, wr, model.isAlphaPremultiplied()); } } public VolatileImage createVolatileImage(int width, int height) { return new WVolatileImage((Component)target, width, height); } public boolean prepareImage(Image img, int w, int h, ImageObserver o) { return WToolkit.prepareScrImage(img, w, h, o); } public int checkImage(Image img, int w, int h, ImageObserver o) { return WToolkit.checkScrImage(img, w, h, o); } // Object overrides public String toString() { return getClass().getName() + "[" + target + "]"; } // Toolkit & peer internals private int updateX1, updateY1, updateX2, updateY2; WComponentPeer(Component target) { this.target = target; this.paintArea = new RepaintArea(); Container parent = WToolkit.getNativeContainer(target); WComponentPeer parentPeer = (WComponentPeer) WToolkit.targetToPeer(parent); create(parentPeer); this.surfaceData = Win32SurfaceData.createData(this, numBackBuffers); initialize(); start(); // Initialize enable/disable state, turn on callbacks } abstract void create(WComponentPeer parent); synchronized native void start(); void initialize() { initZOrderPosition(); if (((Component)target).isVisible()) { show(); // the wnd starts hidden } Color fg = ((Component)target).getForeground(); if (fg != null) { setForeground(fg); } // Set background color in C++, to avoid inheriting a parent's color. Font f = ((Component)target).getFont(); if (f != null) { setFont(f); } if (! ((Component)target).isEnabled()) { disable(); } Rectangle r = ((Component)target).getBounds(); setBounds(r.x, r.y, r.width, r.height); } // Callbacks for window-system events to the frame // Invoke a update() method call on the target void handleRepaint(int x, int y, int w, int h) { // Repaints are posted from updateClient now... } // Invoke a paint() method call on the target, after clearing the // damaged area. void handleExpose(int x, int y, int w, int h) { // Bug ID 4081126 & 4129709 - can't do the clearRect() here, // since it interferes with the java thread working in the // same window on multi-processor NT machines. if (!((Component)target).getIgnoreRepaint()) { postEvent(new PaintEvent((Component)target, PaintEvent.PAINT, new Rectangle(x, y, w, h))); } } /* Invoke a paint() method call on the target, without clearing the * damaged area. This is normally called by a native control after * it has painted itself. * * NOTE: This is called on the privileged toolkit thread. Do not * call directly into user code using this thread! */ void handlePaint(int x, int y, int w, int h) { if (!((Component)target).getIgnoreRepaint()) { postEvent(new PaintEvent((Component)target, PaintEvent.PAINT, new Rectangle(x, y, w, h))); } } /* * Post an event. Queue it for execution by the callback thread. */ void postEvent(AWTEvent event) { WToolkit.postEvent(WToolkit.targetToAppContext(target), event); } // Routines to support deferred window positioning. public void beginLayout() { // Skip all painting till endLayout isLayouting = true; } public void endLayout() { if(!paintArea.isEmpty() && !paintPending && !((Component)target).getIgnoreRepaint()) { // if not waiting for native painting repaint damaged area postEvent(new PaintEvent((Component)target, PaintEvent.PAINT, new Rectangle())); } isLayouting = false; } public native void beginValidate(); public native void endValidate(); public void initZOrderPosition() { Container p = ((Component)target).getParent(); WComponentPeer peerAbove = null; if (p != null) { Component children[] = p.getComponents(); for (int i = 0; i < children.length; i++) { if (children[i] == target) { break; } else { Object cpeer = WToolkit.targetToPeer(children[i]); if (cpeer != null && !(cpeer instanceof java.awt.peer.LightweightPeer)) { peerAbove = (WComponentPeer)cpeer; } } } } setZOrderPosition(peerAbove); } native void setZOrderPosition(WComponentPeer compAbove); /** * DEPRECATED */ public Dimension minimumSize() { return getMinimumSize(); } /** * DEPRECATED */ public Dimension preferredSize() { return getPreferredSize(); } /** * register a DropTarget with this native peer */ public synchronized void addDropTarget(DropTarget dt) { if (nDropTargets == 0) { nativeDropTargetContext = addNativeDropTarget(); } nDropTargets++; } /** * unregister a DropTarget with this native peer */ public synchronized void removeDropTarget(DropTarget dt) { nDropTargets--; if (nDropTargets == 0) { removeNativeDropTarget(); nativeDropTargetContext = 0; } } /** * add the native peer's AwtDropTarget COM object * @return reference to AwtDropTarget object */ native long addNativeDropTarget(); /** * remove the native peer's AwtDropTarget COM object */ native void removeNativeDropTarget(); native boolean nativeHandlesWheelScrolling(); public boolean handlesWheelScrolling() { // should this be cached? return nativeHandlesWheelScrolling(); } // Returns true if we are inside begin/endLayout and // are waiting for native painting public boolean isPaintPending() { return paintPending && isLayouting; } // Multi-buffering private boolean isFullScreenExclusive() { GraphicsConfiguration gc = getGraphicsConfiguration(); Win32GraphicsDevice gd = (Win32GraphicsDevice)gc.getDevice(); Component target = (Component)this.target; while (target != null && !(target instanceof Window)) { target = target.getParent(); } return (target == gd.getFullScreenWindow()) && gd.isDDEnabledOnDevice(); } public synchronized void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException { if (!isFullScreenExclusive()) { throw new AWTException( "The operation requested is only supported on a full-screen" + " exclusive window"); } // Re-create the primary surface this.numBackBuffers = (numBuffers - 1); try { replaceSurfaceData(); } catch (InvalidPipeException e) { throw new AWTException(e.getMessage()); } } public synchronized void destroyBuffers() { disposeBackBuffer(); numBackBuffers = 0; } private synchronized void disposeBackBuffer() { if (backBuffer == null) { return; } backBuffer = null; } private synchronized void createBackBuffer() { if (numBackBuffers > 0) { // Create the back buffer object backBuffer = new Win32BackBuffer((Component)target, surfaceData); } else { backBuffer = null; } } public synchronized void flip(BufferCapabilities.FlipContents flipAction) { if (backBuffer == null) { throw new IllegalStateException( "Buffers have not been created"); } Component target = (Component)this.target; int width = target.getWidth(); int height = target.getHeight(); if (flipAction == BufferCapabilities.FlipContents.COPIED) { Graphics g = target.getGraphics(); g.drawImage(backBuffer, 0, 0, width, height, target); g.dispose(); } else { try { surfaceData.flip(backBuffer.getHWSurfaceData()); } catch (sun.java2d.InvalidPipeException e) { return; // Flip failed } if (flipAction == BufferCapabilities.FlipContents.BACKGROUND) { Graphics g = backBuffer.getGraphics(); g.setColor(target.getBackground()); g.fillRect(0, 0, width, height); g.dispose(); } } } public Image getBackBuffer() { if (backBuffer == null) { throw new IllegalStateException("Buffers have not been created"); } return backBuffer; } /* override and return false on components that DO NOT require a clearRect() before painting (i.e. native components) */ public boolean shouldClearRectBeforePaint() { return true; } }