Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / gnu / java / awt / peer / gtk / GtkComponentPeer.java
blob1a85de5fe49c079f1ff4ddb1b5f0efbc030efdb0
1 /* GtkComponentPeer.java -- Implements ComponentPeer with GTK
2 Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
40 package gnu.java.awt.peer.gtk;
42 import java.awt.AWTEvent;
43 import java.awt.AWTException;
44 import java.awt.BufferCapabilities;
45 import java.awt.Color;
46 import java.awt.Component;
47 import java.awt.Container;
48 import java.awt.Cursor;
49 import java.awt.Dimension;
50 import java.awt.EventQueue;
51 import java.awt.Font;
52 import java.awt.FontMetrics;
53 import java.awt.Graphics;
54 import java.awt.GraphicsConfiguration;
55 import java.awt.Image;
56 import java.awt.Insets;
57 import java.awt.ItemSelectable;
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.MouseWheelEvent;
67 import java.awt.event.PaintEvent;
68 import java.awt.event.TextEvent;
69 import java.awt.image.BufferedImage;
70 import java.awt.image.ColorModel;
71 import java.awt.image.ImageObserver;
72 import java.awt.image.ImageProducer;
73 import java.awt.image.VolatileImage;
74 import java.awt.peer.ComponentPeer;
75 import java.awt.peer.ContainerPeer;
76 import java.awt.peer.WindowPeer;
77 import java.util.Timer;
78 import java.util.TimerTask;
80 public class GtkComponentPeer extends GtkGenericPeer
81 implements ComponentPeer
83 VolatileImage backBuffer;
84 BufferCapabilities caps;
86 Component awtComponent;
88 Insets insets;
90 /* this isEnabled differs from Component.isEnabled, in that it
91 knows if a parent is disabled. In that case Component.isEnabled
92 may return true, but our isEnabled will always return false */
93 native boolean isEnabled ();
94 static native boolean modalHasGrab();
96 native int[] gtkWidgetGetForeground ();
97 native int[] gtkWidgetGetBackground ();
98 native void gtkWidgetGetDimensions (int[] dim);
99 native void gtkWidgetGetPreferredDimensions (int[] dim);
100 native void gtkWindowGetLocationOnScreen (int[] point);
101 native void gtkWidgetGetLocationOnScreen (int[] point);
102 native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y);
103 native void gtkWidgetSetCursorUnlocked (int type, GtkImage image,
104 int x, int y);
105 native void gtkWidgetSetBackground (int red, int green, int blue);
106 native void gtkWidgetSetForeground (int red, int green, int blue);
107 native void gtkWidgetSetSensitive (boolean sensitive);
108 native void gtkWidgetSetParent (ComponentPeer parent);
109 native void gtkWidgetRequestFocus ();
110 native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
111 int keyCode, int keyLocation);
113 native boolean isRealized ();
115 void realize ()
117 // Default implementation does nothing
120 native void setNativeEventMask ();
122 void create ()
124 throw new RuntimeException ();
127 native void connectSignals ();
129 protected GtkComponentPeer (Component awtComponent)
131 super (awtComponent);
132 this.awtComponent = awtComponent;
133 insets = new Insets (0, 0, 0, 0);
135 create ();
137 connectSignals ();
139 if (awtComponent.getForeground () != null)
140 setForeground (awtComponent.getForeground ());
141 if (awtComponent.getBackground () != null)
142 setBackground (awtComponent.getBackground ());
143 if (awtComponent.getFont() != null)
144 setFont(awtComponent.getFont());
146 Component parent = awtComponent.getParent ();
148 setParentAndBounds ();
150 setNativeEventMask ();
152 realize ();
154 if (awtComponent.isCursorSet())
155 setCursor ();
158 void setParentAndBounds ()
160 setParent ();
162 setComponentBounds ();
164 setVisibleAndEnabled ();
167 void setParent ()
169 ComponentPeer p;
170 Component component = awtComponent;
173 component = component.getParent ();
174 p = component.getPeer ();
176 while (p instanceof java.awt.peer.LightweightPeer);
178 if (p != null)
179 gtkWidgetSetParent (p);
183 * Set the bounds of this peer's AWT Component based on dimensions
184 * returned by the native windowing system. Most Components impose
185 * their dimensions on the peers which is what the default
186 * implementation does. However some peers, like GtkFileDialogPeer,
187 * need to pass their size back to the AWT Component.
189 void setComponentBounds ()
191 Rectangle bounds = awtComponent.getBounds ();
192 setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
195 void setVisibleAndEnabled ()
197 setVisible (awtComponent.isVisible ());
198 setEnabled (awtComponent.isEnabled ());
201 public int checkImage (Image image, int width, int height,
202 ImageObserver observer)
204 return getToolkit().checkImage(image, width, height, observer);
207 public Image createImage (ImageProducer producer)
209 return new GtkImage (producer);
212 public Image createImage (int width, int height)
214 Image image;
215 if (GtkToolkit.useGraphics2D ())
216 image = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
217 else
218 image = new GtkImage (width, height);
220 Graphics g = image.getGraphics();
221 g.setColor(getBackground());
222 g.fillRect(0, 0, width, height);
223 return image;
226 public void disable ()
228 setEnabled (false);
231 public void enable ()
233 setEnabled (true);
236 public ColorModel getColorModel ()
238 return ColorModel.getRGBdefault ();
241 public FontMetrics getFontMetrics (Font font)
243 return getToolkit().getFontMetrics(font);
246 // getGraphics may be overridden by derived classes but it should
247 // never return null.
248 public Graphics getGraphics ()
250 if (GtkToolkit.useGraphics2D ())
251 return new GdkGraphics2D (this);
252 else
253 return new GdkGraphics (this);
256 public Point getLocationOnScreen ()
258 int point[] = new int[2];
259 if( this instanceof WindowPeer )
260 gtkWindowGetLocationOnScreen (point);
261 else
262 gtkWidgetGetLocationOnScreen (point);
263 return new Point (point[0], point[1]);
266 public Dimension getMinimumSize ()
268 return minimumSize ();
271 public Dimension getPreferredSize ()
273 return preferredSize ();
276 public Toolkit getToolkit ()
278 return Toolkit.getDefaultToolkit();
281 public void handleEvent (AWTEvent event)
283 int id = event.getID();
284 KeyEvent ke = null;
286 switch (id)
288 case PaintEvent.PAINT:
289 paintComponent((PaintEvent) event);
290 break;
291 case PaintEvent.UPDATE:
292 updateComponent((PaintEvent) event);
293 break;
294 case KeyEvent.KEY_PRESSED:
295 ke = (KeyEvent) event;
296 gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
297 ke.getKeyCode (), ke.getKeyLocation ());
298 break;
299 case KeyEvent.KEY_RELEASED:
300 ke = (KeyEvent) event;
301 gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
302 ke.getKeyCode (), ke.getKeyLocation ());
303 break;
307 // This method and its overrides are the only methods in the peers
308 // that should call awtComponent.paint.
309 protected void paintComponent (PaintEvent event)
311 // Do not call Component.paint if the component is not showing or
312 // if its bounds form a degenerate rectangle.
313 if (!awtComponent.isShowing()
314 || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
315 return;
317 // Creating and disposing a GdkGraphics every time paint is called
318 // seems expensive. However, the graphics state does not carry
319 // over between calls to paint, and resetting the graphics object
320 // may even be more costly than simply creating a new one.
321 Graphics g = getGraphics();
323 g.setClip(event.getUpdateRect());
325 awtComponent.paint(g);
327 g.dispose();
330 // This method and its overrides are the only methods in the peers
331 // that should call awtComponent.update.
332 protected void updateComponent (PaintEvent event)
334 // Do not call Component.update if the component is not showing or
335 // if its bounds form a degenerate rectangle.
336 if (!awtComponent.isShowing()
337 || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
338 return;
340 Graphics g = getGraphics();
342 g.setClip(event.getUpdateRect());
344 awtComponent.update(g);
346 g.dispose();
349 public boolean isFocusTraversable ()
351 return true;
354 public Dimension minimumSize ()
356 int dim[] = new int[2];
358 gtkWidgetGetPreferredDimensions (dim);
360 return new Dimension (dim[0], dim[1]);
363 public void paint (Graphics g)
367 public Dimension preferredSize ()
369 int dim[] = new int[2];
371 gtkWidgetGetPreferredDimensions (dim);
373 return new Dimension (dim[0], dim[1]);
376 public boolean prepareImage (Image image, int width, int height,
377 ImageObserver observer)
379 return getToolkit().prepareImage(image, width, height, observer);
382 public void print (Graphics g)
384 throw new RuntimeException ();
387 public void repaint (long tm, int x, int y, int width, int height)
389 if (width < 1 || height < 1)
390 return;
392 if (tm <= 0)
393 q().postEvent(new PaintEvent(awtComponent, PaintEvent.UPDATE,
394 new Rectangle(x, y, width, height)));
395 else
396 RepaintTimerTask.schedule(tm, x, y, width, height, awtComponent);
400 * Used for scheduling delayed paint updates on the event queue.
402 private static class RepaintTimerTask extends TimerTask
404 private static final Timer repaintTimer = new Timer(true);
406 private int x, y, width, height;
407 private Component awtComponent;
409 RepaintTimerTask(Component c, int x, int y, int width, int height)
411 this.x = x;
412 this.y = y;
413 this.width = width;
414 this.height = height;
415 this.awtComponent = c;
418 public void run()
420 q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE,
421 new Rectangle (x, y, width, height)));
424 static void schedule(long tm, int x, int y, int width, int height,
425 Component c)
427 repaintTimer.schedule(new RepaintTimerTask(c, x, y, width, height), tm);
431 public void requestFocus ()
433 gtkWidgetRequestFocus();
434 postFocusEvent(FocusEvent.FOCUS_GAINED, false);
437 public void reshape (int x, int y, int width, int height)
439 setBounds (x, y, width, height);
442 public void setBackground (Color c)
444 gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue());
447 native void setNativeBounds (int x, int y, int width, int height);
449 public void setBounds (int x, int y, int width, int height)
451 int new_x = x;
452 int new_y = y;
454 Component parent = awtComponent.getParent ();
456 // Heavyweight components that are children of one or more
457 // lightweight containers have to be handled specially. Because
458 // calls to GLightweightPeer.setBounds do nothing, GTK has no
459 // knowledge of the lightweight containers' positions. So we have
460 // to add the offsets manually when placing a heavyweight
461 // component within a lightweight container. The lightweight
462 // container may itself be in a lightweight container and so on,
463 // so we need to continue adding offsets until we reach a
464 // container whose position GTK knows -- that is, the first
465 // non-lightweight.
466 Insets i;
467 while (parent.isLightweight())
469 i = ((Container) parent).getInsets();
471 new_x += parent.getX() + i.left;
472 new_y += parent.getY() + i.top;
474 parent = parent.getParent();
476 // We only need to convert from Java to GTK coordinates if we're
477 // placing a heavyweight component in a Window.
478 if (parent instanceof Window)
480 GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer ();
481 // important: we want the window peer's insets here, not the
482 // window's, since user sub-classes of Window can override
483 // getInset and we only want to correct for the frame borders,
484 // not for any user-defined inset values
485 Insets insets = peer.getInsets ();
487 int menuBarHeight = 0;
488 if (peer instanceof GtkFramePeer)
489 menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight ();
491 new_x -= insets.left;
492 new_y -= insets.top;
493 new_y += menuBarHeight;
496 setNativeBounds (new_x, new_y, width, height);
498 // If the height or width were (or are now) smaller than zero
499 // then we want to adjust the visibility.
500 setVisible(awtComponent.isVisible());
503 void setCursor ()
505 setCursor (awtComponent.getCursor ());
508 public void setCursor (Cursor cursor)
510 int x, y;
511 GtkImage image;
512 int type = cursor.getType();
513 if (cursor instanceof GtkCursor)
515 GtkCursor gtkCursor = (GtkCursor) cursor;
516 image = gtkCursor.getGtkImage();
517 Point hotspot = gtkCursor.getHotspot();
518 x = hotspot.x;
519 y = hotspot.y;
521 else
523 image = null;
524 x = 0;
525 y = 0;
528 if (Thread.currentThread() == GtkToolkit.mainThread)
529 gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
530 else
531 gtkWidgetSetCursor(cursor.getType(), image, x, y);
534 public void setEnabled (boolean b)
536 gtkWidgetSetSensitive (b);
539 public void setFont (Font f)
541 // FIXME: This should really affect the widget tree below me.
542 // Currently this is only handled if the call is made directly on
543 // a text widget, which implements setFont() itself.
544 gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
547 public void setForeground (Color c)
549 gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue());
552 public Color getForeground ()
554 int rgb[] = gtkWidgetGetForeground ();
555 return new Color (rgb[0], rgb[1], rgb[2]);
558 public Color getBackground ()
560 int rgb[] = gtkWidgetGetBackground ();
561 return new Color (rgb[0], rgb[1], rgb[2]);
564 public native void setVisibleNative (boolean b);
565 public native void setVisibleNativeUnlocked (boolean b);
567 public void setVisible (boolean b)
569 // Only really set visible when component is bigger than zero pixels.
570 if (b && ! (awtComponent instanceof Window))
572 Rectangle bounds = awtComponent.getBounds();
573 b = (bounds.width > 0) && (bounds.height > 0);
576 if (Thread.currentThread() == GtkToolkit.mainThread)
577 setVisibleNativeUnlocked (b);
578 else
579 setVisibleNative (b);
582 public void hide ()
584 setVisible (false);
587 public void show ()
589 setVisible (true);
592 protected void postMouseEvent(int id, long when, int mods, int x, int y,
593 int clickCount, boolean popupTrigger)
595 q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y,
596 clickCount, popupTrigger));
600 * Callback for component_scroll_cb.
602 protected void postMouseWheelEvent(int id, long when, int mods,
603 int x, int y, int clickCount,
604 boolean popupTrigger,
605 int type, int amount, int rotation)
607 q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods,
608 x, y, clickCount, popupTrigger,
609 type, amount, rotation));
612 protected void postExposeEvent (int x, int y, int width, int height)
614 q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
615 new Rectangle (x, y, width, height)));
618 protected void postKeyEvent (int id, long when, int mods,
619 int keyCode, char keyChar, int keyLocation)
621 KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
622 keyCode, keyChar, keyLocation);
624 EventQueue q = q();
626 // Also post a KEY_TYPED event if keyEvent is a key press that
627 // doesn't represent an action or modifier key.
628 if (keyEvent.getID () == KeyEvent.KEY_PRESSED
629 && (!keyEvent.isActionKey ()
630 && keyCode != KeyEvent.VK_SHIFT
631 && keyCode != KeyEvent.VK_CONTROL
632 && keyCode != KeyEvent.VK_ALT))
634 synchronized(q)
636 q.postEvent(keyEvent);
637 keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when,
638 mods, KeyEvent.VK_UNDEFINED, keyChar,
639 keyLocation);
640 q.postEvent(keyEvent);
643 else
644 q.postEvent(keyEvent);
647 protected void postFocusEvent (int id, boolean temporary)
649 q().postEvent (new FocusEvent (awtComponent, id, temporary));
652 protected void postItemEvent (Object item, int stateChange)
654 q().postEvent (new ItemEvent ((ItemSelectable)awtComponent,
655 ItemEvent.ITEM_STATE_CHANGED,
656 item, stateChange));
659 protected void postTextEvent ()
661 q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED));
664 public GraphicsConfiguration getGraphicsConfiguration ()
666 // FIXME: just a stub for now.
667 return null;
670 public void setEventMask (long mask)
672 // FIXME: just a stub for now.
675 public boolean isFocusable ()
677 return false;
680 public boolean requestFocus (Component source, boolean b1,
681 boolean b2, long x)
683 return false;
686 public boolean isObscured ()
688 return false;
691 public boolean canDetermineObscurity ()
693 return false;
696 public void coalescePaintEvent (PaintEvent e)
701 public void updateCursorImmediately ()
703 if (awtComponent.getCursor() != null)
704 setCursor(awtComponent.getCursor());
707 public boolean handlesWheelScrolling ()
709 return false;
712 // Convenience method to create a new volatile image on the screen
713 // on which this component is displayed.
714 public VolatileImage createVolatileImage (int width, int height)
716 return new GtkVolatileImage (width, height);
719 // Creates buffers used in a buffering strategy.
720 public void createBuffers (int numBuffers, BufferCapabilities caps)
721 throws AWTException
723 // numBuffers == 2 implies double-buffering, meaning one back
724 // buffer and one front buffer.
725 if (numBuffers == 2)
726 backBuffer = new GtkVolatileImage(awtComponent.getWidth(),
727 awtComponent.getHeight(),
728 caps.getBackBufferCapabilities());
729 else
730 throw new AWTException("GtkComponentPeer.createBuffers:"
731 + " multi-buffering not supported");
732 this.caps = caps;
735 // Return the back buffer.
736 public Image getBackBuffer ()
738 return backBuffer;
741 // FIXME: flip should be implemented as a fast native operation
742 public void flip (BufferCapabilities.FlipContents contents)
744 getGraphics().drawImage(backBuffer,
745 awtComponent.getWidth(),
746 awtComponent.getHeight(),
747 null);
749 // create new back buffer and clear it to the background color.
750 if (contents == BufferCapabilities.FlipContents.BACKGROUND)
752 backBuffer = createVolatileImage(awtComponent.getWidth(),
753 awtComponent.getHeight());
754 backBuffer.getGraphics().clearRect(0, 0,
755 awtComponent.getWidth(),
756 awtComponent.getHeight());
758 // FIXME: support BufferCapabilities.FlipContents.PRIOR
761 // Release the resources allocated to back buffers.
762 public void destroyBuffers ()
764 backBuffer.flush();
767 public String toString ()
769 return "peer of " + awtComponent.toString();
771 public Rectangle getBounds()
773 // FIXME: implement
774 return null;
776 public void reparent(ContainerPeer parent)
778 // FIXME: implement
781 public void setBounds(int x, int y, int width, int height, int z)
783 // FIXME: implement
784 setBounds (x, y, width, height);
787 public boolean isReparentSupported()
789 // FIXME: implement
791 return false;
793 public void layout()
795 // FIXME: implement