Source for gnu.java.awt.peer.gtk.GtkToolkit

   1: /* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers
   2:    Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006, 2007
   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 gnu.classpath.Configuration;
  43: 
  44: import gnu.java.awt.AWTUtilities;
  45: import gnu.java.awt.EmbeddedWindow;
  46: import gnu.java.awt.dnd.GtkMouseDragGestureRecognizer;
  47: import gnu.java.awt.dnd.peer.gtk.GtkDragSourceContextPeer;
  48: import gnu.java.awt.peer.ClasspathFontPeer;
  49: import gnu.java.awt.peer.EmbeddedWindowPeer;
  50: 
  51: import java.awt.AWTException;
  52: import java.awt.Button;
  53: import java.awt.Canvas;
  54: import java.awt.Checkbox;
  55: import java.awt.CheckboxMenuItem;
  56: import java.awt.Choice;
  57: import java.awt.Component;
  58: import java.awt.Cursor;
  59: import java.awt.Dialog;
  60: import java.awt.Dimension;
  61: import java.awt.EventQueue;
  62: import java.awt.FileDialog;
  63: import java.awt.Font;
  64: import java.awt.FontMetrics;
  65: import java.awt.Frame;
  66: import java.awt.GraphicsDevice;
  67: import java.awt.GraphicsEnvironment;
  68: import java.awt.HeadlessException;
  69: import java.awt.Image;
  70: import java.awt.Label;
  71: import java.awt.List;
  72: import java.awt.Menu;
  73: import java.awt.MenuBar;
  74: import java.awt.MenuItem;
  75: import java.awt.Panel;
  76: import java.awt.Point;
  77: import java.awt.PopupMenu;
  78: import java.awt.PrintJob;
  79: import java.awt.Rectangle;
  80: import java.awt.ScrollPane;
  81: import java.awt.Scrollbar;
  82: import java.awt.TextArea;
  83: import java.awt.TextField;
  84: import java.awt.Window;
  85: import java.awt.datatransfer.Clipboard;
  86: import java.awt.dnd.DragGestureEvent;
  87: import java.awt.dnd.DragGestureListener;
  88: import java.awt.dnd.DragGestureRecognizer;
  89: import java.awt.dnd.DragSource;
  90: import java.awt.dnd.InvalidDnDOperationException;
  91: import java.awt.dnd.peer.DragSourceContextPeer;
  92: import java.awt.font.TextAttribute;
  93: import java.awt.im.InputMethodHighlight;
  94: import java.awt.image.ColorModel;
  95: import java.awt.image.DirectColorModel;
  96: import java.awt.image.ImageObserver;
  97: import java.awt.image.ImageProducer;
  98: import java.awt.peer.ButtonPeer;
  99: import java.awt.peer.CanvasPeer;
 100: import java.awt.peer.CheckboxMenuItemPeer;
 101: import java.awt.peer.CheckboxPeer;
 102: import java.awt.peer.ChoicePeer;
 103: import java.awt.peer.DialogPeer;
 104: import java.awt.peer.FileDialogPeer;
 105: import java.awt.peer.FontPeer;
 106: import java.awt.peer.FramePeer;
 107: import java.awt.peer.LabelPeer;
 108: import java.awt.peer.ListPeer;
 109: import java.awt.peer.MenuBarPeer;
 110: import java.awt.peer.MenuItemPeer;
 111: import java.awt.peer.MenuPeer;
 112: import java.awt.peer.MouseInfoPeer;
 113: import java.awt.peer.PanelPeer;
 114: import java.awt.peer.PopupMenuPeer;
 115: import java.awt.peer.RobotPeer;
 116: import java.awt.peer.ScrollPanePeer;
 117: import java.awt.peer.ScrollbarPeer;
 118: import java.awt.peer.TextAreaPeer;
 119: import java.awt.peer.TextFieldPeer;
 120: import java.awt.peer.WindowPeer;
 121: import java.io.InputStream;
 122: import java.net.URL;
 123: import java.util.HashMap;
 124: import java.util.LinkedHashMap;
 125: import java.util.Map;
 126: import java.util.Properties;
 127: 
 128: import javax.imageio.spi.IIORegistry;
 129: 
 130: /* This class uses a deprecated method java.awt.peer.ComponentPeer.getPeer().
 131:    This merits comment.  We are basically calling Sun's bluff on this one.
 132:    We think Sun has deprecated it simply to discourage its use as it is
 133:    bad programming style.  However, we need to get at a component's peer in
 134:    this class.  If getPeer() ever goes away, we can implement a hash table
 135:    that will keep up with every window's peer, but for now this is faster. */
 136: 
 137: public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
 138: {
 139:   static final Object GTK_LOCK;
 140: 
 141:   private static EventQueue q;
 142: 
 143:   static native void gtkInit(int portableNativeSync, Object lock);
 144: 
 145:   static native void gtkMain();
 146: 
 147:   static native void gtkQuit();
 148: 
 149:   /**
 150:    * Initializes field IDs that are used by native code.
 151:    */
 152:   private static native void initIDs();
 153: 
 154:   /**
 155:    * True when the field IDs are already initialized, false otherwise.
 156:    */
 157:   private static boolean initializedGlobalIDs = false;
 158: 
 159:   /**
 160:    * Initializes some global fieldIDs for use in the native code. This is
 161:    * called by a couple of classes in the GTK peers to ensure that
 162:    * some necessary stuff is loaded.
 163:    */
 164:   static synchronized void initializeGlobalIDs()
 165:   {
 166:     if (! initializedGlobalIDs)
 167:       {
 168:         initIDs();
 169:         initializedGlobalIDs = true;
 170:       }
 171:   }
 172: 
 173:   static
 174:   {
 175:     if (true) // GCJ LOCAL
 176:       {
 177:         System.loadLibrary("gtkpeer");
 178:       }
 179: 
 180:     /**
 181:      * Gotta do that first.
 182:      */
 183:     initializeGlobalIDs();
 184: 
 185:     int portableNativeSync;
 186:     String portNatSyncProp =
 187:       System.getProperty("gnu.classpath.awt.gtk.portable.native.sync");
 188: 
 189:     if (portNatSyncProp == null)
 190:       portableNativeSync = -1;  // unset
 191:     else if (Boolean.valueOf(portNatSyncProp).booleanValue())
 192:       portableNativeSync = 1;   // true
 193:     else
 194:       portableNativeSync = 0;   // false
 195: 
 196:     GTK_LOCK = new String("GTK LOCK");
 197:     gtkInit(portableNativeSync, GTK_LOCK);
 198:   }
 199: 
 200:   public GtkToolkit ()
 201:   {
 202:   }
 203: 
 204:   public native void beep();
 205: 
 206:   private native void getScreenSizeDimensions(int[] xy);
 207: 
 208:   public int checkImage (Image image, int width, int height,
 209:                          ImageObserver observer)
 210:   {
 211:     int status = ImageObserver.ALLBITS
 212:       | ImageObserver.WIDTH
 213:       | ImageObserver.HEIGHT;
 214: 
 215:     if (image instanceof GtkImage)
 216:       return ((GtkImage) image).checkImage (observer);
 217: 
 218:     if (image instanceof AsyncImage)
 219:       return ((AsyncImage) image).checkImage(observer);
 220: 
 221:     if (observer != null)
 222:       observer.imageUpdate (image, status,
 223:                             -1, -1,
 224:                             image.getWidth (observer),
 225:                             image.getHeight (observer));
 226: 
 227:     return status;
 228:   }
 229: 
 230:   /**
 231:    * Helper to return either a Image -- the argument -- or a
 232:    * GtkImage with the errorLoading flag set if the argument is null.
 233:    */
 234:   static Image imageOrError(Image b)
 235:   {
 236:     if (b == null)
 237:       return GtkImage.getErrorImage();
 238:     else
 239:       return b;
 240:   }
 241: 
 242:   public Image createImage (String filename)
 243:   {
 244:     if (filename.length() == 0)
 245:       return new GtkImage ();
 246: 
 247:     Image image;
 248:     try
 249:       {
 250:         image = CairoSurface.getBufferedImage( new GtkImage( filename ) );
 251:       }
 252:     catch (IllegalArgumentException iae)
 253:       {
 254:         image = null;
 255:       }
 256:     return imageOrError(image);
 257:   }
 258: 
 259:   public Image createImage (URL url)
 260:   {
 261:     return new AsyncImage(url);
 262:   }
 263: 
 264:   public Image createImage (ImageProducer producer)
 265:   {
 266:     if (producer == null)
 267:       return null;
 268: 
 269:     Image image;
 270:     try
 271:       {
 272:         image = CairoSurface.getBufferedImage( new GtkImage( producer ) );
 273:       }
 274:     catch (IllegalArgumentException iae)
 275:       {
 276:         image = null;
 277:       }
 278:     return imageOrError(image);
 279:   }
 280: 
 281:   public Image createImage (byte[] imagedata, int imageoffset,
 282:                             int imagelength)
 283:   {
 284:     Image image;
 285:     try
 286:       {
 287:         byte[] data = new byte[ imagelength ];
 288:         System.arraycopy(imagedata, imageoffset, data, 0, imagelength);
 289:         image = CairoSurface.getBufferedImage( new GtkImage( data ) );
 290:       }
 291:     catch (IllegalArgumentException iae)
 292:       {
 293:         image = null;
 294:       }
 295:     return imageOrError(image);
 296:   }
 297: 
 298:   /**
 299:    * Creates an ImageProducer from the specified URL. The image is assumed
 300:    * to be in a recognised format.
 301:    *
 302:    * @param url URL to read image data from.
 303:    */
 304:   public ImageProducer createImageProducer(URL url)
 305:   {
 306:     return createImage( url ).getSource();
 307:   }
 308: 
 309:   /**
 310:    * Returns the native color model (which isn't the same as the default
 311:    * ARGB color model, but doesn't have to be).
 312:    */
 313:   public ColorModel getColorModel ()
 314:   {
 315:     /* Return the GDK-native ABGR format */
 316:     return new DirectColorModel(32,
 317:                                 0x000000FF,
 318:                                 0x0000FF00,
 319:                                 0x00FF0000,
 320:                                 0xFF000000);
 321:   }
 322: 
 323:   public String[] getFontList ()
 324:   {
 325:     return (new String[] { "Dialog",
 326:                            "DialogInput",
 327:                            "Monospaced",
 328:                            "Serif",
 329:                            "SansSerif" });
 330:   }
 331: 
 332:   static class LRUCache<K,V> extends LinkedHashMap<K,V>
 333:   {
 334:     int max_entries;
 335:     public LRUCache(int max)
 336:     {
 337:       super(max, 0.75f, true);
 338:       max_entries = max;
 339:     }
 340:     protected boolean removeEldestEntry(Map.Entry eldest)
 341:     {
 342:       return size() > max_entries;
 343:     }
 344:   }
 345: 
 346:   private LRUCache<Map,ClasspathFontPeer> fontCache =
 347:     new LRUCache<Map,ClasspathFontPeer>(50);
 348:   private LRUCache<Object,Image> imageCache = new LRUCache<Object,Image>(50);
 349: 
 350:   public FontMetrics getFontMetrics (Font font)
 351:   {
 352:     return ((GdkFontPeer) font.getPeer()).getFontMetrics(font);
 353:   }
 354: 
 355:   public Image getImage (String filename)
 356:   {
 357:     if (imageCache.containsKey(filename))
 358:       return imageCache.get(filename);
 359:     else
 360:       {
 361:         Image im = createImage(filename);
 362:         imageCache.put(filename, im);
 363:         return im;
 364:       }
 365:   }
 366: 
 367:   public Image getImage (URL url)
 368:   {
 369:     if (imageCache.containsKey(url))
 370:       return imageCache.get(url);
 371:     else
 372:       {
 373:         Image im = createImage(url);
 374:         imageCache.put(url, im);
 375:         return im;
 376:       }
 377:   }
 378: 
 379:   public PrintJob getPrintJob (Frame frame, String jobtitle, Properties props)
 380:   {
 381:     SecurityManager sm;
 382:     sm = System.getSecurityManager();
 383:     if (sm != null)
 384:       sm.checkPrintJobAccess();
 385: 
 386:     return null;
 387:   }
 388: 
 389:   public native int getScreenResolution();
 390: 
 391:   public Dimension getScreenSize ()
 392:   {
 393:     int dim[] = new int[2];
 394:     getScreenSizeDimensions(dim);
 395:     return new Dimension(dim[0], dim[1]);
 396:   }
 397: 
 398:   public Clipboard getSystemClipboard()
 399:   {
 400:     SecurityManager secman = System.getSecurityManager();
 401:     if (secman != null)
 402:       secman.checkSystemClipboardAccess();
 403: 
 404:     return GtkClipboard.getClipboardInstance();
 405:   }
 406: 
 407:   public Clipboard getSystemSelection()
 408:   {
 409:     SecurityManager secman = System.getSecurityManager();
 410:     if (secman != null)
 411:       secman.checkSystemClipboardAccess();
 412: 
 413:     return GtkClipboard.getSelectionInstance();
 414:   }
 415: 
 416:   /**
 417:    * Prepares a GtkImage. For every other kind of Image it just
 418:    * assumes the image is already prepared for rendering.
 419:    */
 420:   public boolean prepareImage (Image image, int width, int height,
 421:                                ImageObserver observer)
 422:   {
 423:     /* GtkImages are always prepared, as long as they're loaded. */
 424:     if (image instanceof GtkImage)
 425:       return ((((GtkImage)image).checkImage (observer)
 426:                & ImageObserver.ALLBITS) != 0);
 427: 
 428:     if (image instanceof AsyncImage)
 429:       {
 430:         AsyncImage aImg = (AsyncImage) image;
 431:         aImg.addObserver(observer);
 432:         return aImg.realImage != null;
 433:       }
 434: 
 435:     /* Assume anything else is too */
 436:     return true;
 437:   }
 438: 
 439:   public native void sync();
 440: 
 441:   protected void setComponentState (Component c, GtkComponentPeer cp)
 442:   {
 443:     /* Make the Component reflect Peer defaults */
 444:     if (c.getForeground () == null)
 445:       c.setForeground (cp.getForeground ());
 446:     if (c.getBackground () == null)
 447:       c.setBackground (cp.getBackground ());
 448:     //        if (c.getFont () == null)
 449:     //          c.setFont (cp.getFont ());
 450: 
 451:     /* Make the Peer reflect the state of the Component */
 452:     if (! (c instanceof Window))
 453:       {
 454:         cp.setCursor (c.getCursor ());
 455: 
 456:         Rectangle bounds = c.getBounds ();
 457:         cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
 458:         cp.setVisible (c.isVisible ());
 459:       }
 460:   }
 461: 
 462:   protected ButtonPeer createButton (Button b)
 463:   {
 464:     checkHeadless();
 465:     return new GtkButtonPeer (b);
 466:   }
 467: 
 468:   protected CanvasPeer createCanvas (Canvas c)
 469:   {
 470:     checkHeadless();
 471:     return new GtkCanvasPeer (c);
 472:   }
 473: 
 474:   protected CheckboxPeer createCheckbox (Checkbox cb)
 475:   {
 476:     checkHeadless();
 477:     return new GtkCheckboxPeer (cb);
 478:   }
 479: 
 480:   protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi)
 481:   {
 482:     checkHeadless();
 483:     return new GtkCheckboxMenuItemPeer (cmi);
 484:   }
 485: 
 486:   protected ChoicePeer createChoice (Choice c)
 487:   {
 488:     checkHeadless();
 489:     return new GtkChoicePeer (c);
 490:   }
 491: 
 492:   protected DialogPeer createDialog (Dialog d)
 493:   {
 494:     checkHeadless();
 495:     GtkMainThread.createWindow();
 496:     return new GtkDialogPeer (d);
 497:   }
 498: 
 499:   protected FileDialogPeer createFileDialog (FileDialog fd)
 500:   {
 501:     checkHeadless();
 502:     return new GtkFileDialogPeer (fd);
 503:   }
 504: 
 505:   protected FramePeer createFrame (Frame f)
 506:   {
 507:     checkHeadless();
 508:     GtkMainThread.createWindow();
 509:     return new GtkFramePeer (f);
 510:   }
 511: 
 512:   protected LabelPeer createLabel (Label label)
 513:   {
 514:     checkHeadless();
 515:     return new GtkLabelPeer (label);
 516:   }
 517: 
 518:   protected ListPeer createList (List list)
 519:   {
 520:     checkHeadless();
 521:     return new GtkListPeer (list);
 522:   }
 523: 
 524:   protected MenuPeer createMenu (Menu m)
 525:   {
 526:     checkHeadless();
 527:     return new GtkMenuPeer (m);
 528:   }
 529: 
 530:   protected MenuBarPeer createMenuBar (MenuBar mb)
 531:   {
 532:     checkHeadless();
 533:     return new GtkMenuBarPeer (mb);
 534:   }
 535: 
 536:   protected MenuItemPeer createMenuItem (MenuItem mi)
 537:   {
 538:     checkHeadless();
 539:     return new GtkMenuItemPeer (mi);
 540:   }
 541: 
 542:   protected PanelPeer createPanel (Panel p)
 543:   {
 544:     checkHeadless();
 545:     return new GtkPanelPeer (p);
 546:   }
 547: 
 548:   protected PopupMenuPeer createPopupMenu (PopupMenu target)
 549:   {
 550:     checkHeadless();
 551:     return new GtkPopupMenuPeer (target);
 552:   }
 553: 
 554:   protected ScrollPanePeer createScrollPane (ScrollPane sp)
 555:   {
 556:     checkHeadless();
 557:     return new GtkScrollPanePeer (sp);
 558:   }
 559: 
 560:   protected ScrollbarPeer createScrollbar (Scrollbar sb)
 561:   {
 562:     checkHeadless();
 563:     return new GtkScrollbarPeer (sb);
 564:   }
 565: 
 566:   protected TextAreaPeer createTextArea (TextArea ta)
 567:   {
 568:     checkHeadless();
 569:     return new GtkTextAreaPeer (ta);
 570:   }
 571: 
 572:   protected TextFieldPeer createTextField (TextField tf)
 573:   {
 574:     checkHeadless();
 575:     return new GtkTextFieldPeer (tf);
 576:   }
 577: 
 578:   protected WindowPeer createWindow (Window w)
 579:   {
 580:     checkHeadless();
 581:     GtkMainThread.createWindow();
 582:     return new GtkWindowPeer (w);
 583:   }
 584: 
 585:   public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w)
 586:   {
 587:     checkHeadless();
 588:     GtkMainThread.createWindow();
 589:     return new GtkEmbeddedWindowPeer (w);
 590:   }
 591: 
 592:   /**
 593:    * @deprecated part of the older "logical font" system in earlier AWT
 594:    * implementations. Our newer Font class uses getClasspathFontPeer.
 595:    */
 596:   protected FontPeer getFontPeer (String name, int style) {
 597:     // All fonts get a default size of 12 if size is not specified.
 598:     return getFontPeer(name, style, 12);
 599:   }
 600: 
 601:   /**
 602:    * Private method that allows size to be set at initialization time.
 603:    */
 604:   private FontPeer getFontPeer (String name, int style, int size)
 605:   {
 606:     Map<TextAttribute,Object> attrs = new HashMap<TextAttribute,Object>();
 607:     ClasspathFontPeer.copyStyleToAttrs (style, attrs);
 608:     ClasspathFontPeer.copySizeToAttrs (size, attrs);
 609:     return getClasspathFontPeer (name, attrs);
 610:   }
 611: 
 612:   /**
 613:    * Newer method to produce a peer for a Font object, even though Sun's
 614:    * design claims Font should now be peerless, we do not agree with this
 615:    * model, hence "ClasspathFontPeer".
 616:    */
 617: 
 618:   public ClasspathFontPeer getClasspathFontPeer (String name,
 619:                                                  Map<?,?> attrs)
 620:   {
 621:     Map<Object,Object> keyMap = new HashMap<Object,Object>(attrs);
 622:     // We don't know what kind of "name" the user requested (logical, face,
 623:     // family), and we don't actually *need* to know here. The worst case
 624:     // involves failure to consolidate fonts with the same backend in our
 625:     // cache. This is harmless.
 626:     keyMap.put ("GtkToolkit.RequestedFontName", name);
 627:     if (fontCache.containsKey (keyMap))
 628:       return fontCache.get (keyMap);
 629:     else
 630:       {
 631:         ClasspathFontPeer newPeer = new GdkFontPeer (name, attrs);
 632:         fontCache.put (keyMap, newPeer);
 633:         return newPeer;
 634:       }
 635:   }
 636: 
 637:   protected EventQueue getSystemEventQueueImpl()
 638:   {
 639:     synchronized (GtkToolkit.class)
 640:       {
 641:         if (q == null)
 642:           {
 643:             q = new EventQueue();
 644:           }
 645:       }
 646:     return q;
 647:   }
 648: 
 649:   public Cursor createCustomCursor(Image image, Point hotspot, String name)
 650:   {
 651:     return new GtkCursor(image, hotspot, name);
 652:   }
 653: 
 654:   protected native void loadSystemColors (int[] systemColors);
 655: 
 656:   public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
 657:   {
 658:     if (GraphicsEnvironment.isHeadless())
 659:       throw new InvalidDnDOperationException();
 660:     return new GtkDragSourceContextPeer(e);
 661:   }
 662: 
 663:   public <T extends DragGestureRecognizer> T
 664:   createDragGestureRecognizer(Class<T> recognizer, DragSource ds,
 665:                               Component comp, int actions,
 666:                               DragGestureListener l)
 667:   {
 668:     if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer")
 669:         && ! GraphicsEnvironment.isHeadless())
 670:       {
 671:         GtkMouseDragGestureRecognizer gestureRecognizer
 672:           = new GtkMouseDragGestureRecognizer(ds, comp, actions, l);
 673:         gestureRecognizer.registerListeners();
 674:         return recognizer.cast(gestureRecognizer);
 675:       }
 676:     else
 677:       {
 678:         return null;
 679:       }
 680:   }
 681: 
 682:   public Map<TextAttribute,?> mapInputMethodHighlight(InputMethodHighlight highlight)
 683:   {
 684:     throw new Error("not implemented");
 685:   }
 686: 
 687:   public Rectangle getBounds()
 688:   {
 689:     int[] dims = new int[2];
 690:     getScreenSizeDimensions(dims);
 691:     return new Rectangle(0, 0, dims[0], dims[1]);
 692:   }
 693: 
 694:   // ClasspathToolkit methods
 695: 
 696:   public GraphicsEnvironment getLocalGraphicsEnvironment()
 697:   {
 698:     return new GdkGraphicsEnvironment();
 699:   }
 700: 
 701:   public Font createFont(int format, InputStream stream)
 702:   {
 703:     throw new UnsupportedOperationException();
 704:   }
 705: 
 706:   public RobotPeer createRobot (GraphicsDevice screen) throws AWTException
 707:   {
 708:     return new GdkRobotPeer (screen);
 709:   }
 710: 
 711:   public boolean getLockingKeyState(int keyCode)
 712:   {
 713:     int state = getLockState(keyCode);
 714: 
 715:     if (state != -1)
 716:       return state == 1;
 717: 
 718:     if (AWTUtilities.isValidKey(keyCode))
 719:       throw new UnsupportedOperationException
 720:         ("cannot get locking state of key code " + keyCode);
 721: 
 722:     throw new IllegalArgumentException("invalid key code " + keyCode);
 723:   }
 724: 
 725:   protected native int getLockState(int keyCode);
 726: 
 727:   public void registerImageIOSpis(IIORegistry reg)
 728:   {
 729:     GdkPixbufDecoder.registerSpis(reg);
 730:   }
 731: 
 732:   protected MouseInfoPeer getMouseInfoPeer()
 733:   {
 734:     return new GtkMouseInfoPeer();
 735:   }
 736: 
 737:   public boolean isFrameStateSupported(int state)
 738:   {
 739:     // GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but
 740:     // not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ.
 741:     return state == Frame.NORMAL || state == Frame.ICONIFIED
 742:            || state == Frame.MAXIMIZED_BOTH;
 743:   }
 744: 
 745:   private void checkHeadless()
 746:   {
 747:     if (GraphicsEnvironment.isHeadless())
 748:       throw new HeadlessException();
 749:   }
 750: 
 751:   public native int getMouseNumberOfButtons();
 752: 
 753:   @Override
 754:   public boolean isModalExclusionTypeSupported
 755:   (Dialog.ModalExclusionType modalExclusionType)
 756:   {
 757:     return false;
 758:   }
 759: 
 760:   @Override
 761:   public boolean isModalityTypeSupported(Dialog.ModalityType modalityType)
 762:   {
 763:     return false;
 764:   }
 765: 
 766: } // class GtkToolkit