| /* Copyright (C) 2000, 2002, 2003 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| package gnu.awt.xlib; |
| |
| import java.awt.Dimension; |
| import java.awt.BufferCapabilities; |
| import java.awt.Component; |
| import java.awt.EventQueue; |
| import java.awt.Rectangle; |
| import java.awt.Color; |
| import java.awt.Container; |
| import java.awt.Image; |
| import java.awt.GraphicsConfiguration; |
| import java.awt.Font; |
| import java.awt.FontMetrics; |
| import java.awt.Graphics; |
| import java.awt.Point; |
| import java.awt.Toolkit; |
| import java.awt.AWTEvent; |
| import java.awt.Cursor; |
| import java.awt.Shape; |
| |
| import java.awt.peer.*; |
| import java.awt.image.*; |
| |
| import java.awt.event.MouseListener; |
| import java.awt.event.PaintEvent; |
| |
| import java.util.EventListener; |
| |
| import gnu.gcj.xlib.WMSizeHints; |
| import gnu.gcj.xlib.Window; |
| import gnu.gcj.xlib.WindowAttributes; |
| import gnu.gcj.xlib.Display; |
| import gnu.gcj.xlib.Visual; |
| import gnu.gcj.xlib.Screen; |
| import gnu.gcj.xlib.XImage; |
| |
| import gnu.awt.j2d.*; |
| |
| public class XCanvasPeer implements CanvasPeer |
| { |
| static final Dimension MIN_SIZE = new Dimension(1, 1); |
| |
| public // temporary |
| |
| Window window; |
| Window parent; |
| |
| Component component; |
| XGraphicsConfiguration config; |
| private WindowAttributes attributes = new WindowAttributes(); |
| private long eventMask; |
| |
| public XCanvasPeer(Component component) |
| { |
| this.component = component; |
| |
| // Set up graphics configuration (ie. screen + visual): |
| |
| config = (XGraphicsConfiguration) |
| component.getGraphicsConfiguration(); |
| |
| if (config == null) |
| { |
| // This will usually only happen for toplevel windows |
| config = getXToolkit().getDefaultXGraphicsConfiguration(); |
| } |
| |
| Rectangle bounds = component.getBounds(); |
| parent = locateParentWindow(bounds); |
| |
| // Windows in X must atleast be of size 1x1 |
| boolean boundsChanged = false; |
| if (bounds.width < 1) |
| { |
| boundsChanged = true; |
| bounds.width = 1; |
| } |
| if (bounds.height < 1) |
| { |
| boundsChanged = true; |
| bounds.height = 1; |
| } |
| |
| /* don't worry about this calling back to us, since the real |
| component object has not yet received a reference to this peer |
| object. */ |
| component.setBounds(bounds); |
| |
| |
| /* Set background color */ |
| Color bg = component.getBackground(); |
| if (bg != null) |
| { |
| int[] components = |
| { |
| bg.getRed(), |
| bg.getGreen(), |
| bg.getBlue(), |
| 0xff |
| }; |
| |
| ColorModel cm = config.getColorModel(); |
| long pixel = cm.getDataElement(components, 0); |
| attributes.setBackground(pixel); |
| } |
| |
| /* Set exposure mask so that we get exposure events |
| that can be translated into paint() calls. */ |
| long eventMask = WindowAttributes.MASK_EXPOSURE; |
| |
| /* It would be nice to set up all other required events here, but |
| it is not possible to do so before after all the children of |
| this component has been realized. The reason is that it is not |
| determined whether a component is lightweight before after the |
| addNotify() method has been called. Thus, it is not possible |
| for parent component to determine what events it needs to |
| furnish for lightweight children. Instead, we currently rely |
| on the component calling our setEventMask() method after the |
| correct event mask has been determined. */ |
| |
| attributes.setEventMask(eventMask); |
| |
| |
| // TODO: set more window attributes? |
| |
| /* don't allow event queue to process events from the newly |
| created window before this peer has been registered as client |
| data. */ |
| synchronized (getXToolkit().eventLoop) |
| { |
| window = new gnu.gcj.xlib.Window(parent, bounds, attributes); |
| window.setClientData(this); /* make it possible to find back |
| to this peer object. Used by |
| XEventQueue. */ |
| } |
| |
| initWindowProperties(); |
| |
| if (component.isVisible()) |
| EventQueue.invokeLater(new DoMap(window)); |
| } |
| |
| /** |
| * Override this in subclasses to implement other ways of obtaining |
| * parent windows. Toplevel windows will typically have a different |
| * implementation. |
| */ |
| gnu.gcj.xlib.Window locateParentWindow(Rectangle bounds) |
| { |
| Container parent = component.getParent(); |
| while (parent.isLightweight()) |
| { |
| bounds.x += parent.getX(); |
| bounds.y += parent.getY(); |
| parent = parent.getParent(); |
| // a null pointer here is a genuine error |
| } |
| |
| XCanvasPeer parentPeer = (XCanvasPeer) parent.getPeer(); |
| if (parentPeer == null) |
| throw new NullPointerException("Parent has no peer. This should " + |
| "not be possible, since the " + |
| "calls leading here should come " + |
| "from parent, after it has " + |
| "set the parent peer."); |
| return parentPeer.window; |
| } |
| |
| |
| /** |
| * Template method to allow subclasses to apply properties to X11 |
| * window right after creation. |
| */ |
| void initWindowProperties() |
| { |
| } |
| |
| XToolkit getXToolkit() |
| { |
| return XToolkit.INSTANCE; |
| } |
| |
| protected void ensureFlush() |
| { |
| getXToolkit().flushIfIdle(); |
| } |
| |
| public Component getComponent() |
| { |
| return component; |
| } |
| |
| long getBasicEventMask() |
| { |
| return WindowAttributes.MASK_EXPOSURE; |
| } |
| |
| // -------- java.awt.peer.ComponentPeer implementation |
| |
| public int checkImage(Image img, int width, int height, ImageObserver o) |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| public Image createImage(ImageProducer prod) |
| { |
| return new XOffScreenImage (config, window, prod, config.getColorModel()); |
| } |
| public Image createImage(int width, int height) |
| { |
| return new XOffScreenImage (config, window, width, height, config.getColorModel()); |
| } |
| public void dispose() |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public GraphicsConfiguration getGraphicsConfiguration() |
| { |
| return config; |
| } |
| |
| public FontMetrics getFontMetrics(Font f) |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public ColorModel getColorModel () |
| { |
| return null; |
| } |
| |
| public Graphics getGraphics() |
| { |
| DirectRasterGraphics gfxDevice = new XGraphics(window, config); |
| IntegerGraphicsState igState = new IntegerGraphicsState(gfxDevice); |
| Graphics2DImpl gfx2d = new Graphics2DImpl(config); |
| |
| gfx2d.setState(igState); |
| gfx2d.setColor(component.getBackground()); |
| return gfx2d; |
| } |
| |
| private Rectangle locationBounds; |
| public Point getLocationOnScreen() |
| { |
| locationBounds = window.getBounds (locationBounds); |
| return new Point (locationBounds.x,locationBounds.y); |
| } |
| |
| public Dimension getMinimumSize () |
| { |
| return MIN_SIZE; |
| } |
| |
| public Dimension minimumSize () |
| { |
| return getMinimumSize (); |
| } |
| |
| public Dimension getPreferredSize () |
| { |
| return component.getSize(); |
| } |
| |
| public Dimension preferredSize () |
| { |
| return getPreferredSize(); |
| } |
| |
| public Toolkit getToolkit() |
| { |
| return getXToolkit(); |
| } |
| |
| public void handleEvent(AWTEvent event) |
| { |
| int id = event.getID (); |
| |
| switch (id) |
| { |
| case PaintEvent.PAINT: |
| case PaintEvent.UPDATE: |
| { |
| try |
| { |
| Graphics g = getGraphics (); |
| g.setClip (((PaintEvent)event).getUpdateRect ()); |
| |
| if (id == PaintEvent.PAINT) |
| component.paint (g); |
| else |
| component.update (g); |
| |
| g.dispose (); |
| } |
| catch (InternalError e) |
| { |
| System.err.println (e); |
| } |
| } |
| break; |
| } |
| } |
| |
| public boolean isFocusTraversable() |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public void paint(Graphics gfx) |
| { |
| // do nothing by default |
| } |
| |
| public boolean prepareImage(Image img, int width, int height, |
| ImageObserver o) |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public void print(Graphics graphics) |
| { |
| paint(graphics); |
| } |
| |
| public void repaint(long tm, int x, int y, int w, int h) |
| { |
| /* TODO? |
| |
| X allows intelligent X servers to do smart |
| refreshing. Perhaps involve X in repainting of components, |
| rather that keeping it all within the local event queue. */ |
| |
| PaintEvent updateEvent = new PaintEvent(component, |
| PaintEvent.UPDATE, |
| new Rectangle(x, y, w, h)); |
| getXToolkit().queue.postEvent(updateEvent); |
| } |
| |
| public void requestFocus() |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public void setBackground(Color color) |
| { |
| if (color != null) |
| { |
| int[] components = |
| { |
| color.getRed (), |
| color.getGreen (), |
| color.getBlue (), |
| 0xff |
| }; |
| |
| ColorModel cm = config.getColorModel (); |
| long pixel = cm.getDataElement (components, 0); |
| attributes.setBackground (pixel); |
| window.setAttributes (attributes); |
| } |
| } |
| |
| public void setBounds(int x, int y, int width, int height) |
| { |
| width = Math.max(width, 1); |
| height = Math.max(height, 1); |
| window.setBounds(x, y, width, height); |
| ensureFlush(); |
| } |
| |
| public void reshape (int x, int y, int width, int height) |
| { |
| setBounds (x, y, width, height); |
| } |
| |
| public void setCursor(Cursor cursor) |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public void setEnabled(boolean enabled) |
| { |
| throw new UnsupportedOperationException("FIXME, not implemented"); |
| } |
| |
| public void enable () |
| { |
| setEnabled (true); |
| } |
| |
| public void disable () |
| { |
| setEnabled (false); |
| } |
| |
| public void setEventMask(long eventMask) |
| { |
| if (this.eventMask != eventMask) |
| { |
| this.eventMask = eventMask; |
| long xEventMask = getBasicEventMask (); |
| |
| if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) |
| { |
| xEventMask |= |
| WindowAttributes.MASK_BUTTON_PRESS | |
| WindowAttributes.MASK_BUTTON_RELEASE; |
| } |
| |
| attributes.setEventMask (xEventMask); |
| window.setAttributes (attributes); |
| ensureFlush (); |
| } |
| } |
| |
| public void setFont(Font font) |
| { |
| /* default canvas peer does not keep track of font, since it won't |
| paint anything. */ |
| } |
| |
| public void setForeground(Color color) |
| { |
| /* default canvas peer does not keep track of foreground, since it won't |
| paint anything. */ |
| } |
| |
| public void setVisible(boolean visible) |
| { |
| if (visible) |
| { |
| window.map(); |
| ensureFlush(); |
| } |
| else |
| { |
| window.unmap(); |
| ensureFlush(); |
| } |
| } |
| |
| public void show () |
| { |
| setVisible (true); |
| } |
| |
| public void hide () |
| { |
| setVisible (false); |
| } |
| |
| public boolean isFocusable () |
| { |
| return false; |
| } |
| |
| public boolean requestFocus (Component source, boolean b1, |
| boolean b2, long x) |
| { |
| return false; |
| } |
| |
| public boolean isObscured () |
| { |
| return false; |
| } |
| |
| public boolean canDetermineObscurity () |
| { |
| return false; |
| } |
| |
| public void coalescePaintEvent (PaintEvent e) |
| { |
| } |
| |
| public void updateCursorImmediately () |
| { |
| } |
| |
| public VolatileImage createVolatileImage (int width, int height) |
| { |
| return null; |
| } |
| |
| public boolean handlesWheelScrolling () |
| { |
| return false; |
| } |
| |
| public void createBuffers (int x, BufferCapabilities capabilities) |
| throws java.awt.AWTException |
| |
| { |
| } |
| |
| public Image getBackBuffer () |
| { |
| return null; |
| } |
| |
| public void flip (BufferCapabilities.FlipContents contents) |
| { |
| } |
| |
| public void destroyBuffers () |
| { |
| } |
| |
| static class DoMap implements Runnable |
| { |
| Window window; |
| public DoMap(Window w) |
| { |
| this.window = w; |
| } |
| |
| public void run() |
| { |
| window.map(); |
| } |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public boolean isRestackSupported () |
| { |
| return false; |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public void cancelPendingPaint (int x, int y, int width, int height) |
| { |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public void restack () |
| { |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public Rectangle getBounds () |
| { |
| return null; |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public void reparent (ContainerPeer parent) |
| { |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public void setBounds (int x, int y, int width, int height, int z) |
| { |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public boolean isReparentSupported () |
| { |
| return false; |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| public void layout () |
| { |
| } |
| } |