/*
 * java-gnome, a UI library for writing GTK and GNOME programs from Java!
 *
 * Copyright © 2007-2010 Operational Dynamics Consulting, Pty Ltd and Others
 *
 * The code in this file, and the program it is a part of, is made available
 * to you by its authors as open source software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License version
 * 2 ("GPL") as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
 *
 * You should have received a copy of the GPL along with this program. If not,
 * see http://www.gnu.org/licenses/. The authors of this program may be
 * contacted through http://java-gnome.sourceforge.net/.
 *
 * Linking this library statically or dynamically with other modules is making
 * a combined work based on this library. Thus, the terms and conditions of
 * the GPL cover the whole combination. As a special exception (the
 * "Classpath Exception"), the copyright holders of this library give you
 * permission to link this library with independent modules to produce an
 * executable, regardless of the license terms of these independent modules,
 * and to copy and distribute the resulting executable under terms of your
 * choice, provided that you also meet, for each linked independent module,
 * the terms and conditions of the license of that module. An independent
 * module is a module which is not derived from or based on this library. If
 * you modify this library, you may extend the Classpath Exception to your
 * version of the library, but you are not obligated to do so. If you do not
 * wish to do so, delete this exception statement from your version.
 */

#include <jni.h>
#include <gdk/gdk.h>
#include "bindings_java.h"

/*
 * Permit multi threaded use of GTK by synchronizing access via "the GTK
 * main lock". We do this almost entirely on the Java side, except that a
 * mutex is a mutex, ultimately, so by overriding the default implementations
 * in gtk+'s gdk/gdk.c we can properly interoperate with the rest of the GTK
 * library.
 */

static jobject lock;

/**
 * Save a reference to the lock object on the Java side, and then register our
 * custom lock functions. This function also initializes  GLib's thread
 * mechanism; which call needs to be the _very_ first thing in a GLib program
 * these days.
 */
void
bindings_java_threads_init
(
	JNIEnv *env,
	jobject obj
)
{
	// must be first GLib call!
	g_thread_init(NULL);

	// now get about setting up GDK's threads
	lock = (*env)->NewGlobalRef(env, obj);

	gdk_threads_set_lock_functions(bindings_java_threads_lock, bindings_java_threads_unlock);
	gdk_threads_init();
}

/**
 * Enter the monitor for our Java side GDK lock object. This is, strictly,
 * the opening half of a sychronized (obj) { ... } in Java, as expressed in
 * JNI.
 */
/*
 * Signature the prototype of the generic (*GCallback) prototype, meeting the
 * requirements of the first argument to gdk_threads_set_lock_functions()
 */
void
bindings_java_threads_lock
(
)
{
	JNIEnv* env;
	
	env = bindings_java_getEnv();

	if ((*env)->MonitorEnter(env, lock) != JNI_OK) {
		g_critical("Error trying to get Java side GDK lock!?!");
	}
}

/**
 * Release the monitor (lock) held on our Java side GDK lock object. Note the
 * Sun Java VM implementation will still show this thread as having entered
 * the lock, but if you look at a thread dump closely you'll see it waiting
 * on monitor, which is correct.
 */
/*
 * Signature the prototype of the generic (*GCallback) prototype, meeting the
 * requirements of the second argument to gdk_threads_set_lock_functions()
 */
void
bindings_java_threads_unlock
(
)
{
	JNIEnv* env;

	env = bindings_java_getEnv();

	if ((*env)->MonitorExit(env, lock) != JNI_OK) {
		g_critical("Error trying to release Java side GDK lock?!?");
	}
}
