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