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.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:     // It is important to do the getLocationOnScreen() here, instead
 623:     // of using the old MouseEvent constructors, because
 624:     // Component.getLocationOnScreen() locks on the AWT lock, which can
 625:     // trigger a deadlock. You don't want this.
 626:     Point locOnScreen = getLocationOnScreen();
 627:     q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y,
 628:                                  locOnScreen.x + x, locOnScreen.y + y,
 629:                                  clickCount, popupTrigger,
 630:                                  MouseEvent.NOBUTTON));
 631:   }
 632: 
 633:   /**
 634:    * Callback for component_scroll_cb.
 635:    */
 636:   protected void postMouseWheelEvent(int id, long when, int mods,
 637:                                      int x, int y, int clickCount,
 638:                                      boolean popupTrigger,
 639:                                      int type, int amount, int rotation) 
 640:   {
 641:     q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods,
 642:                                       x, y, clickCount, popupTrigger,
 643:                                       type, amount, rotation));
 644:   }
 645: 
 646:   protected void postExposeEvent (int x, int y, int width, int height)
 647:   {
 648:     q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
 649:                                    new Rectangle (x, y, width, height)));
 650:   }
 651: 
 652:   protected void postKeyEvent (int id, long when, int mods,
 653:                                int keyCode, char keyChar, int keyLocation)
 654:   {
 655:     KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
 656:                                       keyCode, keyChar, keyLocation);
 657: 
 658:     EventQueue q = q();
 659: 
 660:     // Also post a KEY_TYPED event if keyEvent is a key press that
 661:     // doesn't represent an action or modifier key.
 662:     if (keyEvent.getID () == KeyEvent.KEY_PRESSED
 663:         && (!keyEvent.isActionKey ()
 664:             && keyCode != KeyEvent.VK_SHIFT
 665:             && keyCode != KeyEvent.VK_CONTROL
 666:             && keyCode != KeyEvent.VK_ALT))
 667:       {
 668:         synchronized(q)
 669:           {
 670:             q.postEvent(keyEvent);
 671:             keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when,
 672:                                     mods, KeyEvent.VK_UNDEFINED, keyChar,
 673:                                     keyLocation);
 674:             q.postEvent(keyEvent);
 675:           }
 676:       }
 677:     else
 678:       q.postEvent(keyEvent);
 679:   }
 680: 
 681:   /**
 682:    * Referenced from native code.
 683:    *
 684:    * @param id
 685:    * @param temporary
 686:    */
 687:   protected void postFocusEvent (int id, boolean temporary)
 688:   {
 689:     q().postEvent (new FocusEvent (awtComponent, id, temporary));
 690:   }
 691: 
 692:   protected void postItemEvent (Object item, int stateChange)
 693:   {
 694:     q().postEvent (new ItemEvent ((ItemSelectable)awtComponent, 
 695:                                   ItemEvent.ITEM_STATE_CHANGED,
 696:                                   item, stateChange));
 697:   }
 698: 
 699:   protected void postTextEvent ()
 700:   {
 701:     q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED));
 702:   }
 703: 
 704:   public GraphicsConfiguration getGraphicsConfiguration ()
 705:   {
 706:     // FIXME: The component might be showing on a non-default screen.
 707:     GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
 708:     GraphicsDevice dev = env.getDefaultScreenDevice();
 709:     return dev.getDefaultConfiguration();
 710:   }
 711: 
 712:   public void setEventMask (long mask)
 713:   {
 714:     // FIXME: just a stub for now.
 715:   }
 716: 
 717:   public boolean isFocusable ()
 718:   {
 719:     return false;
 720:   }
 721: 
 722:   public boolean requestFocus (Component request, boolean temporary, 
 723:                                boolean allowWindowFocus, long time)
 724:   {
 725:     assert request == awtComponent || isLightweightDescendant(request);
 726:     boolean retval = false;
 727:     if (gtkWidgetHasFocus())
 728:       {
 729:         KeyboardFocusManager kfm =
 730:           KeyboardFocusManager.getCurrentKeyboardFocusManager();
 731:         Component currentFocus = kfm.getFocusOwner();
 732:         if (currentFocus == request)
 733:           // Nothing to do in this trivial case.
 734:           retval = true;
 735:         else
 736:           {
 737:             // Requested component is a lightweight descendant of this one
 738:             // or the actual heavyweight.
 739:             // Since this (native) component is already focused, we simply
 740:             // change the actual focus and be done.
 741:             postFocusEvent(FocusEvent.FOCUS_GAINED, temporary);
 742:             retval = true;
 743:           }
 744:       }
 745:     else
 746:       {
 747:         if (gtkWidgetCanFocus())
 748:           {
 749:             if (allowWindowFocus)
 750:               {
 751:                 Window window = getWindowFor(request);
 752:                 GtkWindowPeer wPeer = (GtkWindowPeer) window.getPeer();
 753:                 if (! wPeer.gtkWindowHasFocus())
 754:                   wPeer.requestWindowFocus();
 755:               }
 756:             // Store requested focus component so that the corresponding
 757:             // event is dispatched correctly.
 758:             gtkWidgetRequestFocus();
 759:             retval = true;
 760:           }
 761:       }
 762:     return retval;
 763:   }
 764: 
 765:   private Window getWindowFor(Component c)
 766:   {
 767:     Component comp = c;
 768:     while (! (comp instanceof Window))
 769:       comp = comp.getParent();
 770:     return (Window) comp;
 771:   }
 772: 
 773:   /**
 774:    * Returns <code>true</code> if the component is a direct (== no intermediate
 775:    * heavyweights) lightweight descendant of this peer's component.
 776:    *
 777:    * @param c the component to check
 778:    *
 779:    * @return <code>true</code> if the component is a direct (== no intermediate
 780:    *         heavyweights) lightweight descendant of this peer's component
 781:    */
 782:   protected boolean isLightweightDescendant(Component c)
 783:   {
 784:     Component comp = c;
 785:     while (comp.getPeer() instanceof LightweightPeer)
 786:       comp = comp.getParent();
 787:     return comp == awtComponent;
 788:   }
 789: 
 790:   public boolean isObscured ()
 791:   {
 792:     return false;
 793:   }
 794: 
 795:   public boolean canDetermineObscurity ()
 796:   {
 797:     return false;
 798:   }
 799: 
 800:   public void coalescePaintEvent (PaintEvent e)
 801:   {
 802:     synchronized (this)
 803:     {
 804:       Rectangle newRect = e.getUpdateRect();
 805:       if (currentPaintArea == null)
 806:         currentPaintArea = newRect;
 807:       else
 808:         Rectangle.union(currentPaintArea, newRect, currentPaintArea);
 809:     }
 810:   }
 811: 
 812:   public void updateCursorImmediately ()
 813:   {
 814:     if (awtComponent.getCursor() != null)
 815:       setCursor(awtComponent.getCursor());
 816:   }
 817: 
 818:   public boolean handlesWheelScrolling ()
 819:   {
 820:     return false;
 821:   }
 822: 
 823:   // Convenience method to create a new volatile image on the screen
 824:   // on which this component is displayed.
 825:   public VolatileImage createVolatileImage (int width, int height)
 826:   {
 827:     return new GtkVolatileImage (this, width, height, null);
 828:   }
 829: 
 830:   // Creates buffers used in a buffering strategy.
 831:   public void createBuffers (int numBuffers, BufferCapabilities caps)
 832:     throws AWTException
 833:   {
 834:     // numBuffers == 2 implies double-buffering, meaning one back
 835:     // buffer and one front buffer.
 836:     if (numBuffers == 2)
 837:       backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(),
 838:                                         awtComponent.getHeight(),
 839:                                         caps.getBackBufferCapabilities());
 840:     else
 841:       throw new AWTException("GtkComponentPeer.createBuffers:"
 842:                  + " multi-buffering not supported");
 843:     this.caps = caps;
 844:   }
 845: 
 846:   // Return the back buffer.
 847:   public Image getBackBuffer ()
 848:   {
 849:     return backBuffer;
 850:   }
 851: 
 852:   // FIXME: flip should be implemented as a fast native operation
 853:   public void flip (BufferCapabilities.FlipContents contents)
 854:   {
 855:     getGraphics().drawImage(backBuffer,
 856:                             awtComponent.getWidth(),
 857:                             awtComponent.getHeight(),
 858:                             null);
 859: 
 860:     // create new back buffer and clear it to the background color.
 861:     if (contents == BufferCapabilities.FlipContents.BACKGROUND)
 862:     {
 863:       backBuffer = createVolatileImage(awtComponent.getWidth(),
 864:                                        awtComponent.getHeight());
 865:       backBuffer.getGraphics().clearRect(0, 0,
 866:                                          awtComponent.getWidth(),
 867:                                          awtComponent.getHeight());
 868:     }
 869:     // FIXME: support BufferCapabilities.FlipContents.PRIOR
 870:   }
 871: 
 872:   // Release the resources allocated to back buffers.
 873:   public void destroyBuffers ()
 874:   {
 875:     backBuffer.flush();
 876:   }
 877:   
 878:   public String toString ()
 879:   {
 880:     return "peer of " + awtComponent.toString();
 881:   }
 882:   public Rectangle getBounds()
 883:   {
 884:       // FIXME: implement
 885:     return null;
 886:   }
 887:   public void reparent(ContainerPeer parent)
 888:   {
 889:     // FIXME: implement
 890:   
 891:   }
 892:   public void setBounds(int x, int y, int width, int height, int z)
 893:   {
 894:     // FIXME: implement
 895:       setBounds (x, y, width, height);
 896:    
 897:   }
 898:   public boolean isReparentSupported()
 899:   {
 900:     // FIXME: implement
 901: 
 902:     return false;
 903:   }
 904:   public void layout()
 905:   {
 906:     // FIXME: implement
 907:  
 908:   }
 909: 
 910:   public boolean requestFocus(Component lightweightChild, boolean temporary,
 911:                               boolean focusedWindowChangeAllowed,
 912:                               long time, sun.awt.CausedFocusEvent.Cause cause)
 913:   {
 914:     // TODO: Implement this properly and remove the other requestFocus()
 915:     // methods.
 916:     return true;
 917:   }
 918: 
 919: }