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