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.Dialog;
  48: import java.awt.Dimension;
  49: import java.awt.EventQueue;
  50: import java.awt.FileDialog;
  51: import java.awt.Font;
  52: import java.awt.FontMetrics;
  53: import java.awt.Frame;
  54: import java.awt.GraphicsConfiguration;
  55: import java.awt.GraphicsDevice;
  56: import java.awt.GraphicsEnvironment;
  57: import java.awt.HeadlessException;
  58: import java.awt.Image;
  59: import java.awt.Label;
  60: import java.awt.List;
  61: import java.awt.Menu;
  62: import java.awt.MenuBar;
  63: import java.awt.MenuItem;
  64: import java.awt.Panel;
  65: import java.awt.PopupMenu;
  66: import java.awt.PrintJob;
  67: import java.awt.ScrollPane;
  68: import java.awt.Scrollbar;
  69: import java.awt.TextArea;
  70: import java.awt.TextField;
  71: import java.awt.Transparency;
  72: import java.awt.Window;
  73: import java.awt.Dialog.ModalExclusionType;
  74: import java.awt.Dialog.ModalityType;
  75: import java.awt.datatransfer.Clipboard;
  76: import java.awt.dnd.DragGestureEvent;
  77: import java.awt.dnd.peer.DragSourceContextPeer;
  78: import java.awt.im.InputMethodHighlight;
  79: import java.awt.image.BufferedImage;
  80: import java.awt.image.ColorModel;
  81: import java.awt.image.DirectColorModel;
  82: import java.awt.image.ImageObserver;
  83: import java.awt.image.ImageProducer;
  84: import java.awt.peer.ButtonPeer;
  85: import java.awt.peer.CanvasPeer;
  86: import java.awt.peer.CheckboxMenuItemPeer;
  87: import java.awt.peer.CheckboxPeer;
  88: import java.awt.peer.ChoicePeer;
  89: import java.awt.peer.DialogPeer;
  90: import java.awt.peer.FileDialogPeer;
  91: import java.awt.peer.FontPeer;
  92: import java.awt.peer.FramePeer;
  93: import java.awt.peer.LabelPeer;
  94: import java.awt.peer.ListPeer;
  95: import java.awt.peer.MenuBarPeer;
  96: import java.awt.peer.MenuItemPeer;
  97: import java.awt.peer.MenuPeer;
  98: import java.awt.peer.PanelPeer;
  99: import java.awt.peer.PopupMenuPeer;
 100: import java.awt.peer.RobotPeer;
 101: import java.awt.peer.ScrollPanePeer;
 102: import java.awt.peer.ScrollbarPeer;
 103: import java.awt.peer.TextAreaPeer;
 104: import java.awt.peer.TextFieldPeer;
 105: import java.awt.peer.WindowPeer;
 106: import java.io.ByteArrayInputStream;
 107: import java.io.File;
 108: import java.io.IOException;
 109: import java.io.InputStream;
 110: import java.net.MalformedURLException;
 111: import java.net.URL;
 112: import java.util.HashMap;
 113: import java.util.Map;
 114: import java.util.Properties;
 115: import java.util.WeakHashMap;
 116: 
 117: import javax.imageio.ImageIO;
 118: 
 119: import gnu.classpath.SystemProperties;
 120: import gnu.java.awt.ClasspathToolkit;
 121: import gnu.java.awt.EmbeddedWindow;
 122: import gnu.java.awt.font.OpenTypeFontPeer;
 123: import gnu.java.awt.image.ImageConverter;
 124: import gnu.java.awt.java2d.AbstractGraphics2D;
 125: import gnu.java.awt.peer.ClasspathFontPeer;
 126: import gnu.java.awt.peer.EmbeddedWindowPeer;
 127: import gnu.java.awt.peer.swing.SwingButtonPeer;
 128: import gnu.java.awt.peer.swing.SwingCanvasPeer;
 129: import gnu.java.awt.peer.swing.SwingCheckboxPeer;
 130: import gnu.java.awt.peer.swing.SwingLabelPeer;
 131: import gnu.java.awt.peer.swing.SwingPanelPeer;
 132: import gnu.java.awt.peer.swing.SwingTextAreaPeer;
 133: import gnu.java.awt.peer.swing.SwingTextFieldPeer;
 134: 
 135: public class XToolkit
 136:   extends ClasspathToolkit
 137: {
 138: 
 139:   /**
 140:    * Set to true to enable debug output.
 141:    */
 142:   static boolean DEBUG = false;
 143: 
 144:   /**
 145:    * Maps AWT colors to X colors.
 146:    */
 147:   HashMap colorMap = new HashMap();
 148: 
 149:   /**
 150:    * The system event queue.
 151:    */
 152:   private EventQueue eventQueue;
 153: 
 154:   /**
 155:    * The default color model of this toolkit.
 156:    */
 157:   private ColorModel colorModel;
 158: 
 159:   /**
 160:    * Maps image URLs to Image instances.
 161:    */
 162:   private HashMap imageCache = new HashMap();
 163: 
 164:   /**
 165:    * The cached fonts.
 166:    */
 167:   private WeakHashMap<String,ClasspathFontPeer> fontCache =
 168:     new WeakHashMap<String,ClasspathFontPeer>();
 169: 
 170:   public XToolkit()
 171:   {
 172:     SystemProperties.setProperty("gnu.javax.swing.noGraphics2D", "true");
 173:     SystemProperties.setProperty("java.awt.graphicsenv",
 174:                                  "gnu.java.awt.peer.x.XGraphicsEnvironment");
 175:   }
 176: 
 177:   public GraphicsEnvironment getLocalGraphicsEnvironment()
 178:   {
 179:     return new XGraphicsEnvironment();
 180:   }
 181: 
 182:   /**
 183:    * Returns the font peer for a font with the specified name and attributes.
 184:    *
 185:    * @param name the font name
 186:    * @param attrs the font attributes
 187:    *
 188:    * @return the font peer for a font with the specified name and attributes
 189:    */
 190:   public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs)
 191:   {
 192:     ClasspathFontPeer font;
 193:     if ("true".equals(System.getProperty("escherpeer.usexfonts")))
 194:       {
 195:         String canonical = XFontPeer.encodeFont(name, attrs);
 196:         if (!fontCache.containsKey(canonical))
 197:           {
 198:             font = new XFontPeer(name, attrs);
 199:             fontCache.put(canonical, font);
 200:           }
 201:         else
 202:           {
 203:             font = fontCache.get(canonical);
 204:           }
 205:       }
 206:     else
 207:       {
 208:         String canonical = OpenTypeFontPeer.encodeFont(name, attrs);
 209:         if (!fontCache.containsKey(canonical))
 210:           {
 211:             font = new OpenTypeFontPeer(name, attrs);
 212:             fontCache.put(canonical, font);
 213:           }
 214:         else
 215:           {
 216:             font = fontCache.get(canonical);
 217:           }
 218:       }
 219:     return font;
 220:   }
 221: 
 222:   public Font createFont(int format, InputStream stream)
 223:   {
 224:     return null;
 225:   }
 226: 
 227:   public RobotPeer createRobot(GraphicsDevice screen) throws AWTException
 228:   {
 229:     // TODO: Implement this.
 230:     throw new UnsupportedOperationException("Not yet implemented.");
 231:   }
 232: 
 233:   public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w)
 234:   {
 235:     // TODO: Implement this.
 236:     throw new UnsupportedOperationException("Not yet implemented.");
 237:   }
 238: 
 239:   protected ButtonPeer createButton(Button target)
 240:   {
 241:     checkHeadLess("No ButtonPeer can be created in an headless" +
 242:                       "graphics environment.");
 243: 
 244:     return new SwingButtonPeer(target);
 245:   }
 246: 
 247:   protected TextFieldPeer createTextField(TextField target)
 248:   {
 249:     checkHeadLess("No TextFieldPeer can be created in an headless " +
 250:                       "graphics environment.");
 251: 
 252:     return new SwingTextFieldPeer(target);
 253:   }
 254: 
 255:   protected LabelPeer createLabel(Label target)
 256:   {
 257:     checkHeadLess("No LabelPeer can be created in an headless graphics " +
 258:                       "environment.");
 259:     return new SwingLabelPeer(target);
 260:   }
 261: 
 262:   protected ListPeer createList(List target)
 263:   {
 264:     // TODO: Implement this.
 265:     throw new UnsupportedOperationException("Not yet implemented.");
 266:   }
 267: 
 268:   protected CheckboxPeer createCheckbox(Checkbox target)
 269:   {
 270:     checkHeadLess("No CheckboxPeer can be created in an headless graphics " +
 271:                   "environment.");
 272: 
 273:     return new SwingCheckboxPeer(target);
 274:   }
 275: 
 276:   protected ScrollbarPeer createScrollbar(Scrollbar target)
 277:   {
 278:     // TODO: Implement this.
 279:     throw new UnsupportedOperationException("Not yet implemented.");
 280:   }
 281: 
 282:   protected ScrollPanePeer createScrollPane(ScrollPane target)
 283:   {
 284:     // TODO: Implement this.
 285:     throw new UnsupportedOperationException("Not yet implemented.");
 286:   }
 287: 
 288:   protected TextAreaPeer createTextArea(TextArea target)
 289:   {
 290:     checkHeadLess("No TextAreaPeer can be created in an headless graphics " +
 291:                       "environment.");
 292: 
 293:     return new SwingTextAreaPeer(target);
 294:   }
 295: 
 296:   protected ChoicePeer createChoice(Choice target)
 297:   {
 298:     // TODO: Implement this.
 299:     throw new UnsupportedOperationException("Not yet implemented.");
 300:   }
 301: 
 302:   protected FramePeer createFrame(Frame target)
 303:   {
 304:     XFramePeer frame = new XFramePeer(target);
 305:     return frame;
 306:   }
 307: 
 308:   protected CanvasPeer createCanvas(Canvas target)
 309:   {
 310:     return new SwingCanvasPeer(target);
 311:   }
 312: 
 313:   protected PanelPeer createPanel(Panel target)
 314:   {
 315:     return new SwingPanelPeer(target);
 316:   }
 317: 
 318:   protected WindowPeer createWindow(Window target)
 319:   {
 320:     return new XWindowPeer(target);
 321:   }
 322: 
 323:   protected DialogPeer createDialog(Dialog target)
 324:   {
 325:     return new XDialogPeer(target);
 326:   }
 327: 
 328:   protected MenuBarPeer createMenuBar(MenuBar target)
 329:   {
 330:     // TODO: Implement this.
 331:     throw new UnsupportedOperationException("Not yet implemented.");
 332:   }
 333: 
 334:   protected MenuPeer createMenu(Menu target)
 335:   {
 336:     // TODO: Implement this.
 337:     throw new UnsupportedOperationException("Not yet implemented.");
 338:   }
 339: 
 340:   protected PopupMenuPeer createPopupMenu(PopupMenu target)
 341:   {
 342:     // TODO: Implement this.
 343:     throw new UnsupportedOperationException("Not yet implemented.");
 344:   }
 345: 
 346:   protected MenuItemPeer createMenuItem(MenuItem target)
 347:   {
 348:     // TODO: Implement this.
 349:     throw new UnsupportedOperationException("Not yet implemented.");
 350:   }
 351: 
 352:   protected FileDialogPeer createFileDialog(FileDialog target)
 353:   {
 354:     // TODO: Implement this.
 355:     throw new UnsupportedOperationException("Not yet implemented.");
 356:   }
 357: 
 358:   protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
 359:   {
 360:     // TODO: Implement this.
 361:     throw new UnsupportedOperationException("Not yet implemented.");
 362:   }
 363: 
 364:   protected FontPeer getFontPeer(String name, int style)
 365:   {
 366:     // TODO: Implement this.
 367:     throw new UnsupportedOperationException("Not yet implemented.");
 368:   }
 369: 
 370:   public Dimension getScreenSize()
 371:   {
 372:     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 373:     GraphicsDevice gd = ge.getDefaultScreenDevice();
 374:     GraphicsConfiguration gc = gd.getDefaultConfiguration();
 375:     XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc;
 376: 
 377:     return xgc.getSize();
 378:   }
 379: 
 380:   public int getScreenResolution()
 381:   {
 382:     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 383:     GraphicsDevice gd = ge.getDefaultScreenDevice();
 384:     GraphicsConfiguration gc = gd.getDefaultConfiguration();
 385:     XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc;
 386: 
 387:     return xgc.getResolution();
 388:   }
 389: 
 390:   /**
 391:    * Returns the color model used by this toolkit.
 392:    *
 393:    * @return the color model used by this toolkit
 394:    */
 395:   public ColorModel getColorModel()
 396:   {
 397:     // TODO: I assume 24 bit depth here, we can do this better.
 398:     if (colorModel == null)
 399:       colorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF);
 400:     return colorModel;
 401:   }
 402: 
 403:   public String[] getFontList()
 404:   {
 405:     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 406:     return ge.getAvailableFontFamilyNames();
 407:   }
 408: 
 409:   public FontMetrics getFontMetrics(Font name)
 410:   {
 411:     ClasspathFontPeer peer = (ClasspathFontPeer) name.getPeer();
 412:     return peer.getFontMetrics(name);
 413:   }
 414: 
 415:   public void sync()
 416:   {
 417:     // TODO: Implement this.
 418:     throw new UnsupportedOperationException("Not yet implemented.");
 419:   }
 420: 
 421:   /**
 422:    * Returns an image that has its pixel data loaded from a file with the
 423:    * specified name. If that file doesn't exist, an empty or error image
 424:    * is returned instead.
 425:    *
 426:    * @param name the filename of the file that contains the pixel data
 427:    *
 428:    * @return the image
 429:    */
 430:   public Image getImage(String name)
 431:   {
 432:     Image image;
 433:     try
 434:       {
 435:         File file = new File(name);
 436:         image = getImage(file.toURL());
 437:       }
 438:     catch (MalformedURLException ex)
 439:       {
 440:         // TODO: Replace by a more meaningful error image instead.
 441:         image = null;
 442:       }
 443:     return image;
 444:   }
 445: 
 446:   /**
 447:    * Returns an image that has its pixel data loaded from the specified URL.
 448:    * If the image cannot be loaded for some reason, an empty or error image
 449:    * is returned instead.
 450:    *
 451:    * @param url the URL to the image data
 452:    *
 453:    * @return the image
 454:    */
 455:   public Image getImage(URL url)
 456:   {
 457:     Image image;
 458:     if (imageCache.containsKey(url))
 459:       {
 460:         image = (Image) imageCache.get(url);
 461:       }
 462:     else
 463:       {
 464:         image = createImage(url);
 465:         imageCache.put(url, image);
 466:       }
 467:     return image;
 468:   }
 469: 
 470:   /**
 471:    * Returns an image that has its pixel data loaded from a file with the
 472:    * specified name. If that file doesn't exist, an empty or error image
 473:    * is returned instead.
 474:    *
 475:    * @param filename the filename of the file that contains the pixel data
 476:    *
 477:    * @return the image
 478:    */
 479:   public Image createImage(String filename)
 480:   {
 481:     Image im;
 482:     try
 483:       {
 484:         File file = new File(filename);
 485:         URL url = file.toURL();
 486:         im = createImage(url);
 487:       }
 488:     catch (MalformedURLException ex)
 489:       {
 490:         im = createErrorImage();
 491:       }
 492:     return im;
 493:   }
 494: 
 495:   /**
 496:    * Returns an image that has its pixel data loaded from the specified URL.
 497:    * If the image cannot be loaded for some reason, an empty or error image
 498:    * is returned instead.
 499:    *
 500:    * @param url the URL to the image data
 501:    *
 502:    * @return the image
 503:    */
 504:   public Image createImage(URL url)
 505:   {
 506:     Image image;
 507:     try
 508:       {
 509:         image = createImage(url.openStream());
 510:       }
 511:     catch (IOException ex)
 512:       {
 513:         image = createErrorImage();
 514:       }
 515:     return image;
 516:   }
 517: 
 518:   /**
 519:    * Creates an image that is returned when calls to createImage() yields an
 520:    * error.
 521:    *
 522:    * @return an image that is returned when calls to createImage() yields an
 523:    *         error
 524:    */
 525:   private Image createErrorImage()
 526:   {
 527:     // TODO: Create better error image.
 528:     return new XImage(1, 1);
 529:   }
 530: 
 531:   public boolean prepareImage(Image image, int width, int height, ImageObserver observer)
 532:   {
 533:     Image scaled = AbstractGraphics2D.prepareImage(image, width, height);
 534:     return checkImage(image, width, height, observer) == ImageObserver.ALLBITS;
 535:   }
 536: 
 537:   public int checkImage(Image image, int width, int height, ImageObserver observer)
 538:   {
 539:     // Images are loaded synchronously, so we don't bother and return true.
 540:     return ImageObserver.ALLBITS;
 541:   }
 542: 
 543:   public Image createImage(ImageProducer producer)
 544:   {
 545:     ImageConverter conv = new ImageConverter();
 546:     producer.startProduction(conv);
 547:     Image image = conv.getImage();
 548:     return image;
 549:   }
 550: 
 551:   public Image createImage(byte[] data, int offset, int len)
 552:   {
 553:     Image image;
 554:     try
 555:       {
 556:         ByteArrayInputStream i = new ByteArrayInputStream(data, offset, len);
 557:         image = createImage(i);
 558:       }
 559:     catch (IOException ex)
 560:       {
 561:         image = createErrorImage();
 562:       }
 563:     return image;
 564:   }
 565: 
 566:   private Image createImage(InputStream i)
 567:     throws IOException
 568:   {
 569:     Image image;
 570:     BufferedImage buffered = ImageIO.read(i);
 571:     // If the bufferedimage is opaque, then we can copy it over to an
 572:     // X Pixmap for faster drawing.
 573:     if (buffered != null && buffered.getTransparency() == Transparency.OPAQUE)
 574:       {
 575:         ImageProducer source = buffered.getSource();
 576:         image = createImage(source);
 577:       }
 578:     else if (buffered != null)
 579:       {
 580:         image = buffered;
 581:       }
 582:     else
 583:       {
 584:         image = createErrorImage();
 585:       }
 586:     return image;
 587:   }
 588: 
 589:   public PrintJob getPrintJob(Frame frame, String title, Properties props)
 590:   {
 591:     // TODO: Implement this.
 592:     throw new UnsupportedOperationException("Not yet implemented.");
 593:   }
 594: 
 595:   public void beep()
 596:   {
 597:     // TODO: Implement this.
 598:     throw new UnsupportedOperationException("Not yet implemented.");
 599:   }
 600: 
 601:   public Clipboard getSystemClipboard()
 602:   {
 603:     // TODO: Implement this.
 604:     throw new UnsupportedOperationException("Not yet implemented.");
 605:   }
 606: 
 607:   /**
 608:    * Returns the eventqueue used by the XLib peers.
 609:    *
 610:    * @return the eventqueue used by the XLib peers
 611:    */
 612:   protected EventQueue getSystemEventQueueImpl()
 613:   {
 614:     if (eventQueue == null)
 615:       eventQueue = new EventQueue();
 616:     return eventQueue;
 617:   }
 618: 
 619:   public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
 620:   {
 621:     // TODO: Implement this.
 622:     throw new UnsupportedOperationException("Not yet implemented.");
 623:   }
 624: 
 625:   public Map mapInputMethodHighlight(InputMethodHighlight highlight)
 626:   {
 627:     // TODO: Implement this.
 628:     throw new UnsupportedOperationException("Not yet implemented.");
 629:   }
 630: 
 631:   /**
 632:    * Helper method to quickly fetch the default device (X Display).
 633:    *
 634:    * @return the default XGraphicsDevice
 635:    */
 636:   static XGraphicsDevice getDefaultDevice()
 637:   {
 638:     XGraphicsEnvironment env = (XGraphicsEnvironment)
 639:       XGraphicsEnvironment.getLocalGraphicsEnvironment();
 640:     return (XGraphicsDevice) env.getDefaultScreenDevice();
 641:   }
 642: 
 643:   @Override
 644:   public boolean isModalExclusionTypeSupported(ModalExclusionType modalExclusionType)
 645:   {
 646:     // TODO Auto-generated method stub
 647:     return false;
 648:   }
 649: 
 650:   @Override
 651:   public boolean isModalityTypeSupported(ModalityType modalityType)
 652:   {
 653:     // TODO Auto-generated method stub
 654:     return false;
 655:   }
 656: 
 657:   private void checkHeadLess(String message) throws HeadlessException
 658:   {
 659:     if(GraphicsEnvironment.isHeadless())
 660:       {
 661:         if(message == null)
 662:           message = "This method cannot be called in headless mode.";
 663: 
 664:         throw new HeadlessException(message);
 665:       }
 666:   }
 667: }