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