/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.gtk;

import java.util.Vector;

import org.gnu.atk.AtkObject;
import org.gnu.gdk.Bitmap;
import org.gnu.gdk.Color;
import org.gnu.gdk.Colormap;
import org.gnu.gdk.Display;
import org.gnu.gdk.DragAction;
import org.gnu.gdk.DragContext;
import org.gnu.gdk.EventButton;
import org.gnu.gdk.EventCrossing;
import org.gnu.gdk.EventKey;
import org.gnu.gdk.EventScroll;
import org.gnu.gdk.ModifierType;
import org.gnu.gdk.Pixbuf;
import org.gnu.gdk.Pixmap;
import org.gnu.gdk.Point;
import org.gnu.gdk.Rectangle;
import org.gnu.gdk.Screen;
import org.gnu.gdk.Window;
import org.gnu.glib.EventMap;
import org.gnu.glib.GObject;
import org.gnu.glib.Type;
import org.gnu.gtk.event.DragDestinationListener;
import org.gnu.gtk.event.DragSourceListener;
import org.gnu.gtk.event.FocusEvent;
import org.gnu.gtk.event.FocusListener;
import org.gnu.gtk.event.GtkEventType;
import org.gnu.gtk.event.KeyEvent;
import org.gnu.gtk.event.KeyListener;
import org.gnu.gtk.event.LifeCycleEvent;
import org.gnu.gtk.event.LifeCycleListener;
import org.gnu.gtk.event.MouseEvent;
import org.gnu.gtk.event.MouseListener;
import org.gnu.pango.Context;
import org.gnu.pango.FontDescription;

/**
 * GtkWidget is the base class of all widgets.
 * 
 */

public class Widget extends GtkObject {

	/**
	 * The list of objects interested in focus events.
	 */
	private Vector focusListeners = null;

	/**
	 * Ths list of objects interested in key events.
	 */
	private Vector keyListeners = null;

	/**
	 * The list of objects interested in life cycle events.
	 */
	private Vector lifeCycleListeners = null;

	/**
	 * The list of objects interested in mouse events.
	 */
	private Vector mouseListeners = null;

	/**
	 * The list of objects interested in drag destination events.
	 */
	private Vector dragDestinationListeners = null;

	/**
	 * The list of objects interested in drag source events.
	 */
	private Vector dragSourceListeners = null;

	/**
	 * Create a new Widget with a handle to a native resource
	 * returned from a call to the native libraries.
	 * 
	 * @param handle The handle that represents a pointer to a native resource.
	 */
	public Widget(int handle) {
		super(handle);
		initializeEventHandlers();
	}

	/**
	 * Cause this Widget to be visible.
	 */
	public void show() {
		Widget.gtk_widget_show(getHandle());
	}

	/**
	 * Cause this Widget and all of its' children to be visible.
	 */
	public void showAll() {
		Widget.gtk_widget_show_all(getHandle());
	}

	/**
	 * Cause this Widget to not be visible.
	 */
	public void hide() {
		Widget.gtk_widget_hide(getHandle());
	}

	/**
	 * Cause this Widget and all of its' children to not be visible.
	 */
	public void hideAll() {
		Widget.gtk_widget_hide_all(getHandle());
	}

	/**
	 * Destroy this widget.  If this widget is inside a container the widget will be
	 * removed from the container.  All of this widget's children are also destroyed.
	 */
	public void destroy() {
		Widget.gtk_widget_destroy(getHandle());
	}

	/**
	 * Creates a native window resource associated with this widget.  Normally a widget
	 * realization happens implicitly; if you show a widget and all of its' parent containers
	 * then the widget will be realized automatically.
	 */
	public void realize() {
		Widget.gtk_widget_realize(getHandle());
	}

	/**
	 *  Causes the entire widget to be redrawn.
	 */
	public void draw() {
		Widget.gtk_widget_queue_draw(getHandle());
	}

	/**
	 * Causes the specified area to be redrawn.
	 * 
	 * @param area The area to be redrawn.
	 */
	public void drawArea(Rectangle area) {
		drawArea(area.getX(), area.getY(), area.getWidth(), area.getHeight());
	}

	/**
	 * Causes the specified area to be redrawn
	 * 
	 * @param x The x coordinate for the area to be redrawn.
	 * @param y The y coordinate for the area to be redrawn.
	 * @param width The width of the area to be redrawn.
	 * @param height The height of the area to be redrawn.
	 */
	public void drawArea(int x, int y, int width, int height) {
		Widget.gtk_widget_queue_draw_area(getHandle(), x, y, width, height);
	}

	/**
	 * For widgets that can be activeated (buttons, menu items, etc.) this
	 * method activiates them.  Activation is what happens when you press
	 * Enter on a widget during keyboard navigation.
	 *
	 * @return False if this widget is not activatable.
	 */
	public boolean activate() {
		return Widget.gtk_widget_activate(getHandle());
	}

	/**
	 * Moves a widget from one Container to another.
	 * 
	 * @param newParent The widget that will be the new parent.
	 */
	public void reparent(Widget newParent) {
		Widget.gtk_widget_reparent(getHandle(), newParent.getHandle());
	}

	/**
	 * Returns the parent container for this widget
	 * 
	 * @return The parent container for this widget.
	 */
	public Widget getParent() {
		int hndl = gtk_widget_get_parent(getHandle());
		if (0 == hndl)
			return null;
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}

	/**
	 * Returns the widget's parent window.
	 * 
	 * @return Returns the widget's parent window.
	 */
	public Window getParentWindow() {
		int hndl = gtk_widget_get_parent_window(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Window)obj;
		return new Window(hndl);
	}

	/**
	 * Computes the intersection of the widget's area and <code>area</code>.
	 * 
	 * @param area The area to use to compute the intersection.
	 * @return The intersection.  If the areas don't intersect this method returns null.
	 */
	public Rectangle intersect(Rectangle area) {
		int[] rect = new int[1];
		boolean val = Widget.gtk_widget_intersect(getHandle(), area.getHandle(), rect);
		if (false == val)
			return null;
		return new Rectangle(rect[0]);
	}

	/**
	 * Determines if the widget has focus within its' TOPLEVEL.
	 * 
	 * @return true if the widget has focus.
	 */
	public boolean hasFocus() {
		return Widget.gtk_widget_is_focus(getHandle());
	}

	/**
	 * Causes the widget to gain focus within its' TOPLEVEL.
	 */
	public void grabFocus() {
		Widget.gtk_widget_grab_focus(getHandle());
	}

	/**
	 * Causes the widget to become the default widget.  The default widget
	 * is activated when the user presses Enter in the window.  Default widgets
	 * must be activatable.
	 */
	public void grabDefault() {
		// make sure CAN_DEFAULT has been set.
		//Moving flag setting to the c layer.
		//GtkObject.setFlags(handle, WidgetFlags.CAN_DEFAULT.getValue());
		Widget.gtk_widget_grab_default(getHandle());
	}

	/**
	 * Sets the name for this widget.  Widgets can be named which allows you
	 * to refer to them from a gtkrc file.  You can apply a style to widgets with a
	 * particular name in the gtkrc file.
	 * 
	 * @param name The name for the widget.
	 */
	public void setName(String name) {
		Widget.gtk_widget_set_name(getHandle(), name);
	}

	/**
	 * Returns the name for the widget.
	 * 
	 * @return The name for the widget.
	 */
	public String getName() {
		return Widget.gtk_widget_get_name(getHandle());
	}

	/**
	 * Sets the sensitivity of the widget.
	 * 
	 * @param sensitive Indicates if the widget should be sensitive.
	 */
	public void setSensitive(boolean sensitive) {
		Widget.gtk_widget_set_sensitive(getHandle(), sensitive);
	}

	/**
	 * Gets the sensitivity of the widget.
	 *
	 * @return true if the widget is sensitive, false otherwise.
	 */
    public boolean getSensitive() {
		return gtk_widget_get_sensitive(getHandle());
	}

	/**
	 * Returns the topmost widget in the container hierarchy.
	 * 
	 * @return The topmost widget.
	 */
	public Widget getToplevel() {
		int hndl = gtk_widget_get_toplevel(getHandle());
		if (0 == hndl)
			return null;
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Widget)obj;
		return new Widget(hndl);
	}

	/**
	 * Returns the Colormap that will be used to render this widget.
	 * 
	 * @return The colormap used for this widget.
	 */
	public Colormap getColormap() {
		int colorHandle = Widget.gtk_widget_get_colormap(getHandle());
		GObject obj = retrieveGObject(colorHandle);
		if (null != obj)
			return (Colormap)obj;
		return new Colormap(colorHandle);
	}

	/**
	 * Set the Colormap that will be used to render this widget.
	 * 
	 * @param colormap The colormap to be used.
	 */
	public void setColormap(Colormap colormap) {
		Widget.gtk_widget_set_colormap(getHandle(), colormap.getHandle());
	}

	/**
	 * Returns the location of the mouse pointer in widget coordinates.  This
	 * method will return null if the mouse is not currently in the widget.
	 * 
	 * @return The location of the mouse or null
	 */
	public Point getPointer() {
		int[] x = new int[1];
		int[] y = new int[1];
		Widget.gtk_widget_get_pointer(getHandle(), x, y);
		if (null == x)
			return null;
		if (null == y)
			return null;
		return new Point(x[0], y[0]);
	}

	/**
	 * Determines whether this widget is somewhere inside of ancestor.
	 * 
	 * @param ancestor The possible parent widget
	 */
	public boolean isAncestor(Widget ancestor) {
		return Widget.gtk_widget_is_ancestor(getHandle(), ancestor.getHandle());
	}

	/**
	 * Pushes a Colormap onto the stack of colormaps.  The topmost Colormap
	 * on the stack will be used to create all Widgets.
	 * 
	 * @param colormap The Colormap to push onto the stack.
	 */
	public void pushColormap(Colormap colormap) {
		Widget.gtk_widget_push_colormap(colormap.getHandle());
	}

	/**
	 * Pops the top colormap off of the stack of colormaps.  The topmost Colormap
	 * on the stack will be used to create all Widgets.
	 */
	public void popColormap() {
		Widget.gtk_widget_pop_colormap();
	}

	/**
	 * Sets the shape of this widgets OS window.  This allows for transparent windows.
	 * 
	 * @param shapeMask Shape to be added or null to remove an existing shape.
	 * @param x X Position of the shape mask with respect to the window.
	 * @param y Y Position of the shape mask with respect to the window.
	 */
	public void shapeCombineMask(Bitmap shapeMask, int x, int y) {
		Widget.gtk_widget_shape_combine_mask(getHandle(), shapeMask.getHandle(), x, y);
	}

	/**
	 * Sets the foreground color for a widget in a particular state.  All other
	 * style values are left untouched.
	 * 
	 * @param state The widget state to modify.
	 * @param color The color to set the foreground.
	 */
	public void setForegroundColor(StateType state, Color color) {
		Widget.gtk_widget_modify_fg(getHandle(), state.getValue(), color.getHandle());
	}

	/**
	 * Sets the background color for a widget in a particular state.  All other
	 * style values are left untouched.
	 * 
	 * @param state The widget state to modify.
	 * @param color The color to set the background.
	 */
	public void setBackgroundColor(StateType state, Color color) {
		Widget.gtk_widget_modify_bg(getHandle(), state.getValue(), color.getHandle());
	}

	/**
	 * Sets the text color for a widget in a particilar state.  All other style values
	 * are left untouched.  The text color is the foreground color along with the
	 * base color for widgets such as Entry, TextView, etc.
	 * 
	 * @param state The widget state to modify.
	 * @param color The color to set the text.
	 */
	public void setTextColor(StateType state, Color color) {
		Widget.gtk_widget_modify_text(getHandle(), state.getValue(), color.getHandle());
	}

	/**
	 * Sets the base color used for a widget in a particular state.  The base color
	 * is the backgound color used along with the text color for widgets such as
	 * Entry, TextView, etc.
	 * 
	 * @param state The widget state to modify.
	 * @param color The color to set.
	 */
	public void setBaseColor(StateType state, Color color) {
		Widget.gtk_widget_modify_base(getHandle(), state.getValue(), color.getHandle());
	}

	/**
	 * Sets the font to use for the widget.
	 * 
	 * @param fontDesc The font description to use.
	 */
	public void setFont(FontDescription fontDesc) {
		Widget.gtk_widget_modify_font(getHandle(), fontDesc.getHandle());
	}

	/**
	 * Modifies style values on the Widget.  Modifications made using this
	 * technique take precedence over style values set via an RC file.
	 * 
	 * @param style The style to apply to the Widget
	 */
	public void modifyStyle(RcStyle style) {
		Widget.gtk_widget_modify_style(getHandle(), style.getHandle());
	}

	/**
	 * Retruns the Widget's {@link RcStyle}.
	 * 
	 * @return The current RcStyle for the Widget.
	 */
	public RcStyle getModifierStyle() {
		int hndl = Widget.gtk_widget_get_modifier_style(getHandle());
		return new RcStyle(hndl);
	}

	/**
	 * Returns the Widgets {@link Style}.
	 * 
	 * @return The current Style for the Widget.
	 */
	public Style getStyle() {
		int hndl = Widget.gtk_widget_get_style(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Style)obj;
		return new Style(hndl);
	}

	/**
	 * Creates a new Context with the appropriate Colormap, FontDescription,
	 * and base direction for drawing text for this widget.
	 * 
	 * @return A context that can be used for drawig text.
	 */
	public Context createContext() {
		int pc = Widget.gtk_widget_create_pango_context(getHandle());
		return new Context(pc);
	}

	/**
	 * Gets a Context with the appropriate Colormap, FontDescription and base
	 * direction for this widget.  Unlike the createContext method, this context
	 * is owned by the widget and can be as long as the widget exists.  This
	 * context will be updated to match any changes to the widget's attributes.
	 *
	 * @return A context that can be used for drawing text.
	 */
	public Context getContext() {
		int pc = Widget.gtk_widget_get_pango_context(getHandle());
		GObject obj = retrieveGObject(pc);
		if (null != obj)
			return (Context)obj;
		return new Context(pc);
	}

	/**
	 * Creates a new Layout with the appropriate Colormap, FontDescription and
	 * base direction for drawing text for this widget.
	 *
	 * @param text The text used for the layout.
	 * @return The layout that can be used for drawing text.
	 */
	public org.gnu.pango.Layout createLayout(String text) {
		int layout = Widget.gtk_widget_create_pango_layout(getHandle(), text);
		return new org.gnu.pango.Layout(layout);
	}

	/**
	 * Enables/Disables double buffering for this widget.  Widgets are double buffered
	 * by default.
	 * 
	 * @param doubleBuffered Set if the widget should be double buffered.
	 */
	public void setDoubleBuffered(boolean doubleBuffered) {
		Widget.gtk_widget_set_double_buffered(getHandle(), doubleBuffered);
	}

	/**
	 * Returns the accessible object associated with this widget.
	 * 
	 * @returns The AtkObject.
	 */
	public AtkObject getAccessible() {
		int ao = Widget.gtk_widget_get_accessible(getHandle());
		GObject obj = retrieveGObject(ao);
		if (null != obj)
			return (AtkObject)obj;
		return new AtkObject(ao);
	}

	public boolean canActivateAccel(int signalId) {
		return gtk_widget_can_activate_accel(getHandle(), signalId);
	}

	public Screen getScreen() {
		int hndl = gtk_widget_get_screen(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Screen)obj;
		return new Screen(hndl);
	}

	public boolean hasScreen() {
		return gtk_widget_has_screen(getHandle());
	}

	public Display getDisplay() {
		int hndl = gtk_widget_get_display(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Display)obj;
		return new Display(hndl);
	}

	public Window getRootWindow() {
		int hndl = gtk_widget_get_root_window(getHandle());
		GObject obj = retrieveGObject(hndl);
		if (null != obj)
			return (Window)obj;
		return new Window(hndl);
	}

	/**
	 * Sets the minimum size of a widget.  You can use this method to force a widget
	 * to be either larger or smaller that it normally be.  
	 * <p>
	 * In most cases <code>Window.setDefaultSize()</code> is a better choice for toplevel
	 * windows than this method.  Setting the default size will still allow users to shrink
	 * the window.  Setting the minimum size will force them to leave the window at
	 * least as large as the request.  
	 * <p>
	 * Note the inherent danger of setting any fixed size - themes, translations into
	 * other languages, different fonts, and user action can change the appropriate
	 * size for a given widget.  So, it's basically impossible to hardcode a size that 
	 * will always be correct.
	 * <p>
	 * If the minimum size in a given direction is -1 then the "natural" size for the
	 * widget will be used instead.
	 * 
	 * @param width The minimum width size to use.
	 * @param height The minimum height size to use.
	 */
	public void setMinimumSize(int width, int height) {
		Widget.gtk_widget_set_size_request(getHandle(), width, height);
	}

	/**
	 * Initialize this widget to receive its' own events so it can
	 * propogate them to the listeners.
	 */
	protected void initializeEventHandlers() {
		if (!eventsInitialized) {
			evtMap.initialize(this);
			eventsInitialized = true;
		}
	}

	public Class getEventListenerClass(String signal) {
		Class rv = evtMap.getEventListenerClass(signal);
		if (rv == null)
			rv = super.getEventListenerClass( signal );
		return rv;
	}

	public GtkEventType getEventType(String signal) {
		GtkEventType et = evtMap.getEventType(signal);
		if (et == null) et = super.getEventType( signal );
		return et;
	}

	private static EventMap evtMap = new EventMap();
	static {
		addEvents(evtMap);
	}

	/**
	* Implementation method to build an EventMap for this widget class.
	* Not useful (or supported) for application use.
	*/
	private static void addEvents(EventMap anEvtMap) {
		anEvtMap.addEvent("hide", "handleHide", LifeCycleEvent.Type.HIDE, LifeCycleListener.class);
		anEvtMap.addEvent("show", "handleShow", LifeCycleEvent.Type.SHOW, LifeCycleListener.class);
		anEvtMap.addEvent("realize", "handleRealize", LifeCycleEvent.Type.REALIZE, LifeCycleListener.class);
		anEvtMap.addEvent("unrealize", "handleUnrealize", LifeCycleEvent.Type.UNREALIZE, LifeCycleListener.class);
		anEvtMap.addEvent("destroy_event", "handleDestroy", LifeCycleEvent.Type.DESTROY, LifeCycleListener.class);
		anEvtMap.addEvent("delete_event", "handleDelete", LifeCycleEvent.Type.DELETE, LifeCycleListener.class);
		anEvtMap.addEvent("focus_in_event", "handleFocusIn", FocusEvent.Type.FOCUS_IN, FocusListener.class);
		anEvtMap.addEvent("focus_out_event", "handleFocusOut", FocusEvent.Type.FOCUS_OUT, FocusListener.class);
		anEvtMap.addEvent("key_press_event", "handleKeyPressed", KeyEvent.Type.KEY_PRESSED, KeyListener.class);
		anEvtMap.addEvent("key_release_event", "handleKeyReleased", KeyEvent.Type.KEY_RELEASED, KeyListener.class);
		anEvtMap.addEvent("button_press_event", "handleButtonPressed", MouseEvent.Type.BUTTON_PRESS, MouseListener.class);
		anEvtMap.addEvent("button_release_event", "handleButtonReleased", MouseEvent.Type.BUTTON_RELEASE, MouseListener.class);
		anEvtMap.addEvent("scroll_event", "handleScroll", MouseEvent.Type.WHEEL_SCROLL, MouseListener.class);
		anEvtMap.addEvent("enter_notify_event", "handleMouseEnter", MouseEvent.Type.ENTER, MouseListener.class);
		anEvtMap.addEvent("leave_notify_event", "handleMouseLeave", MouseEvent.Type.LEAVE, MouseListener.class);
		anEvtMap.addEvent("drag_data_received", "handleDragDestination", null, DragDestinationListener.class);
		anEvtMap.addEvent("drag_data_get", "handleDragDataGet", null, DragSourceListener.class);
	}

	/****************************************
	 * Life Cycle event handling.
	 ****************************************/
	/**
	 * Register an object to receive life cycle event notification.
	 * 
	 * @param listener The object that has implemented the 
	 * LifeCycleListener interface that is to receive the life cycle events.
	 */
	public void addListener(LifeCycleListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(lifeCycleListeners, listener);
		if (i == -1) {
			if (null == lifeCycleListeners)
				lifeCycleListeners = new Vector();
			lifeCycleListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving life cycle event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * life cycle events.
	 */
	public void removeListener(LifeCycleListener listener) {
		int i = findListener(lifeCycleListeners, listener);
		if (i > -1)
			lifeCycleListeners.remove(i);
		if (0 == lifeCycleListeners.size())
			lifeCycleListeners = null;
	}

	protected void fireLifeCycleEvent(LifeCycleEvent event) {
		if (null == lifeCycleListeners)
			return;
		int size = lifeCycleListeners.size();
		int i = 0;
		while (i < size) {
			LifeCycleListener lc = (LifeCycleListener)lifeCycleListeners.elementAt(i);
			lc.lifeCycleEvent(event);
			i++;
		}
	}

	protected boolean fireBooleanLifeCycleEvent(LifeCycleEvent event, boolean defaultValue) {
		boolean returnValue = defaultValue;
		if (null == lifeCycleListeners)
			return defaultValue;
		int size = lifeCycleListeners.size();
		int i = 0;
		while (i < size) {
			LifeCycleListener lc = (LifeCycleListener)lifeCycleListeners.elementAt(i);
			if (lc.lifeCycleQuery(event) != defaultValue)
				returnValue = !defaultValue;
			i++;
		}
		return returnValue;
	}

	protected void handleShow() {
		fireLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.SHOW));
	}

	protected void handleHide() {
		fireLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.HIDE));
	}

	protected void handleRealize() {
		fireLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.REALIZE));
	}

	private void handleUnrealize() {
		fireLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.UNREALIZE));
	}

	private boolean handleDestroy(int event) {
		return fireBooleanLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.DESTROY), true );
	}

	protected boolean handleDelete(int event) {
		return fireBooleanLifeCycleEvent(new LifeCycleEvent(this, LifeCycleEvent.Type.DELETE), false);
	}

	/****************************************
	 * Focus event handling.
	 ****************************************/
	/**
	 * Register an object to receive focus event notification.
	 * 
	 * @param listener The object that has implemented the 
	 * FocusListener interface that is to receive the focus events.
	 */
	public void addListener(FocusListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(focusListeners, listener);
		if (i == -1) {
			if (null == focusListeners)
				focusListeners = new Vector();
			focusListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving focus event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * focus events.
	 */
	public void removeListener(FocusListener listener) {
		int i = findListener(focusListeners, listener);
		if (i > -1)
			focusListeners.remove(i);
		if (0 == focusListeners.size())
			focusListeners = null;
	}

	protected boolean fireFocusEvent(FocusEvent event) {
		if (null == focusListeners)
			return false;
		boolean retval = false;
		int size = focusListeners.size();
		int i = 0;
		while (i < size) {
			FocusListener fl = (FocusListener)focusListeners.elementAt(i);
			if (fl.focusEvent(event))
				retval = true;
			i++;
		}
		return retval;
	}

	protected boolean handleFocusIn(int event) {
		return fireFocusEvent(new FocusEvent(this, FocusEvent.Type.FOCUS_IN));
	}

	protected boolean handleFocusOut(int event) {
		return fireFocusEvent(new FocusEvent(this, FocusEvent.Type.FOCUS_OUT));
	}

	/****************************************
	 * Key event handling.
	 ****************************************/
	/**
	 * Register an object to receive key event notification.
	 * 
	 * @param listener The object that has implemented the 
	 * KeyListener interface that is to receive the key events.
	 */
	public void addListener(KeyListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(keyListeners, listener);
		if (i == -1) {
			if (null == keyListeners)
				keyListeners = new Vector();
			keyListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving key event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * key events.
	 */
	public void removeListener(KeyListener listener) {
		int i = findListener(keyListeners, listener);
		if (i > -1)
			keyListeners.remove(i);
		if (0 == keyListeners.size())
			keyListeners = null;
	}

	protected boolean fireKeyEvent(KeyEvent event) {
		if (null == keyListeners)
			return false;
		boolean retval = false;
		int size = keyListeners.size();
		int i = 0;
		while (i < size) {
			KeyListener kl = (KeyListener)keyListeners.elementAt(i);
			if (kl.keyEvent(event))
				retval = true;
			i++;
		}
		return retval;
	}

	protected boolean handleKeyPressed(int event) {
		return fireKeyEvent(new KeyEvent(this, KeyEvent.Type.KEY_PRESSED, new EventKey(event)));
	}

	protected boolean handleKeyReleased(int event) {
		return fireKeyEvent(new KeyEvent(this, KeyEvent.Type.KEY_RELEASED, new EventKey(event)));
	}

	/****************************************
	 * Mouse event handling.
	 ****************************************/
	/**
	 * Register an object to receive mouse event notification.
	 * 
	 * @param listener The object that has implemented the 
	 * MouseListener interface that is to receive the mouse events.
	 */
	public void addListener(MouseListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(mouseListeners, listener);
		if (i == -1) {
			if (null == mouseListeners)
				mouseListeners = new Vector();
			mouseListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving mouse event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * mouse events.
	 */
	public void removeListener(MouseListener listener) {
		int i = findListener(mouseListeners, listener);
		if (i > -1)
			mouseListeners.remove(i);
		if (0 == mouseListeners.size())
			mouseListeners = null;
	}

	protected boolean fireMouseEvent(MouseEvent event) {
		if (null == mouseListeners)
			return false;
		boolean retval = false;
		int size = mouseListeners.size();
		int i = 0;
		while (i < size) {
			MouseListener ml = (MouseListener)mouseListeners.elementAt(i);
			if (ml.mouseEvent(event))
				retval = true;
			i++;
		}
		return retval;
	}

	protected boolean handleButtonPressed(int event) {
		return fireMouseEvent(new MouseEvent(this, MouseEvent.Type.BUTTON_PRESS, new EventButton(event)));
	}

	protected boolean handleButtonReleased(int event) {
		return fireMouseEvent(new MouseEvent(this, MouseEvent.Type.BUTTON_RELEASE, new EventButton(event)));
	}

	protected boolean handleScroll(int event) {
		return fireMouseEvent(new MouseEvent(this, MouseEvent.Type.WHEEL_SCROLL, new EventScroll(event)));
	}

	protected boolean handleMouseEnter(int event) {
		return fireMouseEvent(new MouseEvent(this, MouseEvent.Type.ENTER, new EventCrossing(event)));
	}

	protected boolean handleMouseLeave(int event) {
		return fireMouseEvent(new MouseEvent(this, MouseEvent.Type.LEAVE, new EventCrossing(event)));
	}

	/**
	 * Give us a way to locate a specific listener in a Vector.
	* @param list The Vector of listeners to search.
	* @param listener The object that is to be located in the Vector.
	* @return Returns the index of the listener in the Vector, or -1 if
	*                 the listener is not contained in the Vector.
	 */
	protected static int findListener(Vector list, Object listener) {
		if (null == list || null == listener)
			return -1;
		return list.indexOf(listener);
	}

	/**
	 * Retrieve the runtime type used by the GLib library.
	 */
	public static Type getType() {
		return new Type(gtk_widget_get_type());
	}

	/**
	* Create a Java-GNOME Widget subclass from an existing native
	* GTK+ handle.  
	*
	* @param handle The handle that represents a pointer to a 
	*               native resource.
	* @throws ClassNotFoundException if a Java-GNOME class cannot
	*         be found for the specified handle.
	*/
	public static Widget makeWidget(int handle) throws ClassNotFoundException {
		String widgetClass = getTypeClass(handle);
		if (widgetClass == null)
			throw new ClassNotFoundException("No GTK class name: invalid handle?");
		try {
			Class cls = Class.forName(widgetClass);
			java.lang.reflect.Constructor constr = cls.getConstructor(new Class[] { Integer.TYPE });
			Widget cons =  (Widget)constr.newInstance(new Object[] { new Integer(handle)});
			return cons;
		} catch (ClassNotFoundException e) {
			throw e;
		} catch (NoSuchMethodException e) {
			throw new ClassNotFoundException("could not find constructor: " + widgetClass + "(int)");
		} catch (Exception e) {
			throw new ClassNotFoundException(e.toString());
		}
	}

	private static String getTypeClass(int handle) {
		String widgetType = Gtk.getTypeName(handle);
		if (widgetType.startsWith("Gtk"))
			return "org.gnu.gtk." + widgetType.substring(3);
		else if (widgetType.startsWith("Gnome"))
			return "org.gnu.gnome." + widgetType.substring(5);

		// Custom class?  See if it exists as specified.
		return widgetType;
	}

	/****************************************
	 * Drag and Drop Support
	 ****************************************/
	/**
	 * Sets up the widget so that it can be the source of drag and drop
	 * operations.
	 * @param buttons Buttons which can start the drag
	 * @param targets An array of names of drag and drop operations accepted
	 * (these are made up by the application designers. Widgets must set as drag
	 * sources and destinations with one of these the same)
	 * @param action Drag action - determines which events will be called.
	 */
	public void setDragSource(
		ModifierType buttons,
		TargetEntry[] targets,
		DragAction actions) {
		int[] targets_g = new int[targets.length];
		for (int i = 0; i < targets.length; i++)
			targets_g[i] = targets[i].getHandle();
		gtk_drag_source_set(getHandle(), buttons.getValue(), targets_g, actions.getValue());
	}

	/**
	 * Removes support for this widget being a drag and drop source.
	 */
	public void setNoDragSource() {
		gtk_drag_source_unset(getHandle());
	}

	public void setDragIcon(Widget widget, Colormap cmap, Pixmap pixmap, Bitmap mask) {
		gtk_drag_source_set_icon(widget.getHandle(), cmap.getHandle(), pixmap.getHandle(), mask.getHandle());
	}
	
	public void setDragIconPixbuf(Widget widget, Pixbuf pixbuf) {
		gtk_drag_source_set_icon_pixbuf(widget.getHandle(), pixbuf.getHandle());
	}
	
	public void setDragIconStock(Widget widget, String stockId) {
		gtk_drag_source_set_icon_stock(widget.getHandle(), stockId);
	}

	/**
	 * Sets up the widget so that is can receive drops as part of drag drop
	 * events and specifies what sort of drops it will accept
	 * @param flags 
	 */
	public void setDragDestination(DestDefaults flags, TargetEntry[] targets, org.gnu.gdk.DragAction actions) {
		int[] targets_g = new int[targets.length];
		for (int i = 0; i < targets.length; i++)
			targets_g[i] = targets[i].getHandle();
		gtk_drag_dest_set(getHandle(), flags.getValue(), targets_g, actions.getValue());
	}

	/**
	 * Removes support for this widget being a drag and drop target
	 */
	public void setNoDragDestination() {
		gtk_drag_dest_unset(getHandle());
	}
	public static void getData(Widget widget, DragContext context, int target) {
		gtk_drag_get_data(widget.getHandle(), context.getHandle(), target);
	}
	
	public static void finish(DragContext context, boolean success, boolean delete) {
		gtk_drag_finish(context.getHandle(), success, delete);
	}
	
	public static void highlight(Widget widget) {
		gtk_drag_highlight(widget.getHandle());
	}
	
	public static void unHighlight(Widget widget) {
		gtk_drag_unhighlight(widget.getHandle());
	}
	
	
	/**
	 * Register an object to receive drag drop (destination) events.
	 * 
	 * @param listener The object that has implemented the
	 * DragDestinationListener interface
	 */
	public void addListener(DragDestinationListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(dragDestinationListeners, listener);
		if (i == -1) {
			if (null == dragDestinationListeners)
				dragDestinationListeners = new Vector();
			dragDestinationListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving dragDestination event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * dragDestination events
	 */
	public void removeListener(DragDestinationListener listener) {
		int i = findListener(dragDestinationListeners, listener);
		if (i > -1)
			dragDestinationListeners.remove(i);
		if (0 == dragDestinationListeners.size())
			dragDestinationListeners = null;
	}

	protected void fireDragDestinationEvent(
		Widget widget,
		org.gnu.gdk.DragContext dragContext,
		int x,
		int y,
		SelectionData data,
		int id,
		int time) {
		if (null == dragDestinationListeners)
			return;
		int size = dragDestinationListeners.size();
		int i = 0;
		while (i < size) {
			DragDestinationListener lc = (DragDestinationListener)dragDestinationListeners.elementAt(i);
			lc.dataReceived(widget, dragContext, data, id);
			i++;
		}
	}

	protected void handleDragDestination(int context, int x, int y, int data, int id, int time) {
		SelectionData sd;
		GObject obj = retrieveGObject(data);
		if (null != obj)
			sd = (SelectionData)obj;
		else
			sd = new SelectionData(data);
		DragContext dc;
		GObject obj2 = retrieveGObject(context);
		if (null != obj2)
			dc = (DragContext)obj2;
		else
			dc = new DragContext(context);
		fireDragDestinationEvent(this, dc, x, y, sd, id, time);
	}

	/**
	 * Register an object to receive drag source events.
	 * 
	 * @param listener The object that has implemented the
	 * DragSourceListener interface
	 */
	public void addListener(DragSourceListener listener) {
		// Don't add the listener a second time if it is in the Vector.
		int i = findListener(dragSourceListeners, listener);
		if (i == -1) {
			if (null == dragSourceListeners)
				dragSourceListeners = new Vector();
			dragSourceListeners.addElement(listener);
		}
	}

	/**
	 * Unregister an object that was receiving drag source event notification.
	 * 
	 * @param listener The object that is to no longer receive
	 * drag source events
	 */
	public void removeListener(DragSourceListener listener) {
		int i = findListener(dragSourceListeners, listener);
		if (i > -1)
			dragSourceListeners.remove(i);
		if (0 == dragSourceListeners.size())
			dragSourceListeners = null;
	}

	protected void fireDragSourceEvent(
		Widget widget,
		org.gnu.gdk.DragContext dragContext,
		SelectionData data,
		int id,
		int time) {
		if (null == dragSourceListeners)
			return;
		int size = dragSourceListeners.size();
		int i = 0;
		while (i < size) {
			DragSourceListener lc = (DragSourceListener)dragSourceListeners.elementAt(i);
			lc.getDragData(widget, dragContext, data, id);
			i++;
		}
	}

	protected void handleDragDataGet(int context, int data, int id, int time) {
		SelectionData sd;
		GObject obj = retrieveGObject(data);
		if (null != obj)
			sd = (SelectionData)obj;
		else
			sd = new SelectionData(data);
		DragContext dc;
		GObject obj2 = retrieveGObject(context);
		if (null != obj2)
			dc = (DragContext)obj2;
		else
			dc = new DragContext(context);
		fireDragSourceEvent(this, dc, sd, id, time);
	}

	/****************************************
	 * BEGINNING OF JNI CODE
	 ****************************************/
	native static final protected int gtk_widget_get_type();
	native static final protected int gtk_widget_ref(int widget);
	native static final protected void gtk_widget_unref(int widget);
	native static final protected void gtk_widget_destroy(int widget);
	native static final protected void gtk_widget_destroyed(int widget, int[] widgetPointer);
	native static final protected void gtk_widget_unparent(int widget);
	native static final protected void gtk_widget_show(int widget);
	native static final protected void gtk_widget_show_now(int widget);
	native static final protected void gtk_widget_hide(int widget);
	native static final protected void gtk_widget_show_all(int widget);
	native static final protected void gtk_widget_hide_all(int widget);
	native static final protected void gtk_widget_map(int widget);
	native static final protected void gtk_widget_unmap(int widget);
	native static final protected void gtk_widget_realize(int widget);
	native static final protected void gtk_widget_unrealize(int widget);
	native static final protected void gtk_widget_queue_draw(int widget);
	native static final protected void gtk_widget_queue_draw_area(int widget, int x, int y, int width, int height);
	native static final protected void gtk_widget_queue_resize(int widget);
	native static final protected void gtk_widget_size_request(int widget, int requisition);
	native static final protected void gtk_widget_size_allocate(int widget, int allocation);
	native static final protected void gtk_widget_get_child_requisition(int widget, int[] requisition);
	native static final protected void gtk_widget_add_accelerator(int widget, String accelSignal, int accelGroup, int accelKey, int accelMods, int accelFlags);
	native static final protected boolean gtk_widget_remove_accelerator(int widget, int accelGroup, int accelKey, int accelMods);
	native static final protected void gtk_widget_set_accel_path(int widget, String accelPath, int accelGroup);
	native static final protected int gtk_widget_list_accel_closures(int widget);
	native static final protected boolean gtk_widget_can_activate_accel(int widget, int signalId);
	native static final protected boolean gtk_widget_mnemonic_activate(int widget, boolean groupCycling);
	native static final protected boolean gtk_widget_event(int widget, int event);
	native static final protected int gtk_widget_send_expose(int widget, int event);
	native static final protected boolean gtk_widget_activate(int widget);
	native static final protected void gtk_widget_set_scroll_adjustments(int widget, int hadj, int vadj);
	native static final protected void gtk_widget_reparent(int widget, int newParent);
	native static final protected boolean gtk_widget_intersect(int widget, int area, int[] intersection);
	native static final protected int gtk_widget_region_intersect(int widget, int region);
	native static final protected void gtk_widget_freeze_child_notify(int widget);
	native static final protected void gtk_widget_child_notify(int widget, String childProperty);
	native static final protected void gtk_widget_thaw_child_notify(int widget);
	native static final protected boolean gtk_widget_is_focus(int widget);
	native static final protected void gtk_widget_grab_focus(int widget);
	native static final protected void gtk_widget_grab_default(int widget);
	native static final protected void gtk_widget_set_name(int widget, String name);
	native static final protected String gtk_widget_get_name(int widget);
	native static final protected void gtk_widget_set_state(int widget, int state);
	native static final protected void gtk_widget_set_sensitive(int widget, boolean sensitive);
	native static final protected void gtk_widget_set_app_paintable(int widget, boolean appPaintable);
	native static final protected void gtk_widget_set_double_buffered(int widget, boolean doubleBuffered);
	native static final protected void gtk_widget_set_redraw_on_allocate(int widget, boolean redrawOnAllocate);
	native static final protected void gtk_widget_set_parent(int widget, int parent);
	native static final protected void gtk_widget_set_parent_window(int widget, int parent);
	native static final protected void gtk_widget_set_child_visible(int widget, boolean isVisible);
	native static final protected boolean gtk_widget_get_child_visible(int widget);
	native static final protected int gtk_widget_get_parent(int widget);
	native static final protected int gtk_widget_get_parent_window(int widget);
	native static final protected boolean gtk_widget_child_focus(int widget, int direction);
	native static final protected void gtk_widget_set_size_request(int widget, int width, int height);
	native static final protected void gtk_widget_get_size_request(int widget, int[] width, int[] height);
	native static final protected void gtk_widget_set_events(int widget, int events);
	native static final protected void gtk_widget_add_events(int widget, int events);
	native static final protected void gtk_widget_set_extension_events(int widget, int mode);
	native static final protected int gtk_widget_get_extension_events(int widget);
	native static final protected int gtk_widget_get_toplevel(int widget);
	native static final protected int gtk_widget_get_ancestor(int widget, int widgetType);
	native static final protected int gtk_widget_get_colormap(int widget);
	native static final protected int gtk_widget_get_visual(int widget);
	native static final protected int gtk_widget_get_screen(int widget);
	native static final protected boolean gtk_widget_has_screen(int widget); 
	native static final protected int gtk_widget_get_display(int widget);
	native static final protected int gtk_widget_get_root_window(int widget);
	native static final protected boolean gtk_widget_get_sensitive(int widget);
	native static final protected int gtk_widget_get_settings(int widget);
	native static final protected int gtk_widget_get_accessible(int widget);
	native static final protected void gtk_widget_set_colormap(int widget, int cmap);
	native static final protected int gtk_widget_get_events(int widget);
	native static final protected void gtk_widget_get_pointer(int widget, int[] x, int[] y);
	native static final protected boolean gtk_widget_is_ancestor(int widget, int ancestor);
	native static final protected boolean gtk_widget_translate_coordinates(int srcWidget, int destWidget, int srcX, int srcY, int[] destX, int[] destY);
	native static final protected boolean gtk_widget_hide_on_delete(int widget);
	native static final protected void gtk_widget_set_style(int widget, int style);
	native static final protected void gtk_widget_ensure_style(int widget);
	native static final protected int gtk_widget_get_style(int widget);
	native static final protected void gtk_widget_modify_style(int widget, int style);
	native static final protected int gtk_widget_get_modifier_style(int widget);
	native static final protected void gtk_widget_modify_fg(int widget, int state, int color);
	native static final protected void gtk_widget_modify_bg(int widget, int state, int color);
	native static final protected void gtk_widget_modify_text(int widget, int state, int color);
	native static final protected void gtk_widget_modify_base(int widget, int state, int color);
	native static final protected void gtk_widget_modify_font(int widget, int fontDesc);
	native static final protected int gtk_widget_create_pango_context(int widget);
	native static final protected int gtk_widget_get_pango_context(int widget);
	native static final protected int gtk_widget_create_pango_layout(int widget, String text);
	native static final protected int gtk_widget_render_icon(int widget, String stockID, int size, String detail);
	native static final protected void gtk_widget_set_composite_name(int widget, String name);
	native static final protected String gtk_widget_get_composite_name(int widget);
	native static final protected void gtk_widget_reset_rc_styles(int widget);
	native static final protected void gtk_widget_push_colormap(int cmap);
	native static final protected void gtk_widget_pop_colormap();
	native static final protected void gtk_widget_push_composite_child();
	native static final protected void gtk_widget_pop_composite_child();
	native static final protected void gtk_widget_style_get_property(int widget, String propertyName, int value);
	native static final protected void gtk_widget_set_default_colormap(int cmap);
	native static final protected int gtk_widget_get_default_colormap();
	native static final protected int gtk_widget_get_default_visual();
	native static final protected int gtk_widget_get_default_style();
	native static final protected void gtk_widget_set_direction(int widget, int dir);
	native static final protected int gtk_widget_get_direction(int widget);
	native static final protected void gtk_widget_set_default_direction(int dir);
	native static final protected int gtk_widget_get_default_direction();
	native static final protected void gtk_widget_shape_combine_mask(int widget, int shapeMask, int offsetX, int offsetY); 
	native static final protected void gtk_widget_path(int widget, int[] pathLength, String[] path, String[] pathReversed); 
	native static final protected void gtk_widget_class_path(int widget, int[] pathLength, String[] path, String[] pathReversed);
	native static final protected int[] gtk_widget_list_mnemonic_labels(int widget);
	native static final protected void gtk_widget_add_mnemonic_label(int widget, int label);
	native static final protected void gtk_widget_remove_mnemonic_label(int widget, int label);
	// Drag and Drop support
	native static final protected void gtk_drag_dest_set(int widget, int flags, int[] targets, int actions);
	native static final protected void gtk_drag_dest_unset(int widget);
	native static final protected void gtk_drag_get_data(int widget, int context, int target);
	native static final protected void gtk_drag_finish(int context, boolean success, boolean delete);
	native static final protected void gtk_drag_highlight(int widget);
	native static final protected void gtk_drag_unhighlight(int widget);
	native static final protected void gtk_drag_source_set(int widget, int start_button_mask, int[] targets, int actions);
	native static final protected void gtk_drag_source_unset(int widget);
	native static final protected void gtk_drag_source_set_icon(int widget, int colormap, int pixmap, int mask);
	native static final protected void gtk_drag_source_set_icon_pixbuf(int widget, int pixbuf);
	native static final protected void gtk_drag_source_set_icon_stock(int widget, String stockId);
	/****************************************
	 * END OF JNI CODE
	 ****************************************/
}
