Source for gnu.java.awt.peer.x.XToolkit

   1: /* XToolkit.java -- The central AWT Toolkit for the X peers
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.peer.x;
  40: 
  41: import java.awt.AWTException;
  42: import java.awt.Button;
  43: import java.awt.Canvas;
  44: import java.awt.Checkbox;
  45: import java.awt.CheckboxMenuItem;
  46: import java.awt.Choice;
  47: import java.awt.Component;
  48: import java.awt.Dialog;
  49: import java.awt.Dimension;
  50: import java.awt.EventQueue;
  51: import java.awt.FileDialog;
  52: import java.awt.Font;
  53: import java.awt.FontMetrics;
  54: import java.awt.Frame;
  55: import java.awt.GraphicsDevice;
  56: import java.awt.GraphicsEnvironment;
  57: import java.awt.Image;
  58: import java.awt.Label;
  59: import java.awt.List;
  60: import java.awt.Menu;
  61: import java.awt.MenuBar;
  62: import java.awt.MenuItem;
  63: import java.awt.Panel;
  64: import java.awt.PopupMenu;
  65: import java.awt.PrintJob;
  66: import java.awt.ScrollPane;
  67: import java.awt.Scrollbar;
  68: import java.awt.TextArea;
  69: import java.awt.TextField;
  70: import java.awt.Transparency;
  71: import java.awt.Window;
  72: import java.awt.datatransfer.Clipboard;
  73: import java.awt.dnd.DragGestureEvent;
  74: import java.awt.dnd.peer.DragSourceContextPeer;
  75: import java.awt.im.InputMethodHighlight;
  76: import java.awt.image.BufferedImage;
  77: import java.awt.image.ColorModel;
  78: import java.awt.image.DirectColorModel;
  79: import java.awt.image.ImageObserver;
  80: import java.awt.image.ImageProducer;
  81: import java.awt.peer.ButtonPeer;
  82: import java.awt.peer.CanvasPeer;
  83: import java.awt.peer.CheckboxMenuItemPeer;
  84: import java.awt.peer.CheckboxPeer;
  85: import java.awt.peer.ChoicePeer;
  86: import java.awt.peer.DialogPeer;
  87: import java.awt.peer.FileDialogPeer;
  88: import java.awt.peer.FontPeer;
  89: import java.awt.peer.FramePeer;
  90: import java.awt.peer.LabelPeer;
  91: import java.awt.peer.LightweightPeer;
  92: import java.awt.peer.ListPeer;
  93: import java.awt.peer.MenuBarPeer;
  94: import java.awt.peer.MenuItemPeer;
  95: import java.awt.peer.MenuPeer;
  96: import java.awt.peer.PanelPeer;
  97: import java.awt.peer.PopupMenuPeer;
  98: import java.awt.peer.RobotPeer;
  99: import java.awt.peer.ScrollPanePeer;
 100: import java.awt.peer.ScrollbarPeer;
 101: import java.awt.peer.TextAreaPeer;
 102: import java.awt.peer.TextFieldPeer;
 103: import java.awt.peer.WindowPeer;
 104: import java.io.ByteArrayInputStream;
 105: import java.io.File;
 106: import java.io.IOException;
 107: import java.io.InputStream;
 108: import java.net.MalformedURLException;
 109: import java.net.URL;
 110: import java.util.HashMap;
 111: import java.util.Map;
 112: import java.util.Properties;
 113: import java.util.WeakHashMap;
 114: 
 115: import javax.imageio.ImageIO;
 116: 
 117: import gnu.classpath.SystemProperties;
 118: import gnu.java.awt.ClasspathToolkit;
 119: import gnu.java.awt.EmbeddedWindow;
 120: import gnu.java.awt.peer.ClasspathFontPeer;
 121: import gnu.java.awt.peer.EmbeddedWindowPeer;
 122: import gnu.java.awt.peer.swing.SwingCanvasPeer;
 123: import gnu.java.awt.peer.swing.SwingLabelPeer;
 124: import gnu.java.awt.peer.swing.SwingPanelPeer;
 125: 
 126: public class XToolkit
 127:   extends ClasspathToolkit
 128: {
 129: 
 130:   /**
 131:    * Set to true to enable debug output.
 132:    */
 133:   static boolean DEBUG = false;
 134: 
 135:   /**
 136:    * Maps AWT colors to X colors.
 137:    */
 138:   HashMap colorMap = new HashMap();
 139: 
 140:   /**
 141:    * The system event queue.
 142:    */
 143:   private EventQueue eventQueue;
 144: 
 145:   /**
 146:    * The default color model of this toolkit.
 147:    */
 148:   private ColorModel colorModel;
 149: 
 150:   /**
 151:    * Maps image URLs to Image instances.
 152:    */
 153:   private HashMap imageCache = new HashMap();
 154: 
 155:   /**
 156:    * The cached fonts.
 157:    */
 158:   private WeakHashMap fontCache = new WeakHashMap();
 159: 
 160:   public XToolkit()
 161:   {
 162:     SystemProperties.setProperty("gnu.javax.swing.noGraphics2D", "true");
 163:     SystemProperties.setProperty("java.awt.graphicsenv",
 164:                                  "gnu.java.awt.peer.x.XGraphicsEnvironment");
 165:   }
 166: 
 167:   public GraphicsEnvironment getLocalGraphicsEnvironment()
 168:   {
 169:     return new XGraphicsEnvironment();
 170:   }
 171: 
 172:   /**
 173:    * Returns the font peer for a font with the specified name and attributes.
 174:    *
 175:    * @param name the font name
 176:    * @param attrs the font attributes
 177:    *
 178:    * @return the font peer for a font with the specified name and attributes
 179:    */
 180:   public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs)
 181:   {
 182:     String canonical = XFontPeer.encodeFont(name, attrs);
 183:     ClasspathFontPeer font;
 184:     if (!fontCache.containsKey(canonical))
 185:       {
 186:         String graphics2d =
 187:           SystemProperties.getProperty("gnu.xawt.graphics2d");
 188:         if (graphics2d != null && graphics2d.equals("gl"))
 189:           font = new XFontPeer2(name, attrs);
 190:         else
 191:           font = new XFontPeer(name, attrs);
 192:         fontCache.put(canonical, font);
 193:       }
 194:     else
 195:       {
 196:         font = (ClasspathFontPeer) fontCache.get(canonical);
 197:       }
 198:     return font;
 199:   }
 200: 
 201:   public Font createFont(int format, InputStream stream)
 202:   {
 203:     return null;
 204:   }
 205: 
 206:   public RobotPeer createRobot(GraphicsDevice screen) throws AWTException
 207:   {
 208:     // TODO: Implement this.
 209:     throw new UnsupportedOperationException("Not yet implemented.");
 210:   }
 211: 
 212:   public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w)
 213:   {
 214:     // TODO: Implement this.
 215:     throw new UnsupportedOperationException("Not yet implemented.");
 216:   }
 217: 
 218:   protected ButtonPeer createButton(Button target)
 219:   {
 220:     // TODO: Implement this.
 221:     throw new UnsupportedOperationException("Not yet implemented.");
 222:   }
 223: 
 224:   protected TextFieldPeer createTextField(TextField target)
 225:   {
 226:     // TODO: Implement this.
 227:     throw new UnsupportedOperationException("Not yet implemented.");
 228:   }
 229: 
 230:   protected LabelPeer createLabel(Label target)
 231:   {
 232:     return new SwingLabelPeer(target);
 233:   }
 234: 
 235:   protected ListPeer createList(List target)
 236:   {
 237:     // TODO: Implement this.
 238:     throw new UnsupportedOperationException("Not yet implemented.");
 239:   }
 240: 
 241:   protected CheckboxPeer createCheckbox(Checkbox target)
 242:   {
 243:     // TODO: Implement this.
 244:     throw new UnsupportedOperationException("Not yet implemented.");
 245:   }
 246: 
 247:   protected ScrollbarPeer createScrollbar(Scrollbar target)
 248:   {
 249:     // TODO: Implement this.
 250:     throw new UnsupportedOperationException("Not yet implemented.");
 251:   }
 252: 
 253:   protected ScrollPanePeer createScrollPane(ScrollPane target)
 254:   {
 255:     // TODO: Implement this.
 256:     throw new UnsupportedOperationException("Not yet implemented.");
 257:   }
 258: 
 259:   protected TextAreaPeer createTextArea(TextArea target)
 260:   {
 261:     // TODO: Implement this.
 262:     throw new UnsupportedOperationException("Not yet implemented.");
 263:   }
 264: 
 265:   protected ChoicePeer createChoice(Choice target)
 266:   {
 267:     // TODO: Implement this.
 268:     throw new UnsupportedOperationException("Not yet implemented.");
 269:   }
 270: 
 271:   protected FramePeer createFrame(Frame target)
 272:   {
 273:     XFramePeer frame = new XFramePeer(target);
 274:     return frame;
 275:   }
 276: 
 277:   protected CanvasPeer createCanvas(Canvas target)
 278:   {
 279:     return new SwingCanvasPeer(target);
 280:   }
 281: 
 282:   protected PanelPeer createPanel(Panel target)
 283:   {
 284:     return new SwingPanelPeer(target);
 285:   }
 286: 
 287:   protected WindowPeer createWindow(Window target)
 288:   {
 289:     return new XWindowPeer(target);
 290:   }
 291: 
 292:   protected DialogPeer createDialog(Dialog target)
 293:   {
 294:     return new XDialogPeer(target);
 295:   }
 296: 
 297:   protected MenuBarPeer createMenuBar(MenuBar target)
 298:   {
 299:     // TODO: Implement this.
 300:     throw new UnsupportedOperationException("Not yet implemented.");
 301:   }
 302: 
 303:   protected MenuPeer createMenu(Menu target)
 304:   {
 305:     // TODO: Implement this.
 306:     throw new UnsupportedOperationException("Not yet implemented.");
 307:   }
 308: 
 309:   protected PopupMenuPeer createPopupMenu(PopupMenu target)
 310:   {
 311:     // TODO: Implement this.
 312:     throw new UnsupportedOperationException("Not yet implemented.");
 313:   }
 314: 
 315:   protected MenuItemPeer createMenuItem(MenuItem target)
 316:   {
 317:     // TODO: Implement this.
 318:     throw new UnsupportedOperationException("Not yet implemented.");
 319:   }
 320: 
 321:   protected FileDialogPeer createFileDialog(FileDialog target)
 322:   {
 323:     // TODO: Implement this.
 324:     throw new UnsupportedOperationException("Not yet implemented.");
 325:   }
 326: 
 327:   protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
 328:   {
 329:     // TODO: Implement this.
 330:     throw new UnsupportedOperationException("Not yet implemented.");
 331:   }
 332: 
 333:   protected FontPeer getFontPeer(String name, int style)
 334:   {
 335:     // TODO: Implement this.
 336:     throw new UnsupportedOperationException("Not yet implemented.");
 337:   }
 338: 
 339:   public Dimension getScreenSize()
 340:   {
 341:     // FIXME: This is only a hack to get some apps working.
 342:     return new Dimension(1024, 768);
 343:   }
 344: 
 345:   public int getScreenResolution()
 346:   {
 347:     // TODO: Implement this.
 348:     throw new UnsupportedOperationException("Not yet implemented.");
 349:   }
 350: 
 351:   /**
 352:    * Returns the color model used by this toolkit.
 353:    *
 354:    * @return the color model used by this toolkit
 355:    */
 356:   public ColorModel getColorModel()
 357:   {
 358:     // TODO: I assume 24 bit depth here, we can do this better.
 359:     if (colorModel == null)
 360:       colorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
 361:     return colorModel;
 362:   }
 363: 
 364:   public String[] getFontList()
 365:   {
 366:     // TODO: Implement this.
 367:     throw new UnsupportedOperationException("Not yet implemented.");
 368:   }
 369: 
 370:   public FontMetrics getFontMetrics(Font name)
 371:   {
 372:     ClasspathFontPeer peer = (ClasspathFontPeer) name.getPeer();
 373:     return peer.getFontMetrics(name);
 374:   }
 375: 
 376:   public void sync()
 377:   {
 378:     // TODO: Implement this.
 379:     throw new UnsupportedOperationException("Not yet implemented.");
 380:   }
 381: 
 382:   /**
 383:    * Returns an image that has its pixel data loaded from a file with the
 384:    * specified name. If that file doesn't exist, an empty or error image
 385:    * is returned instead.
 386:    *
 387:    * @param name the filename of the file that contains the pixel data
 388:    *
 389:    * @return the image
 390:    */
 391:   public Image getImage(String name)
 392:   {
 393:     Image image;
 394:     try
 395:       {
 396:         File file = new File(name);
 397:         image = getImage(file.toURL());
 398:       }
 399:     catch (MalformedURLException ex)
 400:       {
 401:         // TODO: Replace by a more meaningful error image instead.
 402:         image = null;
 403:       }
 404:     return image;
 405:   }
 406: 
 407:   /**
 408:    * Returns an image that has its pixel data loaded from the specified URL.
 409:    * If the image cannot be loaded for some reason, an empty or error image
 410:    * is returned instead.
 411:    *
 412:    * @param url the URL to the image data
 413:    *
 414:    * @return the image
 415:    */
 416:   public Image getImage(URL url)
 417:   {
 418:     Image image;
 419:     if (imageCache.containsKey(url))
 420:       {
 421:         image = (Image) imageCache.get(url);
 422:       }
 423:     else
 424:       {
 425:         image = createImage(url);
 426:         imageCache.put(url, image);
 427:       }
 428:     return image;
 429:   }
 430: 
 431:   /**
 432:    * Returns an image that has its pixel data loaded from a file with the
 433:    * specified name. If that file doesn't exist, an empty or error image
 434:    * is returned instead.
 435:    *
 436:    * @param filename the filename of the file that contains the pixel data
 437:    *
 438:    * @return the image
 439:    */
 440:   public Image createImage(String filename)
 441:   {
 442:     Image im;
 443:     try
 444:       {
 445:         File file = new File(filename);
 446:         URL url = file.toURL();
 447:         im = createImage(url);
 448:       }
 449:     catch (MalformedURLException ex)
 450:       {
 451:         im = createErrorImage();
 452:       }
 453:     return im;
 454:   }
 455: 
 456:   /**
 457:    * Returns an image that has its pixel data loaded from the specified URL.
 458:    * If the image cannot be loaded for some reason, an empty or error image
 459:    * is returned instead.
 460:    *
 461:    * @param url the URL to the image data
 462:    *
 463:    * @return the image
 464:    */
 465:   public Image createImage(URL url)
 466:   {
 467:     Image image;
 468:     try
 469:       {
 470:         image = createImage(url.openStream());
 471:       }
 472:     catch (IOException ex)
 473:       {
 474:         image = createErrorImage();
 475:       }
 476:     return image;
 477:   }
 478: 
 479:   /**
 480:    * Creates an image that is returned when calls to createImage() yields an
 481:    * error.
 482:    * 
 483:    * @return an image that is returned when calls to createImage() yields an
 484:    *         error
 485:    */
 486:   private Image createErrorImage()
 487:   {
 488:     // TODO: Create better error image.
 489:     return new XImage(1, 1);
 490:   }
 491: 
 492:   public boolean prepareImage(Image image, int width, int height, ImageObserver observer)
 493:   {
 494:     // Images are loaded synchronously, so we don't bother and return true.
 495:     return true;
 496:   }
 497: 
 498:   public int checkImage(Image image, int width, int height, ImageObserver observer)
 499:   {
 500:     // TODO: Implement this.
 501:     throw new UnsupportedOperationException("Not yet implemented.");
 502:   }
 503: 
 504:   public Image createImage(ImageProducer producer)
 505:   {
 506:     ImageConverter conv = new ImageConverter();
 507:     producer.startProduction(conv);
 508:     Image image = conv.getXImage();
 509:     return image;
 510:   }
 511: 
 512:   public Image createImage(byte[] data, int offset, int len)
 513:   {
 514:     Image image;
 515:     try
 516:       {
 517:         ByteArrayInputStream i = new ByteArrayInputStream(data, offset, len);
 518:         image = createImage(i);
 519:       }
 520:     catch (IOException ex)
 521:       {
 522:         image = createErrorImage();
 523:       }
 524:     return image;
 525:   }
 526: 
 527:   private Image createImage(InputStream i)
 528:     throws IOException
 529:   {
 530:     Image image;
 531:     BufferedImage buffered = ImageIO.read(i);
 532:     // If the bufferedimage is opaque, then we can copy it over to an
 533:     // X Pixmap for faster drawing.
 534:     if (buffered != null && buffered.getTransparency() == Transparency.OPAQUE)
 535:       {
 536:         ImageProducer source = buffered.getSource();
 537:         image = createImage(source);
 538:       }
 539:     else if (buffered != null)
 540:       {
 541:         image = buffered;
 542:       }
 543:     else
 544:       {
 545:         image = createErrorImage();
 546:       }
 547:     return image;
 548:   }
 549: 
 550:   public PrintJob getPrintJob(Frame frame, String title, Properties props)
 551:   {
 552:     // TODO: Implement this.
 553:     throw new UnsupportedOperationException("Not yet implemented.");
 554:   }
 555: 
 556:   public void beep()
 557:   {
 558:     // TODO: Implement this.
 559:     throw new UnsupportedOperationException("Not yet implemented.");
 560:   }
 561: 
 562:   public Clipboard getSystemClipboard()
 563:   {
 564:     // TODO: Implement this.
 565:     throw new UnsupportedOperationException("Not yet implemented.");
 566:   }
 567: 
 568:   /**
 569:    * Returns the eventqueue used by the XLib peers.
 570:    *
 571:    * @return the eventqueue used by the XLib peers
 572:    */
 573:   protected EventQueue getSystemEventQueueImpl()
 574:   {
 575:     if (eventQueue == null)
 576:       eventQueue = new EventQueue();
 577:     return eventQueue;
 578:   }
 579: 
 580:   public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
 581:   {
 582:     // TODO: Implement this.
 583:     throw new UnsupportedOperationException("Not yet implemented.");
 584:   }
 585: 
 586:   public Map mapInputMethodHighlight(InputMethodHighlight highlight)
 587:   {
 588:     // TODO: Implement this.
 589:     throw new UnsupportedOperationException("Not yet implemented.");
 590:   }
 591: 
 592:   /**
 593:    * Helper method to quickly fetch the default device (X Display).
 594:    *
 595:    * @return the default XGraphicsDevice
 596:    */
 597:   static XGraphicsDevice getDefaultDevice()
 598:   {
 599:     XGraphicsEnvironment env = (XGraphicsEnvironment)
 600:       XGraphicsEnvironment.getLocalGraphicsEnvironment();
 601:     return (XGraphicsDevice) env.getDefaultScreenDevice();
 602:   }
 603: 
 604:   protected LightweightPeer createComponent(Component c)
 605:   {
 606:     return new XLightweightPeer(c);
 607:   }
 608: }