/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2003 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 org.gnu.glib.GObject;
import org.gnu.glib.Handle;
import org.gnu.gdk.Event;
import org.gnu.gdk.EventKey;

/**
 * This class is a catch-all for methods in GTK that are not
 * associated with a GTK object.
 */

public class Gtk 
{
	
	/**
	 * This method should be called before using any java-gnome
	 * objects.  It initialized everything needed to use the native
	 * libraries.  This method will terminate you program if it is
	 * unable to initialize the native libraries.
	 * 
	 * @param args The command line arguments passed to the applicaion.
	 */
	public static void init(String[] args) {
	    int [] argLen = new int[1];

	    String appName = System.getProperty("gnome.appName", "java-gnome");

		if (args == null) {
			args = new String[] { appName };
		} else {
			String[] newArr = new String[args.length + 1];
			System.arraycopy(args, 0, newArr, 1, args.length);
			newArr[0] = appName;
			args = newArr;
		}
		argLen[0] = args.length;
	    Gtk.gtk_init(argLen, args);
	}
	
	/**
	 * Runs the main event loop.
	 */
	public static void main() {
        gtkThread = Thread.currentThread();
	    Gtk.gtk_main();
	}

    private static Thread gtkThread;
    /**
     * Returns true if the current thread is the Gtk thread
     */
    public static boolean isGtkThread() {
        return gtkThread == Thread.currentThread();
    }
	
	/**
	 * Runs a single iteration of the main loop.  If no events are waiting
	 * to be processed GTK will block until the next event is noticed.
	 */
	public static boolean mainIteration() {
		return Gtk.gtk_main_iteration();
	}

	/**
	 * Quit the main event loop.
	 */
	public static void mainQuit() {
		Gtk.gtk_main_quit();
	}
	
	/**
	 * Checks if any events are pending.  This can be used to update the 
	 * GUI and invoke timeouts etc. while doing some time intensive 
	 * computation.
	 * 
	 * @return true if any events are pending.
	 */
	public static boolean eventsPending() {
            return Gtk.gtk_events_pending();
	}

	static String getTypeName(Handle handle) {
	    try {
	    	return gtk_type_name(handle);
	    } catch (Throwable t) {
			System.err.println(t.toString());
	        return null;
	    }
	}

    /**
     * All this function does is to return TRUE. This can be useful
     * for example if you want to inhibit the deletion of a window. Of
     * course you should not do this as the user expects a reaction
     * from clicking the close icon of the window.
     */
    public static boolean getTrue() {
        return gtk_true();
    }
    /**
     * Analogical to {@link #getTrue}. This function does nothing but always
     * return FALSE.
     */
    public static boolean getFalse() {
        return gtk_false();
    }

    /**
     * Runs a single iteration of the mainloop. If no events are
     * available either return or block dependent on the value of
     * <tt>blocking</tt>.
     *
     * @param blocking TRUE if you want GTK+ to block if no events are pending.
     * @return TRUE if {@link #mainQuit} has been called for the
     * innermost mainloop.
     */
    public static boolean mainIterationDo( boolean blocking ) {
        return gtk_main_iteration_do( blocking );
    }

    // Private data members for keysnooping data.
    private static KeySnoopMethod keySnooperMethod = null;
    private static int keySnooperId = 0;
    /**
     * Installs a key snooper method, which will get called on all
     * key events before delivering them normally.  This can be used to 
     * implement custom key event handling.
     */
    public static void setKeySnoopMethod( KeySnoopMethod method ) {
        keySnooperId = gtk_key_snooper_install( method, 
                                                "handleKeySnoopEvent" );
        keySnooperMethod = method;
    }
    /**
     * Removes current the key snooper method.
     */
    public static void removeKeySnoopMethod() {
        gtk_key_snooper_remove( keySnooperId );
        keySnooperMethod = null;
        keySnooperId = 0;
    }

    protected static boolean handleKeySnoopEvent( Handle widget, 
                                                  Handle event ) {
        if ( keySnooperMethod != null ) {
            Widget widg = null;
            GObject obj = GObject.getGObjectFromHandle( widget );
            if ( obj == null ) {
                widg = new Widget( widget );
            } else {
                widg = (Widget)obj;
            }
            EventKey evt = new EventKey( event );
            return keySnooperMethod.keyEvent( widg, evt );
        } else {
            return false;
        }
    }

    /**
     * Sends an event to a widget, propagating the event to parent
     * widgets if the event remains unhandled.
     *
     * <b>NOTE</b>: You most likely don't want to use this function.
     * Synthesizing events is rarely needed. Consider asking on the
     * mailing list for better ways to achieve your goals.
     *
     * @param widget A Widget.
     * @param event An Event.
     */
    public void propagateEvent( Widget widget, Event event ) {
        gtk_propagate_event( widget.getHandle(), event.getHandle() );
    }

	// Load the library
	static {
		System.loadLibrary(org.gnu.glib.Config.LIBRARY_NAME + org.gnu.glib.Config.GTK_API_VERSION);
	}


    native static final protected void gtk_init (int [] argc, String[] args);
    native static final protected void gtk_init_check (int [] argc, String[] args);
    native static final protected void gtk_disable_setlocale ();
    native static final protected String gtk_set_locale ();
    native static final protected Handle gtk_get_default_language ();
    native static final protected boolean gtk_events_pending ();
    native static final protected void gtk_main_do_event (Handle event);
    native static final protected void gtk_main ();
    native static final protected int gtk_main_level ();
    native static final protected void gtk_main_quit ();
    native static final protected boolean gtk_main_iteration ();
    native static final protected void gtk_grab_add (Handle widget);
    native static final protected Handle gtk_grab_get_current ();
    native static final protected void gtk_grab_remove (Handle widget);
    native static final protected Handle gtk_get_current_event ();
    native static final protected int gtk_get_current_event_time ();
    native static final protected Handle gtk_get_event_widget (Handle event);
    native static final protected String gtk_type_name (Handle type);
    native static final protected Handle gtk_type_from_name (String name);

    native static final private boolean gtk_true();
    native static final private boolean gtk_false();
    native static final private boolean gtk_main_iteration_do(boolean blocking);
    native static final private int gtk_key_snooper_install(KeySnoopMethod snooper, String callback);
    native static final private void gtk_key_snooper_remove(int snooper_handler_id);
    native static final private void gtk_propagate_event(Handle widget, Handle event);

    /* Undocumented functions.
    native static final private String gtk_check_version(int required_major, int required_minor, int required_micro);
    */
    /* Deprecated functions.
    native static final private void gtk_exit(int error_code);
    native static final private int gtk_timeout_add(int interval, int function, gpointer data);
    native static final private int gtk_timeout_add_full(int interval, int function, int marshal, gpointer data, int destroy);
    native static final private void gtk_timeout_remove(int timeout_handler_id);
    native static final private int gtk_idle_add(int function, gpointer data);
    native static final private int gtk_idle_add_priority(int priority, int function, gpointer data);
    native static final private int gtk_idle_add_full(int priority, int function, int marshal, gpointer data, int destroy);
    native static final private void gtk_idle_remove(int idle_handler_id);
    native static final private void gtk_idle_remove_by_data(gpointer data);
    native static final private int gtk_input_add_full(int source, int condition, int function, int marshal, gpointer data, int destroy);
    native static final private void gtk_input_remove(int input_handler_id);
    */

    private Gtk() {
	// prevent instantiation
    }
}

