Source for gnu.java.awt.peer.gtk.GtkComponentPeer

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