mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			921 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			921 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* GtkComponentPeer.java -- Implements ComponentPeer with GTK
 | |
|    Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
 | |
|    Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package gnu.java.awt.peer.gtk;
 | |
| 
 | |
| import java.awt.AWTEvent;
 | |
| import java.awt.AWTException;
 | |
| import java.awt.BufferCapabilities;
 | |
| import java.awt.Color;
 | |
| import java.awt.Component;
 | |
| import java.awt.Container;
 | |
| import java.awt.Cursor;
 | |
| import java.awt.Dimension;
 | |
| import java.awt.EventQueue;
 | |
| import java.awt.Font;
 | |
| import java.awt.FontMetrics;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.GraphicsConfiguration;
 | |
| import java.awt.GraphicsDevice;
 | |
| import java.awt.GraphicsEnvironment;
 | |
| import java.awt.Image;
 | |
| import java.awt.Insets;
 | |
| import java.awt.ItemSelectable;
 | |
| import java.awt.KeyboardFocusManager;
 | |
| import java.awt.Point;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.Toolkit;
 | |
| import java.awt.Window;
 | |
| import java.awt.event.FocusEvent;
 | |
| import java.awt.event.ItemEvent;
 | |
| import java.awt.event.KeyEvent;
 | |
| import java.awt.event.MouseEvent;
 | |
| import java.awt.event.MouseWheelEvent;
 | |
| import java.awt.event.PaintEvent;
 | |
| import java.awt.event.TextEvent;
 | |
| import java.awt.image.ColorModel;
 | |
| import java.awt.image.ImageObserver;
 | |
| import java.awt.image.ImageProducer;
 | |
| import java.awt.image.VolatileImage;
 | |
| import java.awt.peer.ComponentPeer;
 | |
| import java.awt.peer.ContainerPeer;
 | |
| import java.awt.peer.LightweightPeer;
 | |
| import java.util.Timer;
 | |
| import java.util.TimerTask;
 | |
| 
 | |
| public class GtkComponentPeer extends GtkGenericPeer
 | |
|   implements ComponentPeer
 | |
| {
 | |
|   VolatileImage backBuffer;
 | |
|   BufferCapabilities caps;
 | |
| 
 | |
|   Component awtComponent;
 | |
| 
 | |
|   Insets insets;
 | |
| 
 | |
|   /**
 | |
|    * The current repaint area. Use should be guarded by synchronizing on this.
 | |
|    */
 | |
|   private Rectangle currentPaintArea;
 | |
| 
 | |
|   /* this isEnabled differs from Component.isEnabled, in that it
 | |
|      knows if a parent is disabled.  In that case Component.isEnabled
 | |
|      may return true, but our isEnabled will always return false */
 | |
|   native boolean isEnabled ();
 | |
|   static native boolean modalHasGrab();
 | |
| 
 | |
|   native int[] gtkWidgetGetForeground ();
 | |
|   native int[] gtkWidgetGetBackground ();
 | |
|   native void gtkWidgetGetDimensions (int[] dim);
 | |
|   native void gtkWidgetGetPreferredDimensions (int[] dim);
 | |
|   native void gtkWindowGetLocationOnScreen (int[] point);
 | |
|   native void gtkWindowGetLocationOnScreenUnlocked (int[] point);
 | |
|   native void gtkWidgetGetLocationOnScreen (int[] point);
 | |
|   native void gtkWidgetGetLocationOnScreenUnlocked (int[] point);
 | |
|   native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y);
 | |
|   native void gtkWidgetSetCursorUnlocked (int type, GtkImage image,
 | |
|                                           int x, int y);
 | |
|   native void gtkWidgetSetBackground (int red, int green, int blue);
 | |
|   native void gtkWidgetSetForeground (int red, int green, int blue);
 | |
|   native void gtkWidgetSetSensitive (boolean sensitive);
 | |
|   native void gtkWidgetSetParent (ComponentPeer parent);
 | |
|   native void gtkWidgetRequestFocus ();
 | |
|   native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
 | |
|                                          int keyCode, int keyLocation);
 | |
|   native boolean gtkWidgetHasFocus();
 | |
|   native boolean gtkWidgetCanFocus();
 | |
| 
 | |
|   native void realize();
 | |
|   native void setNativeEventMask ();
 | |
| 
 | |
|   void create ()
 | |
|   {
 | |
|     throw new RuntimeException ();
 | |
|   }
 | |
| 
 | |
|   native void connectSignals ();
 | |
| 
 | |
|   protected GtkComponentPeer (Component awtComponent)
 | |
|   {
 | |
|     super (awtComponent);
 | |
|     this.awtComponent = awtComponent;
 | |
|     insets = new Insets (0, 0, 0, 0);
 | |
| 
 | |
|     create ();
 | |
| 
 | |
|     connectSignals ();
 | |
| 
 | |
|     if (awtComponent.getForeground () != null)
 | |
|       setForeground (awtComponent.getForeground ());
 | |
|     if (awtComponent.getBackground () != null)
 | |
|       setBackground (awtComponent.getBackground ());
 | |
|     if (awtComponent.getFont() != null)
 | |
|       setFont(awtComponent.getFont());
 | |
| 
 | |
|     Component parent = awtComponent.getParent ();
 | |
| 
 | |
|     setParentAndBounds ();
 | |
| 
 | |
|     setNativeEventMask ();
 | |
| 
 | |
|     // This peer is guaranteed to have an X window upon construction.
 | |
|     // That is, native methods such as those in GdkGraphics can rely
 | |
|     // on this component's widget->window field being non-null.
 | |
|     realize ();
 | |
| 
 | |
|     if (awtComponent.isCursorSet())
 | |
|       setCursor ();
 | |
|   }
 | |
| 
 | |
|   void setParentAndBounds ()
 | |
|   {
 | |
|     setParent ();
 | |
| 
 | |
|     setComponentBounds ();
 | |
| 
 | |
|     setVisibleAndEnabled ();
 | |
|   }
 | |
| 
 | |
|   void setParent ()
 | |
|   {
 | |
|     ComponentPeer p;
 | |
|     Component component = awtComponent;
 | |
|     do
 | |
|       {
 | |
|         component = component.getParent ();
 | |
|         p = component.getPeer ();
 | |
|       }
 | |
|     while (p instanceof java.awt.peer.LightweightPeer);
 | |
| 
 | |
|     if (p != null)
 | |
|       gtkWidgetSetParent (p);
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|    * Set the bounds of this peer's AWT Component based on dimensions
 | |
|    * returned by the native windowing system.  Most Components impose
 | |
|    * their dimensions on the peers which is what the default
 | |
|    * implementation does.  However some peers, like GtkFileDialogPeer,
 | |
|    * need to pass their size back to the AWT Component.
 | |
|    */
 | |
|   void setComponentBounds ()
 | |
|   {
 | |
|     Rectangle bounds = awtComponent.getBounds ();
 | |
|     setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
 | |
|   }
 | |
| 
 | |
|   void setVisibleAndEnabled ()
 | |
|   {
 | |
|     setVisible (awtComponent.isVisible ());
 | |
|     setEnabled (awtComponent.isEnabled ());
 | |
|   }
 | |
| 
 | |
|   public int checkImage (Image image, int width, int height,
 | |
|                          ImageObserver observer)
 | |
|   {
 | |
|     return getToolkit().checkImage(image, width, height, observer);
 | |
|   }
 | |
| 
 | |
|   public Image createImage (ImageProducer producer)
 | |
|   {
 | |
|     return new GtkImage (producer);
 | |
|   }
 | |
| 
 | |
|   public Image createImage (int width, int height)
 | |
|   {
 | |
|     return CairoSurface.getBufferedImage(width, height);
 | |
|   }
 | |
| 
 | |
|   public void disable ()
 | |
|   {
 | |
|     setEnabled (false);
 | |
|   }
 | |
| 
 | |
|   public void enable ()
 | |
|   {
 | |
|     setEnabled (true);
 | |
|   }
 | |
| 
 | |
|   public ColorModel getColorModel ()
 | |
|   {
 | |
|     return ColorModel.getRGBdefault ();
 | |
|   }
 | |
| 
 | |
|   public FontMetrics getFontMetrics (Font font)
 | |
|   {
 | |
|     return getToolkit().getFontMetrics(font);
 | |
|   }
 | |
| 
 | |
|   // getGraphics may be overridden by derived classes but it should
 | |
|   // never return null.
 | |
|   public Graphics getGraphics ()
 | |
|   {
 | |
|     return ComponentGraphics.getComponentGraphics(this);
 | |
|   }
 | |
| 
 | |
|   public Point getLocationOnScreen ()
 | |
|   {
 | |
|     int point[] = new int[2];
 | |
|     if (Thread.currentThread() == GtkMainThread.mainThread)
 | |
|         gtkWidgetGetLocationOnScreenUnlocked (point);
 | |
|     else
 | |
|         gtkWidgetGetLocationOnScreen (point);
 | |
|     return new Point (point[0], point[1]);
 | |
|   }
 | |
| 
 | |
|   public Dimension getMinimumSize ()
 | |
|   {
 | |
|     return minimumSize ();
 | |
|   }
 | |
| 
 | |
|   public Dimension getPreferredSize ()
 | |
|   {
 | |
|     return preferredSize ();
 | |
|   }
 | |
| 
 | |
|   public Toolkit getToolkit ()
 | |
|   {
 | |
|     return Toolkit.getDefaultToolkit();
 | |
|   }
 | |
| 
 | |
|   public void handleEvent (AWTEvent event)
 | |
|   {
 | |
|     int id = event.getID();
 | |
|     KeyEvent ke = null;
 | |
| 
 | |
|     switch (id)
 | |
|       {
 | |
|       case PaintEvent.PAINT:
 | |
|         paintComponent((PaintEvent) event);
 | |
|         break;
 | |
|       case PaintEvent.UPDATE:
 | |
|         updateComponent((PaintEvent) event);
 | |
|         break;
 | |
|       case KeyEvent.KEY_PRESSED:
 | |
|         ke = (KeyEvent) event;
 | |
|         gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
 | |
|                                    ke.getKeyCode (), ke.getKeyLocation ());
 | |
|         break;
 | |
|       case KeyEvent.KEY_RELEASED:
 | |
|         ke = (KeyEvent) event;
 | |
|         gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
 | |
|                                    ke.getKeyCode (), ke.getKeyLocation ());
 | |
|         break;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   // This method and its overrides are the only methods in the peers
 | |
|   // that should call awtComponent.paint.
 | |
|   protected void paintComponent (PaintEvent event)
 | |
|   {
 | |
|     // Do not call Component.paint if the component is not showing or
 | |
|     // if its bounds form a degenerate rectangle.
 | |
|     if (!awtComponent.isShowing()
 | |
|         || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
 | |
|       return;
 | |
| 
 | |
|     // Creating and disposing a GdkGraphics every time paint is called
 | |
|     // seems expensive.  However, the graphics state does not carry
 | |
|     // over between calls to paint, and resetting the graphics object
 | |
|     // may even be more costly than simply creating a new one.
 | |
| 
 | |
|     // Make sure that the paintArea includes the area from the event
 | |
|     // in the case when an application sends PaintEvents directly.
 | |
|     coalescePaintEvent(event);
 | |
|     Rectangle paintArea;
 | |
|     synchronized (this)
 | |
|       {
 | |
|         paintArea = currentPaintArea;
 | |
|         currentPaintArea = null;
 | |
|       }
 | |
| 
 | |
|     if (paintArea != null)
 | |
|       {
 | |
|         Graphics g = getGraphics();
 | |
|         try
 | |
|           {
 | |
|             g.setClip(paintArea);
 | |
|             awtComponent.paint(g);
 | |
|           }
 | |
|         finally
 | |
|           {
 | |
|             g.dispose();
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   // This method and its overrides are the only methods in the peers
 | |
|   // that should call awtComponent.update.
 | |
|   protected void updateComponent (PaintEvent event)
 | |
|   {
 | |
|     // Do not call Component.update if the component is not showing or
 | |
|     // if its bounds form a degenerate rectangle.
 | |
|     if (!awtComponent.isShowing()
 | |
|         || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
 | |
|       return;
 | |
| 
 | |
|     // Make sure that the paintArea includes the area from the event
 | |
|     // in the case when an application sends PaintEvents directly.
 | |
|     coalescePaintEvent(event);
 | |
|     Rectangle paintArea;
 | |
|     synchronized (this)
 | |
|       {
 | |
|         paintArea = currentPaintArea;
 | |
|         currentPaintArea = null;
 | |
|       }
 | |
| 
 | |
|     if (paintArea != null)
 | |
|     {
 | |
|       Graphics g = getGraphics();
 | |
|       try
 | |
|         {
 | |
|           g.setClip(paintArea);
 | |
|           awtComponent.update(g);
 | |
|         }
 | |
|       finally
 | |
|         {
 | |
|           g.dispose();
 | |
|         }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public boolean isFocusTraversable ()
 | |
|   {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   public Dimension minimumSize ()
 | |
|   {
 | |
|     int dim[] = new int[2];
 | |
| 
 | |
|     gtkWidgetGetPreferredDimensions (dim);
 | |
| 
 | |
|     return new Dimension (dim[0], dim[1]);
 | |
|   }
 | |
| 
 | |
|   public void paint (Graphics g)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   public Dimension preferredSize ()
 | |
|   {
 | |
|     int dim[] = new int[2];
 | |
| 
 | |
|     gtkWidgetGetPreferredDimensions (dim);
 | |
| 
 | |
|     return new Dimension (dim[0], dim[1]);
 | |
|   }
 | |
| 
 | |
|   public boolean prepareImage (Image image, int width, int height,
 | |
|                                ImageObserver observer)
 | |
|   {
 | |
|     return getToolkit().prepareImage(image, width, height, observer);
 | |
|   }
 | |
| 
 | |
|   public void print (Graphics g)
 | |
|   {
 | |
|     g.drawImage( ComponentGraphics.grab( this ), 0, 0, null );
 | |
|   }
 | |
| 
 | |
|   public void repaint (long tm, int x, int y, int width, int height)
 | |
|   {
 | |
|     if (width < 1 || height < 1)
 | |
|       return;
 | |
| 
 | |
|     if (tm <= 0)
 | |
|       q().postEvent(new PaintEvent(awtComponent, PaintEvent.UPDATE,
 | |
|                                    new Rectangle(x, y, width, height)));
 | |
|     else
 | |
|       RepaintTimerTask.schedule(tm, x, y, width, height, awtComponent);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Used for scheduling delayed paint updates on the event queue.
 | |
|    */
 | |
|   private static class RepaintTimerTask extends TimerTask
 | |
|   {
 | |
|     private static final Timer repaintTimer = new Timer(true);
 | |
| 
 | |
|     private int x, y, width, height;
 | |
|     private Component awtComponent;
 | |
| 
 | |
|     RepaintTimerTask(Component c, int x, int y, int width, int height)
 | |
|     {
 | |
|       this.x = x;
 | |
|       this.y = y;
 | |
|       this.width = width;
 | |
|       this.height = height;
 | |
|       this.awtComponent = c;
 | |
|     }
 | |
| 
 | |
|     public void run()
 | |
|     {
 | |
|       q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE,
 | |
|                                      new Rectangle (x, y, width, height)));
 | |
|     }
 | |
| 
 | |
|     static void schedule(long tm, int x, int y, int width, int height,
 | |
|                          Component c)
 | |
|     {
 | |
|       repaintTimer.schedule(new RepaintTimerTask(c, x, y, width, height), tm);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public void requestFocus ()
 | |
|   {
 | |
|     assert false: "Call new requestFocus() method instead";
 | |
|   }
 | |
| 
 | |
|   public void reshape (int x, int y, int width, int height)
 | |
|   {
 | |
|     setBounds (x, y, width, height);
 | |
|   }
 | |
| 
 | |
|   public void setBackground (Color c)
 | |
|   {
 | |
|     gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue());
 | |
|   }
 | |
| 
 | |
|   native void setNativeBounds (int x, int y, int width, int height);
 | |
| 
 | |
|   public void setBounds (int x, int y, int width, int height)
 | |
|   {
 | |
|     int new_x = x;
 | |
|     int new_y = y;
 | |
| 
 | |
|     Component parent = awtComponent.getParent ();
 | |
| 
 | |
|     // Heavyweight components that are children of one or more
 | |
|     // lightweight containers have to be handled specially.  Because
 | |
|     // calls to GLightweightPeer.setBounds do nothing, GTK has no
 | |
|     // knowledge of the lightweight containers' positions.  So we have
 | |
|     // to add the offsets manually when placing a heavyweight
 | |
|     // component within a lightweight container.  The lightweight
 | |
|     // container may itself be in a lightweight container and so on,
 | |
|     // so we need to continue adding offsets until we reach a
 | |
|     // container whose position GTK knows -- that is, the first
 | |
|     // non-lightweight.
 | |
|     Insets i;
 | |
|     while (parent.isLightweight())
 | |
|       {
 | |
|         i = ((Container) parent).getInsets();
 | |
| 
 | |
|         new_x += parent.getX() + i.left;
 | |
|         new_y += parent.getY() + i.top;
 | |
| 
 | |
|         parent = parent.getParent();
 | |
|       }
 | |
|     // We only need to convert from Java to GTK coordinates if we're
 | |
|     // placing a heavyweight component in a Window.
 | |
|     if (parent instanceof Window)
 | |
|       {
 | |
|         GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer ();
 | |
|         // important: we want the window peer's insets here, not the
 | |
|         // window's, since user sub-classes of Window can override
 | |
|         // getInset and we only want to correct for the frame borders,
 | |
|         // not for any user-defined inset values
 | |
|         Insets insets = peer.getInsets ();
 | |
| 
 | |
|         int menuBarHeight = 0;
 | |
|         if (peer instanceof GtkFramePeer)
 | |
|           menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight ();
 | |
| 
 | |
|         new_x -= insets.left;
 | |
|         new_y -= insets.top;
 | |
|         new_y += menuBarHeight;
 | |
|       }
 | |
| 
 | |
|     setNativeBounds (new_x, new_y, width, height);
 | |
| 
 | |
|     // If the height or width were (or are now) smaller than zero
 | |
|     // then we want to adjust the visibility.
 | |
|     setVisible(awtComponent.isVisible());
 | |
|   }
 | |
| 
 | |
|   void setCursor ()
 | |
|   {
 | |
|     setCursor (awtComponent.getCursor ());
 | |
|   }
 | |
| 
 | |
|   public void setCursor (Cursor cursor)
 | |
|   {
 | |
|     int x, y;
 | |
|     GtkImage image;
 | |
|     int type = cursor.getType();
 | |
|     if (cursor instanceof GtkCursor)
 | |
|       {
 | |
|         GtkCursor gtkCursor = (GtkCursor) cursor;
 | |
|         image = gtkCursor.getGtkImage();
 | |
|         Point hotspot = gtkCursor.getHotspot();
 | |
|         x = hotspot.x;
 | |
|         y = hotspot.y;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         image = null;
 | |
|         x = 0;
 | |
|         y = 0;
 | |
|       }
 | |
| 
 | |
|     if (Thread.currentThread() == GtkMainThread.mainThread)
 | |
|       gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
 | |
|     else
 | |
|       gtkWidgetSetCursor(cursor.getType(), image, x, y);
 | |
|   }
 | |
| 
 | |
|   public void setEnabled (boolean b)
 | |
|   {
 | |
|     gtkWidgetSetSensitive (b);
 | |
|   }
 | |
| 
 | |
|   public void setFont (Font f)
 | |
|   {
 | |
|     // FIXME: This should really affect the widget tree below me.
 | |
|     // Currently this is only handled if the call is made directly on
 | |
|     // a text widget, which implements setFont() itself.
 | |
|     gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
 | |
|   }
 | |
| 
 | |
|   public void setForeground (Color c)
 | |
|   {
 | |
|     gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue());
 | |
|   }
 | |
| 
 | |
|   public Color getForeground ()
 | |
|   {
 | |
|     int rgb[] = gtkWidgetGetForeground ();
 | |
|     return new Color (rgb[0], rgb[1], rgb[2]);
 | |
|   }
 | |
| 
 | |
|   public Color getBackground ()
 | |
|   {
 | |
|     int rgb[] = gtkWidgetGetBackground ();
 | |
|     return new Color (rgb[0], rgb[1], rgb[2]);
 | |
|   }
 | |
| 
 | |
|   public native void setVisibleNative (boolean b);
 | |
|   public native void setVisibleNativeUnlocked (boolean b);
 | |
| 
 | |
|   public void setVisible (boolean b)
 | |
|   {
 | |
|     // Only really set visible when component is bigger than zero pixels.
 | |
|     if (b && ! (awtComponent instanceof Window))
 | |
|       {
 | |
|         Rectangle bounds = awtComponent.getBounds();
 | |
|         b = (bounds.width > 0) && (bounds.height > 0);
 | |
|       }
 | |
| 
 | |
|     if (Thread.currentThread() == GtkMainThread.mainThread)
 | |
|       setVisibleNativeUnlocked (b);
 | |
|     else
 | |
|       setVisibleNative (b);
 | |
|   }
 | |
| 
 | |
|   public void hide ()
 | |
|   {
 | |
|     setVisible (false);
 | |
|   }
 | |
| 
 | |
|   public void show ()
 | |
|   {
 | |
|     setVisible (true);
 | |
|   }
 | |
| 
 | |
|   protected void postMouseEvent(int id, long when, int mods, int x, int y,
 | |
|                                 int clickCount, boolean popupTrigger)
 | |
|   {
 | |
|     // It is important to do the getLocationOnScreen() here, instead
 | |
|     // of using the old MouseEvent constructors, because
 | |
|     // Component.getLocationOnScreen() locks on the AWT lock, which can
 | |
|     // trigger a deadlock. You don't want this.
 | |
|     Point locOnScreen = getLocationOnScreen();
 | |
|     q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y,
 | |
|                                  locOnScreen.x + x, locOnScreen.y + y,
 | |
|                                  clickCount, popupTrigger,
 | |
|                                  MouseEvent.NOBUTTON));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Callback for component_scroll_cb.
 | |
|    */
 | |
|   protected void postMouseWheelEvent(int id, long when, int mods,
 | |
|                                      int x, int y, int clickCount,
 | |
|                                      boolean popupTrigger,
 | |
|                                      int type, int amount, int rotation)
 | |
|   {
 | |
|     q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods,
 | |
|                                       x, y, clickCount, popupTrigger,
 | |
|                                       type, amount, rotation));
 | |
|   }
 | |
| 
 | |
|   protected void postExposeEvent (int x, int y, int width, int height)
 | |
|   {
 | |
|     q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
 | |
|                                    new Rectangle (x, y, width, height)));
 | |
|   }
 | |
| 
 | |
|   protected void postKeyEvent (int id, long when, int mods,
 | |
|                                int keyCode, char keyChar, int keyLocation)
 | |
|   {
 | |
|     KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
 | |
|                                       keyCode, keyChar, keyLocation);
 | |
| 
 | |
|     EventQueue q = q();
 | |
| 
 | |
|     // Also post a KEY_TYPED event if keyEvent is a key press that
 | |
|     // doesn't represent an action or modifier key.
 | |
|     if (keyEvent.getID () == KeyEvent.KEY_PRESSED
 | |
|         && (!keyEvent.isActionKey ()
 | |
|             && keyCode != KeyEvent.VK_SHIFT
 | |
|             && keyCode != KeyEvent.VK_CONTROL
 | |
|             && keyCode != KeyEvent.VK_ALT))
 | |
|       {
 | |
|         synchronized(q)
 | |
|           {
 | |
|             q.postEvent(keyEvent);
 | |
|             keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when,
 | |
|                                     mods, KeyEvent.VK_UNDEFINED, keyChar,
 | |
|                                     keyLocation);
 | |
|             q.postEvent(keyEvent);
 | |
|           }
 | |
|       }
 | |
|     else
 | |
|       q.postEvent(keyEvent);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Referenced from native code.
 | |
|    *
 | |
|    * @param id
 | |
|    * @param temporary
 | |
|    */
 | |
|   protected void postFocusEvent (int id, boolean temporary)
 | |
|   {
 | |
|     q().postEvent (new FocusEvent (awtComponent, id, temporary));
 | |
|   }
 | |
| 
 | |
|   protected void postItemEvent (Object item, int stateChange)
 | |
|   {
 | |
|     q().postEvent (new ItemEvent ((ItemSelectable)awtComponent,
 | |
|                                   ItemEvent.ITEM_STATE_CHANGED,
 | |
|                                   item, stateChange));
 | |
|   }
 | |
| 
 | |
|   protected void postTextEvent ()
 | |
|   {
 | |
|     q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED));
 | |
|   }
 | |
| 
 | |
|   public GraphicsConfiguration getGraphicsConfiguration ()
 | |
|   {
 | |
|     // FIXME: The component might be showing on a non-default screen.
 | |
|     GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
 | |
|     GraphicsDevice dev = env.getDefaultScreenDevice();
 | |
|     return dev.getDefaultConfiguration();
 | |
|   }
 | |
| 
 | |
|   public void setEventMask (long mask)
 | |
|   {
 | |
|     // FIXME: just a stub for now.
 | |
|   }
 | |
| 
 | |
|   public boolean isFocusable ()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   public boolean requestFocus (Component request, boolean temporary,
 | |
|                                boolean allowWindowFocus, long time)
 | |
|   {
 | |
|     assert request == awtComponent || isLightweightDescendant(request);
 | |
|     boolean retval = false;
 | |
|     if (gtkWidgetHasFocus())
 | |
|       {
 | |
|         KeyboardFocusManager kfm =
 | |
|           KeyboardFocusManager.getCurrentKeyboardFocusManager();
 | |
|         Component currentFocus = kfm.getFocusOwner();
 | |
|         if (currentFocus == request)
 | |
|           // Nothing to do in this trivial case.
 | |
|           retval = true;
 | |
|         else
 | |
|           {
 | |
|             // Requested component is a lightweight descendant of this one
 | |
|             // or the actual heavyweight.
 | |
|             // Since this (native) component is already focused, we simply
 | |
|             // change the actual focus and be done.
 | |
|             postFocusEvent(FocusEvent.FOCUS_GAINED, temporary);
 | |
|             retval = true;
 | |
|           }
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         if (gtkWidgetCanFocus())
 | |
|           {
 | |
|             if (allowWindowFocus)
 | |
|               {
 | |
|                 Window window = getWindowFor(request);
 | |
|                 GtkWindowPeer wPeer = (GtkWindowPeer) window.getPeer();
 | |
|                 if (! wPeer.gtkWindowHasFocus())
 | |
|                   wPeer.requestWindowFocus();
 | |
|               }
 | |
|             // Store requested focus component so that the corresponding
 | |
|             // event is dispatched correctly.
 | |
|             gtkWidgetRequestFocus();
 | |
|             retval = true;
 | |
|           }
 | |
|       }
 | |
|     return retval;
 | |
|   }
 | |
| 
 | |
|   private Window getWindowFor(Component c)
 | |
|   {
 | |
|     Component comp = c;
 | |
|     while (! (comp instanceof Window))
 | |
|       comp = comp.getParent();
 | |
|     return (Window) comp;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if the component is a direct (== no intermediate
 | |
|    * heavyweights) lightweight descendant of this peer's component.
 | |
|    *
 | |
|    * @param c the component to check
 | |
|    *
 | |
|    * @return <code>true</code> if the component is a direct (== no intermediate
 | |
|    *         heavyweights) lightweight descendant of this peer's component
 | |
|    */
 | |
|   protected boolean isLightweightDescendant(Component c)
 | |
|   {
 | |
|     Component comp = c;
 | |
|     while (comp.getPeer() instanceof LightweightPeer)
 | |
|       comp = comp.getParent();
 | |
|     return comp == awtComponent;
 | |
|   }
 | |
| 
 | |
|   public boolean isObscured ()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   public boolean canDetermineObscurity ()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   public void coalescePaintEvent (PaintEvent e)
 | |
|   {
 | |
|     synchronized (this)
 | |
|     {
 | |
|       Rectangle newRect = e.getUpdateRect();
 | |
|       if (currentPaintArea == null)
 | |
|         currentPaintArea = newRect;
 | |
|       else
 | |
|         Rectangle.union(currentPaintArea, newRect, currentPaintArea);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public void updateCursorImmediately ()
 | |
|   {
 | |
|     if (awtComponent.getCursor() != null)
 | |
|       setCursor(awtComponent.getCursor());
 | |
|   }
 | |
| 
 | |
|   public boolean handlesWheelScrolling ()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Convenience method to create a new volatile image on the screen
 | |
|   // on which this component is displayed.
 | |
|   public VolatileImage createVolatileImage (int width, int height)
 | |
|   {
 | |
|     return new GtkVolatileImage (this, width, height, null);
 | |
|   }
 | |
| 
 | |
|   // Creates buffers used in a buffering strategy.
 | |
|   public void createBuffers (int numBuffers, BufferCapabilities caps)
 | |
|     throws AWTException
 | |
|   {
 | |
|     // numBuffers == 2 implies double-buffering, meaning one back
 | |
|     // buffer and one front buffer.
 | |
|     if (numBuffers == 2)
 | |
|       backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(),
 | |
|                                         awtComponent.getHeight(),
 | |
|                                         caps.getBackBufferCapabilities());
 | |
|     else
 | |
|       throw new AWTException("GtkComponentPeer.createBuffers:"
 | |
|                              + " multi-buffering not supported");
 | |
|     this.caps = caps;
 | |
|   }
 | |
| 
 | |
|   // Return the back buffer.
 | |
|   public Image getBackBuffer ()
 | |
|   {
 | |
|     return backBuffer;
 | |
|   }
 | |
| 
 | |
|   // FIXME: flip should be implemented as a fast native operation
 | |
|   public void flip (BufferCapabilities.FlipContents contents)
 | |
|   {
 | |
|     getGraphics().drawImage(backBuffer,
 | |
|                             awtComponent.getWidth(),
 | |
|                             awtComponent.getHeight(),
 | |
|                             null);
 | |
| 
 | |
|     // create new back buffer and clear it to the background color.
 | |
|     if (contents == BufferCapabilities.FlipContents.BACKGROUND)
 | |
|         {
 | |
|           backBuffer = createVolatileImage(awtComponent.getWidth(),
 | |
|                                            awtComponent.getHeight());
 | |
|           backBuffer.getGraphics().clearRect(0, 0,
 | |
|                                              awtComponent.getWidth(),
 | |
|                                              awtComponent.getHeight());
 | |
|         }
 | |
|     // FIXME: support BufferCapabilities.FlipContents.PRIOR
 | |
|   }
 | |
| 
 | |
|   // Release the resources allocated to back buffers.
 | |
|   public void destroyBuffers ()
 | |
|   {
 | |
|     backBuffer.flush();
 | |
|   }
 | |
| 
 | |
|   public String toString ()
 | |
|   {
 | |
|     return "peer of " + awtComponent.toString();
 | |
|   }
 | |
|   public Rectangle getBounds()
 | |
|   {
 | |
|       // FIXME: implement
 | |
|     return null;
 | |
|   }
 | |
|   public void reparent(ContainerPeer parent)
 | |
|   {
 | |
|     // FIXME: implement
 | |
| 
 | |
|   }
 | |
|   public void setBounds(int x, int y, int width, int height, int z)
 | |
|   {
 | |
|     // FIXME: implement
 | |
|       setBounds (x, y, width, height);
 | |
| 
 | |
|   }
 | |
|   public boolean isReparentSupported()
 | |
|   {
 | |
|     // FIXME: implement
 | |
| 
 | |
|     return false;
 | |
|   }
 | |
|   public void layout()
 | |
|   {
 | |
|     // FIXME: implement
 | |
| 
 | |
|   }
 | |
| 
 | |
|   public boolean requestFocus(Component lightweightChild, boolean temporary,
 | |
|                               boolean focusedWindowChangeAllowed,
 | |
|                               long time, sun.awt.CausedFocusEvent.Cause cause)
 | |
|   {
 | |
|     // TODO: Implement this properly and remove the other requestFocus()
 | |
|     // methods.
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
| }
 |