Source for gnu.awt.xlib.XCanvasPeer

   1: /* Copyright (C) 2000, 2002, 2003  Free Software Foundation
   2: 
   3:    This file is part of libgcj.
   4: 
   5: This software is copyrighted work licensed under the terms of the
   6: Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
   7: details.  */
   8: 
   9: package gnu.awt.xlib;
  10: 
  11: import java.awt.Dimension;
  12: import java.awt.BufferCapabilities;
  13: import java.awt.Component;
  14: import java.awt.EventQueue;
  15: import java.awt.Rectangle;
  16: import java.awt.Color;
  17: import java.awt.Container;
  18: import java.awt.Image;
  19: import java.awt.GraphicsConfiguration;
  20: import java.awt.Font;
  21: import java.awt.FontMetrics;
  22: import java.awt.Graphics;
  23: import java.awt.Point;
  24: import java.awt.Toolkit;
  25: import java.awt.AWTEvent;
  26: import java.awt.Cursor;
  27: import java.awt.Shape;
  28: 
  29: import java.awt.peer.*;
  30: import java.awt.image.*;
  31: 
  32: import java.awt.event.MouseListener;
  33: import java.awt.event.PaintEvent;
  34: 
  35: import java.util.EventListener;
  36: 
  37: import gnu.gcj.xlib.WMSizeHints;
  38: import gnu.gcj.xlib.Window;
  39: import gnu.gcj.xlib.WindowAttributes;
  40: import gnu.gcj.xlib.Display;
  41: import gnu.gcj.xlib.Visual;
  42: import gnu.gcj.xlib.Screen;
  43: import gnu.gcj.xlib.XImage;
  44: 
  45: import gnu.awt.j2d.*;
  46: 
  47: import sun.awt.CausedFocusEvent;
  48: 
  49: public class XCanvasPeer implements CanvasPeer
  50: {
  51:   static final Dimension MIN_SIZE = new Dimension(1, 1);
  52:   
  53:   public // temporary
  54:   
  55:   Window window;
  56:   Window parent;
  57: 
  58:   Component component;
  59:   XGraphicsConfiguration config;
  60:   private WindowAttributes attributes = new WindowAttributes();
  61:   private long eventMask;
  62:   
  63:   public XCanvasPeer(Component component)
  64:   {
  65:     this.component = component;
  66:     
  67:     // Set up graphics configuration (ie. screen + visual):
  68: 
  69:     config = (XGraphicsConfiguration)
  70:       component.getGraphicsConfiguration();
  71: 
  72:     if (config == null)
  73:       {
  74:     // This will usually only happen for toplevel windows
  75:     config = getXToolkit().getDefaultXGraphicsConfiguration();
  76:       } 
  77: 
  78:     Rectangle bounds = component.getBounds();
  79:     parent = locateParentWindow(bounds);
  80:     
  81:     // Windows in X must atleast be of size 1x1
  82:     boolean boundsChanged = false;
  83:     if (bounds.width < 1)
  84:       {
  85:     boundsChanged = true;
  86:     bounds.width = 1;
  87:       }
  88:     if (bounds.height < 1)
  89:       {
  90:     boundsChanged = true;
  91:     bounds.height = 1;
  92:       }
  93:     
  94:     /* don't worry about this calling back to us, since the real
  95:        component object has not yet received a reference to this peer
  96:        object. */
  97:     component.setBounds(bounds);
  98:         
  99: 
 100:     /* Set background color */
 101:     Color bg = component.getBackground();
 102:     if (bg != null)
 103:       {
 104:     int[] components =
 105:     {
 106:       bg.getRed(),
 107:       bg.getGreen(),
 108:       bg.getBlue(),
 109:       0xff
 110:     };
 111: 
 112:     ColorModel cm = config.getColorModel();
 113:     long pixel = cm.getDataElement(components, 0);
 114:     attributes.setBackground(pixel);
 115:       }
 116:     
 117:     /* Set exposure mask so that we get exposure events
 118:        that can be translated into paint() calls. */
 119:     long eventMask = WindowAttributes.MASK_EXPOSURE;
 120: 
 121:     /* It would be nice to set up all other required events here, but
 122:        it is not possible to do so before after all the children of
 123:        this component has been realized.  The reason is that it is not
 124:        determined whether a component is lightweight before after the
 125:        addNotify() method has been called.  Thus, it is not possible
 126:        for parent component to determine what events it needs to
 127:        furnish for lightweight children.  Instead, we currently rely
 128:        on the component calling our setEventMask() method after the
 129:        correct event mask has been determined. */
 130: 
 131:     attributes.setEventMask(eventMask);
 132:     
 133:         
 134:     // TODO: set more window attributes?
 135: 
 136:     /* don't allow event queue to process events from the newly
 137:        created window before this peer has been registered as client
 138:        data. */
 139:     synchronized (getXToolkit().eventLoop)
 140:       {
 141:     window = new gnu.gcj.xlib.Window(parent, bounds, attributes);
 142:     window.setClientData(this); /* make it possible to find back
 143:                        to this peer object. Used by
 144:                        XEventQueue. */
 145:       }
 146:     
 147:     initWindowProperties();
 148: 
 149:     if (component.isVisible())
 150:       EventQueue.invokeLater(new DoMap(window));
 151:   }
 152: 
 153:   /**
 154:    * Override this in subclasses to implement other ways of obtaining
 155:    * parent windows.  Toplevel windows will typically have a different
 156:    * implementation.
 157:    */
 158:   gnu.gcj.xlib.Window locateParentWindow(Rectangle bounds)
 159:   {
 160:     Container parent = component.getParent();
 161:     while (parent.isLightweight())
 162:       {
 163:     bounds.x += parent.getX();
 164:     bounds.y += parent.getY();
 165:     parent = parent.getParent();
 166:     // a null pointer here is a genuine error
 167:       }
 168:     
 169:     XCanvasPeer parentPeer = (XCanvasPeer) parent.getPeer();
 170:     if (parentPeer == null)
 171:       throw new NullPointerException("Parent has no peer. This should " +
 172:                      "not be possible, since the " +
 173:                      "calls leading here should come " +
 174:                      "from parent, after it has " +
 175:                      "set the parent peer.");
 176:     return parentPeer.window;
 177:   }
 178:     
 179: 
 180:   /** 
 181:    * Template method to allow subclasses to apply properties to X11
 182:    * window right after creation.
 183:    */
 184:   void initWindowProperties()
 185:   {
 186:   }
 187:     
 188:   XToolkit getXToolkit()
 189:   {
 190:     return XToolkit.INSTANCE;
 191:   }
 192: 
 193:   protected void ensureFlush()
 194:   {
 195:     getXToolkit().flushIfIdle();
 196:   }
 197: 
 198:   public Component getComponent()
 199:   {
 200:     return component;
 201:   }
 202:   
 203:   long getBasicEventMask()
 204:   {
 205:     return WindowAttributes.MASK_EXPOSURE;
 206:   }
 207:     
 208:   // -------- java.awt.peer.ComponentPeer implementation
 209: 
 210:   public int checkImage(Image img, int width, int height, ImageObserver o)
 211:   {
 212:     throw new UnsupportedOperationException("FIXME, not implemented");
 213:   }
 214:   public Image createImage(ImageProducer prod)
 215:   {
 216:     return new XOffScreenImage (config, window, prod, config.getColorModel());
 217:   }
 218:   public Image createImage(int width, int height)
 219:   {
 220:     return new XOffScreenImage (config, window, width, height, config.getColorModel());
 221:   }
 222:   public void dispose()
 223:   {
 224:     throw new UnsupportedOperationException("FIXME, not implemented");
 225:   }
 226: 
 227:   public GraphicsConfiguration getGraphicsConfiguration()
 228:   {
 229:     return config;
 230:   }
 231: 
 232:   public FontMetrics getFontMetrics(Font f)
 233:   {
 234:     throw new UnsupportedOperationException("FIXME, not implemented");
 235:   }
 236: 
 237:   public ColorModel getColorModel ()
 238:   {
 239:     return null;
 240:   }
 241: 
 242:   public Graphics getGraphics()
 243:   {
 244:     DirectRasterGraphics gfxDevice = new XGraphics(window, config);
 245:     IntegerGraphicsState igState = new IntegerGraphicsState(gfxDevice);
 246:     Graphics2DImpl gfx2d = new Graphics2DImpl(config);
 247: 
 248:     gfx2d.setState(igState);
 249:     gfx2d.setColor(component.getBackground());
 250:     return gfx2d;
 251:   }
 252: 
 253:   private Rectangle locationBounds;
 254:   public Point getLocationOnScreen()
 255:   {
 256:     locationBounds = window.getBounds (locationBounds);
 257:     return new Point (locationBounds.x,locationBounds.y);
 258:   }
 259: 
 260:   public Dimension getMinimumSize ()
 261:   {
 262:     return MIN_SIZE;
 263:   }
 264: 
 265:   public Dimension minimumSize ()
 266:   {
 267:     return getMinimumSize ();
 268:   }
 269: 
 270:   public Dimension getPreferredSize ()
 271:   {
 272:     return component.getSize();
 273:   }
 274:     
 275:   public Dimension preferredSize ()
 276:   {
 277:     return getPreferredSize();
 278:   }
 279:     
 280:   public Toolkit getToolkit()
 281:   {
 282:     return getXToolkit();
 283:   }
 284: 
 285:   public void handleEvent(AWTEvent event)
 286:   {
 287:     int id = event.getID ();
 288:     
 289:     switch (id)
 290:     {
 291:       case PaintEvent.PAINT:
 292:       case PaintEvent.UPDATE:
 293:       {
 294:         try
 295:         {
 296:           Graphics g = getGraphics ();
 297:           g.setClip (((PaintEvent)event).getUpdateRect ());
 298:           
 299:           if (id == PaintEvent.PAINT)
 300:             component.paint (g);
 301:           else
 302:             component.update (g);
 303:           
 304:           g.dispose ();
 305:         }
 306:         catch (InternalError e)
 307:         {
 308:           System.err.println (e);
 309:         }
 310:       }
 311:       break;
 312:     }
 313:   }
 314: 
 315:   public boolean isFocusTraversable()
 316:   {
 317:     throw new UnsupportedOperationException("FIXME, not implemented");
 318:   }
 319: 
 320:   public void paint(Graphics gfx)
 321:   {
 322:     // do nothing by default
 323:   }
 324:     
 325:   public boolean prepareImage(Image img, int width, int height,
 326:                   ImageObserver o)
 327:   {
 328:     throw new UnsupportedOperationException("FIXME, not implemented");
 329:   }
 330: 
 331:   public void print(Graphics graphics)
 332:   {
 333:     paint(graphics);
 334:   }
 335: 
 336:   public void repaint(long tm, int x, int y, int w, int h)
 337:   {
 338:     /* TODO?
 339: 
 340:        X allows intelligent X servers to do smart
 341:        refreshing. Perhaps involve X in repainting of components,
 342:        rather that keeping it all within the local event queue. */
 343:     
 344:     PaintEvent updateEvent = new PaintEvent(component,
 345:                         PaintEvent.UPDATE,
 346:                         new Rectangle(x, y, w, h));
 347:     getXToolkit().queue.postEvent(updateEvent);
 348:   }
 349:     
 350:   public void requestFocus()
 351:   {
 352:     throw new UnsupportedOperationException("FIXME, not implemented");
 353:   }
 354: 
 355:   public void setBackground(Color color)
 356:   {
 357:     if (color != null)
 358:     {
 359:       int[] components =
 360:       {
 361:         color.getRed (),
 362:         color.getGreen (),
 363:         color.getBlue (),
 364:         0xff
 365:       };
 366:       
 367:       ColorModel cm = config.getColorModel ();
 368:       long pixel = cm.getDataElement (components, 0);
 369:       attributes.setBackground (pixel);
 370:       window.setAttributes (attributes);
 371:     }
 372:   }
 373: 
 374:   public void setBounds(int x, int y, int width, int height)
 375:   {
 376:     width  = Math.max(width,  1);
 377:     height = Math.max(height, 1);
 378:     window.setBounds(x, y, width, height);
 379:     ensureFlush();        
 380:   }
 381:     
 382:   public void reshape (int x, int y, int width, int height)
 383:   {
 384:     setBounds (x, y, width, height);
 385:   }
 386: 
 387:   public void setCursor(Cursor cursor)
 388:   {
 389:     throw new UnsupportedOperationException("FIXME, not implemented");
 390:   }
 391: 
 392:   public void setEnabled(boolean enabled)
 393:   {
 394:     throw new UnsupportedOperationException("FIXME, not implemented");
 395:   }
 396: 
 397:   public void enable ()
 398:   {
 399:     setEnabled (true);
 400:   }
 401: 
 402:   public void disable ()
 403:   {
 404:     setEnabled (false);
 405:   }
 406: 
 407:   public void setEventMask(long eventMask)
 408:   {
 409:     if (this.eventMask != eventMask)
 410:     {
 411:       this.eventMask = eventMask;
 412:       long xEventMask = getBasicEventMask ();
 413:       
 414:       if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0)
 415:       {
 416:         xEventMask |=
 417:           WindowAttributes.MASK_BUTTON_PRESS |
 418:           WindowAttributes.MASK_BUTTON_RELEASE;
 419:       }
 420:       
 421:       attributes.setEventMask (xEventMask);
 422:       window.setAttributes (attributes);
 423:       ensureFlush ();
 424:     }
 425:   }
 426: 
 427:   public void setFont(Font font)
 428:   {
 429:     /* default canvas peer does not keep track of font, since it won't
 430:        paint anything. */
 431:   }
 432: 
 433:   public void setForeground(Color color)
 434:   {
 435:     /* default canvas peer does not keep track of foreground, since it won't
 436:        paint anything. */
 437:   }
 438:     
 439:   public void setVisible(boolean visible)
 440:   {
 441:     if (visible)
 442:       {
 443:     window.map();
 444:     ensureFlush();        
 445:       }
 446:     else
 447:       {
 448:     window.unmap();
 449:     ensureFlush();        
 450:       }
 451:   }
 452:     
 453:   public void show ()
 454:   {
 455:     setVisible (true);
 456:   }
 457: 
 458:   public void hide ()
 459:   {
 460:     setVisible (false);
 461:   }
 462: 
 463:   public boolean isFocusable ()
 464:   {
 465:     return false;
 466:   }
 467: 
 468:   public boolean requestFocus (Component source, boolean b1, 
 469:                                boolean b2, long x)
 470:   {
 471:     return false;
 472:   }
 473: 
 474:   public boolean requestFocus (Component source, boolean b1, 
 475:                                boolean b2, long x,
 476:                    CausedFocusEvent.Cause cause)
 477:   {
 478:     return false;
 479:   }
 480: 
 481:   public boolean isObscured ()
 482:   {
 483:     return false;
 484:   }
 485: 
 486:   public boolean canDetermineObscurity ()
 487:   {
 488:     return false;
 489:   }
 490: 
 491:   public void coalescePaintEvent (PaintEvent e)
 492:   {
 493:   }
 494: 
 495:   public void updateCursorImmediately ()
 496:   {
 497:   }
 498: 
 499:   public VolatileImage createVolatileImage (int width, int height)
 500:   {
 501:     return null;
 502:   }
 503: 
 504:   public boolean handlesWheelScrolling ()
 505:   {
 506:     return false;
 507:   }
 508: 
 509:   public void createBuffers (int x, BufferCapabilities capabilities)
 510:     throws java.awt.AWTException
 511: 
 512:   {
 513:   }
 514: 
 515:   public Image getBackBuffer ()
 516:   {
 517:     return null;
 518:   }
 519: 
 520:   public void flip (BufferCapabilities.FlipContents contents)
 521:   {
 522:   }
 523: 
 524:   public void destroyBuffers ()
 525:   {
 526:   }
 527: 
 528:   static class DoMap implements Runnable 
 529:   {
 530:     Window window;
 531:     public DoMap(Window w) 
 532:     {
 533:       this.window = w;
 534:     }
 535:     
 536:     public void run() 
 537:     {
 538:       window.map();
 539:     }
 540:   }
 541: 
 542:   /**
 543:    * @since 1.5
 544:    */
 545:   public boolean isRestackSupported ()
 546:   {
 547:     return false;
 548:   }
 549: 
 550:   /**
 551:    * @since 1.5
 552:    */
 553:   public void cancelPendingPaint (int x, int y, int width, int height)
 554:   {
 555:   }
 556: 
 557:   /**
 558:    * @since 1.5
 559:    */
 560:   public void restack ()
 561:   {
 562:   }
 563: 
 564:   /**
 565:    * @since 1.5
 566:    */
 567:   public Rectangle getBounds ()
 568:   {
 569:     return null;
 570:   }
 571: 
 572:   /**
 573:    * @since 1.5
 574:    */
 575:   public void reparent (ContainerPeer parent)
 576:   {
 577:   }
 578: 
 579:   /**
 580:    * @since 1.5
 581:    */
 582:   public void setBounds (int x, int y, int width, int height, int z)
 583:   {
 584:   }
 585: 
 586:   /**
 587:    * @since 1.5
 588:    */
 589:   public boolean isReparentSupported ()
 590:   {
 591:     return false;
 592:   }
 593: 
 594:   /**
 595:    * @since 1.5
 596:    */
 597:   public void layout ()
 598:   {
 599:   }
 600: }