OSDN Git Service

libjava/classpath/ChangeLog.gcj:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / awt / peer / gtk / GtkComponentPeer.java
1 /* GtkComponentPeer.java -- Implements ComponentPeer with GTK
2    Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39
40 package gnu.java.awt.peer.gtk;
41
42 import java.awt.AWTEvent;
43 import java.awt.AWTException;
44 import java.awt.BufferCapabilities;
45 import java.awt.Color;
46 import java.awt.Component;
47 import java.awt.Container;
48 import java.awt.Cursor;
49 import java.awt.Dimension;
50 import java.awt.EventQueue;
51 import java.awt.Font;
52 import java.awt.FontMetrics;
53 import java.awt.Graphics;
54 import java.awt.GraphicsConfiguration;
55 import java.awt.GraphicsDevice;
56 import java.awt.GraphicsEnvironment;
57 import java.awt.Image;
58 import java.awt.Insets;
59 import java.awt.ItemSelectable;
60 import java.awt.KeyboardFocusManager;
61 import java.awt.Point;
62 import java.awt.Rectangle;
63 import java.awt.Toolkit;
64 import java.awt.Window;
65 import java.awt.event.FocusEvent;
66 import java.awt.event.ItemEvent;
67 import java.awt.event.KeyEvent;
68 import java.awt.event.MouseEvent;
69 import java.awt.event.MouseWheelEvent;
70 import java.awt.event.PaintEvent;
71 import java.awt.event.TextEvent;
72 import java.awt.image.ColorModel;
73 import java.awt.image.ImageObserver;
74 import java.awt.image.ImageProducer;
75 import java.awt.image.VolatileImage;
76 import java.awt.peer.ComponentPeer;
77 import java.awt.peer.ContainerPeer;
78 import java.awt.peer.LightweightPeer;
79 import java.awt.peer.WindowPeer;
80 import java.util.Timer;
81 import java.util.TimerTask;
82
83 public class GtkComponentPeer extends GtkGenericPeer
84   implements ComponentPeer
85 {
86   VolatileImage backBuffer;
87   BufferCapabilities caps;
88
89   Component awtComponent;
90
91   Insets insets;
92
93   /**
94    * The current repaint area. Use should be guarded by synchronizing on this.
95    */
96   private Rectangle currentPaintArea;
97
98   /* this isEnabled differs from Component.isEnabled, in that it
99      knows if a parent is disabled.  In that case Component.isEnabled 
100      may return true, but our isEnabled will always return false */
101   native boolean isEnabled ();
102   static native boolean modalHasGrab();
103
104   native int[] gtkWidgetGetForeground ();
105   native int[] gtkWidgetGetBackground ();
106   native void gtkWidgetGetDimensions (int[] dim);
107   native void gtkWidgetGetPreferredDimensions (int[] dim);
108   native void gtkWindowGetLocationOnScreen (int[] point);
109   native void gtkWidgetGetLocationOnScreen (int[] point);
110   native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y);
111   native void gtkWidgetSetCursorUnlocked (int type, GtkImage image,
112                                           int x, int y);
113   native void gtkWidgetSetBackground (int red, int green, int blue);
114   native void gtkWidgetSetForeground (int red, int green, int blue);
115   native void gtkWidgetSetSensitive (boolean sensitive);
116   native void gtkWidgetSetParent (ComponentPeer parent);
117   native void gtkWidgetRequestFocus ();
118   native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
119                                          int keyCode, int keyLocation);
120   native boolean gtkWidgetHasFocus();
121   native boolean gtkWidgetCanFocus();
122
123   native void realize();
124   native void setNativeEventMask ();
125
126   void create ()
127   {
128     throw new RuntimeException ();
129   }
130
131   native void connectSignals ();
132
133   protected GtkComponentPeer (Component awtComponent)
134   {
135     super (awtComponent);
136     this.awtComponent = awtComponent;
137     insets = new Insets (0, 0, 0, 0);
138
139     create ();
140
141     connectSignals ();
142
143     if (awtComponent.getForeground () != null)
144       setForeground (awtComponent.getForeground ());
145     if (awtComponent.getBackground () != null)
146       setBackground (awtComponent.getBackground ());
147     if (awtComponent.getFont() != null)
148       setFont(awtComponent.getFont());
149
150     Component parent = awtComponent.getParent ();
151
152     setParentAndBounds ();
153
154     setNativeEventMask ();
155
156     // This peer is guaranteed to have an X window upon construction.
157     // That is, native methods such as those in GdkGraphics can rely
158     // on this component's widget->window field being non-null.
159     realize ();
160
161     if (awtComponent.isCursorSet())
162       setCursor ();
163   }
164
165   void setParentAndBounds ()
166   {
167     setParent ();
168
169     setComponentBounds ();
170
171     setVisibleAndEnabled ();
172   }
173
174   void setParent ()
175   {
176     ComponentPeer p;
177     Component component = awtComponent;
178     do
179       {
180         component = component.getParent ();
181         p = component.getPeer ();
182       }
183     while (p instanceof java.awt.peer.LightweightPeer);
184
185     if (p != null)
186       gtkWidgetSetParent (p);
187   }
188
189   /*
190    * Set the bounds of this peer's AWT Component based on dimensions
191    * returned by the native windowing system.  Most Components impose
192    * their dimensions on the peers which is what the default
193    * implementation does.  However some peers, like GtkFileDialogPeer,
194    * need to pass their size back to the AWT Component.
195    */
196   void setComponentBounds ()
197   {
198     Rectangle bounds = awtComponent.getBounds ();
199     setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
200   }
201
202   void setVisibleAndEnabled ()
203   {
204     setVisible (awtComponent.isVisible ());
205     setEnabled (awtComponent.isEnabled ());
206   }
207
208   public int checkImage (Image image, int width, int height, 
209                          ImageObserver observer) 
210   {
211     return getToolkit().checkImage(image, width, height, observer);
212   }
213
214   public Image createImage (ImageProducer producer) 
215   {
216     return new GtkImage (producer);
217   }
218
219   public Image createImage (int width, int height)
220   {
221     return CairoSurface.getBufferedImage(width, height);
222   }
223
224   public void disable () 
225   {
226     setEnabled (false);
227   }
228
229   public void enable () 
230   {
231     setEnabled (true);
232   }
233
234   public ColorModel getColorModel () 
235   {
236     return ColorModel.getRGBdefault ();
237   }
238
239   public FontMetrics getFontMetrics (Font font)
240   {
241     return getToolkit().getFontMetrics(font);
242   }
243
244   // getGraphics may be overridden by derived classes but it should
245   // never return null.
246   public Graphics getGraphics ()
247   {
248     return ComponentGraphics.getComponentGraphics(this);
249   }
250
251   public Point getLocationOnScreen () 
252   { 
253     int point[] = new int[2];
254     if( this instanceof WindowPeer )
255       gtkWindowGetLocationOnScreen (point);
256     else
257       gtkWidgetGetLocationOnScreen (point);
258     return new Point (point[0], point[1]);
259   }
260
261   public Dimension getMinimumSize () 
262   {
263     return minimumSize ();
264   }
265
266   public Dimension getPreferredSize ()
267   {
268     return preferredSize ();
269   }
270
271   public Toolkit getToolkit ()
272   {
273     return Toolkit.getDefaultToolkit();
274   }
275   
276   public void handleEvent (AWTEvent event)
277   {
278     int id = event.getID();
279     KeyEvent ke = null;
280
281     switch (id)
282       {
283       case PaintEvent.PAINT:
284         paintComponent((PaintEvent) event);
285         break;
286       case PaintEvent.UPDATE:
287         updateComponent((PaintEvent) event);
288         break;
289       case KeyEvent.KEY_PRESSED:
290         ke = (KeyEvent) event;
291         gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
292                                    ke.getKeyCode (), ke.getKeyLocation ());
293         break;
294       case KeyEvent.KEY_RELEASED:
295         ke = (KeyEvent) event;
296         gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
297                                    ke.getKeyCode (), ke.getKeyLocation ());
298         break;
299       }
300   }
301
302   // This method and its overrides are the only methods in the peers
303   // that should call awtComponent.paint.
304   protected void paintComponent (PaintEvent event)
305   {
306     // Do not call Component.paint if the component is not showing or
307     // if its bounds form a degenerate rectangle.
308     if (!awtComponent.isShowing()
309         || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
310       return;
311
312     // Creating and disposing a GdkGraphics every time paint is called
313     // seems expensive.  However, the graphics state does not carry
314     // over between calls to paint, and resetting the graphics object
315     // may even be more costly than simply creating a new one.
316
317     // Make sure that the paintArea includes the area from the event
318     // in the case when an application sends PaintEvents directly.
319     coalescePaintEvent(event);
320     Rectangle paintArea;
321     synchronized (this)
322       {
323         paintArea = currentPaintArea;
324         currentPaintArea = null;
325       }
326
327     if (paintArea != null)
328       {
329         Graphics g = getGraphics();
330         try
331           {
332             g.setClip(paintArea);
333             awtComponent.paint(g);
334           }
335         finally
336           {
337             g.dispose();
338           }
339       }
340   }
341
342   // This method and its overrides are the only methods in the peers
343   // that should call awtComponent.update.
344   protected void updateComponent (PaintEvent event)
345   {
346     // Do not call Component.update if the component is not showing or
347     // if its bounds form a degenerate rectangle.
348     if (!awtComponent.isShowing()
349         || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
350       return;
351
352     // Make sure that the paintArea includes the area from the event
353     // in the case when an application sends PaintEvents directly.
354     coalescePaintEvent(event);
355     Rectangle paintArea;
356     synchronized (this)
357       {
358         paintArea = currentPaintArea;
359         currentPaintArea = null;
360       }
361
362     if (paintArea != null)
363     {
364       Graphics g = getGraphics();
365       try
366         {
367           g.setClip(paintArea);
368           awtComponent.update(g);
369         }
370       finally
371         {
372           g.dispose();
373         }
374     }
375   }
376
377   public boolean isFocusTraversable () 
378   {
379     return true;
380   }
381
382   public Dimension minimumSize () 
383   {
384     int dim[] = new int[2];
385
386     gtkWidgetGetPreferredDimensions (dim);
387
388     return new Dimension (dim[0], dim[1]);
389   }
390
391   public void paint (Graphics g)
392   {
393   }
394
395   public Dimension preferredSize ()
396   {
397     int dim[] = new int[2];
398
399     gtkWidgetGetPreferredDimensions (dim);
400
401     return new Dimension (dim[0], dim[1]);
402   }
403
404   public boolean prepareImage (Image image, int width, int height,
405                                ImageObserver observer) 
406   {
407     return getToolkit().prepareImage(image, width, height, observer);
408   }
409
410   public void print (Graphics g) 
411   {
412     g.drawImage( ComponentGraphics.grab( this ), 0, 0, null );
413   }
414
415   public void repaint (long tm, int x, int y, int width, int height)
416   {
417     if (width < 1 || height < 1)
418       return;
419
420     if (tm <= 0)
421       q().postEvent(new PaintEvent(awtComponent, PaintEvent.UPDATE,
422                                    new Rectangle(x, y, width, height)));
423     else
424       RepaintTimerTask.schedule(tm, x, y, width, height, awtComponent);
425   }
426
427   /**
428    * Used for scheduling delayed paint updates on the event queue.
429    */
430   private static class RepaintTimerTask extends TimerTask
431   {
432     private static final Timer repaintTimer = new Timer(true);
433
434     private int x, y, width, height;
435     private Component awtComponent;
436
437     RepaintTimerTask(Component c, int x, int y, int width, int height)
438     {
439       this.x = x;
440       this.y = y;
441       this.width = width;
442       this.height = height;
443       this.awtComponent = c;
444     }
445
446     public void run()
447     {
448       q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE,
449                                      new Rectangle (x, y, width, height)));
450     }
451
452     static void schedule(long tm, int x, int y, int width, int height,
453                          Component c)
454     {
455       repaintTimer.schedule(new RepaintTimerTask(c, x, y, width, height), tm);
456     }
457   }
458
459   public void requestFocus ()
460   {
461     assert false: "Call new requestFocus() method instead";
462   }
463
464   public void reshape (int x, int y, int width, int height) 
465   {
466     setBounds (x, y, width, height);
467   }
468
469   public void setBackground (Color c) 
470   {
471     gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue());
472   }
473
474   native void setNativeBounds (int x, int y, int width, int height);
475
476   public void setBounds (int x, int y, int width, int height)
477   {
478     int new_x = x;
479     int new_y = y;
480
481     Component parent = awtComponent.getParent ();
482     
483     // Heavyweight components that are children of one or more
484     // lightweight containers have to be handled specially.  Because
485     // calls to GLightweightPeer.setBounds do nothing, GTK has no
486     // knowledge of the lightweight containers' positions.  So we have
487     // to add the offsets manually when placing a heavyweight
488     // component within a lightweight container.  The lightweight
489     // container may itself be in a lightweight container and so on,
490     // so we need to continue adding offsets until we reach a
491     // container whose position GTK knows -- that is, the first
492     // non-lightweight.
493     Insets i;    
494     while (parent.isLightweight())
495       {
496         i = ((Container) parent).getInsets();
497         
498         new_x += parent.getX() + i.left;
499         new_y += parent.getY() + i.top;
500         
501         parent = parent.getParent();
502       }
503     // We only need to convert from Java to GTK coordinates if we're
504     // placing a heavyweight component in a Window.
505     if (parent instanceof Window)
506       {
507         GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer ();
508         // important: we want the window peer's insets here, not the
509         // window's, since user sub-classes of Window can override
510         // getInset and we only want to correct for the frame borders,
511         // not for any user-defined inset values
512         Insets insets = peer.getInsets ();
513
514         int menuBarHeight = 0;
515         if (peer instanceof GtkFramePeer)
516           menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight ();
517         
518         new_x -= insets.left;
519         new_y -= insets.top;
520         new_y += menuBarHeight;
521       }
522
523     setNativeBounds (new_x, new_y, width, height);
524
525     // If the height or width were (or are now) smaller than zero
526     // then we want to adjust the visibility.
527     setVisible(awtComponent.isVisible());
528   }
529
530   void setCursor ()
531   {
532     setCursor (awtComponent.getCursor ());
533   }
534
535   public void setCursor (Cursor cursor) 
536   {
537     int x, y;
538     GtkImage image;
539     int type = cursor.getType();
540     if (cursor instanceof GtkCursor)
541       {
542         GtkCursor gtkCursor = (GtkCursor) cursor;
543         image = gtkCursor.getGtkImage();
544         Point hotspot = gtkCursor.getHotspot();
545         x = hotspot.x;
546         y = hotspot.y;
547       }
548     else
549       {
550         image = null;
551         x = 0;
552         y = 0;
553       }
554
555     if (Thread.currentThread() == GtkMainThread.mainThread)
556       gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
557     else
558       gtkWidgetSetCursor(cursor.getType(), image, x, y);
559   }
560
561   public void setEnabled (boolean b)
562   {
563     gtkWidgetSetSensitive (b);
564   }
565
566   public void setFont (Font f)
567   {
568     // FIXME: This should really affect the widget tree below me.
569     // Currently this is only handled if the call is made directly on
570     // a text widget, which implements setFont() itself.
571     gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
572   }
573
574   public void setForeground (Color c) 
575   {
576     gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue());
577   }
578
579   public Color getForeground ()
580   {
581     int rgb[] = gtkWidgetGetForeground ();
582     return new Color (rgb[0], rgb[1], rgb[2]);
583   }
584
585   public Color getBackground ()
586   {
587     int rgb[] = gtkWidgetGetBackground ();
588     return new Color (rgb[0], rgb[1], rgb[2]);
589   }
590
591   public native void setVisibleNative (boolean b);
592   public native void setVisibleNativeUnlocked (boolean b);
593
594   public void setVisible (boolean b)
595   {
596     // Only really set visible when component is bigger than zero pixels.
597     if (b && ! (awtComponent instanceof Window))
598       {
599         Rectangle bounds = awtComponent.getBounds();
600         b = (bounds.width > 0) && (bounds.height > 0);
601       }
602
603     if (Thread.currentThread() == GtkMainThread.mainThread)
604       setVisibleNativeUnlocked (b);
605     else
606       setVisibleNative (b);
607   }
608
609   public void hide ()
610   {
611     setVisible (false);
612   }
613
614   public void show ()
615   {
616     setVisible (true);
617   }
618
619   protected void postMouseEvent(int id, long when, int mods, int x, int y, 
620                                 int clickCount, boolean popupTrigger) 
621   {
622     q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y, 
623                                  clickCount, popupTrigger));
624   }
625
626   /**
627    * Callback for component_scroll_cb.
628    */
629   protected void postMouseWheelEvent(int id, long when, int mods,
630                                      int x, int y, int clickCount,
631                                      boolean popupTrigger,
632                                      int type, int amount, int rotation) 
633   {
634     q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods,
635                                       x, y, clickCount, popupTrigger,
636                                       type, amount, rotation));
637   }
638
639   protected void postExposeEvent (int x, int y, int width, int height)
640   {
641     q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
642                                    new Rectangle (x, y, width, height)));
643   }
644
645   protected void postKeyEvent (int id, long when, int mods,
646                                int keyCode, char keyChar, int keyLocation)
647   {
648     KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
649                                       keyCode, keyChar, keyLocation);
650
651     EventQueue q = q();
652
653     // Also post a KEY_TYPED event if keyEvent is a key press that
654     // doesn't represent an action or modifier key.
655     if (keyEvent.getID () == KeyEvent.KEY_PRESSED
656         && (!keyEvent.isActionKey ()
657             && keyCode != KeyEvent.VK_SHIFT
658             && keyCode != KeyEvent.VK_CONTROL
659             && keyCode != KeyEvent.VK_ALT))
660       {
661         synchronized(q)
662           {
663             q.postEvent(keyEvent);
664             keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when,
665                                     mods, KeyEvent.VK_UNDEFINED, keyChar,
666                                     keyLocation);
667             q.postEvent(keyEvent);
668           }
669       }
670     else
671       q.postEvent(keyEvent);
672   }
673
674   /**
675    * Referenced from native code.
676    *
677    * @param id
678    * @param temporary
679    */
680   protected void postFocusEvent (int id, boolean temporary)
681   {
682     q().postEvent (new FocusEvent (awtComponent, id, temporary));
683   }
684
685   protected void postItemEvent (Object item, int stateChange)
686   {
687     q().postEvent (new ItemEvent ((ItemSelectable)awtComponent, 
688                                   ItemEvent.ITEM_STATE_CHANGED,
689                                   item, stateChange));
690   }
691
692   protected void postTextEvent ()
693   {
694     q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED));
695   }
696
697   public GraphicsConfiguration getGraphicsConfiguration ()
698   {
699     // FIXME: The component might be showing on a non-default screen.
700     GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
701     GraphicsDevice dev = env.getDefaultScreenDevice();
702     return dev.getDefaultConfiguration();
703   }
704
705   public void setEventMask (long mask)
706   {
707     // FIXME: just a stub for now.
708   }
709
710   public boolean isFocusable ()
711   {
712     return false;
713   }
714
715   public boolean requestFocus (Component request, boolean temporary, 
716                                boolean allowWindowFocus, long time)
717   {
718     assert request == awtComponent || isLightweightDescendant(request);
719     boolean retval = false;
720     if (gtkWidgetHasFocus())
721       {
722         KeyboardFocusManager kfm =
723           KeyboardFocusManager.getCurrentKeyboardFocusManager();
724         Component currentFocus = kfm.getFocusOwner();
725         if (currentFocus == request)
726           // Nothing to do in this trivial case.
727           retval = true;
728         else
729           {
730             // Requested component is a lightweight descendant of this one
731             // or the actual heavyweight.
732             // Since this (native) component is already focused, we simply
733             // change the actual focus and be done.
734             postFocusEvent(FocusEvent.FOCUS_GAINED, temporary);
735             retval = true;
736           }
737       }
738     else
739       {
740         if (gtkWidgetCanFocus())
741           {
742             if (allowWindowFocus)
743               {
744                 Window window = getWindowFor(request);
745                 GtkWindowPeer wPeer = (GtkWindowPeer) window.getPeer();
746                 if (! wPeer.gtkWindowHasFocus())
747                   wPeer.requestWindowFocus();
748               }
749             // Store requested focus component so that the corresponding
750             // event is dispatched correctly.
751             gtkWidgetRequestFocus();
752             retval = true;
753           }
754       }
755     return retval;
756   }
757
758   private Window getWindowFor(Component c)
759   {
760     Component comp = c;
761     while (! (comp instanceof Window))
762       comp = comp.getParent();
763     return (Window) comp;
764   }
765
766   /**
767    * Returns <code>true</code> if the component is a direct (== no intermediate
768    * heavyweights) lightweight descendant of this peer's component.
769    *
770    * @param c the component to check
771    *
772    * @return <code>true</code> if the component is a direct (== no intermediate
773    *         heavyweights) lightweight descendant of this peer's component
774    */
775   protected boolean isLightweightDescendant(Component c)
776   {
777     Component comp = c;
778     while (comp.getPeer() instanceof LightweightPeer)
779       comp = comp.getParent();
780     return comp == awtComponent;
781   }
782
783   public boolean isObscured ()
784   {
785     return false;
786   }
787
788   public boolean canDetermineObscurity ()
789   {
790     return false;
791   }
792
793   public void coalescePaintEvent (PaintEvent e)
794   {
795     synchronized (this)
796     {
797       Rectangle newRect = e.getUpdateRect();
798       if (currentPaintArea == null)
799         currentPaintArea = newRect;
800       else
801         Rectangle.union(currentPaintArea, newRect, currentPaintArea);
802     }
803   }
804
805   public void updateCursorImmediately ()
806   {
807     if (awtComponent.getCursor() != null)
808       setCursor(awtComponent.getCursor());
809   }
810
811   public boolean handlesWheelScrolling ()
812   {
813     return false;
814   }
815
816   // Convenience method to create a new volatile image on the screen
817   // on which this component is displayed.
818   public VolatileImage createVolatileImage (int width, int height)
819   {
820     return new GtkVolatileImage (this, width, height, null);
821   }
822
823   // Creates buffers used in a buffering strategy.
824   public void createBuffers (int numBuffers, BufferCapabilities caps)
825     throws AWTException
826   {
827     // numBuffers == 2 implies double-buffering, meaning one back
828     // buffer and one front buffer.
829     if (numBuffers == 2)
830       backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(),
831                                         awtComponent.getHeight(),
832                                         caps.getBackBufferCapabilities());
833     else
834       throw new AWTException("GtkComponentPeer.createBuffers:"
835                              + " multi-buffering not supported");
836     this.caps = caps;
837   }
838
839   // Return the back buffer.
840   public Image getBackBuffer ()
841   {
842     return backBuffer;
843   }
844
845   // FIXME: flip should be implemented as a fast native operation
846   public void flip (BufferCapabilities.FlipContents contents)
847   {
848     getGraphics().drawImage(backBuffer,
849                             awtComponent.getWidth(),
850                             awtComponent.getHeight(),
851                             null);
852
853     // create new back buffer and clear it to the background color.
854     if (contents == BufferCapabilities.FlipContents.BACKGROUND)
855         {
856           backBuffer = createVolatileImage(awtComponent.getWidth(),
857                                            awtComponent.getHeight());
858           backBuffer.getGraphics().clearRect(0, 0,
859                                              awtComponent.getWidth(),
860                                              awtComponent.getHeight());
861         }
862     // FIXME: support BufferCapabilities.FlipContents.PRIOR
863   }
864
865   // Release the resources allocated to back buffers.
866   public void destroyBuffers ()
867   {
868     backBuffer.flush();
869   }
870   
871   public String toString ()
872   {
873     return "peer of " + awtComponent.toString();
874   }
875   public Rectangle getBounds()
876   {
877       // FIXME: implement
878     return null;
879   }
880   public void reparent(ContainerPeer parent)
881   {
882     // FIXME: implement
883   
884   }
885   public void setBounds(int x, int y, int width, int height, int z)
886   {
887     // FIXME: implement
888       setBounds (x, y, width, height);
889    
890   }
891   public boolean isReparentSupported()
892   {
893     // FIXME: implement
894
895     return false;
896   }
897   public void layout()
898   {
899     // FIXME: implement
900  
901   }
902 }