1 /* GtkComponentPeer.java -- Implements ComponentPeer with GTK
2 Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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., 59 Temple Place, Suite 330, Boston, MA
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
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. */
39 package gnu.java.awt.peer.gtk;
41 import java.awt.AWTEvent;
42 import java.awt.BufferCapabilities;
43 import java.awt.Color;
44 import java.awt.Component;
45 import java.awt.Container;
46 import java.awt.Cursor;
47 import java.awt.Dimension;
49 import java.awt.FontMetrics;
50 import java.awt.Frame;
51 import java.awt.Graphics;
52 import java.awt.Graphics2D;
53 import java.awt.GraphicsConfiguration;
54 import java.awt.Image;
55 import java.awt.Insets;
56 import java.awt.ItemSelectable;
57 import java.awt.KeyboardFocusManager;
58 import java.awt.Point;
59 import java.awt.Rectangle;
60 import java.awt.Toolkit;
61 import java.awt.Window;
62 import java.awt.event.FocusEvent;
63 import java.awt.event.ItemEvent;
64 import java.awt.event.KeyEvent;
65 import java.awt.event.MouseEvent;
66 import java.awt.event.PaintEvent;
67 import java.awt.image.ColorModel;
68 import java.awt.image.ImageObserver;
69 import java.awt.image.ImageProducer;
70 import java.awt.image.VolatileImage;
71 import java.awt.peer.ComponentPeer;
73 public class GtkComponentPeer extends GtkGenericPeer
74 implements ComponentPeer
76 Component awtComponent;
82 /* this isEnabled differs from Component.isEnabled, in that it
83 knows if a parent is disabled. In that case Component.isEnabled
84 may return true, but our isEnabled will always return false */
85 native boolean isEnabled ();
86 native static boolean modalHasGrab ();
88 native int[] gtkWidgetGetForeground ();
89 native int[] gtkWidgetGetBackground ();
90 native void gtkWidgetGetDimensions (int[] dim);
91 native void gtkWidgetGetPreferredDimensions (int[] dim);
92 native void gtkWidgetGetLocationOnScreen (int[] point);
93 native void gtkWidgetSetCursor (int type);
94 native void gtkWidgetSetBackground (int red, int green, int blue);
95 native void gtkWidgetSetForeground (int red, int green, int blue);
96 native void gtkWidgetSetSensitive (boolean sensitive);
97 native void gtkWidgetSetParent (ComponentPeer parent);
98 native void gtkWidgetRequestFocus ();
99 native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
100 int keyCode, int keyLocation);
102 native boolean isRealized ();
106 throw new RuntimeException ();
109 native void connectSignals ();
111 protected GtkComponentPeer (Component awtComponent)
113 super (awtComponent);
114 this.awtComponent = awtComponent;
115 insets = new Insets (0, 0, 0, 0);
121 if (awtComponent.getForeground () != null)
122 setForeground (awtComponent.getForeground ());
123 if (awtComponent.getBackground () != null)
124 setBackground (awtComponent.getBackground ());
125 if (awtComponent.getFont() != null)
126 setFont(awtComponent.getFont());
128 Component parent = awtComponent.getParent ();
130 // Only set our parent on the GTK side if our parent on the AWT
131 // side is not showing. Otherwise the gtk peer will be shown
132 // before we've had a chance to position and size it properly.
133 if (awtComponent instanceof Window
134 || (parent != null && ! parent.isShowing ()))
135 setParentAndBounds ();
138 void setParentAndBounds ()
142 setComponentBounds ();
144 setVisibleAndEnabled ();
150 Component component = awtComponent;
153 component = component.getParent ();
154 p = component.getPeer ();
156 while (p instanceof java.awt.peer.LightweightPeer);
159 gtkWidgetSetParent (p);
162 void beginNativeRepaint ()
167 void endNativeRepaint ()
173 * Set the bounds of this peer's AWT Component based on dimensions
174 * returned by the native windowing system. Most Components impose
175 * their dimensions on the peers which is what the default
176 * implementation does. However some peers, like GtkFileDialogPeer,
177 * need to pass their size back to the AWT Component.
179 void setComponentBounds ()
181 Rectangle bounds = awtComponent.getBounds ();
183 if (bounds.x == 0 && bounds.y == 0
184 && bounds.width == 0 && bounds.height == 0)
187 setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
190 void setVisibleAndEnabled ()
192 setVisible (awtComponent.isVisible ());
193 setEnabled (awtComponent.isEnabled ());
196 public int checkImage (Image image, int width, int height,
197 ImageObserver observer)
199 GtkImage i = (GtkImage) image;
200 return i.checkImage ();
203 public Image createImage (ImageProducer producer)
205 GtkImage image = new GtkImage (producer, null);
206 producer.startProduction (image);
210 public Image createImage (int width, int height)
213 if (GtkToolkit.useGraphics2D ())
215 Graphics2D g2 = new GdkGraphics2D (width, height);
216 g2.setBackground (getBackground ());
220 g = new GdkGraphics (width, height);
222 g.setColor(getBackground());
223 g.fillRect(0, 0, width, height);
225 return new GtkOffScreenImage (null, g, width, height);
228 public void disable ()
233 public void enable ()
238 public ColorModel getColorModel ()
240 return ColorModel.getRGBdefault ();
243 public FontMetrics getFontMetrics (Font font)
245 return getToolkit().getFontMetrics(font);
248 public Graphics getGraphics ()
250 if (GtkToolkit.useGraphics2D ())
251 return new GdkGraphics2D (this);
253 return new GdkGraphics (this);
256 public Point getLocationOnScreen ()
258 int point[] = new int[2];
259 gtkWidgetGetLocationOnScreen (point);
260 return new Point (point[0], point[1]);
263 public Dimension getMinimumSize ()
265 return minimumSize ();
268 public Dimension getPreferredSize ()
270 return preferredSize ();
273 public Toolkit getToolkit ()
275 return Toolkit.getDefaultToolkit();
278 public void handleEvent (AWTEvent event)
280 int id = event.getID();
285 case PaintEvent.PAINT:
286 case PaintEvent.UPDATE:
290 Graphics g = getGraphics ();
292 // Some peers like GtkFileDialogPeer are repainted by Gtk itself
296 g.setClip (((PaintEvent) event).getUpdateRect());
298 if (id == PaintEvent.PAINT)
299 awtComponent.paint (g);
301 awtComponent.update (g);
305 catch (InternalError e)
307 System.err.println (e);
311 case KeyEvent.KEY_PRESSED:
312 ke = (KeyEvent) event;
313 gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
314 ke.getKeyCode (), ke.getKeyLocation ());
316 case KeyEvent.KEY_RELEASED:
317 ke = (KeyEvent) event;
318 gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
319 ke.getKeyCode (), ke.getKeyLocation ());
324 public boolean isFocusTraversable ()
329 public Dimension minimumSize ()
331 int dim[] = new int[2];
333 gtkWidgetGetPreferredDimensions (dim);
335 return new Dimension (dim[0], dim[1]);
338 public void paint (Graphics g)
342 public Dimension preferredSize ()
344 int dim[] = new int[2];
346 gtkWidgetGetPreferredDimensions (dim);
348 return new Dimension (dim[0], dim[1]);
351 public boolean prepareImage (Image image, int width, int height,
352 ImageObserver observer)
354 GtkImage i = (GtkImage) image;
356 if (i.isLoaded ()) return true;
358 class PrepareImage extends Thread
361 ImageObserver observer;
363 PrepareImage (GtkImage image, ImageObserver observer)
366 image.setObserver (observer);
371 image.source.startProduction (image);
375 new PrepareImage (i, observer).start ();
379 public void print (Graphics g)
381 throw new RuntimeException ();
384 public void repaint (long tm, int x, int y, int width, int height)
386 if (x == 0 && y == 0 && width == 0 && height == 0)
389 q.postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE,
390 new Rectangle (x, y, width, height)));
393 public void requestFocus ()
395 gtkWidgetRequestFocus();
396 postFocusEvent(FocusEvent.FOCUS_GAINED, false);
399 public void reshape (int x, int y, int width, int height)
401 setBounds (x, y, width, height);
404 public void setBackground (Color c)
406 gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue());
409 native void setNativeBounds (int x, int y, int width, int height);
411 public void setBounds (int x, int y, int width, int height)
413 Component parent = awtComponent.getParent ();
415 // Heavyweight components that are children of one or more
416 // lightweight containers have to be handled specially. Because
417 // calls to GLightweightPeer.setBounds do nothing, GTK has no
418 // knowledge of the lightweight containers' positions. So we have
419 // to add the offsets manually when placing a heavyweight
420 // component within a lightweight container. The lightweight
421 // container may itself be in a lightweight container and so on,
422 // so we need to continue adding offsets until we reach a
423 // container whose position GTK knows -- that is, the first
425 boolean lightweightChild = false;
427 while (parent.isLightweight ())
429 lightweightChild = true;
431 i = ((Container) parent).getInsets ();
433 x += parent.getX () + i.left;
434 y += parent.getY () + i.top;
436 parent = parent.getParent ();
439 // We only need to convert from Java to GTK coordinates if we're
440 // placing a heavyweight component in a Window.
441 if (parent instanceof Window && !lightweightChild)
443 Insets insets = ((Window) parent).getInsets ();
444 GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer ();
445 int menuBarHeight = 0;
446 if (peer instanceof GtkFramePeer)
447 menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight ();
449 // Convert from Java coordinates to GTK coordinates.
450 setNativeBounds (x - insets.left, y - insets.top + menuBarHeight,
454 setNativeBounds (x, y, width, height);
459 setCursor (awtComponent.getCursor ());
462 public void setCursor (Cursor cursor)
464 gtkWidgetSetCursor (cursor.getType ());
467 public void setEnabled (boolean b)
469 gtkWidgetSetSensitive (b);
472 public void setFont (Font f)
474 // FIXME: This should really affect the widget tree below me.
475 // Currently this is only handled if the call is made directly on
476 // a text widget, which implements setFont() itself.
477 gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
480 public void setForeground (Color c)
482 gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue());
485 public Color getForeground ()
487 int rgb[] = gtkWidgetGetForeground ();
488 return new Color (rgb[0], rgb[1], rgb[2]);
491 public Color getBackground ()
493 int rgb[] = gtkWidgetGetBackground ();
494 return new Color (rgb[0], rgb[1], rgb[2]);
497 public void setVisible (boolean b)
505 public native void hide ();
506 public native void show ();
508 protected void postMouseEvent(int id, long when, int mods, int x, int y,
509 int clickCount, boolean popupTrigger)
511 q.postEvent(new MouseEvent(awtComponent, id, when, mods, x, y,
512 clickCount, popupTrigger));
515 protected void postExposeEvent (int x, int y, int width, int height)
518 q.postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
519 new Rectangle (x, y, width, height)));
522 protected void postKeyEvent (int id, long when, int mods,
523 int keyCode, char keyChar, int keyLocation)
525 KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
526 keyCode, keyChar, keyLocation);
528 // Also post a KEY_TYPED event if keyEvent is a key press that
529 // doesn't represent an action or modifier key.
530 if (keyEvent.getID () == KeyEvent.KEY_PRESSED
531 && (!keyEvent.isActionKey ()
532 && keyCode != KeyEvent.VK_SHIFT
533 && keyCode != KeyEvent.VK_CONTROL
534 && keyCode != KeyEvent.VK_ALT))
538 q.postEvent (keyEvent);
539 q.postEvent (new KeyEvent (awtComponent, KeyEvent.KEY_TYPED, when, mods,
540 KeyEvent.VK_UNDEFINED, keyChar, keyLocation));
544 q.postEvent (keyEvent);
547 protected void postFocusEvent (int id, boolean temporary)
549 q.postEvent (new FocusEvent (awtComponent, id, temporary));
552 protected void postItemEvent (Object item, int stateChange)
554 q.postEvent (new ItemEvent ((ItemSelectable)awtComponent,
555 ItemEvent.ITEM_STATE_CHANGED,
559 public GraphicsConfiguration getGraphicsConfiguration ()
561 // FIXME: just a stub for now.
565 public void setEventMask (long mask)
567 // FIXME: just a stub for now.
570 public boolean isFocusable ()
575 public boolean requestFocus (Component source, boolean b1,
581 public boolean isObscured ()
586 public boolean canDetermineObscurity ()
591 public void coalescePaintEvent (PaintEvent e)
596 public void updateCursorImmediately ()
601 public VolatileImage createVolatileImage (int width, int height)
606 public boolean handlesWheelScrolling ()
611 public void createBuffers (int x, BufferCapabilities capabilities)
612 throws java.awt.AWTException
618 public Image getBackBuffer ()
623 public void flip (BufferCapabilities.FlipContents contents)
628 public void destroyBuffers ()