diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-16 00:30:23 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-07-16 00:30:23 +0000 |
commit | c8875fb97fc03779a5bba09872227b1d08e5d52a (patch) | |
tree | a0b991cf5866ae1d616639b906ac001811d74508 /libjava/classpath/native/jni | |
parent | c40c1730800ed292b6db39a83d592476fa59623c (diff) | |
download | ppe42-gcc-c8875fb97fc03779a5bba09872227b1d08e5d52a.tar.gz ppe42-gcc-c8875fb97fc03779a5bba09872227b1d08e5d52a.zip |
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102074 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/native/jni')
108 files changed, 34316 insertions, 0 deletions
diff --git a/libjava/classpath/native/jni/.cvsignore b/libjava/classpath/native/jni/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/Makefile.am b/libjava/classpath/native/jni/Makefile.am new file mode 100644 index 00000000000..41d9a913bd1 --- /dev/null +++ b/libjava/classpath/native/jni/Makefile.am @@ -0,0 +1,20 @@ +## Input file for automake to generate the Makefile.in used by configure + +if CREATE_CORE_JNI_LIBRARIES + JNIDIRS = java-io java-lang java-net java-nio java-util +endif + +if CREATE_GTK_PEER_LIBRARIES + GTKDIR = gtk-peer +endif + +if CREATE_XMLJ_LIBRARY + XMLJDIR = xmlj +endif + +SUBDIRS = classpath $(JNIDIRS) $(GTKDIR) $(XMLJDIR) +DIST_SUBDIRS = classpath java-io java-lang java-net java-nio java-util \ + gtk-peer xmlj + +all-local: + cd $(top_srcdir) && scripts/check_jni_methods.sh diff --git a/libjava/classpath/native/jni/classpath/.cvsignore b/libjava/classpath/native/jni/classpath/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/classpath/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/classpath/Makefile.am b/libjava/classpath/native/jni/classpath/Makefile.am new file mode 100644 index 00000000000..0171d3728e0 --- /dev/null +++ b/libjava/classpath/native/jni/classpath/Makefile.am @@ -0,0 +1,10 @@ +noinst_LTLIBRARIES = libclasspath.la + +libclasspath_la_SOURCES = jcl.c jcl.h \ + jnilink.c jnilink.h \ + primlib.c primlib.h \ + native_state.c native_state.h + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/classpath/classpath_jawt.h b/libjava/classpath/native/jni/classpath/classpath_jawt.h new file mode 100644 index 00000000000..6ff5c53355e --- /dev/null +++ b/libjava/classpath/native/jni/classpath/classpath_jawt.h @@ -0,0 +1,64 @@ +/* classpath_awt.h -- libjawt's interface to the peer library + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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. */ + +/* + * libjawt.so is linked directly to the peer library with -l. This + * header declares all the functions that libjawt.so needs -- X-based + * peer libraries wanting to support libjawt.so must implement these + * functions. + */ + +#ifndef __classpath_jawt_h__ +#define __classpath_jawt_h__ + +#include <jni.h> +#include <X11/Xlib.h> + +#define CLASSPATH_JAWT_VERSION 0x10004 + +jint classpath_jawt_get_awt_version (); +Display* classpath_jawt_get_default_display (JNIEnv* env, jobject canvas); +Drawable classpath_jawt_get_drawable (JNIEnv* env, jobject canvas); +VisualID classpath_jawt_get_visualID (JNIEnv* env, jobject canvas); +jint classpath_jawt_object_lock (jobject lock); +void classpath_jawt_object_unlock (jobject lock); +jint classpath_jawt_lock (); +void classpath_jawt_unlock (); +jobject classpath_jawt_create_lock (); +void classpath_jawt_destroy_lock (jobject lock); + +#endif /* __classpath_jawt_h__ */ diff --git a/libjava/classpath/native/jni/classpath/jcl.c b/libjava/classpath/native/jni/classpath/jcl.c new file mode 100644 index 00000000000..03f9b3753cc --- /dev/null +++ b/libjava/classpath/native/jni/classpath/jcl.c @@ -0,0 +1,180 @@ +/* jcl.c + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <jcl.h> + +#ifndef __GNUC__ +#define __attribute__(x) /* nothing */ +#endif + +JNIEXPORT void JNICALL +JCL_ThrowException (JNIEnv * env, const char *className, const char *errMsg) +{ + jclass excClass; + if ((*env)->ExceptionOccurred (env)) + { + (*env)->ExceptionClear (env); + } + excClass = (*env)->FindClass (env, className); + if (excClass == NULL) + { + jclass errExcClass; + errExcClass = + (*env)->FindClass (env, "java/lang/ClassNotFoundException"); + if (errExcClass == NULL) + { + errExcClass = (*env)->FindClass (env, "java/lang/InternalError"); + if (errExcClass == NULL) + { + fprintf (stderr, "JCL: Utterly failed to throw exeption "); + fprintf (stderr, className); + fprintf (stderr, " with message "); + fprintf (stderr, errMsg); + return; + } + } + /* Removed this (more comprehensive) error string to avoid the need for + * a static variable or allocation of a buffer for this message in this + * (unlikely) error case. --Fridi. + * + * sprintf(errstr,"JCL: Failed to throw exception %s with message %s: could not find exception class.", className, errMsg); + */ + (*env)->ThrowNew (env, errExcClass, className); + } + (*env)->ThrowNew (env, excClass, errMsg); +} + +JNIEXPORT void *JNICALL +JCL_malloc (JNIEnv * env, size_t size) +{ + void *mem = malloc (size); + if (mem == NULL) + { + JCL_ThrowException (env, "java/lang/OutOfMemoryError", + "malloc() failed."); + return NULL; + } + return mem; +} + +JNIEXPORT void *JNICALL +JCL_realloc (JNIEnv * env, void *ptr, size_t size) +{ + ptr = realloc (ptr, size); + if (ptr == 0) + { + JCL_ThrowException (env, "java/lang/OutOfMemoryError", + "malloc() failed."); + return NULL; + } + return (ptr); +} + +JNIEXPORT void JNICALL +JCL_free (JNIEnv * env __attribute__ ((unused)), void *p) +{ + if (p != NULL) + { + free (p); + } +} + +JNIEXPORT const char *JNICALL +JCL_jstring_to_cstring (JNIEnv * env, jstring s) +{ + const char *cstr; + if (s == NULL) + { + JCL_ThrowException (env, "java/lang/NullPointerException", + "Null string"); + return NULL; + } + cstr = (const char *) (*env)->GetStringUTFChars (env, s, NULL); + if (cstr == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "GetStringUTFChars() failed."); + return NULL; + } + return cstr; +} + +JNIEXPORT void JNICALL +JCL_free_cstring (JNIEnv * env, jstring s, const char *cstr) +{ + (*env)->ReleaseStringUTFChars (env, s, cstr); +} + +JNIEXPORT jint JNICALL +JCL_MonitorEnter (JNIEnv * env, jobject o) +{ + jint retval = (*env)->MonitorEnter (env, o); + if (retval != 0) + { + JCL_ThrowException (env, "java/lang/InternalError", + "MonitorEnter() failed."); + } + return retval; +} + +JNIEXPORT jint JNICALL +JCL_MonitorExit (JNIEnv * env, jobject o) +{ + jint retval = (*env)->MonitorExit (env, o); + if (retval != 0) + { + JCL_ThrowException (env, "java/lang/InternalError", + "MonitorExit() failed."); + } + return retval; +} + +JNIEXPORT jclass JNICALL +JCL_FindClass (JNIEnv * env, const char *className) +{ + jclass retval = (*env)->FindClass (env, className); + if (retval == NULL) + { + JCL_ThrowException (env, "java/lang/ClassNotFoundException", className); + } + return retval; +} diff --git a/libjava/classpath/native/jni/classpath/jcl.h b/libjava/classpath/native/jni/classpath/jcl.h new file mode 100644 index 00000000000..e526b293966 --- /dev/null +++ b/libjava/classpath/native/jni/classpath/jcl.h @@ -0,0 +1,68 @@ +/* jcl.h + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef __JCL_H__ +#define __JCL_H__ + +#include <stddef.h> +#include <jni.h> +#include <config.h> + +JNIEXPORT jclass JNICALL JCL_FindClass (JNIEnv * env, const char *className); +JNIEXPORT void JNICALL JCL_ThrowException (JNIEnv * env, + const char *className, + const char *errMsg); +JNIEXPORT void *JNICALL JCL_malloc (JNIEnv * env, size_t size); +JNIEXPORT void *JNICALL JCL_realloc (JNIEnv * env, void *ptr, size_t size); +JNIEXPORT void JNICALL JCL_free (JNIEnv * env, void *p); +JNIEXPORT const char *JNICALL JCL_jstring_to_cstring (JNIEnv * env, + jstring s); +JNIEXPORT void JNICALL JCL_free_cstring (JNIEnv * env, jstring s, + const char *cstr); +JNIEXPORT jint JNICALL JCL_MonitorEnter (JNIEnv * env, jobject o); +JNIEXPORT jint JNICALL JCL_MonitorExit (JNIEnv * env, jobject o); + +#define JCL_RETHROW_EXCEPTION(env) if((*(env))->ExceptionOccurred((env)) != NULL) return NULL; + +/* Simple debug macro */ +#ifdef DEBUG +#define DBG(x) fprintf(stderr, (x)); +#else +#define DBG(x) +#endif + +#endif diff --git a/libjava/classpath/native/jni/classpath/jnilink.c b/libjava/classpath/native/jni/classpath/jnilink.c new file mode 100644 index 00000000000..15e73a7210b --- /dev/null +++ b/libjava/classpath/native/jni/classpath/jnilink.c @@ -0,0 +1,125 @@ +/* JNILINK 1.1: JNI version. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <stdlib.h> +#include <string.h> +#include <jcl.h> + +#include "jnilink.h" + +#define GETCLASS(c) *(jclass*)(c) + +JNIEXPORT jclass JNICALL +LINK_RelinkClass (JNIEnv * env, linkedClass * c, const char *name) +{ + jclass found; + LINK_UnlinkClass (env, *c); + + found = (*env)->FindClass (env, name); + if (found == NULL) + return NULL; + + *c = JCL_malloc (env, sizeof (jclass)); + if (*c == NULL) + return NULL; + + GETCLASS (*c) = (*env)->NewGlobalRef (env, found); + return GETCLASS (*c); +} + +JNIEXPORT jclass JNICALL +LINK_RelinkKnownClass (JNIEnv * env, linkedClass * c, jclass newClass) +{ + LINK_UnlinkClass (env, *c); + + *c = JCL_malloc (env, sizeof (jclass)); + if (*c == NULL) + return NULL; + + GETCLASS (*c) = (*env)->NewGlobalRef (env, newClass); + return newClass; +} + +JNIEXPORT jmethodID JNICALL +LINK_RelinkMethod (JNIEnv * env, jmethodID * m, linkedClass c, + const char *name, const char *sig) +{ + *m = (*env)->GetMethodID (env, GETCLASS (c), name, sig); + return *m; +} + +JNIEXPORT jmethodID JNICALL +LINK_RelinkStaticMethod (JNIEnv * env, jmethodID * m, linkedClass c, + const char *name, const char *sig) +{ + *m = (*env)->GetStaticMethodID (env, GETCLASS (c), name, sig); + return *m; +} + +JNIEXPORT jfieldID JNICALL +LINK_RelinkField (JNIEnv * env, jfieldID * f, linkedClass c, + const char *name, const char *sig) +{ + *f = (*env)->GetFieldID (env, GETCLASS (c), name, sig); + return *f; +} + +JNIEXPORT jfieldID JNICALL +LINK_RelinkStaticField (JNIEnv * env, jfieldID * f, linkedClass c, + const char *name, const char *sig) +{ + *f = (*env)->GetStaticFieldID (env, GETCLASS (c), name, sig); + return *f; +} + + +/* These are for when the class referencing the symbols is unloaded; it +destroys any object references + * the linker might have kept around. + */ +JNIEXPORT void JNICALL +LINK_UnlinkClass (JNIEnv * env, linkedClass * c) +{ + if (*c != NULL) + { + if (GETCLASS (*c) != NULL) + (*env)->DeleteGlobalRef (env, GETCLASS (*c)); + JCL_free (env, *c); + *c = NULL; + } +} diff --git a/libjava/classpath/native/jni/classpath/jnilink.h b/libjava/classpath/native/jni/classpath/jnilink.h new file mode 100644 index 00000000000..dd94b3a7aed --- /dev/null +++ b/libjava/classpath/native/jni/classpath/jnilink.h @@ -0,0 +1,82 @@ +/* JNILINK 1.1: JNI version. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + + +#ifndef __JNILINK_H__ +#define __JNILINK_H__ + +#include <jni.h> + +typedef void *linkedClass; + +#define LINK_LinkClass(env,c,name) ((c)==NULL ? LINK_ReallyLinkClass((env),&(c),(name)) : (c)) +#define LINK_LinkKnownClass(env,c,newClass) ((c)==NULL ? LINK_ReallyLinkKnownClass((env),&(c),(newClass)) : (c)) +#define LINK_LinkMethod(env,m,c,name,sig) ((m)==NULL ? LINK_RelinkMethod((env),&(m),(c),(name),(sig)) : (m)) +#define LINK_LinkStaticMethod(env,m,c,name,sig) ((m)==NULL ? LINK_RelinkStaticMethod((env),&(m),(c),(name),(sig)) : (m)) +#define LINK_LinkField(env,f,c,name,sig) ((m)==NULL ? LINK_RelinkField((env),&(f),(c),(name),(sig)) : (f)) +#define LINK_LinkStaticField(env,f,c,name,sig) ((m)==NULL ? LINK_RelinkStaticField((env),&(f),(c),(name),(sig)) : (f)) + +#define LINK_LinkConstructor(env,m,c,sig) ((m)==NULL ? LINK_RelinkMethod((env),&(m),(c),"<init>",(sig)) : (m)) + +JNIEXPORT jclass JNICALL +LINK_ReallyLinkClass (JNIEnv * env, linkedClass * c, const char *name); +JNIEXPORT jclass JNICALL +LINK_ReallyLinkKnownClass (JNIEnv * env, linkedClass * c, jclass newClass); +JNIEXPORT jclass JNICALL +LINK_RelinkClass (JNIEnv * env, linkedClass * c, const char *name); +JNIEXPORT jclass JNICALL +LINK_RelinkKnownClass (JNIEnv * env, linkedClass * c, jclass newClass); +JNIEXPORT jmethodID JNICALL +LINK_RelinkMethod (JNIEnv * env, jmethodID * m, linkedClass c, + const char *name, const char *sig); +JNIEXPORT jmethodID JNICALL +LINK_RelinkStaticMethod (JNIEnv * env, jmethodID * m, linkedClass c, + const char *name, const char *sig); +JNIEXPORT jfieldID JNICALL +LINK_RelinkField (JNIEnv * env, jfieldID * f, linkedClass c, + const char *name, const char *sig); +JNIEXPORT jfieldID JNICALL +LINK_RelinkStaticField (JNIEnv * env, jfieldID * f, linkedClass c, + const char *name, const char *sig); + +/* These are for when the class referencing the symbols is unloaded; it +destroys any object references + * the linker might have kept around. + */ +JNIEXPORT void JNICALL LINK_UnlinkClass (JNIEnv * env, linkedClass * c); + +#endif diff --git a/libjava/classpath/native/jni/classpath/native_state.c b/libjava/classpath/native/jni/classpath/native_state.c new file mode 100644 index 00000000000..3c11b8343de --- /dev/null +++ b/libjava/classpath/native/jni/classpath/native_state.c @@ -0,0 +1,248 @@ +/* Magical NSA API -- Associate a C ptr with an instance of an object + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <stdlib.h> +#include <jni.h> +#include "native_state.h" + +#define DEFAULT_TABLE_SIZE 97 + +struct state_table * +cp_gtk_init_state_table_with_size (JNIEnv * env, jclass clazz, jint size) +{ + struct state_table *table; + jfieldID hash; + jclass clazz_g; + + hash = (*env)->GetFieldID (env, clazz, "native_state", "I"); + if (hash == NULL) + return NULL; + + clazz_g = (*env)->NewGlobalRef (env, clazz); + if (clazz_g == NULL) + return NULL; + + table = (struct state_table *) malloc (sizeof (struct state_table)); + table->size = size; + table->head = (struct state_node **) calloc (sizeof (struct state_node *), + table->size); + table->hash = hash; + table->clazz = clazz_g; + + return table; +} + +struct state_table * +cp_gtk_init_state_table (JNIEnv * env, jclass clazz) +{ + return cp_gtk_init_state_table_with_size (env, clazz, DEFAULT_TABLE_SIZE); +} + +static void * +remove_node (struct state_node **head, jint obj_id) +{ + struct state_node *back_ptr = NULL; + struct state_node *node = *head; + + while (node != NULL) + { + if (node->key == obj_id) + { + void *return_value; + if (back_ptr == NULL) + *head = node->next; + else + back_ptr->next = node->next; + return_value = node->c_state; + free (node); + return return_value; + } + back_ptr = node; + node = node->next; + } + + return NULL; +} + +static void * +get_node (struct state_node **head, jint obj_id) +{ + struct state_node *back_ptr = NULL; + struct state_node *node = *head; + + while (node != NULL) + { + if (node->key == obj_id) + { + /* Move the node we found to the front of the list. */ + if (back_ptr != NULL) + { + back_ptr->next = node->next; + node->next = *head; + *head = node; + } + + /* Return the match. */ + return node->c_state; + } + + back_ptr = node; + node = node->next; + } + + return NULL; +} + +static void +add_node (struct state_node **head, jint obj_id, void *state) +{ + struct state_node *node = *head; + struct state_node *back_ptr = NULL; + + struct state_node *new_node; + + if (node != NULL) + { + while (node->next != NULL && obj_id != node->key) + { + back_ptr = node; + node = node->next; + } + + if (node->key == obj_id) + { + /* If we're updating a node, move it to the front of the + list. */ + if (back_ptr != NULL) + { + back_ptr->next = node->next; + node->next = *head; + *head = node; + } + node->c_state = state; + return; + } + } + + new_node = (struct state_node *) malloc (sizeof (struct state_node)); + new_node->key = obj_id; + new_node->c_state = state; + new_node->next = *head; + *head = new_node; +} + +void +cp_gtk_set_state_oid (JNIEnv * env, jobject lock, struct state_table *table, + jint obj_id, void *state) +{ + jint hash; + + hash = obj_id % table->size; + + (*env)->MonitorEnter (env, lock); + add_node (&table->head[hash], obj_id, state); + (*env)->MonitorExit (env, lock); +} + +void * +cp_gtk_get_state_oid (JNIEnv * env, jobject lock, struct state_table *table, + jint obj_id) +{ + jint hash; + void *return_value; + + hash = obj_id % table->size; + + (*env)->MonitorEnter (env, lock); + return_value = get_node (&table->head[hash], obj_id); + (*env)->MonitorExit (env, lock); + + return return_value; +} + +void * +cp_gtk_remove_state_oid (JNIEnv * env, jobject lock, struct state_table *table, + jint obj_id) +{ + jint hash; + void *return_value; + + hash = obj_id % table->size; + + (*env)->MonitorEnter (env, lock); + return_value = remove_node (&table->head[hash], obj_id); + (*env)->MonitorExit (env, lock); + + return return_value; +} + +int +cp_gtk_set_state (JNIEnv * env, jobject obj, struct state_table *table, void *state) +{ + jint obj_id; + obj_id = (*env)->GetIntField (env, obj, table->hash); + + if ((*env)->ExceptionOccurred (env) != NULL) + return -1; + + cp_gtk_set_state_oid (env, table->clazz, table, obj_id, state); + return 0; +} + +void * +cp_gtk_get_state (JNIEnv * env, jobject obj, struct state_table *table) +{ + jint obj_id; + obj_id = (*env)->GetIntField (env, obj, table->hash); + + if ((*env)->ExceptionOccurred (env) != NULL) + return NULL; + + return cp_gtk_get_state_oid (env, table->clazz, table, obj_id); +} + +void * +cp_gtk_remove_state_slot (JNIEnv * env, jobject obj, struct state_table *table) +{ + jint obj_id; + obj_id = (*env)->GetIntField (env, obj, table->hash); + + if ((*env)->ExceptionOccurred (env) != NULL) + return NULL; + + return cp_gtk_remove_state_oid (env, table->clazz, table, obj_id); +} diff --git a/libjava/classpath/native/jni/classpath/native_state.h b/libjava/classpath/native/jni/classpath/native_state.h new file mode 100644 index 00000000000..641e588827d --- /dev/null +++ b/libjava/classpath/native/jni/classpath/native_state.h @@ -0,0 +1,71 @@ +/* Magical NSA API -- Associate a C ptr with an instance of an object + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef JCL_NATIVE_STATE +#define JCL_NATIVE_STATE + +#include <jni.h> + +struct state_table +{ + jint size; /* number of slots, should be prime */ + jfieldID hash; /* field containing System.identityHashCode(this) */ + jclass clazz; /* lock aquired for reading/writing nodes */ + struct state_node **head; +}; + +struct state_node +{ + jint key; + void *c_state; + struct state_node *next; +}; + +struct state_table *cp_gtk_init_state_table_with_size (JNIEnv *, jclass, jint); +struct state_table *cp_gtk_init_state_table (JNIEnv *, jclass); + +/* lowlevel api */ +void cp_gtk_set_state_oid (JNIEnv *, jobject, struct state_table *, jint, void *); +void *cp_gtk_get_state_oid (JNIEnv *, jobject, struct state_table *, jint); +void *cp_gtk_remove_state_oid (JNIEnv *, jobject, struct state_table *, jint); + +/* highlevel api */ +int cp_gtk_set_state (JNIEnv *, jobject, struct state_table *, void *); +void *cp_gtk_get_state (JNIEnv *, jobject, struct state_table *); +void *cp_gtk_remove_state_slot (JNIEnv *, jobject, struct state_table *); + +#endif diff --git a/libjava/classpath/native/jni/classpath/primlib.c b/libjava/classpath/native/jni/classpath/primlib.c new file mode 100644 index 00000000000..e6773ba5353 --- /dev/null +++ b/libjava/classpath/native/jni/classpath/primlib.c @@ -0,0 +1,724 @@ +/* primlib.c + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <jnilink.h> +#include <primlib.h> +#include <jcl.h> + +static jclass nativeWrapClass[PRIMLIB_NUMTYPES] = + { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static jclass nativeTypeClass[PRIMLIB_NUMTYPES] = + { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static jmethodID nativeWrapClassConstructor[PRIMLIB_NUMTYPES] = + { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static jmethodID nativeWrapClassAccessor[PRIMLIB_NUMTYPES] = + { NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static const char *nativeWrapClassName[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "java/lang/Boolean", + "java/lang/Byte", + "java/lang/Character", + "java/lang/Short", + "java/lang/Integer", + "java/lang/Long", + "java/lang/Float", + "java/lang/Double", + "java/lang/Void", + NULL +}; + +static const char *nativeWrapClassConstructorSig[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "(Z)V", + "(B)V", + "(C)V", + "(S)V", + "(I)V", + "(J)V", + "(F)V", + "(D)V", + "()V", + NULL +}; + +static const char *nativeWrapClassAccessorName[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "booleanValue", + "byteValue", + "charValue", + "shortValue", + "intValue", + "longValue", + "floatValue", + "doubleValue", + NULL, + NULL +}; + +static const char *nativeWrapClassAccessorSig[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "()Z", + "()B", + "()C", + "()S", + "()I", + "()J", + "()F", + "()D", + NULL, + NULL +}; + + +JNIEXPORT jclass JNICALL +PRIMLIB_GetNativeWrapClass (JNIEnv * env, int reflectType) +{ + return LINK_LinkClass (env, nativeWrapClass[reflectType], + nativeWrapClassName[reflectType]); +} + +static jclass +ActuallyGetNativeTypeClass (JNIEnv * env, int reflectType) +{ + jclass wrapClass; + jfieldID typeField; + + wrapClass = PRIMLIB_GetNativeWrapClass (env, reflectType); + if (wrapClass == NULL) + return NULL; + typeField = + (*env)->GetStaticFieldID (env, wrapClass, "TYPE", "Ljava/lang/Class"); + if (typeField == NULL) + return NULL; + return (*env)->GetStaticObjectField (env, wrapClass, typeField); +} + +JNIEXPORT jclass JNICALL +PRIMLIB_GetNativeTypeClass (JNIEnv * env, int reflectType) +{ + return LINK_LinkKnownClass (env, nativeTypeClass[reflectType], + ActuallyGetNativeTypeClass (env, reflectType)); +} + +JNIEXPORT jmethodID JNICALL +PRIMLIB_GetNativeWrapClassConstructor (JNIEnv * env, int reflectType) +{ + PRIMLIB_GetNativeWrapClass (env, reflectType); + return LINK_LinkConstructor (env, nativeWrapClassConstructor[reflectType], + nativeWrapClass[reflectType], + nativeWrapClassConstructorSig[reflectType]); +} + +JNIEXPORT jmethodID JNICALL +PRIMLIB_GetNativeWrapClassAccessor (JNIEnv * env, int reflectType) +{ + PRIMLIB_GetNativeWrapClass (env, reflectType); + return LINK_LinkMethod (env, nativeWrapClassAccessor[reflectType], + nativeWrapClass[reflectType], + nativeWrapClassAccessorName[reflectType], + nativeWrapClassAccessorSig[reflectType]); +} + + + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapBoolean (JNIEnv * env, jboolean b) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_BOOLEAN); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BOOLEAN), + construct, b); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapByte (JNIEnv * env, jbyte b) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_BYTE); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE), + construct, b); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapChar (JNIEnv * env, jchar c) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_CHAR); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR), + construct, c); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapShort (JNIEnv * env, jshort s) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_SHORT); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT), + construct, s); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapInt (JNIEnv * env, jint i) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_INT); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT), + construct, i); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapLong (JNIEnv * env, jlong l) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_LONG); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_LONG), + construct, l); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapFloat (JNIEnv * env, jfloat f) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_FLOAT); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_FLOAT), + construct, f); +} + +JNIEXPORT jobject JNICALL +PRIMLIB_WrapDouble (JNIEnv * env, jdouble d) +{ + jmethodID construct = + PRIMLIB_GetNativeWrapClassConstructor (env, PRIMLIB_DOUBLE); + JCL_RETHROW_EXCEPTION (env); + return (*env)->NewObject (env, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_DOUBLE), + construct, d); +} + + +JNIEXPORT jboolean JNICALL +PRIMLIB_UnwrapBoolean (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BOOLEAN))) + { + return PRIMLIB_GetBooleanObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return JNI_FALSE; + } +} + +JNIEXPORT jbyte JNICALL +PRIMLIB_UnwrapByte (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jshort JNICALL +PRIMLIB_UnwrapShort (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT))) + { + return PRIMLIB_GetShortObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return (jshort) PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jchar JNICALL +PRIMLIB_UnwrapChar (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR))) + { + return PRIMLIB_GetCharObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jint JNICALL +PRIMLIB_UnwrapInt (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT))) + { + return PRIMLIB_GetIntObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT))) + { + return (jint) PRIMLIB_GetShortObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR))) + { + return (jint) PRIMLIB_GetCharObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return (jint) PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jlong JNICALL +PRIMLIB_UnwrapLong (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, PRIMLIB_GetNativeWrapClass (env, PRIMLIB_LONG))) + { + return PRIMLIB_GetLongObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT))) + { + return (jlong) PRIMLIB_GetIntObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT))) + { + return (jlong) PRIMLIB_GetShortObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR))) + { + return (jlong) PRIMLIB_GetCharObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return (jlong) PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jfloat JNICALL +PRIMLIB_UnwrapFloat (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_FLOAT))) + { + return PRIMLIB_GetFloatObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_LONG))) + { + return (jfloat) PRIMLIB_GetLongObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT))) + { + return (jfloat) PRIMLIB_GetIntObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT))) + { + return (jfloat) PRIMLIB_GetShortObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR))) + { + return (jfloat) PRIMLIB_GetCharObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return (jfloat) PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jdouble JNICALL +PRIMLIB_UnwrapDouble (JNIEnv * env, jobject obj) +{ + if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_DOUBLE))) + { + return PRIMLIB_GetDoubleObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_FLOAT))) + { + return (jdouble) PRIMLIB_GetFloatObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_LONG))) + { + return (jdouble) PRIMLIB_GetLongObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT))) + { + return (jdouble) PRIMLIB_GetIntObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT))) + { + return (jdouble) PRIMLIB_GetShortObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR))) + { + return (jdouble) PRIMLIB_GetCharObjectValue (env, obj); + } + else if ((*env)-> + IsInstanceOf (env, obj, + PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE))) + { + return (jdouble) PRIMLIB_GetByteObjectValue (env, obj); + } + else + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct type."); + return 0; + } +} + +JNIEXPORT jint JNICALL +PRIMLIB_GetReflectiveWrapperType (JNIEnv * env, jobject obj) +{ + jclass typeClass; + if (obj == NULL) + { + return PRIMLIB_NULL; + } + + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_DOUBLE); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_DOUBLE; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_FLOAT); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_FLOAT; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_LONG); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_LONG; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_INT); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_INT; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_CHAR); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_CHAR; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_SHORT); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_SHORT; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BYTE); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_BYTE; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_BOOLEAN); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_BOOLEAN; + } + typeClass = PRIMLIB_GetNativeWrapClass (env, PRIMLIB_VOID); + if ((*env)->IsInstanceOf (env, obj, typeClass)) + { + return PRIMLIB_VOID; + } + return PRIMLIB_OBJECT; +} + +JNIEXPORT jint JNICALL +PRIMLIB_GetReflectiveType (JNIEnv * env, jclass returnType) +{ + jclass typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_DOUBLE); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_DOUBLE; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_FLOAT); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_FLOAT; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_LONG); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_LONG; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_INT); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_INT; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_CHAR); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_CHAR; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_SHORT); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_SHORT; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_BYTE); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_BYTE; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_BOOLEAN); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_BOOLEAN; + } + typeClass = PRIMLIB_GetNativeTypeClass (env, PRIMLIB_VOID); + if ((*env)->IsAssignableFrom (env, returnType, typeClass)) + { + return PRIMLIB_VOID; + } + return PRIMLIB_OBJECT; +} + + +JNIEXPORT jboolean JNICALL +PRIMLIB_GetBooleanObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_BOOLEAN); + return (*env)->CallBooleanMethod (env, obj, acc); +} + +JNIEXPORT jbyte JNICALL +PRIMLIB_GetByteObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_BYTE); + return (*env)->CallByteMethod (env, obj, acc); +} + +JNIEXPORT jshort JNICALL +PRIMLIB_GetShortObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_SHORT); + return (*env)->CallShortMethod (env, obj, acc); +} + +JNIEXPORT jchar JNICALL +PRIMLIB_GetCharObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_CHAR); + return (*env)->CallCharMethod (env, obj, acc); +} + +JNIEXPORT jint JNICALL +PRIMLIB_GetIntObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_INT); + return (*env)->CallIntMethod (env, obj, acc); +} + +JNIEXPORT jlong JNICALL +PRIMLIB_GetLongObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_LONG); + return (*env)->CallLongMethod (env, obj, acc); +} + +JNIEXPORT jfloat JNICALL +PRIMLIB_GetFloatObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_FLOAT); + return (*env)->CallFloatMethod (env, obj, acc); +} + +JNIEXPORT jdouble JNICALL +PRIMLIB_GetDoubleObjectValue (JNIEnv * env, jobject obj) +{ + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor (env, PRIMLIB_DOUBLE); + return (*env)->CallDoubleMethod (env, obj, acc); +} + + + +JNIEXPORT jvalue JNICALL +PRIMLIB_UnwrapJValue (JNIEnv * env, jobject obj, jclass classType) +{ + jvalue retval; + jint objType = PRIMLIB_GetReflectiveType (env, classType); + if (objType == PRIMLIB_BOOLEAN) + { + retval.z = PRIMLIB_UnwrapBoolean (env, obj); + } + else if (objType == PRIMLIB_BYTE) + { + retval.b = PRIMLIB_UnwrapByte (env, obj); + } + else if (objType == PRIMLIB_CHAR) + { + retval.c = PRIMLIB_UnwrapChar (env, obj); + } + else if (objType == PRIMLIB_SHORT) + { + retval.s = PRIMLIB_UnwrapShort (env, obj); + } + else if (objType == PRIMLIB_INT) + { + retval.i = PRIMLIB_UnwrapInt (env, obj); + } + else if (objType == PRIMLIB_LONG) + { + retval.j = PRIMLIB_UnwrapLong (env, obj); + } + else if (objType == PRIMLIB_FLOAT) + { + retval.f = PRIMLIB_UnwrapFloat (env, obj); + } + else if (objType == PRIMLIB_DOUBLE) + { + retval.d = PRIMLIB_UnwrapDouble (env, obj); + } + else + { + if (obj != NULL && !(*env)->IsInstanceOf (env, obj, classType)) + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Argument not of correct object type."); + return retval; + } + retval.l = obj; + } + return retval; +} diff --git a/libjava/classpath/native/jni/classpath/primlib.h b/libjava/classpath/native/jni/classpath/primlib.h new file mode 100644 index 00000000000..3cdaaa4a148 --- /dev/null +++ b/libjava/classpath/native/jni/classpath/primlib.h @@ -0,0 +1,119 @@ +/* primlib.h + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef __PRIMLIB_H__ +#define __PRIMLIB_H__ + +#include <jni.h> + +#define PRIMLIB_UNKNOWN 0 +#define PRIMLIB_OBJECT 1 +#define PRIMLIB_BOOLEAN 2 +#define PRIMLIB_BYTE 3 +#define PRIMLIB_CHAR 4 +#define PRIMLIB_SHORT 5 +#define PRIMLIB_INT 6 +#define PRIMLIB_LONG 7 +#define PRIMLIB_FLOAT 8 +#define PRIMLIB_DOUBLE 9 +#define PRIMLIB_VOID 10 +#define PRIMLIB_NULL 11 +#define PRIMLIB_NUMTYPES 12 + +/* Low-level primitive class accessor functions. */ +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeWrapClass (JNIEnv * env, + int reflectType); +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeTypeClass (JNIEnv * env, + int reflectType); +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassConstructor (JNIEnv * + env, + int + reflectType); +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassAccessor (JNIEnv * env, + int + reflectType); + +/* Type discovery functions: WrapperType finds out j.l.Boolean/Byte/etc., and + Type finds out j.l.Boolean.TYPE, etc. +*/ +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveWrapperType (JNIEnv * env, + jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveType (JNIEnv * env, + jclass returnType); + +/* Constructor functions. */ +JNIEXPORT jobject JNICALL PRIMLIB_WrapBoolean (JNIEnv * env, jboolean b); +JNIEXPORT jobject JNICALL PRIMLIB_WrapByte (JNIEnv * env, jbyte b); +JNIEXPORT jobject JNICALL PRIMLIB_WrapChar (JNIEnv * env, jchar c); +JNIEXPORT jobject JNICALL PRIMLIB_WrapShort (JNIEnv * env, jshort s); +JNIEXPORT jobject JNICALL PRIMLIB_WrapInt (JNIEnv * env, jint i); +JNIEXPORT jobject JNICALL PRIMLIB_WrapLong (JNIEnv * env, jlong l); +JNIEXPORT jobject JNICALL PRIMLIB_WrapFloat (JNIEnv * env, jfloat f); +JNIEXPORT jobject JNICALL PRIMLIB_WrapDouble (JNIEnv * env, jdouble d); + +/* Widening conversion unwrapping functions. */ +JNIEXPORT jboolean JNICALL PRIMLIB_UnwrapBoolean (JNIEnv * env, jobject obj); +JNIEXPORT jbyte JNICALL PRIMLIB_UnwrapByte (JNIEnv * env, jobject obj); +JNIEXPORT jshort JNICALL PRIMLIB_UnwrapShort (JNIEnv * env, jobject obj); +JNIEXPORT jchar JNICALL PRIMLIB_UnwrapChar (JNIEnv * env, jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_UnwrapInt (JNIEnv * env, jobject obj); +JNIEXPORT jlong JNICALL PRIMLIB_UnwrapLong (JNIEnv * env, jobject obj); +JNIEXPORT jfloat JNICALL PRIMLIB_UnwrapFloat (JNIEnv * env, jobject obj); +JNIEXPORT jdouble JNICALL PRIMLIB_UnwrapDouble (JNIEnv * env, jobject obj); + +/* Simple unwrapping functions. Objects *must* be of correct type. */ +JNIEXPORT jboolean JNICALL PRIMLIB_GetBooleanObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jbyte JNICALL PRIMLIB_GetByteObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jshort JNICALL PRIMLIB_GetShortObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jchar JNICALL PRIMLIB_GetCharObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_GetIntObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jlong JNICALL PRIMLIB_GetLongObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jfloat JNICALL PRIMLIB_GetFloatObjectValue (JNIEnv * env, + jobject obj); +JNIEXPORT jdouble JNICALL PRIMLIB_GetDoubleObjectValue (JNIEnv * env, + jobject obj); + +/* jvalue conversion: Unwrap obj to the type of classType, with widening conversion. */ +JNIEXPORT jvalue JNICALL PRIMLIB_UnwrapJValue (JNIEnv * env, jobject obj, + jclass classType); + +#endif diff --git a/libjava/classpath/native/jni/gtk-peer/.cvsignore b/libjava/classpath/native/jni/gtk-peer/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/gtk-peer/Makefile.am b/libjava/classpath/native/jni/gtk-peer/Makefile.am new file mode 100644 index 00000000000..f4e7bdfcce1 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/Makefile.am @@ -0,0 +1,61 @@ +pkglib_LTLIBRARIES = libgtkpeer.la + +# Gtk/Cairo JNI sources. +if GTK_CAIRO + gtk_cairo_c_source_files = \ + gnu_java_awt_peer_gtk_GdkGraphics2D.c +else + gtk_cairo_c_source_files = +endif + +libgtkpeer_la_SOURCES = $(gtk_cairo_c_source_files) \ + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c \ + gnu_java_awt_peer_gtk_GdkFontPeer.c \ + gnu_java_awt_peer_gtk_GdkGraphics.c \ + gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c \ + gnu_java_awt_peer_gtk_GdkPixbufDecoder.c \ + gnu_java_awt_peer_gtk_GdkRobotPeer.c \ + gnu_java_awt_peer_gtk_GdkTextLayout.c \ + gnu_java_awt_peer_gtk_GtkButtonPeer.c \ + gnu_java_awt_peer_gtk_GtkCanvasPeer.c \ + gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c \ + gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer.c \ + gnu_java_awt_peer_gtk_GtkCheckboxPeer.c \ + gnu_java_awt_peer_gtk_GtkChoicePeer.c \ + gnu_java_awt_peer_gtk_GtkClipboard.c \ + gnu_java_awt_peer_gtk_GtkComponentPeer.c \ + gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c \ + gnu_java_awt_peer_gtk_GtkFileDialogPeer.c \ + gnu_java_awt_peer_gtk_GtkFramePeer.c \ + gnu_java_awt_peer_gtk_GtkGenericPeer.c \ + gnu_java_awt_peer_gtk_GtkImage.c \ + gnu_java_awt_peer_gtk_GtkLabelPeer.c \ + gnu_java_awt_peer_gtk_GtkListPeer.c \ + gnu_java_awt_peer_gtk_GtkMenuBarPeer.c \ + gnu_java_awt_peer_gtk_GtkMenuComponentPeer.c \ + gnu_java_awt_peer_gtk_GtkMenuItemPeer.c \ + gnu_java_awt_peer_gtk_GtkMenuPeer.c \ + gnu_java_awt_peer_gtk_GtkPanelPeer.c \ + gnu_java_awt_peer_gtk_GtkPopupMenuPeer.c \ + gnu_java_awt_peer_gtk_GtkScrollbarPeer.c \ + gnu_java_awt_peer_gtk_GtkScrollPanePeer.c \ + gnu_java_awt_peer_gtk_GtkTextAreaPeer.c \ + gnu_java_awt_peer_gtk_GtkTextFieldPeer.c \ + gnu_java_awt_peer_gtk_GtkToolkit.c \ + gnu_java_awt_peer_gtk_GtkWindowPeer.c \ + gthread-jni.c \ + gdkfont.h \ + gthread-jni.h \ + gtkcairopeer.h \ + gtkpeer.h + +libgtkpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/native_state.lo \ + $(top_builddir)/native/jni/classpath/jcl.lo + +AM_LDFLAGS = @CLASSPATH_MODULE@ @GTK_LIBS@ @CAIRO_LIBS@ @PANGOFT2_LIBS@ @X_LIBS@ -lXtst +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ + +# Just the WARNING_CFLAGS. We cannot use the strict flags since the gtk +# headers contain broken prototypes (by design, see gtkitemfactory.h). +AM_CFLAGS = @WARNING_CFLAGS@ @ERROR_CFLAGS@ \ + @GTK_CFLAGS@ @CAIRO_CFLAGS@ @PANGOFT2_CFLAGS@ diff --git a/libjava/classpath/native/jni/gtk-peer/gdkfont.h b/libjava/classpath/native/jni/gtk-peer/gdkfont.h new file mode 100644 index 00000000000..cf233301547 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gdkfont.h @@ -0,0 +1,142 @@ +#ifndef __GDKFONT_H__ +#define __GDKFONT_H__ + +/* gdkfont.h -- Some global stuff related to fonts and glyphs + Copyright (C) 2003 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gtkpeer.h" + +#include <pango/pango.h> +#include <pango/pango-context.h> +#include <pango/pango-fontmap.h> +#include <pango/pangoft2.h> + +extern struct state_table *cp_gtk_native_font_state_table; +extern struct state_table *native_glyphvector_state_table; +extern struct state_table *cp_gtk_native_text_layout_state_table; + +#define NSA_FONT_INIT(env, clazz) \ + cp_gtk_native_font_state_table = cp_gtk_init_state_table (env, clazz) + +#define NSA_GET_FONT_PTR(env, obj) \ + cp_gtk_get_state (env, obj, cp_gtk_native_font_state_table) + +#define NSA_SET_FONT_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, cp_gtk_native_font_state_table, (void *)ptr) + +#define NSA_DEL_FONT_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, cp_gtk_native_font_state_table) + + +#define NSA_GV_INIT(env, clazz) \ + native_glyphvector_state_table = cp_gtk_init_state_table (env, clazz) + +#define NSA_GET_GV_PTR(env, obj) \ + cp_gtk_get_state (env, obj, native_glyphvector_state_table) + +#define NSA_SET_GV_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, native_glyphvector_state_table, (void *)ptr) + +#define NSA_DEL_GV_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, native_glyphvector_state_table) + + +#define NSA_TEXT_LAYOUT_INIT(env, clazz) \ + cp_gtk_native_text_layout_state_table = cp_gtk_init_state_table (env, clazz) + +#define NSA_GET_TEXT_LAYOUT_PTR(env, obj) \ + cp_gtk_get_state (env, obj, cp_gtk_native_text_layout_state_table) + +#define NSA_SET_TEXT_LAYOUT_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, cp_gtk_native_text_layout_state_table, (void *)ptr) + +#define NSA_DEL_TEXT_LAYOUT_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, cp_gtk_native_text_layout_state_table) + +#define FONT_METRICS_ASCENT 0 +#define FONT_METRICS_MAX_ASCENT 1 +#define FONT_METRICS_DESCENT 2 +#define FONT_METRICS_MAX_DESCENT 3 +#define FONT_METRICS_MAX_ADVANCE 4 +#define NUM_FONT_METRICS 5 + +#define TEXT_METRICS_X_BEARING 0 +#define TEXT_METRICS_Y_BEARING 1 +#define TEXT_METRICS_WIDTH 2 +#define TEXT_METRICS_HEIGHT 3 +#define TEXT_METRICS_X_ADVANCE 4 +#define TEXT_METRICS_Y_ADVANCE 5 +#define NUM_TEXT_METRICS 6 + +#define NUM_GLYPH_METRICS 10 + +#define GLYPH_LOG_X(i) (NUM_GLYPH_METRICS * (i) ) +#define GLYPH_LOG_Y(i) (NUM_GLYPH_METRICS * (i) + 1) +#define GLYPH_LOG_WIDTH(i) (NUM_GLYPH_METRICS * (i) + 2) +#define GLYPH_LOG_HEIGHT(i) (NUM_GLYPH_METRICS * (i) + 3) + +#define GLYPH_INK_X(i) (NUM_GLYPH_METRICS * (i) + 4) +#define GLYPH_INK_Y(i) (NUM_GLYPH_METRICS * (i) + 5) +#define GLYPH_INK_WIDTH(i) (NUM_GLYPH_METRICS * (i) + 6) +#define GLYPH_INK_HEIGHT(i) (NUM_GLYPH_METRICS * (i) + 7) + +#define GLYPH_POS_X(i) (NUM_GLYPH_METRICS * (i) + 8) +#define GLYPH_POS_Y(i) (NUM_GLYPH_METRICS * (i) + 9) + +struct peerfont +{ + PangoFont *font; + PangoFontDescription *desc; + PangoContext *ctx; + PangoLayout *layout; + /* + * The GdkGraphics2D (using cairo) may store a pointer to a + * cairo_font_t here; since we want to work equally well with + * the GdkGraphics class (using GDK) we do not explicitly mention + * cairo types here; it is up to the higher level driver routine + * in GdkClasspathFontPeer.java to decide which backend functions + * to invoke. + */ + void *graphics_resource; +}; + +struct textlayout +{ + PangoLayout *pango_layout; +}; + +#endif /* __GDKFONT_H__ */ diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c new file mode 100644 index 00000000000..595c1a28a6e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c @@ -0,0 +1,70 @@ +/* Native implementation of functions in GThreadNativeMethodRunner + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h" +#include "gthread-jni.h" + +/* + * Class: GThreadNativeMethodRunner + * Method: nativeRun + * Signature: (J)V + * + * Purpose: Run the C function whose function pointer is + * + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_nativeRun + (JNIEnv *env __attribute__((unused)), + jobject lcl_obj __attribute__((unused)), + jlong funcAddr, jlong funcArg) +{ + /* Convert the function's address back into a pointer to a C function. */ + void *(*funcPtr)(void *) = (void *(*)(void *)) (size_t)funcAddr; + + /* We do not need to worry about the return value from funcPtr(); it's + just thrown away. That is part of the g_threads spec, so no reason + to worry about returning it. */ + (void) funcPtr((void *) (size_t)funcArg); + /* Fall off the end and terminate the thread of control. */ +} + +/* Local Variables: */ +/* c-file-style: "gnu" */ +/* End: */ + + diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c new file mode 100644 index 00000000000..401d62337b3 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c @@ -0,0 +1,418 @@ +/* gnu_java_awt_GdkFont.c + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gdkfont.h" +#include "gnu_java_awt_peer_gtk_GdkFontPeer.h" + +struct state_table *cp_gtk_native_font_state_table; + +enum java_awt_font_style { + java_awt_font_PLAIN = 0, + java_awt_font_BOLD = 1, + java_awt_font_ITALIC = 2 +}; + +enum java_awt_font_baseline { + java_awt_font_ROMAN_BASELINE = 0, + java_awt_font_CENTER_BASELINE = 1, + java_awt_font_HANGING_BASELINE = 2 +}; + +static jmethodID glyphVector_ctor; +static jclass glyphVector_class; +static PangoAttrList *attrs = NULL; + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_initStaticState + (JNIEnv *env, jclass clazz) +{ + NSA_FONT_INIT (env, clazz); + + glyphVector_class = (*env)->FindClass + (env, "gnu/java/awt/peer/gtk/GdkGlyphVector"); + + glyphVector_ctor = (*env)->GetMethodID + (env, glyphVector_class, "<init>", + "([D[ILjava/awt/Font;Ljava/awt/font/FontRenderContext;)V"); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_initState + (JNIEnv *env, jobject self) +{ + struct peerfont *pfont = NULL; + + gdk_threads_enter (); + + g_assert (self != NULL); + pfont = (struct peerfont *) g_malloc0 (sizeof (struct peerfont)); + g_assert (pfont != NULL); + NSA_SET_FONT_PTR (env, self, pfont); + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_dispose + (JNIEnv *env, jobject self) +{ + struct peerfont *pfont = NULL; + + gdk_threads_enter (); + + pfont = (struct peerfont *)NSA_DEL_FONT_PTR (env, self); + g_assert (pfont != NULL); + if (pfont->layout != NULL) + g_object_unref (pfont->font); + if (pfont->font != NULL) + g_object_unref (pfont->font); + if (pfont->ctx != NULL) + g_object_unref (pfont->ctx); + if (pfont->desc != NULL) + pango_font_description_free (pfont->desc); + g_free (pfont); + + gdk_threads_leave (); +} + + +JNIEXPORT jobject JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_getGlyphVector + (JNIEnv *env, jobject self, + jstring chars, + jobject font, + jobject fontRenderContext) +{ + struct peerfont *pfont = NULL; + GList *items = NULL; + GList *i = NULL; + gchar *str = NULL; + int len = 0; + int j = 0; + double *native_extents = NULL; + int *native_codes = NULL; + jintArray java_codes = NULL; + jdoubleArray java_extents = NULL; + + gdk_threads_enter (); + + pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, self); + g_assert (pfont != NULL); + + len = (*cp_gtk_gdk_env())->GetStringUTFLength (env, chars); + str = (gchar *)(*env)->GetStringUTFChars (env, chars, NULL); + g_assert (str != NULL); + + if (attrs == NULL) + attrs = pango_attr_list_new (); + + if (len > 0 && str[len-1] == '\0') + len--; + + items = pango_itemize (pfont->ctx, str, 0, len, attrs, NULL); + + i = g_list_first (items); + + if (i == NULL) + { + gdk_threads_leave (); + + java_extents = (*env)->NewDoubleArray (env, 0); + java_codes = (*env)->NewIntArray (env, 0); + + gdk_threads_enter (); + } + else + { + PangoGlyphString *glyphs; + PangoItem *item = (PangoItem *)i->data; + + pango_context_set_font_description (pfont->ctx, pfont->desc); + pango_context_set_language (pfont->ctx, gtk_get_default_language()); + pango_context_load_font (pfont->ctx, pfont->desc); + + glyphs = pango_glyph_string_new (); + g_assert (glyphs != NULL); + + pango_shape (str + item->offset, item->length, + &(item->analysis), glyphs); + + if (glyphs->num_glyphs > 0) + { + int x = 0; + double scale = ((double) PANGO_SCALE); + + gdk_threads_leave (); + + java_extents = (*env)->NewDoubleArray (env, glyphs->num_glyphs * NUM_GLYPH_METRICS); + java_codes = (*env)->NewIntArray (env, glyphs->num_glyphs); + + gdk_threads_enter (); + + native_extents = (*env)->GetDoubleArrayElements (env, java_extents, NULL); + native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL); + + for (j = 0; j < glyphs->num_glyphs; ++j) + { + PangoRectangle ink; + PangoRectangle logical; + PangoGlyphGeometry *geom = &glyphs->glyphs[j].geometry; + + pango_font_get_glyph_extents (pfont->font, + glyphs->glyphs[j].glyph, + &ink, &logical); + + native_codes[j] = glyphs->glyphs[j].glyph; + + native_extents[ GLYPH_LOG_X(j) ] = (logical.x) / scale; + native_extents[ GLYPH_LOG_Y(j) ] = (- logical.y) / scale; + native_extents[ GLYPH_LOG_WIDTH(j) ] = (logical.width) / scale; + native_extents[ GLYPH_LOG_HEIGHT(j) ] = (logical.height) / scale; + + native_extents[ GLYPH_INK_X(j) ] = (ink.x) / scale; + native_extents[ GLYPH_INK_Y(j) ] = (- ink.y) / scale; + native_extents[ GLYPH_INK_WIDTH(j) ] = (ink.width) / scale; + native_extents[ GLYPH_INK_HEIGHT(j) ] = (ink.height) / scale; + + native_extents[ GLYPH_POS_X(j) ] = (x + geom->x_offset) / scale; + native_extents[ GLYPH_POS_Y(j) ] = ( - geom->y_offset) / scale; + + x += geom->width; + } + (*env)->ReleaseDoubleArrayElements (env, java_extents, native_extents, 0); + (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0); + } + + pango_glyph_string_free (glyphs); + } + + (*env)->ReleaseStringUTFChars (env, chars, str); + + for (i = g_list_first (items); i != NULL; i = g_list_next (i)) + g_free (i->data); + + g_list_free (items); + + gdk_threads_leave (); + + return (*env)->NewObject (env, + glyphVector_class, + glyphVector_ctor, + java_extents, java_codes, + font, fontRenderContext); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_getFontMetrics + (JNIEnv *env, jobject java_font, jdoubleArray java_metrics) +{ + struct peerfont *pfont = NULL; + jdouble *native_metrics = NULL; + PangoFontMetrics *pango_metrics = NULL; + + gdk_threads_enter(); + + pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, java_font); + g_assert (pfont != NULL); + + pango_metrics + = pango_context_get_metrics (pfont->ctx, pfont->desc, + gtk_get_default_language ()); + + native_metrics + = (*env)->GetDoubleArrayElements (env, java_metrics, NULL); + + g_assert (native_metrics != NULL); + + native_metrics[FONT_METRICS_ASCENT] + = PANGO_PIXELS (pango_font_metrics_get_ascent (pango_metrics)); + + native_metrics[FONT_METRICS_MAX_ASCENT] + = native_metrics[FONT_METRICS_ASCENT]; + + native_metrics[FONT_METRICS_DESCENT] + = PANGO_PIXELS (pango_font_metrics_get_descent (pango_metrics)); + + if (native_metrics[FONT_METRICS_DESCENT] < 0) + native_metrics[FONT_METRICS_DESCENT] + = - native_metrics[FONT_METRICS_DESCENT]; + + native_metrics[FONT_METRICS_MAX_DESCENT] + = native_metrics[FONT_METRICS_DESCENT]; + + native_metrics[FONT_METRICS_MAX_ADVANCE] + = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width + (pango_metrics)); + + (*env)->ReleaseDoubleArrayElements (env, + java_metrics, + native_metrics, 0); + + pango_font_metrics_unref (pango_metrics); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_getTextMetrics + (JNIEnv *env, jobject java_font, jstring str, jdoubleArray java_metrics) +{ + struct peerfont *pfont = NULL; + const char *cstr = NULL; + jdouble *native_metrics = NULL; + PangoRectangle log; + + gdk_threads_enter(); + + pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, java_font); + g_assert (pfont != NULL); + + cstr = (*env)->GetStringUTFChars (env, str, NULL); + g_assert(cstr != NULL); + + pango_layout_set_text (pfont->layout, cstr, -1); + pango_layout_get_extents (pfont->layout, NULL, &log); + + (*env)->ReleaseStringUTFChars (env, str, cstr); + pango_layout_set_text (pfont->layout, "", -1); + + native_metrics = (*env)->GetDoubleArrayElements (env, java_metrics, NULL); + g_assert (native_metrics != NULL); + + native_metrics[TEXT_METRICS_X_BEARING] + = PANGO_PIXELS( ((double)log.x) ); + + native_metrics[TEXT_METRICS_Y_BEARING] + = PANGO_PIXELS( ((double)log.y) ); + + native_metrics[TEXT_METRICS_WIDTH] + = PANGO_PIXELS( ((double)log.width) ); + + native_metrics[TEXT_METRICS_HEIGHT] + = PANGO_PIXELS( ((double)log.height) ); + + native_metrics[TEXT_METRICS_X_ADVANCE] + = PANGO_PIXELS( ((double) (log.x + log.width)) ); + + native_metrics[TEXT_METRICS_Y_ADVANCE] + = PANGO_PIXELS( ((double) (log.y + log.height)) ); + + (*env)->ReleaseDoubleArrayElements (env, java_metrics, native_metrics, 0); + + gdk_threads_leave(); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkFontPeer_setFont + (JNIEnv *env, jobject self, jstring family_name_str, jint style_int, jint size, jboolean useGraphics2D) +{ + struct peerfont *pfont = NULL; + char const *family_name = NULL; + enum java_awt_font_style style; + PangoFT2FontMap *ft2_map = NULL; + + gdk_threads_enter (); + + style = (enum java_awt_font_style) style_int; + + g_assert (self != NULL); + pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, self); + g_assert (pfont != NULL); + + if (pfont->ctx != NULL) + g_object_unref (pfont->ctx); + if (pfont->font != NULL) + g_object_unref (pfont->font); + if (pfont->desc != NULL) + pango_font_description_free (pfont->desc); + + pfont->desc = pango_font_description_new (); + g_assert (pfont->desc != NULL); + + family_name = (*env)->GetStringUTFChars(env, family_name_str, 0); + g_assert (family_name != NULL); + pango_font_description_set_family (pfont->desc, family_name); + (*env)->ReleaseStringUTFChars(env, family_name_str, family_name); + + + if (style & java_awt_font_BOLD) + pango_font_description_set_weight (pfont->desc, PANGO_WEIGHT_BOLD); + + if (style & java_awt_font_ITALIC) + pango_font_description_set_style (pfont->desc, PANGO_STYLE_ITALIC); + + if (useGraphics2D) + { + pango_font_description_set_size (pfont->desc, size * PANGO_SCALE); + if (pfont->ctx == NULL) + { + ft2_map = PANGO_FT2_FONT_MAP(pango_ft2_font_map_for_display ()); + pfont->ctx = pango_ft2_font_map_create_context (ft2_map); + } + } + else + { + /* GDK uses a slightly different DPI setting. */ + pango_font_description_set_size (pfont->desc, + size * cp_gtk_dpi_conversion_factor); + if (pfont->ctx == NULL) + pfont->ctx = gdk_pango_context_get(); + } + + g_assert (pfont->ctx != NULL); + + if (pfont->font != NULL) + { + g_object_unref (pfont->font); + pfont->font = NULL; + } + + pango_context_set_font_description (pfont->ctx, pfont->desc); + pango_context_set_language (pfont->ctx, gtk_get_default_language()); + pfont->font = pango_context_load_font (pfont->ctx, pfont->desc); + g_assert (pfont->font != NULL); + + if (pfont->layout == NULL) + pfont->layout = pango_layout_new (pfont->ctx); + g_assert (pfont->layout != NULL); + + gdk_threads_leave (); +} + + diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c new file mode 100644 index 00000000000..9b2f16e7145 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c @@ -0,0 +1,642 @@ +/* gdkgraphics.c + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gdkfont.h" +#include "gnu_java_awt_peer_gtk_GdkGraphics.h" +#include <gdk/gdkprivate.h> +#include <gdk/gdkx.h> + +static jmethodID initComponentGraphicsID; + +void +cp_gtk_graphics_init_jni (void) +{ + jclass gdkgraphics; + + gdkgraphics = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GdkGraphics"); + + initComponentGraphicsID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gdkgraphics, + "initComponentGraphics", + "()V"); +} + +#define GDK_STABLE_IS_PIXMAP(d) (GDK_IS_PIXMAP(d)) + +static GdkPoint *translate_points (JNIEnv *env, jintArray xpoints, + jintArray ypoints, jint npoints, + jint x_offset, jint y_offset); +static void realize_cb (GtkWidget *widget, jobject jgraphics); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_copyState + (JNIEnv *env, jobject obj, jobject old) +{ + struct graphics *g = NULL; + struct graphics *g_old = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) g_malloc (sizeof (struct graphics)); + g_old = (struct graphics *) NSA_GET_PTR (env, old); + + *g = *g_old; + + g->gc = gdk_gc_new (g->drawable); + gdk_gc_copy (g->gc, g_old->gc); + + if (GDK_STABLE_IS_PIXMAP (g->drawable)) + gdk_pixmap_ref (g->drawable); + else /* GDK_IS_WINDOW (g->drawable) */ + gdk_window_ref (g->drawable); + + gdk_colormap_ref (g->cm); + + NSA_SET_PTR (env, obj, g); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__II + (JNIEnv *env, jobject obj, jint width, jint height) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) g_malloc (sizeof (struct graphics)); + g->x_offset = g->y_offset = 0; + + g->drawable = (GdkDrawable *) gdk_pixmap_new (NULL, width, height, + gdk_rgb_get_visual ()->depth); + g->cm = gdk_rgb_get_cmap (); + gdk_colormap_ref (g->cm); + g->gc = gdk_gc_new (g->drawable); + + NSA_SET_PTR (env, obj, g); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_initFromImage + (JNIEnv *env, jobject obj, jobject source) +{ + struct graphics *g = NULL; + GdkPixmap *pixmap = NULL; + + gdk_threads_enter (); + + pixmap = cp_gtk_image_get_pixmap (env, source); + g_assert(pixmap != NULL); + gdk_pixmap_ref (pixmap); + + g = (struct graphics *) g_malloc (sizeof (struct graphics)); + g->x_offset = g->y_offset = 0; + + g->drawable = (GdkDrawable *)pixmap; + + g->cm = gdk_drawable_get_colormap (g->drawable); + gdk_colormap_ref (g->cm); + g->gc = gdk_gc_new (g->drawable); + + NSA_SET_PTR (env, obj, g); + + gdk_threads_leave (); +} + +/* copy the native state of the peer (GtkWidget *) to the native state + of the graphics object */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 + (JNIEnv *env, jobject obj, jobject peer) +{ + struct graphics *g = NULL; + void *ptr = NULL; + GtkWidget *widget = NULL; + GdkColor color; + + gdk_threads_enter (); + + g = (struct graphics *) g_malloc (sizeof (struct graphics)); + ptr = NSA_GET_PTR (env, peer); + g->x_offset = 0; + g->y_offset = 0; + + widget = GTK_WIDGET (ptr); + g->drawable = (GdkDrawable *) widget->window; + + gdk_window_ref (g->drawable); + g->cm = gtk_widget_get_colormap (widget); + gdk_colormap_ref (g->cm); + g->gc = gdk_gc_new (g->drawable); + gdk_gc_copy (g->gc, widget->style->fg_gc[GTK_STATE_NORMAL]); + color = widget->style->fg[GTK_STATE_NORMAL]; + + NSA_SET_PTR (env, obj, g); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_connectSignals + (JNIEnv *env, jobject obj, jobject peer) +{ + void *ptr = NULL; + jobject *gref = NULL; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + ptr = NSA_GET_PTR (env, peer); + + g_signal_connect_after (G_OBJECT (ptr), "realize", + G_CALLBACK (realize_cb), *gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_dispose + (JNIEnv *env, jobject obj) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_DEL_PTR (env, obj); + + /* check if dispose has been called already */ + if (!g) + { + gdk_threads_leave (); + return; + } + + XFlush (GDK_DISPLAY ()); + + gdk_gc_destroy (g->gc); + + if (GDK_STABLE_IS_PIXMAP (g->drawable)) + gdk_pixmap_unref (g->drawable); + else /* GDK_IS_WINDOW (g->drawable) */ + gdk_window_unref (g->drawable); + + gdk_colormap_unref (g->cm); + + g_free (g); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_translateNative + (JNIEnv *env, jobject obj, jint x, jint y) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + g->x_offset += x; + g->y_offset += y; + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawString + (JNIEnv *env, jobject obj, jobject font, jstring str, jint x, jint y) +{ + struct peerfont *pfont = NULL; + struct graphics *g = NULL; + const char *cstr = NULL; + int baseline_y = 0; + PangoLayoutIter *iter = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + g_assert (g != NULL); + + pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, font); + g_assert (pfont != NULL); + + cstr = (*env)->GetStringUTFChars (env, str, NULL); + + pango_layout_set_font_description (pfont->layout, pfont->desc); + pango_layout_set_text (pfont->layout, cstr, -1); + iter = pango_layout_get_iter (pfont->layout); + + baseline_y = pango_layout_iter_get_baseline (iter); + + gdk_draw_layout (g->drawable, g->gc, + x + g->x_offset, + y + g->y_offset - PANGO_PIXELS (baseline_y), + pfont->layout); + + pango_layout_iter_free (iter); + pango_layout_set_text (pfont->layout, "", -1); + + gdk_flush (); + + (*env)->ReleaseStringUTFChars (env, str, cstr); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawLine + (JNIEnv *env, jobject obj, jint x, jint y, jint x2, jint y2) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_line (g->drawable, g->gc, + x + g->x_offset, y + g->y_offset, + x2 + g->x_offset, y2 + g->y_offset); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_fillRect + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_rectangle (g->drawable, g->gc, TRUE, + x + g->x_offset, y + g->y_offset, width, height); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawRect + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_rectangle (g->drawable, g->gc, FALSE, + x + g->x_offset, y + g->y_offset, width, height); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_copyArea + (JNIEnv *env, jobject obj, jint x, jint y, + jint width, jint height, jint dx, jint dy) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_window_copy_area ((GdkWindow *)g->drawable, + g->gc, + x + g->x_offset + dx, y + g->y_offset + dy, + (GdkWindow *)g->drawable, + x + g->x_offset, y + g->y_offset, + width, height); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_clearRect + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + GdkGCValues saved; + GtkWidget *widget = NULL; + union widget_union w; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + if (!g) + { + gdk_threads_leave (); + return; + } + + if (GDK_IS_WINDOW (g->drawable)) + { + w.widget = &widget; + gdk_window_get_user_data (GDK_WINDOW (g->drawable), w.void_widget); + if (widget == NULL || !GTK_IS_EVENT_BOX (widget)) + gdk_window_clear_area ((GdkWindow *) g->drawable, + x + g->x_offset, y + g->y_offset, + width, height); + } + else + { + gdk_gc_get_values (g->gc, &saved); + gdk_gc_set_foreground (g->gc, &(saved.background)); + gdk_draw_rectangle (g->drawable, g->gc, TRUE, + x + g->x_offset, y + g->y_offset, width, height); + gdk_gc_set_foreground (g->gc, &(saved.foreground)); + } + + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_setFunction + (JNIEnv *env, jobject obj, jint func) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_gc_set_function (g->gc, func); + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_setFGColor + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + struct graphics *g = NULL; + + gdk_threads_enter (); + + color.red = red << 8; + color.green = green << 8; + color.blue = blue << 8; + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_color_alloc (g->cm, &color); + gdk_gc_set_foreground (g->gc, &color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawArc + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height, + jint angle1, jint angle2) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_arc (g->drawable, g->gc, FALSE, + x + g->x_offset, y + g->y_offset, + width, height, angle1 << 6, angle2 << 6); + gdk_flush (); + + gdk_threads_leave (); +} + +static GdkPoint * +translate_points (JNIEnv *env, jintArray xpoints, jintArray ypoints, + jint npoints, jint x_offset, jint y_offset) +{ + GdkPoint *points; + jint *x, *y; + int i; + + /* allocate one more point than necessary, in case we need to tack + on an extra due to the semantics of Java polygons. */ + points = g_malloc (sizeof (GdkPoint) * (npoints + 1)); + + x = (*env)->GetIntArrayElements (env, xpoints, NULL); + y = (*env)->GetIntArrayElements (env, ypoints, NULL); + + for (i = 0; i < npoints; i++) + { + points[i].x = x[i] + x_offset; + points[i].y = y[i] + y_offset; + } + + (*env)->ReleaseIntArrayElements (env, xpoints, x, JNI_ABORT); + (*env)->ReleaseIntArrayElements (env, ypoints, y, JNI_ABORT); + + return points; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawPolyline + (JNIEnv *env, jobject obj, jintArray xpoints, jintArray ypoints, + jint npoints) +{ + struct graphics *g = NULL; + GdkPoint *points = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + points = translate_points (env, xpoints, ypoints, npoints, + g->x_offset, g->y_offset); + + gdk_draw_lines (g->drawable, g->gc, points, npoints); + gdk_flush (); + + g_free (points); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawPolygon + (JNIEnv *env, jobject obj, jintArray xpoints, jintArray ypoints, + jint npoints) +{ + struct graphics *g = NULL; + GdkPoint *points = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + points = translate_points (env, xpoints, ypoints, npoints, + g->x_offset, g->y_offset); + + /* make sure the polygon is closed, per Java semantics. + if it's not, we close it. */ + if (points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y) + points[npoints++] = points[0]; + + gdk_draw_lines (g->drawable, g->gc, points, npoints); + gdk_flush (); + + g_free (points); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_fillPolygon + (JNIEnv *env, jobject obj, jintArray xpoints, jintArray ypoints, + jint npoints) +{ + struct graphics *g = NULL; + GdkPoint *points = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + points = translate_points (env, xpoints, ypoints, npoints, + g->x_offset, g->y_offset); + gdk_draw_polygon (g->drawable, g->gc, TRUE, points, npoints); + gdk_flush (); + + g_free (points); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_fillArc + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height, + jint angle1, jint angle2) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_arc (g->drawable, g->gc, TRUE, + x + g->x_offset, y + g->y_offset, + width, height, angle1 << 6, angle2 << 6); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_drawOval + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_arc (g->drawable, g->gc, FALSE, + x + g->x_offset, y + g->y_offset, + width, height, 0, 23040); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_fillOval + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + gdk_draw_arc (g->drawable, g->gc, TRUE, + x + g->x_offset, y + g->y_offset, + width, height, 0, 23040); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics_setClipRectangle + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + struct graphics *g = NULL; + GdkRectangle rectangle; + + gdk_threads_enter (); + + g = (struct graphics *) NSA_GET_PTR (env, obj); + + rectangle.x = x + g->x_offset; + rectangle.y = y + g->y_offset; + rectangle.width = width; + rectangle.height = height; + + gdk_gc_set_clip_rectangle (g->gc, &rectangle); + + gdk_threads_leave (); +} + +static void +realize_cb (GtkWidget *widget __attribute__ ((unused)), jobject jgraphics) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), jgraphics, initComponentGraphicsID); + + NSA_DEL_GLOBAL_REF (cp_gtk_gdk_env(), jgraphics); + + gdk_threads_enter (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c new file mode 100644 index 00000000000..b4bd676e7b9 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c @@ -0,0 +1,1881 @@ +/* gnu_java_awt_peer_gtk_GdkGraphics2d.c + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gtkcairopeer.h" +#include "gdkfont.h" +#include "gnu_java_awt_peer_gtk_GdkGraphics2D.h" +#include <gdk/gdktypes.h> +#include <gdk/gdkprivate.h> +#include <gdk/gdkx.h> +#include <X11/extensions/Xrender.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk-pixbuf/gdk-pixdata.h> + +#include <cairo-ft.h> +#include <cairo-xlib.h> + +#include <stdio.h> +#include <stdlib.h> + +static jmethodID initComponentGraphics2DID; + +void +cp_gtk_graphics2d_init_jni (void) +{ + jclass gdkgraphics2d; + + gdkgraphics2d = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GdkGraphics2D"); + + initComponentGraphics2DID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gdkgraphics2d, + "initComponentGraphics2D", + "()V"); +} + +static struct state_table *native_graphics2d_state_table; + +#define NSA_G2D_INIT(env, clazz) \ + native_graphics2d_state_table = cp_gtk_init_state_table (env, clazz) + +#define NSA_GET_G2D_PTR(env, obj) \ + cp_gtk_get_state (env, obj, native_graphics2d_state_table) + +#define NSA_SET_G2D_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, native_graphics2d_state_table, (void *)ptr) + +#define NSA_DEL_G2D_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, native_graphics2d_state_table) + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initStaticState + (JNIEnv *env, jclass clazz) +{ + gdk_threads_enter(); + + NSA_G2D_INIT (env, clazz); + + gdk_threads_leave(); +} + +/* these public final constants are part of the java2d public API, so we + write them explicitly here to save fetching them from the constant pool + all the time. */ + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +enum java_awt_alpha_composite_rule + { + java_awt_alpha_composite_CLEAR = 1, + java_awt_alpha_composite_SRC = 2, + java_awt_alpha_composite_SRC_OVER = 3, + java_awt_alpha_composite_DST_OVER = 4, + java_awt_alpha_composite_SRC_IN = 5, + java_awt_alpha_composite_DST_IN = 6, + java_awt_alpha_composite_SRC_OUT = 7, + java_awt_alpha_composite_DST_OUT = 8, + java_awt_alpha_composite_DST = 9, + java_awt_alpha_composite_SRC_ATOP = 10, + java_awt_alpha_composite_DST_ATOP = 11, + java_awt_alpha_composite_XOR = 12 + }; + +enum java_awt_basic_stroke_join_rule + { + java_awt_basic_stroke_JOIN_MITER = 0, + java_awt_basic_stroke_JOIN_ROUND = 1, + java_awt_basic_stroke_JOIN_BEVEL = 2 + }; + +enum java_awt_basic_stroke_cap_rule + { + java_awt_basic_stroke_CAP_BUTT = 0, + java_awt_basic_stroke_CAP_ROUND = 1, + java_awt_basic_stroke_CAP_SQUARE = 2 + }; + +enum java_awt_geom_path_iterator_winding_rule + { + java_awt_geom_path_iterator_WIND_EVEN_ODD = 0, + java_awt_geom_path_iterator_WIND_NON_ZERO = 1 + }; + +enum java_awt_rendering_hints_filter + { + java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR = 0, + java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR = 1, + java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED = 2, + java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY = 3, + java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT = 4 + + }; + +static int +peer_is_disposed(JNIEnv *env, jobject obj) +{ + static jfieldID fid = NULL; + jclass cls; + jobject peer; + + return 0; + + if (fid == NULL) + { + cls = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, cls, "component", + "Lgnu/java/awt/peer/gtk/GtkComponentPeer;"); + } + g_assert(fid != NULL); + peer = (*env)->GetObjectField(env, obj, fid); + if (peer == NULL || NSA_GET_PTR (env, peer) != NULL) + return 0; + else + { + return 1; + } +} + + +static void +grab_current_drawable (GtkWidget *widget, GdkDrawable **draw, GdkWindow **win) +{ + g_assert (widget != NULL); + g_assert (draw != NULL); + g_assert (win != NULL); + + *win = widget->window; + + *draw = *win; + gdk_window_get_internal_paint_info (*win, draw, 0, 0); + g_object_ref (*draw); +} + + +static int +x_server_has_render_extension (void) +{ + int ev = 0, err = 0; + return (int) XRenderQueryExtension (GDK_DISPLAY (), &ev, &err); +} + +static void +init_graphics2d_as_pixbuf (struct graphics2d *gr) +{ + gint width, height; + gint bits_per_sample = 8; + gint total_channels = 4; + gboolean has_alpha = TRUE; + + g_assert (gr != NULL); + g_assert (gr->drawable != NULL); + + if (gr->debug) printf ("initializing graphics2d as pixbuf\n"); + gdk_drawable_get_size (gr->drawable, &width, &height); + gr->drawbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + has_alpha, bits_per_sample, + width, height); + g_assert (gr->drawbuf != NULL); + g_assert (gdk_pixbuf_get_bits_per_sample (gr->drawbuf) == bits_per_sample); + g_assert (gdk_pixbuf_get_n_channels (gr->drawbuf) == total_channels); + + gr->surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (gr->drawbuf), + CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width (gr->drawbuf), + gdk_pixbuf_get_height (gr->drawbuf), + gdk_pixbuf_get_rowstride (gr->drawbuf)); + g_assert (gr->surface != NULL); + gr->mode = MODE_DRAWABLE_NO_RENDER; + if (gr->cr != NULL) + cairo_destroy (gr->cr); + gr->cr = cairo_create (gr->surface); +} + +static void +init_graphics2d_as_renderable (struct graphics2d *gr) +{ + Drawable draw; + Display * dpy; + Visual * vis; + + g_assert (gr != NULL); + g_assert (gr->drawable != NULL); + + gr->drawbuf = NULL; + + if (gr->debug) printf ("initializing graphics2d as renderable\n"); + draw = gdk_x11_drawable_get_xid (gr->drawable); + + dpy = gdk_x11_drawable_get_xdisplay (gr->drawable); + g_assert (dpy != NULL); + + vis = gdk_x11_visual_get_xvisual (gdk_drawable_get_visual (gr->drawable)); + g_assert (vis != NULL); + + gr->surface = cairo_xlib_surface_create (dpy, draw, vis, gr->width, gr->height); + g_assert (gr->surface != NULL); + gr->mode = MODE_DRAWABLE_WITH_RENDER; + if (gr->cr != NULL) + cairo_destroy (gr->cr); + gr->cr = cairo_create (gr->surface); +} + +static void +begin_drawing_operation (JNIEnv *env, struct graphics2d * gr) +{ + g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS); + + switch (gr->mode) + { + case MODE_DRAWABLE_WITH_RENDER: + break; + + case MODE_DRAWABLE_NO_RENDER: + { + + gint drawable_width, drawable_height; + gint pixbuf_width, pixbuf_height; + gint width, height; + + gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height); + pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf); + pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf); + width = min (drawable_width, pixbuf_width); + height = min (drawable_height, pixbuf_height); + + gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */ + gr->drawable, + NULL, /* colormap */ + 0, 0, 0, 0, + width, height); + + if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n", + width, height); + } + break; + + case MODE_JAVA_ARRAY: + { + jboolean isCopy; + gr->javabuf = (*env)->GetPrimitiveArrayCritical (env, gr->jarray, &isCopy); + gr->isCopy |= isCopy; + if (gr->isCopy) + { + /* Make sure that the pixel buffer copy is already initalized, + i.e. we already failed to get direct access in initState. */ + g_assert (gr->javabuf_copy != NULL); + memcpy (gr->javabuf_copy, gr->javabuf, gr->width * gr->height * 4); + } + } + break; + } +} + +static void +end_drawing_operation (JNIEnv *env, struct graphics2d * gr) +{ + g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS); + + switch (gr->mode) + { + case MODE_DRAWABLE_WITH_RENDER: + break; + + case MODE_DRAWABLE_NO_RENDER: + { + + gint drawable_width, drawable_height; + gint pixbuf_width, pixbuf_height; + gint width, height; + + gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height); + pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf); + pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf); + width = min (drawable_width, pixbuf_width); + height = min (drawable_height, pixbuf_height); + + gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf, + 0, 0, 0, 0, + width, height, + GDK_RGB_DITHER_NORMAL, 0, 0); + + if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n", + width, height); + } + break; + + case MODE_JAVA_ARRAY: + if (gr->isCopy) + memcpy (gr->javabuf, gr->javabuf_copy, gr->width * gr->height * 4); + (*env)->ReleasePrimitiveArrayCritical (env, gr->jarray, gr->javabuf, JNI_COMMIT); + } +} + + +static void +update_pattern_transform (struct graphics2d *gr) +{ + cairo_matrix_t mat; + + g_assert (gr != NULL); + if (gr->pattern == NULL) + return; + + cairo_get_matrix (gr->cr, &mat); + cairo_pattern_set_matrix (gr->pattern, &mat); +} + +static void +check_for_debug (struct graphics2d *gr) +{ + gr->debug = (gboolean)(getenv("DEBUGJ2D") != NULL); +} + +static void +realize_cb (GtkWidget *widget __attribute__ ((unused)), jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, initComponentGraphics2DID); + + gdk_threads_enter (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState + (JNIEnv *env, jobject obj, jobject old) +{ + struct graphics2d *g = NULL, *g_old = NULL; + + gdk_threads_enter(); + + g = (struct graphics2d *) g_malloc (sizeof (struct graphics2d)); + g_assert (g != NULL); + memset (g, 0, sizeof(struct graphics2d)); + + g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old); + g_assert (g_old != NULL); + + if (g_old->debug) printf ("copying state from existing graphics2d\n"); + + g->debug = g_old->debug; + g->mode = g_old->mode; + + g->width = g_old->width; + g->height = g_old->height; + + if (g_old->mode == MODE_JAVA_ARRAY) + { + jint size = g->width * g->height * 4; + + g->jarray = (*env)->NewGlobalRef (env, g_old->jarray); + g->javabuf = (*env)->GetIntArrayElements (env, g->jarray, &g->isCopy); + g->isCopy = JNI_TRUE; + g->javabuf_copy = (jint *) g_malloc (size); + memcpy (g->javabuf_copy, g->javabuf, size); + g->surface = cairo_image_surface_create_for_data ((unsigned char *) g->javabuf, + CAIRO_FORMAT_ARGB32, + g->width, + g->height, + g->width * 4); + g_assert (g->surface != NULL); + g->cr = cairo_create (g->surface); + g_assert (g->cr != NULL); + (*env)->ReleaseIntArrayElements (env, g->jarray, g->javabuf, JNI_ABORT); + } + else + { + g->drawable = g_old->drawable; + g_object_ref (g->drawable); + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (g); + else + init_graphics2d_as_pixbuf (g); + } + + if (g->pattern) + cairo_pattern_set_filter (g->pattern, CAIRO_FILTER_FAST); + + NSA_SET_G2D_PTR (env, obj, g); + + gdk_threads_leave(); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState___3III +(JNIEnv *env, jobject obj, jintArray jarr, jint width, jint height) +{ + struct graphics2d *gr = NULL; + jint *cairobuf = NULL; + + gdk_threads_enter(); + + gr = (struct graphics2d *) g_malloc (sizeof (struct graphics2d)); + g_assert (gr != NULL); + memset (gr, 0, sizeof(struct graphics2d)); + + check_for_debug (gr); + + if (gr->debug) printf ("constructing java-backed image of size (%d,%d)\n", + width, height); + + gr->width = width; + gr->height = height; + gr->jarray = (*env)->NewGlobalRef(env, jarr); + gr->javabuf = (*env)->GetPrimitiveArrayCritical (env, gr->jarray, &gr->isCopy); + if (gr->isCopy) + { + /* We didn't get direct access to the pixel buffer, so we'll have to + maintain a separate copy for Cairo. */ + jint size = gr->width * gr->height * 4; + gr->javabuf_copy = (jint *) g_malloc (size); + memcpy (gr->javabuf_copy, gr->javabuf, size); + cairobuf = gr->javabuf_copy; + } + else + { + /* Have Cairo write directly to the Java array. */ + cairobuf = gr->javabuf; + } + gr->surface = cairo_image_surface_create_for_data ((unsigned char *) cairobuf, + CAIRO_FORMAT_ARGB32, + gr->width, + gr->height, + gr->width * 4); + g_assert (gr->surface != NULL); + gr->cr = cairo_create (gr->surface); + g_assert (gr->cr != NULL); + (*env)->ReleasePrimitiveArrayCritical (env, gr->jarray, gr->javabuf, JNI_COMMIT); + + gr->mode = MODE_JAVA_ARRAY; + + if (gr->debug) printf ("constructed java-backed image of size (%d,%d)\n", + width, height); + + NSA_SET_G2D_PTR (env, obj, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__II + (JNIEnv *env, jobject obj, jint width, jint height) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + gr = (struct graphics2d *) g_malloc (sizeof (struct graphics2d)); + g_assert (gr != NULL); + memset (gr, 0, sizeof(struct graphics2d)); + + check_for_debug (gr); + + if (gr->debug) printf ("constructing offscreen drawable of size (%d,%d)\n", + width, height); + + gr->drawable = (GdkDrawable *) gdk_pixmap_new (NULL, width, height, + gdk_rgb_get_visual ()->depth); + g_assert (gr->drawable != NULL); + + gr->width = width; + gr->height = height; + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (gr); + else + init_graphics2d_as_pixbuf (gr); + + if (gr->debug) printf ("constructed offscreen drawable of size (%d,%d)\n", + width, height); + NSA_SET_G2D_PTR (env, obj, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable + (JNIEnv *env, jobject self, jobject other, jint x, jint y) +{ + struct graphics2d *src = NULL; + struct graphics2d *dst = NULL; + gint s_height; + gint s_width; + gint d_height; + gint d_width; + gint height; + gint width; + cairo_matrix_t matrix; + cairo_operator_t tmp_op; + + gdk_threads_enter(); + + if (peer_is_disposed(env, self)) + { + gdk_threads_leave(); + return; + } + + src = (struct graphics2d *)NSA_GET_G2D_PTR (env, other); + dst = (struct graphics2d *)NSA_GET_G2D_PTR (env, self); + g_assert (src != NULL); + g_assert (dst != NULL); + + if (src->debug) printf ("copying from offscreen drawable\n"); + + begin_drawing_operation(env, dst); + + /* gdk_flush(); */ + + gdk_drawable_get_size (src->drawable, &s_width, &s_height); + gdk_drawable_get_size (dst->drawable, &d_width, &d_height); + width = min (s_width, d_width); + height = min (s_height, d_height); + + cairo_get_matrix (src->cr, &matrix); + cairo_matrix_translate (&matrix, (double)-x, (double)-y); + if (src->pattern) + cairo_pattern_set_matrix (src->pattern, &matrix); + tmp_op = cairo_get_operator (dst->cr); + cairo_set_operator(dst->cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (dst->cr, src->surface, 0, 0); + cairo_paint (dst->cr); + cairo_set_operator(dst->cr, tmp_op); + + cairo_matrix_translate (&matrix, (double)x, (double)y); + if (src->pattern) + cairo_pattern_set_matrix (src->pattern, &matrix); + + gdk_flush(); + + end_drawing_operation(env, dst); + + if (src->debug) printf ("copied %d x %d pixels from offscreen drawable\n", width, height); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 + (JNIEnv *env, jobject obj, jobject peer) +{ + struct graphics2d *gr = NULL; + GtkWidget *widget = NULL; + void *ptr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + ptr = NSA_GET_PTR (env, peer); + g_assert (ptr != NULL); + + gr = (struct graphics2d *) g_malloc (sizeof (struct graphics2d)); + g_assert (gr != NULL); + memset (gr, 0, sizeof(struct graphics2d)); + + check_for_debug (gr); + + widget = GTK_WIDGET (ptr); + g_assert (widget != NULL); + + grab_current_drawable (widget, &(gr->drawable), &(gr->win)); + g_assert (gr->drawable != NULL); + + gr->width = widget->allocation.width; + gr->height = widget->allocation.height; + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (gr); + else + init_graphics2d_as_pixbuf (gr); + + NSA_SET_G2D_PTR (env, obj, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_connectSignals + (JNIEnv *env, jobject obj, jobject peer) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, peer); + + g_signal_connect_after (G_OBJECT (ptr), "realize", + G_CALLBACK (realize_cb), obj); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + gr = (struct graphics2d *) NSA_DEL_G2D_PTR (env, obj); + + if (gr == NULL) + { + gdk_threads_leave(); + return; /* dispose has been called more than once */ + } + + if (gr->surface) + cairo_surface_destroy (gr->surface); + + cairo_destroy (gr->cr); + + if (gr->drawbuf) + g_object_unref (gr->drawbuf); + + if (gr->drawable) + g_object_unref (gr->drawable); + + if (gr->pattern) + cairo_pattern_destroy (gr->pattern); + + if (gr->pattern_surface) + cairo_surface_destroy (gr->pattern_surface); + + if (gr->pattern_pixels) + g_free (gr->pattern_pixels); + + if (gr->mode == MODE_JAVA_ARRAY) + { + (*env)->DeleteGlobalRef (env, gr->jarray); + if (gr->javabuf_copy) + g_free (gr->javabuf_copy); + } + + if (gr->debug) printf ("disposed of graphics2d\n"); + + g_free (gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient + (JNIEnv *env, jobject obj, + jdouble x1, jdouble y1, + jdouble x2, jdouble y2, + jint r1, jint g1, jint b1, jint a1, + jint r2, jint g2, jint b2, jint a2, + jboolean cyclic) +{ + struct graphics2d *gr = NULL; + cairo_surface_t *surf = NULL; + cairo_t *cr2 = NULL; + cairo_matrix_t mat; + + gdk_threads_enter(); + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + if (gr->debug) printf ("setGradient (%f,%f) -> (%f,%f); (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n", + x1, y1, + x2, y2, + r1, g1, b1, a1, + r2, g2, b2, a2); + + if (cyclic) + surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 3, 2); + else + surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 2, 2); + g_assert (surf != NULL); + + cr2 = cairo_create (surf); + + cairo_identity_matrix (cr2); + + cairo_set_source_rgba (cr2, r1 / 255.0, g1 / 255.0, b1 / 255.0, a1 / 255.0); + cairo_rectangle (cr2, 0, 0, 1, 2); + cairo_fill (cr2); + + cairo_set_source_rgba (cr2, r2 / 255.0, g2 / 255.0, b2 / 255.0, a2 / 255.0); + cairo_rectangle (cr2, 1, 0, 1, 2); + cairo_fill (cr2); + + if (cyclic) + { + cairo_set_source_rgba (cr2, r1 / 255.0, g1 / 255.0, b1 / 255.0, a1 / 255.0); + cairo_rectangle (cr2, 2, 0, 1, 2); + cairo_fill (cr2); + } + + cairo_matrix_init_identity (&mat); + + /* + consider the vector [x2 - x1, y2 - y1] = [p,q] + + this is a line in space starting at an 'origin' x1, y1. + + it can also be thought of as a "transformed" unit vector in either the + x or y directions. we have just *drawn* our gradient as a unit vector + (well, a 2-3x unit vector) in the x dimension. so what we want to know + is which transformation turns our existing unit vector into [p,q]. + + which means solving for M in + + [p,q] = M[1,0] + + [p,q] = |a b| [1,0] + |c d| + + [p,q] = [a,c], with b = d = 0. + + what does this mean? it means that our gradient is 1-dimensional; as + you move through the x axis of our 2 or 3 pixel gradient from logical + x positions 0 to 1, the transformation of your x coordinate under the + matrix M causes you to accumulate both x and y values in fill + space. the y value of a gradient coordinate is ignored, since the + gradient is one dimensional. which is correct. + + unfortunately we want the opposite transformation, it seems, because of + the way cairo is going to use this transformation. I'm a bit confused by + that, but it seems to work right, so we take reciprocals of values and + negate offsets. oh well. + + */ + { + double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1)); + double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1)); + double dx = (x1 == 0.) ? 0. : 1. / x1; + double dy = (y1 == 0.) ? 0. : 1. / y1; + cairo_pattern_t *p; + + cairo_matrix_init (&mat, + a, 0., + c, 0., + dx, dy); + + p = cairo_pattern_create_for_surface (surf); + cairo_pattern_set_matrix (p, &mat); + cairo_pattern_set_filter (p, CAIRO_FILTER_BILINEAR); + } + + /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */ + /* cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */ + + if (gr->pattern) + cairo_pattern_destroy (gr->pattern); + + if (gr->pattern_surface) + cairo_surface_destroy (gr->pattern_surface); + + if (gr->pattern_pixels) + g_free (gr->pattern_pixels); + + gr->pattern_pixels = NULL; + gr->pattern_surface = surf; + gr->pattern = cairo_pattern_create_for_surface(surf); + + cairo_set_source (gr->cr, gr->pattern); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setTexturePixels + (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride) +{ + struct graphics2d *gr = NULL; + jint *jpixels = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (gr->debug) printf ("setTexturePixels (%d pixels, %dx%d, stride: %d)\n", + (*env)->GetArrayLength (env, jarr), w, h, stride); + + if (gr->pattern) + cairo_pattern_destroy (gr->pattern); + + if (gr->pattern_surface) + cairo_surface_destroy (gr->pattern_surface); + + if (gr->pattern_pixels) + g_free (gr->pattern_pixels); + + gr->pattern = NULL; + gr->pattern_surface = NULL; + gr->pattern_pixels = NULL; + + gr->pattern_pixels = (char *) g_malloc (h * stride * 4); + g_assert (gr->pattern_pixels != NULL); + + jpixels = (*env)->GetIntArrayElements (env, jarr, NULL); + g_assert (jpixels != NULL); + memcpy (gr->pattern_pixels, jpixels, h * stride * 4); + (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0); + + gr->pattern_surface = cairo_image_surface_create_for_data ((unsigned char *)gr->pattern_pixels, + CAIRO_FORMAT_ARGB32, + w, h, stride * 4); + g_assert (gr->pattern_surface != NULL); + cairo_pattern_set_extend (gr->pattern, 1); + gr->pattern = cairo_pattern_create_for_surface (gr->pattern_surface); + g_assert (gr->pattern != NULL); + cairo_set_source (gr->cr, gr->pattern); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels + (JNIEnv *env, jobject obj, jintArray java_pixels, + jint w, jint h, jint stride, jdoubleArray java_matrix) +{ + struct graphics2d *gr = NULL; + jint *native_pixels = NULL; + jdouble *native_matrix = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (gr->debug) printf ("drawPixels (%d pixels, %dx%d, stride: %d)\n", + (*env)->GetArrayLength (env, java_pixels), w, h, stride); + + native_pixels = (*env)->GetIntArrayElements (env, java_pixels, NULL); + native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL); + g_assert (native_pixels != NULL); + g_assert (native_matrix != NULL); + g_assert ((*env)->GetArrayLength (env, java_matrix) == 6); + + begin_drawing_operation (env, gr); + + { + cairo_matrix_t mat; + cairo_pattern_t *p; + cairo_surface_t *surf = cairo_image_surface_create_for_data ((unsigned char *)native_pixels, + CAIRO_FORMAT_ARGB32, + w, h, stride * 4); + cairo_matrix_init_identity (&mat); + cairo_matrix_init (&mat, + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); + + p = cairo_pattern_create_for_surface (surf); + cairo_pattern_set_matrix (p, &mat); + if (gr->pattern) + cairo_pattern_set_filter (p, cairo_pattern_get_filter (gr->pattern)); + cairo_set_source (gr->cr, p); + cairo_paint (gr->cr); + cairo_pattern_destroy (p); + cairo_surface_destroy (surf); + } + + end_drawing_operation (env, gr); + + (*env)->ReleaseIntArrayElements (env, java_pixels, native_pixels, 0); + (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0); + + gdk_threads_leave(); +} + +/* passthrough methods to cairo */ + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSave + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_save\n"); + cairo_save (gr->cr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRestore + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_restore\n"); + cairo_restore (gr->cr); + update_pattern_transform (gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMatrix + (JNIEnv *env, jobject obj, jdoubleArray java_matrix) +{ + struct graphics2d *gr = NULL; + jdouble *native_matrix = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + + /* cairoSetMatrix was called before this graphics object's component + was realized. */ + if (gr == NULL) + { + gdk_threads_leave (); + return; + } + + native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL); + g_assert (native_matrix != NULL); + g_assert ((*env)->GetArrayLength (env, java_matrix) == 6); + + if (gr->debug) printf ("cairo_set_matrix [ %f, %f, %f, %f, %f, %f ]\n", + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); + + { + cairo_matrix_t mat; + + cairo_matrix_init_identity (&mat); + cairo_matrix_init (&mat, + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); + cairo_set_matrix (gr->cr, &mat); + } + + (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0); + update_pattern_transform (gr); + + gdk_threads_leave(); +} + +static void +install_font_peer(cairo_t *cr, + struct peerfont *pfont, + int debug) +{ + cairo_font_face_t *ft; + FT_Face face = NULL; + + g_assert(cr != NULL); + g_assert(pfont != NULL); + + if (pfont->graphics_resource == NULL) + { + face = pango_ft2_font_get_face (pfont->font); + g_assert (face != NULL); + + ft = cairo_ft_font_face_create_for_ft_face (face, 0); + g_assert (ft != NULL); + + if (debug) printf ("install_font_peer made new cairo font for '%s' at %f\n", + face->family_name, + (pango_font_description_get_size (pfont->desc) / + (double)PANGO_SCALE)); + + cairo_set_font_face (cr, ft); + cairo_font_face_destroy (ft); + cairo_set_font_size (cr, + (pango_font_description_get_size (pfont->desc) / + (double)PANGO_SCALE)); + ft = cairo_get_font_face (cr); + pfont->graphics_resource = ft; + } + else + { + if (debug) printf ("install_font_peer reused existing font resource\n"); + ft = (cairo_font_face_t *) pfont->graphics_resource; + cairo_set_font_face (cr, ft); + } +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_releasePeerGraphicsResource + (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject java_font) +{ + struct peerfont *pfont = NULL; + + gdk_threads_enter(); + + g_assert(java_font != NULL); + + pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, java_font); + g_assert (pfont != NULL); + if (pfont->graphics_resource != NULL) + { + cairo_font_face_destroy ((cairo_font_face_t *) pfont->graphics_resource); + pfont->graphics_resource = NULL; + } + + gdk_threads_leave(); +} + +static void +paint_glyph_run(JNIEnv *env, + struct graphics2d *gr, + cairo_glyph_t **glyphs, + gint *n_glyphs, + PangoLayoutRun *run) +{ + gint i = 0; + gint x = 0, y = 0; + + g_assert (gr != NULL); + g_assert (glyphs != NULL); + g_assert (n_glyphs != NULL); + g_assert (run != NULL); + + if (run->glyphs != NULL && run->glyphs->num_glyphs > 0) + { + if (*n_glyphs < run->glyphs->num_glyphs) + { + *glyphs = g_realloc(*glyphs, + (sizeof(cairo_glyph_t) + * run->glyphs->num_glyphs)); + *n_glyphs = run->glyphs->num_glyphs; + } + + g_assert (*glyphs != NULL); + + if (gr->debug) printf ("painting %d glyphs: ", run->glyphs->num_glyphs); + + for (i = 0; i < run->glyphs->num_glyphs; ++i) + { + (*glyphs)[i].index = run->glyphs->glyphs[i].glyph; + + (*glyphs)[i].x = + ((double) (x + run->glyphs->glyphs[i].geometry.x_offset)) + / ((double) PANGO_SCALE); + + (*glyphs)[i].y = + ((double) (y + run->glyphs->glyphs[i].geometry.y_offset)) + / ((double) PANGO_SCALE); + + if (gr->debug) printf(" (%ld @ %f,%f)", + (*glyphs)[i].index, + (*glyphs)[i].x, + (*glyphs)[i].y); + + x += run->glyphs->glyphs[i].geometry.width; + } + + if (gr->debug) printf("\n"); + begin_drawing_operation (env, gr); + cairo_show_glyphs (gr->cr, *glyphs, run->glyphs->num_glyphs); + end_drawing_operation (env, gr); + } +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGlyphVector + (JNIEnv *env, jobject self, + jobject font, + jfloat x, jfloat y, jint n, + jintArray java_codes, + jfloatArray java_positions) +{ + + struct graphics2d *gr = NULL; + struct peerfont *pfont = NULL; + cairo_glyph_t *glyphs = NULL; + int *native_codes; + float *native_positions; + jint i = 0; + + gdk_threads_enter (); + + g_assert (self != NULL); + g_assert (java_codes != NULL); + g_assert (java_positions != NULL); + + if (peer_is_disposed(env, self)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self); + g_assert (gr != NULL); + + pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, font); + g_assert (pfont != NULL); + + install_font_peer(gr->cr, pfont, gr->debug); + + glyphs = g_malloc( sizeof(cairo_glyph_t) * n); + g_assert (glyphs != NULL); + + native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL); + native_positions = (*env)->GetFloatArrayElements (env, java_positions, NULL); + + for (i = 0; i < n; ++i) + { + glyphs[i].index = native_codes[i]; + glyphs[i].x = x + native_positions[ 2*i ]; + glyphs[i].y = y + native_positions[ 2*i + 1]; + } + + (*env)->ReleaseFloatArrayElements (env, java_positions, native_positions, 0); + (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0); + + begin_drawing_operation (env, gr); + cairo_show_glyphs (gr->cr, glyphs, n); + end_drawing_operation (env, gr); + + g_free(glyphs); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout + (JNIEnv *env, jobject self, jobject java_layout, jfloat x, jfloat y) +{ + /* + * FIXME: Some day we expect either cairo or pango will know how to make + * a pango layout paint to a cairo surface. that day is not yet here. + */ + + struct graphics2d *gr = NULL; + struct textlayout *tl = NULL; + PangoLayoutIter *i = NULL; + PangoLayoutRun *run = NULL; + cairo_glyph_t *glyphs = NULL; + gint n_glyphs = 0; + + gdk_threads_enter (); + + g_assert (self != NULL); + g_assert (java_layout != NULL); + + gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self); + tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, java_layout); + + g_assert (gr != NULL); + g_assert (tl != NULL); + g_assert (tl->pango_layout != NULL); + + if (gr->debug) printf ("painting pango layout\n"); + + if (peer_is_disposed(env, self)) + { + gdk_threads_leave(); + return; + } + + i = pango_layout_get_iter (tl->pango_layout); + g_assert (i != NULL); + + cairo_translate (gr->cr, x, y); + + do + { + run = pango_layout_iter_get_run (i); + if (run != NULL) + paint_glyph_run (env, gr, &glyphs, &n_glyphs, run); + } + while (pango_layout_iter_next_run (i)); + + if (glyphs != NULL) + g_free (glyphs); + + cairo_translate (gr->cr, -x, -y); + + pango_layout_iter_free (i); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetOperator + (JNIEnv *env, jobject obj, jint op) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_operator %d\n", op); + switch ((enum java_awt_alpha_composite_rule) op) + { + case java_awt_alpha_composite_CLEAR: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_CLEAR); + break; + + case java_awt_alpha_composite_SRC: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_SOURCE); + break; + + case java_awt_alpha_composite_SRC_OVER: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER); + break; + + case java_awt_alpha_composite_DST_OVER: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DEST_OVER); + break; + + case java_awt_alpha_composite_SRC_IN: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN); + break; + + case java_awt_alpha_composite_DST_IN: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DEST_IN); + break; + + case java_awt_alpha_composite_SRC_OUT: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT); + break; + + case java_awt_alpha_composite_DST_OUT: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DEST_OUT); + break; + + case java_awt_alpha_composite_DST: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DEST); + break; + + case java_awt_alpha_composite_SRC_ATOP: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP); + break; + + case java_awt_alpha_composite_DST_ATOP: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DEST_ATOP); + break; + + case java_awt_alpha_composite_XOR: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_XOR); + break; + } + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetRGBAColor + (JNIEnv *env, jobject obj, jdouble r, jdouble g, jdouble b, jdouble a) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + /* this is a very weird fact: GDK Pixbufs and RENDER drawables consider + colors in opposite pixel order. I have no idea why. thus when you + draw to a PixBuf, you must exchange the R and B components of your + color. */ + + if (gr->debug) printf ("cairo_set_source_rgb (%f, %f, %f)\n", r, g, b); + + if (gr->drawbuf) + cairo_set_source_rgba (gr->cr, b, g, r, a); + else + cairo_set_source_rgba (gr->cr, r, g, b, a); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetFillRule + (JNIEnv *env, jobject obj, jint rule) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + if (gr->debug) printf ("cairo_set_fill_rule %d\n", rule); + g_assert (gr != NULL); + switch ((enum java_awt_geom_path_iterator_winding_rule) rule) + { + case java_awt_geom_path_iterator_WIND_NON_ZERO: + cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_WINDING); + break; + case java_awt_geom_path_iterator_WIND_EVEN_ODD: + cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_EVEN_ODD); + break; + } + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineWidth + (JNIEnv *env, jobject obj, jdouble width) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + return; + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_width %f\n", width); + cairo_set_line_width (gr->cr, width); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineCap + (JNIEnv *env, jobject obj, jint cap) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_cap %d\n", cap); + switch ((enum java_awt_basic_stroke_cap_rule) cap) + { + case java_awt_basic_stroke_CAP_BUTT: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_BUTT); + break; + + case java_awt_basic_stroke_CAP_ROUND: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_ROUND); + break; + + case java_awt_basic_stroke_CAP_SQUARE: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_SQUARE); + break; + } + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineJoin + (JNIEnv *env, jobject obj, jint join) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_join %d\n", join); + switch ((enum java_awt_basic_stroke_join_rule) join) + { + case java_awt_basic_stroke_JOIN_MITER: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_MITER); + break; + + case java_awt_basic_stroke_JOIN_ROUND: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_ROUND); + break; + + case java_awt_basic_stroke_JOIN_BEVEL: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_BEVEL); + break; + } + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetDash + (JNIEnv *env, jobject obj, jdoubleArray dashes, jint ndash, jdouble offset) +{ + struct graphics2d *gr = NULL; + jdouble *dasharr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_dash\n"); + dasharr = (*env)->GetDoubleArrayElements (env, dashes, NULL); + g_assert (dasharr != NULL); + cairo_set_dash (gr->cr, dasharr, ndash, offset); + (*env)->ReleaseDoubleArrayElements (env, dashes, dasharr, 0); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMiterLimit + (JNIEnv *env, jobject obj, jdouble miter) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_miter_limit %f\n", miter); + cairo_set_miter_limit (gr->cr, miter); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoNewPath + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + + if (gr == NULL) + { + gdk_threads_leave (); + return; + } + + if (gr->debug) printf ("cairo_new_path\n"); + cairo_new_path (gr->cr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoMoveTo + (JNIEnv *env, jobject obj, jdouble x, jdouble y) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_move_to (%f, %f)\n", x, y); + cairo_move_to (gr->cr, x, y); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoLineTo + (JNIEnv *env, jobject obj, jdouble x, jdouble y) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_line_to (%f, %f)\n", x, y); + cairo_line_to (gr->cr, x, y); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoCurveTo + (JNIEnv *env, jobject obj, jdouble x1, jdouble y1, jdouble x2, jdouble y2, jdouble x3, jdouble y3) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_curve_to (%f, %f), (%f, %f), (%f, %f)\n", x1, y1, x2, y2, x3, y3); + cairo_curve_to (gr->cr, x1, y1, x2, y2, x3, y3); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelMoveTo + (JNIEnv *env, jobject obj, jdouble dx, jdouble dy) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_move_to (%f, %f)\n", dx, dy); + cairo_rel_move_to (gr->cr, dx, dy); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelLineTo + (JNIEnv *env, jobject obj, jdouble dx, jdouble dy) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_line_to (%f, %f)\n", dx, dy); + cairo_rel_line_to (gr->cr, dx, dy); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelCurveTo + (JNIEnv *env, jobject obj, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dx3, jdouble dy3) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_curve_to (%f, %f), (%f, %f), (%f, %f)\n", dx1, dy1, dx2, dy2, dx3, dy3); + cairo_rel_curve_to (gr->cr, dx1, dy1, dx2, dy2, dx3, dy3); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRectangle + (JNIEnv *env, jobject obj, jdouble x, jdouble y, jdouble width, jdouble height) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + + if (gr == NULL) + { + gdk_threads_leave (); + return; + } + + if (gr->debug) printf ("cairo_rectangle (%f, %f) (%f, %f)\n", x, y, width, height); + cairo_rectangle (gr->cr, x, y, width, height); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClosePath + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_close_path\n"); + cairo_close_path (gr->cr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoStroke + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_stroke\n"); + begin_drawing_operation (env, gr); + cairo_stroke (gr->cr); + end_drawing_operation (env, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoFill + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_fill\n"); + begin_drawing_operation (env, gr); + cairo_fill (gr->cr); + end_drawing_operation (env, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClip + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave(); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + + if (gr == NULL) + { + gdk_threads_leave (); + return; + } + + if (gr->debug) printf ("cairo_clip\n"); + begin_drawing_operation (env, gr); + cairo_reset_clip (gr->cr); + cairo_clip (gr->cr); + end_drawing_operation (env, gr); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSurfaceSetFilter + (JNIEnv *env, jobject obj, jint filter) +{ + struct graphics2d *gr = NULL; + + gdk_threads_enter(); + + if (peer_is_disposed(env, obj)) + { + gdk_threads_leave (); + return; + } + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_surface_set_filter %d\n", filter); + switch ((enum java_awt_rendering_hints_filter) filter) + { + case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR: + cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_NEAREST); + break; + case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR: + cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_BILINEAR); + break; + case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED: + cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_FAST); + break; + case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT: + cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_NEAREST); + break; + case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY: + cairo_pattern_set_filter (gr->pattern, CAIRO_FILTER_BEST); + break; + } + + gdk_threads_leave(); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c new file mode 100644 index 00000000000..0467c3c7acd --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c @@ -0,0 +1,102 @@ +/* gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gdkfont.h" +#include "gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.h" + + +static gint +cmp_families (const void *a, const void *b) +{ + const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a); + const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b); + + return g_utf8_collate (a_name, b_name); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphicsEnvironment_nativeGetFontFamilies +(JNIEnv *env, jobject self __attribute__((unused)), jobjectArray family_name) +{ + PangoContext *context = NULL; + PangoFontFamily **families = NULL; + int n_families = 0; + int idx = 0; + + gdk_threads_enter (); + + context = gdk_pango_context_get(); + g_assert (context != NULL); + + pango_context_list_families (context, &families, &n_families); + + qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families); + + for (idx = 0; idx < n_families; idx++) + { + const char *name_tmp = pango_font_family_get_name (families[idx]); + jstring name = (*env)->NewStringUTF (env, name_tmp); + (*env)->SetObjectArrayElement (env, family_name, idx, name); + } + g_free (families); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GdkGraphicsEnvironment_nativeGetNumFontFamilies +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + PangoContext *context = NULL; + PangoFontFamily **families = NULL; + gint n_families = 0; + gint num = 0; + + gdk_threads_enter (); + + context = gdk_pango_context_get(); + g_assert (context != NULL); + + pango_context_list_families (context, &families, &n_families); + + num = n_families; + g_free (families); + + gdk_threads_leave (); + + return num; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c new file mode 100644 index 00000000000..648cd6603d1 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c @@ -0,0 +1,515 @@ +/* gdkpixbufdecoder.c + Copyright (C) 1999, 2003, 2004, 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 <gtkpeer.h> +#include <gdk/gdk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk-pixbuf/gdk-pixbuf-loader.h> + +#include <jni.h> +#include <jcl.h> +#include "native_state.h" +#include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h" + +#include <string.h> +#include <stdlib.h> + +static struct state_table *native_pixbufdecoder_state_table; + +#define NSA_PB_INIT(env, clazz) \ + native_pixbufdecoder_state_table = cp_gtk_init_state_table (env, clazz) + +#define NSA_GET_PB_PTR(env, obj) \ + cp_gtk_get_state (env, obj, native_pixbufdecoder_state_table) + +#define NSA_SET_PB_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr) + +#define NSA_DEL_PB_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, native_pixbufdecoder_state_table) + +/* Union used for type punning. */ +union env_union +{ + void **void_env; + JNIEnv **jni_env; +}; + +static JavaVM *vm; + +static jmethodID areaPreparedID; +static jmethodID areaUpdatedID; +static jmethodID dataOutputWriteID; +static jmethodID registerFormatID; + +static void +area_prepared_cb (GdkPixbufLoader *loader, + jobject *decoder) +{ + JNIEnv *env = NULL; + union env_union e; + jint width = 0; + jint height = 0; + GdkPixbuf *pixbuf = NULL; + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + g_assert (pixbuf != NULL); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + g_assert (decoder != NULL); + + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + + gdk_threads_leave (); + + (*env)->CallVoidMethod (env, + *decoder, + areaPreparedID, + width, height); + + gdk_threads_enter (); +} + +static void +area_updated_cb (GdkPixbufLoader *loader, + gint x, gint y, + gint width, gint height, + jobject *decoder) +{ + JNIEnv *env; + union env_union e; + jint stride_bytes, stride_pixels, n_channels, n_pixels; + jintArray jpixels; + jint *java_pixels; + guchar *gdk_pixels; + + GdkPixbuf *pixbuf_no_alpha = NULL; + GdkPixbuf *pixbuf = NULL; + +#ifndef WORDS_BIGENDIAN + int i; +#endif + + pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf_no_alpha == NULL) + return; + + pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0); + g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + stride_bytes = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + stride_pixels = stride_bytes / n_channels; + n_pixels = height * stride_pixels; + gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); + + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + + gdk_threads_leave (); + + jpixels = (*env)->NewIntArray (env, n_pixels); + + gdk_threads_enter (); + + java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL); + + memcpy (java_pixels, + gdk_pixels + (y * stride_bytes), + (height * stride_bytes)); + +#ifndef WORDS_BIGENDIAN + /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */ + for (i = 0; i < n_pixels; ++i) + { + java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]); + } +#endif + + g_object_unref (pixbuf); + + gdk_threads_leave (); + + (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0); + + (*env)->CallVoidMethod (env, + *decoder, + areaUpdatedID, + (jint) x, (jint) y, + (jint) width, (jint) height, + jpixels, + stride_pixels); + + (*env)->DeleteLocalRef(env, jpixels); + + gdk_threads_enter (); +} + +static void +closed_cb (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder) +{ + JNIEnv *env; + union env_union e; + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + + gdk_threads_leave (); + + (*env)->DeleteGlobalRef (env, *decoder); + g_free (decoder); + + gdk_threads_enter (); +} + + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState + (JNIEnv *env, jobject obj) +{ + GdkPixbufLoader *loader = NULL; + jobject *decoder = NULL; + + gdk_threads_enter (); + + decoder = (jobject *) g_malloc (sizeof (jobject)); + g_assert (decoder != NULL); + *decoder = (*env)->NewGlobalRef (env, obj); + + loader = gdk_pixbuf_loader_new (); + g_assert (loader != NULL); + g_signal_connect (loader, "area-prepared", G_CALLBACK (area_prepared_cb), decoder); + g_signal_connect (loader, "area-updated", G_CALLBACK (area_updated_cb), decoder); + g_signal_connect (loader, "closed", G_CALLBACK (closed_cb), decoder); + + NSA_SET_PB_PTR (env, obj, loader); + + gdk_threads_leave (); +} + +static void +query_formats (JNIEnv *env, jclass clazz) +{ + jobject jformat; + GSList *formats, *f; + GdkPixbufFormat *format; + char **ch, *name; + + jclass formatClass; + jmethodID addExtensionID; + jmethodID addMimeTypeID; + jobject string; + + formatClass = (*env)->FindClass + (env, "gnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec"); + + g_assert(formatClass != NULL); + + addExtensionID = (*env)->GetMethodID (env, formatClass, + "addExtension", + "(Ljava/lang/String;)V"); + + addMimeTypeID = (*env)->GetMethodID (env, formatClass, + "addMimeType", + "(Ljava/lang/String;)V"); + + formats = gdk_pixbuf_get_formats (); + + for (f = formats; f; f = f->next) + { + format = (GdkPixbufFormat *) f->data; + name = gdk_pixbuf_format_get_name(format); + + string = (*env)->NewStringUTF(env, name); + g_assert(string != NULL); + + jformat = (*env)->CallStaticObjectMethod + (env, clazz, registerFormatID, string, + (jboolean) gdk_pixbuf_format_is_writable(format)); + (*env)->DeleteLocalRef(env, string); + + g_assert(jformat != NULL); + + ch = gdk_pixbuf_format_get_extensions(format); + while (*ch) + { + string = (*env)->NewStringUTF(env, *ch); + g_assert(string != NULL); + (*env)->CallVoidMethod (env, jformat, addExtensionID, string); + (*env)->DeleteLocalRef(env, string); + ++ch; + } + + ch = gdk_pixbuf_format_get_mime_types(format); + while (*ch) + { + string = (*env)->NewStringUTF(env, *ch); + g_assert(string != NULL); + (*env)->CallVoidMethod (env, jformat, addMimeTypeID, string); + (*env)->DeleteLocalRef(env, string); + ++ch; + } + } + + g_slist_free(formats); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState + (JNIEnv *env, jclass clazz) +{ + jclass dataOutputClass; + + (*env)->GetJavaVM(env, &vm); + + areaPreparedID = (*env)->GetMethodID (env, clazz, + "areaPrepared", + "(II)V"); + + areaUpdatedID = (*env)->GetMethodID (env, clazz, + "areaUpdated", + "(IIII[II)V"); + + registerFormatID = (*env)->GetStaticMethodID + (env, clazz, + "registerFormat", + "(Ljava/lang/String;Z)" + "Lgnu/java/awt/peer/gtk/GdkPixbufDecoder$ImageFormatSpec;"); + + + dataOutputClass = (*env)->FindClass(env, "java/io/DataOutput"); + dataOutputWriteID = (*env)->GetMethodID (env, dataOutputClass, + "write", "([B)V"); + + query_formats (env, clazz); + + NSA_PB_INIT (env, clazz); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish +(JNIEnv *env, jobject obj, jboolean needs_close) +{ + GdkPixbufLoader *loader = NULL; + + gdk_threads_enter (); + + loader = (GdkPixbufLoader *)NSA_DEL_PB_PTR (env, obj); + if (loader == NULL) + return; + + if (needs_close) + gdk_pixbuf_loader_close (loader, NULL); + g_object_unref (loader); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpDone +(JNIEnv *env, jobject obj) +{ + GError *err = NULL; + GdkPixbufLoader *loader = NULL; + + gdk_threads_enter (); + + loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj); + g_assert (loader != NULL); + + gdk_pixbuf_loader_close (loader, &err); + + if (err != NULL) + { + JCL_ThrowException (env, "java/io/IOException", err->message); + g_error_free (err); + } + + gdk_threads_leave (); +} + +struct stream_save_request +{ + JNIEnv *env; + jobject *stream; +}; + +static gboolean +save_to_stream(const gchar *buf, + gsize count, + GError **error __attribute__((unused)), + gpointer data) +{ + struct stream_save_request *ssr = (struct stream_save_request *)data; + + jbyteArray jbuf; + jbyte *cbuf; + + gdk_threads_leave (); + + jbuf = (*(ssr->env))->NewByteArray ((ssr->env), count); + cbuf = (*(ssr->env))->GetByteArrayElements ((ssr->env), jbuf, NULL); + memcpy (cbuf, buf, count); + (*(ssr->env))->ReleaseByteArrayElements ((ssr->env), jbuf, cbuf, 0); + (*(ssr->env))->CallVoidMethod ((ssr->env), *(ssr->stream), + dataOutputWriteID, jbuf); + + gdk_threads_enter (); + + return TRUE; +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage +(JNIEnv *env, jclass clazz __attribute__((unused)), + jintArray jarr, jstring jenctype, jint width, jint height, + jboolean hasAlpha, jobject stream) +{ + GdkPixbuf* pixbuf; + jint *ints; + guchar a, r, g, b, *pix, *p; + GError *err = NULL; + const char *enctype; + int i; + struct stream_save_request ssr; + + gdk_threads_enter (); + + ssr.stream = &stream; + ssr.env = env; + + ints = (*env)->GetIntArrayElements (env, jarr, NULL); + pix = g_malloc(width * height * (hasAlpha ? 4 : 3)); + + enctype = (*env)->GetStringUTFChars (env, jenctype, NULL); + g_assert(enctype != NULL); + + g_assert (pix != NULL); + g_assert (ints != NULL); + + p = pix; + for (i = 0; i < width*height; ++i) + { + /* + * Java encodes pixels as integers in a predictable arithmetic order: + * 0xAARRGGBB. Since these are jints, JNI has already byte-swapped + * them for us if necessary, so they're in "our" endianness, whatever + * that is. It uses 4 bytes per pixel whether or not there's an alpha + * channel. + */ + + a = 0xff & (ints[i] >> 24); + r = 0xff & (ints[i] >> 16); + g = 0xff & (ints[i] >> 8); + b = 0xff & ints[i]; + + /* + * GDK-pixbuf has a very different storage model: + * + * - A different alpha order (alpha after colors). + * - A different packing model (no alpha -> 3-bytes-per-pixel). + * - A different "RGB" order (host memory order, not endian-neutral). + */ + + *p++ = r; + *p++ = g; + *p++ = b; + if (hasAlpha) + *p++ = a; + } + + pixbuf = gdk_pixbuf_new_from_data (pix, + GDK_COLORSPACE_RGB, + (gboolean) hasAlpha, + 8, width, height, + width * (hasAlpha ? 4 : 3), /* rowstride */ + NULL, NULL); + g_assert (pixbuf != NULL); + + g_assert(gdk_pixbuf_save_to_callback (pixbuf, + &save_to_stream, + &ssr, + enctype, + &err, NULL)); + + g_object_unref (pixbuf); + + g_free(pix); + + (*env)->ReleaseStringUTFChars (env, jenctype, enctype); + (*env)->ReleaseIntArrayElements (env, jarr, ints, 0); + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes + (JNIEnv *env, jobject obj, jbyteArray jarr, jint len) +{ + GdkPixbufLoader *loader = NULL; + jbyte *bytes = NULL; + GError *err = NULL; + + gdk_threads_enter (); + + g_assert (len >= 1); + g_assert (jarr != NULL); + + bytes = (*env)->GetByteArrayElements (env, jarr, NULL); + g_assert (bytes != NULL); + loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj); + g_assert (loader != NULL); + + gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, &err); + + (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0); + + if (err != NULL) + { + JCL_ThrowException (env, "java/io/IOException", err->message); + g_error_free (err); + } + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkRobotPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkRobotPeer.c new file mode 100644 index 00000000000..8c0ac6ce35f --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkRobotPeer.c @@ -0,0 +1,341 @@ +/* gdkrobotpeer.c + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GdkRobotPeer.h" +#include <gdk/gdkx.h> +#include <X11/extensions/XTest.h> + +static int +awt_button_mask_to_num (int buttons) +{ + switch (buttons) + { + case AWT_BUTTON1_MASK: + return 1; + case AWT_BUTTON2_MASK: + return 2; + case AWT_BUTTON3_MASK: + return 3; + } + + return 0; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_initXTest + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + GdkDisplay *display; + Display *xdisplay; + int event_basep; + int error_basep; + int majorp; + int minorp; + jboolean result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + result = XTestQueryExtension (xdisplay, + &event_basep, + &error_basep, + &majorp, + &minorp); + + gdk_threads_leave (); + + return result; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_mouseMove + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint x, jint y) +{ + GdkDisplay *display; + Display *xdisplay; + int result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + result = XTestFakeMotionEvent (xdisplay, + -1, + x, y, CurrentTime); + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_mousePress + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint buttons) +{ + GdkDisplay *display; + Display *xdisplay; + int result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + result = XTestFakeButtonEvent (xdisplay, + awt_button_mask_to_num (buttons), + True, CurrentTime); + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_mouseRelease + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint buttons) +{ + GdkDisplay *display; + Display *xdisplay; + int result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + result = XTestFakeButtonEvent (xdisplay, + awt_button_mask_to_num (buttons), + False, CurrentTime); + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_mouseWheel + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint wheelAmt) +{ + GdkDisplay *display; + Display *xdisplay; + int i = 0; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + if (wheelAmt < 0) + for (i = 0; i < -wheelAmt; i++) + { + XTestFakeButtonEvent (xdisplay, + 4, + True, CurrentTime); + XTestFakeButtonEvent (xdisplay, + 4, + False, CurrentTime); + } + else + for (i = 0; i < wheelAmt; i++) + { + XTestFakeButtonEvent (xdisplay, + 5, + True, CurrentTime); + XTestFakeButtonEvent (xdisplay, + 5, + False, CurrentTime); + } + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_keyPress + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint keycode) +{ + GdkDisplay *display; + Display *xdisplay; + GdkKeymapKey *keymap_keys = NULL; + gint n_keys = 0; + guint lookup_keyval = 0; + int result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + lookup_keyval = cp_gtk_awt_keycode_to_keysym (keycode, + AWT_KEY_LOCATION_LEFT); + + if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), + lookup_keyval, + &keymap_keys, + &n_keys)) + { + /* No matching keymap entry was found. */ + g_printerr ("No matching keymap entries were found\n"); + gdk_threads_leave (); + return; + } + + /* If n_keys > 1 then there are multiple hardware keycodes that + translate to lookup_keyval. We arbitrarily choose the first + hardware keycode from the list returned by + gdk_keymap_get_entries_for_keyval. */ + result = XTestFakeKeyEvent (xdisplay, + keymap_keys[0].keycode, + True, CurrentTime); + + g_free (keymap_keys); + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_keyRelease + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jint keycode) +{ + GdkDisplay *display; + Display *xdisplay; + GdkKeymapKey *keymap_keys = NULL; + gint n_keys = 0; + guint lookup_keyval = 0; + int result; + + gdk_threads_enter (); + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + lookup_keyval = cp_gtk_awt_keycode_to_keysym (keycode, + AWT_KEY_LOCATION_LEFT); + + if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), + lookup_keyval, + &keymap_keys, + &n_keys)) + { + /* No matching keymap entry was found. */ + g_printerr ("No matching keymap entries were found\n"); + gdk_threads_leave (); + return; + } + + /* If n_keys > 1 then there are multiple hardware keycodes that + translate to lookup_keyval. We arbitrarily choose the first + hardware keycode from the list returned by + gdk_keymap_get_entries_for_keyval. */ + result = XTestFakeKeyEvent (xdisplay, + keymap_keys[0].keycode, + False, CurrentTime); + + g_free (keymap_keys); + + XFlush (xdisplay); + + gdk_threads_leave (); +} + +JNIEXPORT jintArray JNICALL +Java_gnu_java_awt_peer_gtk_GdkRobotPeer_nativeGetRGBPixels + (JNIEnv *env, jobject obj __attribute__((unused)), jint x, jint y, + jint width, jint height) +{ + jint stride_bytes, stride_pixels, n_channels, n_pixels; + jintArray jpixels; + jint *java_pixels; + guchar *gdk_pixels; + GdkPixbuf *pixbuf_no_alpha = NULL; + GdkPixbuf *pixbuf = NULL; + +#ifndef WORDS_BIGENDIAN + int i; +#endif + + gdk_threads_enter (); + + pixbuf_no_alpha = gdk_pixbuf_get_from_drawable (NULL, + gdk_get_default_root_window (), + NULL, x, y, 0, 0, + width, height); + + pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0); + g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + stride_bytes = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + stride_pixels = stride_bytes / n_channels; + n_pixels = height * stride_pixels; + gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); + + gdk_threads_leave (); + + jpixels = (*env)->NewIntArray (env, n_pixels); + + gdk_threads_enter (); + + java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL); + + memcpy (java_pixels, + gdk_pixels, + (height * stride_bytes)); + +#ifndef WORDS_BIGENDIAN + /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */ + for (i = 0; i < n_pixels; ++i) + { + java_pixels[i] = SWAPU32 ((unsigned)java_pixels[i]); + } +#endif + + g_object_unref (pixbuf); + + (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0); + + gdk_threads_leave (); + + return jpixels; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkTextLayout.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkTextLayout.c new file mode 100644 index 00000000000..918ecfd0a8e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkTextLayout.c @@ -0,0 +1,192 @@ +/* gnu_java_awt_GdkTextLayout.c + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 <gtk/gtk.h> +#include "native_state.h" +#include "gdkfont.h" +#include "gnu_java_awt_peer_gtk_GdkTextLayout.h" + +struct state_table *cp_gtk_native_text_layout_state_table; + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_initStaticState + (JNIEnv *env, jclass clazz) +{ + NSA_TEXT_LAYOUT_INIT (env, clazz); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_initState + (JNIEnv *env, jobject self) +{ + struct textlayout *tl; + + gdk_threads_enter (); + + g_assert(self != NULL); + tl = g_malloc0 (sizeof (struct textlayout)); + g_assert(tl != NULL); + tl->pango_layout = pango_layout_new(gdk_pango_context_get()); + g_assert(tl->pango_layout != NULL); + NSA_SET_TEXT_LAYOUT_PTR (env, self, tl); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_setText + (JNIEnv *env, jobject self, jstring text) +{ + struct textlayout *tl; + gchar *str = NULL; + gint len = 0; + + gdk_threads_enter (); + + g_assert(self != NULL); + g_assert(text != NULL); + + tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, self); + g_assert(tl != NULL); + g_assert(tl->pango_layout != NULL); + + len = (*env)->GetStringUTFLength (env, text); + str = (gchar *)(*env)->GetStringUTFChars (env, text, NULL); + g_assert (str != NULL); + + pango_layout_set_text (tl->pango_layout, text, len); + + (*env)->ReleaseStringUTFChars (env, text, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_indexToPos + (JNIEnv *env, jobject self, jint idx, jdoubleArray javaPos) +{ + struct textlayout *tl; + PangoRectangle pangoPos; + jdouble *nativePos; + + gdk_threads_enter (); + + g_assert(self != NULL); + g_assert(javaPos != NULL); + + tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, self); + g_assert(tl != NULL); + g_assert(tl->pango_layout != NULL); + + g_assert((*env)->GetArrayLength (env, javaPos) == 4); + + nativePos = (*env)->GetDoubleArrayElements (env, javaPos, NULL); + + pango_layout_index_to_pos (tl->pango_layout, idx, &pangoPos); + + nativePos[0] = (jdouble) pangoPos.x; + nativePos[1] = (jdouble) pangoPos.y; + nativePos[2] = (jdouble) pangoPos.width; + nativePos[3] = (jdouble) pangoPos.height; + + (*env)->ReleaseDoubleArrayElements (env, javaPos, nativePos, 0); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_getExtents + (JNIEnv *env, jobject self, jdoubleArray javaInkExtents, jdoubleArray javaLogExtents) +{ + struct textlayout *tl; + PangoRectangle pangoInkExtents, pangoLogExtents; + jdouble *nativeInkExtents, *nativeLogExtents; + + gdk_threads_enter (); + + g_assert(self != NULL); + g_assert(javaInkExtents != NULL); + g_assert(javaLogExtents != NULL); + + tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, self); + g_assert(tl != NULL); + g_assert(tl->pango_layout != NULL); + + g_assert((*env)->GetArrayLength (env, javaInkExtents) == 4); + g_assert((*env)->GetArrayLength (env, javaLogExtents) == 4); + + nativeInkExtents = (*env)->GetDoubleArrayElements (env, javaInkExtents, NULL); + nativeLogExtents = (*env)->GetDoubleArrayElements (env, javaLogExtents, NULL); + + pango_layout_get_extents (tl->pango_layout, + &pangoInkExtents, &pangoLogExtents); + + nativeInkExtents[0] = (jdouble) pangoInkExtents.x; + nativeInkExtents[1] = (jdouble) pangoInkExtents.y; + nativeInkExtents[2] = (jdouble) pangoInkExtents.width; + nativeInkExtents[3] = (jdouble) pangoInkExtents.height; + + nativeLogExtents[0] = (jdouble) pangoLogExtents.x; + nativeLogExtents[1] = (jdouble) pangoLogExtents.y; + nativeLogExtents[2] = (jdouble) pangoLogExtents.width; + nativeLogExtents[3] = (jdouble) pangoLogExtents.height; + + (*env)->ReleaseDoubleArrayElements (env, javaInkExtents, nativeInkExtents, 0); + (*env)->ReleaseDoubleArrayElements (env, javaLogExtents, nativeLogExtents, 0); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GdkTextLayout_dispose + (JNIEnv *env, jobject self) +{ + struct textlayout *tl; + + gdk_threads_enter (); + + g_assert(self != NULL); + tl = (struct textlayout *) NSA_DEL_TEXT_LAYOUT_PTR (env, self); + g_assert(tl != NULL); + if (tl->pango_layout != NULL) + g_object_unref (tl->pango_layout); + g_free(tl); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c new file mode 100644 index 00000000000..5e8ab26c3ed --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c @@ -0,0 +1,338 @@ +/* gtkbuttonpeer.c -- Native implementation of GtkButtonPeer + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkButtonPeer.h" + +static jmethodID beginNativeRepaintID; +static jmethodID endNativeRepaintID; + +void +cp_gtk_button_init_jni (void) +{ + jclass gtkbuttonpeer; + + gtkbuttonpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkButtonPeer"); + + beginNativeRepaintID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkbuttonpeer, + "beginNativeRepaint", + "()V"); + + endNativeRepaintID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkbuttonpeer, + "endNativeRepaint", "()V"); +} + +static void block_expose_event_cb (GtkWidget *widget, + jobject peer); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_create + (JNIEnv *env, jobject obj, jstring label) +{ + const char *c_label; + GtkWidget *eventbox; + GtkWidget *button; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + c_label = (*env)->GetStringUTFChars (env, label, NULL); + + eventbox = gtk_event_box_new (); + button = gtk_button_new_with_label (c_label); + gtk_container_add (GTK_CONTAINER (eventbox), button); + gtk_widget_show (button); + + (*env)->ReleaseStringUTFChars (env, label, c_label); + NSA_SET_PTR (env, obj, eventbox); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + GtkWidget *button; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + button = gtk_bin_get_child (GTK_BIN (ptr)); + + /* Button signals */ + g_signal_connect_after (G_OBJECT (button), "pressed", + G_CALLBACK (block_expose_event_cb), *gref); + + g_signal_connect_after (G_OBJECT (button), "released", + G_CALLBACK (block_expose_event_cb), *gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (button), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkSetLabel + (JNIEnv *env, jobject obj, jstring jtext) +{ + const char *text; + GtkWidget *button; + GtkWidget *label; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = (*env)->GetStringUTFChars (env, jtext, NULL); + + button = gtk_bin_get_child (GTK_BIN (ptr)); + label = gtk_bin_get_child (GTK_BIN (button)); + gtk_label_set_text (GTK_LABEL (label), text); + + (*env)->ReleaseStringUTFChars (env, jtext, text); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *button; + GtkWidget *label; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + button = gtk_bin_get_child (GTK_BIN (ptr)); + label = gtk_bin_get_child (GTK_BIN (button)); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET(label), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkWidgetSetBackground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor normal_color; + GdkColor prelight_color; + GdkColor active_color; + int prelight_red; + int prelight_blue; + int prelight_green; + GtkWidget *button; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + normal_color.red = (red / 255.0) * 65535; + normal_color.green = (green / 255.0) * 65535; + normal_color.blue = (blue / 255.0) * 65535; + + /* This calculation only approximate the active color produced by + Sun's AWT. */ + active_color.red = 0.85 * (red / 255.0) * 65535; + active_color.green = 0.85 * (green / 255.0) * 65535; + active_color.blue = 0.85 * (blue / 255.0) * 65535; + + /* There is no separate prelight color in Motif. */ + prelight_red = 1.15 * (red / 255.0) * 65535; + prelight_green = 1.15 * (green / 255.0) * 65535; + prelight_blue = 1.15 * (blue / 255.0) * 65535; + + prelight_color.red = prelight_red > 65535 ? 65535 : prelight_red; + prelight_color.green = prelight_green > 65535 ? 65535 : prelight_green; + prelight_color.blue = prelight_blue > 65535 ? 65535 : prelight_blue; + + button = gtk_bin_get_child (GTK_BIN (ptr)); + + gtk_widget_modify_bg (button, GTK_STATE_NORMAL, &normal_color); + gtk_widget_modify_bg (button, GTK_STATE_ACTIVE, &active_color); + gtk_widget_modify_bg (button, GTK_STATE_PRELIGHT, &prelight_color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkWidgetSetForeground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + GtkWidget *button; + GtkWidget *label; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + button = gtk_bin_get_child (GTK_BIN (ptr)); + label = gtk_bin_get_child (GTK_BIN (button)); + + gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &color); + gtk_widget_modify_fg (label, GTK_STATE_ACTIVE, &color); + gtk_widget_modify_fg (label, GTK_STATE_PRELIGHT, &color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkActivate + (JNIEnv *env, jobject obj) +{ + GtkWidget *button; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + button = gtk_bin_get_child (GTK_BIN (ptr)); + gtk_widget_activate (GTK_WIDGET (button)); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkWidgetRequestFocus + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkWidget *button; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + button = gtk_bin_get_child (GTK_BIN (ptr)); + gtk_widget_grab_focus (button); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkButtonPeer_setNativeBounds + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + GtkWidget *widget, *child; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + widget = GTK_WIDGET (ptr); + + /* We assume that -1 is a width or height and not a request for the + widget's natural size. */ + width = width < 0 ? 0 : width; + height = height < 0 ? 0 : height; + child = gtk_bin_get_child (GTK_BIN (widget)); + + if (!(width == 0 && height == 0)) + { + /* Set the event box's size request... */ + gtk_widget_set_size_request (widget, width, height); + /* ...and the button's size request... */ + gtk_widget_set_size_request (child, width, height); + /* ...and the label's size request. */ + gtk_widget_set_size_request (gtk_bin_get_child (GTK_BIN (child)), width, + height); + if (widget->parent != NULL) + gtk_fixed_move (GTK_FIXED (widget->parent), widget, x, y); + } + + gdk_threads_leave (); +} + +static void +block_expose_event_cb (GtkWidget *widget, jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + beginNativeRepaintID); + + gdk_threads_enter (); + + gdk_window_process_updates (widget->window, TRUE); + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + endNativeRepaintID); + + gdk_threads_enter (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCanvasPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCanvasPeer.c new file mode 100644 index 00000000000..52922ddb82e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCanvasPeer.c @@ -0,0 +1,58 @@ +/* gtkcanvaspeer.c -- Native implementation of GtkCanvasPeer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkCanvasPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCanvasPeer_create + (JNIEnv *env, jobject obj) +{ + gpointer widget; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + widget = gtk_type_new (gtk_drawing_area_get_type ()); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c new file mode 100644 index 00000000000..4f28750921b --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c @@ -0,0 +1,77 @@ +/* gtkcheckboxgrouppeer.c -- Native implementation of GtkCheckboxGroupPeer + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer_dispose + (JNIEnv *env, jobject obj) +{ + /* The actual underlying widget is owned by a different class. So + we just clean up the hash table here. */ + NSA_DEL_PTR (env, obj); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer_remove + (JNIEnv *env, jobject obj, jobject checkbox) +{ + GtkRadioButton *button; + void *ptr; + GSList *list; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, checkbox); + button = GTK_RADIO_BUTTON (ptr); + + /* Update the group to point to some other widget in the group. We + have to do this because Gtk doesn't have a separate object to + represent a radio button's group. */ + for (list = gtk_radio_button_group (button); list != NULL; + list = list->next) + { + if (list->data != button) + break; + } + + NSA_SET_PTR (env, obj, list ? list->data : NULL); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer.c new file mode 100644 index 00000000000..77836cedd1e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer.c @@ -0,0 +1,78 @@ +/* gtkmenuitempeer.c -- Native implementation of GtkMenuItemPeer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer_create + (JNIEnv *env, jobject obj, jstring label) +{ + GtkWidget *widget; + const char *str; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + str = (*env)->GetStringUTFChars (env, label, NULL); + + widget = gtk_check_menu_item_new_with_label (str); + gtk_widget_show (widget); + + (*env)->ReleaseStringUTFChars (env, label, str); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxMenuItemPeer_setState + (JNIEnv *env, jobject obj, jboolean state) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ptr), state); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c new file mode 100644 index 00000000000..cf883dd3307 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c @@ -0,0 +1,240 @@ +/* gtkcheckboxpeer.c -- Native implementation of GtkCheckboxPeer + Copyright (C) 1998, 1999, 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkCheckboxPeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" + +static jmethodID postItemEventID; + +void +cp_gtk_checkbox_init_jni (void) +{ + jclass gtkcheckboxpeer; + + gtkcheckboxpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkCheckboxPeer"); + + postItemEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcheckboxpeer, + "postItemEvent", + "(Ljava/lang/Object;I)V"); +} + +static void item_toggled_cb (GtkToggleButton *item, jobject peer); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_create + (JNIEnv *env, jobject obj, jobject group) +{ + GtkWidget *button; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + if (group == NULL) + button = gtk_check_button_new_with_label (""); + else + { + void *native_group = NSA_GET_PTR (env, group); + button = gtk_radio_button_new_with_label_from_widget (native_group, ""); + if (native_group == NULL) + { + /* Set the native group so we can use the correct value the + next time around. FIXME: this doesn't work! */ + NSA_SET_PTR (env, group, button); + } + } + + NSA_SET_PTR (env, obj, button); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr = NULL; + jobject *gref = NULL; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* Checkbox signals */ + g_signal_connect (G_OBJECT (ptr), "toggled", + G_CALLBACK (item_toggled_cb), *gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (ptr), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_nativeSetCheckboxGroup + (JNIEnv *env, jobject obj, jobject group) +{ + GtkRadioButton *button; + void *native_group, *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + /* FIXME: we can't yet switch between a checkbutton and a + radiobutton. However, AWT requires this. For now we just + crash. */ + + button = GTK_RADIO_BUTTON (ptr); + + native_group = NSA_GET_PTR (env, group); + if (native_group == NULL) + gtk_radio_button_set_group (button, NULL); + else + gtk_radio_button_set_group (button, + gtk_radio_button_group + (GTK_RADIO_BUTTON (native_group))); + + /* If the native group wasn't set on the new CheckboxGroup, then set + it now so that the right thing will happen with the next + radiobutton. The native state for a CheckboxGroup is a pointer + to one of the widgets in the group. We are careful to keep this + always pointing at a live widget; whenever a widget is destroyed + (or otherwise removed from the group), the CheckboxGroup peer is + notified. */ + if (native_group == NULL) + NSA_SET_PTR (env, group, native_group); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkToggleButtonSetActive + (JNIEnv *env, jobject obj, jboolean is_active) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ptr), is_active); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *button; + GtkWidget *label; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + button = GTK_WIDGET (ptr); + label = gtk_bin_get_child (GTK_BIN(button)); + + if (!label) + return; + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET(label), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkButtonSetLabel + (JNIEnv *env, jobject obj, jstring label) +{ + const char *c_label; + GtkWidget *label_widget; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + c_label = (*env)->GetStringUTFChars (env, label, NULL); + + label_widget = gtk_bin_get_child (GTK_BIN (ptr)); + gtk_label_set_text (GTK_LABEL (label_widget), c_label); + + (*env)->ReleaseStringUTFChars (env, label, c_label); + + gdk_threads_leave (); +} + +static void +item_toggled_cb (GtkToggleButton *item, jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postItemEventID, + peer, + item->active ? + (jint) AWT_ITEM_SELECTED : + (jint) AWT_ITEM_DESELECTED); + + gdk_threads_enter (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c new file mode 100644 index 00000000000..ed9df543332 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c @@ -0,0 +1,248 @@ +/* gtkchoicepeer.c -- Native implementation of GtkChoicePeer + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkChoicePeer.h" + +static jmethodID postChoiceItemEventID; + +void +cp_gtk_choice_init_jni (void) +{ + jclass gtkchoicepeer; + + gtkchoicepeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkChoicePeer"); + + postChoiceItemEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkchoicepeer, + "postChoiceItemEvent", + "(Ljava/lang/String;I)V"); +} + +static void selection_changed_cb (GtkComboBox *combobox, jobject peer); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_create + (JNIEnv *env, jobject obj) +{ + GtkWidget *combobox; + jobject *gref; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + combobox = gtk_combo_box_new_text (); + + NSA_SET_PTR (env, obj, combobox); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr = NULL; + jobject *gref = NULL; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* Choice signals */ + g_signal_connect (G_OBJECT (ptr), "changed", + G_CALLBACK (selection_changed_cb), *gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (ptr), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_append + (JNIEnv *env, jobject obj, jobjectArray items) +{ + gpointer ptr; + jsize count, i; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + count = (*env)->GetArrayLength (env, items); + + for (i = 0; i < count; i++) + { + jobject item; + const char *label; + + item = (*env)->GetObjectArrayElement (env, items, i); + label = (*env)->GetStringUTFChars (env, item, NULL); + + gtk_combo_box_append_text (GTK_COMBO_BOX (ptr), label); + + (*env)->ReleaseStringUTFChars (env, item, label); + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeAdd + (JNIEnv *env, jobject obj, jstring item, jint index) +{ + void *ptr; + const char *label; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + label = (*env)->GetStringUTFChars (env, item, 0); + + gtk_combo_box_insert_text (GTK_COMBO_BOX (ptr), index, label); + + (*env)->ReleaseStringUTFChars (env, item, label); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemove + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_combo_box_remove_text (GTK_COMBO_BOX (ptr), index); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemoveAll + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkTreeModel *model; + gint count, i; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (ptr)); + count = gtk_tree_model_iter_n_children (model, NULL); + + /* First, unselect everything, to avoid problems when removing items. */ + gtk_combo_box_set_active (GTK_COMBO_BOX (ptr), -1); + + for (i = count - 1; i >= 0; i--) { + gtk_combo_box_remove_text (GTK_COMBO_BOX (ptr), i); + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_select + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_combo_box_set_active (GTK_COMBO_BOX (ptr), index); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeGetSelected + (JNIEnv *env, jobject obj) +{ + void *ptr; + int index; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + index = gtk_combo_box_get_active (GTK_COMBO_BOX (ptr)); + + gdk_threads_leave (); + + return index; +} + +static void selection_changed_cb (GtkComboBox *combobox, jobject peer) +{ + jstring label; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *selected; + gint index; + + index = gtk_combo_box_get_active(combobox); + + if (index >= 0) + { + model = gtk_combo_box_get_model (combobox); + gtk_combo_box_get_active_iter (combobox, &iter); + gtk_tree_model_get (model, &iter, 0, &selected, -1); + label = (*cp_gtk_gdk_env())->NewStringUTF (cp_gtk_gdk_env(), selected); + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postChoiceItemEventID, + label, + (jint) AWT_ITEM_SELECTED); + + gdk_threads_enter (); + } +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c new file mode 100644 index 00000000000..dea9d4cc7c2 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkClipboard.c @@ -0,0 +1,204 @@ +/* gtkclipboard.c + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkClipboard.h" + +static jmethodID stringSelectionReceivedID; +static jmethodID stringSelectionHandlerID; +static jmethodID selectionClearID; + +static void selection_received_cb (GtkWidget *, GtkSelectionData *, + guint, gpointer); +static void selection_get_cb (GtkWidget *, GtkSelectionData *, guint, + guint, gpointer); +static gint selection_clear_cb (GtkWidget *, GdkEventSelection *); + +static GtkWidget *clipboard; +static jobject cb_obj; + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env, + jobject obj) +{ + gdk_threads_enter (); + + if (!stringSelectionReceivedID) + { + jclass gtkclipboard; + + gtkclipboard = (*env)->FindClass (env, + "gnu/java/awt/peer/gtk/GtkClipboard"); + stringSelectionReceivedID = (*env)->GetMethodID (env, gtkclipboard, + "stringSelectionReceived", + "(Ljava/lang/String;)V"); + stringSelectionHandlerID = (*env)->GetMethodID (env, gtkclipboard, + "stringSelectionHandler", + "()Ljava/lang/String;"); + selectionClearID = (*env)->GetMethodID (env, gtkclipboard, + "selectionClear", "()V"); + } + + cb_obj = (*env)->NewGlobalRef (env, obj); + + clipboard = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + g_signal_connect (G_OBJECT(clipboard), "selection_received", + G_CALLBACK (selection_received_cb), NULL); + + g_signal_connect (G_OBJECT(clipboard), "selection_clear_event", + G_CALLBACK (selection_clear_cb), NULL); + + gtk_selection_add_target (clipboard, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, 0); + + g_signal_connect (G_OBJECT(clipboard), "selection_get", + G_CALLBACK (selection_get_cb), NULL); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkClipboard_requestStringConversion + (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused))) +{ + gdk_threads_enter (); + + gtk_selection_convert (clipboard, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, GDK_CURRENT_TIME); + + gdk_threads_leave (); +} + +static void +selection_received_cb (GtkWidget *widget __attribute__((unused)), + GtkSelectionData *selection_data __attribute__((unused)), + guint time __attribute__((unused)), + gpointer data __attribute__((unused))) +{ + /* Check to see if retrieval succeeded */ + if (selection_data->length < 0 + || selection_data->type != GDK_SELECTION_TYPE_STRING) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, stringSelectionReceivedID, + NULL); + + gdk_threads_enter (); + } + else + { + char *str = (char *) selection_data->data; + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, stringSelectionReceivedID, + (*cp_gtk_gdk_env())->NewStringUTF (cp_gtk_gdk_env(), str)); + + gdk_threads_enter (); + } + + return; +} + +static void +selection_get_cb (GtkWidget *widget __attribute__((unused)), + GtkSelectionData *selection_data, + guint info __attribute__((unused)), + guint time __attribute__((unused)), + gpointer data __attribute__((unused))) +{ + jstring jstr; + const char *utf; + jsize utflen; + + gdk_threads_leave (); + + jstr = (*cp_gtk_gdk_env())->CallObjectMethod (cp_gtk_gdk_env(), cb_obj, + stringSelectionHandlerID); + + gdk_threads_enter (); + + if (!jstr) + { + gtk_selection_data_set (selection_data, + GDK_TARGET_STRING, 8, NULL, 0); + return; + } + + utflen = (*cp_gtk_gdk_env())->GetStringUTFLength (cp_gtk_gdk_env(), jstr); + utf = (*cp_gtk_gdk_env())->GetStringUTFChars (cp_gtk_gdk_env(), jstr, NULL); + + gtk_selection_data_set (selection_data, GDK_TARGET_STRING, 8, + (const unsigned char*)utf, utflen); + + (*cp_gtk_gdk_env())->ReleaseStringUTFChars (cp_gtk_gdk_env(), jstr, utf); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkClipboard_selectionGet + (JNIEnv *env, jclass clazz __attribute__((unused))) +{ + GdkWindow *owner; + + gdk_threads_enter (); + + /* if we already own the clipboard, we need to tell the old data object + that we're no longer going to be using him */ + owner = gdk_selection_owner_get (GDK_SELECTION_PRIMARY); + if (owner && owner == clipboard->window) + (*env)->CallVoidMethod (env, cb_obj, selectionClearID); + + gtk_selection_owner_set (clipboard, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + + gdk_threads_leave (); +} + +static gint +selection_clear_cb (GtkWidget *widget __attribute__((unused)), + GdkEventSelection *event __attribute__((unused))) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), cb_obj, selectionClearID); + + gdk_threads_enter (); + + return TRUE; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c new file mode 100644 index 00000000000..bd9dde39283 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c @@ -0,0 +1,1161 @@ +/* gtkcomponentpeer.c -- Native implementation of GtkComponentPeer + Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" + +#include <gtk/gtkprivate.h> + +#define AWT_DEFAULT_CURSOR 0 +#define AWT_CROSSHAIR_CURSOR 1 +#define AWT_TEXT_CURSOR 2 +#define AWT_WAIT_CURSOR 3 +#define AWT_SW_RESIZE_CURSOR 4 +#define AWT_SE_RESIZE_CURSOR 5 +#define AWT_NW_RESIZE_CURSOR 6 +#define AWT_NE_RESIZE_CURSOR 7 +#define AWT_N_RESIZE_CURSOR 8 +#define AWT_S_RESIZE_CURSOR 9 +#define AWT_W_RESIZE_CURSOR 10 +#define AWT_E_RESIZE_CURSOR 11 +#define AWT_HAND_CURSOR 12 +#define AWT_MOVE_CURSOR 13 + +#define AWT_BUTTON1_DOWN_MASK (1 << 10) +#define AWT_BUTTON2_DOWN_MASK (1 << 11) +#define AWT_BUTTON3_DOWN_MASK (1 << 12) + +/* FIXME: use gtk-double-click-time, gtk-double-click-distance */ +#define MULTI_CLICK_TIME 250 +/* as opposed to a MULTI_PASS_TIME :) */ + +#define AWT_MOUSE_CLICKED 500 +#define AWT_MOUSE_PRESSED 501 +#define AWT_MOUSE_RELEASED 502 +#define AWT_MOUSE_MOVED 503 +#define AWT_MOUSE_ENTERED 504 +#define AWT_MOUSE_EXITED 505 +#define AWT_MOUSE_DRAGGED 506 + +#define AWT_FOCUS_GAINED 1004 +#define AWT_FOCUS_LOST 1005 + +static GtkWidget *find_fg_color_widget (GtkWidget *widget); +static GtkWidget *find_bg_color_widget (GtkWidget *widget); + +static jmethodID postMouseEventID; +static jmethodID setCursorID; +static jmethodID postExposeEventID; +static jmethodID postFocusEventID; + +void +cp_gtk_component_init_jni (void) + { + jclass gtkcomponentpeer; + + gtkcomponentpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkComponentPeer"); + + postMouseEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, + "postMouseEvent", "(IJIIIIZ)V"); + + setCursorID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, + "setCursor", "()V"); + + postExposeEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, + "postExposeEvent", "(IIII)V"); + + postFocusEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, + "postFocusEvent", "(IZ)V"); +} + +static gboolean component_button_press_cb (GtkWidget *widget, + GdkEventButton *event, + jobject peer); +static gboolean component_button_release_cb (GtkWidget *widget, + GdkEventButton *event, + jobject peer); +static gboolean component_motion_notify_cb (GtkWidget *widget, + GdkEventMotion *event, + jobject peer); +static gboolean component_enter_notify_cb (GtkWidget *widget, + GdkEventCrossing *event, + jobject peer); +static gboolean component_leave_notify_cb (GtkWidget *widget, + GdkEventCrossing *event, + jobject peer); +static gboolean component_expose_cb (GtkWidget *widget, + GdkEventExpose *event, + jobject peer); +static gboolean component_focus_in_cb (GtkWidget *widget, + GdkEventFocus *event, + jobject peer); +static gboolean component_focus_out_cb (GtkWidget *widget, + GdkEventFocus *event, + jobject peer); + +static jint +button_to_awt_mods (int button) +{ + switch (button) + { + case 1: + return AWT_BUTTON1_MASK; + case 2: + return AWT_BUTTON2_MASK; + case 3: + return AWT_BUTTON3_MASK; + } + + return 0; +} + +static jint +state_to_awt_mods (guint state) +{ + jint result = 0; + + if (state & GDK_SHIFT_MASK) + result |= AWT_SHIFT_DOWN_MASK; + if (state & GDK_CONTROL_MASK) + result |= AWT_CTRL_DOWN_MASK; + if (state & GDK_MOD1_MASK) + result |= AWT_ALT_DOWN_MASK; + + return result; +} + +static jint +state_to_awt_mods_with_button_states (guint state) +{ + jint result = 0; + + if (state & GDK_SHIFT_MASK) + result |= AWT_SHIFT_DOWN_MASK; + if (state & GDK_CONTROL_MASK) + result |= AWT_CTRL_DOWN_MASK; + if (state & GDK_MOD1_MASK) + result |= AWT_ALT_DOWN_MASK; + if (state & GDK_BUTTON1_MASK) + result |= AWT_BUTTON1_DOWN_MASK; + if (state & GDK_BUTTON2_MASK) + result |= AWT_BUTTON2_DOWN_MASK; + if (state & GDK_BUTTON3_MASK) + result |= AWT_BUTTON3_DOWN_MASK; + + return result; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursor + (JNIEnv *env, jobject obj, jint type) +{ + void *ptr; + GtkWidget *widget; + GdkCursorType gdk_cursor_type; + GdkCursor *gdk_cursor; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + switch (type) + { + case AWT_CROSSHAIR_CURSOR: + gdk_cursor_type = GDK_CROSSHAIR; + break; + case AWT_TEXT_CURSOR: + gdk_cursor_type = GDK_XTERM; + break; + case AWT_WAIT_CURSOR: + gdk_cursor_type = GDK_WATCH; + break; + case AWT_SW_RESIZE_CURSOR: + gdk_cursor_type = GDK_BOTTOM_LEFT_CORNER; + break; + case AWT_SE_RESIZE_CURSOR: + gdk_cursor_type = GDK_BOTTOM_RIGHT_CORNER; + break; + case AWT_NW_RESIZE_CURSOR: + gdk_cursor_type = GDK_TOP_LEFT_CORNER; + break; + case AWT_NE_RESIZE_CURSOR: + gdk_cursor_type = GDK_TOP_RIGHT_CORNER; + break; + case AWT_N_RESIZE_CURSOR: + gdk_cursor_type = GDK_TOP_SIDE; + break; + case AWT_S_RESIZE_CURSOR: + gdk_cursor_type = GDK_BOTTOM_SIDE; + break; + case AWT_W_RESIZE_CURSOR: + gdk_cursor_type = GDK_LEFT_SIDE; + break; + case AWT_E_RESIZE_CURSOR: + gdk_cursor_type = GDK_RIGHT_SIDE; + break; + case AWT_HAND_CURSOR: + gdk_cursor_type = GDK_HAND2; + break; + case AWT_MOVE_CURSOR: + gdk_cursor_type = GDK_FLEUR; + break; + default: + gdk_cursor_type = GDK_LEFT_PTR; + } + + widget = GTK_WIDGET(ptr); + + gdk_cursor = gdk_cursor_new (gdk_cursor_type); + gdk_window_set_cursor (widget->window, gdk_cursor); + gdk_cursor_destroy (gdk_cursor); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetParent + (JNIEnv *env, jobject obj, jobject parent) +{ + void *ptr; + void *parent_ptr; + GtkWidget *widget; + GtkWidget *parent_widget; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + parent_ptr = NSA_GET_PTR (env, parent); + + widget = GTK_WIDGET (ptr); + parent_widget = GTK_WIDGET (parent_ptr); + + if (widget->parent == NULL) + { + if (GTK_IS_WINDOW (parent_widget)) + { + GList *children = gtk_container_children + (GTK_CONTAINER (parent_widget)); + + if (GTK_IS_MENU_BAR (children->data)) + gtk_fixed_put (GTK_FIXED (children->next->data), widget, 0, 0); + else + gtk_fixed_put (GTK_FIXED (children->data), widget, 0, 0); + } + else + if (GTK_IS_SCROLLED_WINDOW (parent_widget)) + { + gtk_scrolled_window_add_with_viewport + (GTK_SCROLLED_WINDOW (parent_widget), widget); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (widget->parent), + GTK_SHADOW_NONE); + + } + else + { + if (widget->parent == NULL) + gtk_fixed_put (GTK_FIXED (parent_widget), widget, 0, 0); + } + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetSensitive + (JNIEnv *env, jobject obj, jboolean sensitive) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_set_sensitive (GTK_WIDGET (ptr), sensitive); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus + (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_grab_focus (GTK_WIDGET (ptr)); + + gdk_threads_leave (); +} + +/* + * Translate a Java KeyEvent object into a GdkEventKey event, then + * pass it to the GTK main loop for processing. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent + (JNIEnv *env, jobject obj, jint id, jlong when, jint mods, + jint keyCode, jint keyLocation) +{ + void *ptr; + GdkEvent *event = NULL; + GdkKeymapKey *keymap_keys = NULL; + gint n_keys = 0; + guint lookup_keyval = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (id == AWT_KEY_PRESSED) + event = gdk_event_new (GDK_KEY_PRESS); + else if (id == AWT_KEY_RELEASED) + event = gdk_event_new (GDK_KEY_RELEASE); + else + { + gdk_threads_leave (); + /* Don't send AWT KEY_TYPED events to GTK. */ + return; + } + + if (GTK_IS_BUTTON (ptr)) + event->key.window = GTK_BUTTON (ptr)->event_window; + else if (GTK_IS_SCROLLED_WINDOW (ptr)) + event->key.window = GTK_WIDGET (GTK_SCROLLED_WINDOW (ptr)->container.child)->window; + else + event->key.window = GTK_WIDGET (ptr)->window; + + event->key.send_event = 0; + event->key.time = (guint32) when; + + if (mods & AWT_SHIFT_DOWN_MASK) + event->key.state |= GDK_SHIFT_MASK; + if (mods & AWT_CTRL_DOWN_MASK) + event->key.state |= GDK_CONTROL_MASK; + if (mods & AWT_ALT_DOWN_MASK) + event->key.state |= GDK_MOD1_MASK; + + /* This hack is needed because the AWT has no notion of num lock. + It infers numlock state from the only Java virtual keys that are + affected by it. */ + if (keyCode == VK_NUMPAD9 + || keyCode == VK_NUMPAD8 + || keyCode == VK_NUMPAD7 + || keyCode == VK_NUMPAD6 + || keyCode == VK_NUMPAD5 + || keyCode == VK_NUMPAD4 + || keyCode == VK_NUMPAD3 + || keyCode == VK_NUMPAD2 + || keyCode == VK_NUMPAD1 + || keyCode == VK_NUMPAD0 + || keyCode == VK_DECIMAL) + event->key.state |= GDK_MOD2_MASK; + + /* These values don't need to be filled in since GTK doesn't use + them. */ + event->key.length = 0; + event->key.string = NULL; + + lookup_keyval = cp_gtk_awt_keycode_to_keysym (keyCode, keyLocation); + + if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), + lookup_keyval, + &keymap_keys, + &n_keys)) + { + /* No matching keymap entry was found. */ + g_printerr ("No matching keymap entries were found\n"); + gdk_threads_leave (); + return; + } + + /* Note: if n_keys > 1 then there are multiple hardware keycodes + that translate to lookup_keyval. We arbitrarily choose the first + hardware keycode from the list returned by + gdk_keymap_get_entries_for_keyval. */ + + event->key.hardware_keycode = keymap_keys[0].keycode; + event->key.group = keymap_keys[0].group; + + g_free (keymap_keys); + + if (!gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), + event->key.hardware_keycode, + event->key.state, + event->key.group, + &event->key.keyval, + NULL, NULL, NULL)) + { + /* No matching keyval was found. */ + g_printerr ("No matching keyval was found\n"); + gdk_threads_leave (); + return; + } + + /* keyevent = (GdkEventKey *) event; */ + /* g_printerr ("generated event: sent: %d time: %d state: %d keyval: %d length: %d string: %s hardware_keycode: %d group: %d\n", keyevent->send_event, keyevent->time, keyevent->state, keyevent->keyval, keyevent->length, keyevent->string, keyevent->hardware_keycode, keyevent->group); */ + + /* We already received the original key event on the window itself, + so we don't want to resend it. */ + if (!GTK_IS_WINDOW (ptr)) + { + if (GTK_IS_SCROLLED_WINDOW (ptr)) + gtk_widget_event (GTK_WIDGET (GTK_SCROLLED_WINDOW (ptr)->container.child), event); + else + gtk_widget_event (GTK_WIDGET (ptr), event); + } + + gdk_threads_leave (); +} + +/* + * Find the origin of a widget's window. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetLocationOnScreen + (JNIEnv * env, jobject obj, jintArray jpoint) +{ + void *ptr; + jint *point; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + point = (*env)->GetIntArrayElements (env, jpoint, 0); + + gdk_window_get_origin (GTK_WIDGET (ptr)->window, point, point+1); + + if (!GTK_IS_CONTAINER (ptr)) + { + *point += GTK_WIDGET(ptr)->allocation.x; + *(point+1) += GTK_WIDGET(ptr)->allocation.y; + } + + (*env)->ReleaseIntArrayElements(env, jpoint, point, 0); + + gdk_threads_leave (); +} + +/* + * Find this widget's current size. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetDimensions + (JNIEnv *env, jobject obj, jintArray jdims) +{ + void *ptr; + jint *dims; + GtkRequisition requisition; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + dims = (*env)->GetIntArrayElements (env, jdims, 0); + dims[0] = dims[1] = 0; + + gtk_widget_size_request (GTK_WIDGET (ptr), &requisition); + + dims[0] = requisition.width; + dims[1] = requisition.height; + + (*env)->ReleaseIntArrayElements (env, jdims, dims, 0); + + gdk_threads_leave (); +} + +/* + * Find this widget's preferred size. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetPreferredDimensions + (JNIEnv *env, jobject obj, jintArray jdims) +{ + void *ptr; + jint *dims; + GtkRequisition current_req; + GtkRequisition natural_req; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + dims = (*env)->GetIntArrayElements (env, jdims, 0); + dims[0] = dims[1] = 0; + + /* Widgets that extend GtkWindow such as GtkFileChooserDialog may have + a default size. These values seem more useful then the natural + requisition values, particularly for GtkFileChooserDialog. */ + if (GTK_IS_WINDOW (ptr)) + { + gint width, height; + gtk_window_get_default_size (GTK_WINDOW (ptr), &width, &height); + + dims[0] = width; + dims[1] = height; + } + else + { + /* Save the widget's current size request. */ + gtk_widget_size_request (GTK_WIDGET (ptr), ¤t_req); + + /* Get the widget's "natural" size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1); + gtk_widget_size_request (GTK_WIDGET (ptr), &natural_req); + + /* Reset the widget's size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), + current_req.width, current_req.height); + + dims[0] = natural_req.width; + dims[1] = natural_req.height; + } + + (*env)->ReleaseIntArrayElements (env, jdims, dims, 0); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeBounds + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + GtkWidget *widget; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + widget = GTK_WIDGET (ptr); + + /* We assume that -1 is a width or height and not a request for the + widget's natural size. */ + width = width < 0 ? 0 : width; + height = height < 0 ? 0 : height; + + if (GTK_IS_VIEWPORT (widget->parent)) + gtk_widget_set_size_request (widget, width, height); + else + { + if (!(width == 0 && height == 0)) + { + gtk_widget_set_size_request (widget, width, height); + if (widget->parent != NULL) + gtk_fixed_move (GTK_FIXED (widget->parent), widget, x, y); + } + } + + gdk_threads_leave (); +} + +JNIEXPORT jintArray JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetBackground + (JNIEnv *env, jobject obj) +{ + void *ptr; + jintArray array; + int *rgb; + GdkColor bg; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + bg = GTK_WIDGET (ptr)->style->bg[GTK_STATE_NORMAL]; + + gdk_threads_leave (); + + array = (*env)->NewIntArray (env, 3); + + gdk_threads_enter (); + + rgb = (*env)->GetIntArrayElements (env, array, NULL); + /* convert color data from 16 bit values down to 8 bit values */ + rgb[0] = bg.red >> 8; + rgb[1] = bg.green >> 8; + rgb[2] = bg.blue >> 8; + (*env)->ReleaseIntArrayElements (env, array, rgb, 0); + + gdk_threads_leave (); + + return array; +} + +JNIEXPORT jintArray JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetForeground + (JNIEnv *env, jobject obj) +{ + void *ptr; + jintArray array; + jint *rgb; + GdkColor fg; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + fg = GTK_WIDGET (ptr)->style->fg[GTK_STATE_NORMAL]; + + gdk_threads_leave (); + + array = (*env)->NewIntArray (env, 3); + + gdk_threads_enter (); + + rgb = (*env)->GetIntArrayElements (env, array, NULL); + /* convert color data from 16 bit values down to 8 bit values */ + rgb[0] = fg.red >> 8; + rgb[1] = fg.green >> 8; + rgb[2] = fg.blue >> 8; + (*env)->ReleaseIntArrayElements (env, array, rgb, 0); + + gdk_threads_leave (); + + return array; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetBackground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor normal_color; + GdkColor active_color; + GtkWidget *widget; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + normal_color.red = (red / 255.0) * 65535; + normal_color.green = (green / 255.0) * 65535; + normal_color.blue = (blue / 255.0) * 65535; + + /* This calculation only approximates the active colors produced by + Sun's AWT. */ + active_color.red = 0.85 * (red / 255.0) * 65535; + active_color.green = 0.85 * (green / 255.0) * 65535; + active_color.blue = 0.85 * (blue / 255.0) * 65535; + + widget = find_bg_color_widget (GTK_WIDGET (ptr)); + + gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &normal_color); + gtk_widget_modify_bg (widget, GTK_STATE_ACTIVE, &active_color); + gtk_widget_modify_bg (widget, GTK_STATE_PRELIGHT, &normal_color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetForeground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + GtkWidget *widget; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + widget = find_fg_color_widget (GTK_WIDGET (ptr)); + + gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_fg (widget, GTK_STATE_ACTIVE, &color); + gtk_widget_modify_fg (widget, GTK_STATE_PRELIGHT, &color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_show + (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_show (GTK_WIDGET (ptr)); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_hide + (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_hide (GTK_WIDGET (ptr)); + + gdk_threads_leave(); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_isEnabled + (JNIEnv *env, jobject obj) +{ + void *ptr; + jboolean ret_val; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + ret_val = GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (ptr)); + + gdk_threads_leave (); + + return ret_val; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_isRealized + (JNIEnv *env, jobject obj) +{ + void *ptr; + jboolean ret_val; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (ptr == NULL) + return FALSE; + + ret_val = GTK_WIDGET_REALIZED (GTK_WIDGET (ptr)); + + gdk_threads_leave (); + + return ret_val; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_modalHasGrab + (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused))) +{ + GtkWidget *widget; + jboolean retval; + + gdk_threads_enter (); + + widget = gtk_grab_get_current (); + retval = (widget && GTK_IS_WINDOW (widget) && GTK_WINDOW (widget)->modal); + + gdk_threads_leave (); + + return retval; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + cp_gtk_component_connect_signals (ptr, gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeEventMask + (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_add_events (GTK_WIDGET (ptr), + GDK_POINTER_MOTION_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_STRUCTURE_MASK + | GDK_KEY_PRESS_MASK + | GDK_FOCUS_CHANGE_MASK); + + gdk_threads_leave (); +} + +/* FIXME: these functions should be implemented by overridding the + appropriate GtkComponentPeer methods. */ +static GtkWidget * +find_fg_color_widget (GtkWidget *widget) +{ + GtkWidget *fg_color_widget; + + if (GTK_IS_EVENT_BOX (widget) + || (GTK_IS_BUTTON (widget) + && !GTK_IS_OPTION_MENU (widget))) + fg_color_widget = gtk_bin_get_child (GTK_BIN(widget)); + else + fg_color_widget = widget; + + return fg_color_widget; +} + +static GtkWidget * +find_bg_color_widget (GtkWidget *widget) +{ + GtkWidget *bg_color_widget; + + bg_color_widget = widget; + + return bg_color_widget; +} + +void +cp_gtk_component_connect_expose_signals (GObject *ptr, jobject *gref) +{ + g_signal_connect (G_OBJECT (ptr), "expose-event", + G_CALLBACK (component_expose_cb), *gref); +} + +void +cp_gtk_component_connect_focus_signals (GObject *ptr, jobject *gref) +{ + g_signal_connect (G_OBJECT (ptr), "focus-in-event", + G_CALLBACK (component_focus_in_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "focus-out-event", + G_CALLBACK (component_focus_out_cb), *gref); +} + +void +cp_gtk_component_connect_mouse_signals (GObject *ptr, jobject *gref) +{ + g_signal_connect (G_OBJECT (ptr), "button-press-event", + G_CALLBACK (component_button_press_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "button-release-event", + G_CALLBACK (component_button_release_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "enter-notify-event", + G_CALLBACK (component_enter_notify_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "leave-notify-event", + G_CALLBACK (component_leave_notify_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "motion-notify-event", + G_CALLBACK (component_motion_notify_cb), *gref); +} + +void +cp_gtk_component_connect_signals (GObject *ptr, jobject *gref) +{ + cp_gtk_component_connect_expose_signals (ptr, gref); + cp_gtk_component_connect_focus_signals (ptr, gref); + cp_gtk_component_connect_mouse_signals (ptr, gref); +} + +/* These variables are used to keep track of click counts. The AWT + allows more than a triple click to occur but GTK doesn't report + more-than-triple clicks. */ +static jint click_count = 1; +static guint32 button_click_time = 0; +static GdkWindow *button_window = NULL; +static guint button_number = -1; +static int hasBeenDragged; + +static gboolean +component_button_press_cb (GtkWidget *widget __attribute__((unused)), + GdkEventButton *event, + jobject peer) +{ + /* Ignore double and triple click events. */ + if (event->type == GDK_2BUTTON_PRESS + || event->type == GDK_3BUTTON_PRESS) + return FALSE; + + if ((event->time < (button_click_time + MULTI_CLICK_TIME)) + && (event->window == button_window) + && (event->button == button_number)) + click_count++; + else + click_count = 1; + + button_click_time = event->time; + button_window = event->window; + button_number = event->button; + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postMouseEventID, + AWT_MOUSE_PRESSED, + (jlong)event->time, + state_to_awt_mods (event->state) + | button_to_awt_mods (event->button), + (jint)event->x, + (jint)event->y, + click_count, + (event->button == 3) ? JNI_TRUE : + JNI_FALSE); + + gdk_threads_enter (); + + hasBeenDragged = FALSE; + + return FALSE; +} + +static gboolean +component_button_release_cb (GtkWidget *widget __attribute__((unused)), + GdkEventButton *event, + jobject peer) +{ + int width, height; + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postMouseEventID, + AWT_MOUSE_RELEASED, + (jlong)event->time, + state_to_awt_mods (event->state) + | button_to_awt_mods (event->button), + (jint)event->x, + (jint)event->y, + click_count, + JNI_FALSE); + + gdk_threads_enter (); + + /* Generate an AWT click event only if the release occured in the + window it was pressed in, and the mouse has not been dragged since + the last time it was pressed. */ + gdk_window_get_size (event->window, &width, &height); + if (! hasBeenDragged + && event->x >= 0 + && event->y >= 0 + && event->x <= width + && event->y <= height) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postMouseEventID, + AWT_MOUSE_CLICKED, + (jlong)event->time, + state_to_awt_mods (event->state) + | button_to_awt_mods (event->button), + (jint)event->x, + (jint)event->y, + click_count, + JNI_FALSE); + + gdk_threads_enter (); + } + return FALSE; +} + +static gboolean +component_motion_notify_cb (GtkWidget *widget __attribute__((unused)), + GdkEventMotion *event, + jobject peer) +{ + if (event->state & (GDK_BUTTON1_MASK + | GDK_BUTTON2_MASK + | GDK_BUTTON3_MASK + | GDK_BUTTON4_MASK + | GDK_BUTTON5_MASK)) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postMouseEventID, + AWT_MOUSE_DRAGGED, + (jlong)event->time, + state_to_awt_mods_with_button_states (event->state), + (jint)event->x, + (jint)event->y, + 0, + JNI_FALSE); + + gdk_threads_enter (); + + hasBeenDragged = TRUE; + } + else + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID, + AWT_MOUSE_MOVED, + (jlong)event->time, + state_to_awt_mods (event->state), + (jint)event->x, + (jint)event->y, + 0, + JNI_FALSE); + + gdk_threads_enter (); + } + return FALSE; +} + +static gboolean +component_enter_notify_cb (GtkWidget *widget __attribute__((unused)), + GdkEventCrossing *event, + jobject peer) +{ + /* We are not interested in enter events that are due to + grab/ungrab and not to actually crossing boundaries */ + if (event->mode == GDK_CROSSING_NORMAL) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID, + AWT_MOUSE_ENTERED, + (jlong)event->time, + state_to_awt_mods_with_button_states (event->state), + (jint)event->x, + (jint)event->y, + 0, + JNI_FALSE); + + gdk_threads_enter (); + } + return FALSE; +} + +static gboolean +component_leave_notify_cb (GtkWidget *widget __attribute__((unused)), + GdkEventCrossing *event, + jobject peer) +{ + /* We are not interested in leave events that are due to + grab/ungrab and not to actually crossing boundaries */ + if (event->mode == GDK_CROSSING_NORMAL) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postMouseEventID, + AWT_MOUSE_EXITED, + (jlong)event->time, + state_to_awt_mods_with_button_states (event->state), + (jint)event->x, + (jint)event->y, + 0, + JNI_FALSE); + + gdk_threads_enter (); + } + return FALSE; +} + +static gboolean +component_expose_cb (GtkWidget *widget __attribute__((unused)), + GdkEventExpose *event, + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postExposeEventID, + (jint)event->area.x, + (jint)event->area.y, + (jint)event->area.width, + (jint)event->area.height); + + gdk_threads_enter (); + + return FALSE; +} + +static gboolean +component_focus_in_cb (GtkWidget *widget __attribute((unused)), + GdkEventFocus *event __attribute((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postFocusEventID, + AWT_FOCUS_GAINED, + JNI_FALSE); + + gdk_threads_enter (); + + return FALSE; +} + +static gboolean +component_focus_out_cb (GtkWidget *widget __attribute((unused)), + GdkEventFocus *event __attribute((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postFocusEventID, + AWT_FOCUS_LOST, + JNI_FALSE); + + gdk_threads_enter (); + + return FALSE; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c new file mode 100644 index 00000000000..563a0257eca --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c @@ -0,0 +1,82 @@ +/* gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c -- Native + implementation of GtkEmbeddedWindowPeer + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer_create + (JNIEnv *env, jobject obj, jlong socket_id) +{ + GtkWidget *window; + GtkWidget *fixed; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + window = gtk_plug_new ((GdkNativeWindow) socket_id); + + fixed = gtk_fixed_new (); + gtk_container_add (GTK_CONTAINER (window), fixed); + + gtk_widget_show (fixed); + + NSA_SET_PTR (env, obj, window); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer_construct + (JNIEnv *env, jobject obj, jlong socket_id) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (GTK_WIDGET_REALIZED (GTK_WIDGET (ptr))) + g_printerr ("ERROR: GtkPlug is already realized\n"); + + gtk_plug_construct (GTK_PLUG (ptr), (GdkNativeWindow) socket_id); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c new file mode 100644 index 00000000000..48478d3b9bb --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c @@ -0,0 +1,281 @@ +/* gtkfiledialogpeer.c -- Native implementation of GtkFileDialogPeer + Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" +#include "gnu_java_awt_peer_gtk_GtkFileDialogPeer.h" + +static void handle_response_cb (GtkDialog *dialog, + gint responseId, + jobject peer_obj); + +/* + * Make a new file selection dialog + */ + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_create + (JNIEnv *env, jobject obj, jobject parent) +{ + void *parentp; + gpointer widget; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + parentp = NSA_GET_PTR(env, parent); + + /* FIXME: we should be using the default gnome-vfs backend but it is + not currently thread-safe. See: + http://bugzilla.gnome.org/show_bug.cgi?id=166852 */ + widget = gtk_file_chooser_dialog_new_with_backend + ("Open File", + GTK_WINDOW(parentp), + GTK_FILE_CHOOSER_ACTION_OPEN, + "gtk+", + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + /* GtkFileSelect is not modal by default */ + gtk_window_set_modal (GTK_WINDOW (widget), TRUE); + + /* We must add this window to the group so input in the others are + disable while it is being shown */ + gtk_window_group_add_window (cp_gtk_global_window_group, + GTK_WINDOW (widget)); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr = NULL; + jobject *gref = NULL; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* FileDialog signals */ + g_signal_connect (G_OBJECT (ptr), "response", + G_CALLBACK (handle_response_cb), *gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (ptr), gref); + + gdk_threads_leave (); +} + +JNIEXPORT jstring JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeGetDirectory + (JNIEnv *env, jobject obj) +{ + void *ptr; + const char *str; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + str = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER(ptr)); + + gdk_threads_leave (); + + return (*env)->NewStringUTF(env, str); +} + + +/* This function interfaces with the Java callback method of the same name. + This function extracts the filename from the GtkFileFilterInfo object, + and passes it to the Java method. The Java method will call the filter's + accept() method and will give back the return value. */ +static gboolean filenameFilterCallback (const GtkFileFilterInfo *filter_info, + gpointer obj) +{ + jclass cx; + jmethodID id; + jstring *filename; + gboolean accepted; + + cx = (*cp_gtk_gdk_env())->GetObjectClass (cp_gtk_gdk_env(), (jobject) obj); + id = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), cx, "filenameFilterCallback", + "(Ljava/lang/String;)Z"); + + filename = (*cp_gtk_gdk_env())->NewStringUTF(cp_gtk_gdk_env(), filter_info->filename); + + gdk_threads_leave(); + + accepted = (*cp_gtk_gdk_env())->CallBooleanMethod(cp_gtk_gdk_env(), obj, id, filename); + + gdk_threads_enter(); + + return accepted; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFilenameFilter + (JNIEnv *env, jobject obj, jobject filter_obj __attribute__((unused))) +{ + void *ptr; + GtkFileFilter *filter; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + filter = gtk_file_filter_new(); + gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, + filenameFilterCallback, obj, NULL); + + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(ptr), filter); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetDirectory + (JNIEnv *env, jobject obj, jstring directory) +{ + void *ptr; + const char *str; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + str = (*env)->GetStringUTFChars (env, directory, 0); + + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(ptr), str); + + (*env)->ReleaseStringUTFChars (env, directory, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFile + (JNIEnv *env, jobject obj, jstring filename) +{ + void *ptr; + const char *str; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + str = (*env)->GetStringUTFChars (env, filename, 0); + + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (ptr), str); + + (*env)->ReleaseStringUTFChars (env, filename, str); + + gdk_threads_leave (); +} + +static void +handle_response_cb (GtkDialog *dialog __attribute__((unused)), + gint responseId, + jobject peer_obj) +{ + static int isDisposeIDSet = 0; + static int isIDSet = 0; + static jmethodID gtkSetFilenameID; + static jmethodID hideID; + static jmethodID disposeID; + void *ptr; + G_CONST_RETURN gchar *fileName; + jstring str_fileName = NULL; + + /* We only need this for the case when the user closed the window, + or clicked ok or cancel. */ + if (responseId != GTK_RESPONSE_DELETE_EVENT + && responseId != GTK_RESPONSE_ACCEPT + && responseId != GTK_RESPONSE_CANCEL) + return; + + ptr = NSA_GET_PTR (cp_gtk_gdk_env(), peer_obj); + + if (responseId == GTK_RESPONSE_DELETE_EVENT) + { + if (!isDisposeIDSet) + { + jclass cx = (*cp_gtk_gdk_env())->GetObjectClass (cp_gtk_gdk_env(), peer_obj); + disposeID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), cx, "gtkDisposeFileDialog", "()V"); + isDisposeIDSet = 1; + } + + /* We can dispose of the dialog now (and unblock show) */ + gdk_threads_leave (); + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer_obj, disposeID); + gdk_threads_enter (); + + return; + } + + if (responseId == GTK_RESPONSE_ACCEPT) { + fileName = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (GTK_WIDGET (ptr))); + str_fileName = (*cp_gtk_gdk_env())->NewStringUTF (cp_gtk_gdk_env(), fileName); + } + + if (!isIDSet) + { + jclass cx = (*cp_gtk_gdk_env())->GetObjectClass (cp_gtk_gdk_env(), peer_obj); + hideID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), cx, "gtkHideFileDialog", "()V"); + gtkSetFilenameID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), cx, + "gtkSetFilename", "(Ljava/lang/String;)V"); + isIDSet = 1; + } + + /* Set the Java object field 'file' with this value. */ + gdk_threads_leave (); + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer_obj, gtkSetFilenameID, str_fileName); + + /* We can hide the dialog now (and unblock show) */ + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer_obj, hideID); + + gdk_threads_enter (); +} + diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFramePeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFramePeer.c new file mode 100644 index 00000000000..41dfcea67b2 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFramePeer.c @@ -0,0 +1,180 @@ +/* gtkframepeer.c -- Native implementation of GtkFramePeer + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkFramePeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_removeMenuBarPeer + (JNIEnv *env, jobject obj) +{ + void *ptr; + void *mptr; + void *fixed; + GList* children; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + fixed = gtk_container_get_children (GTK_CONTAINER (ptr))->data; + children = gtk_container_get_children (GTK_CONTAINER (fixed)); + + while (children != NULL && !GTK_IS_MENU_SHELL (children->data)) + { + children = children->next; + } + + /* If there's a menu bar, remove it. */ + if (children != NULL) + { + mptr = children->data; + + /* This will actually destroy the MenuBar. By removing it from + its parent, the reference count for the MenuBar widget will + decrement to 0. The widget will be automatically destroyed by + GTK. */ + gtk_container_remove (GTK_CONTAINER (fixed), GTK_WIDGET (mptr)); + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_setMenuBarPeer + (JNIEnv *env, jobject obj, jobject menubar) +{ + void *ptr; + void *mptr; + void *fixed; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + mptr = NSA_GET_PTR (env, menubar); + + fixed = gtk_container_get_children (GTK_CONTAINER (ptr))->data; + gtk_fixed_put (GTK_FIXED (fixed), mptr, 0, 0); + gtk_widget_show (mptr); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_getMenuBarHeight + (JNIEnv *env, jobject obj __attribute__((unused)), jobject menubar) +{ + GtkWidget *ptr; + GtkRequisition requisition; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, menubar); + + gtk_widget_size_request (ptr, &requisition); + + gdk_threads_leave (); + + return requisition.height; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_setMenuBarWidth + (JNIEnv *env, jobject obj __attribute__((unused)), jobject menubar, jint width) +{ + GtkWidget *ptr; + GtkRequisition natural_req; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, menubar); + + /* Get the menubar's natural size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1); + gtk_widget_size_request (GTK_WIDGET (ptr), &natural_req); + + /* Set the menubar's size request to width by natural_req.height. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), + width, natural_req.height); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_gtkFixedSetVisible + (JNIEnv *env, jobject obj, jboolean visible) +{ + void *ptr; + void *fixed; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + fixed = gtk_container_get_children (GTK_CONTAINER (ptr))->data; + + if (visible) + gtk_widget_show (GTK_WIDGET (fixed)); + else + gtk_widget_hide (GTK_WIDGET (fixed)); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_nativeSetIconImage + (JNIEnv *env, jobject obj, jobject gtkimage) +{ + void *ptr; + GdkPixbuf *pixbuf = NULL; + + gdk_threads_enter (); + + pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage); + g_assert (pixbuf != NULL); + + ptr = NSA_GET_PTR (env, obj); + + gtk_window_set_icon (GTK_WINDOW (ptr), pixbuf); + + /* if the GtkImage is offscreen, this is a temporary pixbuf which should + be thrown out. */ + if(cp_gtk_image_is_offscreen (env, gtkimage) == JNI_TRUE) + gdk_pixbuf_unref (pixbuf); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c new file mode 100644 index 00000000000..0fae1da42b4 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c @@ -0,0 +1,101 @@ +/* gtkgenericpeer.c -- Native implementation of GtkGenericPeer + Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkGenericPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkGenericPeer_dispose + (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + /* For now the native state for any object must be a widget. + However, a subclass could override dispose() if required. */ + gtk_widget_destroy (GTK_WIDGET (ptr)); + + /* Remove entries from state tables */ + NSA_DEL_GLOBAL_REF (env, obj); + NSA_DEL_PTR (env, obj); + + gdk_threads_leave (); + + /* + * Wake up the main thread, to make sure it re-checks the window + * destruction condition. + */ + + g_main_context_wakeup (NULL); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkGenericPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET(ptr), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c new file mode 100644 index 00000000000..86cad1487c6 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImage.c @@ -0,0 +1,621 @@ +/* gtkimage.c + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkImage.h" +#include <gdk-pixbuf/gdk-pixbuf.h> + +/* The constant fields in java.awt.Image */ +#define SCALE_DEFAULT 1 +#define SCALE_FAST 2 +#define SCALE_SMOOTH 4 +#define SCALE_REPLICATE 8 +#define SCALE_AREA_AVERAGING 16 + +/* local stuff */ +static GdkInterpType mapHints(jint hints); +static jboolean offScreen (JNIEnv * env, jobject obj); +static void *getData (JNIEnv * env, jobject obj); +static void createRawData (JNIEnv * env, jobject obj, void *ptr); +static void setWidthHeight (JNIEnv * env, jobject obj, int width, int height); + +/** + * Loads a pixmap from a file. + */ +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_loadPixbuf + (JNIEnv *env, jobject obj, jstring name) +{ + const char *filename; + int width, height; + GdkPixbuf *pixbuf; + + gdk_threads_enter (); + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + + if (filename == NULL) + { + gdk_threads_leave (); + return JNI_FALSE; + } + + pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + if (pixbuf == NULL) + { + (*env)->ReleaseStringUTFChars (env, name, filename); + gdk_threads_leave (); + return JNI_FALSE; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + createRawData (env, obj, pixbuf); + setWidthHeight(env, obj, width, height); + (*env)->ReleaseStringUTFChars (env, name, filename); + + gdk_threads_leave (); + + return JNI_TRUE; +} + +/** + * Returns a copy of the pixel data as a java array. + */ +JNIEXPORT jintArray JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_getPixels(JNIEnv *env, jobject obj) +{ + GdkPixbuf *pixbuf; + int width, height, rowstride; + guchar *pixeldata; + jintArray result_array; + jint *result_array_iter, *dst; + int i,j; + + gdk_threads_enter (); + + pixbuf = cp_gtk_image_get_pixbuf (env, obj); + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + /* Must release the GDK lock before allocating memory through the + JVM, since some JVMs use the same lock for allocations and + finalization. Deadlock can occur on those JVMs. */ + gdk_threads_leave (); + + result_array = (*env)->NewIntArray (env, (width * height)); + + gdk_threads_enter (); + + dst = result_array_iter = + (*env)->GetIntArrayElements (env, result_array, NULL); + + + pixeldata = gdk_pixbuf_get_pixels (pixbuf); + + g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8); + + if (gdk_pixbuf_get_has_alpha (pixbuf)) + { + for(i = 0 ; i < height; i++) + { + memcpy(dst, (void *)pixeldata, width * 4); + dst += width; + pixeldata += rowstride; + } + } else { + for(i = 0; i < height; i++) + { + for(j = 0; j < width; j++) + dst[j] = 0xFF000000 | + (pixeldata[j*3 + 2] & 0xFF) << 16 | + (pixeldata[j*3 + 1] & 0xFF) << 8 | + (pixeldata[j*3] & 0xFF); + dst += width; + pixeldata += rowstride; + } + } + + if (offScreen (env, obj) == JNI_TRUE) + gdk_pixbuf_unref (pixbuf); + + (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0); + + gdk_threads_leave (); + + return result_array; +} + +/** + * Returns a copy of the pixel data as a java array. + * (GdkPixbuf only) + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_setPixels(JNIEnv *env, jobject obj, + jintArray pixels) +{ + GdkPixbuf *pixbuf = (GdkPixbuf *)getData (env, obj); + int width, height, rowstride; + guchar *pixeldata; + jint *src_array_iter, *src; + int i; + + gdk_threads_enter (); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + src = src_array_iter = + (*env)->GetIntArrayElements (env, pixels, NULL); + + pixeldata = gdk_pixbuf_get_pixels (pixbuf); + for(i = 0 ; i < height; i++) + { + memcpy((void *)pixeldata, (void *)src, width * 4); + src += width; + pixeldata += rowstride; + } + + (*env)->ReleaseIntArrayElements (env, pixels, src_array_iter, 0); + + gdk_threads_leave (); +} + +/** + * Allocates a Gtk Pixbuf or Pixmap. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_createPixmap(JNIEnv *env, jobject obj) +{ + int width, height; + jclass cls; + jfieldID field; + + gdk_threads_enter (); + + cls = (*env)->GetObjectClass (env, obj); + field = (*env)->GetFieldID (env, cls, "width", "I"); + g_assert (field != 0); + width = (*env)->GetIntField (env, obj, field); + + field = (*env)->GetFieldID (env, cls, "height", "I"); + g_assert (field != 0); + height = (*env)->GetIntField (env, obj, field); + + if (offScreen (env, obj) == JNI_FALSE) + createRawData (env, obj, gdk_pixbuf_new (GDK_COLORSPACE_RGB, + TRUE, + 8, + width, + height)); + else + createRawData (env, obj, gdk_pixmap_new (NULL, width, height, + gdk_rgb_get_visual ()->depth)); + + gdk_threads_leave (); +} + +/** + * Frees the Gtk Pixmap. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_freePixmap(JNIEnv *env, jobject obj) +{ + gdk_threads_enter (); + if (offScreen (env, obj) == JNI_FALSE) + gdk_pixbuf_unref ((GdkPixbuf *)getData (env, obj)); + else + gdk_pixmap_unref ((GdkPixmap *)getData (env, obj)); + + gdk_threads_leave (); +} + +/** + * Sets this pixmap to a scaled version of the source pixmap. + * width and height of the destination GtkImage must be set. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_createScaledPixmap(JNIEnv *env, + jobject destination, + jobject source, + jint hints) +{ + GdkPixbuf* dst; + int width, height; + jclass cls; + jfieldID field; + + GdkPixbuf *pixbuf; + + gdk_threads_enter (); + + cls = (*env)->GetObjectClass (env, destination); + field = (*env)->GetFieldID (env, cls, "width", "I"); + g_assert (field != 0); + width = (*env)->GetIntField (env, destination, field); + + field = (*env)->GetFieldID (env, cls, "height", "I"); + g_assert (field != 0); + height = (*env)->GetIntField (env, destination, field); + + pixbuf = cp_gtk_image_get_pixbuf (env, source); + + dst = gdk_pixbuf_scale_simple(pixbuf, + width, height, + mapHints(hints)); + + if (offScreen (env, source) == JNI_TRUE) + gdk_pixbuf_unref (pixbuf); + + createRawData (env, destination, (void *)dst); + + gdk_threads_leave (); +} + +/** + * Draws the pixbuf at x, y, scaled to width and height and + * optionally composited with a given background color. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaled + (JNIEnv *env, jobject obj, jobject gc_obj, + jint bg_red, jint bg_green, jint bg_blue, + jint x, jint y, jint width, jint height, jboolean composite) +{ + GdkPixbuf* dst; + struct graphics *g; + guint32 bgColor; + + gdk_threads_enter (); + + bgColor = ((bg_red & 0xFF) << 16) | + ((bg_green & 0xFF) << 8) | (bg_blue & 0xFF); + + g = (struct graphics *) NSA_GET_PTR (env, gc_obj); + + if (!g || !GDK_IS_DRAWABLE (g->drawable)) + { + gdk_threads_leave (); + return; + } + + if (offScreen (env, obj) == JNI_FALSE) + { + GdkPixbuf* pixbuf = (GdkPixbuf *)getData (env, obj); + + /* Scale and composite the image */ + if (composite == JNI_TRUE) + dst = gdk_pixbuf_composite_color_simple (pixbuf, + width, + height, + GDK_INTERP_BILINEAR, + 255, + width, + bgColor, + bgColor); + else + dst = gdk_pixbuf_scale_simple(pixbuf, + width, height, + GDK_INTERP_BILINEAR); + + gdk_draw_pixbuf (g->drawable, + g->gc, + dst, + 0, 0, + x + g->x_offset, y + g->y_offset, + width, height, + GDK_RGB_DITHER_NORMAL, 0, 0); + gdk_pixbuf_unref (dst); + + } else { + /* Get a pixmap */ + GdkPixmap* pixmap = (GdkPixmap *)getData (env, obj); + gdk_draw_drawable (g->drawable, + g->gc, + pixmap, + 0, 0, /* src x,y */ + x + g->x_offset, y + g->y_offset, + width, height); + } + + gdk_threads_leave (); +} + +/** + * Draws the pixbuf at x, y, scaled to width and height and + * optionally composited and/or flipped with a given background color. + */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkImage_drawPixelsScaledFlipped +(JNIEnv *env, jobject obj, jobject gc_obj, + jint bg_red, jint bg_green, jint bg_blue, + jboolean flipx, jboolean flipy, + jint srcx, jint srcy, jint srcwidth, jint srcheight, + jint dstx, jint dsty, jint dstwidth, jint dstheight, + jboolean composite) +{ + GdkPixbuf *pixbuf; + GdkPixbuf *tmp, *dst; + struct graphics *g; + guint32 bgColor; + + gdk_threads_enter (); + + bgColor = ((bg_red & 0xFF) << 16) | + ((bg_green & 0xFF) << 8) | (bg_blue & 0xFF); + + g = (struct graphics *) NSA_GET_PTR (env, gc_obj); + + if (!g || !GDK_IS_DRAWABLE (g->drawable)) + { + gdk_threads_leave (); + return; + } + + if (offScreen (env, obj) == JNI_FALSE) + { + pixbuf = (GdkPixbuf *)getData (env, obj); + + /* Get the source area */ + tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + TRUE, + 8, + srcwidth, + srcheight); + + gdk_pixbuf_copy_area (pixbuf, + srcx, srcy, + srcwidth, srcheight, + tmp, + 0, 0); /* dst x , dst y */ + } else { + /* Get a pixbuf from the pixmap */ + GdkDrawable *pixmap = (GdkDrawable *)getData(env, obj); + tmp = gdk_pixbuf_get_from_drawable (NULL, + pixmap, + gdk_drawable_get_colormap( pixmap ), + srcx, srcy, + 0, 0, /* dst x , dst y */ + srcwidth, srcheight); + } + + /* FIXME: This #if should be discarded once I feel comfortable about + GTK 2.6 dependence */ +#if GTK_MINOR_VERSION > 4 + /* Flip it if necessary. */ + if (flipx == JNI_TRUE) + { + GdkPixbuf *tmp2 = gdk_pixbuf_flip (tmp, TRUE); + gdk_pixbuf_unref (tmp); + tmp = tmp2; + } + if (flipy == JNI_TRUE) + { + GdkPixbuf *tmp2 = gdk_pixbuf_flip (tmp, FALSE); + gdk_pixbuf_unref (tmp); + tmp = tmp2; + } +#endif + + /* Scale and composite the image */ + if (composite == JNI_TRUE) + dst = gdk_pixbuf_composite_color_simple (tmp, + dstwidth, + dstheight, + GDK_INTERP_BILINEAR, + 255, + dstwidth, + bgColor, + bgColor); + else + dst = gdk_pixbuf_scale_simple(tmp, + dstwidth, dstheight, + GDK_INTERP_BILINEAR); + gdk_pixbuf_unref (tmp); + + gdk_draw_pixbuf (g->drawable, + g->gc, + dst, + 0, 0, + dstx + g->x_offset, dsty + g->y_offset, + dstwidth, dstheight, + GDK_RGB_DITHER_NORMAL, 0, 0); + + gdk_pixbuf_unref (dst); + + gdk_threads_leave (); +} + +/** + * Used by GtkFramePeer + */ +GdkPixbuf *cp_gtk_image_get_pixbuf (JNIEnv *env, jobject obj) +{ + int width, height; + GdkPixbuf *pixbuf; + GdkPixmap* pixmap; + jclass cls; + jfieldID field; + + if (offScreen (env, obj) == JNI_FALSE) + return (GdkPixbuf *)getData (env, obj); + + cls = (*env)->GetObjectClass (env, obj); + field = (*env)->GetFieldID (env, cls, "width", "I"); + g_assert (field != 0); + width = (*env)->GetIntField (env, obj, field); + + field = (*env)->GetFieldID (env, cls, "height", "I"); + g_assert (field != 0); + height = (*env)->GetIntField (env, obj, field); + + /* Get a pixmap */ + pixmap = (GdkPixmap *)getData (env, obj); + pixbuf = gdk_pixbuf_get_from_drawable (NULL, + pixmap, + gdk_drawable_get_colormap( pixmap ), + 0, 0, /* src x , src y */ + 0, 0, /* dst x , dst y */ + width, height); + return pixbuf; +} + +/** + * Used by GdkGraphics + */ +GdkPixmap *cp_gtk_image_get_pixmap (JNIEnv *env, jobject obj) +{ + if (offScreen (env, obj) == JNI_FALSE) + return NULL; + return (GdkPixmap *)getData (env, obj); +} + +jboolean cp_gtk_image_is_offscreen (JNIEnv *env, jobject obj) +{ + return offScreen(env, obj); +} + +/** + * Maps java.awt.Image scaling hints to the native GDK ones. + */ +static GdkInterpType mapHints(jint hints) +{ + switch ( hints ) + { + /* For FAST, we use the nearest-neighbor. Fastest and lowest quality. */ + case SCALE_FAST: + case SCALE_REPLICATE: + return GDK_INTERP_NEAREST; + + /* Hyperbolic for smooth. Slowest too. */ + case SCALE_SMOOTH: + return GDK_INTERP_HYPER; + + /* the inbetweenish method */ + case SCALE_AREA_AVERAGING: + return GDK_INTERP_TILES; + + /* default to bilinear */ + } + return GDK_INTERP_BILINEAR; +} + +/* Sets the width and height fields of a GtkImage object. */ +static void setWidthHeight (JNIEnv * env, jobject obj, int width, int height) +{ + jclass cls; + jfieldID field; + + cls = (*env)->GetObjectClass (env, obj); + g_assert (cls != 0); + field = (*env)->GetFieldID (env, cls, "width", "I"); + g_assert (field != 0); + (*env)->SetIntField (env, obj, field, (jint)width); + + field = (*env)->GetFieldID (env, cls, "height", "I"); + g_assert (field != 0); + (*env)->SetIntField (env, obj, field, (jint)height); +} + +/* Returns the value of the offScreen field. */ +static jboolean offScreen (JNIEnv *env, jobject obj) +{ + jclass cls; + jfieldID field; + + cls = (*env)->GetObjectClass (env, obj); + field = (*env)->GetFieldID (env, cls, "offScreen", "Z"); + g_assert (field != 0); + return (*env)->GetBooleanField (env, obj, field); +} + +/* Store and get the pixbuf pointer */ +static void +createRawData (JNIEnv * env, jobject obj, void *ptr) +{ + jclass cls; + jmethodID method; + jobject data; + jfieldID data_fid; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "pixmap", + "Lgnu/classpath/RawData;"); + g_assert (data_fid != 0); + +#if SIZEOF_VOID_P == 8 + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + method = (*env)->GetMethodID (env, cls, "<init>", "(J)V"); + data = (*env)->NewObject (env, cls, method, (jlong) ptr); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + method = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); + data = (*env)->NewObject (env, cls, method, (jint) ptr); +#endif + + (*env)->SetObjectField (env, obj, data_fid, data); +} + +static void * +getData (JNIEnv * env, jobject obj) +{ + jclass cls; + jfieldID field; + jfieldID data_fid; + jobject data; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "pixmap", + "Lgnu/classpath/RawData;"); + g_assert (data_fid != 0); + data = (*env)->GetObjectField (env, obj, data_fid); + +#if SIZEOF_VOID_P == 8 + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + field = (*env)->GetFieldID (env, cls, "data", "J"); + return (void *) (*env)->GetLongField (env, data, field); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + field = (*env)->GetFieldID (env, cls, "data", "I"); + return (void *) (*env)->GetIntField (env, data, field); +#endif +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkLabelPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkLabelPeer.c new file mode 100644 index 00000000000..7968ca77371 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkLabelPeer.c @@ -0,0 +1,183 @@ +/* gtklabelpeer.c -- Native implementation of GtkLabelPeer + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkLabelPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkLabelPeer_create + (JNIEnv *env, jobject obj, jstring text, jfloat xalign) +{ + GtkWidget *label; + GtkWidget *eventbox; + const char *str; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + str = (*env)->GetStringUTFChars (env, text, 0); + + eventbox = gtk_event_box_new (); + label = gtk_label_new (str); + gtk_misc_set_alignment (GTK_MISC (label), xalign, 0.5); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_widget_show (label); + + (*env)->ReleaseStringUTFChars (env, text, str); + + NSA_SET_PTR (env, obj, eventbox); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkLabelPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *label; + PangoFontDescription *font_desc; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + label = gtk_bin_get_child (GTK_BIN (ptr)); + + if (!label) + { + gdk_threads_leave (); + return; + } + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET (label), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkLabelPeer_setText + (JNIEnv *env, jobject obj, jstring text) +{ + const char *str; + void *ptr; + GtkWidget *label; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + str = (*env)->GetStringUTFChars (env, text, 0); + + label = gtk_bin_get_child (GTK_BIN (ptr)); + + gtk_label_set_label (GTK_LABEL (label), str); + + (*env)->ReleaseStringUTFChars (env, text, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkLabelPeer_nativeSetAlignment + (JNIEnv *env, jobject obj, jfloat xalign) +{ + void *ptr; + GtkWidget *label; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + label = gtk_bin_get_child (GTK_BIN(ptr)); + + gtk_misc_set_alignment (GTK_MISC (label), xalign, 0.5); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkLabelPeer_setNativeBounds + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + GtkWidget *widget; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + widget = GTK_WIDGET (ptr); + + /* We assume that -1 is a width or height and not a request for the + widget's natural size. */ + width = width < 0 ? 0 : width; + height = height < 0 ? 0 : height; + + if (!(width == 0 && height == 0)) + { + /* Set the event box's size request... */ + gtk_widget_set_size_request (widget, width, height); + /* ...and the label's size request. */ + gtk_widget_set_size_request (gtk_bin_get_child (GTK_BIN (widget)), + width, height); + + if (widget->parent != NULL) + gtk_fixed_move (GTK_FIXED (widget->parent), widget, x, y); + } + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c new file mode 100644 index 00000000000..d513176bed1 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c @@ -0,0 +1,539 @@ +/* GtkListPeer.c -- implements GtkListPeer's native methods + Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + 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 GNU General Public License cover the whole + combination. + + As a special 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 + this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkListPeer.h" + +static jmethodID postListItemEventID; + +void +cp_gtk_list_init_jni (void) +{ + jclass gtklistpeer; + + gtklistpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkListPeer"); + + postListItemEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtklistpeer, + "postItemEvent", + "(II)V"); +} + +enum + { + COLUMN_STRING, + N_COLUMNS + }; + +static gboolean item_highlighted_cb (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + jobject peer); + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_create + (JNIEnv *env, jobject obj, jint rows) +{ + GtkWidget *sw; + GtkWidget *list; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkListStore *list_store; + GtkTreeIter iter; + GtkRequisition req; + gint i; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING); + /* Add the number of rows so that we can calculate the tree view's + size request. */ + for (i = 0; i < rows; i++) + { + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, + COLUMN_STRING, "", + -1); + } + list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "text", + COLUMN_STRING, + NULL); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_tree_view_append_column (GTK_TREE_VIEW (list), column); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE); + + gtk_widget_size_request (GTK_WIDGET (list), &req); + + gtk_widget_set_size_request (GTK_WIDGET (list), req.width, req.height); + + gtk_container_add (GTK_CONTAINER (sw), list); + + /* Remove the blank rows. */ + gtk_list_store_clear (list_store); + + gtk_widget_show (list); + gtk_widget_show (sw); + + NSA_SET_PTR (env, obj, sw); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + GtkWidget *list; + GtkTreeSelection *selection; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + gtk_tree_selection_set_select_function (selection, item_highlighted_cb, + *gref, NULL); + + cp_gtk_component_connect_signals (G_OBJECT (list), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *list; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET (list), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_gtkWidgetRequestFocus + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkWidget *list; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + gtk_widget_grab_focus (list); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_append + (JNIEnv *env, jobject obj, jobjectArray items) +{ + void *ptr; + GtkWidget *list; + GtkTreeIter iter; + GtkTreeModel *list_store; + jint count; + jint i; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + count = (*env)->GetArrayLength (env, items); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + + for (i = 0; i < count; i++) + { + const char *text; + jobject item; + + item = (*env)->GetObjectArrayElement (env, items, i); + + text = (*env)->GetStringUTFChars (env, item, NULL); + gtk_list_store_append (GTK_LIST_STORE (list_store), &iter); + gtk_list_store_set (GTK_LIST_STORE (list_store), &iter, + COLUMN_STRING, text, + -1); + (*env)->ReleaseStringUTFChars (env, item, text); + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_add + (JNIEnv *env, jobject obj, jstring text, jint index) +{ + void *ptr; + const char *str; + GtkWidget *list; + GtkTreeIter iter; + GtkTreeModel *list_store; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + str = (*env)->GetStringUTFChars (env, text, NULL); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + + if (index == -1) + gtk_list_store_append (GTK_LIST_STORE (list_store), &iter); + else + gtk_list_store_insert (GTK_LIST_STORE (list_store), &iter, index); + + gtk_list_store_set (GTK_LIST_STORE (list_store), &iter, + COLUMN_STRING, str, -1); + + (*env)->ReleaseStringUTFChars (env, text, str); + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_delItems + (JNIEnv *env, jobject obj, jint start, jint end) +{ + void *ptr; + GtkWidget *list; + GtkTreeIter iter; + GtkTreeModel *list_store; + jint i; + jint num_items; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + list_store = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + + /* Special case: remove all rows. */ + if (end == -1) + gtk_list_store_clear (GTK_LIST_STORE (list_store)); + else + { + i = 0; + num_items = end - start + 1; + gtk_tree_model_iter_nth_child (list_store, &iter, NULL, start); + while (i < num_items) + { + gtk_list_store_remove (GTK_LIST_STORE (list_store), &iter); + i++; + } + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_select + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + GtkWidget *list; + GtkTreePath *path; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + path = gtk_tree_path_new_from_indices (index, -1); + gtk_tree_view_set_cursor (GTK_TREE_VIEW (list), path, NULL, FALSE); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_deselect + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + GtkWidget *list; + GtkTreeSelection *selection; + GtkTreePath *path; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + path = gtk_tree_path_new_from_indices (index, -1); + gtk_tree_selection_unselect_path (selection, path); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_getSize + (JNIEnv *env, jobject obj, jint rows, jint visible_rows, jintArray jdims) +{ + void *ptr; + jint *dims; + GtkRequisition current_req; + GtkRequisition natural_req; + + gdk_threads_enter (); + + dims = (*env)->GetIntArrayElements (env, jdims, NULL); + dims[0] = dims[1] = 0; + + ptr = NSA_GET_PTR (env, obj); + + /* Save the widget's current size request. */ + gtk_widget_size_request (GTK_WIDGET (ptr), ¤t_req); + + /* Get the widget's "natural" size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1); + gtk_widget_size_request (GTK_WIDGET (ptr), &natural_req); + + /* Reset the widget's size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), + current_req.width, current_req.height); + + dims[0] = natural_req.width; + + /* Calculate the final height, by comparing the number of rows + in the list to the number of rows requested by the caller. + FIXME: Is there a GTK method that counts the number of rows + in the list? If so, we don't need to bring visible_rows from + the Java peer. */ + if (rows == visible_rows) + dims[1] = natural_req.height; + else + dims[1] = natural_req.height / visible_rows * rows; + + (*env)->ReleaseIntArrayElements (env, jdims, dims, 0); + + gdk_threads_leave (); +} + + +JNIEXPORT jintArray JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_getSelectedIndexes + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkWidget *list; + GtkTreeSelection *selection; + jintArray result_array; + jint *result_array_iter; + GList *current_row; + GList *rows; + gint *indices; + jint count; + jint i; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + count = gtk_tree_selection_count_selected_rows (selection); + if (count > 0) + { + current_row = rows = gtk_tree_selection_get_selected_rows (selection, NULL); + + gdk_threads_leave (); + + result_array = (*env)->NewIntArray (env, count); + + gdk_threads_enter (); + + result_array_iter = (*env)->GetIntArrayElements (env, result_array, NULL); + + for (i = 0; i < count; i++) + { + indices = gtk_tree_path_get_indices (current_row->data); + result_array_iter[i] = indices ? indices[0] : -1; + current_row = g_list_next (current_row); + } + + if (rows) + { + g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (rows); + } + + (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0); + } + else + result_array = NULL; + + gdk_threads_leave (); + + return result_array; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_makeVisible + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + GtkWidget *list; + GtkTreePath *path; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + path = gtk_tree_path_new_from_indices (index, -1); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (list), path, + NULL, FALSE, 0.0, 0.0); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkListPeer_setMultipleMode + (JNIEnv *env, jobject obj, jboolean mode) +{ + void *ptr; + GtkWidget *list; + GtkTreeSelection *selection; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_bin_get_child (GTK_BIN (ptr)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + gtk_tree_selection_set_mode (selection, + mode ? GTK_SELECTION_MULTIPLE + : GTK_SELECTION_SINGLE); + + gdk_threads_leave (); +} + +static gboolean +item_highlighted_cb (GtkTreeSelection *selection __attribute__((unused)), + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + jobject peer) +{ + GtkTreeIter iter; + jint row; + gint *indices; + + if (gtk_tree_model_get_iter (model, &iter, path)) + { + indices = gtk_tree_path_get_indices (path); + row = indices ? indices[0] : -1; + + if (!path_currently_selected) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postListItemEventID, + row, + (jint) AWT_ITEM_SELECTED); + + gdk_threads_enter (); + } + else + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postListItemEventID, + row, + (jint) AWT_ITEM_DESELECTED); + + gdk_threads_enter (); + } + } + + return TRUE; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c new file mode 100644 index 00000000000..3e21a04024d --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c @@ -0,0 +1,118 @@ +/* gtkmenubarpeer.c -- Native implementation of GtkMenuBarPeer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkMenuBarPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_create + (JNIEnv *env, jobject obj) +{ + GtkWidget *widget; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + widget = gtk_menu_bar_new (); + gtk_widget_show (widget); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_addMenu + (JNIEnv *env, jobject obj, jobject menupeer) +{ + void *mbar, *menu; + + gdk_threads_enter (); + + mbar = NSA_GET_PTR (env, obj); + menu = NSA_GET_PTR (env, menupeer); + + gtk_menu_shell_append (GTK_MENU_SHELL (mbar), GTK_WIDGET (menu)); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_nativeSetHelpMenu + (JNIEnv *env, jobject obj, jobject menupeer) +{ + static void *helpmenu; + void *mbar, *menu; + GList *list; + + gdk_threads_enter (); + + mbar = NSA_GET_PTR (env, obj); + menu = NSA_GET_PTR (env, menupeer); + + if (helpmenu != NULL) + { + list = gtk_container_children (GTK_CONTAINER (mbar)); + while (list != NULL && list->data != helpmenu) + list = list->next; + if (list != NULL && list->data == helpmenu) + gtk_container_remove (GTK_CONTAINER (mbar), GTK_WIDGET (list->data)); + } + helpmenu = menu; + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_delMenu + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + GList *list; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_container_children (GTK_CONTAINER (ptr)); + list = g_list_nth (list, index); + gtk_container_remove (GTK_CONTAINER (ptr), GTK_WIDGET (list->data)); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuComponentPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuComponentPeer.c new file mode 100644 index 00000000000..01b74e46c57 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuComponentPeer.c @@ -0,0 +1,56 @@ +/* gtkmenucomponentpeer.c -- Native implementation of GtkMenuComponentPeer + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkMenuComponentPeer.h" + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuComponentPeer_dispose + (JNIEnv *env, jobject obj) +{ + /* For MenuComponents and its subclasses, the widgets are + automatically destroyed by Gtk when the parent MenuBar + is removed from the Frame. So we avoid the widget + destruction in GtkGenericPeer dispose() by overriding + it here. */ + + /* However, references to the Java objects still exist in the + state tables, so we still have to remove those. */ + + NSA_DEL_GLOBAL_REF (env, obj); + NSA_DEL_PTR (env, obj); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c new file mode 100644 index 00000000000..2746f1e4a70 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c @@ -0,0 +1,193 @@ +/* gtkmenuitempeer.c -- Native implementation of GtkMenuItemPeer + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkMenuItemPeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" + +static jmethodID postMenuActionEventID; + +void +cp_gtk_menuitem_init_jni (void) +{ + jclass gtkmenuitempeer; + + gtkmenuitempeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkMenuItemPeer"); + + postMenuActionEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkmenuitempeer, + "postMenuActionEvent", + "()V"); +} + +static void item_activate_cb (GtkMenuItem *item __attribute__((unused)), + jobject peer_obj); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_create + (JNIEnv *env, jobject obj, jstring label) +{ + GtkWidget *widget; + const char *str; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + str = (*env)->GetStringUTFChars (env, label, NULL); + + /* "-" signals that we need a separator. */ + if (strcmp (str, "-") == 0) + widget = gtk_menu_item_new (); + else + widget = gtk_menu_item_new_with_label (str); + + gtk_widget_show (widget); + + (*env)->ReleaseStringUTFChars (env, label, str); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + g_signal_connect (G_OBJECT (ptr), "activate", + G_CALLBACK (item_activate_cb), *gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *label; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + label = gtk_bin_get_child (GTK_BIN (ptr)); + + if (label) + { + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET(label), font_desc); + + pango_font_description_free (font_desc); + } + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_setEnabled + (JNIEnv *env, jobject obj, jboolean enabled) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_set_sensitive (GTK_WIDGET (ptr), enabled); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_setLabel + (JNIEnv *env, jobject obj, jstring label) +{ + void *ptr; + const char *str; + GtkAccelLabel *accel_label; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + str = (*env)->GetStringUTFChars (env, label, NULL); + + accel_label = GTK_ACCEL_LABEL (GTK_BIN (ptr)->child); + + gtk_label_set_text (GTK_LABEL (accel_label), str); + gtk_accel_label_refetch (accel_label); + + (*env)->ReleaseStringUTFChars (env, label, str); + + gdk_threads_leave (); +} + +static void +item_activate_cb (GtkMenuItem *item __attribute__((unused)), jobject peer_obj) +{ + gdk_threads_leave (); + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer_obj, + postMenuActionEventID); + gdk_threads_enter (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c new file mode 100644 index 00000000000..16018f001e4 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c @@ -0,0 +1,173 @@ +/* gtkmenupeer.c -- Native implementation of GtkMenuPeer + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkMenuPeer.h" + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuPeer_setupAccelGroup + (JNIEnv *env, jobject obj, jobject parent) +{ + void *ptr1, *ptr2; + + gdk_threads_enter (); + + ptr1 = NSA_GET_PTR (env, obj); + + if (!parent) + { + gtk_menu_set_accel_group (GTK_MENU (GTK_MENU_ITEM (ptr1)->submenu), + gtk_accel_group_new ()); + } + else + { + GtkAccelGroup *parent_accel; + + ptr2 = NSA_GET_PTR (env, parent); + parent_accel = gtk_menu_get_accel_group (GTK_MENU (GTK_MENU_ITEM (ptr2)->submenu)); + + gtk_menu_set_accel_group (GTK_MENU (GTK_MENU_ITEM (ptr1)->submenu), + parent_accel); + } + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuPeer_create + (JNIEnv *env, jobject obj, jstring label) +{ + GtkWidget *menu_title, *menu, *toplevel; + const char *str; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + str = (*env)->GetStringUTFChars (env, label, NULL); + + menu = gtk_menu_new (); + + if (str != NULL) + menu_title = gtk_menu_item_new_with_label (str); + else + menu_title = gtk_menu_item_new(); + + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_title), menu); + + /* Allow this menu to grab the pointer. */ + toplevel = gtk_widget_get_toplevel (menu); + if (GTK_IS_WINDOW (toplevel)) + { + gtk_window_group_add_window (cp_gtk_global_window_group, + GTK_WINDOW(toplevel)); + } + + gtk_widget_show (menu_title); + + NSA_SET_PTR (env, obj, menu_title); + + (*env)->ReleaseStringUTFChars (env, label, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuPeer_addTearOff + (JNIEnv *env, jobject obj) +{ + void *ptr1; + GtkWidget *menu, *item; + + gdk_threads_enter (); + + ptr1 = NSA_GET_PTR (env, obj); + + menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (ptr1)); + item = gtk_tearoff_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuPeer_addItem + (JNIEnv *env, jobject obj, jobject menuitempeer, jint key, jboolean shift) +{ + void *ptr1, *ptr2; + GtkWidget *menu; + + gdk_threads_enter (); + + ptr1 = NSA_GET_PTR (env, obj); + ptr2 = NSA_GET_PTR (env, menuitempeer); + + menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(ptr1)); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), GTK_WIDGET (ptr2)); + + if (key) + { + gtk_widget_add_accelerator (GTK_WIDGET (ptr2), "activate", + gtk_menu_get_accel_group (GTK_MENU (menu)), key, + (GDK_CONTROL_MASK + | ((shift) ? GDK_SHIFT_MASK : 0)), + GTK_ACCEL_VISIBLE); + } + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkMenuPeer_delItem + (JNIEnv *env, jobject obj, jint index) +{ + void *ptr; + GList *list; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + list = gtk_container_children (GTK_CONTAINER (ptr)); + list = g_list_nth (list, index); + gtk_container_remove (GTK_CONTAINER (ptr), GTK_WIDGET (list->data)); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPanelPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPanelPeer.c new file mode 100644 index 00000000000..8a130e1a4b3 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPanelPeer.c @@ -0,0 +1,112 @@ +/* gtkpanelpeer.c -- Native implementation of GtkPanelPeer + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" +#include "gnu_java_awt_peer_gtk_GtkPanelPeer.h" + +static gboolean panel_focus_in_cb (GtkWidget * widget, + GdkEventFocus *event, + jobject peer); +static gboolean panel_focus_out_cb (GtkWidget * widget, + GdkEventFocus *event, + jobject peer); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkPanelPeer_create + (JNIEnv *env, jobject obj) +{ + GtkWidget *widget; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + widget = gtk_fixed_new (); + + gtk_fixed_set_has_window (GTK_FIXED (widget), TRUE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + + NSA_SET_PTR (env, obj, widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkPanelPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* Panel signals. These callbacks prevent expose events being + delivered to the panel when it is focused. */ + g_signal_connect (G_OBJECT (ptr), "focus-in-event", + G_CALLBACK (panel_focus_in_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "focus-out-event", + G_CALLBACK (panel_focus_out_cb), *gref); + + /* Component signals. Exclude focus signals. */ + cp_gtk_component_connect_expose_signals (ptr, gref); + cp_gtk_component_connect_mouse_signals (ptr, gref); + + gdk_threads_leave (); +} + +static gboolean +panel_focus_in_cb (GtkWidget * widget __attribute__((unused)), + GdkEventFocus *event __attribute__((unused)), + jobject peer __attribute__((unused))) +{ + return TRUE; +} + +static gboolean +panel_focus_out_cb (GtkWidget * widget __attribute__((unused)), + GdkEventFocus *event __attribute__((unused)), + jobject peer __attribute__((unused))) +{ + return TRUE; +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPopupMenuPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPopupMenuPeer.c new file mode 100644 index 00000000000..e684a090f8f --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPopupMenuPeer.c @@ -0,0 +1,105 @@ +/* gtkpopupmenupeer.c -- Native implementation of GtkPopupMenuPeer + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkPopupMenuPeer.h" + +struct pos +{ + gint x; + gint y; +}; + +static void +menu_pos (GtkMenu *menu __attribute__((unused)), + gint *x, gint *y, + gboolean *push_in, + gpointer user_data) +{ + struct pos *p = (struct pos *) user_data; + + *x = p->x; + *y = p->y; + *push_in = TRUE; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkPopupMenuPeer_show + (JNIEnv *env, jobject obj, jint x, jint y, jlong time) +{ + void *ptr; + struct pos *p; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + p = g_malloc (sizeof (struct pos)); + p->x = x; + p->y = y; + + gtk_menu_popup (GTK_MENU (GTK_MENU_ITEM (ptr)->submenu), + NULL, NULL, menu_pos, p, 0, time); + + g_free (p); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkPopupMenuPeer_setupAccelGroup + (JNIEnv *env, jobject obj, jobject parent) +{ + void *ptr1, *ptr2; + GtkMenu *menu; + + gdk_threads_enter (); + + ptr1 = NSA_GET_PTR (env, obj); + ptr2 = NSA_GET_PTR (env, parent); + + menu = GTK_MENU (GTK_MENU_ITEM (ptr1)->submenu); + gtk_menu_set_accel_group (menu, gtk_accel_group_new ()); + /* FIXME: update this to use GTK-2.4 GtkActions. */ +#if 0 + _gtk_accel_group_attach (gtk_menu_get_accel_group (menu), + G_OBJECT (gtk_widget_get_toplevel (ptr2))); +#endif + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollPanePeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollPanePeer.c new file mode 100644 index 00000000000..1445cec5577 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollPanePeer.c @@ -0,0 +1,205 @@ +/* gtkscrollpanepeer.c -- Native implementation of GtkScrollPanePeer + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkScrollPanePeer.h" + +#define AWT_SCROLLPANE_SCROLLBARS_AS_NEEDED 0 +#define AWT_SCROLLPANE_SCROLLBARS_ALWAYS 1 +#define AWT_SCROLLPANE_SCROLLBARS_NEVER 2 + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_create + (JNIEnv *env, jobject obj, int width, int height) +{ + GtkWidget *sw; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + sw = gtk_scrolled_window_new (NULL, NULL); + + gtk_widget_set_size_request (sw, width, height); + + NSA_SET_PTR (env, obj, sw); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_setScrollPosition + (JNIEnv *env, jobject obj, jint x, jint y) +{ + GtkAdjustment *hadj, *vadj; + GtkScrolledWindow *sw; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW (ptr); + + hadj = gtk_scrolled_window_get_hadjustment (sw); + vadj = gtk_scrolled_window_get_vadjustment (sw); + + gtk_adjustment_set_value (hadj, x); + gtk_adjustment_set_value (vadj, y); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_gtkScrolledWindowSetHScrollIncrement + (JNIEnv *env, jobject obj, jint u) +{ + GtkAdjustment *hadj; + GtkScrolledWindow *sw; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW(ptr); + + hadj = gtk_scrolled_window_get_hadjustment (sw); + hadj->step_increment = u; + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_gtkScrolledWindowSetVScrollIncrement + (JNIEnv *env, jobject obj, jint u) +{ + GtkAdjustment *vadj; + GtkScrolledWindow *sw; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW(ptr); + + vadj = gtk_scrolled_window_get_hadjustment (sw); + vadj->step_increment = u; + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_getHScrollbarHeight + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkScrolledWindow *sw; + GtkRequisition requisition; + jint height = 0; + jint spacing = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW (ptr); + + gtk_widget_size_request (sw->hscrollbar, &requisition); + gtk_widget_style_get (GTK_WIDGET (sw), "scrollbar_spacing", &spacing, NULL); + height = requisition.height + spacing; + + gdk_threads_leave (); + + return height; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_getVScrollbarWidth + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkScrolledWindow *sw; + GtkRequisition requisition; + jint width = 0; + jint spacing = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW (ptr); + + gtk_widget_size_request (sw->vscrollbar, &requisition); + gtk_widget_style_get (GTK_WIDGET (sw), "scrollbar_spacing", &spacing, NULL); + width = requisition.width + spacing; + + gdk_threads_leave (); + + return width; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollPanePeer_setPolicy + (JNIEnv *env, jobject obj, jint policy) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + switch (policy) + { + case AWT_SCROLLPANE_SCROLLBARS_AS_NEEDED: + policy = GTK_POLICY_AUTOMATIC; + break; + case AWT_SCROLLPANE_SCROLLBARS_ALWAYS: + policy = GTK_POLICY_ALWAYS; + break; + case AWT_SCROLLPANE_SCROLLBARS_NEVER: + policy = GTK_POLICY_NEVER; + break; + } + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ptr), policy, policy); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollbarPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollbarPeer.c new file mode 100644 index 00000000000..39686271084 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollbarPeer.c @@ -0,0 +1,258 @@ +/* gtkscrollbarpeer.c -- Native implementation of GtkScrollbarPeer + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <math.h> +#include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" +#include "gnu_java_awt_peer_gtk_GtkScrollbarPeer.h" + +#define AWT_ADJUSTMENT_UNIT_INCREMENT 1 +#define AWT_ADJUSTMENT_UNIT_DECREMENT 2 +#define AWT_ADJUSTMENT_BLOCK_DECREMENT 3 +#define AWT_ADJUSTMENT_BLOCK_INCREMENT 4 +#define AWT_ADJUSTMENT_TRACK 5 + +static jmethodID postAdjustmentEventID; + +void +cp_gtk_scrollbar_init_jni (void) +{ + jclass gtkscrollbarpeer; + + gtkscrollbarpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkScrollbarPeer"); + + postAdjustmentEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkscrollbarpeer, + "postAdjustmentEvent", + "(II)V"); +} + +#if GTK_MINOR_VERSION > 4 +static gboolean slider_moved_cb (GtkRange *range, + GtkScrollType scroll, + gdouble value, + jobject obj); +#else +static void post_change_event_cb (GtkRange *range, + jobject peer); +#endif + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_create + (JNIEnv *env, jobject obj, jint orientation, jint value, + jint min, jint max, jint step_incr, jint page_incr, jint visible_amount) +{ + GtkWidget *scrollbar; + GtkObject *adj; + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + gdk_threads_enter (); + + adj = gtk_adjustment_new ((gdouble) value, + (gdouble) min, + (gdouble) max, + (gdouble) step_incr, + (gdouble) page_incr, + (gdouble) visible_amount); + + scrollbar = orientation + ? gtk_vscrollbar_new (GTK_ADJUSTMENT (adj)) + : gtk_hscrollbar_new (GTK_ADJUSTMENT (adj)); + + GTK_RANGE (scrollbar)->round_digits = 0; + /* These calls seem redundant but they are not. They clamp values + so that the slider's entirety is always between the two + steppers. */ + gtk_range_set_range (GTK_RANGE (scrollbar), (gdouble) min, (gdouble) max); + gtk_range_set_value (GTK_RANGE (scrollbar), (gdouble) value); + + gdk_threads_leave (); + + NSA_SET_PTR (env, obj, scrollbar); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr = NSA_GET_PTR (env, obj); + jobject *gref = NSA_GET_GLOBAL_REF (env, obj); + g_assert (gref); + + gdk_threads_enter (); + + /* Scrollbar signals */ +#if GTK_MINOR_VERSION > 4 + g_signal_connect (G_OBJECT (ptr), "change-value", + G_CALLBACK (slider_moved_cb), *gref); +#else + g_signal_connect (G_OBJECT (ptr), "value-changed", + G_CALLBACK (post_change_event_cb), *gref); +#endif + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (ptr), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setLineIncrement + (JNIEnv *env, jobject obj, jint amount) +{ + void *ptr; + GtkAdjustment *adj; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + adj = gtk_range_get_adjustment (GTK_RANGE (ptr)); + adj->step_increment = (gdouble) amount; + gtk_adjustment_changed (adj); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setPageIncrement + (JNIEnv *env, jobject obj, jint amount) +{ + void *ptr; + GtkAdjustment *adj; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + adj = gtk_range_get_adjustment (GTK_RANGE (ptr)); + adj->page_increment = (gdouble) amount; + gtk_adjustment_changed (adj); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setValues + (JNIEnv *env, jobject obj, jint value, jint visible, jint min, jint max) +{ + void *ptr; + GtkAdjustment *adj; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + adj = gtk_range_get_adjustment (GTK_RANGE (ptr)); + adj->page_size = (gdouble) visible; + + gtk_range_set_range (GTK_RANGE (ptr), (gdouble) min, (gdouble) max); + gtk_range_set_value (GTK_RANGE (ptr), (gdouble) value); + + gdk_threads_leave (); +} + +#if GTK_MINOR_VERSION > 4 +static gboolean +slider_moved_cb (GtkRange *range, + GtkScrollType scroll, + gdouble value, + jobject obj) +{ + GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range)); + + value = CLAMP (value, adj->lower, + (adj->upper - adj->page_size)); + + if (range->round_digits >= 0) + { + gdouble power; + gint i; + + i = range->round_digits; + power = 1; + while (i--) + power *= 10; + + value = floor ((value * power) + 0.5) / power; + } + + switch (scroll) + { + case GTK_SCROLL_STEP_BACKWARD: + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), obj, postAdjustmentEventID, + AWT_ADJUSTMENT_UNIT_DECREMENT, + (jint) value); + break; + case GTK_SCROLL_STEP_FORWARD: + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), obj, postAdjustmentEventID, + AWT_ADJUSTMENT_UNIT_INCREMENT, + (jint) value); + break; + case GTK_SCROLL_PAGE_BACKWARD: + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), obj, postAdjustmentEventID, + AWT_ADJUSTMENT_BLOCK_DECREMENT, + (jint) value); + break; + case GTK_SCROLL_PAGE_FORWARD: + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), obj, postAdjustmentEventID, + AWT_ADJUSTMENT_BLOCK_INCREMENT, + (jint) value); + break; + default: + /* GTK_SCROLL_JUMP: */ + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), obj, postAdjustmentEventID, + AWT_ADJUSTMENT_TRACK, + (jint) value); + break; + } + return FALSE; +} +#else +static void +post_change_event_cb (GtkRange *range, jobject peer) +{ + GtkAdjustment *adj; + adj = gtk_range_get_adjustment (range); + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postAdjustmentEventID, + AWT_ADJUSTMENT_TRACK, (jint) adj->value); +} +#endif diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextAreaPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextAreaPeer.c new file mode 100644 index 00000000000..9af88a026ee --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextAreaPeer.c @@ -0,0 +1,522 @@ +/* gtktextareapeer.c -- Native implementation of GtkTextAreaPeer + Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkTextAreaPeer.h" + +#define AWT_TEXTAREA_SCROLLBARS_BOTH 0 +#define AWT_TEXTAREA_SCROLLBARS_VERTICAL_ONLY 1 +#define AWT_TEXTAREA_SCROLLBARS_HORIZONTAL_ONLY 2 + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_create + (JNIEnv *env, jobject obj, + jint textview_width, jint textview_height, jint scroll) +{ + GtkWidget *text, *sw; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + text = gtk_text_view_new (); + gtk_widget_set_size_request (text, textview_width, textview_height); + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (text), TRUE); + + gtk_widget_show (text); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (sw), text); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + /* horizontal scrollbar */ + (scroll == AWT_TEXTAREA_SCROLLBARS_BOTH + || scroll == AWT_TEXTAREA_SCROLLBARS_HORIZONTAL_ONLY) ? + GTK_POLICY_ALWAYS : GTK_POLICY_NEVER, + /* vertical scrollbar */ + (scroll == AWT_TEXTAREA_SCROLLBARS_BOTH + || scroll == AWT_TEXTAREA_SCROLLBARS_VERTICAL_ONLY) ? + GTK_POLICY_ALWAYS : GTK_POLICY_NEVER); + + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text), + (scroll == AWT_TEXTAREA_SCROLLBARS_BOTH + || scroll == AWT_TEXTAREA_SCROLLBARS_HORIZONTAL_ONLY) + ? GTK_WRAP_NONE : GTK_WRAP_WORD); + + NSA_SET_PTR (env, obj, sw); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + GtkWidget *text = NULL; + GtkTextBuffer *buf; + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* Unwrap the text view from the scrolled window */ + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + /* TextComponent signals */ + cp_gtk_textcomponent_connect_signals (G_OBJECT (buf), gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (text), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_insert + (JNIEnv *env, jobject obj, jstring contents, jint position) +{ + GtkTextBuffer *buf; + GtkTextIter iter; + GtkWidget *text; + void *ptr; + const char *str; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + str = (*env)->GetStringUTFChars (env, contents, NULL); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_get_iter_at_offset (buf, &iter, position); + gtk_text_buffer_insert (buf, &iter, str, strlen (str)); + + (*env)->ReleaseStringUTFChars (env, contents, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_replaceRange + (JNIEnv *env, jobject obj, jstring contents, jint start, jint end) +{ + GtkWidget *text; + GtkTextBuffer *buf; + GtkTextIter iter, startIter, endIter; + void *ptr; + const char *str; + int mystart = start; + int myend = end; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + str = (*env)->GetStringUTFChars (env, contents, NULL); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + gtk_text_buffer_get_iter_at_offset (buf, &startIter, mystart); + gtk_text_buffer_get_iter_at_offset (buf, &endIter, myend); + gtk_text_buffer_delete (buf, &startIter, &endIter); + + gtk_text_buffer_get_iter_at_offset (buf, &iter, mystart); + gtk_text_buffer_insert(buf, &iter, str, strlen (str)); + + (*env)->ReleaseStringUTFChars (env, contents, str); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + GtkWidget *text; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET (text), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_gtkWidgetRequestFocus + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkWidget *text; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + gtk_widget_grab_focus (text); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getHScrollbarHeight + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkScrolledWindow *sw; + GtkRequisition requisition; + jint height = 0; + jint spacing = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW (ptr); + + if (sw) + { + gtk_widget_size_request (sw->hscrollbar, &requisition); + gtk_widget_style_get (GTK_WIDGET (sw), "scrollbar_spacing", &spacing, NULL); + height = requisition.height + spacing; + } + + gdk_threads_leave (); + + return height; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getVScrollbarWidth + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkScrolledWindow *sw; + GtkRequisition requisition; + jint width = 0; + jint spacing = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + sw = GTK_SCROLLED_WINDOW (ptr); + + if (sw) + { + gtk_widget_size_request (sw->vscrollbar, &requisition); + gtk_widget_style_get (GTK_WIDGET (sw), "scrollbar_spacing", &spacing, NULL); + width = requisition.width + spacing; + } + + gdk_threads_leave (); + + return width; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getCaretPosition + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextMark *mark; + GtkTextIter iter; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + mark = gtk_text_buffer_get_insert (buf); + gtk_text_buffer_get_iter_at_mark (buf, &iter, mark); + pos = gtk_text_iter_get_offset (&iter); + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_setCaretPosition + (JNIEnv *env, jobject obj, jint pos) +{ + void *ptr; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextIter iter; + GtkTextMark *oldmark; + GtkTextIter olditer; + int oldpos; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + /* Save old position. */ + oldmark = gtk_text_buffer_get_insert (buf); + gtk_text_buffer_get_iter_at_mark (buf, &olditer, oldmark); + oldpos = gtk_text_iter_get_offset (&olditer); + + /* Move to new position. */ + gtk_text_buffer_get_iter_at_offset (buf, &iter, pos); + gtk_text_buffer_place_cursor (buf, &iter); + + /* Scroll to new position. Alignment is determined + comparing the new position to the old position. */ + if (oldpos > pos) + gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (text), + &iter, 0, TRUE, 0, 0); + else if (oldpos < pos) + gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (text), + &iter, 0, TRUE, 1, 1); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getSelectionStart + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextIter start; + GtkTextIter end; + GtkTextMark *mark; + GtkTextIter iter; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + if (gtk_text_buffer_get_selection_bounds (buf, &start, &end)) + { + pos = gtk_text_iter_get_offset (&start); + } + else + { + mark = gtk_text_buffer_get_insert (buf); + gtk_text_buffer_get_iter_at_mark (buf, &iter, mark); + pos = gtk_text_iter_get_offset (&iter); + } + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getSelectionEnd + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextIter start; + GtkTextIter end; + GtkTextMark *mark; + GtkTextIter iter; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + if (gtk_text_buffer_get_selection_bounds (buf, &start, &end)) + { + pos = gtk_text_iter_get_offset (&end); + } + else + { + mark = gtk_text_buffer_get_insert (buf); + gtk_text_buffer_get_iter_at_mark (buf, &iter, mark); + pos = gtk_text_iter_get_offset (&iter); + } + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_select + (JNIEnv *env, jobject obj, jint start, jint end) +{ + void *ptr; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextIter iter; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_get_iter_at_offset (buf, &iter, start); + /* quickly move both 'insert' and 'selection_bound' to the + same position */ + gtk_text_buffer_place_cursor (buf, &iter); + gtk_text_buffer_get_iter_at_offset (buf, &iter, end); + gtk_text_buffer_move_mark_by_name (buf, "selection_bound", &iter); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_setEditable + (JNIEnv *env, jobject obj, jboolean state) +{ + void *ptr; + GtkWidget *text = NULL; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + gtk_text_view_set_editable (GTK_TEXT_VIEW (text), state); + + gdk_threads_leave (); +} + +JNIEXPORT jstring JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_getText + (JNIEnv *env, jobject obj) +{ + void *ptr; + char *contents = NULL; + jstring jcontents; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + GtkTextIter start, end; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_get_start_iter (buf, &start); + gtk_text_buffer_get_end_iter (buf, &end); + contents = gtk_text_buffer_get_text (buf, &start, &end, FALSE); + + jcontents = (*env)->NewStringUTF (env, contents); + g_free (contents); + + gdk_threads_leave (); + + return jcontents; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextAreaPeer_setText + (JNIEnv *env, jobject obj, jstring contents) +{ + void *ptr; + const char *str; + GtkWidget *text = NULL; + GtkTextBuffer *buf; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + str = (*env)->GetStringUTFChars (env, contents, NULL); + + text = gtk_bin_get_child (GTK_BIN (ptr)); + + buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_set_text (buf, str, strlen (str)); + + (*env)->ReleaseStringUTFChars (env, contents, str); + + gdk_threads_leave (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c new file mode 100644 index 00000000000..eb658339dab --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c @@ -0,0 +1,423 @@ +/* gtktextfieldpeer.c -- Native implementation of GtkTextFieldPeer + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkTextFieldPeer.h" + +/* the color used for highlighting when the foreground is black, + since black highlights aren't a Good Idea. */ +#define BB_RED 16962 +#define BB_GREEN 26985 +#define BB_BLUE 31611 + +static jmethodID postTextEventID; + +void +cp_gtk_textcomponent_init_jni (void) +{ + jclass gtkcomponentpeer; + + gtkcomponentpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkComponentPeer"); + + postTextEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer, + "postTextEvent", + "()V"); +} + +static void textcomponent_changed_cb (GtkEditable *editable, jobject peer); + +static jint get_border_width (GtkWidget *entry); + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_create + (JNIEnv *env, jobject obj, jint text_width) +{ + GtkWidget *entry; + + gdk_threads_enter (); + + /* Create global reference and save it for future use */ + NSA_SET_GLOBAL_REF (env, obj); + + entry = gtk_entry_new (); + gtk_widget_set_size_request (entry, + text_width + 2 * get_border_width (entry), -1); + + NSA_SET_PTR (env, obj, entry); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + /* TextComponent signals */ + cp_gtk_textcomponent_connect_signals (G_OBJECT (ptr), gref); + + /* Component signals */ + cp_gtk_component_connect_signals (G_OBJECT (ptr), gref); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetSetBackground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + gtk_widget_modify_base (GTK_WIDGET (ptr), GTK_STATE_NORMAL, &color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetSetForeground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + gtk_widget_modify_text (GTK_WIDGET (ptr), GTK_STATE_NORMAL, &color); + + if ( red == 0 && green == 0 && blue == 0) + { + color.red = BB_RED; + color.green = BB_GREEN; + color.blue = BB_BLUE; + } + gtk_widget_modify_base (GTK_WIDGET (ptr), GTK_STATE_SELECTED, &color); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkEntryGetBorderWidth + (JNIEnv *env, jobject obj) +{ + void *ptr; + int border_width = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + border_width = get_border_width (GTK_WIDGET (ptr)); + + gdk_threads_leave (); + + return border_width; +} + +/* GTK hard-codes this value. It is the space between a GtkEntry's + frame and its text. */ +#define INNER_BORDER 2 + +static jint +get_border_width (GtkWidget *entry) +{ + gint focus_width; + gboolean interior_focus; + int x_border_width = INNER_BORDER; + + gtk_widget_style_get (entry, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + NULL); + + if (GTK_ENTRY (entry)->has_frame) + x_border_width += entry->style->xthickness; + + if (!interior_focus) + x_border_width += focus_width; + + return x_border_width; +} + +#undef INNER_BORDER + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setEchoChar + (JNIEnv *env, jobject obj, jchar c) +{ + void *ptr; + GtkEntry *entry; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + entry = GTK_ENTRY (ptr); + + if (c != 0) + { + /* FIXME: use gtk_entry_set_invisible_char (GtkEntry *entry, + gunichar ch) here. That means we must convert from jchar + (utf16) to gunichar (ucs4). */ + gtk_entry_set_visibility (entry, FALSE); + } + else + gtk_entry_set_visibility (entry, TRUE); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetModifyFont + (JNIEnv *env, jobject obj, jstring name, jint style, jint size) +{ + const char *font_name; + void *ptr; + PangoFontDescription *font_desc; + + gdk_threads_enter(); + + ptr = NSA_GET_PTR (env, obj); + + font_name = (*env)->GetStringUTFChars (env, name, NULL); + + font_desc = pango_font_description_from_string (font_name); + pango_font_description_set_size (font_desc, + size * cp_gtk_dpi_conversion_factor); + + if (style & AWT_STYLE_BOLD) + pango_font_description_set_weight (font_desc, PANGO_WEIGHT_BOLD); + + if (style & AWT_STYLE_ITALIC) + pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE); + + gtk_widget_modify_font (GTK_WIDGET (ptr), font_desc); + + pango_font_description_free (font_desc); + + (*env)->ReleaseStringUTFChars (env, name, font_name); + + gdk_threads_leave(); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_getCaretPosition + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + pos = gtk_editable_get_position (GTK_EDITABLE (ptr)); + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setCaretPosition + (JNIEnv *env, jobject obj, jint pos) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_editable_set_position (GTK_EDITABLE (ptr), pos); + + gdk_threads_leave (); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_getSelectionStart + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + int starti, endi; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (ptr), &starti, &endi)) + pos = starti; + else + pos = gtk_editable_get_position (GTK_EDITABLE (ptr)); + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_getSelectionEnd + (JNIEnv *env, jobject obj) +{ + void *ptr; + int pos = 0; + int starti, endi; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (gtk_editable_get_selection_bounds (GTK_EDITABLE (ptr), &starti, &endi)) + pos = endi; + else + pos = gtk_editable_get_position (GTK_EDITABLE (ptr)); + + gdk_threads_leave (); + + return pos; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_select + (JNIEnv *env, jobject obj, jint start, jint end) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_editable_select_region (GTK_EDITABLE (ptr), start, end); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setEditable + (JNIEnv *env, jobject obj, jboolean state) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_editable_set_editable (GTK_EDITABLE (ptr), state); + + gdk_threads_leave (); +} + +JNIEXPORT jstring JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_getText + (JNIEnv *env, jobject obj) +{ + void *ptr; + char *contents = NULL; + jstring jcontents; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + contents = gtk_editable_get_chars (GTK_EDITABLE (ptr), 0, -1); + + jcontents = (*env)->NewStringUTF (env, contents); + + g_free (contents); + + gdk_threads_leave (); + + return jcontents; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setText + (JNIEnv *env, jobject obj, jstring contents) +{ + void *ptr; + const char *str; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + str = (*env)->GetStringUTFChars (env, contents, NULL); + + gtk_entry_set_text (GTK_ENTRY (ptr), str); + + (*env)->ReleaseStringUTFChars (env, contents, str); + + gdk_threads_leave (); +} + +void +cp_gtk_textcomponent_connect_signals (GObject *ptr, jobject *gref) +{ + g_signal_connect (G_OBJECT(ptr), "changed", + G_CALLBACK (textcomponent_changed_cb), *gref); +} + +static void +textcomponent_changed_cb (GtkEditable *editable __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postTextEventID); + gdk_threads_enter (); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c new file mode 100644 index 00000000000..a8e1957ee20 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c @@ -0,0 +1,524 @@ +/* gtktoolkit.c -- Native portion of GtkToolkit + Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkToolkit.h" +#include "gthread-jni.h" +#include "jcl.h" + +#include <sys/time.h> + +#define RC_FILE ".classpath-gtkrc" + +/* From java.awt.SystemColor */ +#define AWT_DESKTOP 0 +#define AWT_ACTIVE_CAPTION 1 +#define AWT_ACTIVE_CAPTION_TEXT 2 +#define AWT_ACTIVE_CAPTION_BORDER 3 +#define AWT_INACTIVE_CAPTION 4 +#define AWT_INACTIVE_CAPTION_TEXT 5 +#define AWT_INACTIVE_CAPTION_BORDER 6 +#define AWT_WINDOW 7 +#define AWT_WINDOW_BORDER 8 +#define AWT_WINDOW_TEXT 9 +#define AWT_MENU 10 +#define AWT_MENU_TEXT 11 +#define AWT_TEXT 12 +#define AWT_TEXT_TEXT 13 +#define AWT_TEXT_HIGHLIGHT 14 +#define AWT_TEXT_HIGHLIGHT_TEXT 15 +#define AWT_TEXT_INACTIVE_TEXT 16 +#define AWT_CONTROL 17 +#define AWT_CONTROL_TEXT 18 +#define AWT_CONTROL_HIGHLIGHT 19 +#define AWT_CONTROL_LT_HIGHLIGHT 20 +#define AWT_CONTROL_SHADOW 21 +#define AWT_CONTROL_DK_SHADOW 22 +#define AWT_SCROLLBAR 23 +#define AWT_INFO 24 +#define AWT_INFO_TEXT 25 +#define AWT_NUM_COLORS 26 + +struct state_table *cp_gtk_native_state_table; +struct state_table *cp_gtk_native_global_ref_table; + +static jclass gtkgenericpeer; +static JavaVM *java_vm; +static jmethodID printCurrentThreadID; + +union env_union +{ + void *void_env; + JNIEnv *jni_env; +}; + +JNIEnv * +cp_gtk_gdk_env() +{ + union env_union tmp; + g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK); + return tmp.jni_env; +} + + +GtkWindowGroup *cp_gtk_global_window_group; +double cp_gtk_dpi_conversion_factor; + +static void init_glib_threads(JNIEnv *, jint); + +static void init_dpi_conversion_factor (void); +static void dpi_changed_cb (GtkSettings *settings, + GParamSpec *pspec); + +#if GTK_MINOR_VERSION > 4 +static GLogFunc old_glog_func; +static void glog_func (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data); +#endif + +/* + * Call gtk_init. It is very important that this happen before any other + * gtk calls. + * + * The portableNativeSync argument may have the values: + * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync + * is set to "true". + * 0 if it is set to "false" + * -1 if unset. + */ + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env, + jclass clazz __attribute__((unused)), + jint portableNativeSync) +{ + int argc = 1; + char **argv; + char *homedir, *rcpath = NULL; + + gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer"); + + printCurrentThreadID = (*env)->GetStaticMethodID (env, gtkgenericpeer, + "printCurrentThread", "()V"); + + NSA_INIT (env, gtkgenericpeer); + + g_assert((*env)->GetJavaVM(env, &java_vm) == 0); + + /* GTK requires a program's argc and argv variables, and requires that they + be valid. Set it up. */ + argv = (char **) g_malloc (sizeof (char *) * 2); + argv[0] = (char *) g_malloc(1); + argv[0][0] = '\0'; + argv[1] = NULL; + + init_glib_threads(env, portableNativeSync); + + /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */ + gdk_threads_init(); + + gtk_init (&argc, &argv); + + gdk_rgb_init (); + gtk_widget_set_default_colormap (gdk_rgb_get_cmap ()); + gtk_widget_set_default_visual (gdk_rgb_get_visual ()); + + /* Make sure queued calls don't get sent to GTK/GDK while + we're shutting down. */ + atexit (gdk_threads_enter); + + if ((homedir = getenv ("HOME"))) + { + rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2); + sprintf (rcpath, "%s/%s", homedir, RC_FILE); + } + + gtk_rc_parse ((rcpath) ? rcpath : RC_FILE); + + g_free (rcpath); + g_free (argv[0]); + g_free (argv); + + /* On errors or warning print a whole stacktrace. */ +#if GTK_MINOR_VERSION > 4 + old_glog_func = g_log_set_default_handler (&glog_func, NULL); +#endif + +#if GTK_CAIRO + cp_gtk_graphics2d_init_jni (); +#endif + cp_gtk_graphics_init_jni (); + cp_gtk_button_init_jni (); + cp_gtk_checkbox_init_jni (); + cp_gtk_choice_init_jni (); + cp_gtk_component_init_jni (); + cp_gtk_list_init_jni (); + cp_gtk_menuitem_init_jni (); + cp_gtk_scrollbar_init_jni (); + cp_gtk_textcomponent_init_jni (); + cp_gtk_window_init_jni (); + + cp_gtk_global_window_group = gtk_window_group_new (); + + init_dpi_conversion_factor (); +} + + +/** Initialize GLIB's threads properly, based on the value of the + gnu.classpath.awt.gtk.portable.native.sync Java system property. If + that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO: + In some release following 0.10, that config.h macro will go away.) + */ +static void +init_glib_threads(JNIEnv *env, jint portableNativeSync) +{ + if (portableNativeSync < 0) + { +#ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system + property */ + portableNativeSync = 1; +#else + portableNativeSync = 0; +#endif + } + + (*env)->GetJavaVM( env, &cp_gtk_the_vm ); + if (!g_thread_supported ()) + { + if (portableNativeSync) + g_thread_init ( &cp_gtk_portable_native_sync_jni_functions ); + else + g_thread_init ( NULL ); + } + else + { + /* Warn if portable native sync is desired but the threading + system is already initialized. In that case we can't + override the threading implementation with our portable + native sync functions. */ + if (portableNativeSync) + g_printerr ("peer warning: portable native sync disabled.\n"); + } + + /* Debugging progress message; uncomment if needed: */ + /* printf("called gthread init\n"); */ +} + +void +cp_gtk_print_current_thread (void) +{ + (*cp_gtk_gdk_env())->CallStaticVoidMethod (cp_gtk_gdk_env(), gtkgenericpeer, printCurrentThreadID); +} + +/* This is a big hack, needed until this pango bug is resolved: + http://bugzilla.gnome.org/show_bug.cgi?id=119081. + See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html + for details. */ +static void +init_dpi_conversion_factor () +{ + GtkSettings *settings = gtk_settings_get_default (); + GObjectClass *klass; + + klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings)); + if (g_object_class_find_property (klass, "gtk-xft-dpi")) + { + int int_dpi; + g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL); + /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we + have to do approximate calculation here. */ + if (int_dpi < 0) + cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.; + else + cp_gtk_dpi_conversion_factor = + PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE); + + g_signal_connect (settings, "notify::gtk-xft-dpi", + G_CALLBACK (dpi_changed_cb), NULL); + } + else + /* Approximate. */ + cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.; +} + +static void +dpi_changed_cb (GtkSettings *settings, + GParamSpec *pspec __attribute__((unused))) +{ + int int_dpi; + g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL); + if (int_dpi < 0) + cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.; + else + cp_gtk_dpi_conversion_factor = + PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE); +} + +static int +within_human_latency_tolerance(struct timeval *init) +{ + struct timeval curr; + unsigned long milliseconds_elapsed; + + gettimeofday(&curr, NULL); + + milliseconds_elapsed = (((curr.tv_sec * 1000) + (curr.tv_usec / 1000)) + - ((init->tv_sec * 1000) + (init->tv_usec / 1000))); + + return milliseconds_elapsed < 100; +} + +#if GTK_MINOR_VERSION > 4 +static void +glog_func (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + old_glog_func (log_domain, log_level, message, user_data); + if (log_level & (G_LOG_LEVEL_ERROR + | G_LOG_LEVEL_CRITICAL + | G_LOG_LEVEL_WARNING)) + { + JNIEnv *env = cp_gtk_gdk_env (); + jthrowable *exc = (*env)->ExceptionOccurred(env); + gchar *detail = g_strconcat (log_domain, ": ", message, NULL); + JCL_ThrowException (env, "java/lang/InternalError", detail); + g_free (detail); + (*env)->ExceptionDescribe (env); + if (exc != NULL) + (*env)->Throw (env, exc); + else + (*env)->ExceptionClear (env); + } +} +#endif + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_iterateNativeQueue +(JNIEnv *env, + jobject self __attribute__((unused)), + jobject lockedQueue, + jboolean block) +{ + /* We're holding an EventQueue lock, and we're about to acquire the GDK + * lock before dropping the EventQueue lock. This can deadlock if someone + * holds the GDK lock and wants to acquire the EventQueue lock; however + * all callbacks from GTK happen with the GDK lock released, so this + * would only happen in an odd case such as some JNI helper code + * acquiring the GDK lock and calling back into + * EventQueue.getNextEvent(). + */ + + struct timeval init; + gettimeofday(&init, NULL); + + gdk_threads_enter (); + (*env)->MonitorExit (env, lockedQueue); + + if (block) + { + + /* If we're blocking-when-empty, we want a do .. while loop. */ + do + gtk_main_iteration (); + while (within_human_latency_tolerance (&init) + && gtk_events_pending ()); + } + else + { + /* If we're not blocking-when-empty, we want a while loop. */ + while (within_human_latency_tolerance (&init) + && gtk_events_pending ()) + gtk_main_iteration (); + } + + (*env)->MonitorEnter (env, lockedQueue); + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_wakeNativeQueue + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + g_main_context_wakeup (NULL); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_nativeQueueEmpty + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + jboolean empty = FALSE; + + gdk_threads_enter (); + + empty = ! gtk_events_pending(); + + gdk_threads_leave (); + + return empty; +} + + +static jint gdk_color_to_java_color (GdkColor color); + + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_beep + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + gdk_threads_enter (); + + gdk_beep (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_sync + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + gdk_threads_enter (); + + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jintArray jdims) +{ + jint *dims = (*env)->GetIntArrayElements (env, jdims, 0); + + gdk_threads_enter (); + + dims[0] = gdk_screen_width (); + dims[1] = gdk_screen_height (); + + gdk_threads_leave (); + + (*env)->ReleaseIntArrayElements(env, jdims, dims, 0); +} + +JNIEXPORT jint JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + jint res; + + gdk_threads_enter (); + + res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4); + + gdk_threads_leave (); + + return res; +} + +#define CONVERT(type, state) \ + gdk_color_to_java_color (style->type[GTK_STATE_ ## state]) + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors + (JNIEnv *env, jobject obj __attribute__((unused)), + jintArray jcolors) +{ + jint *colors; + GtkStyle *style; + + gdk_threads_enter (); + + colors = (*env)->GetIntArrayElements (env, jcolors, 0); + + style = gtk_widget_get_default_style (); + + colors[AWT_DESKTOP] = CONVERT (bg, SELECTED); + colors[AWT_ACTIVE_CAPTION] = CONVERT (bg, SELECTED); + colors[AWT_ACTIVE_CAPTION_TEXT] = CONVERT (text, SELECTED); + colors[AWT_ACTIVE_CAPTION_BORDER] = CONVERT (fg, NORMAL); + colors[AWT_INACTIVE_CAPTION] = CONVERT (base, INSENSITIVE); + colors[AWT_INACTIVE_CAPTION_TEXT] = CONVERT (fg, INSENSITIVE); + colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE); + colors[AWT_WINDOW] = CONVERT (bg, NORMAL); + colors[AWT_WINDOW_BORDER] = CONVERT (fg, NORMAL); + colors[AWT_WINDOW_TEXT] = CONVERT (fg, NORMAL); + colors[AWT_MENU] = CONVERT (bg, NORMAL); + colors[AWT_MENU_TEXT] = CONVERT (fg, NORMAL); + colors[AWT_TEXT] = CONVERT (bg, NORMAL); + colors[AWT_TEXT_TEXT] = CONVERT (fg, NORMAL); + colors[AWT_TEXT_HIGHLIGHT] = CONVERT (bg, SELECTED); + colors[AWT_TEXT_HIGHLIGHT_TEXT] = CONVERT (fg, SELECTED); + colors[AWT_TEXT_INACTIVE_TEXT] = CONVERT (bg, INSENSITIVE); + colors[AWT_CONTROL] = CONVERT (bg, NORMAL); + colors[AWT_CONTROL_TEXT] = CONVERT (fg, NORMAL); + colors[AWT_CONTROL_HIGHLIGHT] = CONVERT (base, ACTIVE); + colors[AWT_CONTROL_LT_HIGHLIGHT] = CONVERT (bg, PRELIGHT); + colors[AWT_CONTROL_SHADOW] = CONVERT (bg, ACTIVE); + colors[AWT_CONTROL_DK_SHADOW] = CONVERT (fg, INSENSITIVE); + colors[AWT_SCROLLBAR] = CONVERT (base, INSENSITIVE); + colors[AWT_INFO] = CONVERT (bg, NORMAL); + colors[AWT_INFO_TEXT] = CONVERT (fg, NORMAL); + + (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0); + + gdk_threads_leave (); +} + +#undef CONVERT + +static jint +gdk_color_to_java_color (GdkColor gdk_color) +{ + guchar red; + guchar green; + guchar blue; + float factor; + + factor = 255.0 / 65535.0; + + red = (float) gdk_color.red * factor; + green = (float) gdk_color.green * factor; + blue = (float) gdk_color.blue * factor; + + return (jint) (0xff000000 | (red << 16) | (green << 8) | blue); +} diff --git a/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c new file mode 100644 index 00000000000..650d9b6030e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c @@ -0,0 +1,2181 @@ +/* gtkwindowpeer.c -- Native implementation of GtkWindowPeer + Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkWindowPeer.h" +#include <gdk/gdkprivate.h> +#include <gdk/gdkx.h> +#include <X11/Xatom.h> +#include <gdk/gdkkeysyms.h> + +#define AWT_WINDOW_OPENED 200 +#define AWT_WINDOW_CLOSING 201 +#define AWT_WINDOW_CLOSED 202 +#define AWT_WINDOW_ICONIFIED 203 +#define AWT_WINDOW_DEICONIFIED 204 +#define AWT_WINDOW_ACTIVATED 205 +#define AWT_WINDOW_DEACTIVATED 206 +#define AWT_WINDOW_GAINED_FOCUS 207 +#define AWT_WINDOW_LOST_FOCUS 208 +#define AWT_WINDOW_STATE_CHANGED 209 + +/* Virtual Keys */ +/* This list should be kept in the same order as the VK_ field + declarations in KeyEvent.java. */ +#define VK_ENTER '\n' +#define VK_BACK_SPACE '\b' +#define VK_TAB '\t' +#define VK_CANCEL 3 +#define VK_CLEAR 12 +#define VK_SHIFT 16 +#define VK_CONTROL 17 +#define VK_ALT 18 +#define VK_PAUSE 19 +#define VK_CAPS_LOCK 20 +#define VK_ESCAPE 27 +#define VK_SPACE ' ' +#define VK_PAGE_UP 33 +#define VK_PAGE_DOWN 34 +#define VK_END 35 +#define VK_HOME 36 +#define VK_LEFT 37 +#define VK_UP 38 +#define VK_RIGHT 39 +#define VK_DOWN 40 +#define VK_COMMA ',' +#define VK_MINUS '-' +#define VK_PERIOD '.' +#define VK_SLASH '/' +#define VK_0 '0' +#define VK_1 '1' +#define VK_2 '2' +#define VK_3 '3' +#define VK_4 '4' +#define VK_5 '5' +#define VK_6 '6' +#define VK_7 '7' +#define VK_8 '8' +#define VK_9 '9' +#define VK_SEMICOLON ';' +#define VK_EQUALS '=' +#define VK_A 'A' +#define VK_B 'B' +#define VK_C 'C' +#define VK_D 'D' +#define VK_E 'E' +#define VK_F 'F' +#define VK_G 'G' +#define VK_H 'H' +#define VK_I 'I' +#define VK_J 'J' +#define VK_K 'K' +#define VK_L 'L' +#define VK_M 'M' +#define VK_N 'N' +#define VK_O 'O' +#define VK_P 'P' +#define VK_Q 'Q' +#define VK_R 'R' +#define VK_S 'S' +#define VK_T 'T' +#define VK_U 'U' +#define VK_V 'V' +#define VK_W 'W' +#define VK_X 'X' +#define VK_Y 'Y' +#define VK_Z 'Z' +#define VK_OPEN_BRACKET '[' +#define VK_BACK_SLASH '\\' +#define VK_CLOSE_BRACKET ']' +/* See gtkpeer.h */ +/* #define VK_NUMPAD0 96 */ +/* #define VK_NUMPAD1 97 */ +/* #define VK_NUMPAD2 98 */ +/* #define VK_NUMPAD3 99 */ +/* #define VK_NUMPAD4 100 */ +/* #define VK_NUMPAD5 101 */ +/* #define VK_NUMPAD6 102 */ +/* #define VK_NUMPAD7 103 */ +/* #define VK_NUMPAD8 104 */ +/* #define VK_NUMPAD9 105 */ +#define VK_MULTIPLY 106 +#define VK_ADD 107 +#define VK_SEPARATER 108 +#define VK_SEPARATOR 108 +#define VK_SUBTRACT 109 +/* See gtkpeer.h */ +/* #define VK_DECIMAL 110 */ +#define VK_DIVIDE 111 +#define VK_DELETE 127 +#define VK_NUM_LOCK 144 +#define VK_SCROLL_LOCK 145 +#define VK_F1 112 +#define VK_F2 113 +#define VK_F3 114 +#define VK_F4 115 +#define VK_F5 116 +#define VK_F6 117 +#define VK_F7 118 +#define VK_F8 119 +#define VK_F9 120 +#define VK_F10 121 +#define VK_F11 122 +#define VK_F12 123 +#define VK_F13 61440 +#define VK_F14 61441 +#define VK_F15 61442 +#define VK_F16 61443 +#define VK_F17 61444 +#define VK_F18 61445 +#define VK_F19 61446 +#define VK_F20 61447 +#define VK_F21 61448 +#define VK_F22 61449 +#define VK_F23 61450 +#define VK_F24 61451 +#define VK_PRINTSCREEN 154 +#define VK_INSERT 155 +#define VK_HELP 156 +#define VK_META 157 +#define VK_BACK_QUOTE 192 +#define VK_QUOTE 222 +#define VK_KP_UP 224 +#define VK_KP_DOWN 225 +#define VK_KP_LEFT 226 +#define VK_KP_RIGHT 227 +#define VK_DEAD_GRAVE 128 +#define VK_DEAD_ACUTE 129 +#define VK_DEAD_CIRCUMFLEX 130 +#define VK_DEAD_TILDE 131 +#define VK_DEAD_MACRON 132 +#define VK_DEAD_BREVE 133 +#define VK_DEAD_ABOVEDOT 134 +#define VK_DEAD_DIAERESIS 135 +#define VK_DEAD_ABOVERING 136 +#define VK_DEAD_DOUBLEACUTE 137 +#define VK_DEAD_CARON 138 +#define VK_DEAD_CEDILLA 139 +#define VK_DEAD_OGONEK 140 +#define VK_DEAD_IOTA 141 +#define VK_DEAD_VOICED_SOUND 142 +#define VK_DEAD_SEMIVOICED_SOUND 143 +#define VK_AMPERSAND 150 +#define VK_ASTERISK 151 +#define VK_QUOTEDBL 152 +#define VK_LESS 153 +#define VK_GREATER 160 +#define VK_BRACELEFT 161 +#define VK_BRACERIGHT 162 +#define VK_AT 512 +#define VK_COLON 513 +#define VK_CIRCUMFLEX 514 +#define VK_DOLLAR 515 +#define VK_EURO_SIGN 516 +#define VK_EXCLAMATION_MARK 517 +#define VK_INVERTED_EXCLAMATION_MARK 518 +#define VK_LEFT_PARENTHESIS 519 +#define VK_NUMBER_SIGN 520 +#define VK_PLUS 521 +#define VK_RIGHT_PARENTHESIS 522 +#define VK_UNDERSCORE 523 +#define VK_FINAL 24 +#define VK_CONVERT 28 +#define VK_NONCONVERT 29 +#define VK_ACCEPT 30 +#define VK_MODECHANGE 31 +#define VK_KANA 21 +#define VK_KANJI 25 +#define VK_ALPHANUMERIC 240 +#define VK_KATAKANA 241 +#define VK_HIRAGANA 242 +#define VK_FULL_WIDTH 243 +#define VK_HALF_WIDTH 244 +#define VK_ROMAN_CHARACTERS 245 +#define VK_ALL_CANDIDATES 256 +#define VK_PREVIOUS_CANDIDATE 257 +#define VK_CODE_INPUT 258 +#define VK_JAPANESE_KATAKANA 259 +#define VK_JAPANESE_HIRAGANA 260 +#define VK_JAPANESE_ROMAN 261 +#define VK_KANA_LOCK 262 +#define VK_INPUT_METHOD_ON_OFF 263 +#define VK_CUT 65489 +#define VK_COPY 65485 +#define VK_PASTE 65487 +#define VK_UNDO 65483 +#define VK_AGAIN 65481 +#define VK_FIND 65488 +#define VK_PROPS 65482 +#define VK_STOP 65480 +#define VK_COMPOSE 65312 +#define VK_ALT_GRAPH 65406 +#define VK_UNDEFINED 0 + +#define AWT_KEY_CHAR_UNDEFINED 0 + +#define AWT_FRAME_STATE_NORMAL 0 +#define AWT_FRAME_STATE_ICONIFIED 1 +#define AWT_FRAME_STATE_MAXIMIZED_HORIZ 2 +#define AWT_FRAME_STATE_MAXIMIZED_VERT 4 +#define AWT_FRAME_STATE_MAXIMIZED_BOTH 6 + +static jmethodID postKeyEventID; +static jmethodID postWindowEventID; +static jmethodID postConfigureEventID; +static jmethodID postInsetsChangedEventID; +static jmethodID windowGetWidthID; +static jmethodID windowGetHeightID; +static jmethodID setBoundsCallbackID; + +void +cp_gtk_window_init_jni (void) +{ + jclass window; + jclass gtkwindowpeer; + + window = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), "java/awt/Window"); + + setBoundsCallbackID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), window, + "setBoundsCallback", + "(IIII)V"); + + gtkwindowpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkWindowPeer"); + + postKeyEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "postKeyEvent", "(IJIICI)V"); + + postWindowEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "postWindowEvent", + "(ILjava/awt/Window;I)V"); + + postConfigureEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "postConfigureEvent", "(IIII)V"); + + postInsetsChangedEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "postInsetsChangedEvent", + "(IIII)V"); + + windowGetWidthID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "getWidth", "()I"); + + windowGetHeightID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkwindowpeer, + "getHeight", "()I"); + + gtkwindowpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/peer/gtk/GtkWindowPeer"); +} + +/* Get the first keyval in the keymap for this event's keycode. The + first keyval corresponds roughly to Java's notion of a virtual + key. Returns the uppercase version of the first keyval. */ +static guint +get_first_keyval_from_keymap (GdkEventKey *event) +{ + guint keyval; + guint *keyvals; + gint n_entries; + + if (!gdk_keymap_get_entries_for_keycode (NULL, + event->hardware_keycode, + NULL, + &keyvals, + &n_entries)) + { + g_warning ("No keyval found for hardware keycode %d\n", + event->hardware_keycode); + /* Try to recover by using the keyval in the event structure. */ + keyvals = &(event->keyval); + } + keyval = keyvals[0]; + g_free (keyvals); + + return gdk_keyval_to_upper (keyval); +} + +#ifdef __GNUC__ +__inline +#endif +static jint +keysym_to_awt_keycode (GdkEventKey *event) +{ + guint ukeyval; + guint state; + + ukeyval = get_first_keyval_from_keymap (event); + state = event->state; + + /* VK_A through VK_Z */ + if (ukeyval >= GDK_A && ukeyval <= GDK_Z) + return ukeyval; + + /* VK_0 through VK_9 */ + if (ukeyval >= GDK_0 && ukeyval <= GDK_9) + return ukeyval; + + switch (ukeyval) + { + case GDK_Return: + case GDK_KP_Enter: + return VK_ENTER; + case GDK_BackSpace: + return VK_BACK_SPACE; + case GDK_Tab: + return VK_TAB; + case GDK_Cancel: + return VK_CANCEL; + case GDK_Clear: + return VK_CLEAR; + case GDK_Shift_L: + case GDK_Shift_R: + return VK_SHIFT; + case GDK_Control_L: + case GDK_Control_R: + return VK_CONTROL; + case GDK_Alt_L: + case GDK_Alt_R: + return VK_ALT; + case GDK_Pause: + return VK_PAUSE; + case GDK_Caps_Lock: + return VK_CAPS_LOCK; + case GDK_Escape: + return VK_ESCAPE; + case GDK_space: + return VK_SPACE; + case GDK_KP_Page_Up: + /* For keys on the numeric keypad, the JVM produces one of two + virtual keys, depending on the num lock state. */ + if (state & GDK_MOD2_MASK) + return VK_NUMPAD9; + else + return VK_PAGE_UP; + case GDK_Page_Up: + return VK_PAGE_UP; + case GDK_KP_Page_Down: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD3; + else + return VK_PAGE_DOWN; + case GDK_Page_Down: + return VK_PAGE_DOWN; + case GDK_KP_End: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD1; + else + return VK_END; + case GDK_End: + return VK_END; + case GDK_KP_Home: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD7; + else + return VK_HOME; + case GDK_Home: + return VK_HOME; + case GDK_KP_Begin: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD5; + else + return VK_UNDEFINED; + case GDK_Left: + return VK_LEFT; + case GDK_Up: + return VK_UP; + case GDK_Right: + return VK_RIGHT; + case GDK_Down: + return VK_DOWN; + case GDK_comma: + return VK_COMMA; + case GDK_minus: + return VK_MINUS; + case GDK_period: + return VK_PERIOD; + case GDK_slash: + return VK_SLASH; + /* + return VK_0; + return VK_1; + return VK_2; + return VK_3; + return VK_4; + return VK_5; + return VK_6; + return VK_7; + return VK_8; + return VK_9; + */ + case GDK_semicolon: + return VK_SEMICOLON; + case GDK_equal: + return VK_EQUALS; + /* + return VK_A; + return VK_B; + return VK_C; + return VK_D; + return VK_E; + return VK_F; + return VK_G; + return VK_H; + return VK_I; + return VK_J; + return VK_K; + return VK_L; + return VK_M; + return VK_N; + return VK_O; + return VK_P; + return VK_Q; + return VK_R; + return VK_S; + return VK_T; + return VK_U; + return VK_V; + return VK_W; + return VK_X; + return VK_Y; + return VK_Z; + */ + case GDK_bracketleft: + return VK_OPEN_BRACKET; + case GDK_backslash: + return VK_BACK_SLASH; + case GDK_bracketright: + return VK_CLOSE_BRACKET; + case GDK_KP_0: + return VK_NUMPAD0; + case GDK_KP_1: + return VK_NUMPAD1; + case GDK_KP_2: + return VK_NUMPAD2; + case GDK_KP_3: + return VK_NUMPAD3; + case GDK_KP_4: + return VK_NUMPAD4; + case GDK_KP_5: + return VK_NUMPAD5; + case GDK_KP_6: + return VK_NUMPAD6; + case GDK_KP_7: + return VK_NUMPAD7; + case GDK_KP_8: + return VK_NUMPAD8; + case GDK_KP_9: + return VK_NUMPAD9; + case GDK_KP_Multiply: + return VK_MULTIPLY; + case GDK_KP_Add: + return VK_ADD; + /* + return VK_SEPARATER; + */ + case GDK_KP_Separator: + return VK_SEPARATOR; + case GDK_KP_Subtract: + return VK_SUBTRACT; + case GDK_KP_Decimal: + return VK_DECIMAL; + case GDK_KP_Divide: + return VK_DIVIDE; + case GDK_KP_Delete: + if (state & GDK_MOD2_MASK) + return VK_DECIMAL; + else + return VK_DELETE; + case GDK_Delete: + return VK_DELETE; + case GDK_Num_Lock: + return VK_NUM_LOCK; + case GDK_Scroll_Lock: + return VK_SCROLL_LOCK; + case GDK_F1: + return VK_F1; + case GDK_F2: + return VK_F2; + case GDK_F3: + return VK_F3; + case GDK_F4: + return VK_F4; + case GDK_F5: + return VK_F5; + case GDK_F6: + return VK_F6; + case GDK_F7: + return VK_F7; + case GDK_F8: + return VK_F8; + case GDK_F9: + return VK_F9; + case GDK_F10: + return VK_F10; + case GDK_F11: + return VK_F11; + case GDK_F12: + return VK_F12; + case GDK_F13: + return VK_F13; + case GDK_F14: + return VK_F14; + case GDK_F15: + return VK_F15; + case GDK_F16: + return VK_F16; + case GDK_F17: + return VK_F17; + case GDK_F18: + return VK_F18; + case GDK_F19: + return VK_F19; + case GDK_F20: + return VK_F20; + case GDK_F21: + return VK_F21; + case GDK_F22: + return VK_F22; + case GDK_F23: + return VK_F23; + case GDK_F24: + return VK_F24; + case GDK_Print: + return VK_PRINTSCREEN; + case GDK_KP_Insert: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD0; + else + return VK_INSERT; + case GDK_Insert: + return VK_INSERT; + case GDK_Help: + return VK_HELP; + case GDK_Meta_L: + case GDK_Meta_R: + return VK_META; + case GDK_grave: + return VK_BACK_QUOTE; + case GDK_apostrophe: + return VK_QUOTE; + case GDK_KP_Up: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD8; + else + return VK_KP_UP; + case GDK_KP_Down: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD2; + else + return VK_KP_DOWN; + case GDK_KP_Left: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD4; + else + return VK_KP_LEFT; + case GDK_KP_Right: + if (state & GDK_MOD2_MASK) + return VK_NUMPAD6; + else + return VK_KP_RIGHT; + case GDK_dead_grave: + return VK_DEAD_GRAVE; + case GDK_dead_acute: + return VK_DEAD_ACUTE; + case GDK_dead_circumflex: + return VK_DEAD_CIRCUMFLEX; + case GDK_dead_tilde: + return VK_DEAD_TILDE; + case GDK_dead_macron: + return VK_DEAD_MACRON; + case GDK_dead_breve: + return VK_DEAD_BREVE; + case GDK_dead_abovedot: + return VK_DEAD_ABOVEDOT; + case GDK_dead_diaeresis: + return VK_DEAD_DIAERESIS; + case GDK_dead_abovering: + return VK_DEAD_ABOVERING; + case GDK_dead_doubleacute: + return VK_DEAD_DOUBLEACUTE; + case GDK_dead_caron: + return VK_DEAD_CARON; + case GDK_dead_cedilla: + return VK_DEAD_CEDILLA; + case GDK_dead_ogonek: + return VK_DEAD_OGONEK; + case GDK_dead_iota: + return VK_DEAD_IOTA; + case GDK_dead_voiced_sound: + return VK_DEAD_VOICED_SOUND; + case GDK_dead_semivoiced_sound: + return VK_DEAD_SEMIVOICED_SOUND; + case GDK_ampersand: + return VK_AMPERSAND; + case GDK_asterisk: + return VK_ASTERISK; + case GDK_quotedbl: + return VK_QUOTEDBL; + case GDK_less: + return VK_LESS; + case GDK_greater: + return VK_GREATER; + case GDK_braceleft: + return VK_BRACELEFT; + case GDK_braceright: + return VK_BRACERIGHT; + case GDK_at: + return VK_AT; + case GDK_colon: + return VK_COLON; + case GDK_asciicircum: + return VK_CIRCUMFLEX; + case GDK_dollar: + return VK_DOLLAR; + case GDK_EuroSign: + return VK_EURO_SIGN; + case GDK_exclam: + return VK_EXCLAMATION_MARK; + case GDK_exclamdown: + return VK_INVERTED_EXCLAMATION_MARK; + case GDK_parenleft: + return VK_LEFT_PARENTHESIS; + case GDK_numbersign: + return VK_NUMBER_SIGN; + case GDK_plus: + return VK_PLUS; + case GDK_parenright: + return VK_RIGHT_PARENTHESIS; + case GDK_underscore: + return VK_UNDERSCORE; + /* + return VK_FINAL; + return VK_CONVERT; + return VK_NONCONVERT; + return VK_ACCEPT; + */ + case GDK_Mode_switch: + return VK_MODECHANGE; + /* + return VK_KANA; + */ + case GDK_Kanji: + return VK_KANJI; + /* + return VK_ALPHANUMERIC; + */ + case GDK_Katakana: + return VK_KATAKANA; + case GDK_Hiragana: + return VK_HIRAGANA; + /* + return VK_FULL_WIDTH; + return VK_HALF_WIDTH; + return VK_ROMAN_CHARACTERS; + return VK_ALL_CANDIDATES; + */ + case GDK_PreviousCandidate: + return VK_PREVIOUS_CANDIDATE; + case GDK_Codeinput: + return VK_CODE_INPUT; + /* + return VK_JAPANESE_KATAKANA; + return VK_JAPANESE_HIRAGANA; + return VK_JAPANESE_ROMAN; + */ + case GDK_Kana_Lock: + return VK_KANA_LOCK; + /* + return VK_INPUT_METHOD_ON_OFF; + return VK_CUT; + return VK_COPY; + return VK_PASTE; + return VK_UNDO; + return VK_AGAIN; + return VK_FIND; + return VK_PROPS; + return VK_STOP; + return VK_COMPOSE; + return VK_ALT_GRAPH; + */ + default: + return VK_UNDEFINED; + } +} + +static jint +keysym_to_awt_keylocation (GdkEventKey *event) +{ + guint ukeyval; + + ukeyval = get_first_keyval_from_keymap (event); + + /* VK_A through VK_Z */ + if (ukeyval >= GDK_A && ukeyval <= GDK_Z) + return AWT_KEY_LOCATION_STANDARD; + + /* VK_0 through VK_9 */ + if (ukeyval >= GDK_0 && ukeyval <= GDK_9) + return AWT_KEY_LOCATION_STANDARD; + + switch (ukeyval) + { + case GDK_Shift_L: + case GDK_Control_L: + case GDK_Alt_L: + case GDK_Meta_L: + return AWT_KEY_LOCATION_LEFT; + + case GDK_Shift_R: + case GDK_Control_R: + case GDK_Alt_R: + case GDK_Meta_R: + return AWT_KEY_LOCATION_RIGHT; + + case GDK_Return: + case GDK_BackSpace: + case GDK_Tab: + case GDK_Cancel: + case GDK_Clear: + case GDK_Pause: + case GDK_Caps_Lock: + case GDK_Escape: + case GDK_space: + case GDK_Page_Up: + case GDK_Page_Down: + case GDK_End: + case GDK_Home: + case GDK_Left: + case GDK_Up: + case GDK_Right: + case GDK_Down: + case GDK_comma: + case GDK_minus: + case GDK_period: + case GDK_slash: + case GDK_semicolon: + case GDK_equal: + case GDK_bracketleft: + case GDK_backslash: + case GDK_bracketright: + case GDK_Delete: + case GDK_Scroll_Lock: + case GDK_F1: + case GDK_F2: + case GDK_F3: + case GDK_F4: + case GDK_F5: + case GDK_F6: + case GDK_F7: + case GDK_F8: + case GDK_F9: + case GDK_F10: + case GDK_F11: + case GDK_F12: + case GDK_F13: + case GDK_F14: + case GDK_F15: + case GDK_F16: + case GDK_F17: + case GDK_F18: + case GDK_F19: + case GDK_F20: + case GDK_F21: + case GDK_F22: + case GDK_F23: + case GDK_F24: + case GDK_Print: + case GDK_Insert: + case GDK_Help: + case GDK_grave: + case GDK_apostrophe: + case GDK_dead_grave: + case GDK_dead_acute: + case GDK_dead_circumflex: + case GDK_dead_tilde: + case GDK_dead_macron: + case GDK_dead_breve: + case GDK_dead_abovedot: + case GDK_dead_diaeresis: + case GDK_dead_abovering: + case GDK_dead_doubleacute: + case GDK_dead_caron: + case GDK_dead_cedilla: + case GDK_dead_ogonek: + case GDK_dead_iota: + case GDK_dead_voiced_sound: + case GDK_dead_semivoiced_sound: + case GDK_ampersand: + case GDK_asterisk: + case GDK_quotedbl: + case GDK_less: + case GDK_greater: + case GDK_braceleft: + case GDK_braceright: + case GDK_at: + case GDK_colon: + case GDK_asciicircum: + case GDK_dollar: + case GDK_EuroSign: + case GDK_exclam: + case GDK_exclamdown: + case GDK_parenleft: + case GDK_numbersign: + case GDK_plus: + case GDK_parenright: + case GDK_underscore: + case GDK_Mode_switch: + case GDK_Kanji: + case GDK_Katakana: + case GDK_Hiragana: + case GDK_PreviousCandidate: + case GDK_Codeinput: + case GDK_Kana_Lock: + return AWT_KEY_LOCATION_STANDARD; + + case GDK_KP_Enter: + case GDK_KP_Page_Up: + case GDK_KP_Page_Down: + case GDK_KP_End: + case GDK_KP_Home: + case GDK_KP_Begin: + case GDK_KP_0: + case GDK_KP_1: + case GDK_KP_2: + case GDK_KP_3: + case GDK_KP_4: + case GDK_KP_5: + case GDK_KP_6: + case GDK_KP_7: + case GDK_KP_8: + case GDK_KP_9: + case GDK_KP_Multiply: + case GDK_KP_Add: + case GDK_KP_Separator: + case GDK_KP_Subtract: + case GDK_KP_Decimal: + case GDK_KP_Divide: + case GDK_KP_Delete: + case GDK_Num_Lock: + case GDK_KP_Insert: + case GDK_KP_Up: + case GDK_KP_Down: + case GDK_KP_Left: + case GDK_KP_Right: + return AWT_KEY_LOCATION_NUMPAD; + + default: + return AWT_KEY_LOCATION_UNKNOWN; + } +} + +static jchar +keyevent_to_awt_keychar (GdkEventKey *event) +{ + if (event->length > 0) + { + /* Translate GDK carriage return to Java linefeed. */ + if (event->string[0] == 13) + return VK_ENTER; + else + return event->string[0]; + } + else + { + switch (event->keyval) + { + case GDK_BackSpace: + return VK_BACK_SPACE; + case GDK_Tab: + return VK_TAB; + case GDK_Delete: + case GDK_KP_Delete: + return VK_DELETE; + default: + return AWT_KEY_CHAR_UNDEFINED; + } + } +} + +/* Modifier key events need special treatment. In Sun's peer + implementation, when a modifier key is pressed, the KEY_PRESSED + event has that modifier in its modifiers list. The corresponding + KEY_RELEASED event's modifier list does not contain the modifier. + For example, pressing and releasing the shift key will produce a + key press event with modifiers=Shift, and a key release event with + no modifiers. GDK's key events behave in the exact opposite way, + so this translation code is needed. */ +static jint +keyevent_state_to_awt_mods (GdkEventKey *event) +{ + jint result = 0; + guint state; + + if (event->type == GDK_KEY_PRESS) + { + state = event->state; + + if (event->keyval == GDK_Shift_L + || event->keyval == GDK_Shift_R) + result |= AWT_SHIFT_DOWN_MASK; + else + { + if (state & GDK_SHIFT_MASK) + result |= AWT_SHIFT_DOWN_MASK; + } + + if (event->keyval == GDK_Control_L + || event->keyval == GDK_Control_R) + result |= AWT_CTRL_DOWN_MASK; + else + { + if (state & GDK_CONTROL_MASK) + result |= AWT_CTRL_DOWN_MASK; + } + + if (event->keyval == GDK_Alt_L + || event->keyval == GDK_Alt_R) + result |= AWT_ALT_DOWN_MASK; + else + { + if (state & GDK_MOD1_MASK) + result |= AWT_ALT_DOWN_MASK; + } + } + else if (event->type == GDK_KEY_RELEASE) + { + state = event->state; + + if (event->keyval != GDK_Shift_L + && event->keyval != GDK_Shift_R) + { + if (state & GDK_SHIFT_MASK) + result |= AWT_SHIFT_DOWN_MASK; + } + if (event->keyval != GDK_Control_L + && event->keyval != GDK_Control_R) + { + if (state & GDK_CONTROL_MASK) + result |= AWT_CTRL_DOWN_MASK; + } + + if (event->keyval != GDK_Alt_L + && event->keyval != GDK_Alt_R) + { + if (state & GDK_MOD1_MASK) + result |= AWT_ALT_DOWN_MASK; + } + } + + return result; +} + +static gboolean window_configure_cb (GtkWidget *widget, + GdkEventConfigure *event, + jobject peer); + +/* FIXME: we're currently seeing the double-activation that occurs + with metacity and GTK. See + http://bugzilla.gnome.org/show_bug.cgi?id=140977 for details. */ + +static void window_get_frame_extents (GtkWidget *window, + int *top, int *left, + int *bottom, int *right); + +static void request_frame_extents (GtkWidget *window); + +static Bool property_notify_predicate (Display *display, + XEvent *xevent, + XPointer arg); + +static gboolean window_delete_cb (GtkWidget *widget, GdkEvent *event, + jobject peer); +static void window_destroy_cb (GtkWidget *widget, GdkEvent *event, + jobject peer); +static void window_show_cb (GtkWidget *widget, jobject peer); +static void window_active_state_change_cb (GtkWidget *widget, + GParamSpec *pspec, + jobject peer); +static void window_focus_state_change_cb (GtkWidget *widget, + GParamSpec *pspec, + jobject peer); +static gboolean window_focus_in_cb (GtkWidget * widget, + GdkEventFocus *event, + jobject peer); +static gboolean window_focus_out_cb (GtkWidget * widget, + GdkEventFocus *event, + jobject peer); +static gboolean window_window_state_cb (GtkWidget *widget, + GdkEvent *event, + jobject peer); +static jint window_get_new_state (GtkWidget *widget); +static gboolean window_property_changed_cb (GtkWidget *widget, + GdkEventProperty *event, + jobject peer); +static void realize_cb (GtkWidget *widget, jobject peer); + +static gboolean +window_configure_cb (GtkWidget *widget __attribute__((unused)), + GdkEventConfigure *event, + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postConfigureEventID, + (jint) event->x, + (jint) event->y, + (jint) event->width, + (jint) event->height); + + gdk_threads_enter (); + + return FALSE; +} + +static gboolean +key_press_cb (GtkWidget *widget __attribute__((unused)), + GdkEventKey *event, + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postKeyEventID, + (jint) AWT_KEY_PRESSED, + (jlong) event->time, + keyevent_state_to_awt_mods (event), + keysym_to_awt_keycode (event), + keyevent_to_awt_keychar (event), + keysym_to_awt_keylocation (event)); + + gdk_threads_enter (); + + /* FIXME: generation of key typed events needs to be moved + to GtkComponentPeer.postKeyEvent. If the key in a key + press event is not an "action" key + (KeyEvent.isActionKey) and is not a modifier key, then + it should generate a key typed event. */ + return TRUE; +} + + +static gboolean +key_release_cb (GtkWidget *widget __attribute__((unused)), + GdkEventKey *event, + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postKeyEventID, + (jint) AWT_KEY_RELEASED, + (jlong) event->time, + keyevent_state_to_awt_mods (event), + keysym_to_awt_keycode (event), + keyevent_to_awt_keychar (event), + keysym_to_awt_keylocation (event)); + + gdk_threads_enter (); + + return TRUE; +} + +/* Union used for type punning. */ +union extents_union +{ + guchar **gu_extents; + unsigned long **extents; +}; + +union atom_list_union +{ + guchar **gu_extents; + Atom **atom_list; +}; + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create + (JNIEnv *env, jobject obj, jint type, jboolean decorated, jobject parent) +{ + GtkWidget *window_widget; + GtkWindow *window; + void *window_parent; + GtkWidget *fixed; + + gdk_threads_enter (); + + NSA_SET_GLOBAL_REF (env, obj); + + window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); + window = GTK_WINDOW (window_widget); + + /* Keep this window in front of its parent, if it has one. */ + if (parent) + { + window_parent = NSA_GET_PTR (env, parent); + gtk_window_set_transient_for (window, GTK_WINDOW(window_parent)); + } + + gtk_window_set_decorated (window, decorated); + + gtk_window_set_type_hint (window, type); + + gtk_window_group_add_window (cp_gtk_global_window_group, window); + + fixed = gtk_fixed_new (); + + gtk_container_add (GTK_CONTAINER (window_widget), fixed); + + gtk_widget_show (fixed); + + NSA_SET_PTR (env, obj, window_widget); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetTitle + (JNIEnv *env, jobject obj, jstring title) +{ + const char *c_title; + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + c_title = (*env)->GetStringUTFChars (env, title, NULL); + + gtk_window_set_title (GTK_WINDOW (ptr), c_title); + + (*env)->ReleaseStringUTFChars (env, title, c_title); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetResizable + (JNIEnv *env, jobject obj, jboolean resizable) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_window_set_policy (GTK_WINDOW (ptr), resizable, resizable, FALSE); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetModal + (JNIEnv *env, jobject obj, jboolean modal) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_window_set_modal (GTK_WINDOW (ptr), modal); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible + (JNIEnv *env, jobject obj, jboolean visible) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + if (visible) + gtk_widget_show (GTK_WIDGET (ptr)); + else + gtk_widget_hide (GTK_WIDGET (ptr)); + + XFlush (GDK_DISPLAY ()); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr; + jobject *gref; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + gref = NSA_GET_GLOBAL_REF (env, obj); + + g_signal_connect (G_OBJECT (ptr), "delete-event", + G_CALLBACK (window_delete_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "destroy-event", + G_CALLBACK (window_destroy_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "show", + G_CALLBACK (window_show_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "notify::is-active", + G_CALLBACK (window_active_state_change_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "notify::has-toplevel-focus", + G_CALLBACK (window_focus_state_change_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "focus-in-event", + G_CALLBACK (window_focus_in_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "focus-out-event", + G_CALLBACK (window_focus_out_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "window-state-event", + G_CALLBACK (window_window_state_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "property-notify-event", + G_CALLBACK (window_property_changed_cb), *gref); + + g_signal_connect_after (G_OBJECT (ptr), "realize", + G_CALLBACK (realize_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "key-press-event", + G_CALLBACK (key_press_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "key-release-event", + G_CALLBACK (key_release_cb), *gref); + + g_signal_connect_after (G_OBJECT (ptr), "window-state-event", + G_CALLBACK (window_window_state_cb), *gref); + + g_signal_connect (G_OBJECT (ptr), "configure-event", + G_CALLBACK (window_configure_cb), *gref); + + cp_gtk_component_connect_expose_signals (ptr, gref); + cp_gtk_component_connect_mouse_signals (ptr, gref); + + /* FIXME: override focus signals here to prevent child fixed repaint? */ + + gdk_threads_leave (); +} + +/* Realize the window here so that its frame extents are known now. + That way Window.pack can operate with the accurate insets returned + by the window manager rather than the default estimates. */ +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_realize (JNIEnv *env, jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gtk_widget_realize (GTK_WIDGET (ptr)); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env, + jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gdk_window_lower (GTK_WIDGET (ptr)->window); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env, + jobject obj) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + gdk_window_raise (GTK_WIDGET (ptr)->window); + gdk_flush (); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBoundsCallback + (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jobject window, jint x, jint y, jint width, jint height) +{ + /* Circumvent package-private access to call Window's + setBoundsCallback method. */ + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), window, setBoundsCallbackID, + x, y, width, height); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize + (JNIEnv *env, jobject obj, jint width, jint height) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + /* Avoid GTK runtime assertion failures. */ + width = (width < 1) ? 1 : width; + height = (height < 1) ? 1 : height; + + gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds + (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height) +{ + void *ptr; + + gdk_threads_enter (); + + ptr = NSA_GET_PTR (env, obj); + + /* Avoid GTK runtime assertion failures. */ + width = (width < 1) ? 1 : width; + height = (height < 1) ? 1 : height; + + gtk_window_move (GTK_WINDOW(ptr), x, y); + /* The call to gdk_window_move is needed in addition to the call to + gtk_window_move. If gdk_window_move isn't called, then the + following set of operations doesn't give the expected results: + + 1. show a window + 2. manually move it to another position on the screen + 3. hide the window + 4. reposition the window with Component.setLocation + 5. show the window + + Instead of being at the position set by setLocation, the window + is reshown at the position to which it was moved manually. */ + if (GTK_WIDGET (ptr)->window != NULL) + gdk_window_move (GTK_WIDGET (ptr)->window, x, y); + + /* Need to change the widget's request size. */ + gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height); + /* Also need to call gtk_window_resize. If the resize is requested + by the program and the window's "resizable" property is true then + the size request will not be honoured. */ + gtk_window_resize (GTK_WINDOW (ptr), width, height); + + gdk_threads_leave (); +} + +static void +window_get_frame_extents (GtkWidget *window, + int *top, int *left, int *bottom, int *right) +{ + unsigned long *extents = NULL; + union extents_union gu_ex; + + /* Guess frame extents in case _NET_FRAME_EXTENTS is not + supported. */ + *top = 23; + *left = 6; + *bottom = 6; + *right = 6; + + /* Request that the window manager set window's + _NET_FRAME_EXTENTS property. */ + request_frame_extents (window); + + /* Attempt to retrieve window's frame extents. */ + gu_ex.extents = &extents; + if (gdk_property_get (window->window, + gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE), + gdk_atom_intern ("CARDINAL", FALSE), + 0, + sizeof (unsigned long) * 4, + FALSE, + NULL, + NULL, + NULL, + gu_ex.gu_extents)) + { + *left = extents [0]; + *right = extents [1]; + *top = extents [2]; + *bottom = extents [3]; + } +} + +static Atom extents_atom = 0; + +/* Requests that the window manager set window's + _NET_FRAME_EXTENTS property. */ +static void +request_frame_extents (GtkWidget *window) +{ + const char *request_str = "_NET_REQUEST_FRAME_EXTENTS"; + GdkAtom request_extents = gdk_atom_intern (request_str, FALSE); + + /* Check if the current window manager supports + _NET_REQUEST_FRAME_EXTENTS. */ + if (gdk_net_wm_supports (request_extents)) + { + GdkDisplay *display = gtk_widget_get_display (window); + Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); + + GdkWindow *root_window = gdk_get_default_root_window (); + Window xroot_window = GDK_WINDOW_XID (root_window); + + Atom extents_request_atom = + gdk_x11_get_xatom_by_name_for_display (display, request_str); + + XEvent xevent; + XEvent notify_xevent; + + unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window)); + + if (!extents_atom) + { + const char *extents_str = "_NET_FRAME_EXTENTS"; + extents_atom = + gdk_x11_get_xatom_by_name_for_display (display, extents_str); + } + + xevent.xclient.type = ClientMessage; + xevent.xclient.message_type = extents_request_atom; + xevent.xclient.display = xdisplay; + xevent.xclient.window = window_id; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = 0; + xevent.xclient.data.l[1] = 0; + xevent.xclient.data.l[2] = 0; + xevent.xclient.data.l[3] = 0; + xevent.xclient.data.l[4] = 0; + + XSendEvent (xdisplay, xroot_window, False, + (SubstructureRedirectMask | SubstructureNotifyMask), + &xevent); + + XIfEvent(xdisplay, ¬ify_xevent, + property_notify_predicate, (XPointer) &window_id); + } +} + +static Bool +property_notify_predicate (Display *xdisplay __attribute__((unused)), + XEvent *event, + XPointer window_id) +{ + unsigned long *window = (unsigned long *) window_id; + + if (event->xany.type == PropertyNotify + && event->xany.window == *window + && event->xproperty.atom == extents_atom) + return True; + else + return False; +} + +static gboolean +window_delete_cb (GtkWidget *widget __attribute__((unused)), + GdkEvent *event __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_CLOSING, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); + + /* Prevents that the Window dissappears ("destroy" + not being signalled). This is necessary because it + should be up to a WindowListener implementation + how the AWT Frame responds to close requests. */ + return TRUE; +} + +static void +window_destroy_cb (GtkWidget *widget __attribute__((unused)), + GdkEvent *event __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_CLOSED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); +} + +static void +window_show_cb (GtkWidget *widget __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_OPENED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); +} + +static void +window_active_state_change_cb (GtkWidget *widget __attribute__((unused)), + GParamSpec *pspec __attribute__((unused)), + jobject peer __attribute__((unused))) +{ + /* FIXME: not sure if this is needed or not. */ + /* Remove the unused attributes if you fix the below. */ +#if 0 + gdk_threads_leave (); + + if (GTK_WINDOW (widget)->is_active) + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_GAINED_FOCUS, + (jobject) NULL, (jint) 0); + else + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_DEACTIVATED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); +#endif +} + +static void +window_focus_state_change_cb (GtkWidget *widget, + GParamSpec *pspec __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + if (GTK_WINDOW (widget)->has_toplevel_focus) + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_ACTIVATED, + (jobject) NULL, (jint) 0); + else + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_DEACTIVATED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); +} + +static gboolean +window_focus_in_cb (GtkWidget * widget __attribute__((unused)), + GdkEventFocus *event __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_GAINED_FOCUS, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); + + return FALSE; +} + +static gboolean +window_focus_out_cb (GtkWidget * widget __attribute__((unused)), + GdkEventFocus *event __attribute__((unused)), + jobject peer) +{ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_LOST_FOCUS, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); + + return FALSE; +} + +static gboolean +window_window_state_cb (GtkWidget *widget, + GdkEvent *event, + jobject peer) +{ + jint new_state; + + /* Handle WINDOW_ICONIFIED and WINDOW_DEICONIFIED events. */ + if (event->window_state.changed_mask & GDK_WINDOW_STATE_ICONIFIED) + { + /* We've either been iconified or deiconified. */ + if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED) + { + /* We've been iconified. */ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_ICONIFIED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); + } + else + { + /* We've been deiconified. */ + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_DEICONIFIED, + (jobject) NULL, (jint) 0); + + gdk_threads_enter (); + } + } + + /* Post a WINDOW_STATE_CHANGED event, passing the new frame state to + GtkWindowPeer. */ + new_state = AWT_FRAME_STATE_NORMAL; + + if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED) + new_state |= AWT_FRAME_STATE_ICONIFIED; + + new_state |= window_get_new_state (widget); + + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postWindowEventID, + (jint) AWT_WINDOW_STATE_CHANGED, + (jobject) NULL, new_state); + + gdk_threads_enter (); + + return TRUE; +} + +static jint +window_get_new_state (GtkWidget *widget) +{ + GdkDisplay *display = gtk_widget_get_display(widget); + jint new_state = AWT_FRAME_STATE_NORMAL; + Atom type; + gint format; + gulong atom_count; + gulong bytes_after; + Atom *atom_list = NULL; + union atom_list_union alu; + gulong i; + + alu.atom_list = &atom_list; + XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (widget->window), + gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"), + 0, G_MAXLONG, False, XA_ATOM, &type, &format, &atom_count, + &bytes_after, alu.gu_extents); + + if (type != None) + { + Atom maxvert = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT"); + Atom maxhorz = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ"); + + i = 0; + while (i < atom_count) + { + if (atom_list[i] == maxhorz) + new_state |= AWT_FRAME_STATE_MAXIMIZED_HORIZ; + else if (atom_list[i] == maxvert) + new_state |= AWT_FRAME_STATE_MAXIMIZED_VERT; + + ++i; + } + + XFree (atom_list); + } + return new_state; +} + +static gboolean +window_property_changed_cb (GtkWidget *widget __attribute__((unused)), + GdkEventProperty *event, + jobject peer) +{ + unsigned long *extents; + union extents_union gu_ex; + + gu_ex.extents = &extents; + if (gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE) == event->atom + && gdk_property_get (event->window, + gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE), + gdk_atom_intern ("CARDINAL", FALSE), + 0, + sizeof (unsigned long) * 4, + FALSE, + NULL, + NULL, + NULL, + gu_ex.gu_extents)) + { + gdk_threads_leave (); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postInsetsChangedEventID, + (jint) extents[2], /* top */ + (jint) extents[0], /* left */ + (jint) extents[3], /* bottom */ + (jint) extents[1]); /* right */ + + gdk_threads_enter (); + } + + + return FALSE; +} + +static void +realize_cb (GtkWidget *widget, jobject peer) +{ + jint top = 0; + jint left = 0; + jint bottom = 0; + jint right = 0; + jint width = 0; + jint height = 0; + + width = (*cp_gtk_gdk_env())->CallIntMethod (cp_gtk_gdk_env(), peer, windowGetWidthID); + height = (*cp_gtk_gdk_env())->CallIntMethod (cp_gtk_gdk_env(), peer, windowGetHeightID); + + window_get_frame_extents (widget, &top, &left, &bottom, &right); + + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postInsetsChangedEventID, + top, left, bottom, right); + + gtk_window_set_default_size (GTK_WINDOW (widget), + MAX (1, width - left - right), + MAX (1, height - top - bottom)); + + /* set the size like we do in nativeSetBounds */ + gtk_widget_set_size_request (widget, + MAX (1, width - left - right), + MAX (1, height - top - bottom)); + + gtk_window_resize (GTK_WINDOW (widget), + MAX (1, width - left - right), + MAX (1, height - top - bottom)); +} + +/* + * This method returns a GDK keyval that corresponds to one of the + * keysyms in the X keymap table. The return value is only used to + * determine the keyval's corresponding hardware keycode, and doesn't + * reflect an accurate translation of a Java virtual key value to a + * GDK keyval. + */ +#ifdef __GNUC__ +__inline +#endif +guint +cp_gtk_awt_keycode_to_keysym (jint keyCode, jint keyLocation) +{ + /* GDK_A through GDK_Z */ + if (keyCode >= VK_A && keyCode <= VK_Z) + return gdk_keyval_to_lower (keyCode); + + /* GDK_0 through GDK_9 */ + if (keyCode >= VK_0 && keyCode <= VK_9) + return keyCode; + + switch (keyCode) + { + case VK_ENTER: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Enter : GDK_Return; + case VK_BACK_SPACE: + return GDK_BackSpace; + case VK_TAB: + return GDK_Tab; + case VK_CANCEL: + return GDK_Cancel; + case VK_CLEAR: + return GDK_Clear; + case VK_SHIFT: + return keyLocation == AWT_KEY_LOCATION_LEFT ? GDK_Shift_L : GDK_Shift_R; + case VK_CONTROL: + return keyLocation == AWT_KEY_LOCATION_LEFT ? GDK_Control_L : GDK_Control_R; + case VK_ALT: + return keyLocation == AWT_KEY_LOCATION_LEFT ? GDK_Alt_L : GDK_Alt_R; + case VK_PAUSE: + return GDK_Pause; + case VK_CAPS_LOCK: + return GDK_Caps_Lock; + case VK_ESCAPE: + return GDK_Escape; + case VK_SPACE: + return GDK_space; + case VK_PAGE_UP: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Page_Up : GDK_Page_Up; + case VK_PAGE_DOWN: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Page_Down : GDK_Page_Down; + case VK_END: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_End : GDK_End; + case VK_HOME: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Home : GDK_Home; + case VK_LEFT: + return GDK_Left; + case VK_UP: + return GDK_Up; + case VK_RIGHT: + return GDK_Right; + case VK_DOWN: + return GDK_Down; + case VK_COMMA: + return GDK_comma; + case VK_MINUS: + return GDK_minus; + case VK_PERIOD: + return GDK_period; + case VK_SLASH: + return GDK_slash; + /* + case VK_0: + case VK_1: + case VK_2: + case VK_3: + case VK_4: + case VK_5: + case VK_6: + case VK_7: + case VK_8: + case VK_9: + */ + case VK_SEMICOLON: + return GDK_semicolon; + case VK_EQUALS: + return GDK_equal; + /* + case VK_A: + case VK_B: + case VK_C: + case VK_D: + case VK_E: + case VK_F: + case VK_G: + case VK_H: + case VK_I: + case VK_J: + case VK_K: + case VK_L: + case VK_M: + case VK_N: + case VK_O: + case VK_P: + case VK_Q: + case VK_R: + case VK_S: + case VK_T: + case VK_U: + case VK_V: + case VK_W: + case VK_X: + case VK_Y: + case VK_Z: + */ + case VK_OPEN_BRACKET: + return GDK_bracketleft; + case VK_BACK_SLASH: + return GDK_backslash; + case VK_CLOSE_BRACKET: + return GDK_bracketright; + case VK_NUMPAD0: + return GDK_KP_0; + case VK_NUMPAD1: + return GDK_KP_1; + case VK_NUMPAD2: + return GDK_KP_2; + case VK_NUMPAD3: + return GDK_KP_3; + case VK_NUMPAD4: + return GDK_KP_4; + case VK_NUMPAD5: + return GDK_KP_5; + case VK_NUMPAD6: + return GDK_KP_6; + case VK_NUMPAD7: + return GDK_KP_7; + case VK_NUMPAD8: + return GDK_KP_8; + case VK_NUMPAD9: + return GDK_KP_9; + case VK_MULTIPLY: + return GDK_KP_Multiply; + case VK_ADD: + return GDK_KP_Add; + /* + case VK_SEPARATER: + */ + case VK_SEPARATOR: + return GDK_KP_Separator; + case VK_SUBTRACT: + return GDK_KP_Subtract; + case VK_DECIMAL: + return GDK_KP_Decimal; + case VK_DIVIDE: + return GDK_KP_Divide; + case VK_DELETE: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Delete : GDK_Delete; + case VK_NUM_LOCK: + return GDK_Num_Lock; + case VK_SCROLL_LOCK: + return GDK_Scroll_Lock; + case VK_F1: + return GDK_F1; + case VK_F2: + return GDK_F2; + case VK_F3: + return GDK_F3; + case VK_F4: + return GDK_F4; + case VK_F5: + return GDK_F5; + case VK_F6: + return GDK_F6; + case VK_F7: + return GDK_F7; + case VK_F8: + return GDK_F8; + case VK_F9: + return GDK_F9; + case VK_F10: + return GDK_F10; + case VK_F11: + return GDK_F11; + case VK_F12: + return GDK_F12; + case VK_F13: + return GDK_F13; + case VK_F14: + return GDK_F14; + case VK_F15: + return GDK_F15; + case VK_F16: + return GDK_F16; + case VK_F17: + return GDK_F17; + case VK_F18: + return GDK_F18; + case VK_F19: + return GDK_F19; + case VK_F20: + return GDK_F20; + case VK_F21: + return GDK_F21; + case VK_F22: + return GDK_F22; + case VK_F23: + return GDK_F23; + case VK_F24: + return GDK_F24; + case VK_PRINTSCREEN: + return GDK_Print; + case VK_INSERT: + return keyLocation == AWT_KEY_LOCATION_NUMPAD ? GDK_KP_Insert : GDK_Insert; + case VK_HELP: + return GDK_Help; + case VK_META: + return keyLocation == AWT_KEY_LOCATION_LEFT ? GDK_Meta_L : GDK_Meta_R; + case VK_BACK_QUOTE: + return GDK_grave; + case VK_QUOTE: + return GDK_apostrophe; + case VK_KP_UP: + return GDK_KP_Up; + case VK_KP_DOWN: + return GDK_KP_Down; + case VK_KP_LEFT: + return GDK_KP_Left; + case VK_KP_RIGHT: + return GDK_KP_Right; + case VK_DEAD_GRAVE: + return GDK_dead_grave; + case VK_DEAD_ACUTE: + return GDK_dead_acute; + case VK_DEAD_CIRCUMFLEX: + return GDK_dead_circumflex; + case VK_DEAD_TILDE: + return GDK_dead_tilde; + case VK_DEAD_MACRON: + return GDK_dead_macron; + case VK_DEAD_BREVE: + return GDK_dead_breve; + case VK_DEAD_ABOVEDOT: + return GDK_dead_abovedot; + case VK_DEAD_DIAERESIS: + return GDK_dead_diaeresis; + case VK_DEAD_ABOVERING: + return GDK_dead_abovering; + case VK_DEAD_DOUBLEACUTE: + return GDK_dead_doubleacute; + case VK_DEAD_CARON: + return GDK_dead_caron; + case VK_DEAD_CEDILLA: + return GDK_dead_cedilla; + case VK_DEAD_OGONEK: + return GDK_dead_ogonek; + case VK_DEAD_IOTA: + return GDK_dead_iota; + case VK_DEAD_VOICED_SOUND: + return GDK_dead_voiced_sound; + case VK_DEAD_SEMIVOICED_SOUND: + return GDK_dead_semivoiced_sound; + case VK_AMPERSAND: + return GDK_ampersand; + case VK_ASTERISK: + return GDK_asterisk; + case VK_QUOTEDBL: + return GDK_quotedbl; + case VK_LESS: + return GDK_less; + case VK_GREATER: + return GDK_greater; + case VK_BRACELEFT: + return GDK_braceleft; + case VK_BRACERIGHT: + return GDK_braceright; + case VK_AT: + return GDK_at; + case VK_COLON: + return GDK_colon; + case VK_CIRCUMFLEX: + return GDK_asciicircum; + case VK_DOLLAR: + return GDK_dollar; + case VK_EURO_SIGN: + return GDK_EuroSign; + case VK_EXCLAMATION_MARK: + return GDK_exclam; + case VK_INVERTED_EXCLAMATION_MARK: + return GDK_exclamdown; + case VK_LEFT_PARENTHESIS: + return GDK_parenleft; + case VK_NUMBER_SIGN: + return GDK_numbersign; + case VK_PLUS: + return GDK_plus; + case VK_RIGHT_PARENTHESIS: + return GDK_parenright; + case VK_UNDERSCORE: + return GDK_underscore; + /* + case VK_FINAL: + case VK_CONVERT: + case VK_NONCONVERT: + case VK_ACCEPT: + */ + case VK_MODECHANGE: + return GDK_Mode_switch; + /* + case VK_KANA: + */ + case VK_KANJI: + return GDK_Kanji; + /* + case VK_ALPHANUMERIC: + */ + case VK_KATAKANA: + return GDK_Katakana; + case VK_HIRAGANA: + return GDK_Hiragana; + /* + case VK_FULL_WIDTH: + case VK_HALF_WIDTH: + case VK_ROMAN_CHARACTERS: + case VK_ALL_CANDIDATES: + */ + case VK_PREVIOUS_CANDIDATE: + return GDK_PreviousCandidate; + case VK_CODE_INPUT: + return GDK_Codeinput; + /* + case VK_JAPANESE_KATAKANA: + case VK_JAPANESE_HIRAGANA: + case VK_JAPANESE_ROMAN: + */ + case VK_KANA_LOCK: + return GDK_Kana_Lock; + /* + case VK_INPUT_METHOD_ON_OFF: + case VK_CUT: + case VK_COPY: + case VK_PASTE: + case VK_UNDO: + case VK_AGAIN: + case VK_FIND: + case VK_PROPS: + case VK_STOP: + case VK_COMPOSE: + case VK_ALT_GRAPH: + */ + default: + return GDK_VoidSymbol; + } +} diff --git a/libjava/classpath/native/jni/gtk-peer/gthread-jni.c b/libjava/classpath/native/jni/gtk-peer/gthread-jni.c new file mode 100644 index 00000000000..e673de07d27 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gthread-jni.c @@ -0,0 +1,2592 @@ +/* gthread-jni.c -- JNI threading routines for GLIB + Copyright (C) 1998, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/************************************************************************/ +/* Header */ +/************************************************************************/ + +/* + * @author Julian Dolby (dolby@us.ibm.com) + * @date February 7, 2003 implemented for GLIB v.1 + * + * + * @author Steven Augart + * <steve+classpath at augart dot com>, <augart at watson dot ibm dot com> + * @date April 30, 2004 -- May 10 2004: Support new functions for Glib v.2, + * fix cond_wait to free and re-acquire the mutex, + * replaced trylock stub implementation with a full one. + * + * This code implements the GThreadFunctions interface for GLIB using + * Java threading primitives. All of the locking and conditional variable + * functionality required by GThreadFunctions is implemented using the + * monitor and wait/notify functionality of Java objects. The thread- + * local functionality uses the java.lang.ThreadLocal class. + * + * Classpath's AWT support uses GTK+ peers. GTK+ uses GLIB. GLIB by default + * uses the platform's native threading model -- pthreads in most cases. If + * the Java runtime doesn't use the native threading model, then it needs this + * code in order to use Classpath's (GTK+-based) AWT routines. + * + * This code should be portable; I believe it makes no assumptions + * about the underlying VM beyond that it implements the JNI functionality + * that this code uses. + * + * Currently, use of this code is governed by the configuration option + * --enable-portable-native-sync. We will soon add a VM hook so the VM can + * select which threading model it wants to use at run time; at that point, + * the configuration option will go away. + * + * The code in this file uses only JNI 1.1, except for one JNI 1.2 function: + * GetEnv, in the JNI Invocation API. (There seems to be no way around using + * GetEnv). + * + * ACKNOWLEDGEMENT: + * + * I would like to thank Mark Wielaard for his kindness in spending at least + * six hours of his own time in reviewing this code and correcting my GNU + * coding and commenting style. --Steve Augart + * + * + * NOTES: + * + * This code has been tested with Jikes RVM and with Kaffe. + * + * This code should have proper automated unit tests. I manually tested it + * by running an application that uses AWT. --Steven Augart + * + * MINOR NIT: + * + * - Using a jboolean in the arglist to "throw()" and "rethrow()" + * triggers many warnings from GCC's -Wconversion operation, because that + * is not the same as the conversion (upcast to an int) that would occur in + * the absence of a prototype. + * + * It would be very slightly more efficient to just pass the jboolean, but + * is not worth the clutter of messages. The right solution would be to + * turn off the -Wconversion warning for just this file, *except* that + * -Wconversion also warns you against constructs such as: + * unsigned u = -1; + * and that is a useful warning. So I went from a "jboolean" to a + * "gboolean" (-Wconversion is not enabled by default for GNU Classpath, + * but it is in my own CFLAGS, which, for gcc 3.3.3, read: -pipe -ggdb3 -W + * -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual + * -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations + * -fkeep-static-consts -fkeep-inline-functions -Wundef -Wwrite-strings + * -Wno-aggregate-return -Wmissing-noreturn -Wnested-externs -Wtrigraphs + * -Wconversion -Wsign-compare -Wno-float-equal -Wmissing-format-attribute + * -Wno-unreachable-code -Wdisabled-optimization ) + */ + +#include <config.h> + +/************************************************************************/ +/* Configuration */ +/************************************************************************/ + +/** Tracing and Reporting **/ +#define TRACE_API_CALLS 0 /* announce entry and exit into each method, + by printing to stderr. */ + +#define TRACE_MONITORS 0 /* Every enterMonitor() and exitMonitor() goes + to stderr. */ + +/** Trouble handling. There is a discussion below of this. **/ +#define EXPLAIN_TROUBLE 1 /* Describe any unexpected trouble that + happens. This is a superset + of EXPLAIN_BROKEN, and if set trumps an + unset EXPLAIN_BROKEN. It is not a strict + superset, since at the moment there is no + TROUBLE that is not also BROKEN. + + Use criticalMsg() to describe the problem. + */ + +#define EXPLAIN_BROKEN 1 /* Describe trouble that is serious enough to + be BROKEN. (Right now all trouble is at + least BROKEN.) */ + +/* There is no EXPLAIN_BADLY_BROKEN definition. We always explain + BADLY_BROKEN trouble, since there is no other way to report it. */ + + +/** Error Handling **/ +#define DIE_IF_BROKEN 1 /* Dies if serious trouble happens. There is + really no non-serious trouble, except + possibly problems that arise during + pthread_create, which are reported by a + GError. + + If you do not set DIE_IF_BROKEN, then + trouble will raise a Java RuntimeException. + We probably do want to die right away, + since anything that's BROKEN really + indicates a programming error or a + system-wide error, and that's what the glib + documentation says you should do in case of + that kind of error in a glib-style + function. But it does work to turn this + off. */ + +#if DIE_IF_BROKEN +#define DIE_IF_BADLY_BROKEN 1 /* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */ +#else +#define DIE_IF_BADLY_BROKEN 1 /* Die if the system is badly broken -- + that is, if we have further trouble while + attempting to throw an exception + upwards, or if we are unable to generate + one of the classes we'll need in order to + throw wrapped exceptions upward. + + If unset, we will print a warning message, + and limp along anyway. Not that the system + is likely to work. */ +#endif + +/** Performance tuning parameters **/ + +#define ENABLE_EXPENSIVE_ASSERTIONS 0 /* Enable expensive assertions? */ + +#define DELETE_LOCAL_REFS 1 /* Whether to delete local references. + + JNI only guarantees that there wil be 16 + available. (Jikes RVM provides an number + only limited by VM memory.) + + Jikes RVM will probably perform faster if + this is turned off, but other VMs may need + this to be turned on in order to perform at + all, or might need it if things change. + + Remember, we don't know how many of those + local refs might have already been used up + by higher layers of JNI code that end up + calling g_thread_self(), + g_thread_set_private(), and so on. + + We set this to 1 for GNU Classpath, since + one of our principles is "always go for the + most robust implementation" */ + +#define HAVE_JNI_VERSION_1_2 0 /* Assume we don't. We could + dynamically check for this. We will + assume JNI 1.2 in later versions of + Classpath. + + As it stands, the code in this file + already needs one JNI 1.2 function: + GetEnv, in the JNI Invocation API. + + TODO This code hasn't been tested yet. + And really hasn't been implemented yet. + */ + +/************************************************************************/ +/* Global data */ +/************************************************************************/ + +#if defined HAVE_STDINT_H +#include <stdint.h> /* provides intptr_t */ +#elif defined HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#include <stdarg.h> /* va_list */ +#include <glib.h> +#include "gthread-jni.h" +#include <assert.h> /* assert() */ + +/* For Java thread priority constants. */ +#include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h> + +/* Since not all JNI header generators actually define constants we + define them here explicitly. */ +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY 1 +#endif +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY 5 +#endif +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY 10 +#endif + +/* The VM handle. This is set in + Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */ +JavaVM *cp_gtk_the_vm; + +/* Unions used for type punning. */ +union env_union +{ + void **void_env; + JNIEnv **jni_env; +}; + +union func_union +{ + void *void_func; + GThreadFunc g_func; +}; + +/* Forward Declarations for Functions */ +static int threadObj_set_priority (JNIEnv * env, jobject threadObj, + GThreadPriority gpriority); +static void fatalMsg (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))) + __attribute__ ((noreturn)); + +static void criticalMsg (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))); + +static void tracing (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))); + +static jint javaPriorityLevel (GThreadPriority priority) + __attribute__ ((const)); + +/************************************************************************/ +/* Trouble-handling, including utilities to reflect exceptions */ +/* back to the VM. Also some status reporting. */ +/************************************************************************/ + +/* How are we going to handle problems? + + There are several approaches: + + 1) Report them with the GError mechanism. + + (*thread_create)() is the only one of these functions that takes a + GError pointer. And the only G_THREAD error defined maps onto EAGAIN. + We don't have any errors in our (*thread_create)() implementation that + can be mapped to EAGAIN. So this idea is a non-starter. + + 2) Reflect the exception back to the VM, wrapped in a RuntimeException. + This will fail sometimes, if we're so broken (BADLY_BROKEN) that we + fail to throw the exception. + + 3) Abort execution. This is what the glib functions themselves do for + errors that they can't report via GError. + + Enable DIE_IF_BROKEN and/or DIE_IF_BADLY_BROKEN to + make this the default for BROKEN and/or BADLY_BROKEN trouble. + + 4) Display messages to stderr. We always do this for BADLY_BROKEN + trouble. The glib functions do that for errors they can't report via + GError. + + There are some complications. + + When I attempted to report a problem in g_thread_self() using g_critical (a + macro around g_log(), I found that g_log in turn looks for thread-private + data and calls g_thread_self() again. + + We got a segfault, probably due to stack overflow. So, this code doesn't + use the g_critical() and g_error() functions any more. Nor do we use + g_assert(); we use the C library's assert() instead. +*/ + + +#define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": " + +/* This is portable to older compilers that lack variable-argument macros. + This used to be just g_critical(), but then we ran into the error reporting + problem discussed above. +*/ +static void +fatalMsg (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputs ("\nAborting execution\n", stderr); + abort (); +} + + +static void +criticalMsg (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + putc ('\n', stderr); +} + +/* Unlike the other two, this one does not append a newline. This is only + used if one of the TRACE_ macros is defined. */ +static void +tracing (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +} + +#define assert_not_reached() \ + do \ + { \ + fputs(WHERE "You should never get here. Aborting execution.\n", \ + stderr); \ + abort(); \ + } \ + while(0) + + +#if DIE_IF_BADLY_BROKEN +#define BADLY_BROKEN fatalMsg +#else +#define BADLY_BROKEN criticalMsg +/* So, the user may still attempt to recover, even though we do not advise + this. */ +#endif + +/* I find it so depressing to have to use C without varargs macros. */ +#define BADLY_BROKEN_MSG WHERE "Something fundamental" \ + " to GNU Classpath's AWT JNI broke while we were trying to pass up a Java error message" + +#define BADLY_BROKEN0() \ + BADLY_BROKEN(BADLY_BROKEN_MSG); +#define BADLY_BROKEN1(msg) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg) +#define BADLY_BROKEN2(msg, arg) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg) +#define BADLY_BROKEN3(msg, arg, arg2) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2) +#define BADLY_BROKEN4(msg, arg, arg2, arg3) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2, arg3) + +#define DELETE_LOCAL_REF(env, ref) \ + do \ + { \ + if ( DELETE_LOCAL_REFS ) \ + { \ + (*env)->DeleteLocalRef (env, ref); \ + (ref) = NULL; \ + } \ + } \ + while(0) + +/* Cached info for Exception-wrapping */ + +static jclass runtimeException_class; /* java.lang.RuntimeException */ +static jmethodID runtimeException_ctor; /* constructor for it */ + + +/* Throw a new RuntimeException. It may wrap around an existing exception. + 1 if we did rethrow, -1 if we had trouble while rethrowing. + isBroken is always true in this case. */ +static int +throw (JNIEnv * env, jthrowable cause, const char *message, + gboolean isBroken, const char *file, int line) +{ + jstring jmessage; + gboolean describedException = FALSE; /* Did we already describe the + exception to stderr or the + equivalent? */ + jthrowable wrapper; + + /* allocate local message in Java */ + const char fmt[] = "In AWT JNI, %s (at %s:%d)"; + size_t len = strlen (message) + strlen (file) + sizeof fmt + 25; + char *buf; + + if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN)) + { + criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line, + isBroken ? " (BROKEN)" : "", message); + if (cause) + { + jthrowable currentException = (*env)->ExceptionOccurred (env); + + if (cause == currentException) + { + criticalMsg ("Description follows to System.err:"); + (*env)->ExceptionDescribe (env); + /* ExceptionDescribe has the side-effect of clearing the pending + exception; relaunch it. */ + describedException = TRUE; + + if ((*env)->Throw (env, cause)) + { + BADLY_BROKEN1 + ("Relaunching an exception with Throw failed."); + return -1; + } + } + else + { + DELETE_LOCAL_REF (env, currentException); + criticalMsg (WHERE + "currentException != cause; something else happened" + " while handling an exception."); + } + } + } /* if (EXPLAIN_TROUBLE) */ + + if (isBroken && DIE_IF_BROKEN) + fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message); + + if ((buf = malloc (len))) + { + memset (buf, 0, len); + g_snprintf (buf, len, fmt, message, file, line); + jmessage = (*env)->NewStringUTF (env, buf); + free (buf); + } + else + { + jmessage = NULL; + } + + /* Create the RuntimeException wrapper object and throw it. It is OK for + CAUSE to be NULL. */ + wrapper = (jthrowable) (*env)->NewObject + (env, runtimeException_class, runtimeException_ctor, jmessage, cause); + DELETE_LOCAL_REF (env, jmessage); + + if (!wrapper) + { + /* I think this should only happen: + - if there are bugs in my JNI code, or + - if the VM is broken, or + - if we run out of memory. + */ + if (EXPLAIN_TROUBLE) + { + criticalMsg (WHERE "GNU Classpath: JNI NewObject() could not create" + " a new java.lang.RuntimeException."); + criticalMsg ("We were trying to warn about the following" + " previous failure:"); + criticalMsg ("%s:%d: %s", file, line, message); + criticalMsg ("The latest (NewObject()) exception's description" + " follows, to System.err:"); + (*env)->ExceptionDescribe (env); + } + BADLY_BROKEN1 ("Failure of JNI NewObject()" + " to make a java.lang.RuntimeException"); + return -1; + } + + + /* throw it */ + if ((*env)->Throw (env, wrapper)) + { + /* Throw() should just never fail, unless we're in such severe trouble + that we might as well die. */ + BADLY_BROKEN1 + ("GNU Classpath: Failure of JNI Throw to report an Exception"); + return -1; + } + + DELETE_LOCAL_REF (env, wrapper); + return 1; +} + + + +/* Rethrow an exception we received, wrapping it with a RuntimeException. 1 + if we did rethrow, -1 if we had trouble while rethrowing. + CAUSE should be identical to the most recent exception that happened, so + that ExceptionDescribe will work. (Otherwise nix.) */ +static int +rethrow (JNIEnv * env, jthrowable cause, const char *message, + gboolean isBroken, const char *file, int line) +{ + assert (cause); + return throw (env, cause, message, isBroken, file, line); +} + + +/* This function checks for a pending exception, and rethrows it with + * a wrapper RuntimeException to deal with possible type problems (in + * case some calling piece of code does not expect the exception being + * thrown) and to include the given extra message. + * + * Returns 0 if no problems found (so no exception thrown), 1 if we rethrew an + * exception. Returns -1 on failure. + */ +static int +maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken, + const char *file, int line) +{ + jthrowable cause = (*env)->ExceptionOccurred (env); + int ret = 0; + + /* rethrow if an exception happened */ + if (cause) + { + ret = rethrow (env, cause, message, isBroken, file, line); + DELETE_LOCAL_REF (env, cause); + } + + return 0; +} + +/* MAYBE_TROUBLE() is used to include a source location in the exception + message. Once we have run maybe_rethrow, if there WAS trouble, + return TRUE, else FALSE. + + MAYBE_TROUBLE() is actually never used; all problems that throw exceptions + are BROKEN, at least. Nothing is recoverable :(. See the discussion of + possible errors at thread_create_jni_impl(). */ +#define MAYBE_TROUBLE(_env, _message) \ + maybe_rethrow(_env, _message, FALSE, __FILE__, __LINE__) + +/* MAYBE_TROUBLE(), but something would be BROKEN if it were true. */ +#define MAYBE_BROKEN(_env, _message) \ + maybe_rethrow(_env, _message, TRUE, __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), TROUBLE() is never used. */ +#define TROUBLE(_env, _message) \ + rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \ + __FILE__, __LINE__) + +#define BROKEN(_env, _message) \ + rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \ + __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */ +#define NEW_TROUBLE(_env, _message) \ + throw (_env, NULL, _message, FALSE, __FILE__, __LINE__) + +#define NEW_BROKEN(_env, _message) \ + throw (_env, NULL, _message, TRUE, __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */ +#define RETHROW_CAUSE(_env, _cause, _message) \ + rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__) + +#define BROKEN_CAUSE(_env, _cause, _message) \ + rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__) + +/* Macros to handle the possibility that someone might have called one of the + GThreadFunctions API functions with a Java exception pending. It is + generally discouraged to continue to use JNI after a Java exception has + been raised. Sun's JNI book advises that one trap JNI errors immediately + and not continue with an exception pending. + + These are #if'd out for these reasons: + + 1) They do not work in the C '89 subset that Classpath is currently + (2004 May 10) sticking to; HIDE_OLD_TROUBLE() includes a declaration + that should be in scope for the rest of the function, so it needs a + language version that lets you mix declarations and statements. (This + could be worked around if it were important.) + + 2) They chew up more time and resources. + + 3) There does not ever seem to be old trouble -- the assertion in + HIDE_OLD_TROUBLE never goes off. + + You will want to re-enable them if this code needs to be used in a context + where old exceptions might be pending when the GThread functions are + called. + + The implementations in this file are responsible for skipping around calls + to SHOW_OLD_TROUBLE() if they've raised exceptions during the call. So, if + we reach SHOW_OLD_TROUBLE, we are guaranteed that there are no exceptions + pending. */ +#if 1 +#define HIDE_OLD_TROUBLE(env) \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) + +#define SHOW_OLD_TROUBLE() \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) +#else /* 0 */ +#define HIDE_OLD_TROUBLE(env) \ + jthrowable savedTrouble = (*env)->ExceptionOccurred (env); \ + (*env)->ExceptionClear (env); + +#define SHOW_OLD_TROUBLE() do \ +{ \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) \ + if (savedTrouble) \ + { \ + if ((*env)->Throw (env, savedTrouble)) \ + BADLY_BROKEN ("ReThrowing the savedTrouble failed"); \ + } \ + DELETE_LOCAL_REF (env, savedTrouble); \ +} while(0) + +#endif /* 0 */ + +/* Set up the cache of jclass and jmethodID primitives we need + in order to throw new exceptions and rethrow exceptions. We do this + independently of the other caching. We need to have this cache set up + first, so that we can then report errors properly. + + If any errors while setting up the error cache, the world is BADLY_BROKEN. + + May be called more than once. + + Returns -1 if the cache was not initialized properly, 1 if it was. +*/ +static int +setup_exception_cache (JNIEnv * env) +{ + static int exception_cache_initialized = 0; /* -1 for trouble, 1 for proper + init. */ + + jclass lcl_class; /* a class used for local refs */ + + if (exception_cache_initialized) + return exception_cache_initialized; + lcl_class = (*env)->FindClass (env, "java/lang/RuntimeException"); + if ( ! lcl_class ) + { + BADLY_BROKEN1 ("Broken Class library or VM?" + " Couldn't find java/lang/RuntimeException"); + return exception_cache_initialized = -1; + } + /* Pin it down. */ + runtimeException_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!runtimeException_class) + { + BADLY_BROKEN1 ("Serious trouble: could not turn" + " java.lang.RuntimeException into a global reference"); + return exception_cache_initialized = -1; + } + + runtimeException_ctor = + (*env)->GetMethodID (env, runtimeException_class, "<init>", + "(Ljava/lang/String;Ljava/lang/Throwable;)V"); + if ( ! runtimeException_ctor ) + { + BADLY_BROKEN1 ("Serious trouble: classpath couldn't find a" + " two-arg constructor for java/lang/RuntimeException"); + return exception_cache_initialized = -1; + } + + return exception_cache_initialized = 1; +} + + +/**********************************************************/ +/***** The main cache *************************************/ +/**********************************************************/ + +/** This is a cache of all classes, methods, and field IDs that we use during + the run. We maintain a permanent global reference to each of the classes + we cache, since otherwise the (local) jclass that refers to that class + would go out of scope and possibly be reused in further calls. + + The permanent global reference also achieves the secondary goal of + protecting the validity of the methods and field IDs in case the classes + were otherwise unloaded and then later loaded again. Obviously, this will + never happen to classes such as java.lang.Thread and java.lang.Object, but + the primary reason for maintaining permanent global refs is sitll valid. + + The code in jnilink.c has a similar objective. TODO: Consider using that + code instead. + + --Steven Augart +*/ + +/* All of these are cached classes and method IDs: */ +/* java.lang.Object */ +static jclass obj_class; /* java.lang.Object */ +static jmethodID obj_ctor; /* no-arg Constructor for java.lang.Object */ +static jmethodID obj_notify_mth; /* java.lang.Object.notify() */ +static jmethodID obj_notifyall_mth; /* java.lang.Object.notifyall() */ +static jmethodID obj_wait_mth; /* java.lang.Object.wait() */ +static jmethodID obj_wait_nanotime_mth; /* java.lang.Object.wait(JI) */ + +/* GThreadMutex and its methods */ +static jclass mutex_class; +static jmethodID mutex_ctor; +static jfieldID mutex_lockForPotentialLockers_fld; +static jfieldID mutex_potentialLockers_fld; + +/* java.lang.Thread and its methods*/ +static jclass thread_class; /* java.lang.Thread */ +static jmethodID thread_current_mth; /* Thread.currentThread() */ +static jmethodID thread_equals_mth; /* Thread.equals() */ +static jmethodID thread_join_mth; /* Thread.join() */ +static jmethodID thread_setPriority_mth; /* Thread.setPriority() */ +static jmethodID thread_stop_mth; /* Thread.stop() */ +static jmethodID thread_yield_mth; /* Thread.yield() */ + +/* java.lang.ThreadLocal and its methods */ +static jclass threadlocal_class; /* java.lang.ThreadLocal */ +static jmethodID threadlocal_ctor; /* Its constructor */ +static jmethodID threadlocal_set_mth; /* ThreadLocal.set() */ +static jmethodID threadlocal_get_mth; /* ThreadLocal.get() */ + +/* java.lang.Long and its methods */ +static jclass long_class; /* java.lang.Long */ +static jmethodID long_ctor; /* constructor for it: (J) */ +static jmethodID long_longValue_mth; /* longValue()J */ + + +/* GThreadNativeMethodRunner */ +static jclass runner_class; +static jmethodID runner_ctor; +static jmethodID runner_threadToThreadID_mth; +static jmethodID runner_threadIDToThread_mth; +static jmethodID runner_deRegisterJoinable_mth; +static jmethodID runner_start_mth; /* Inherited Thread.start() */ + + +/* java.lang.InterruptedException */ +static jclass interrupted_exception_class; + + + + +/* Returns a negative value if there was trouble during initialization. + Returns a positive value of the cache was initialized correctly. + Never returns zero. */ +static int +setup_cache (JNIEnv * env) +{ + jclass lcl_class; + static int initialized = 0; /* 1 means initialized, 0 means uninitialized, + -1 means mis-initialized */ + + if (initialized) + return initialized; + + /* make sure we can report on trouble */ + if (setup_exception_cache (env) < 0) + return initialized = -1; + +#ifdef JNI_VERSION_1_2 + if (HAVE_JNI_VERSION_1_2) + assert ( ! (*env)->ExceptionCheck (env)); + else +#endif + assert ( ! (*env)->ExceptionOccurred (env)); + + /* java.lang.Object and its methods */ + lcl_class = (*env)->FindClass (env, "java/lang/Object"); + if (!lcl_class) + { + BROKEN (env, "cannot find java.lang.Object"); + return initialized = -1; + } + + /* Pin it down. */ + obj_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!obj_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Object"); + return initialized = -1; + } + + obj_ctor = (*env)->GetMethodID (env, obj_class, "<init>", "()V"); + if (!obj_ctor) + { + BROKEN (env, "cannot find constructor for java.lang.Object"); + return initialized = -1; + } + + obj_notify_mth = (*env)->GetMethodID (env, obj_class, "notify", "()V"); + if ( ! obj_notify_mth ) + { + BROKEN (env, "cannot find java.lang.Object.notify()V"); + return initialized = -1; + } + + obj_notifyall_mth = + (*env)->GetMethodID (env, obj_class, "notifyAll", "()V"); + if ( ! obj_notifyall_mth) + { + BROKEN (env, "cannot find java.lang.Object.notifyall()V"); + return initialized = -1; + } + + obj_wait_mth = (*env)->GetMethodID (env, obj_class, "wait", "()V"); + if ( ! obj_wait_mth ) + { + BROKEN (env, "cannot find Object.<wait()V>"); + return initialized = -1; + } + + obj_wait_nanotime_mth = + (*env)->GetMethodID (env, obj_class, "wait", "(JI)V"); + if ( ! obj_wait_nanotime_mth ) + { + BROKEN (env, "cannot find Object.<wait(JI)V>"); + return initialized = -1; + } + + /* GThreadMutex and its methods */ + lcl_class = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GThreadMutex"); + if ( ! lcl_class) + { + BROKEN (env, "cannot find gnu.java.awt.peer.gtk.GThreadMutex"); + return initialized = -1; + } + /* Pin it down. */ + mutex_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if ( ! mutex_class) + { + BROKEN (env, "Cannot get a global reference to GThreadMutex"); + return initialized = -1; + } + + mutex_ctor = (*env)->GetMethodID (env, mutex_class, "<init>", "()V"); + if ( ! mutex_ctor) + { + BROKEN (env, "cannot find zero-arg constructor for GThreadMutex"); + return initialized = -1; + } + + mutex_potentialLockers_fld = (*env)->GetFieldID + (env, mutex_class, "potentialLockers", "I"); + if ( ! mutex_class ) + { + BROKEN (env, "cannot find GThreadMutex.potentialLockers"); + return initialized = -1; + } + + if (! (mutex_lockForPotentialLockers_fld = (*env)->GetFieldID + (env, mutex_class, "lockForPotentialLockers", "Ljava/lang/Object;"))) + { + BROKEN (env, "cannot find GThreadMutex.lockForPotentialLockers"); + return initialized = -1; + } + + + /* java.lang.Thread */ + if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread"))) + { + BROKEN (env, "cannot find java.lang.Thread"); + return initialized = -1; + } + + /* Pin it down. */ + thread_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!thread_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Thread"); + return initialized = -1; + } + + thread_current_mth = + (*env)->GetStaticMethodID (env, thread_class, "currentThread", + "()Ljava/lang/Thread;"); + if (!thread_current_mth) + { + BROKEN (env, "cannot find Thread.currentThread() method"); + return initialized = -1; + } + + thread_equals_mth = + (*env)->GetMethodID (env, thread_class, "equals", "(Ljava/lang/Object;)Z"); + if (!thread_equals_mth) + { + BROKEN (env, "cannot find Thread.equals() method"); + return initialized = -1; + } + + thread_join_mth = (*env)->GetMethodID (env, thread_class, "join", "()V"); + if (!thread_join_mth) + { + BROKEN (env, "cannot find Thread.join() method"); + return initialized = -1; + } + + thread_stop_mth = (*env)->GetMethodID (env, thread_class, "stop", "()V"); + if ( ! thread_stop_mth ) + { + BROKEN (env, "cannot find Thread.stop() method"); + return initialized = -1; + } + + thread_setPriority_mth = + (*env)->GetMethodID (env, thread_class, "setPriority", "(I)V"); + if ( ! thread_setPriority_mth ) + { + BROKEN (env, "cannot find Thread.setPriority() method"); + return initialized = -1; + } + + thread_yield_mth = + (*env)->GetStaticMethodID (env, thread_class, "yield", "()V"); + if ( ! thread_yield_mth ) + { + BROKEN (env, "cannot find Thread.yield() method"); + return initialized = -1; + } + + /* java.lang.ThreadLocal */ + lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.ThreadLocal"); + return initialized = -1; + } + + /* Pin it down. */ + threadlocal_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if ( ! threadlocal_class ) + { + BROKEN (env, "Cannot get a global reference to java.lang.ThreadLocal"); + return initialized = -1; + } + + threadlocal_ctor = (*env)->GetMethodID (env, threadlocal_class, + "<init>", "()V"); + if ( ! threadlocal_ctor ) + { + BROKEN (env, "cannot find ThreadLocal.<init>()V"); + return initialized = -1; + } + + threadlocal_get_mth = (*env)->GetMethodID (env, threadlocal_class, + "get", "()Ljava/lang/Object;"); + if ( ! threadlocal_get_mth ) + { + BROKEN (env, "cannot find java.lang.ThreadLocal.get()Object"); + return initialized = -1; + } + + threadlocal_set_mth = (*env)->GetMethodID (env, threadlocal_class, + "set", "(Ljava/lang/Object;)V"); + if ( ! threadlocal_set_mth ) + { + BROKEN (env, "cannot find ThreadLocal.set(Object)V"); + return initialized = -1; + } + + /* java.lang.Long */ + lcl_class = (*env)->FindClass (env, "java/lang/Long"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.Long"); + return initialized = -1; + } + + /* Pin it down. */ + long_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!long_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Long"); + return initialized = -1; + } + + long_ctor = (*env)->GetMethodID (env, long_class, "<init>", "(J)V"); + if (!long_ctor) + { + BROKEN (env, "cannot find method java.lang.Long.<init>(J)V"); + return initialized = -1; + } + + long_longValue_mth = + (*env)->GetMethodID (env, long_class, "longValue", "()J"); + if (!long_longValue_mth) + { + BROKEN (env, "cannot find method java.lang.Long.longValue()J"); + return initialized = -1; + } + + + /* GThreadNativeMethodRunner */ + lcl_class = + (*env)->FindClass (env, + "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner"); + if ( ! lcl_class ) + { + BROKEN (env, + "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner"); + return initialized = -1; + } + + /* Pin it down. */ + runner_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!runner_class) + { + BROKEN (env, + "Cannot get a global reference to the class GThreadNativeMethodRunner"); + return initialized = -1; + } + + runner_ctor = (*env)->GetMethodID (env, runner_class, "<init>", "(JJZ)V"); + if ( ! runner_ctor ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.<init>(JJZ)"); + return initialized = -1; + } + + runner_start_mth = (*env)->GetMethodID (env, runner_class, "start", "()V"); + if ( ! runner_start_mth ) + { + BROKEN (env, "cannot find method GThreadNativeMethodRunner.start()V"); + return initialized = -1; + } + + + runner_threadToThreadID_mth = + (*env)->GetStaticMethodID (env, runner_class, + "threadToThreadID", "(Ljava/lang/Thread;)I"); + if ( ! runner_threadToThreadID_mth ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.threadToThreadID(java.lang.Thread)I"); + return initialized = -1; + } + + + runner_threadIDToThread_mth = + (*env)->GetStaticMethodID (env, runner_class, + "threadIDToThread", "(I)Ljava/lang/Thread;"); + if ( ! runner_threadIDToThread_mth ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.threadIDToThread(I)java.lang.Thread"); + return initialized = -1; + } + + + runner_deRegisterJoinable_mth = + (*env)->GetStaticMethodID (env, runner_class, "deRegisterJoinable", + "(Ljava/lang/Thread;)V"); + if (!runner_deRegisterJoinable_mth) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.deRegisterJoinable(java.lang.Thread)V"); + return initialized = -1; + } + + + /* java.lang.InterruptedException */ + lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.InterruptedException"); + return initialized = -1; + } + + /* Pin it down. */ + interrupted_exception_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!interrupted_exception_class) + { + BROKEN (env, "Cannot make a global reference" + " to java.lang.InterruptedException"); + return initialized = -1; + } + +#ifdef JNI_VERSION_1_2 + if (HAVE_JNI_VERSION_1_2) + assert ( ! (*env)->ExceptionCheck (env)); + else +#endif + assert ( ! (*env)->ExceptionOccurred (env)); + + + return initialized = 1; +} + + + + + +/************************************************************************/ +/* Utilities to allocate and free java.lang.Objects */ +/************************************************************************/ + +/* The condition variables are java.lang.Object objects, + * which this method allocates and returns a global ref. Note that global + * refs must be explicitly freed (isn't C fun?). + */ +static jobject +allocatePlainObject (JNIEnv * env) +{ + jobject lcl_obj, global_obj; + + lcl_obj = (*env)->NewObject (env, obj_class, obj_ctor); + if (!lcl_obj) + { + BROKEN (env, "cannot allocate object"); + return NULL; + } + + global_obj = (*env)->NewGlobalRef (env, lcl_obj); + DELETE_LOCAL_REF (env, lcl_obj); + if (!global_obj) + { + NEW_BROKEN (env, "cannot make global ref for a new plain Java object"); + /* Deliberate fall-through */ + } + + return global_obj; +} + +/* Frees any Java object given a global ref (isn't C fun?) */ +static void +freeObject (JNIEnv * env, jobject obj) +{ + if (obj) + { + (*env)->DeleteGlobalRef (env, obj); + /* DeleteGlobalRef can never fail */ + } +} + + +/************************************************************************/ +/* Utilities to allocate and free Java mutexes */ +/************************************************************************/ + +/* The mutexes are gnu.java.awt.peer.gtk.GThreadMutex objects, + * which this method allocates and returns a global ref. Note that global + * refs must be explicitly freed (isn't C fun?). + * + * Free this with freeObject() + */ +static jobject +allocateMutexObject (JNIEnv * env) +{ + jobject lcl_obj, global_obj; + + lcl_obj = (*env)->NewObject (env, mutex_class, mutex_ctor); + if (!lcl_obj) + { + BROKEN (env, "cannot allocate a GThreadMutex"); + return NULL; + } + + global_obj = (*env)->NewGlobalRef (env, lcl_obj); + DELETE_LOCAL_REF (env, lcl_obj); + if (!global_obj) + { + NEW_BROKEN (env, "cannot make global ref"); + /* Deliberate fallthrough */ + } + + return global_obj; +} + + +/************************************************************************/ +/* Locking code */ +/************************************************************************/ + +/* Lock a Java object */ +#define ENTER_MONITOR(env, m) \ + enterMonitor(env, m, G_STRINGIFY(m)) + +/* Return -1 on failure, 0 on success. */ +static int +enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[]) +{ + if (TRACE_MONITORS) + tracing (" <MonitorEnter(%s)>", monName); + assert (monitorObj); + if ((*env)->MonitorEnter (env, monitorObj) < 0) + { + BROKEN (env, "cannot enter monitor"); + return -1; + } + return 0; +} + + +/* Unlock a Java object */ +#define EXIT_MONITOR(env, m) \ + exitMonitor(env, m, G_STRINGIFY(m)) + +static int +exitMonitor (JNIEnv * env, jobject mutexObj, const char monName[]) +{ + if (TRACE_MONITORS) + tracing (" <MonitorExit(%s)>", monName); + assert (mutexObj); + if ((*env)->MonitorExit (env, mutexObj) < 0) + { + BROKEN (env, "cannot exit monitor "); + return -1; + } + return 0; +} + + +/************************************************************************/ +/* Miscellaneous utilities */ +/************************************************************************/ + +/* Get the Java Thread object that corresponds to a particular thread ID. + A negative thread Id gives us a null object. + + Returns a local reference. +*/ +static jobject +getThreadFromThreadID (JNIEnv * env, gpointer gThreadID) +{ + jint threadNum = (jint) gThreadID; + jobject thread; + + if (threadNum < 0) + { + NEW_BROKEN (env, "getThreadFromThreadID asked to look up" + " a negative thread index"); + return NULL; + } + + thread = (*env)->CallStaticObjectMethod + (env, runner_class, runner_threadIDToThread_mth, threadNum); + + if (MAYBE_BROKEN (env, "cannot get Thread for threadID ")) + return NULL; + + return thread; +} + +/** Return the unique threadID of THREAD. + + Error handling: Return (gpointer) -1 on all failures, + and propagate an exception. +*/ +static gpointer +getThreadIDFromThread (JNIEnv * env, jobject thread) +{ + jint threadNum; + + if (ENABLE_EXPENSIVE_ASSERTIONS) + assert ((*env)->IsInstanceOf (env, thread, thread_class)); + + HIDE_OLD_TROUBLE (env); + + threadNum = (*env)->CallStaticIntMethod + (env, runner_class, runner_threadToThreadID_mth, thread); + + if (MAYBE_BROKEN (env, "cannot get ThreadID for a Thread ")) + { + threadNum = -1; + goto done; + } + + + SHOW_OLD_TROUBLE (); + +done: + return (gpointer) threadNum; +} + + +/************************************************************************/ +/* The Actual JNI functions that we pass to the function vector. */ +/************************************************************************/ + + +/************************************************************************/ +/* Mutex Functions */ +/************************************************************************/ + +/*** Mutex Utilities ****/ +struct mutexObj_cache +{ + jobject lockForPotentialLockersObj; /* Lock for the potentialLockers + field. Local reference. */ + jobject lockObj; /* The real lock we use. This is a GLOBAL + reference and must not be freed. */ +}; + +/* Initialize the cache of sub-locks for a particular mutex object. + + -1 on error, 0 on success. The caller is not responsible for freeing the + partially-populated cache in case of failure (but in practice does anyway) + (This actually never fails, though, since GetObjectField allegedly never + fails.) + + Guaranteed to leave all fields of the cache initialized, even if only to + zero. +*/ +static int +populate_mutexObj_cache (JNIEnv * env, jobject mutexObj, + struct mutexObj_cache *mcache) +{ + mcache->lockObj = mutexObj; /* the mutexObj is its own lock. */ + assert (mcache->lockObj); + + mcache->lockForPotentialLockersObj = (*env)->GetObjectField + (env, mutexObj, mutex_lockForPotentialLockers_fld); + /* GetObjectField can never fail. */ + + /* Retrieving a NULL object could only happen if we somehow got a + a mutex object that was not properly intialized. */ + assert (mcache->lockForPotentialLockersObj); + + return 0; +} + + +/* Clean out the mutexObj_cache, even if it was never populated. */ +static void +clean_mutexObj_cache (JNIEnv * env, struct mutexObj_cache *mcache) +{ + /* OK to pass NULL refs to DELETE_LOCAL_REF */ + DELETE_LOCAL_REF (env, mcache->lockForPotentialLockersObj); + /* mcache->lockObj is a GLOBAL reference. */ + mcache->lockObj = NULL; +} + +/* -1 on failure, 0 on success. + The mutexObj_cache is already populated for this particular object. */ +static int +mutexObj_lock (JNIEnv * env, jobject mutexObj, struct mutexObj_cache *mcache) +{ + jint potentialLockers; + + if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj)) + return -1; + + assert(mutexObj); + potentialLockers = + (*env)->GetIntField (env, mutexObj, mutex_potentialLockers_fld); + /* GetIntField() never fails. */ + + ++potentialLockers; + + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + + if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj)) + return -1; + + if (ENTER_MONITOR (env, mcache->lockObj)) + return -1; + + SHOW_OLD_TROUBLE (); + + return 0; +} + +/* Unlock a GMutex, once we're already in JNI and have already gotten the + mutexObj for it. This skips the messages that TRACE_API_CALLS would + print. + + Returns -1 on error, 0 on success. */ +static int +mutexObj_unlock (JNIEnv * env, jobject mutexObj, + struct mutexObj_cache *mcache) +{ + jint potentialLockers; + int ret = -1; /* assume failure until we suceed. */ + + /* Free the lock first, so that someone waiting for the lock can get it + ASAP. */ + /* This is guaranteed not to block. */ + if (EXIT_MONITOR (env, mcache->lockObj) < 0) + goto done; + + /* Kick down potentialLockers by one. We do this AFTER we free the lock, so + that we hold it no longer than necessary. */ + if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) + goto done; + + potentialLockers = (*env)->GetIntField + (env, mutexObj, mutex_potentialLockers_fld); + /* GetIntField never fails */ + + assert (potentialLockers >= 1); + --potentialLockers; + + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + /* Never fails, so the JNI book says. */ + + /* Clean up. */ + if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) + goto done; + ret = 0; + +done: + return ret; +} + +/*** Mutex Implementations ****/ + +/* Create a mutex, which is a java.lang.Object for us. + In case of failure, we'll return NULL. Which will implicitly + cause future calls to fail. */ +static GMutex * +mutex_new_jni_impl (void) +{ + jobject mutexObj; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_new_jni_impl()"); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + { + mutexObj = NULL; + goto done; + } + + mutexObj = allocateMutexObject (env); + +done: + if (TRACE_API_CALLS) + tracing (" ==> %p \n", mutexObj); + + return (GMutex *) mutexObj; + +} + +/* Lock a mutex. */ +static void +mutex_lock_jni_impl (GMutex * mutex) +{ + struct mutexObj_cache mcache; + jobject mutexObj = (jobject) mutex; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj); + + assert (mutexObj); + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + goto done; + + HIDE_OLD_TROUBLE (env); + + if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + mutexObj_lock (env, mutexObj, &mcache); + /* No need to error check; we've already reported it in any case. */ + +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); +} + + +/* Try to lock a mutex. Return TRUE if we succeed, FALSE if we fail. + FALSE on error. */ +static gboolean +mutex_trylock_jni_impl (GMutex * gmutex) +{ + jobject mutexObj = (jobject) gmutex; + jint potentialLockers; + gboolean ret = FALSE; + JNIEnv *env; + union env_union e; + struct mutexObj_cache mcache; + + if (TRACE_API_CALLS) + tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj); + + assert (mutexObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + if (ENTER_MONITOR (env, mcache.lockForPotentialLockersObj)) + goto done; + + potentialLockers = (*env)->GetIntField + (env, mutexObj, mutex_potentialLockers_fld); + + assert (potentialLockers >= 0); + + if (potentialLockers) + { + /* Already locked. Clean up and leave. */ + EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); + /* Ignore any error code from EXIT_MONITOR; there's nothing we could do + at this level, in any case. */ + goto done; + } + + /* Guaranteed not to block. */ + if (ENTER_MONITOR (env, mcache.lockObj)) + { + /* Clean up the existing lock. */ + EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); + /* Ignore any error code from EXIT_MONITOR; there's nothing we could do + at this level, in any case. */ + goto done; + } + + + /* We have the monitor. Record that fact. */ + potentialLockers = 1; + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + /* Set*Field() never fails */ + + ret = TRUE; /* We have the lock. */ + + /* Clean up. */ + if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj)) + goto done; /* If we fail at this point, still keep the + main lock. */ + + SHOW_OLD_TROUBLE (); +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); + return ret; +} + + +/* Unlock a mutex. */ +static void +mutex_unlock_jni_impl (GMutex * gmutex) +{ + jobject mutexObj = (jobject) gmutex; + struct mutexObj_cache mcache; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (mutexObj); + + if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + (void) mutexObj_unlock (env, mutexObj, &mcache); + + SHOW_OLD_TROUBLE (); + +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + + +/* Free a mutex (isn't C fun?). OK this time for it to be NULL. + No failure conditions, for a change. */ +static void +mutex_free_jni_impl (GMutex * mutex) +{ + jobject mutexObj = (jobject) mutex; + JNIEnv *env; + union env_union e; + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + if (TRACE_API_CALLS) + tracing ("mutex_free_jni_impl(%p)", mutexObj); + + freeObject (env, mutexObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + + + +/************************************************************************/ +/* Condition variable code */ +/************************************************************************/ + +/* Create a new condition variable. This is a java.lang.Object for us. */ +static GCond * +cond_new_jni_impl (void) +{ + jobject condObj; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_free_jni_impl()"); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + condObj = allocatePlainObject (env); + + if (TRACE_API_CALLS) + tracing (" ==> %p\n", condObj); + + return (GCond *) condObj; +} + +/* Signal on a condition variable. This is simply calling Object.notify + * for us. + */ +static void +cond_signal_jni_impl (GCond * gcond) +{ + JNIEnv *env; + union env_union e; + jobject condObj = (jobject) gcond; + + if (TRACE_API_CALLS) + tracing ("cond_signal_jni_impl(condObj = %p)", condObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (condObj); + + /* Must have locked an object to call notify */ + if (ENTER_MONITOR (env, condObj)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_notify_mth); + if (MAYBE_BROKEN (env, "cannot signal mutex with Object.notify()")) + { + if (EXIT_MONITOR (env, condObj)) + BADLY_BROKEN1 ("Failed to unlock a monitor; the VM may deadlock."); + goto done; + } + + EXIT_MONITOR (env, condObj); + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + +/* Broadcast to all waiting on a condition variable. This is simply + * calling Object.notifyAll for us. + */ +static void +cond_broadcast_jni_impl (GCond * gcond) +{ + jobject condObj = (jobject) gcond; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (condObj); + /* Must have locked an object to call notifyAll */ + if (ENTER_MONITOR (env, condObj)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_notifyall_mth); + if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()")) + { + EXIT_MONITOR (env, condObj); + goto done; + } + + EXIT_MONITOR (env, condObj); + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/* Wait on a condition variable. For us, this simply means calling + * Object.wait. + * + * Throws a Java exception on trouble; may leave the mutexes set arbitrarily. + * XXX TODO: Further improve error recovery. + */ +static void +cond_wait_jni_impl (GCond * gcond, GMutex * gmutex) +{ + struct mutexObj_cache cache; + jobject condObj = (jobject) gcond; + jobject mutexObj = (jobject) gmutex; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)", + condObj, mutexObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (condObj); + assert (mutexObj); + /* Must have locked a Java object to call wait on it */ + if (ENTER_MONITOR (env, condObj) < 0) + goto done; + + /* Our atomicity is now guaranteed; we're protected by the Java monitor on + condObj. Unlock the GMutex. */ + if (mutexObj_unlock (env, mutexObj, &cache)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_wait_mth); + if (MAYBE_BROKEN (env, "cannot wait on condObj")) + { + EXIT_MONITOR (env, condObj); /* ignore err checking */ + goto done; + } + + /* Re-acquire the lock on the GMutex. Do this while we're protected by the + Java monitor on condObj. */ + if (mutexObj_lock (env, mutexObj, &cache)) + goto done; + + EXIT_MONITOR (env, condObj); + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/** Wait on a condition variable until a timeout. This is a little tricky + * for us. We first call Object.wait(J) giving it the appropriate timeout + * value. On return, we check whether an InterruptedException happened. If + * so, that is Java-speak for wait timing out. + * + * We return FALSE if we timed out. Return TRUE if the condition was + * signalled first, before we timed out. + * + * In case of trouble we throw a Java exception. Whether we return FALSE or + * TRUE depends upon whether the condition was raised before the trouble + * happened. + * + * I believe that this function goes to the proper lengths to try to unlock + * all of the locked mutexes and monitors, as appropriate, and that it further + * tries to make sure that the thrown exception is the current one, not any + * future cascaded one from something like a failure to unlock the monitors. + */ +static gboolean +cond_timed_wait_jni_impl (GCond * gcond, GMutex * gmutex, GTimeVal * end_time) +{ + JNIEnv *env; + union env_union e; + jlong time_millisec; + jint time_nanosec; + jthrowable cause; + jobject condObj = (jobject) gcond; + jobject mutexObj = (jobject) gmutex; + gboolean condRaised = FALSE; /* Condition has not been raised yet. */ + struct mutexObj_cache cache; + gboolean interrupted; + + if (TRACE_API_CALLS) + { + tracing ("cond_timed_wait_jni_impl(cond=%p, mutex=%p," + " end_time=< sec=%lu, usec=%lu >)", condObj, mutexObj, + (unsigned long) end_time->tv_sec, + (unsigned long) end_time->tv_usec); + } + + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + time_millisec = end_time->tv_sec * 1000 + end_time->tv_usec / 1000; + time_nanosec = 1000 * (end_time->tv_usec % 1000); + + /* Must have locked an object to call wait */ + if (ENTER_MONITOR (env, condObj) < 0) + goto done; + + if (mutexObj_unlock (env, mutexObj, &cache) < 0) + { + if (EXIT_MONITOR (env, condObj) < 0) + criticalMsg + ("Unable to unlock an existing lock on a condition; your proram may deadlock"); + goto done; + } + + + (*env)->CallVoidMethod (env, condObj, obj_wait_nanotime_mth, + time_millisec, time_nanosec); + + /* If there was trouble, save that fact, and the reason for the trouble. We + want to respond to this condition as fast as possible. */ + cause = (*env)->ExceptionOccurred (env); + + if ( ! cause ) + { + condRaised = TRUE; /* condition was signalled */ + } + else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class)) + { + condRaised = FALSE; /* Condition was not raised before timeout. + (This is redundant with the initialization + of condRaised above) */ + (*env)->ExceptionClear (env); /* Clear the InterruptedException. */ + cause = NULL; /* no pending cause now. */ + } + else + { + interrupted = FALSE; /* Trouble, but not because of + InterruptedException. Assume the condition + was not raised. */ + /* Leave condRaised set to FALSE */ + } + + /* Irrespective of whether there is a pending problem to report, go ahead + and try to clean up. This may end up throwing an exception that is + different from the one that was thrown by the call to Object.wait(). + So we will override it with the first exception (don't want to have + cascading problems). */ + if (mutexObj_lock (env, mutexObj, &cache) && !cause) + { + cause = (*env)->ExceptionOccurred (env); + assert (cause); + } + + if (EXIT_MONITOR (env, condObj) && !cause) + { + cause = (*env)->ExceptionOccurred (env); + assert (cause); + } + + if (cause) /* Raise the first cause. */ + { + BROKEN_CAUSE (env, cause, "error in timed wait or during its cleanup"); + goto done; + } + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> condRaised = %s\n", condRaised ? "TRUE" : "FALSE"); + return condRaised; +} + + +/* Free a condition variable. (isn't C fun?). Can not fail. */ +static void +cond_free_jni_impl (GCond * cond) +{ + jobject condObj = (jobject) cond; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("cond_free_jni_impl(condObj = %p)", condObj); + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + freeObject (env, condObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/************************************************************************/ +/* Thread-local data code */ +/************************************************************************/ + +/* Create a new thread-local key. We use java.lang.ThreadLocal objects + * for this. This returns the pointer representation of a Java global + * reference. + * + * We will throw a Java exception and return NULL in case of failure. + */ +static GPrivate * +private_new_jni_impl (GDestroyNotify notify __attribute__ ((unused))) +{ + JNIEnv *env; + union env_union e; + jobject lcl_key; + jobject global_key; + GPrivate *gkey = NULL; /* Error return code */ + + if (TRACE_API_CALLS) + tracing ("private_new_jni_impl()"); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + lcl_key = (*env)->NewObject (env, threadlocal_class, threadlocal_ctor); + if ( ! lcl_key ) + { + BROKEN (env, "cannot allocate a ThreadLocal"); + goto done; + } + + global_key = ((*env)->NewGlobalRef (env, lcl_key)); + DELETE_LOCAL_REF (env, lcl_key); + if ( ! global_key) + { + NEW_BROKEN (env, "cannot create a GlobalRef to a new ThreadLocal"); + goto done; + } + + gkey = (GPrivate *) global_key; + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> %p\n", (void *) gkey); + + return gkey; +} + +/* Get this thread's value for a thread-local key. This is simply + * ThreadLocal.get for us. Return NULL if no value. (I can't think of + * anything else to do.) + */ +static gpointer +private_get_jni_impl (GPrivate * gkey) +{ + JNIEnv *env; + union env_union e; + jobject val_wrapper; + jobject keyObj = (jobject) gkey; + gpointer thread_specific_data = NULL; /* Init to the error-return value */ + + jlong val; + + if (TRACE_API_CALLS) + tracing ("private_get_jni_impl(keyObj=%p)", keyObj); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + val_wrapper = (*env)->CallObjectMethod (env, keyObj, threadlocal_get_mth); + if (MAYBE_BROKEN (env, "cannot find thread-local object")) + goto done; + + if (! val_wrapper ) + { + /* It's Java's "null" object. No ref found. This is OK; we must never + have set a value in this thread. Note that this next statement is + not necessary, strictly speaking, since we're already initialized to + NULL. A good optimizing C compiler will detect that and optimize out + this statement. */ + thread_specific_data = NULL; + goto done; + } + + val = (*env)->CallLongMethod (env, val_wrapper, long_longValue_mth); + + if (MAYBE_BROKEN (env, "cannot get thread local value")) + goto done; + + thread_specific_data = (gpointer) (intptr_t) val; + + /* Only re-raise the old pending exception if a new one hasn't come along to + supersede it. */ + SHOW_OLD_TROUBLE (); + +done: + + if (TRACE_API_CALLS) + tracing (" ==> %p\n", thread_specific_data); + + return thread_specific_data; +} + +/* Set this thread's value for a thread-local key. This is simply + * ThreadLocal.set() for us. + */ +static void +private_set_jni_impl (GPrivate * gkey, gpointer thread_specific_data) +{ + JNIEnv *env; + union env_union e; + jobject val_wrapper; + jobject keyObj = (jobject) gkey; + + + if (TRACE_API_CALLS) + tracing ("private_set_jni_impl(keyObj=%p, thread_specific_data=%p)", + keyObj, thread_specific_data); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + /* We are just going to always use a Java long to represent a C pointer. + Otherwise all of the code would end up being conditionalized for various + pointer sizes, and that seems like too much of a hassle, in order to save + a paltry few bytes, especially given the horrendous overhead of JNI in + any case. + */ + + val_wrapper = (*env)->NewObject (env, long_class, long_ctor, + (jlong) (intptr_t) thread_specific_data); + if ( ! val_wrapper ) + { + BROKEN (env, "cannot create a java.lang.Long"); + goto done; + } + + /* At this point, we now have set lcl_obj as a numeric class that wraps + around the thread-specific data we were given. */ + (*env)->CallVoidMethod (env, keyObj, threadlocal_set_mth, val_wrapper); + if (MAYBE_BROKEN (env, "cannot set thread local value")) + goto done; + + SHOW_OLD_TROUBLE (); +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner. + Run it. + + We need to create joinable threads. We handle the notion of a joinable + thread by determining whether or not we are going to maintain a permanent + hard reference to it until it croaks. + + Posix does not appear to have a Java-like concept of daemon threads, where + the JVM will exit when there are only daemon threads running. + + Error handling: + + To quote from the glib guide: + "GError should only be used to report recoverable runtime errors, never + to report programming errors." + + So how do we consider the failure to create a thread? Well, each of the + failure cases in this function are discussed, and none of them are really + recoverable. + + The glib library is really designed so that you should fail + catastrophically in case of "programming errors". The only error defined + for the GThread functions is G_THREAD_ERROR_AGAIN, and that for + thread_create. + + Most of these GThread functions could fail if we run out of memory, for + example, but the only one capable of reporting that fact is + thread_create. */ +static void +thread_create_jni_impl (GThreadFunc func, + gpointer data, + gulong stack_size __attribute__((unused)), + gboolean joinable, + gboolean bound __attribute__((unused)), + GThreadPriority gpriority, + /* This prototype is horrible. threadIDp is actually + a gpointer to the thread's thread-ID. Which is, + of course, itself a gpointer-typed value. Ouch. */ + gpointer threadIDp, + /* Do not touch the GError stuff unless you have + RECOVERABLE trouble. There is no recoverable + trouble in this implementation. */ + GError **errorp __attribute__((unused))) +{ + JNIEnv *env; + union env_union e; + union func_union f; + jboolean jjoinable = joinable; + jobject newThreadObj; + gpointer threadID; /* to be filled in */ + + if (TRACE_API_CALLS) + { + f.g_func = func; + tracing ("thread_create_jni_impl(func=%p, data=%p, joinable=%s," + " threadIDp=%p, *(int *) threadIDp = %d)", + f.void_func, data, joinable ? "TRUE" : "FALSE", + threadIDp, *(int *) threadIDp); + } + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + { + /* The failed call to setup the cache is certainly not recoverable; + not appropriate for G_THREAD_ERROR_AGAIN. */ + *(gpointer *) threadIDp = NULL; + goto done; + } + HIDE_OLD_TROUBLE (env); + + /* If a thread is joinable, then notify its constructor. The constructor + will enter a hard reference for it, and the hard ref. won't go away until + the thread has been joined. */ + newThreadObj = + (*env)->NewObject (env, runner_class, runner_ctor, + (jlong) (intptr_t) func, (jlong) (intptr_t) data, + jjoinable); + if ( ! newThreadObj ) + { + BROKEN (env, "creating a new thread failed in the constructor"); + *(gpointer *) threadIDp = NULL; + /* The failed call to the constructor does not throw any errors such + that G_THREAD_ERROR_AGAIN is appropriate. No other recoverable + errors defined. Once again, we go back to the VM. */ + goto done; + } + + if (threadObj_set_priority (env, newThreadObj, gpriority) < 0) + { + *(gpointer *) threadIDp = NULL; + /* None of these possible exceptions from Thread.setPriority() are + recoverable, so they are not appropriate for EAGAIN. So we should + fail. */ + goto done; + } + + (*env)->CallVoidMethod (env, runner_class, runner_start_mth); + + if (MAYBE_BROKEN (env, "starting a new thread failed")) + { + *(gpointer *) threadIDp = NULL; + /* The only exception Thread.start() throws is + IllegalStateException. And that would indicate a programming error. + + So there are no situations such that G_THREAD_ERROR_AGAIN would be + OK. + + So, we don't use g_set_error() here to perform any error reporting. + */ + goto done; + } + + threadID = getThreadIDFromThread (env, newThreadObj); + + *(gpointer *) threadIDp = threadID; + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> (threadID = %p) \n", threadID); +} + + +/* Wraps a call to g_thread_yield. */ +static void +thread_yield_jni_impl (void) +{ + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("thread_yield_jni_impl()"); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + (*env)->CallStaticVoidMethod (env, thread_class, thread_yield_mth); + if (MAYBE_BROKEN (env, "Thread.yield() failed")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +static void +thread_join_jni_impl (gpointer threadID) +{ + JNIEnv *env; + union env_union e; + jobject threadObj = NULL; + + if ( TRACE_API_CALLS ) + tracing ("thread_join_jni_impl(threadID=%p) ", threadID); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + threadObj = getThreadFromThreadID (env, threadID); + if ( ! threadObj ) /* Already reported with BROKEN */ + goto done; + + (*env)->CallVoidMethod (env, threadObj, thread_join_mth); + if (MAYBE_BROKEN (env, "Thread.join() failed")) + goto done; + + + (*env)->CallStaticVoidMethod + (env, runner_class, runner_deRegisterJoinable_mth, threadObj); + if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + DELETE_LOCAL_REF (env, threadObj); + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); +} + +/* Terminate the current thread. Unlike pthread_exit(), here we do not need + to bother with a return value or exit value for the thread which is about + to croak. (The gthreads abstraction doesn't use it.) However, we *do* + need to bail immediately. We handle this with Thread.stop(), which is + a deprecated method. + + It's deprecated since we might leave objects protected by monitors in + half-constructed states on the way out -- Thread.stop() throws a + ThreadDeath exception, which is usually unchecked. There is no good + solution that I can see. */ +static void +thread_exit_jni_impl (void) +{ + JNIEnv *env; + union env_union e; + jobject this_thread; + + if (TRACE_API_CALLS) + tracing ("thread_exit_jni_impl() "); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + + HIDE_OLD_TROUBLE (env); + + this_thread = (*env)-> + CallStaticObjectMethod (env, thread_class, thread_current_mth); + + if ( ! this_thread ) + { + BROKEN (env, "cannot get current thread"); + goto done; + } + + (*env)->CallVoidMethod (env, this_thread, thread_stop_mth); + if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); +} + + +/* Translate a GThreadPriority to a Java priority level. */ +static jint +javaPriorityLevel (GThreadPriority priority) +{ + /* We have these fields in java.lang.Thread to play with: + + static int MIN_PRIORITY The minimum priority that a thread can have. + static int NORM_PRIORITY The default priority that is assigned to a + thread. + static int MAX_PRIORITY The maximum priority that a thread can have. + + We get these from the header file generated by javah, even though they're + documented as being 1, 5, and 10. + */ + static const jint minJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY; + static const jint normJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY; + static const jint maxJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY; + + switch (priority) + { + case G_THREAD_PRIORITY_LOW: + return minJPri; + break; + + default: + assert_not_reached (); + /* Deliberate fall-through if assertions are turned off; also shuts up + GCC warnings if they're turned on. */ + case G_THREAD_PRIORITY_NORMAL: + return normJPri; + break; + + case G_THREAD_PRIORITY_HIGH: + return (normJPri + maxJPri) / 2; + break; + + case G_THREAD_PRIORITY_URGENT: + return maxJPri; + break; + } +} + + +/** It would be safe not to implement this, according to the JNI docs, since + not all platforms do thread priorities. However, we might as well + provide the hint for those who want it. +*/ +static void +thread_set_priority_jni_impl (gpointer gThreadID, GThreadPriority gpriority) +{ + jobject threadObj = NULL; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ", + gThreadID, gpriority); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + goto done; + + HIDE_OLD_TROUBLE (env); + + + threadObj = getThreadFromThreadID (env, gThreadID); + if ( ! threadObj) /* Reported with BROKEN already. */ + goto done; + + if (threadObj_set_priority (env, threadObj, gpriority)) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + DELETE_LOCAL_REF (env, threadObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/** It would be safe not to implement this, according to the JNI docs, since + not all platforms do thread priorities. However, we might as well + provide the hint for those who want it. + + -1 on failure, 0 on success. */ +static int +threadObj_set_priority (JNIEnv * env, jobject threadObj, + GThreadPriority gpriority) +{ + jint javaPriority = javaPriorityLevel (gpriority); + (*env)->CallVoidMethod (env, threadObj, thread_setPriority_mth, + javaPriority); + return MAYBE_BROKEN (env, "Thread.setPriority() failed"); +} + + +/** Return the result of Thread.currentThread(), a static method. */ +static void +thread_self_jni_impl (/* Another confusing glib prototype. This is + actually a gpointer to the thread's thread-ID. + Which is, of course, a gpointer. */ + gpointer my_thread_IDp) +{ + JNIEnv *env; + union env_union e; + jobject this_thread; + gpointer my_threadID; + + if (TRACE_API_CALLS) + tracing ("thread_self_jni_impl(my_thread_IDp=%p)", my_thread_IDp); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + return; + + HIDE_OLD_TROUBLE (env); + + this_thread = (*env)-> + CallStaticObjectMethod (env, thread_class, thread_current_mth); + if (! this_thread ) + { + BROKEN (env, "cannot get current thread"); + my_threadID = NULL; + goto done; + } + + my_threadID = getThreadIDFromThread (env, this_thread); + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> (my_threadID = %p) \n", my_threadID); + + *(gpointer *) my_thread_IDp = my_threadID; +} + + +static gboolean +thread_equal_jni_impl (gpointer thread1, gpointer thread2) +{ + JNIEnv *env; + union env_union e; + + gpointer threadID1 = *(gpointer *) thread1; + gpointer threadID2 = *(gpointer *) thread2; + + jobject thread1_obj = NULL; + jobject thread2_obj = NULL; + gboolean ret; + + if (TRACE_API_CALLS) + tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)", + threadID1, threadID2); + + e.jni_env = &env; + (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + { + ret = FALSE; /* what is safer? We really don't ever want + to return from here. */ + goto done; + } + + HIDE_OLD_TROUBLE (env); + thread1_obj = getThreadFromThreadID (env, threadID1); + thread2_obj = getThreadFromThreadID (env, threadID2); + + ret = (*env)->CallBooleanMethod (env, thread1_obj, + thread_equals_mth, thread2_obj); + + if (MAYBE_BROKEN (env, "Thread.equals() failed")) + { + ret = FALSE; + goto done; + } + + SHOW_OLD_TROUBLE (); + + +done: + DELETE_LOCAL_REF (env, thread1_obj); + DELETE_LOCAL_REF (env, thread2_obj); + + if (TRACE_API_CALLS) + tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); + + return ret; +} + + + + +/************************************************************************/ +/* GLIB interface */ +/************************************************************************/ + +/* set of function pointers to give to glib. */ +GThreadFunctions cp_gtk_portable_native_sync_jni_functions = { + mutex_new_jni_impl, /* mutex_new */ + mutex_lock_jni_impl, /* mutex_lock */ + mutex_trylock_jni_impl, /* mutex_trylock */ + mutex_unlock_jni_impl, /* mutex_unlock */ + mutex_free_jni_impl, /* mutex_free */ + cond_new_jni_impl, /* cond_new */ + cond_signal_jni_impl, /* cond_signal */ + cond_broadcast_jni_impl, /* cond_broadcast */ + cond_wait_jni_impl, /* cond_wait */ + cond_timed_wait_jni_impl, /* cond_timed_wait */ + cond_free_jni_impl, /* cond_free */ + private_new_jni_impl, /* private_new */ + private_get_jni_impl, /* private_get */ + private_set_jni_impl, /* private_set */ + thread_create_jni_impl, /* thread_create */ + thread_yield_jni_impl, /* thread_yield */ + thread_join_jni_impl, /* thread_join */ + thread_exit_jni_impl, /* thread_exit */ + thread_set_priority_jni_impl, /* thread_set_priority */ + thread_self_jni_impl, /* thread_self */ + thread_equal_jni_impl, /* thread_equal */ +}; + + +/* Keep c-font-lock-extra-types in alphabetical order. */ +/* Local Variables: */ +/* c-file-style: "gnu" */ +/* c-font-lock-extra-types: ("\\sw+_t" "gboolean" "GError" "gpointer" + "GPrivate" "GThreadFunc" "GThreadFunctions" "GThreadPriority" + "gulong" + "JNIEnv" + "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject" "jstring" "jthrowable" ) */ +/* End: */ diff --git a/libjava/classpath/native/jni/gtk-peer/gthread-jni.h b/libjava/classpath/native/jni/gtk-peer/gthread-jni.h new file mode 100644 index 00000000000..3d052dc106e --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gthread-jni.h @@ -0,0 +1,48 @@ +/* gthread-jni.h + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef __GTHREADJNI_H__ +#define __GTHREADJNI_H__ + +#include <jni.h> +#include <glib.h> +#include "gtkpeer.h" + +extern GThreadFunctions cp_gtk_portable_native_sync_jni_functions; +extern JavaVM *cp_gtk_the_vm; + +#endif /* __GTHREADJNI_H__ */ diff --git a/libjava/classpath/native/jni/gtk-peer/gtkcairopeer.h b/libjava/classpath/native/jni/gtk-peer/gtkcairopeer.h new file mode 100644 index 00000000000..dee843c8a70 --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gtkcairopeer.h @@ -0,0 +1,93 @@ +#ifndef __GTKCAIROPEER_H__ +#define __GTKCAIROPEER_H__ + +/* gtkcairopeer.h -- Some global variables and #defines + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gtkpeer.h" +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +/* + A graphics2d struct is both simpler and uglier than a graphics + struct. + + Most of the graphics2d drawing state is held in the referenced cairo_t + and corresponding cairo_surface_t, so we can ignore it. + + In addition to the cairo_t, we need to hold an extra reference to the + underlying GdkDrawable so its refcount matches the lifecycle of the java + Graphics object which is peering with us; also a reference to a byte + buffer and cairo_surface_t which contain the pattern you're drawing from + (if it exists). + + Finally, it is possible that we are using a non-RENDER capable X server, + therefore we will be drawing to an cairo_surface_t which is actually a + pixbuf. When this is the case, the pointer to a GdkPixbuf will be + non-NULL and any drawing operation needs to be bracketed by pixbuf + load/save operations. If the GdkPixbuf pointer is NULL, we will treat + the cairo_surface_t as RENDER-capable. + */ + +struct graphics2d +{ + cairo_t *cr; + cairo_surface_t *surface; + GdkDrawable *drawable; + GdkWindow *win; + GdkPixbuf *drawbuf; + char *pattern_pixels; + cairo_surface_t *pattern_surface; + cairo_pattern_t *pattern; + gboolean debug; + enum + { + MODE_DRAWABLE_WITH_RENDER, + MODE_DRAWABLE_NO_RENDER, + MODE_JAVA_ARRAY + } + mode; + + /* Support for MODE_JAVA_ARRAY */ + jintArray jarray; + jint width, height; + jint *javabuf; + jint *javabuf_copy; + jboolean isCopy; +}; + +#endif /* __GTKCAIROPEER_H */ diff --git a/libjava/classpath/native/jni/gtk-peer/gtkpeer.h b/libjava/classpath/native/jni/gtk-peer/gtkpeer.h new file mode 100644 index 00000000000..f291d82ef4b --- /dev/null +++ b/libjava/classpath/native/jni/gtk-peer/gtkpeer.h @@ -0,0 +1,206 @@ +/* gtkpeer.h -- Some global variables and #defines + Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <gtk/gtk.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <config.h> +#include "native_state.h" + +#include <jni.h> + +#ifndef __GTKPEER_H__ +#define __GTKPEER_H__ + +#ifndef __GNUC__ +#define __attribute__(x) /* nothing */ +#endif + +extern struct state_table *cp_gtk_native_state_table; +extern struct state_table *cp_gtk_native_global_ref_table; + +#define NSA_INIT(env, clazz) \ + do {cp_gtk_native_state_table = cp_gtk_init_state_table (env, clazz); \ + cp_gtk_native_global_ref_table = cp_gtk_init_state_table (env, clazz);} while (0) + +#define NSA_GET_PTR(env, obj) \ + cp_gtk_get_state (env, obj, cp_gtk_native_state_table) + +#define NSA_SET_PTR(env, obj, ptr) \ + cp_gtk_set_state (env, obj, cp_gtk_native_state_table, (void *)ptr) + +#define NSA_DEL_PTR(env, obj) \ + cp_gtk_remove_state_slot (env, obj, cp_gtk_native_state_table) + +#define NSA_GET_GLOBAL_REF(env, obj) \ + cp_gtk_get_state (env, obj, cp_gtk_native_global_ref_table) + +#define NSA_SET_GLOBAL_REF(env, obj) \ + do {jobject *globRefPtr; \ + globRefPtr = (jobject *) malloc (sizeof (jobject)); \ + *globRefPtr = (*env)->NewGlobalRef (env, obj); \ + cp_gtk_set_state (env, obj, cp_gtk_native_global_ref_table, (void *)globRefPtr);} while (0) + +#define NSA_DEL_GLOBAL_REF(env, obj) \ + do {jobject *globRefPtr = cp_gtk_get_state (env, obj, cp_gtk_native_global_ref_table); \ + cp_gtk_remove_state_slot (env, obj, cp_gtk_native_global_ref_table); \ + (*env)->DeleteGlobalRef (env, *globRefPtr); \ + free (globRefPtr);} while (0) + +#define SWAPU32(w) \ + (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24)) + +struct graphics +{ + GdkDrawable *drawable; + GdkGC *gc; + GdkColormap *cm; + PangoFontDescription *pango_font; + PangoContext *pango_context; + PangoLayout *pango_layout; + jint x_offset, y_offset; +}; + +#define AWT_SHIFT_DOWN_MASK (1 << 6) +#define AWT_CTRL_DOWN_MASK (1 << 7) +#define AWT_META_DOWN_MASK (1 << 8) +#define AWT_ALT_DOWN_MASK (1 << 9) + +#define AWT_BUTTON1_MASK (1 << 4) +#define AWT_BUTTON2_MASK (1 << 3) +#define AWT_BUTTON3_MASK (1 << 2) + +#define AWT_ITEM_SELECTED 1 +#define AWT_ITEM_DESELECTED 2 + +#define AWT_KEY_TYPED 400 +#define AWT_KEY_PRESSED 401 +#define AWT_KEY_RELEASED 402 + +#define AWT_KEY_LOCATION_UNKNOWN 0 +#define AWT_KEY_LOCATION_STANDARD 1 +#define AWT_KEY_LOCATION_LEFT 2 +#define AWT_KEY_LOCATION_RIGHT 3 +#define AWT_KEY_LOCATION_NUMPAD 4 + +#define AWT_STYLE_PLAIN 0 +#define AWT_STYLE_BOLD 1 +#define AWT_STYLE_ITALIC 2 + +/* Used in GtkComponentPeer and GtkWindowPeer */ +#define VK_NUMPAD0 96 +#define VK_NUMPAD1 97 +#define VK_NUMPAD2 98 +#define VK_NUMPAD3 99 +#define VK_NUMPAD4 100 +#define VK_NUMPAD5 101 +#define VK_NUMPAD6 102 +#define VK_NUMPAD7 103 +#define VK_NUMPAD8 104 +#define VK_NUMPAD9 105 +#define VK_DECIMAL 110 + +JNIEnv *cp_gtk_gdk_env(void); + +/* Global variables */ +extern double cp_gtk_dpi_conversion_factor; +extern GtkWindowGroup *cp_gtk_global_window_group; + +/* Union used for type punning. */ +union widget_union +{ + void **void_widget; + GtkWidget **widget; +}; + +/* Keycode helpers */ +guint cp_gtk_awt_keycode_to_keysym (jint keyCode, jint keyLocation); + +/* Image helpers */ +GdkPixbuf *cp_gtk_image_get_pixbuf (JNIEnv *env, jobject obj); +GdkPixmap *cp_gtk_image_get_pixmap (JNIEnv *env, jobject obj); +jboolean cp_gtk_image_is_offscreen (JNIEnv *env, jobject obj); + +/* JNI initialization functions */ +#if GTK_CAIRO +void cp_gtk_graphics2d_init_jni (void); +#endif +void cp_gtk_graphics_init_jni (void); +void cp_gtk_button_init_jni (void); +void cp_gtk_checkbox_init_jni (void); +void cp_gtk_choice_init_jni (void); +void cp_gtk_component_init_jni (void); +void cp_gtk_list_init_jni (void); +void cp_gtk_menuitem_init_jni (void); +void cp_gtk_scrollbar_init_jni (void); +void cp_gtk_textcomponent_init_jni (void); +void cp_gtk_window_init_jni (void); + +/* Signal connection convience functions */ +void cp_gtk_component_connect_expose_signals (GObject *ptr, jobject *gref); +void cp_gtk_component_connect_focus_signals (GObject *ptr, jobject *gref); +void cp_gtk_component_connect_mouse_signals (GObject *ptr, jobject *gref); +void cp_gtk_component_connect_signals (GObject *ptr, jobject *gref); +void cp_gtk_textcomponent_connect_signals (GObject *ptr, jobject *gref); + +/* Debugging */ +void cp_gtk_print_current_thread (void); + +#define DEBUG_LOCKING 0 + +#if DEBUG_LOCKING +#define gdk_threads_enter() \ +{ \ + g_print ("locking: %s, %d\n", __FILE__, __LINE__); \ + cp_gtk_print_current_thread (); \ + gdk_threads_enter (); \ + g_print ("locked: %s, %d\n", __FILE__, __LINE__); \ + cp_gtk_print_current_thread (); \ +} +#define gdk_threads_leave() \ +{ \ + g_print ("unlocking: %s, %d\n", __FILE__, __LINE__); \ + cp_gtk_print_current_thread (); \ + gdk_threads_leave (); \ + g_print ("unlocked: %s, %d\n", __FILE__, __LINE__); \ + cp_gtk_print_current_thread (); \ +} +#endif + +#endif /* __GTKPEER_H */ diff --git a/libjava/classpath/native/jni/java-io/.cvsignore b/libjava/classpath/native/jni/java-io/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/java-io/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/java-io/Makefile.am b/libjava/classpath/native/jni/java-io/Makefile.am new file mode 100644 index 00000000000..5ed8a1baf4c --- /dev/null +++ b/libjava/classpath/native/jni/java-io/Makefile.am @@ -0,0 +1,13 @@ +pkglib_LTLIBRARIES = libjavaio.la + +libjavaio_la_SOURCES = javaio.h \ + javaio.c \ + java_io_VMFile.c \ + java_io_VMObjectInputStream.c \ + java_io_VMObjectStreamClass.c + +libjavaio_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/java-io/java_io_VMFile.c b/libjava/classpath/native/jni/java-io/java_io_VMFile.c new file mode 100644 index 00000000000..b32c29477e0 --- /dev/null +++ b/libjava/classpath/native/jni/java-io/java_io_VMFile.c @@ -0,0 +1,734 @@ +/* java_io_VMFile.c - Native methods for java.io.File class + Copyright (C) 1998, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <jni.h> +#include <jcl.h> + +#include "target_native.h" +#ifndef WITHOUT_FILESYSTEM +#include "target_native_file.h" +#endif +#include "target_native_math_int.h" + +#include "javaio.h" + +#include "java_io_VMFile.h" + +/*************************************************************************/ + +/* + * Method to create an empty file. + * + * Class: java_io_VMFile + * Method: create + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_create (JNIEnv * env, + jclass clazz __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int fd; + int result; + + filename = JCL_jstring_to_cstring (env, name); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_OPEN_CREATE (filename, fd, result); + if (result != TARGET_NATIVE_OK) + { + /* XXX ??? NYI */ + if (errno != EEXIST) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + JCL_free_cstring (env, name, filename); + return (0); + } + TARGET_NATIVE_FILE_CLOSE (fd, result); + + JCL_free_cstring (env, name, filename); + return (1); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method checks to see if we have read permission on a file. + * + * Class: java_io_VMFile + * Method: canRead + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_canRead (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int fd; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + /* The lazy man's way out. We actually do open the file for reading + briefly to verify it can be done */ + TARGET_NATIVE_FILE_OPEN_READ (filename, fd, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + if (result != TARGET_NATIVE_OK) + { + return (0); + } + TARGET_NATIVE_FILE_CLOSE (fd, result); + + return (1); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method checks to see if we have write permission on a file. + * + * Class: java_io_VMFile + * Method: canWrite + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_canWrite (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int fd; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + /* The lazy man's way out. We actually do open the file for writing + briefly to verify it can be done */ + TARGET_NATIVE_FILE_OPEN_READWRITE (filename, fd, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + if (result != TARGET_NATIVE_OK) + { + return (0); + } + TARGET_NATIVE_FILE_CLOSE (fd, result); + + return (1); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method makes a file read only. + * + * Class: java_io_VMFile + * Method: setReadOnly + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_setReadOnly (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_SET_MODE_READONLY (filename, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method checks to see if a file exists. + * + * Class: java_io_VMFile + * Method: exists + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_exists (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_EXISTS (filename, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method checks to see if a file is a "plain" file; that is, not + * a directory, pipe, etc. + * + * Class: java_io_VMFile + * Method: isFile + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_isFile (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_IS_FILE (filename, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method checks to see if a file is a directory or not. + * + * Class: java_io_VMFile + * Method: isDirectory + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_isDirectory (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_IS_DIRECTORY (filename, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method returns the length of the file. + * + * Class: java_io_VMFile + * Method: length + * Signature: (Ljava/lang/String;)J + */ + +JNIEXPORT jlong JNICALL +Java_java_io_VMFile_length (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int tmpfd; + jlong length; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); + } + + /* open file for reading, get size and close file */ + TARGET_NATIVE_FILE_OPEN_READ (filename, tmpfd, result); + if (result != TARGET_NATIVE_OK) + { + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); + } + TARGET_NATIVE_FILE_SIZE (tmpfd, length, result); + if (result != TARGET_NATIVE_OK) + { + TARGET_NATIVE_FILE_CLOSE (tmpfd, result); + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); + } + TARGET_NATIVE_FILE_CLOSE (tmpfd, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == + TARGET_NATIVE_OK) ? length : TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#else /* not WITHOUT_FILESYSTEM */ + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method returns the modification date of the file. + * + * Class: java_io_VMFile + * Method: lastModified + * Signature: (Ljava/lang/String;)J + */ + +JNIEXPORT jlong JNICALL +Java_java_io_VMFile_lastModified (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + jlong mtime; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); + } + + TARGET_NATIVE_FILE_GET_LAST_MODIFIED (filename, mtime, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == + TARGET_NATIVE_OK) ? mtime : TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#else /* not WITHOUT_FILESYSTEM */ + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method sets the modification date of the file. + * + * Class: java_io_VMFile + * Method: setLastModified + * Signature: (Ljava/lang/String;J)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_setLastModified (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name, jlong newtime) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_SET_LAST_MODIFIED (filename, newtime, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method deletes a file (actually a name for a file - additional + * links could exist). + * + * Class: java_io_VMFile + * Method: delete + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_delete (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + filename = (*env)->GetStringUTFChars (env, name, 0); + if (filename == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_DELETE (filename, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method creates a directory. + * + * Class: java_io_VMFile + * Method: mkdir + * Signature: (Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_mkdir (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *pathname; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + pathname = (*env)->GetStringUTFChars (env, name, 0); + if (pathname == NULL) + { + return (0); + } + + TARGET_NATIVE_FILE_MAKE_DIR (pathname, result); + (*env)->ReleaseStringUTFChars (env, name, pathname); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method renames a (link to a) file. + * + * Class: java_io_VMFile + * Method: renameTo + * Signature: (Ljava/lang/String;Ljava/lang/String;)Z + */ + +JNIEXPORT jboolean JNICALL +Java_java_io_VMFile_renameTo (JNIEnv * env, + jobject obj __attribute__ ((__unused__)), + jstring t, jstring d) +{ +#ifndef WITHOUT_FILESYSTEM + const char *old_filename, *new_filename; + int result; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + old_filename = (*env)->GetStringUTFChars (env, t, 0); + if (old_filename == NULL) + { + return (0); + } + + new_filename = (*env)->GetStringUTFChars (env, d, 0); + if (new_filename == NULL) + { + (*env)->ReleaseStringUTFChars (env, t, old_filename); + return (0); + } + + TARGET_NATIVE_FILE_RENAME (old_filename, new_filename, result); + (*env)->ReleaseStringUTFChars (env, d, new_filename); + (*env)->ReleaseStringUTFChars (env, t, old_filename); + + return ((result == TARGET_NATIVE_OK) ? 1 : 0); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * This method returns an array of String representing all the files + * in a directory except "." and "..". + * + * Class: java_io_VMFile + * Method: list + * Signature: (Ljava/lang/String;)[Ljava/lang/String; + */ + +JNIEXPORT jobjectArray JNICALL +Java_java_io_VMFile_list (JNIEnv * env, jobject obj + __attribute__ ((__unused__)), jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const int REALLOC_SIZE = 10; + + const char *dirname; + int result; + char **filelist; + void *handle; + const char *filename; + unsigned long int filelist_count, max_filelist_count; + char **tmp_filelist; + jclass str_clazz; + jobjectArray filearray; + unsigned long int i; + jstring str; + + /* Don't use the JCL convert function because it throws an exception + on failure */ + dirname = (*env)->GetStringUTFChars (env, name, 0); + if (dirname == NULL) + { + return (0); + } + + /* open directory for reading */ + TARGET_NATIVE_FILE_OPEN_DIR (dirname, handle, result); + + (*env)->ReleaseStringUTFChars (env, name, dirname); + + if (result != TARGET_NATIVE_OK) + { + return (0); + } + + /* allocate filelist */ + filelist = (char **) JCL_malloc (env, sizeof (char *) * REALLOC_SIZE); + if (filelist == NULL) + { + TARGET_NATIVE_FILE_CLOSE_DIR (handle, result); + return (0); + } + filelist_count = 0; + max_filelist_count = REALLOC_SIZE; + + /* read the files from the directory */ + TARGET_NATIVE_FILE_READ_DIR (handle, filename, result); + while (result == TARGET_NATIVE_OK) + { + if ((strcmp (filename, ".") != 0) && (strcmp (filename, "..") != 0)) + { + /* allocate more memory if necessary */ + if (filelist_count >= max_filelist_count) + { + tmp_filelist = (char **) JCL_realloc (env, + filelist, + (max_filelist_count + + REALLOC_SIZE) * + sizeof (char *)); + if (tmp_filelist == NULL) + { + for (i = 0; i < filelist_count; i++) + { + JCL_free (env, filelist[i]); + } + JCL_free (env, filelist); + TARGET_NATIVE_FILE_CLOSE_DIR (handle, result); + return (0); + } + filelist = tmp_filelist; + max_filelist_count += REALLOC_SIZE; + } + + /* save entry in list (avoid strdup, because it is not ANSI C, thus difficult to port) */ + filelist[filelist_count] = + (char *) JCL_malloc (env, strlen (filename) + 1); + assert (filelist[filelist_count] != NULL); + strcpy (filelist[filelist_count], filename); + filelist_count++; + } + + /* read next directory entry */ + TARGET_NATIVE_FILE_READ_DIR (handle, filename, result); + } + + /* close directory */ + TARGET_NATIVE_FILE_CLOSE_DIR (handle, result); + + /* put the list of files into a Java String array and return it */ + str_clazz = (*env)->FindClass (env, "java/lang/String"); + if (str_clazz == NULL) + { + for (i = 0; i < filelist_count; i++) + { + JCL_free (env, filelist[i]); + } + JCL_free (env, filelist); + return (0); + } + filearray = (*env)->NewObjectArray (env, filelist_count, str_clazz, 0); + if (filearray == NULL) + { + for (i = 0; i < filelist_count; i++) + { + JCL_free (env, filelist[i]); + } + JCL_free (env, filelist); + return (0); + } + for (i = 0; i < filelist_count; i++) + { + /* create new string */ + str = (*env)->NewStringUTF (env, filelist[i]); + if (str == NULL) + { + /* We don't clean up everything here, but if this failed, + something serious happened anyway */ + for (i = 0; i < filelist_count; i++) + { + JCL_free (env, filelist[i]); + } + JCL_free (env, filelist); + return (0); + } + + /* save into array */ + (*env)->SetObjectArrayElement (env, filearray, i, str); + + /* delete local reference */ + (*env)->DeleteLocalRef (env, str); + } + + /* free resources */ + for (i = 0; i < filelist_count; i++) + { + JCL_free (env, filelist[i]); + } + JCL_free (env, filelist); + + return (filearray); +#else /* not WITHOUT_FILESYSTEM */ + return (0); +#endif /* not WITHOUT_FILESYSTEM */ +} diff --git a/libjava/classpath/native/jni/java-io/java_io_VMObjectInputStream.c b/libjava/classpath/native/jni/java-io/java_io_VMObjectInputStream.c new file mode 100644 index 00000000000..d8d80714989 --- /dev/null +++ b/libjava/classpath/native/jni/java-io/java_io_VMObjectInputStream.c @@ -0,0 +1,69 @@ +/* java_io_VMObjectInputStream.c -- Native methods for ObjectInputStream class + Copyright (C) 1998, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + + +/* TODO: check exceptions */ +/* comments */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <jni.h> +#include <jcl.h> + +#include "java_io_VMObjectInputStream.h" + +/* + * Class: java_io_VMObjectInputStream + * Method: allocateObject + * Signature: (Ljava/lang/Class;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL +Java_java_io_VMObjectInputStream_allocateObject (JNIEnv * env, + jclass clazz + __attribute__((__unused__)), + jclass target_clazz, + jclass constr_clazz, + jobject constructor) +{ + jobject obj = (*env)->AllocObject (env, target_clazz); + jmethodID id = (*env)->FromReflectedMethod (env, constructor); + + (*env)->CallNonvirtualVoidMethod (env, obj, constr_clazz, id); + + return obj; +} diff --git a/libjava/classpath/native/jni/java-io/java_io_VMObjectStreamClass.c b/libjava/classpath/native/jni/java-io/java_io_VMObjectStreamClass.c new file mode 100644 index 00000000000..8c2556bcf30 --- /dev/null +++ b/libjava/classpath/native/jni/java-io/java_io_VMObjectStreamClass.c @@ -0,0 +1,381 @@ +/* java_io_VMObjectStreamClass.c -- Native methods for VMObjectStreamClass.java + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <jcl.h> + +#include <stdlib.h> +#include <string.h> + +#include "java_io_VMObjectStreamClass.h" + +/* + * Class: java_io_VMObjectOutputStream + * Method: hasClassInitializer + * Signature: (Ljava/lang/Class;)Z + */ +JNIEXPORT jboolean JNICALL +Java_java_io_VMObjectStreamClass_hasClassInitializer (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), jclass klass) +{ + jmethodID mid = (*env)->GetStaticMethodID (env, klass, "<clinit>", "()V"); + if (mid == NULL) + { + (*env)->ExceptionClear (env); + return JNI_FALSE; + } + return JNI_TRUE; +} + +static void +throwInternalError (JNIEnv * env) +{ + jclass internalErrorClass; + jthrowable previousException, newException; + jmethodID initException, getMessageID, initCauseID; + jstring message; + + internalErrorClass = (*env)->FindClass (env, "java/lang/InternalError"); + /** Just give up if this also fails. */ + if (internalErrorClass == NULL) + return; + + previousException = (*env)->ExceptionOccurred (env); + + if (previousException == NULL) + { + (*env)->ThrowNew (env, internalErrorClass, + "Unknown error raised by the VM"); + return; + } + + initException = (*env)->GetMethodID + (env, internalErrorClass, "<init>", "(Ljava/lang/String;)V"); + getMessageID = (*env)->GetMethodID + (env, (*env)->GetObjectClass (env, previousException), + "getMessage", "()Ljava/lang/String;"); + initCauseID = (*env)->GetMethodID + (env, internalErrorClass, "initCause", "(Ljava/lang/Throwable;)V"); + + message = (*env)->CallObjectMethod (env, previousException, getMessageID); + + newException = (*env)->NewObject (env, internalErrorClass, initException, + message); + (*env)->CallVoidMethod (env, newException, initCauseID, previousException); + + (*env)->ExceptionClear (env); + (*env)->Throw (env, newException); +} + +static jfieldID +getFieldReference (JNIEnv * env, jobject field, const char *type) +{ + jclass classClass; + jclass fieldClass; + jclass declaringClass; + jclass typeClass; + jfieldID fid; + const char *field_name; + const char *type_name; + int type_len; + jmethodID mid; + jstring name; + jstring tname; + int i; + + fieldClass = (*env)->GetObjectClass (env, field); + + mid = + (*env)->GetMethodID (env, fieldClass, "getName", "()Ljava/lang/String;"); + if (mid == NULL || (*env)->ExceptionOccurred (env) != NULL) + { + throwInternalError (env); + return NULL; + } + + name = (*env)->CallObjectMethod (env, field, mid); + field_name = (*env)->GetStringUTFChars (env, name, NULL); + + mid = (*env)->GetMethodID (env, fieldClass, + "getDeclaringClass", "()Ljava/lang/Class;"); + if (mid == NULL || (*env)->ExceptionOccurred (env) != NULL) + { + throwInternalError (env); + return NULL; + } + + declaringClass = (*env)->CallObjectMethod (env, field, mid); + + /* Do we need to find out the exact type descriptor of the field? */ + if (type == NULL) + { + char *the_type; + + mid = (*env)->GetMethodID (env, fieldClass, + "getType", "()Ljava/lang/Class;"); + + if (mid == NULL || (*env)->ExceptionOccurred (env) != NULL) + { + throwInternalError (env); + return NULL; + } + + typeClass = (*env)->CallObjectMethod (env, field, mid); + classClass = (*env)->FindClass (env, "java/lang/Class"); + + mid = (*env)->GetMethodID (env, classClass, + "getName", "()Ljava/lang/String;"); + + if (mid == NULL || (*env)->ExceptionOccurred (env) != NULL) + { + throwInternalError (env); + return NULL; + } + + tname = (*env)->CallObjectMethod (env, typeClass, mid); + type_name = (*env)->GetStringUTFChars (env, tname, NULL); + + /* + * If it isn't an array class then the actual field type descriptor + * starts with 'L', ends with ';' and has '/' instead of '.'. + */ + type_len = strlen ((char *) type_name); + if (type_name[0] != '[') + { + /* XXX - FIXME - should not use dynamic allocation in core lib. */ + the_type = (char *) malloc (type_len + 3); + the_type[0] = 'L'; + the_type[type_len + 1] = ';'; + the_type[type_len + 2] = '\0'; + the_type++; + } + else + { + /* XXX - FIXME - should not use dynamic allocation in core lib. */ + the_type = (char *) malloc (type_len + 1); + the_type[type_len] = '\0'; + } + + for (i = 0; i < type_len; i++) + if (type_name[i] == '.') + the_type[i] = '/'; + else + the_type[i] = type_name[i]; + + if (type_name[0] != '[') + the_type--; + + (*env)->ReleaseStringUTFChars (env, tname, type_name); + fid = (*env)->GetFieldID (env, declaringClass, field_name, the_type); + free (the_type); + } + else + { + type_len = -1; + fid = (*env)->GetFieldID (env, declaringClass, field_name, type); + } + + if (fid == NULL) + { + throwInternalError (env); + return NULL; + } + (*env)->ReleaseStringUTFChars (env, name, field_name); + + return fid; +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setBooleanNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;Z)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setBooleanNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), jobject field, jobject object, jboolean value) +{ + jfieldID fid = getFieldReference (env, field, "Z"); + + if (fid != NULL) + (*env)->SetBooleanField (env, object, fid, value); +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setCharNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;C)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setCharNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jchar value) +{ + jfieldID fid = getFieldReference (env, field, "C"); + + if (fid != NULL) + (*env)->SetCharField (env, object, fid, value); +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setByteNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;B)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setByteNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jbyte value) +{ + jfieldID fid = getFieldReference (env, field, "B"); + + if (fid != NULL) + (*env)->SetByteField (env, object, fid, value); +} + + +/* + * Class: java_io_VMObjectOutputStream + * Method: setShortNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;S)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setShortNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jshort value) +{ + jfieldID fid = getFieldReference (env, field, "S"); + + if (fid != NULL) + (*env)->SetShortField (env, object, fid, value); +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setIntNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;I)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setIntNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jint value) +{ + jfieldID fid = getFieldReference (env, field, "I"); + + if (fid != NULL) + (*env)->SetIntField (env, object, fid, value); +} + + +/* + * Class: java_io_VMObjectOutputStream + * Method: setLongNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;J)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setLongNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jlong value) +{ + jfieldID fid = getFieldReference (env, field, "J"); + + if (fid != NULL) + (*env)->SetLongField (env, object, fid, value); +} + + +/* + * Class: java_io_VMObjectOutputStream + * Method: setFloatNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;F)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setFloatNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), + jobject field, + jobject object, jfloat value) +{ + jfieldID fid = getFieldReference (env, field, "F"); + + if (fid != NULL) + (*env)->SetFloatField (env, object, fid, value); +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setDoubleNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;D)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setDoubleNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), jobject field, jobject object, jdouble value) +{ + jfieldID fid = getFieldReference (env, field, "D"); + + if (fid != NULL) + (*env)->SetDoubleField (env, object, fid, value); +} + +/* + * Class: java_io_VMObjectOutputStream + * Method: setObjectNative + * Signature: (Ljava/lang/reflect/Field;Ljava/lang/Object;Ljava/lang/Object;)V + */ +JNIEXPORT void JNICALL +Java_java_io_VMObjectStreamClass_setObjectNative (JNIEnv * env, + jclass vmosklass + __attribute__ ((__unused__)), jobject field, jobject object, jobject value) +{ + jfieldID fid = getFieldReference (env, field, NULL); + + if (fid != NULL) + (*env)->SetObjectField (env, object, fid, value); +} diff --git a/libjava/classpath/native/jni/java-io/javaio.c b/libjava/classpath/native/jni/java-io/javaio.c new file mode 100644 index 00000000000..6dc3de8f041 --- /dev/null +++ b/libjava/classpath/native/jni/java-io/javaio.c @@ -0,0 +1,363 @@ +/* javaio.c - Common java.io native functions + Copyright (C) 1998, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <jni.h> +#include <jcl.h> + +#include "target_native.h" +#ifndef WITHOUT_FILESYSTEM +#include "target_native_file.h" +#endif +#include "target_native_math_int.h" + +#include "javaio.h" + +/* + * Function to open a file + */ + +jint +_javaio_open_read (JNIEnv * env, jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int fd; + int result; + + filename = JCL_jstring_to_cstring (env, name); + if (filename == NULL) + return (-1); + + TARGET_NATIVE_FILE_OPEN_READ (filename, fd, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + if (result != TARGET_NATIVE_OK) + { + if (TARGET_NATIVE_LAST_ERROR () == TARGET_NATIVE_ERROR_NO_SUCH_FILE) + JCL_ThrowException (env, + "java/io/FileNotFoundException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + else + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + } + + JCL_free_cstring (env, name, filename); + return (fd); +#else /* not WITHOUT_FILESYSTEM */ + return (-1); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/* + * Function to open a file for reading/writing + */ + +jint +_javaio_open_readwrite (JNIEnv * env, jstring name) +{ +#ifndef WITHOUT_FILESYSTEM + const char *filename; + int fd; + int result; + + filename = JCL_jstring_to_cstring (env, name); + if (filename == NULL) + return (-1); + + TARGET_NATIVE_FILE_OPEN_READWRITE (filename, fd, result); + (*env)->ReleaseStringUTFChars (env, name, filename); + if (result != TARGET_NATIVE_OK) + { + if (TARGET_NATIVE_LAST_ERROR () == TARGET_NATIVE_ERROR_NO_SUCH_FILE) + JCL_ThrowException (env, + "java/io/FileNotFoundException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + else + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + } + + JCL_free_cstring (env, name, filename); + return (fd); +#else /* not WITHOUT_FILESYSTEM */ + return (-1); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * Function to close a file + */ + +void +_javaio_close (JNIEnv * env, jint fd) +{ +#ifndef WITHOUT_FILESYSTEM + int result; + + if (fd != -1) + { + TARGET_NATIVE_FILE_CLOSE (fd, result); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + } +#else /* not WITHOUT_FILESYSTEM */ +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * Skips bytes in a file + */ + +jlong +_javaio_skip_bytes (JNIEnv * env, jint fd, jlong num_bytes) +{ +#ifndef WITHOUT_FILESYSTEM + jlong current_offset, new_offset; + int result; + + TARGET_NATIVE_FILE_SEEK_CURRENT (fd, TARGET_NATIVE_MATH_INT_INT64_CONST_0, + current_offset, result); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + TARGET_NATIVE_FILE_SEEK_CURRENT (fd, num_bytes, new_offset, result); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + return (TARGET_NATIVE_MATH_INT_INT64_SUB (new_offset, current_offset)); +#else /* not WITHOUT_FILESYSTEM */ + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * Gets the size of the file + */ + +jlong +_javaio_get_file_length (JNIEnv * env, jint fd) +{ +#ifndef WITHOUT_FILESYSTEM + jlong length; + int result; + + TARGET_NATIVE_FILE_SIZE (fd, length, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (TARGET_NATIVE_MATH_INT_INT64_CONST_MINUS_1); + } + + return (length); +#else /* not WITHOUT_FILESYSTEM */ + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * Reads data from a file + */ + +jint +_javaio_read (JNIEnv * env, jint fd, jarray buf, jint offset, jint len) +{ +#ifndef WITHOUT_FILESYSTEM + jbyte *bufptr; + int bytesRead; + int result; + + assert (offset >= 0); + assert (len >= 0); + + if (len == 0) + return 0; /* Nothing todo, and GetByteArrayElements() seems undefined. */ + + bufptr = (*env)->GetByteArrayElements (env, buf, JNI_FALSE); + if (bufptr == NULL) + { + JCL_ThrowException (env, "java/io/IOException", + "Internal Error: get byte array fail"); + return (-1); + } + + TARGET_NATIVE_FILE_READ (fd, (bufptr + offset), len, bytesRead, result); + (*env)->ReleaseByteArrayElements (env, buf, bufptr, 0); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + if (bytesRead == 0) + return (-1); + + return (bytesRead); +#else /* not WITHOUT_FILESYSTEM */ + jbyte *bufptr; + int bytesRead; + + assert (offset >= 0); + assert (len >= 0); + + if ((fd == 0) || (fd == 1) || (fd == 2)) + { + if (len == 0) + return 0; /* Nothing todo, and GetByteArrayElements() seems undefined. */ + + bufptr = (*env)->GetByteArrayElements (env, buf, JNI_FALSE); + if (bufptr == NULL) + { + JCL_ThrowException (env, "java/io/IOException", + "Internal Error: get byte array"); + return (-1); + } + + TARGET_NATIVE_FILE_READ (fd, (bufptr + offset), len, bytesRead, result); + (*env)->ReleaseByteArrayElements (env, buf, bufptr, 0); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + if (bytesRead == 0) + return (-1); + + return (bytesRead); + } + else + { + return (-1); + } +#endif /* not WITHOUT_FILESYSTEM */ +} + +/*************************************************************************/ + +/* + * Writes data to a file + */ + +jint +_javaio_write (JNIEnv * env, jint fd, jarray buf, jint offset, jint len) +{ +#ifndef WITHOUT_FILESYSTEM + jbyte *bufptr; + int bytes_written; + int result; + + if (len == 0) + return 0; /* Nothing todo, and GetByteArrayElements() seems undefined. */ + + bufptr = (*env)->GetByteArrayElements (env, buf, 0); + if (bufptr == NULL) + { + JCL_ThrowException (env, "java/io/IOException", + "Internal Error: get byte array"); + return (-1); + } + + TARGET_NATIVE_FILE_WRITE (fd, (bufptr + offset), len, bytes_written, + result); + (*env)->ReleaseByteArrayElements (env, buf, bufptr, 0); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + if (bytes_written == 0) + return (-1); + + return (bytes_written); +#else /* not WITHOUT_FILESYSTEM */ + jbyte *bufptr; + int bytesWritten; + + if ((fd == 0) || (fd == 1) || (fd == 2)) + { + if (len == 0) + return 0; /* Nothing todo, and GetByteArrayElements() seems undefined. */ + + bufptr = (*env)->GetByteArrayElements (env, buf, 0); + if (bufptr == NULL) + { + JCL_ThrowException (env, "java/io/IOException", "Internal Error"); + return (-1); + } + + TARGET_NATIVE_FILE_WRITE (fd, (bufptr + offset), len, bytes_written, + result); + (*env)->ReleaseByteArrayElements (env, buf, bufptr, 0); + + if (bytes_written == -1) + JCL_ThrowException (env, + "java/io/IOException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + + if (bytes_written == 0) + return (-1); + + return (bytes_written); + } + else + { + return (-1); + } +#endif /* not WITHOUT_FILESYSTEM */ +} diff --git a/libjava/classpath/native/jni/java-io/javaio.h b/libjava/classpath/native/jni/java-io/javaio.h new file mode 100644 index 00000000000..2e4a8d1037f --- /dev/null +++ b/libjava/classpath/native/jni/java-io/javaio.h @@ -0,0 +1,58 @@ +/* javaio.h - Declaration for common java.io native functions + Copyright (C) 1998, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + + +#ifndef JAVAIO_H_INCLUDED +#define JAVAIO_H_INCLUDED + +#include <stddef.h> + +/* + * Function Prototypes + */ + +extern jlong _javaio_get_file_length(JNIEnv *, jint); +extern jlong _javaio_skip_bytes(JNIEnv *, jint, jlong); +extern jint _javaio_open(JNIEnv *, jstring, int); +extern jint _javaio_open_read(JNIEnv *, jstring); +extern jint _javaio_open_readwrite(JNIEnv *, jstring); +extern void _javaio_close(JNIEnv *, jint fd); +extern jint _javaio_read(JNIEnv *, jint, jarray, jint, jint); +extern jint _javaio_write(JNIEnv *, jint, jarray, jint, jint); + +#endif /* JAVAIO_H_INCLUDED */ + diff --git a/libjava/classpath/native/jni/java-lang/.cvsignore b/libjava/classpath/native/jni/java-lang/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/java-lang/Makefile.am b/libjava/classpath/native/jni/java-lang/Makefile.am new file mode 100644 index 00000000000..34ffe00fba7 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/Makefile.am @@ -0,0 +1,16 @@ +pkglib_LTLIBRARIES = libjavalang.la libjavalangreflect.la + +libjavalang_la_SOURCES = java_lang_VMSystem.c \ + java_lang_VMFloat.c \ + java_lang_VMDouble.c \ + java_lang_Math.c \ + java_lang_VMProcess.c + +libjavalang_la_LIBADD = $(wildcard $(top_builddir)/native/fdlibm/*.lo) \ + $(top_builddir)/native/jni/classpath/jcl.lo + +libjavalangreflect_la_SOURCES = java_lang_reflect_Array.c + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ -I$(top_srcdir)/native/fdlibm +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/java-lang/java_lang_Math.c b/libjava/classpath/native/jni/java-lang/java_lang_Math.c new file mode 100644 index 00000000000..b4b88a77537 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_Math.c @@ -0,0 +1,161 @@ +/* Math.c - java.lang.Math native functions + Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <java_lang_Math.h> +#include <fdlibm.h> + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_sin + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return sin (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_cos + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return cos (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_tan + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return tan (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_asin + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return asin (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_acos + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return acos (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_atan + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return atan (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_atan2 + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble y, jdouble x) +{ + return atan2 (y, x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_exp + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return exp (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_log + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return log (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_sqrt + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return sqrt (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_pow + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x, jdouble y) +{ + return pow (x, y); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_IEEEremainder + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x, jdouble y) +{ + return remainder (x, y); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_ceil + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return ceil (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_floor + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return floor (x); +} + +JNIEXPORT jdouble JNICALL +Java_java_lang_Math_rint + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble x) +{ + return rint (x); +} diff --git a/libjava/classpath/native/jni/java-lang/java_lang_VMDouble.c b/libjava/classpath/native/jni/java-lang/java_lang_VMDouble.c new file mode 100644 index 00000000000..6b4aed42d27 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_VMDouble.c @@ -0,0 +1,381 @@ +/* VMDouble.c - java.lang.VMDouble native functions + Copyright (C) 1998, 1999, 2001, 2003, 2004i, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "mprec.h" +#include "fdlibm.h" +#include "jcl.h" + +#include "java_lang_VMDouble.h" + +static jclass clsDouble; +static jmethodID isNaNID; +static jdouble NEGATIVE_INFINITY; +static jdouble POSITIVE_INFINITY; +static jdouble NaN; + +/* + * Class: java_lang_VMDouble + * Method: initIDs + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_java_lang_VMDouble_initIDs (JNIEnv * env, jclass cls __attribute__ ((__unused__))) +{ + jfieldID negInfID; + jfieldID posInfID; + jfieldID nanID; + + clsDouble = (*env)->FindClass (env, "java/lang/Double"); + if (clsDouble == NULL) + { + DBG ("unable to get class java.lang.Double\n") return; + } + isNaNID = (*env)->GetStaticMethodID (env, clsDouble, "isNaN", "(D)Z"); + if (isNaNID == NULL) + { + DBG ("unable to determine method id of isNaN\n") return; + } + negInfID = (*env)->GetStaticFieldID (env, clsDouble, "NEGATIVE_INFINITY", "D"); + if (negInfID == NULL) + { + DBG ("unable to determine field id of NEGATIVE_INFINITY\n") return; + } + posInfID = (*env)->GetStaticFieldID (env, clsDouble, "POSITIVE_INFINITY", "D"); + if (posInfID == NULL) + { + DBG ("unable to determine field id of POSITIVE_INFINITY\n") return; + } + nanID = (*env)->GetStaticFieldID (env, clsDouble, "NaN", "D"); + if (posInfID == NULL) + { + DBG ("unable to determine field id of NaN\n") return; + } + POSITIVE_INFINITY = (*env)->GetStaticDoubleField (env, clsDouble, posInfID); + NEGATIVE_INFINITY = (*env)->GetStaticDoubleField (env, clsDouble, negInfID); + NaN = (*env)->GetStaticDoubleField (env, clsDouble, nanID); + +#ifdef DEBUG + fprintf (stderr, "java.lang.Double.initIDs() POSITIVE_INFINITY = %g\n", + POSITIVE_INFINITY); + fprintf (stderr, "java.lang.Double.initIDs() NEGATIVE_INFINITY = %g\n", + NEGATIVE_INFINITY); + fprintf (stderr, "java.lang.Double.initIDs() NaN = %g\n", NaN); +#endif +} + +/* + * Class: java_lang_VMDouble + * Method: doubleToLongBits + * Signature: (D)J + */ +JNIEXPORT jlong JNICALL +Java_java_lang_VMDouble_doubleToLongBits + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble doubleValue) +{ + jvalue val; + jlong e, f; + val.d = doubleValue; + + e = val.j & 0x7ff0000000000000LL; + f = val.j & 0x000fffffffffffffLL; + + if (e == 0x7ff0000000000000LL && f != 0L) + val.j = 0x7ff8000000000000LL; + + return val.j; +} + +/* + * Class: java_lang_VMDouble + * Method: doubleToRawLongBits + * Signature: (D)J + */ +JNIEXPORT jlong JNICALL +Java_java_lang_VMDouble_doubleToRawLongBits + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jdouble doubleValue) +{ + jvalue val; + val.d = doubleValue; + return val.j; +} + +/* + * Class: java_lang_VMDouble + * Method: longBitsToDouble + * Signature: (J)D + */ +JNIEXPORT jdouble JNICALL +Java_java_lang_VMDouble_longBitsToDouble + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jlong longValue) +{ + jvalue val; + val.j = longValue; + return val.d; +} + +/* + * Class: java_lang_VMDouble + * Method: toString + * Signature: (DZ)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_java_lang_VMDouble_toString + (JNIEnv * env, jclass cls __attribute__ ((__unused__)), jdouble value, jboolean isFloat) +{ + char buffer[50], result[50]; + int decpt, sign; + char *s, *d; + int i; + +#ifdef DEBUG + fprintf (stderr, "java.lang.VMDouble.toString (%g)\n", value); +#endif + + if ((*env)->CallStaticBooleanMethod (env, clsDouble, isNaNID, value)) + return (*env)->NewStringUTF (env, "NaN"); + + if (value == POSITIVE_INFINITY) + return (*env)->NewStringUTF (env, "Infinity"); + + if (value == NEGATIVE_INFINITY) + return (*env)->NewStringUTF (env, "-Infinity"); + + _dtoa (value, 0, 20, &decpt, &sign, NULL, buffer, (int) isFloat); + + value = fabs (value); + + s = buffer; + d = result; + + if (sign) + *d++ = '-'; + + if ((value >= 1e-3 && value < 1e7) || (value == 0)) + { + if (decpt <= 0) + *d++ = '0'; + else + { + for (i = 0; i < decpt; i++) + if (*s) + *d++ = *s++; + else + *d++ = '0'; + } + + *d++ = '.'; + + if (*s == 0) + { + *d++ = '0'; + decpt++; + } + + while (decpt++ < 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d = 0; + + return (*env)->NewStringUTF (env, result); + } + + *d++ = *s++; + decpt--; + *d++ = '.'; + + if (*s == 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d++ = 'E'; + + if (decpt < 0) + { + *d++ = '-'; + decpt = -decpt; + } + + { + char exp[4]; + char *e = exp + sizeof exp; + + *--e = 0; + do + { + *--e = '0' + decpt % 10; + decpt /= 10; + } + while (decpt > 0); + + while (*e) + *d++ = *e++; + } + + *d = 0; + + return (*env)->NewStringUTF (env, result); +} + +/* + * Class: java_lang_VMDouble + * Method: parseDouble + * Signature: (Ljava/lang/String;)D + */ +JNIEXPORT jdouble JNICALL +Java_java_lang_VMDouble_parseDouble + (JNIEnv * env, jclass cls __attribute__ ((__unused__)), jstring str) +{ + jboolean isCopy; + const char *buf; + char *endptr; + jdouble val = 0.0; + + if (str == NULL) + { + JCL_ThrowException (env, "java/lang/NullPointerException", "null"); + return val; + } + + buf = (char *) (*env)->GetStringUTFChars (env, str, &isCopy); + if (buf == NULL) + { + /* OutOfMemoryError already thrown */ + } + else + { + const char *p = buf, *end, *last_non_ws, *temp; + int ok = 1; + +#ifdef DEBUG + fprintf (stderr, "java.lang.VMDouble.parseDouble (%s)\n", buf); +#endif + + /* Trim the buffer, similar to String.trim(). First the leading + characters. */ + while (*p && *p <= ' ') + ++p; + + /* Find the last non-whitespace character. This method is safe + even with multi-byte UTF-8 characters. */ + end = p; + last_non_ws = NULL; + while (*end) + { + if (*end > ' ') + last_non_ws = end; + ++end; + } + + if (last_non_ws == NULL) + last_non_ws = p + strlen (p); + else + { + /* Skip past the last non-whitespace character. */ + ++last_non_ws; + } + + /* Check for infinity and NaN */ + temp = p; + if (temp[0] == '+' || temp[0] == '-') + temp++; + if (strncmp ("Infinity", temp, (size_t) 8) == 0) + { + if (p[0] == '-') + return NEGATIVE_INFINITY; + return POSITIVE_INFINITY; + } + if (strncmp ("NaN", temp, (size_t) 3) == 0) + return NaN; + + /* Skip a trailing `f' or `d'. */ + if (last_non_ws > p + && (last_non_ws[-1] == 'f' + || last_non_ws[-1] == 'F' + || last_non_ws[-1] == 'd' || last_non_ws[-1] == 'D')) + --last_non_ws; + + if (last_non_ws > p) + { + struct _Jv_reent reent; + memset (&reent, 0, sizeof reent); + +#ifdef KISSME_LINUX_USER + /* FIXME: The libc strtod may not be reliable. */ + val = strtod (p, &endptr); +#else + val = _strtod_r (&reent, p, &endptr); +#endif + +#ifdef DEBUG + fprintf (stderr, "java.lang.VMDouble.parseDouble val = %g\n", val); + fprintf (stderr, "java.lang.VMDouble.parseDouble %i != %i ???\n", + endptr, last_non_ws); +#endif + if (endptr != last_non_ws) + ok = 0; + } + else + ok = 0; + + if (!ok) + { + val = 0.0; + JCL_ThrowException (env, + "java/lang/NumberFormatException", + "unable to parse double"); + } + + (*env)->ReleaseStringUTFChars (env, str, buf); + } + + return val; +} diff --git a/libjava/classpath/native/jni/java-lang/java_lang_VMFloat.c b/libjava/classpath/native/jni/java-lang/java_lang_VMFloat.c new file mode 100644 index 00000000000..7bff629fc89 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_VMFloat.c @@ -0,0 +1,93 @@ +/* VMFloat.c - java.lang.VMFloat native functions + Copyright (C) 1998, 1999, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> + +#include "java_lang_VMFloat.h" + +/* + * Class: java_lang_VMFloat + * Method: floatToIntBits + * Signature: (F)I + */ +JNIEXPORT jint JNICALL +Java_java_lang_VMFloat_floatToIntBits + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jfloat value) +{ + jvalue u; + jint e, f; + u.f = value; + e = u.i & 0x7f800000; + f = u.i & 0x007fffff; + + if (e == 0x7f800000 && f != 0) + u.i = 0x7fc00000; + + return u.i; +} + +/* + * Class: java_lang_VMFloat + * Method: floatToRawIntBits + * Signature: (F)I + */ +JNIEXPORT jint JNICALL +Java_java_lang_VMFloat_floatToRawIntBits + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jfloat value) +{ + jvalue u; + u.f = value; + return u.i; +} + +/* + * Class: java_lang_VMFloat + * Method: intBitsToFloat + * Signature: (I)F + */ +JNIEXPORT jfloat JNICALL +Java_java_lang_VMFloat_intBitsToFloat + (JNIEnv * env __attribute__ ((__unused__)), + jclass cls __attribute__ ((__unused__)), jint bits) +{ + jvalue u; + u.i = bits; + return u.f; +} diff --git a/libjava/classpath/native/jni/java-lang/java_lang_VMProcess.c b/libjava/classpath/native/jni/java-lang/java_lang_VMProcess.c new file mode 100644 index 00000000000..c1090ed3736 --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_VMProcess.c @@ -0,0 +1,494 @@ +/* java_lang_VMProcess.c -- native code for java.lang.VMProcess + Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> + +#include "java_lang_VMProcess.h" +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> + +#include "target_native.h" +#include "target_native_misc.h" + +/* Internal functions */ +static char *copy_string (JNIEnv * env, jobject string); +static char *copy_elem (JNIEnv * env, jobject stringArray, jint i); + +/* Some O/S's don't declare 'environ' */ +#if HAVE_CRT_EXTERNS_H +/* Darwin does not have a variable named environ + but has a function which you can get the environ + variable with. */ +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif /* HAVE_CRT_EXTERNS_H */ + +/* + * Internal helper function to copy a String in UTF-8 format. + */ +static char * +copy_string (JNIEnv * env, jobject string) +{ + char errbuf[64]; + const char *utf; + jclass clazz; + char *copy; + + /* Check for null */ + if (string == NULL) + { + clazz = (*env)->FindClass (env, "java/lang/NullPointerException"); + if ((*env)->ExceptionOccurred (env)) + return NULL; + (*env)->ThrowNew (env, clazz, NULL); + (*env)->DeleteLocalRef (env, clazz); + return NULL; + } + + /* Extract UTF-8 */ + utf = (*env)->GetStringUTFChars (env, string, NULL); + if ((*env)->ExceptionOccurred (env)) + return NULL; + + /* Copy it */ + if ((copy = strdup (utf)) == NULL) + { + TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf, sizeof (errbuf), + "strdup: %s", strerror (errno)); + clazz = (*env)->FindClass (env, "java/lang/InternalError"); + if ((*env)->ExceptionOccurred (env)) + return NULL; + (*env)->ThrowNew (env, clazz, errbuf); + (*env)->DeleteLocalRef (env, clazz); + } + + /* Done */ + (*env)->ReleaseStringUTFChars (env, string, utf); + return copy; +} + +/* + * Internal helper function to copy a String[] element in UTF-8 format. + */ +static char * +copy_elem (JNIEnv * env, jobject stringArray, jint i) +{ + jobject elem; + char *rtn; + + elem = (*env)->GetObjectArrayElement (env, stringArray, i); + if ((*env)->ExceptionOccurred (env)) + return NULL; + if ((rtn = copy_string (env, elem)) == NULL) + return NULL; + (*env)->DeleteLocalRef (env, elem); + return rtn; +} + +/* + * private final native void nativeSpawn(String[], String[], File) + * throws java/io/IOException + */ +JNIEXPORT void JNICALL +Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this, + jobjectArray cmdArray, + jobjectArray envArray, jobject dirFile) +{ + int fds[3][2] = { {-1, -1}, {-1, -1}, {-1, -1} }; + jobject streams[3] = { NULL, NULL, NULL }; + jobject dirString = NULL; + char **newEnviron = NULL; + jsize cmdArrayLen = 0; + jsize envArrayLen = 0; + char **strings = NULL; + int num_strings = 0; + char *dir = NULL; + pid_t pid = -1; + char errbuf[64]; + jmethodID method; + jclass clazz; + int i; + + /* Check for null */ + if (cmdArray == NULL) + goto null_pointer_exception; + + /* Invoke dirFile.getPath() */ + if (dirFile != NULL) + { + clazz = (*env)->FindClass (env, "java/io/File"); + if ((*env)->ExceptionOccurred (env)) + return; + method = (*env)->GetMethodID (env, + clazz, "getPath", "()Ljava/lang/String;"); + if ((*env)->ExceptionOccurred (env)) + return; + dirString = (*env)->CallObjectMethod (env, dirFile, method); + if ((*env)->ExceptionOccurred (env)) + return; + (*env)->DeleteLocalRef (env, clazz); + } + + /* + * Allocate array of C strings. We put all the C strings we need to + * handle the command parameters, the new environment, and the new + * directory into a single array for simplicity of (de)allocation. + */ + cmdArrayLen = (*env)->GetArrayLength (env, cmdArray); + if (cmdArrayLen == 0) + goto null_pointer_exception; + if (envArray != NULL) + envArrayLen = (*env)->GetArrayLength (env, envArray); + if ((strings = malloc (((cmdArrayLen + 1) + + (envArray != NULL ? envArrayLen + 1 : 0) + + (dirString != + NULL ? 1 : 0)) * sizeof (*strings))) == NULL) + { + TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf, + sizeof (errbuf), "malloc: %s", + strerror (errno)); + goto out_of_memory; + } + + /* Extract C strings from the various String parameters */ + for (i = 0; i < cmdArrayLen; i++) + { + if ((strings[num_strings++] = copy_elem (env, cmdArray, i)) == NULL) + goto done; + } + strings[num_strings++] = NULL; /* terminate array with NULL */ + if (envArray != NULL) + { + newEnviron = strings + num_strings; + for (i = 0; i < envArrayLen; i++) + { + if ((strings[num_strings++] = copy_elem (env, envArray, i)) == NULL) + goto done; + } + strings[num_strings++] = NULL; /* terminate array with NULL */ + } + if (dirString != NULL) + { + if ((dir = copy_string (env, dirString)) == NULL) + goto done; + strings[num_strings++] = dir; + } + + /* Create inter-process pipes */ + for (i = 0; i < 3; i++) + { + if (pipe (fds[i]) == -1) + { + TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf, + sizeof (errbuf), "pipe: %s", + strerror (errno)); + goto system_error; + } + } + + /* Set close-on-exec flag for parent's ends of pipes */ + (void) fcntl (fds[0][1], F_SETFD, 1); + (void) fcntl (fds[1][0], F_SETFD, 1); + (void) fcntl (fds[2][0], F_SETFD, 1); + + /* Fork into parent and child processes */ + if ((pid = fork ()) == (pid_t) - 1) + { + TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf, + sizeof (errbuf), "fork: %s", + strerror (errno)); + goto system_error; + } + + /* Child becomes the new process */ + if (pid == 0) + { + char *const path = strings[0]; + + /* Move file descriptors to standard locations */ + if (fds[0][0] != 0) + { + if (dup2 (fds[0][0], 0) == -1) + { + fprintf (stderr, "dup2: %s", strerror (errno)); + exit (127); + } + close (fds[0][0]); + } + if (fds[1][1] != 1) + { + if (dup2 (fds[1][1], 1) == -1) + { + fprintf (stderr, "dup2: %s", strerror (errno)); + exit (127); + } + close (fds[1][1]); + } + if (fds[2][1] != 2) + { + if (dup2 (fds[2][1], 2) == -1) + { + fprintf (stderr, "dup2: %s", strerror (errno)); + exit (127); + } + close (fds[2][1]); + } + + /* Change into destination directory */ + if (dir != NULL && chdir (dir) == -1) + { + fprintf (stderr, "%s: %s", dir, strerror (errno)); + exit (127); + } + + /* Make argv[0] last component of executable pathname */ + /* XXX should use "file.separator" property here XXX */ + for (i = strlen (path); i > 0 && path[i - 1] != '/'; i--); + strings[0] = path + i; + + /* Set new environment */ + if (newEnviron != NULL) + environ = newEnviron; + + /* Execute new program (this will close the parent end of the pipes) */ + execvp (path, strings); + + /* Failed */ + fprintf (stderr, "%s: %s", path, strerror (errno)); + exit (127); + } + + /* Create Input/OutputStream objects around parent file descriptors */ + clazz = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl"); + if ((*env)->ExceptionOccurred (env)) + goto done; + method = (*env)->GetMethodID (env, clazz, "<init>", "(II)V"); + if ((*env)->ExceptionOccurred (env)) + goto done; + for (i = 0; i < 3; i++) + { + /* Mode is WRITE (2) for in and READ (1) for out and err. */ + const int fd = fds[i][i == 0]; + const int mode = (i == 0) ? 2 : 1; + jclass sclazz; + jmethodID smethod; + + jobject channel = (*env)->NewObject (env, clazz, method, fd, mode); + if ((*env)->ExceptionOccurred (env)) + goto done; + + if (mode == 2) + sclazz = (*env)->FindClass (env, "java/io/FileOutputStream"); + else + sclazz = (*env)->FindClass (env, "java/io/FileInputStream"); + if ((*env)->ExceptionOccurred (env)) + goto done; + + smethod = (*env)->GetMethodID (env, sclazz, "<init>", + "(Lgnu/java/nio/channels/FileChannelImpl;)V"); + if ((*env)->ExceptionOccurred (env)) + goto done; + + streams[i] = (*env)->NewObject (env, sclazz, smethod, channel); + if ((*env)->ExceptionOccurred (env)) + goto done; + + (*env)->DeleteLocalRef (env, sclazz); + } + (*env)->DeleteLocalRef (env, clazz); + + /* Invoke VMProcess.setProcessInfo() to update VMProcess object */ + method = (*env)->GetMethodID (env, + (*env)->GetObjectClass (env, this), + "setProcessInfo", + "(Ljava/io/OutputStream;Ljava/io/InputStream;Ljava/io/InputStream;J)V"); + if ((*env)->ExceptionOccurred (env)) + goto done; + (*env)->CallVoidMethod (env, this, method, + streams[0], streams[1], streams[2], (jlong) pid); + if ((*env)->ExceptionOccurred (env)) + goto done; + (*env)->DeleteLocalRef (env, clazz); + +done: + /* + * We get here in both the success and failure cases in the + * parent process. Our goal is to clean up the mess we created. + */ + + /* Close child's ends of pipes */ + for (i = 0; i < 3; i++) + { + const int fd = fds[i][i != 0]; + + if (fd != -1) + close (fd); + } + + /* + * Close parent's ends of pipes if Input/OutputStreams never got created. + * This can only happen in a failure case. If a Stream object + * was created for a file descriptor, we don't close it because it + * will get closed when the Stream object is finalized. + */ + for (i = 0; i < 3; i++) + { + const int fd = fds[i][i == 0]; + + if (fd != -1 && streams[i] == NULL) + close (fd); + } + + /* Free C strings */ + while (num_strings > 0) + free (strings[--num_strings]); + free (strings); + + /* Done */ + return; + +null_pointer_exception: + clazz = (*env)->FindClass (env, "java/lang/NullPointerException"); + if ((*env)->ExceptionOccurred (env)) + goto done; + (*env)->ThrowNew (env, clazz, NULL); + (*env)->DeleteLocalRef (env, clazz); + goto done; + +out_of_memory: + clazz = (*env)->FindClass (env, "java/lang/InternalError"); + if ((*env)->ExceptionOccurred (env)) + goto done; + (*env)->ThrowNew (env, clazz, errbuf); + (*env)->DeleteLocalRef (env, clazz); + goto done; + +system_error: + clazz = (*env)->FindClass (env, "java/io/IOException"); + if ((*env)->ExceptionOccurred (env)) + goto done; + (*env)->ThrowNew (env, clazz, errbuf); + (*env)->DeleteLocalRef (env, clazz); + goto done; +} + +/* + * private static final native boolean nativeReap() + */ +JNIEXPORT jboolean JNICALL +Java_java_lang_VMProcess_nativeReap (JNIEnv * env, jclass clazz) +{ + char ebuf[64]; + jfieldID field; + jint status; + pid_t pid; + + /* Try to reap a child process, but don't block */ + if ((pid = waitpid ((pid_t) - 1, &status, WNOHANG)) == 0) + return JNI_FALSE; + + /* Check result from waitpid() */ + if (pid == (pid_t) - 1) + { + if (errno == ECHILD || errno == EINTR) + return JNI_FALSE; + TARGET_NATIVE_MISC_FORMAT_STRING2 (ebuf, + sizeof (ebuf), "waitpid(%ld): %s", + (long) pid, strerror (errno)); + clazz = (*env)->FindClass (env, "java/lang/InternalError"); + if ((*env)->ExceptionOccurred (env)) + return JNI_FALSE; + (*env)->ThrowNew (env, clazz, ebuf); + (*env)->DeleteLocalRef (env, clazz); + return JNI_FALSE; + } + + /* Get exit code; for signal termination return negative signal value XXX */ + if (WIFEXITED (status)) + status = (jint) (jbyte) WEXITSTATUS (status); + else if (WIFSIGNALED (status)) + status = -(jint) WTERMSIG (status); + else + return JNI_FALSE; /* process merely stopped; ignore */ + + /* Return process pid and exit status */ + field = (*env)->GetStaticFieldID (env, clazz, "reapedPid", "J"); + if ((*env)->ExceptionOccurred (env)) + return JNI_FALSE; + (*env)->SetStaticLongField (env, clazz, field, (jlong) pid); + if ((*env)->ExceptionOccurred (env)) + return JNI_FALSE; + field = (*env)->GetStaticFieldID (env, clazz, "reapedExitValue", "I"); + if ((*env)->ExceptionOccurred (env)) + return JNI_FALSE; + (*env)->SetStaticIntField (env, clazz, field, status); + if ((*env)->ExceptionOccurred (env)) + return JNI_FALSE; + + /* Done */ + return JNI_TRUE; +} + +/* + * private static final native void nativeKill(long) + */ +JNIEXPORT void JNICALL +Java_java_lang_VMProcess_nativeKill (JNIEnv * env, jclass clazz, jlong pid) +{ + char ebuf[64]; + + if (kill ((pid_t) pid, SIGKILL) == -1) + { + TARGET_NATIVE_MISC_FORMAT_STRING2 (ebuf, + sizeof (ebuf), "kill(%ld): %s", + (long) pid, strerror (errno)); + clazz = (*env)->FindClass (env, "java/lang/InternalError"); + if ((*env)->ExceptionOccurred (env)) + return; + (*env)->ThrowNew (env, clazz, ebuf); + (*env)->DeleteLocalRef (env, clazz); + } +} diff --git a/libjava/classpath/native/jni/java-lang/java_lang_VMSystem.c b/libjava/classpath/native/jni/java-lang/java_lang_VMSystem.c new file mode 100644 index 00000000000..0edbb2e965a --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_VMSystem.c @@ -0,0 +1,156 @@ +/* System.c -- native code for java.lang.System + Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "java_lang_VMSystem.h" + +#include <jcl.h> + +#include <sys/time.h> +#include <stdlib.h> + +/* + * Class: java_lang_VMSystem + * Method: setIn0 + * Signature: (Ljava/io/InputStream;)V + */ +JNIEXPORT void JNICALL +Java_java_lang_VMSystem_setIn (JNIEnv * env, + jclass thisClass __attribute__ ((__unused__)), + jobject obj) +{ + jclass cls; + jfieldID field; + + cls = JCL_FindClass (env, "java/lang/System"); + if (!cls) + return; + + field = (*env)->GetStaticFieldID (env, cls, "in", "Ljava/io/InputStream;"); + if (!field) + return; + (*env)->SetStaticObjectField (env, cls, field, obj); +} + +/* + * Class: java_lang_VMSystem + * Method: setOut0 + * Signature: (Ljava/io/PrintStream;)V + */ +JNIEXPORT void JNICALL +Java_java_lang_VMSystem_setOut (JNIEnv * env, + jclass thisClass __attribute__ ((__unused__)), + jobject obj) +{ + jclass cls; + jfieldID field; + + cls = JCL_FindClass (env, "java/lang/System"); + if (!cls) + return; + + field = (*env)->GetStaticFieldID (env, cls, "out", "Ljava/io/PrintStream;"); + if (!field) + return; + (*env)->SetStaticObjectField (env, cls, field, obj); +} + +/* + * Class: java_lang_VMSystem + * Method: setErr0 + * Signature: (Ljava/io/PrintStream;)V + */ +JNIEXPORT void JNICALL +Java_java_lang_VMSystem_setErr (JNIEnv * env, + jclass thisClass __attribute__ ((__unused__)), + jobject obj) +{ + jclass cls; + jfieldID field; + + cls = JCL_FindClass (env, "java/lang/System"); + if (!cls) + return; + + field = (*env)->GetStaticFieldID (env, cls, "err", "Ljava/io/PrintStream;"); + if (!field) + return; + (*env)->SetStaticObjectField (env, cls, field, obj); +} + +/* + * Class: java_lang_VMSystem + * Method: currentTimeMillis + * Signature: ()J + */ +JNIEXPORT jlong JNICALL +Java_java_lang_VMSystem_currentTimeMillis + (JNIEnv * env __attribute__ ((__unused__)), + jclass thisClass __attribute__ ((__unused__))) +{ + /* Note: this implementation copied directly from Japhar's, by Chris Toshok. */ + jlong result; + struct timeval tp; + + if (gettimeofday (&tp, NULL) == -1) + (*env)->FatalError (env, "gettimeofday call failed."); + + result = (jlong) tp.tv_sec; + result *= 1000; + result += (tp.tv_usec / 1000); + + return result; +} + +JNIEXPORT jstring JNICALL +Java_java_lang_VMSystem_getenv (JNIEnv * env, + jclass klass __attribute__ ((__unused__)), + jstring jname) +{ + const char *cname; + const char *envname; + + cname = JCL_jstring_to_cstring (env, jname); + if (cname == NULL) + return NULL; + + envname = getenv (cname); + if (envname == NULL) + return NULL; + + JCL_free_cstring (env, jname, cname); + return (*env)->NewStringUTF (env, envname); +} diff --git a/libjava/classpath/native/jni/java-lang/java_lang_reflect_Array.c b/libjava/classpath/native/jni/java-lang/java_lang_reflect_Array.c new file mode 100644 index 00000000000..0bd23c16ffc --- /dev/null +++ b/libjava/classpath/native/jni/java-lang/java_lang_reflect_Array.c @@ -0,0 +1,61 @@ +/* java.lang.reflect.Array native functions + Copyright (C) 1998, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* + * java.lang.reflect.Array native functions. + * Author: John Keiser + * Version: 1.1.0 + * Date: 2 Jun 1998 + */ + +#include <stddef.h> + +#include "java_lang_reflect_Array.h" + +/* + * Class: java_lang_reflect_Array + * Method: createObjectArray + * Signature: (Ljava/lang/Class;I)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL +Java_java_lang_reflect_Array_createObjectArray + (JNIEnv * env, + jclass thisClass __attribute__ ((__unused__)), + jclass arrayType, jint arrayLength) +{ + return (jobject) (*env)->NewObjectArray (env, arrayLength, arrayType, NULL); +} diff --git a/libjava/classpath/native/jni/java-net/.cvsignore b/libjava/classpath/native/jni/java-net/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/java-net/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/java-net/Makefile.am b/libjava/classpath/native/jni/java-net/Makefile.am new file mode 100644 index 00000000000..3e8c863a9a9 --- /dev/null +++ b/libjava/classpath/native/jni/java-net/Makefile.am @@ -0,0 +1,14 @@ +pkglib_LTLIBRARIES = libjavanet.la + +libjavanet_la_SOURCES = javanet.c \ + javanet.h \ + java_net_VMInetAddress.c \ + java_net_VMNetworkInterface.c \ + gnu_java_net_PlainDatagramSocketImpl.c \ + gnu_java_net_PlainSocketImpl.c + +libjavanet_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/java-net/gnu_java_net_PlainDatagramSocketImpl.c b/libjava/classpath/native/jni/java-net/gnu_java_net_PlainDatagramSocketImpl.c new file mode 100644 index 00000000000..5bc284f6426 --- /dev/null +++ b/libjava/classpath/native/jni/java-net/gnu_java_net_PlainDatagramSocketImpl.c @@ -0,0 +1,452 @@ +/* PlainDatagramSocketImpl.c - Native methods for PlainDatagramSocketImpl class + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <jni.h> +#include <jcl.h> + +#include "javanet.h" + +#include "target_native.h" +#ifndef WITHOUT_NETWORK +#include "target_native_network.h" +#endif /* WITHOUT_NETWORK */ + +#include "gnu_java_net_PlainDatagramSocketImpl.h" + +/* + * Note that most of the functions in this module simply redirect to another + * internal function. Why? Because many of these functions are shared + * with PlainSocketImpl. + */ + +/*************************************************************************/ + +/* + * Creates a new datagram socket + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_create (JNIEnv * env, jobject obj) +{ + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + _javanet_create (env, obj, 0); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Close the socket. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_close (JNIEnv * env, jobject obj) +{ + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + _javanet_close (env, obj, 0); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method binds the specified address to the specified local port. + * Note that we have to set the local address and local port public instance + * variables. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_bind (JNIEnv * env, jobject obj, + jint port, jobject addr) +{ + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + _javanet_bind (env, obj, addr, port, 0); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method sets the specified option for a socket + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_setOption (JNIEnv * env, + jobject obj, + jint option_id, + jobject val) +{ + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + _javanet_set_option (env, obj, option_id, val); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method sets the specified option for a socket + */ +JNIEXPORT jobject JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_getOption (JNIEnv * env, + jobject obj, + jint option_id) +{ + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + return (_javanet_get_option (env, obj, option_id)); +#else /* not WITHOUT_NETWORK */ + return NULL; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Reads a buffer from a remote host + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_receive0 (JNIEnv * env, jobject obj, + jobject packet) +{ +#ifndef WITHOUT_NETWORK + int addr, port, bytes_read; + unsigned int maxlen, offset; + jclass cls, addr_cls; + jfieldID fid; + jmethodID mid; + jarray arr; + unsigned char octets[4]; + char ip_str[16]; + jobject ip_str_obj, addr_obj; + + assert (env != NULL); + assert ((*env) != NULL); + + addr = 0; + port = 0; + maxlen = 0; + offset = 0; + bytes_read = 0; + + if (packet == NULL) + { + JCL_ThrowException (env, "java/lang/NullPointerException", + "Null datagram packet"); + return; + } + + /* Get the buffer from the packet */ + cls = (*env)->GetObjectClass (env, packet); + if (cls == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error"); + return; + } + + mid = (*env)->GetMethodID (env, cls, "getData", "()[B"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: getData"); + return; + } + + arr = (*env)->CallObjectMethod (env, packet, mid); + if ((*env)->ExceptionOccurred (env)) + return; + if (arr == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: call getData"); + return; + } + + /* Now get the offset from the packet */ + mid = (*env)->GetMethodID (env, cls, "getOffset", "()I"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: getOffset"); + return; + } + + offset = (*env)->CallIntMethod (env, packet, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.receive(): Got the offset\n"); + + /* Now get the maximal available length from the packet */ + fid = (*env)->GetFieldID (env, cls, "maxlen", "I"); + if (fid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: maxlen"); + return; + } + + maxlen = (*env)->GetIntField (env, packet, fid); + if ((*env)->ExceptionOccurred (env)) + return; + + /* Receive the packet */ + /* should we try some sort of validation on the length? */ + bytes_read = + _javanet_recvfrom (env, obj, arr, offset, maxlen, &addr, &port); + if ((*env)->ExceptionOccurred (env)) + return; + if (bytes_read == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: receive"); + return; + } + + DBG ("PlainDatagramSocketImpl.receive(): Received packet\n"); + + /* Store the address */ + TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (addr, + octets[0], + octets[1], + octets[2], octets[3]); + sprintf (ip_str, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); + ip_str_obj = (*env)->NewStringUTF (env, ip_str); + if (ip_str_obj == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: new string"); + return; + } + + addr_cls = (*env)->FindClass (env, "java/net/InetAddress"); + if (addr_cls == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: InetAddress class"); + return; + } + DBG ("PlainDatagramSocketImpl.receive(): Found InetAddress class\n"); + + mid = (*env)->GetStaticMethodID (env, addr_cls, "getByName", + "(Ljava/lang/String;)Ljava/net/InetAddress;"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal Error"); + return; + } + DBG + ("PlainDatagramSocketImpl.receive(): Found InetAddress.getByName method\n"); + + addr_obj = (*env)->CallStaticObjectMethod (env, addr_cls, mid, ip_str_obj); + if ((*env)->ExceptionOccurred (env)) + return; + + mid = (*env)->GetMethodID (env, cls, "setAddress", + "(Ljava/net/InetAddress;)V"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: setAddress"); + return; + } + + (*env)->CallVoidMethod (env, packet, mid, addr_obj); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.receive(): Stored the address\n"); + + /* Store the port */ + mid = (*env)->GetMethodID (env, cls, "setPort", "(I)V"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: setPort"); + return; + } + + (*env)->CallVoidMethod (env, packet, mid, port); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.receive(): Stored the port\n"); + + /* Store back the length */ + fid = (*env)->GetFieldID (env, cls, "length", "I"); + if (fid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error: length"); + return; + } + + (*env)->SetIntField (env, packet, fid, bytes_read); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.receive(): Stored the length\n"); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Writes a buffer to the remote host + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_sendto (JNIEnv * env, jobject obj, + jobject addr, jint port, + jarray buf, jint offset, + jint len) +{ +#ifndef WITHOUT_NETWORK + jint netAddress; + + assert (env != NULL); + assert ((*env) != NULL); + + netAddress = _javanet_get_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.sendto(): have addr\n"); + + _javanet_sendto (env, obj, buf, offset, len, netAddress, port); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.sendto(): finished\n"); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Joins a multicast group + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_join (JNIEnv * env, jobject obj, + jobject addr) +{ +#ifndef WITHOUT_NETWORK + jint netAddress; + int fd; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + netAddress = _javanet_get_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + fd = _javanet_get_int_field (env, obj, "native_fd"); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.join(): have native fd\n"); + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_ADD_MEMBERSHIP (fd, netAddress, + result); + + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + DBG ("PlainDatagramSocketImpl.join(): finished\n"); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Leaves a multicast group + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainDatagramSocketImpl_leave (JNIEnv * env, jobject obj, + jobject addr) +{ +#ifndef WITHOUT_NETWORK + jint netAddress; + int fd; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + netAddress = _javanet_get_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + fd = _javanet_get_int_field (env, obj, "native_fd"); + if ((*env)->ExceptionOccurred (env)) + return; + + DBG ("PlainDatagramSocketImpl.leave(): have native fd\n"); + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_DROP_MEMBERSHIP (fd, netAddress, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + DBG ("PlainDatagramSocketImpl.leave(): finished\n"); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} diff --git a/libjava/classpath/native/jni/java-net/gnu_java_net_PlainSocketImpl.c b/libjava/classpath/native/jni/java-net/gnu_java_net_PlainSocketImpl.c new file mode 100644 index 00000000000..a5261514dce --- /dev/null +++ b/libjava/classpath/native/jni/java-net/gnu_java_net_PlainSocketImpl.c @@ -0,0 +1,320 @@ +/* PlainSocketImpl.c - Native methods for PlainSocketImpl class + Copyright (C) 1998, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <jni.h> +#include <jcl.h> + +#include "javanet.h" + +#include "target_native.h" +#ifndef WITHOUT_NETWORK +#include "target_native_network.h" +#endif /* WITHOUT_NETWORK */ + +#include "gnu_java_net_PlainSocketImpl.h" + +/* + * Note that the functions in this module simply redirect to another + * internal function. Why? Because many of these functions are shared + * with PlainDatagramSocketImpl. The unshared ones were done the same + * way for consistency. + */ + +/*************************************************************************/ + +/* + * Creates a new stream or datagram socket + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_create (JNIEnv * env, jobject this, + jboolean stream) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_create (env, this, stream); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Close the socket. Any underlying streams will be closed by this + * action as well. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_close (JNIEnv * env, jobject this) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_close (env, this, 1); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Connects to the specified destination. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_connect (JNIEnv * env, jobject this, + jobject addr, jint port) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_connect (env, this, addr, port); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method binds the specified address to the specified local port. + * Note that we have to set the local address and local port public instance + * variables. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_bind (JNIEnv * env, jobject this, + jobject addr, jint port) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_bind (env, this, addr, port, 1); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Starts listening on a socket with the specified number of pending + * connections allowed. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_listen (JNIEnv * env, jobject this, + jint queuelen) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_listen (env, this, queuelen); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Accepts a new connection and assigns it to the passed in SocketImpl + * object. Note that we assume this is a PlainSocketImpl just like us. + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_accept (JNIEnv * env, jobject this, + jobject impl) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_accept (env, this, impl); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +JNIEXPORT jint JNICALL +Java_gnu_java_net_PlainSocketImpl_available (JNIEnv * env, jobject this) +{ +#ifndef WITHOUT_NETWORK + jclass cls; + jfieldID fid; + int fd; + int bytesAvailable; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + cls = (*env)->GetObjectClass (env, this); + if (cls == 0) + { + JCL_ThrowException (env, IO_EXCEPTION, "internal error"); + return 0; + } + + fid = (*env)->GetFieldID (env, cls, "native_fd", "I"); + if (fid == 0) + { + JCL_ThrowException (env, IO_EXCEPTION, "internal error"); + return 0; + } + + fd = (*env)->GetIntField (env, this, fid); + + TARGET_NATIVE_NETWORK_SOCKET_RECEIVE_AVAILABLE (fd, bytesAvailable, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return 0; + } + + return bytesAvailable; +#else /* not WITHOUT_NETWORK */ + return 0; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method sets the specified option for a socket + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_setOption (JNIEnv * env, jobject this, + jint option_id, jobject val) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_set_option (env, this, option_id, val); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method sets the specified option for a socket + */ +JNIEXPORT jobject JNICALL +Java_gnu_java_net_PlainSocketImpl_getOption (JNIEnv * env, jobject this, + jint option_id) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + return (_javanet_get_option (env, this, option_id)); +#else /* not WITHOUT_NETWORK */ + return NULL; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Reads a buffer from a remote host + */ +JNIEXPORT jint JNICALL +Java_gnu_java_net_PlainSocketImpl_read (JNIEnv * env, jobject this, + jarray buf, jint offset, jint len) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + return (_javanet_recvfrom (env, this, buf, offset, len, 0, 0)); +#else /* not WITHOUT_NETWORK */ + return 0; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Writes a buffer to the remote host + */ +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_write (JNIEnv * env, jobject this, + jarray buf, jint offset, jint len) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_sendto (env, this, buf, offset, len, 0, 0); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_shutdownInput (JNIEnv * env, jobject this) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_shutdownInput (env, this); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +JNIEXPORT void JNICALL +Java_gnu_java_net_PlainSocketImpl_shutdownOutput (JNIEnv * env, jobject this) +{ +#ifndef WITHOUT_NETWORK + assert (env != NULL); + assert ((*env) != NULL); + + _javanet_shutdownOutput (env, this); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/* end of file */ diff --git a/libjava/classpath/native/jni/java-net/java_net_VMInetAddress.c b/libjava/classpath/native/jni/java-net/java_net_VMInetAddress.c new file mode 100644 index 00000000000..d33265cff7e --- /dev/null +++ b/libjava/classpath/native/jni/java-net/java_net_VMInetAddress.c @@ -0,0 +1,282 @@ +/* VMInetAddress.c - Native methods for InetAddress class + Copyright (C) 1998, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <jni.h> +#include <jcl.h> + +#include "javanet.h" + +#include "target_native.h" +#ifndef WITHOUT_NETWORK +#include "target_native_network.h" +#endif /* WITHOUT_NETWORK */ + +#include "java_net_VMInetAddress.h" + +/*************************************************************************/ + +/* + * Function to return the local hostname + */ +JNIEXPORT jstring JNICALL +Java_java_net_VMInetAddress_getLocalHostname (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + char hostname[256]; + int result; + jstring retval; + + assert (env != NULL); + assert ((*env) != NULL); + +#ifndef WITHOUT_NETWORK + TARGET_NATIVE_NETWORK_GET_HOSTNAME (hostname, sizeof (hostname), result); + if (result != TARGET_NATIVE_OK) + { + strcpy (hostname, "localhost"); + } +#else /* not WITHOUT_NETWORK */ + strcpy (hostname, "localhost"); +#endif /* not WITHOUT_NETWORK */ + + retval = (*env)->NewStringUTF (env, hostname); + + return (retval); +} + +/*************************************************************************/ + +/* + * Returns the value of the special IP address INADDR_ANY + */ +JNIEXPORT jarray JNICALL +Java_java_net_VMInetAddress_lookupInaddrAny (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + jarray IParray; + jbyte *octets; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Allocate an array for the IP address */ + IParray = (*env)->NewByteArray (env, 4); + if (IParray == NULL) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error"); + return (jarray) NULL; + } + + /* Copy in the values */ + octets = (*env)->GetByteArrayElements (env, IParray, 0); + +#ifndef WITHOUT_NETWORK + TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (INADDR_ANY, + octets[0], + octets[1], + octets[2], octets[3]); + (*env)->ReleaseByteArrayElements (env, IParray, octets, 0); +#else /* not WITHOUT_NETWORK */ + octets[0] = 0; + octets[1] = 0; + octets[2] = 0; + octets[3] = 0; +#endif /* not WITHOUT_NETWORK */ + + return (IParray); +} + +/*************************************************************************/ + +/* + * Function to return the canonical hostname for a given IP address passed + * in as a byte array + */ +JNIEXPORT jstring JNICALL +Java_java_net_VMInetAddress_getHostByAddr (JNIEnv * env, + jclass class + __attribute__ ((__unused__)), + jarray arr) +{ +#ifndef WITHOUT_NETWORK + jbyte *octets; + jsize len; + int addr; + char hostname[255]; + int result; + jstring retval; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Grab the byte[] array with the IP out of the input data */ + len = (*env)->GetArrayLength (env, arr); + if (len != 4) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Bad IP Address"); + return (jstring) NULL; + } + + octets = (*env)->GetByteArrayElements (env, arr, 0); + if (!octets) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Bad IP Address"); + return (jstring) NULL; + } + + /* Convert it to a 32 bit address */ + TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], + octets[1], + octets[2], octets[3], addr); + + /* Release some memory */ + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + + /* Resolve the address and return the name */ + TARGET_NATIVE_NETWORK_GET_HOSTNAME_BY_ADDRESS (addr, hostname, + sizeof (hostname), result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Bad IP address"); + return (jstring) NULL; + } + + retval = (*env)->NewStringUTF (env, hostname); + + return (retval); +#else /* not WITHOUT_NETWORK */ + return (jstring) NULL; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +JNIEXPORT jobjectArray JNICALL +Java_java_net_VMInetAddress_getHostByName (JNIEnv * env, + jclass class + __attribute__ ((__unused__)), + jstring host) +{ +#ifndef WITHOUT_NETWORK + const char *hostname; +/* FIXME: limitation of max. 64 addresses - how to make it more flexibale? */ + int addresses[64]; + jsize addresses_count; + int result; + jclass arr_class; + jobjectArray addrs; + int i; + jbyte *octets; + jarray ret_octets; + int max_addresses; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Grab the hostname string */ + hostname = (*env)->GetStringUTFChars (env, host, 0); + if (!hostname) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Null hostname"); + return (jobjectArray) NULL; + } + + max_addresses = sizeof (addresses) / sizeof (addresses[0]); + TARGET_NATIVE_NETWORK_GET_HOSTNAME_BY_NAME (hostname, + addresses, + max_addresses, + addresses_count, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, (char *) hostname); + return (jobjectArray) NULL; + } + (*env)->ReleaseStringUTFChars (env, host, hostname); + + arr_class = (*env)->FindClass (env, "[B"); + if (!arr_class) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error"); + return (jobjectArray) NULL; + } + + addrs = (*env)->NewObjectArray (env, addresses_count, arr_class, 0); + if (!addrs) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error"); + return (jobjectArray) NULL; + } + + /* Now loop and copy in each address */ + for (i = 0; i < addresses_count; i++) + { + ret_octets = (*env)->NewByteArray (env, 4); + if (!ret_octets) + { + JCL_ThrowException (env, UNKNOWN_HOST_EXCEPTION, "Internal Error"); + return (jobjectArray) NULL; + } + + octets = (*env)->GetByteArrayElements (env, ret_octets, 0); + + TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (addresses[i], + octets[0], + octets[1], + octets[2], octets[3]); + + (*env)->ReleaseByteArrayElements (env, ret_octets, octets, 0); + + (*env)->SetObjectArrayElement (env, addrs, i, ret_octets); + } + + return (addrs); +#else /* not WITHOUT_NETWORK */ + return (jobjectArray) NULL; +#endif /* not WITHOUT_NETWORK */ +} + +/* end of file */ diff --git a/libjava/classpath/native/jni/java-net/java_net_VMNetworkInterface.c b/libjava/classpath/native/jni/java-net/java_net_VMNetworkInterface.c new file mode 100644 index 00000000000..71f5e8927e5 --- /dev/null +++ b/libjava/classpath/native/jni/java-net/java_net_VMNetworkInterface.c @@ -0,0 +1,66 @@ +/* VMNetworkInterface.c - Native methods for NetworkInterface class + Copyright (C) 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <jni.h> +#include <jcl.h> + +#include "java_net_VMNetworkInterface.h" + +#include "javanet.h" + +/* + * Returns all local network interfaces as vector + */ +JNIEXPORT jobject JNICALL +Java_java_net_VMNetworkInterface_getInterfaces (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.net.VMNetworkInterface.getInterfaces(): not implemented"); + return 0; +} + +/* end of file */ diff --git a/libjava/classpath/native/jni/java-net/javanet.c b/libjava/classpath/native/jni/java-net/javanet.c new file mode 100644 index 00000000000..fdc1c22ecbf --- /dev/null +++ b/libjava/classpath/native/jni/java-net/javanet.c @@ -0,0 +1,1577 @@ +/* javanet.c - Common internal functions for the java.net package + Copyright (C) 1998, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <jni.h> +#include <jcl.h> + +#include "javanet.h" + +#include "target_native.h" +#ifndef WITHOUT_NETWORK +#include "target_native_network.h" +#endif /* WITHOUT_NETWORK */ + +#ifndef WITHOUT_NETWORK +/* Need to have some value for SO_TIMEOUT */ +#ifndef SO_TIMEOUT +#ifndef SO_RCVTIMEO +#warning Neither SO_TIMEOUT or SO_RCVTIMEO are defined! +#warning This will cause all get/setOption calls with that value to throw an exception +#else +#define SO_TIMEOUT SO_RCVTIMEO +#endif /* not SO_RCVTIMEO */ +#endif /* not SO_TIMEOUT */ +#endif /* WITHOUT_NETWORK */ + +/*************************************************************************/ + +/* + * Sets an integer field in the specified object. + */ +static void +_javanet_set_int_field (JNIEnv * env, jobject obj, + const char *class, const char *field, int val) +{ + jclass cls; + jfieldID fid; + + assert (env != NULL); + assert ((*env) != NULL); + + cls = (*env)->FindClass (env, class); + if (cls == NULL) + return; + + fid = (*env)->GetFieldID (env, cls, field, "I"); + if (fid == NULL) + return; + + (*env)->SetIntField (env, obj, fid, val); + + return; +} + +/*************************************************************************/ + +/* + * Returns the value of the specified integer instance variable field or + * -1 if an error occurs. + */ +int +_javanet_get_int_field (JNIEnv * env, jobject obj, const char *field) +{ + jclass cls = 0; + jfieldID fid; + int fd; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_get_int_field(): Entered _javanet_get_int_field\n"); + + cls = (*env)->GetObjectClass (env, obj); + if (cls == NULL) + return -1; + + fid = (*env)->GetFieldID (env, cls, field, "I"); + if (fid == NULL) + return -1; + DBG ("_javanet_get_int_field(): Found field id\n"); + + fd = (*env)->GetIntField (env, obj, fid); + + return fd; +} + +/*************************************************************************/ + +/* + * Creates a FileDescriptor object in the parent class. It is not used + * by this implementation, but the docs list it as a variable, so we + * need to include it. + */ +static void +_javanet_create_localfd (JNIEnv * env, jobject this) +{ + jclass this_cls, fd_cls; + jfieldID fid; + jmethodID mid; + jobject fd_obj; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_create_localfd(): Entered _javanet_create_localfd\n"); + + /* Look up the fd field */ + this_cls = (*env)->FindClass (env, "java/net/SocketImpl"); + if (this_cls == NULL) + return; + + fid = (*env)->GetFieldID (env, this_cls, "fd", "Ljava/io/FileDescriptor;"); + if (fid == NULL) + return; + + DBG ("_javanet_create_localfd(): Found fd variable\n"); + + /* Create a FileDescriptor */ + fd_cls = (*env)->FindClass (env, "java/io/FileDescriptor"); + if (fd_cls == NULL) + return; + + DBG ("_javanet_create_localfd(): Found FileDescriptor class\n"); + + mid = (*env)->GetMethodID (env, fd_cls, "<init>", "()V"); + if (mid == NULL) + return; + + DBG ("_javanet_create_localfd(): Found FileDescriptor constructor\n"); + + fd_obj = (*env)->NewObject (env, fd_cls, mid); + if (fd_obj == NULL) + return; + + DBG ("_javanet_create_localfd(): Created FileDescriptor\n"); + + /* Now set the pointer to the new FileDescriptor */ + (*env)->SetObjectField (env, this, fid, fd_obj); + DBG ("_javanet_create_localfd(): Set fd field\n"); + + return; +} + +/*************************************************************************/ + +/* + * Returns a Boolean object with the specfied value + */ +static jobject +_javanet_create_boolean (JNIEnv * env, jboolean val) +{ + jclass cls; + jmethodID mid; + jobject obj; + + assert (env != NULL); + assert ((*env) != NULL); + + cls = (*env)->FindClass (env, "java/lang/Boolean"); + if (cls == NULL) + return NULL; + + mid = (*env)->GetMethodID (env, cls, "<init>", "(Z)V"); + if (mid == NULL) + return NULL; + + obj = (*env)->NewObject (env, cls, mid, val); + if (obj == NULL) + return NULL; + + return obj; +} + +/*************************************************************************/ + +/* + * Returns an Integer object with the specfied value + */ +static jobject +_javanet_create_integer (JNIEnv * env, jint val) +{ + jclass cls; + jmethodID mid; + jobject obj; + + assert (env != NULL); + assert ((*env) != NULL); + + cls = (*env)->FindClass (env, "java/lang/Integer"); + if (cls == NULL) + return NULL; + + mid = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); + if (mid == NULL) + return NULL; + + obj = (*env)->NewObject (env, cls, mid, val); + if (obj == NULL) + return NULL; + + return obj; +} + +/*************************************************************************/ + +/* + * Builds an InetAddress object from a 32 bit address in host byte order + */ +static jobject +_javanet_create_inetaddress (JNIEnv * env, int netaddr) +{ +#ifndef WITHOUT_NETWORK + unsigned char octets[4]; + char buf[16]; + jclass ia_cls; + jmethodID mid; + jstring ip_str; + jobject ia; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Build a string IP address */ + TARGET_NATIVE_NETWORK_INT_TO_IPADDRESS_BYTES (netaddr, + octets[0], + octets[1], + octets[2], octets[3]); + sprintf (buf, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); + DBG ("_javanet_create_inetaddress(): Created ip addr string\n"); + + /* Get an InetAddress object for this IP */ + ia_cls = (*env)->FindClass (env, "java/net/InetAddress"); + if (ia_cls == NULL) + { + return NULL; + } + + DBG ("_javanet_create_inetaddress(): Found InetAddress class\n"); + + mid = (*env)->GetStaticMethodID (env, ia_cls, "getByName", + "(Ljava/lang/String;)Ljava/net/InetAddress;"); + if (mid == NULL) + { + return NULL; + } + + DBG ("_javanet_create_inetaddress(): Found getByName method\n"); + + ip_str = (*env)->NewStringUTF (env, buf); + if (ip_str == NULL) + { + return NULL; + } + + ia = (*env)->CallStaticObjectMethod (env, ia_cls, mid, ip_str); + if (ia == NULL) + { + return NULL; + } + + DBG ("_javanet_create_inetaddress(): Called getByName method\n"); + + return ia; +#else /* not WITHOUT_NETWORK */ + return NULL; +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +static void +_javanet_set_remhost_addr (JNIEnv * env, jobject this, jobject ia) +{ + jclass this_cls; + jfieldID fid; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Set the variable in the object */ + this_cls = (*env)->FindClass (env, "java/net/SocketImpl"); + if (this_cls == NULL) + return; + + fid = + (*env)->GetFieldID (env, this_cls, "address", "Ljava/net/InetAddress;"); + if (fid == NULL) + return; + + DBG ("_javanet_set_remhost_addr(): Found address field\n"); + + (*env)->SetObjectField (env, this, fid, ia); + DBG ("_javanet_set_remhost_addr(): Set field\n"); +} + +/* + * Set's the value of the "addr" field in PlainSocketImpl with a new + * InetAddress for the specified addr + */ +static void +_javanet_set_remhost (JNIEnv * env, jobject this, int netaddr) +{ + jobject ia; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_set_remhost(): Entered _javanet_set_remhost\n"); + + /* Get an InetAddress object */ + ia = _javanet_create_inetaddress (env, netaddr); + if (ia == NULL) + return; + + _javanet_set_remhost_addr (env, this, ia); +} + + +/*************************************************************************/ + +/* + * Returns a 32 bit Internet address for the passed in InetAddress object + */ +int +_javanet_get_netaddr (JNIEnv * env, jobject addr) +{ +#ifndef WITHOUT_NETWORK + jclass cls = 0; + jmethodID mid; + jarray arr = 0; + jbyte *octets; + int netaddr, len; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_get_netaddr(): Entered _javanet_get_netaddr\n"); + + if (addr == NULL) + { + JCL_ThrowException (env, "java/lang/NullPointerException", + "Null address"); + return 0; + } + + /* Call the getAddress method on the object to retrieve the IP address */ + cls = (*env)->GetObjectClass (env, addr); + if (cls == NULL) + return 0; + + mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B"); + if (mid == NULL) + return 0; + + DBG ("_javanet_get_netaddr(): Got getAddress method\n"); + + arr = (*env)->CallObjectMethod (env, addr, mid); + if (arr == NULL) + return 0; + + DBG ("_javanet_get_netaddr(): Got the address\n"); + + /* Turn the IP address into a 32 bit Internet address in network byte order */ + len = (*env)->GetArrayLength (env, arr); + if (len != 4) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal Error"); + return 0; + } + DBG ("_javanet_get_netaddr(): Length ok\n"); + + octets = (*env)->GetByteArrayElements (env, arr, 0); + if (octets == NULL) + return 0; + + DBG ("_javanet_get_netaddr(): Grabbed bytes\n"); + + TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], + octets[1], + octets[2], + octets[3], netaddr); + + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + DBG ("_javanet_get_netaddr(): Done getting addr\n"); + + return netaddr; +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Creates a new stream or datagram socket + */ +void +_javanet_create (JNIEnv * env, jobject this, jboolean stream) +{ +#ifndef WITHOUT_NETWORK + int fd; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + if (stream) + { + /* create a stream socket */ + TARGET_NATIVE_NETWORK_SOCKET_OPEN_STREAM (fd, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + else + { + /* create a datagram socket, set broadcast option */ + TARGET_NATIVE_NETWORK_SOCKET_OPEN_DATAGRAM (fd, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_BROADCAST (fd, 1, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + + if (stream) + _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl", + "native_fd", fd); + else + _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl", + "native_fd", fd); + + if ((*env)->ExceptionOccurred (env)) + { + /* Try to make sure we close the socket since close() won't work. */ + do + { + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + if (result != TARGET_NATIVE_OK + && (TARGET_NATIVE_LAST_ERROR () + != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + return; + } + while (result != TARGET_NATIVE_OK); + return; + } + +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Close the socket. Any underlying streams will be closed by this + * action as well. + */ +void +_javanet_close (JNIEnv * env, jobject this, int stream) +{ +#ifndef WITHOUT_NETWORK + int fd; + int result; + int error = 0; + + assert (env != NULL); + assert ((*env) != NULL); + + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + return; + + if (stream) + _javanet_set_int_field (env, this, "gnu/java/net/PlainSocketImpl", + "native_fd", -1); + else + _javanet_set_int_field (env, this, "gnu/java/net/PlainDatagramSocketImpl", + "native_fd", -1); + do + { + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + if (result != TARGET_NATIVE_OK) + { + /* Only throw an error when a "real" error occurs. */ + error = TARGET_NATIVE_LAST_ERROR (); + if (error != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL + && error != ENOTCONN && error != ECONNRESET && error != EBADF) + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + } + } + while (error == TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL); + +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Connects to the specified destination. + */ +void +_javanet_connect (JNIEnv * env, jobject this, jobject addr, jint port) +{ +#ifndef WITHOUT_NETWORK + int netaddr, fd; + int result; + int local_address, local_port; + int remote_address, remote_port; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_connect(): Entered _javanet_connect\n"); + + /* Pre-process input variables */ + netaddr = _javanet_get_netaddr (env, addr); + if ((*env)->ExceptionOccurred (env)) + return; + + if (port == -1) + port = 0; + DBG ("_javanet_connect(): Got network address\n"); + + /* Grab the real socket file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_connect(): no native file descriptor"); + return; + } + DBG ("_javanet_connect(): Got native fd\n"); + + /* Connect up */ + do + { + TARGET_NATIVE_NETWORK_SOCKET_CONNECT (fd, netaddr, port, result); + if (result != TARGET_NATIVE_OK + && (TARGET_NATIVE_LAST_ERROR () + != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + while (result != TARGET_NATIVE_OK); + + DBG ("_javanet_connect(): Connected successfully\n"); + + /* Populate instance variables */ + TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + + _javanet_create_localfd (env, this); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + DBG ("_javanet_connect(): Created fd\n"); + + _javanet_set_int_field (env, this, "java/net/SocketImpl", "localport", + local_port); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + DBG ("_javanet_connect(): Set the local port\n"); + + TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (fd, remote_address, + remote_port, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + + if (remote_address == netaddr) + { + _javanet_set_remhost_addr (env, this, addr); + } + else + { + _javanet_set_remhost (env, this, remote_address); + } + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + DBG ("_javanet_connect(): Set the remote host\n"); + + _javanet_set_int_field (env, this, "java/net/SocketImpl", "port", + remote_port); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (fd, result); + return; + } + DBG ("_javanet_connect(): Set the remote port\n"); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * This method binds the specified address to the specified local port. + * Note that we have to set the local address and local + * port public instance variables. + */ +void +_javanet_bind (JNIEnv * env, jobject this, jobject addr, jint port, + int stream) +{ +#ifndef WITHOUT_NETWORK + jclass cls; + jmethodID mid; + jbyteArray arr = 0; + jbyte *octets; + jint fd; + int tmpaddr; + int result; + int local_address, local_port; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_bind(): Entering native bind()\n"); + + /* Get the address to connect to */ + cls = (*env)->GetObjectClass (env, addr); + if (cls == NULL) + return; + + mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B"); + if (mid == NULL) + return; + + DBG ("_javanet_bind(): Past getAddress method id\n"); + + arr = (*env)->CallObjectMethod (env, addr, mid); + if ((arr == NULL) || (*env)->ExceptionOccurred (env)) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_bind()"); + return; + } + + DBG ("_javanet_bind(): Past call object method\n"); + + octets = (*env)->GetByteArrayElements (env, arr, 0); + if (octets == NULL) + return; + + DBG ("_javanet_bind(): Past grab array\n"); + + /* Get the native socket file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_bind(): no native file descriptor"); + return; + } + DBG ("_javanet_bind(): Past native_fd lookup\n"); + + /* XXX NYI ??? */ + _javanet_set_option (env, this, SOCKOPT_SO_REUSEADDR, + _javanet_create_boolean (env, JNI_TRUE)); + + + /* Bind the socket */ + TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], + octets[1], + octets[2], + octets[3], tmpaddr); + TARGET_NATIVE_NETWORK_SOCKET_BIND (fd, tmpaddr, port, result); + + if (result != TARGET_NATIVE_OK) + { + char *errorstr = TARGET_NATIVE_LAST_ERROR_STRING (); + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + + JCL_ThrowException (env, BIND_EXCEPTION, + errorstr); + return; + } + DBG ("_javanet_bind(): Past bind\n"); + + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + + /* Update instance variables, specifically the local port number */ + TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (fd, local_address, local_port, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + if (stream) + _javanet_set_int_field (env, this, "java/net/SocketImpl", + "localport", local_port); + else + _javanet_set_int_field (env, this, "java/net/DatagramSocketImpl", + "localPort", local_port); + DBG ("_javanet_bind(): Past update port number\n"); + + return; +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Starts listening on a socket with the specified number of pending + * connections allowed. + */ +void +_javanet_listen (JNIEnv * env, jobject this, jint queuelen) +{ +#ifndef WITHOUT_NETWORK + int fd; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_listen(): no native file descriptor"); + return; + } + + /* Start listening */ + TARGET_NATIVE_NETWORK_SOCKET_LISTEN (fd, queuelen, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Accepts a new connection and assigns it to the passed in SocketImpl + * object. Note that we assume this is a PlainSocketImpl just like us + */ +void +_javanet_accept (JNIEnv * env, jobject this, jobject impl) +{ +#ifndef WITHOUT_NETWORK + int fd, newfd; + int result; + int local_address, local_port; + int remote_address, remote_port; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_accept(): no native file descriptor"); + return; + } + + /* Accept the connection */ + do + { + TARGET_NATIVE_NETWORK_SOCKET_ACCEPT (fd, newfd, result); + if (result != TARGET_NATIVE_OK + && (TARGET_NATIVE_LAST_ERROR () + != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_accept(): "); + return; + } + } + while (result != TARGET_NATIVE_OK); + + /* Populate instance variables */ + _javanet_set_int_field (env, impl, "gnu/java/net/PlainSocketImpl", + "native_fd", newfd); + + if ((*env)->ExceptionOccurred (env)) + { + /* Try to make sure we close the socket since close() won't work. */ + do + { + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + if (result != TARGET_NATIVE_OK + && (TARGET_NATIVE_LAST_ERROR () + != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + return; + } + while (result != TARGET_NATIVE_OK); + return; + } + + TARGET_NATIVE_NETWORK_SOCKET_GET_LOCAL_INFO (newfd, local_address, + local_port, result); + if (result != TARGET_NATIVE_OK) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + _javanet_create_localfd (env, impl); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + return; + } + + _javanet_set_int_field (env, impl, "java/net/SocketImpl", "localport", + local_port); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + return; + } + + TARGET_NATIVE_NETWORK_SOCKET_GET_REMOTE_INFO (newfd, remote_address, + remote_port, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + return; + } + + _javanet_set_remhost (env, impl, remote_address); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + return; + } + + _javanet_set_int_field (env, impl, "java/net/SocketImpl", "port", + remote_port); + if ((*env)->ExceptionOccurred (env)) + { + /* We don't care whether this succeeds. close() will cleanup later. */ + TARGET_NATIVE_NETWORK_SOCKET_CLOSE (newfd, result); + return; + } +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Receives a buffer from a remote host. The args are: + * + * buf - The byte array into which the data received will be written + * offset - Offset into the byte array to start writing + * len - The number of bytes to read. + * addr - Pointer to 32 bit net address of host to receive from. If null, + * this parm is ignored. If pointing to an address of 0, the + * actual address read is stored here + * port - Pointer to the port to receive from. If null, this parm is ignored. + * If it is 0, the actual remote port received from is stored here + * + * The actual number of bytes read is returned. + */ +int +_javanet_recvfrom (JNIEnv * env, jobject this, jarray buf, int offset, + int len, int *addr, int *port) +{ +#ifndef WITHOUT_NETWORK + int fd; + jbyte *p; + int from_address, from_port; + int received_bytes; + + assert (env != NULL); + assert ((*env) != NULL); + + DBG ("_javanet_recvfrom(): Entered _javanet_recvfrom\n"); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_recvfrom(): no native file descriptor"); + return 0; + } + DBG ("_javanet_recvfrom(): Got native_fd\n"); + + /* Get a pointer to the buffer */ + p = (*env)->GetByteArrayElements (env, buf, 0); + if (p == NULL) + return 0; + + DBG ("_javanet_recvfrom(): Got buffer\n"); + + /* Read the data */ + from_address = 0; + from_port = 0; + do + { + if (addr != NULL) + { + TARGET_NATIVE_NETWORK_SOCKET_RECEIVE_WITH_ADDRESS_PORT (fd, + p + offset, + len, + from_address, + from_port, + received_bytes); + } + else + { + TARGET_NATIVE_NETWORK_SOCKET_RECEIVE (fd, p + offset, len, + received_bytes); + } + } + while ((received_bytes == -1) && + (TARGET_NATIVE_LAST_ERROR () == + TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)); + + if (received_bytes == -1) + { + if (TARGET_NATIVE_LAST_ERROR () == EAGAIN) + JCL_ThrowException (env, "java/net/SocketTimeoutException", "Timeout"); + else + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + + /* Cleanup and return. */ + (*env)->ReleaseByteArrayElements (env, buf, p, 0); + return 0; + } + + (*env)->ReleaseByteArrayElements (env, buf, p, 0); + + /* Handle return addr case */ + if (addr != NULL) + { + (*addr) = from_address; + if (port != NULL) + (*port) = from_port; + } + + return (received_bytes); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Sends a buffer to a remote host. The args are: + * + * buf - A byte array + * offset - Index into the byte array to start sendign + * len - The number of bytes to write + * addr - The 32bit address to send to (may be 0) + * port - The port number to send to (may be 0) + */ +void +_javanet_sendto (JNIEnv * env, jobject this, jarray buf, int offset, int len, + int addr, int port) +{ +#ifndef WITHOUT_NETWORK + int fd; + jbyte *p; + int bytes_sent; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_sendto(): no native file descriptor"); + return; + } + + /* Get a pointer to the buffer */ + p = (*env)->GetByteArrayElements (env, buf, 0); + if (p == NULL) + return; + + /* We must send all the data, so repeat till done. */ + while (len > 0) + { + /* Send the data */ + if (addr == 0) + { + DBG ("_javanet_sendto(): Sending....\n"); + TARGET_NATIVE_NETWORK_SOCKET_SEND (fd, p + offset, len, bytes_sent); + } + else + { + DBG ("_javanet_sendto(): Sending....\n"); + TARGET_NATIVE_NETWORK_SOCKET_SEND_WITH_ADDRESS_PORT (fd, p + offset, + len, addr, port, + bytes_sent); + } + + if (bytes_sent < 0) + { + if (TARGET_NATIVE_LAST_ERROR () + != TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + break; + } + } + else + { + len -= bytes_sent; + addr += bytes_sent; + } + } + + (*env)->ReleaseByteArrayElements (env, buf, p, 0); + +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Sets the specified option for a socket + */ +void +_javanet_set_option (JNIEnv * env, jobject this, jint option_id, jobject val) +{ +#ifndef WITHOUT_NETWORK + int fd; + int optval; + jclass cls; + jmethodID mid; + int address; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option(): no native file descriptor"); + return; + } + + /* We need a class object for all cases below */ + cls = (*env)->GetObjectClass (env, val); + if (cls == NULL) + return; + + /* Process the option request */ + result = TARGET_NATIVE_ERROR; + switch (option_id) + { + /* TCP_NODELAY case. val is a Boolean that tells us what to do */ + case SOCKOPT_TCP_NODELAY: + mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + /* Should be a 0 or a 1 */ + optval = (*env)->CallBooleanMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_TCP_NODELAY (fd, optval, + result); + break; + + /* SO_LINGER case. If val is a boolean, then it will always be set + to false indicating disable linger, otherwise it will be an + integer that contains the linger value */ + case SOCKOPT_SO_LINGER: + mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); + if (mid) + { + /* We are disabling linger */ + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 1, 0, + result); + } + else + { + /* Clear exception if thrown for failure to do method lookup + above */ + if ((*env)->ExceptionOccurred (env)) + (*env)->ExceptionClear (env); + + mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + optval = (*env)->CallIntMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_LINGER (fd, 0, optval, + result); + } + break; + + /* SO_TIMEOUT case. Val will be an integer with the new value */ + /* Not writable on Linux */ + case SOCKOPT_SO_TIMEOUT: +#ifdef SO_TIMEOUT + mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + optval = (*env)->CallIntMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_TIMEOUT (fd, optval, result); +#else + result = TARGET_NATIVE_OK; +#endif + break; + + case SOCKOPT_SO_SNDBUF: + case SOCKOPT_SO_RCVBUF: + mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + + optval = (*env)->CallIntMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + if (option_id == SOCKOPT_SO_SNDBUF) + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_SNDBUF (fd, optval, + result); + else + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_SO_RCDBUF (fd, optval, + result); + break; + + /* TTL case. Val with be an Integer with the new time to live value */ + case SOCKOPT_IP_TTL: + mid = (*env)->GetMethodID (env, cls, "intValue", "()I"); + if (!mid) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + optval = (*env)->CallIntMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_TTL (fd, optval, result); + break; + + /* Multicast Interface case - val is InetAddress object */ + case SOCKOPT_IP_MULTICAST_IF: + address = _javanet_get_netaddr (env, val); + + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_IP_MULTICAST_IF (fd, address, + result); + break; + + case SOCKOPT_SO_REUSEADDR: + mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + /* Should be a 0 or a 1 */ + optval = (*env)->CallBooleanMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_REUSE_ADDRESS (fd, optval, + result); + break; + + case SOCKOPT_SO_KEEPALIVE: + mid = (*env)->GetMethodID (env, cls, "booleanValue", "()Z"); + if (mid == NULL) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Internal error: _javanet_set_option()"); + return; + } + + /* Should be a 0 or a 1 */ + optval = (*env)->CallBooleanMethod (env, val, mid); + if ((*env)->ExceptionOccurred (env)) + return; + + TARGET_NATIVE_NETWORK_SOCKET_SET_OPTION_KEEP_ALIVE (fd, optval, result); + break; + + case SOCKOPT_SO_BINDADDR: + JCL_ThrowException (env, SOCKET_EXCEPTION, "This option cannot be set"); + break; + + default: + JCL_ThrowException (env, SOCKET_EXCEPTION, "Unrecognized option"); + return; + } + + /* Check to see if above operations succeeded */ + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +/*************************************************************************/ + +/* + * Retrieves the specified option values for a socket + */ +jobject +_javanet_get_option (JNIEnv * env, jobject this, jint option_id) +{ +#ifndef WITHOUT_NETWORK + int fd; + int flag, optval; + int address; + int result; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + "Internal error: _javanet_get_option(): no native file descriptor"); + return (0); + } + + /* Process the option requested */ + switch (option_id) + { + /* TCP_NODELAY case. Return a Boolean indicating on or off */ + case SOCKOPT_TCP_NODELAY: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_TCP_NODELAY (fd, optval, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + if (optval) + return (_javanet_create_boolean (env, JNI_TRUE)); + else + return (_javanet_create_boolean (env, JNI_FALSE)); + + break; + + /* SO_LINGER case. If disabled, return a Boolean object that represents + false, else return an Integer that is the value of SO_LINGER */ + case SOCKOPT_SO_LINGER: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_LINGER (fd, flag, optval, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + if (optval) + return (_javanet_create_integer (env, JNI_TRUE)); + else + return (_javanet_create_boolean (env, JNI_FALSE)); + + break; + + /* SO_TIMEOUT case. Return an Integer object with the timeout value */ + case SOCKOPT_SO_TIMEOUT: +#ifdef SO_TIMEOUT + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_TIMEOUT (fd, optval, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + return (_javanet_create_integer (env, optval)); +#else + JCL_ThrowException (env, SOCKET_EXCEPTION, + "SO_TIMEOUT not supported on this platform"); + return (0); +#endif /* not SO_TIMEOUT */ + break; + + case SOCKOPT_SO_SNDBUF: + case SOCKOPT_SO_RCVBUF: + if (option_id == SOCKOPT_SO_SNDBUF) + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_SNDBUF (fd, optval, + result); + else + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_SO_RCDBUF (fd, optval, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + return (_javanet_create_integer (env, optval)); + break; + + /* The TTL case. Return an Integer with the Time to Live value */ + case SOCKOPT_IP_TTL: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_TTL (fd, optval, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + return (_javanet_create_integer (env, optval)); + break; + + /* Multicast interface case */ + case SOCKOPT_IP_MULTICAST_IF: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_IP_MULTICAST_IF (fd, address, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + return (_javanet_create_inetaddress (env, address)); + break; + + case SOCKOPT_SO_BINDADDR: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_BIND_ADDRESS (fd, address, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + return (_javanet_create_inetaddress (env, address)); + break; + + case SOCKOPT_SO_REUSEADDR: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_REUSE_ADDRESS (fd, optval, + result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + if (optval) + return (_javanet_create_boolean (env, JNI_TRUE)); + else + return (_javanet_create_boolean (env, JNI_FALSE)); + + break; + + case SOCKOPT_SO_KEEPALIVE: + TARGET_NATIVE_NETWORK_SOCKET_GET_OPTION_KEEP_ALIVE (fd, optval, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (0); + } + + if (optval) + return (_javanet_create_boolean (env, JNI_TRUE)); + else + return (_javanet_create_boolean (env, JNI_FALSE)); + + break; + + default: + JCL_ThrowException (env, SOCKET_EXCEPTION, "No such option"); + return (0); + } + + return (0); +#else /* not WITHOUT_NETWORK */ +#endif /* not WITHOUT_NETWORK */ +} + +void +_javanet_shutdownInput (JNIEnv * env, jobject this) +{ + int fd; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor. */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + "Internal error: _javanet_get_option(): no native file descriptor"); + return; + } + + /* Shutdown input stream of socket. */ + if (shutdown (fd, SHUT_RD) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + "Can't shutdown input of socket"); + return; + } +} + +void +_javanet_shutdownOutput (JNIEnv * env, jobject this) +{ + int fd; + + assert (env != NULL); + assert ((*env) != NULL); + + /* Get the real file descriptor. */ + fd = _javanet_get_int_field (env, this, "native_fd"); + if (fd == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + "Internal error: _javanet_get_option(): no native file descriptor"); + return; + } + + /* Shutdown output stream of socket. */ + if (shutdown (fd, SHUT_WR) == -1) + { + JCL_ThrowException (env, SOCKET_EXCEPTION, + "Can't shutdown output of socket"); + return; + } +} + +/* end of file */ diff --git a/libjava/classpath/native/jni/java-net/javanet.h b/libjava/classpath/native/jni/java-net/javanet.h new file mode 100644 index 00000000000..7c77ea77f84 --- /dev/null +++ b/libjava/classpath/native/jni/java-net/javanet.h @@ -0,0 +1,109 @@ +/* javanet.h - Declarations for common functions for the java.net package + Copyright (C) 1998, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + + +#ifndef _JAVANET_LOADED +#define _JAVANET_LOADED + +#include <jni.h> + +/*************************************************************************/ + +/* + * Defined constants + */ + +/* Exception Classes */ +#define BIND_EXCEPTION "java/net/BindException" +#define IO_EXCEPTION "java/io/IOException" +#define SOCKET_EXCEPTION "java/net/SocketException" +#define UNKNOWN_HOST_EXCEPTION "java/net/UnknownHostException" + +/* Socket Option Identifiers - Don't change or binary compatibility with + the JDK will be broken! These also need to + be kept compatible with java.net.SocketOptions */ +#define SOCKOPT_TCP_NODELAY 1 +#define SOCKOPT_SO_BINDADDR 15 +#define SOCKOPT_SO_LINGER 128 +#define SOCKOPT_SO_TIMEOUT 4102 +#define SOCKOPT_SO_SNDBUF 4097 +#define SOCKOPT_SO_RCVBUF 4098 +#define SOCKOPT_SO_REUSEADDR 4 +#define SOCKOPT_IP_MULTICAST_IF 16 +#define SOCKOPT_SO_KEEPALIVE 8 + +/* Internal option identifiers. Not needed for JDK compatibility */ +#define SOCKOPT_IP_TTL 7777 + +/*************************************************************************/ + +/* + * Macros + */ + +/* Simple debug macro */ +#ifdef DEBUG +#define DBG(x) fprintf(stderr, (x)); +#else +#define DBG(x) +#endif + +/*************************************************************************/ + +/* + * Function Prototypes + */ + +extern int _javanet_get_int_field(JNIEnv *, jobject, const char *); +extern int _javanet_get_netaddr(JNIEnv *, jobject); +extern void _javanet_create(JNIEnv *, jobject, jboolean); +extern void _javanet_close(JNIEnv *, jobject, int); +extern void _javanet_connect(JNIEnv *, jobject, jobject, jint); +extern void _javanet_bind(JNIEnv *, jobject, jobject, jint, int); +extern void _javanet_listen(JNIEnv *, jobject, jint); +extern void _javanet_accept(JNIEnv *, jobject, jobject); +extern int _javanet_recvfrom(JNIEnv *, jobject, jarray, int, int, int *, int *); +extern void _javanet_sendto(JNIEnv *, jobject, jarray, int, int, int, int); +extern jobject _javanet_get_option(JNIEnv *, jobject, jint); +extern void _javanet_set_option(JNIEnv *, jobject, jint, jobject); +extern void _javanet_shutdownInput (JNIEnv *, jobject); +extern void _javanet_shutdownOutput (JNIEnv *, jobject); + +/*************************************************************************/ + +#endif /* not _JAVANET_H_LOADED */ + diff --git a/libjava/classpath/native/jni/java-nio/.cvsignore b/libjava/classpath/native/jni/java-nio/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/java-nio/Makefile.am b/libjava/classpath/native/jni/java-nio/Makefile.am new file mode 100644 index 00000000000..9785fee6d9b --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/Makefile.am @@ -0,0 +1,16 @@ +pkglib_LTLIBRARIES = libjavanio.la + +libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \ + gnu_java_nio_VMSelector.c \ + gnu_java_nio_channels_FileChannelImpl.c \ + gnu_java_nio_charset_iconv_IconvDecoder.c \ + gnu_java_nio_charset_iconv_IconvEncoder.c \ + java_nio_MappedByteBufferImpl.c \ + java_nio_VMDirectByteBuffer.c + +libjavanio_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \ + $(LTLIBICONV) + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMPipe.c b/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMPipe.c new file mode 100644 index 00000000000..369c5a3d650 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMPipe.c @@ -0,0 +1,56 @@ +/* gnu_java_nio_VMPipe.c - Native methods for PipeImpl class + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <errno.h> + +#include <jni.h> +#include <jcl.h> + +#include "gnu_java_nio_VMPipe.h" + +#define IO_EXCEPTION "java/io/IOException" + +JNIEXPORT void JNICALL +Java_gnu_java_nio_VMPipe_init (JNIEnv * env, + jclass cls __attribute__ ((__unused__)), + jobject self __attribute__ ((__unused__)), + jobject provider __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "gnu.java.nio.VMPipe.init(): not implemented"); +} diff --git a/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMSelector.c b/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMSelector.c new file mode 100644 index 00000000000..f8a40aa7a15 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/gnu_java_nio_VMSelector.c @@ -0,0 +1,296 @@ +/* gnu_java_nio_VMSelector.c - Native methods for SelectorImpl class + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "config.h" + +/* <sys/types.h> needs to be included on OSX before <sys/select.h> */ +#if defined(HAVE_SYS_TYPES_H) +#include <sys/types.h> +#endif + +#include <sys/select.h> +#include <sys/time.h> + +#include <string.h> + +#include <errno.h> + +#include <jni.h> +#include <jcl.h> + +#include "gnu_java_nio_VMSelector.h" + +/* Amount of characters in the error message buffer for strerror_r. */ +#define BUF_SIZE 250 + +void helper_put_filedescriptors (JNIEnv *, jintArray, fd_set *, int *); + +void helper_get_filedescriptors (JNIEnv *, jintArray *, fd_set *); + +void helper_reset (JNIEnv *, jintArray *); + +int +helper_select (JNIEnv *, jclass, jmethodID, + int, fd_set *, fd_set *, fd_set *, struct timeval *); + +void +helper_put_filedescriptors (JNIEnv * env, jintArray fdArray, fd_set * fds, + int *max_fd) +{ + jint *tmpFDArray = (*env)->GetIntArrayElements (env, fdArray, 0); + int size = (*env)->GetArrayLength (env, fdArray); + int index, fd; + + for (index = 0; index < size; index++) + { + fd = tmpFDArray[index]; + + if (fd > 0) + { + FD_SET (tmpFDArray[index], fds); + + if (tmpFDArray[index] > (*max_fd)) + (*max_fd) = tmpFDArray[index]; + } + } +} + +void +helper_get_filedescriptors (JNIEnv * env, jintArray * fdArray, fd_set * fds) +{ + jint *tmpFDArray = (*env)->GetIntArrayElements (env, fdArray, 0); + int size = (*env)->GetArrayLength (env, fdArray); + int index, fd; + + for (index = 0; index < size; index++) + { + fd = tmpFDArray[index]; + if (fd < 0 || !FD_ISSET (fd, fds)) + tmpFDArray[index] = 0; + } +} + +void +helper_reset (JNIEnv * env, jintArray * fdArray) +{ + jint *tmpFDArray = (*env)->GetIntArrayElements (env, fdArray, 0); + int size = (*env)->GetArrayLength (env, fdArray); + int index; + + for (index = 0; index < size; index++) + tmpFDArray[index] = 0; +} + +/* A wrapper for select() which ignores EINTR. + * Taken from gclib's posix.cc + */ +int +helper_select (JNIEnv * env, jclass thread_class, + jmethodID thread_interrupted, int n, fd_set * readfds, + fd_set * writefds, fd_set * exceptfds, struct timeval *timeout) +{ +#ifdef HAVE_SYS_SELECT_H + /* If we have a timeout, compute the absolute ending time. */ + struct timeval end, delay, after; + int r; + + if (timeout) + { + gettimeofday (&end, NULL); + + end.tv_usec += timeout->tv_usec; + + if (end.tv_usec >= 1000000) + { + ++end.tv_sec; + end.tv_usec -= 1000000; + } + + end.tv_sec += timeout->tv_sec; + delay = *timeout; + } + else + { + /* Placate compiler. */ + delay.tv_sec = delay.tv_usec = 0; + } + + while (1) + { + r = select (n, readfds, writefds, exceptfds, timeout ? &delay : NULL); + + if (r < 0 && errno != EINTR) + return -errno; + else if (r >= 0) + return r; + + /* Here we know we got EINTR. */ + if ((*env)-> + CallStaticBooleanMethod (env, thread_class, thread_interrupted)) + { + return -EINTR; + } + + if (timeout) + { + gettimeofday (&after, NULL); + + /* Now compute new timeout argument. */ + delay.tv_usec = end.tv_usec - after.tv_usec; + delay.tv_sec = end.tv_sec - after.tv_sec; + + if (delay.tv_usec < 0) + { + --delay.tv_sec; + delay.tv_usec += 1000000; + } + + if (delay.tv_sec < 0) + { + /* We assume that the user wants a valid select() call + * more than precise timing. So if we get a series of + * EINTR we just keep trying with delay 0 until we get a + * valid result. + */ + delay.tv_sec = 0; + } + } + } +#else /* HAVE_SYS_SELECT_H */ + return 0; +#endif + +} + +JNIEXPORT jint JNICALL +Java_gnu_java_nio_VMSelector_select (JNIEnv * env, + jclass obj __attribute__ ((__unused__)), + jintArray read, + jintArray write, + jintArray except, jlong timeout) +{ + jint result; + jclass thread_class = (*env)->FindClass (env, "java/lang/Thread"); + jmethodID thread_current_thread = + (*env)->GetStaticMethodID (env, thread_class, "currentThread", + "()Ljava/lang/Thread;"); + jmethodID thread_interrupt = + (*env)->GetMethodID (env, thread_class, "interrupt", "()V"); + jmethodID thread_interrupted = + (*env)->GetStaticMethodID (env, thread_class, "interrupted", "()Z"); + jobject current_thread; + int max_fd = 0; + fd_set read_fds; + fd_set write_fds; + fd_set except_fds; + struct timeval real_time_data; + struct timeval *time_data = NULL; + char message_buf[BUF_SIZE + 1]; + + /* If a legal timeout value isn't given, use NULL. + * This means an infinite timeout. The specification + * also says that a zero timeout should be treated + * as infinite. Otherwise (if the timeout value is legal), + * fill our timeval struct and use it for the select. + */ + if (timeout > 0) + { + real_time_data.tv_sec = timeout / 1000; + real_time_data.tv_usec = (timeout % 1000) * 1000; + time_data = &real_time_data; + } + + /* Reset all fd_set structures */ + FD_ZERO (&read_fds); + FD_ZERO (&write_fds); + FD_ZERO (&except_fds); + + /* Fill the fd_set data structures for the _Jv_select() call. */ + helper_put_filedescriptors (env, read, &read_fds, &max_fd); + helper_put_filedescriptors (env, write, &write_fds, &max_fd); + helper_put_filedescriptors (env, except, &except_fds, &max_fd); + + /* Actually do the select */ + result = + helper_select (env, thread_class, thread_interrupted, max_fd + 1, + &read_fds, &write_fds, &except_fds, time_data); + + if (result == -EINTR) + { + /* The behavior of JRE 1.4.1 is that no exception is thrown + * when the thread is interrupted, but the thread's interrupt + * status is set. Clear all of our select sets and return 0, + * indicating that nothing was selected. + */ + current_thread = + (*env)->CallStaticObjectMethod (env, thread_class, + thread_current_thread); + (*env)->CallVoidMethod (env, current_thread, thread_interrupt); + + helper_reset (env, read); + helper_reset (env, write); + helper_reset (env, except); + + return 0; + } + + if (result < 0) + { + + int errorcode = -result; + + if (strerror_r (errorcode, message_buf, BUF_SIZE)) + { + /* This would mean that message_buf was to small + * to hold the error message. + */ + JCL_ThrowException (env, "java/lang/InternalError", + "Not enough space in message buffer."); + return 0; + } + + JCL_ThrowException (env, "java/io/IOException", message_buf); + return 0; + } + + /* Set the file descriptors according to the values returned from select(). */ + helper_get_filedescriptors (env, read, &read_fds); + helper_get_filedescriptors (env, write, &write_fds); + helper_get_filedescriptors (env, except, &except_fds); + + return result; +} diff --git a/libjava/classpath/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c b/libjava/classpath/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c new file mode 100644 index 00000000000..743e12a8f30 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c @@ -0,0 +1,793 @@ +/* gnu_java_nio_channels_FileChannelImpl.c - + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#include <stdlib.h> +#include <errno.h> + +#include <jni.h> +#include <jcl.h> + +#include "target_native.h" +#ifndef WITHOUT_FILESYSTEM +#include "target_native_file.h" +#endif +#include "target_native_math_int.h" + +#include "gnu_java_nio_channels_FileChannelImpl.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H */ + +/* These values must be kept in sync with FileChannelImpl.java. */ +#define FILECHANNELIMPL_READ 1 +#define FILECHANNELIMPL_WRITE 2 +#define FILECHANNELIMPL_APPEND 4 + +/* These values must be kept in sync with FileChannelImpl.java. */ +/* #define FILECHANNELIMPL_FILESEEK_SET 0 */ +/* #define FILECHANNELIMPL_FILESEEK_CUR 1 */ +/* #define FILECHANNELIMPL_FILESEEK_END 2 */ + +#define FILECHANNELIMPL_FILEOPEN_FLAG_READ 1 +#define FILECHANNELIMPL_FILEOPEN_FLAG_WRITE 2 +#define FILECHANNELIMPL_FILEOPEN_FLAG_APPEND 4 +#define FILECHANNELIMPL_FILEOPEN_FLAG_EXCL 8 +#define FILECHANNELIMPL_FILEOPEN_FLAG_SYNC 16 +#define FILECHANNELIMPL_FILEOPEN_FLAG_DSYNC 32 + +#define IO_EXCEPTION "java/io/IOException" + +/* FIXME: This can't be right. Need converter macros. */ +#define CONVERT_JLONG_TO_INT(x) TARGET_NATIVE_MATH_INT_INT64_TO_INT32(x) +#define CONVERT_INT_TO_JLONG(x) TARGET_NATIVE_MATH_INT_INT32_TO_INT64(x) + +/* FIXME: This can't be right. Need converter macros. */ +#define CONVERT_JLONG_TO_OFF_T(x) TARGET_NATIVE_MATH_INT_INT64_TO_INT32(x) +#define CONVERT_OFF_T_TO_JLONG(x) TARGET_NATIVE_MATH_INT_INT32_TO_INT64(x) + +/* FIXME: This can't be right. Need converter macros */ +#define CONVERT_JINT_TO_INT(x) ((int)(x & 0xFFFFFFFF)) +#define CONVERT_INT_TO_JINT(x) ((int)(x & 0xFFFFFFFF)) + +/* FIXME: This can't be right. Need converter macros. */ +#define CONVERT_SSIZE_T_TO_JINT(x) ((jint)(x & 0xFFFFFFFF)) +#define CONVERT_JINT_TO_SSIZE_T(x) (x) + +/* cached fieldID of gnu.java.nio.channels.FileChannelImpl.fd */ +static jfieldID native_fd_fieldID; + +static jint +get_native_fd (JNIEnv * env, jobject obj) +{ + return (*env)->GetIntField (env, obj, native_fd_fieldID); +} + +/* + * Library initialization routine. Called as part of java.io.FileDescriptor + * static initialization. + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_init (JNIEnv * env, jclass clazz) +{ + jclass clazz_fc; + jfieldID field; + jmethodID constructor; + jobject obj; + + /* Initialize native_fd_fieldID so we only compute it once! */ + clazz_fc = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl"); + if (!clazz_fc) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error"); + return; + } + + field = (*env)->GetFieldID (env, clazz_fc, "fd", "I"); + if (!field) + { + JCL_ThrowException (env, IO_EXCEPTION, "Internal error"); + return; + } + + native_fd_fieldID = field; + + constructor = (*env)->GetMethodID (env, clazz, "<init>", "(II)V"); + if (!constructor) + return; + +#define INIT_FIELD(FIELDNAME, FDVALUE, MODE) \ + field = (*env)->GetStaticFieldID (env, clazz, FIELDNAME, \ + "Lgnu/java/nio/channels/FileChannelImpl;"); \ + if (! field) \ + return; \ + obj = (*env)->NewObject (env, clazz, constructor, FDVALUE, MODE); \ + if (! obj) \ + return; \ + (*env)->SetStaticObjectField (env, clazz, field, obj); \ + if ((*env)->ExceptionOccurred (env)) \ + return; + + INIT_FIELD ("in", 0, FILECHANNELIMPL_READ); + INIT_FIELD ("out", 1, FILECHANNELIMPL_WRITE); + INIT_FIELD ("err", 2, FILECHANNELIMPL_WRITE); + +#undef INIT_FIELD +} + +/* + * Open the specified file and return a native file descriptor + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_open (JNIEnv * env, + jobject obj + __attribute__ ((__unused__)), + jstring name, jint mode) +{ + const char *filename; + int flags; + int permissions; + int native_fd; + int result; + + filename = JCL_jstring_to_cstring (env, name); + if (filename == NULL) + return (-1); /* Exception will already have been thrown */ + + /* get file/permission flags for open() */ + if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_READ) + && (mode & FILECHANNELIMPL_FILEOPEN_FLAG_WRITE)) + { + /* read/write */ + flags = + TARGET_NATIVE_FILE_FILEFLAG_CREATE | + TARGET_NATIVE_FILE_FILEFLAG_READWRITE; + permissions = TARGET_NATIVE_FILE_FILEPERMISSION_NORMAL; + } + else if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_READ)) + { + /* read */ + flags = TARGET_NATIVE_FILE_FILEFLAG_READ; + permissions = TARGET_NATIVE_FILE_FILEPERMISSION_NORMAL; + } + else + { + /* write */ + flags = + TARGET_NATIVE_FILE_FILEFLAG_CREATE | + TARGET_NATIVE_FILE_FILEFLAG_WRITE; + if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_APPEND)) + { + flags |= TARGET_NATIVE_FILE_FILEFLAG_APPEND; + } + else + { + flags |= TARGET_NATIVE_FILE_FILEFLAG_TRUNCATE; + } + permissions = TARGET_NATIVE_FILE_FILEPERMISSION_NORMAL; + } + + if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_SYNC)) + { + flags |= TARGET_NATIVE_FILE_FILEFLAG_SYNC; + } + + if ((mode & FILECHANNELIMPL_FILEOPEN_FLAG_DSYNC)) + { + flags |= TARGET_NATIVE_FILE_FILEFLAG_DSYNC; + } +#ifdef O_BINARY + flags |= TARGET_NATIVE_FILE_FILEFLAG_BINARY; +#endif + + TARGET_NATIVE_FILE_OPEN (filename, native_fd, flags, permissions, result); + JCL_free_cstring (env, name, filename); + + if (result != TARGET_NATIVE_OK) + { + /* We can only throw FileNotFoundException. */ + JCL_ThrowException (env, + "java/io/FileNotFoundException", + TARGET_NATIVE_LAST_ERROR_STRING ()); + return TARGET_NATIVE_MATH_INT_INT64_CONST_MINUS_1; + } + + return native_fd; +} + +/* + * Closes the specified file descriptor and return status code. + * Exception on error + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_implCloseChannel (JNIEnv * env, + jobject obj) +{ + int native_fd; + int result; + + native_fd = get_native_fd (env, obj); + + TARGET_NATIVE_FILE_CLOSE (native_fd, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + } +} + +/* + * Return number of bytes that can be read from the file w/o blocking. + * Exception on error + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_available (JNIEnv * env, + jobject obj) +{ + int native_fd; + jlong bytes_available; + int result; + + native_fd = get_native_fd (env, obj); + + TARGET_NATIVE_FILE_AVAILABLE (native_fd, bytes_available, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return 0; + } + + /* FIXME NYI ??? why only jint and not jlong? */ + return TARGET_NATIVE_MATH_INT_INT64_TO_INT32 (bytes_available); +} + +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_size (JNIEnv * env, jobject obj) +{ + int native_fd; + jlong file_size; + int result; + + native_fd = get_native_fd (env, obj); + + TARGET_NATIVE_FILE_SIZE (native_fd, file_size, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return TARGET_NATIVE_MATH_INT_INT64_CONST_MINUS_1; + } + + return file_size; +} + +/* + * Return the current position of the file pointer + * Exception on error + */ +JNIEXPORT jlong JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_implPosition (JNIEnv * env, + jobject obj) +{ + int native_fd; + jlong current_offset; + int result; + + native_fd = get_native_fd (env, obj); + + TARGET_NATIVE_FILE_TELL (native_fd, current_offset, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return TARGET_NATIVE_MATH_INT_INT64_CONST_MINUS_1; + } + + return current_offset; +} + +/* + * Wrapper around lseek call. Return new file position + * Exception on error + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_seek (JNIEnv * env, jobject obj, + jlong offset) +{ + int native_fd; + jlong new_offset; + int result; + + native_fd = get_native_fd (env, obj); + +#if 0 + /* Should there be such an exception? All native layer macros should + be accepting 64bit-values if needed. It some target is not able + to handle such values it should simply operate with 32bit-values + and convert 64bit-values appriopated. In this case I assume + problems should not occurre: if some specific target is not able + to handle 64bit-values the system is limited to 32bit at all, thus + the application can not do a seek() or something else beyond the + 32bit limit. It this true? + */ + + /* FIXME: What do we do if offset > the max value of off_t on this 32bit + * system? How do we detect that and what do we do? */ + if (CONVERT_OFF_T_TO_JLONG (native_offset) != offset) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Cannot represent position correctly on this system"); + } +#endif /* 0 */ + + result = TARGET_NATIVE_ERROR; + new_offset = TARGET_NATIVE_MATH_INT_INT64_CONST_MINUS_1; + TARGET_NATIVE_FILE_SEEK_BEGIN (native_fd, offset, new_offset, result); + + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + } +} + +/* + * Set the length of the file + * Exception on error + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_implTruncate (JNIEnv * env, + jobject obj, + jlong len) +{ + int native_fd; + jlong file_size; + int bytes_written; + jlong save_offset, new_offset; + char data; + int result; + + native_fd = get_native_fd (env, obj); + +#if 0 + /* Should there be such an exception? All native layer macros should + be accepting 64bit-values if needed. It some target is not able + to handle such values it should simply operate with 32bit-values + and convert 64bit-values appriopated. In this case I assume + problems should not occurre: if some specific target is not able + to handle 64bit-values the system is limited to 32bit at all, thus + the application can not do a seek() or something else beyond the + 32bit limit. It this true? + */ + + /* FIXME: What do we do if len > the max value of off_t on this 32bit + * system? How do we detect that and what do we do? */ + if (CONVERT_OFF_T_TO_JLONG (native_len) != len) + { + JCL_ThrowException (env, IO_EXCEPTION, + "Cannot represent position correctly on this system"); + return; + } +#endif /* 0 */ + + /* get file size */ + TARGET_NATIVE_FILE_SIZE (native_fd, file_size, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + /* Save off current position */ + TARGET_NATIVE_FILE_TELL (native_fd, save_offset, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + if (TARGET_NATIVE_MATH_INT_INT64_LT (file_size, len)) + { + /* File is too short -- seek to one byte short of where we want, + * then write a byte */ + + /* move to position n-1 */ + TARGET_NATIVE_FILE_SEEK_BEGIN (native_fd, + TARGET_NATIVE_MATH_INT_INT64_SUB (len, + 1), + new_offset, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + /* write a byte + Note: This will fail if we somehow get here in read only mode + * That shouldn't happen */ + data = '\0'; + TARGET_NATIVE_FILE_WRITE (native_fd, &data, 1, bytes_written, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + + /* Reposition file pointer to where we started if not beyond new len. */ + if (TARGET_NATIVE_MATH_INT_INT64_LT (save_offset, len)) + { + TARGET_NATIVE_FILE_SEEK_BEGIN (native_fd, save_offset, + new_offset, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + } + else if (TARGET_NATIVE_MATH_INT_INT64_GT (file_size, len)) + { + /* File is too long - use ftruncate if available */ +#ifdef HAVE_FTRUNCATE + TARGET_NATIVE_FILE_TRUNCATE (native_fd, len, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } +#else /* HAVE_FTRUNCATE */ + /* FIXME: Probably operation isn't supported, but this exception + * is too harsh as it will probably crash the program without need + JCL_ThrowException(env, "java/lang/UnsupportedOperationException", + "not implemented - can't shorten files on this platform"); + */ + JCL_ThrowException (env, IO_EXCEPTION, "Unable to shorten file length"); +#endif /* HAVE_FTRUNCATE */ + + /* Reposition file pointer when it now is beyond the end of file. */ + if (TARGET_NATIVE_MATH_INT_INT64_GT (save_offset, len)) + { + TARGET_NATIVE_FILE_SEEK_BEGIN (native_fd, len, new_offset, result); + if (result != TARGET_NATIVE_OK) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_mapImpl (JNIEnv * env, + jobject obj + __attribute__ ((__unused__)), jchar mode __attribute__ ((__unused__)), jlong position __attribute__ ((__unused__)), jint size __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.nio.FileChannelImpl.nio_mmap_file(): not implemented"); + return 0; +} + +/* + * Read a single byte from the file descriptor + * Return byte read or -1 on eof, exception on error + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_read__ (JNIEnv * env, jobject obj) +{ + int native_fd; + char data; + ssize_t bytes_read; + int result; + + native_fd = get_native_fd (env, obj); + + bytes_read = 0; + do + { + TARGET_NATIVE_FILE_READ (native_fd, &data, 1, bytes_read, result); + if ((result == TARGET_NATIVE_OK) && (bytes_read == 0)) + { + return (-1); + } + if ((result != TARGET_NATIVE_OK) + && (TARGET_NATIVE_LAST_ERROR () != + TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return (-1); + } + } + while (result != TARGET_NATIVE_OK); + + return ((jint) (data & 0xFF)); +} + +/* + * Reads to a byte buffer from the specified file descriptor + * Return number of bytes read or -1 on eof, exception on error + */ +JNIEXPORT jint JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_read___3BII (JNIEnv * env, + jobject obj, + jbyteArray buffer, + jint offset, + jint length) +{ + int native_fd; + jbyte *bufptr; + ssize_t bytes_read; + ssize_t n; + int result; + + native_fd = get_native_fd (env, obj); + + /* Must return 0 if an attempt is made to read 0 bytes. */ + if (length == 0) + return 0; + + if (offset < 0) + { + JCL_ThrowException (env, IO_EXCEPTION, "negative offset"); + return -1; + } + + bufptr = (*env)->GetByteArrayElements (env, buffer, 0); + if (!bufptr) + { + JCL_ThrowException (env, IO_EXCEPTION, "Unexpected JNI error"); + return (-1); + } + + if (length + offset > (*env)->GetArrayLength (env, buffer)) + { + JCL_ThrowException (env, IO_EXCEPTION, + "length + offset > buffer.length"); + return -1; + } + + bytes_read = 0; + do + { + TARGET_NATIVE_FILE_READ (native_fd, (bufptr + offset + bytes_read), + (length - bytes_read), n, result); + if ((result == TARGET_NATIVE_OK) && (n == 0)) + { + (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); + if (bytes_read == 0) + return -1; /* Signal end of file to Java */ + else + return CONVERT_SSIZE_T_TO_JINT (bytes_read); + } + if ((result != TARGET_NATIVE_OK) + && (TARGET_NATIVE_LAST_ERROR () != + TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); + return -1; + } + if (result == TARGET_NATIVE_OK) + bytes_read += n; + } + while (bytes_read < 1); + + (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); + return CONVERT_SSIZE_T_TO_JINT (bytes_read); +} + +/* + * Writes a single byte to the specified file descriptor + * Return status code, exception on error + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_write__I (JNIEnv * env, + jobject obj, jint b) +{ + int native_fd; + char native_data; + ssize_t bytes_written; + int result; + + native_fd = get_native_fd (env, obj); + native_data = (char) (CONVERT_JINT_TO_INT (b) & 0xFF); + + do + { + TARGET_NATIVE_FILE_WRITE (native_fd, &native_data, 1, bytes_written, + result); + if ((result != TARGET_NATIVE_OK) + && (TARGET_NATIVE_LAST_ERROR () != + TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + return; + } + } + while (result != TARGET_NATIVE_OK); +} + +/* + * Copies all parts of a file to disk. + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_force (JNIEnv * env, + jobject obj) +{ + int native_fd; + int result; + native_fd = get_native_fd (env, obj); + TARGET_NATIVE_FILE_FSYNC (native_fd, result); + if (result != TARGET_NATIVE_OK) + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); +} + +/* + * Writes a byte buffer to the specified file descriptor + * Return status code, exception on error + */ +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_write___3BII (JNIEnv * env, + jobject obj, + jbyteArray buffer, + jint offset, + jint length) +{ + int native_fd; + jbyte *bufptr; + ssize_t bytes_written; + ssize_t n; + int result; + + native_fd = get_native_fd (env, obj); + + /* Just return if an attempt is made to write 0 bytes. */ + if (length == 0) + return; + + bufptr = (*env)->GetByteArrayElements (env, buffer, 0); + if (!bufptr) + { + JCL_ThrowException (env, IO_EXCEPTION, "Unexpected JNI error"); + return; + } + + bytes_written = 0; + while (bytes_written < CONVERT_JINT_TO_SSIZE_T (length)) + { + TARGET_NATIVE_FILE_WRITE (native_fd, (bufptr + offset + bytes_written), + (length - bytes_written), n, result); + if ((result != TARGET_NATIVE_OK) + && (TARGET_NATIVE_LAST_ERROR () != + TARGET_NATIVE_ERROR_INTERRUPT_FUNCTION_CALL)) + { + JCL_ThrowException (env, IO_EXCEPTION, + TARGET_NATIVE_LAST_ERROR_STRING ()); + (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); + return; + } + if (result == TARGET_NATIVE_OK) + bytes_written += n; + } + + (*env)->ReleaseByteArrayElements (env, buffer, bufptr, 0); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_lock (JNIEnv *env, jobject obj, + jlong position, jlong size, + jboolean shared, jboolean wait) +{ +#ifdef HAVE_FCNTL + int fd = get_native_fd (env, obj); + int cmd = wait ? F_SETLKW : F_SETLK; + struct flock flock; + int ret; + + flock.l_type = shared ? F_RDLCK : F_WRLCK; + flock.l_whence = SEEK_SET; + flock.l_start = (off_t) position; + flock.l_len = (off_t) size; + + ret = fcntl (fd, cmd, &flock); + if (ret) + { + /* Linux man pages for fcntl state that errno might be either + EACCES or EAGAIN if we try F_SETLK, and another process has + an overlapping lock. */ + if (errno != EACCES && errno != EAGAIN) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + } + return JNI_FALSE; + } + return JNI_TRUE; +#else + (void) obj; + (void) position; + (void) size; + (void) shared; + (void) wait; + JCL_ThrowException (env, "java/lang/UnsupportedOperationException", + "file locks not implemented on this platform"); + return JNI_FALSE; +#endif /* HAVE_FCNTL */ +} + +JNIEXPORT void JNICALL +Java_gnu_java_nio_channels_FileChannelImpl_unlock (JNIEnv *env, + jobject obj, + jlong position, + jlong length) +{ +#ifdef HAVE_FCNTL + int fd = get_native_fd (env, obj); + struct flock flock; + int ret; + + flock.l_type = F_UNLCK; + flock.l_whence = SEEK_SET; + flock.l_start = (off_t) position; + flock.l_len = (off_t) length; + + ret = fcntl (fd, F_SETLK, &flock); + if (ret) + { + JCL_ThrowException (env, IO_EXCEPTION, strerror (errno)); + } +#else + (void) obj; + (void) position; + (void) length; + JCL_ThrowException (env, "java/lang/UnsupportedOperationException", + "file locks not implemented on this platform"); +#endif /* HAVE_FCNTL */ +} diff --git a/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvDecoder.c b/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvDecoder.c new file mode 100644 index 00000000000..8c3f83accff --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvDecoder.c @@ -0,0 +1,219 @@ +/* gnu_java_nio_charset_iconv_IconvDecoder.c -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <jcl.h> + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#if defined(HAVE_ICONV) +#include <iconv.h> +#endif + +#include "gnu_java_nio_charset_iconv_IconvDecoder.h" + +static void createRawData (JNIEnv * env, jobject obj, void *ptr); +static void *getData (JNIEnv * env, jobject obj); + +static jfieldID infid = NULL; +static jfieldID outfid = NULL; + +/* Union used for type punning. */ +union char_union +{ + jbyte **jb; + jchar **jc; + char **c; +}; + +JNIEXPORT void JNICALL +Java_gnu_java_nio_charset_iconv_IconvDecoder_openIconv (JNIEnv * env, + jobject obj, + jstring jname) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object; + jclass cls; + + const char *name = JCL_jstring_to_cstring (env, jname); + if (name == NULL) + return; + + /* Cache fieldIDs for use in decode function. */ + if (infid == NULL || outfid == NULL) + { + cls = (*env)->GetObjectClass (env, obj); + infid = (*env)->GetFieldID (env, cls, "inremaining", "I"); + assert (infid != 0); + outfid = (*env)->GetFieldID (env, cls, "outremaining", "I"); + assert (outfid != 0); + } + + /* to java from "name", native java format depends on endianness */ +#ifdef WORDS_BIGENDIAN + iconv_object = iconv_open ("UTF-16BE", name); +#else + iconv_object = iconv_open ("UTF-16LE", name); +#endif + + JCL_free_cstring (env, jname, name); + if ((long) iconv_object == -1L) + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Charset not available"); + return; + } + createRawData (env, obj, (void *) iconv_object); +#else + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "iconv not available"); +#endif +} + +JNIEXPORT jint JNICALL +Java_gnu_java_nio_charset_iconv_IconvDecoder_decode (JNIEnv * env, + jobject obj, + jbyteArray inArr, + jcharArray outArr, + jint posIn, jint remIn, + jint posOut, jint remOut) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object = getData (env, obj); + size_t retval; + union char_union in, out; + jbyte *input, *inputcopy; + jchar *output, *outputcopy; + size_t lenIn = (size_t) remIn; + size_t lenOut = (size_t) remOut * 2; + + inputcopy = input = (*env)->GetByteArrayElements (env, inArr, 0); + outputcopy = output = (*env)->GetCharArrayElements (env, outArr, 0); + + input += posIn; + output += posOut; + + in.jb = &input; + out.jc = &output; + retval = iconv (iconv_object, (ICONV_CONST char **) in.c, &lenIn, + out.c, &lenOut); + + /* XXX: Do we need to relase the input array? It's not modified. */ + (*env)->ReleaseByteArrayElements (env, inArr, inputcopy, 0); + (*env)->ReleaseCharArrayElements (env, outArr, outputcopy, 0); + + if (retval == (size_t) (-1)) + { + if (errno == EILSEQ || errno == EINVAL) + retval = 1; + else + retval = 0; + } + else + retval = 0; + + (*env)->SetIntField (env, obj, infid, (jint) lenIn); + (*env)->SetIntField (env, obj, outfid, (jint) (lenOut >> 1)); + + return (jint) retval; +#else + return -1; +#endif +} + +JNIEXPORT void JNICALL +Java_gnu_java_nio_charset_iconv_IconvDecoder_closeIconv (JNIEnv * env, + jobject obj) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object; + iconv_object = getData (env, obj); + iconv_close (iconv_object); +#endif +} + + +static void +createRawData (JNIEnv * env, jobject obj, void *ptr) +{ + jclass cls; + jmethodID method; + jobject data; + jfieldID data_fid; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/RawData;"); + assert (data_fid != 0); + +#ifdef POINTERS_ARE_64BIT + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + method = (*env)->GetMethodID (env, cls, "<init>", "(J)V"); + data = (*env)->NewObject (env, cls, method, (jlong) ptr); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + method = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); + data = (*env)->NewObject (env, cls, method, (jint) ptr); +#endif + + (*env)->SetObjectField (env, obj, data_fid, data); +} + +static void * +getData (JNIEnv * env, jobject obj) +{ + jclass cls; + jfieldID field; + jfieldID data_fid; + jobject data; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/RawData;"); + assert (data_fid != 0); + data = (*env)->GetObjectField (env, obj, data_fid); + +#if SIZEOF_VOID_P == 8 + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + field = (*env)->GetFieldID (env, cls, "data", "J"); + return (void *) (*env)->GetLongField (env, data, field); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + field = (*env)->GetFieldID (env, cls, "data", "I"); + return (void *) (*env)->GetIntField (env, data, field); +#endif +} diff --git a/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvEncoder.c b/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvEncoder.c new file mode 100644 index 00000000000..cd5d48656f7 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/gnu_java_nio_charset_iconv_IconvEncoder.c @@ -0,0 +1,219 @@ +/* gnu_java_nio_charset_iconv_IconvEncoder.c -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <jcl.h> + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#if defined(HAVE_ICONV) +#include <iconv.h> +#endif + +#include "gnu_java_nio_charset_iconv_IconvEncoder.h" + +static void createRawData (JNIEnv * env, jobject obj, void *ptr); +static void *getData (JNIEnv * env, jobject obj); + +static jfieldID infid = NULL; +static jfieldID outfid = NULL; + +/* Union used for type punning. */ +union char_union +{ + jbyte **jb; + jchar **jc; + char **c; +}; + +JNIEXPORT void JNICALL +Java_gnu_java_nio_charset_iconv_IconvEncoder_openIconv (JNIEnv * env, + jobject obj, + jstring jname) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object; + jclass cls; + + const char *name = JCL_jstring_to_cstring (env, jname); + if (name == NULL) + return; + + /* Cache fieldIDs for use in encode function. */ + if (infid == NULL || outfid == NULL) + { + cls = (*env)->GetObjectClass (env, obj); + infid = (*env)->GetFieldID (env, cls, "inremaining", "I"); + assert (infid != 0); + outfid = (*env)->GetFieldID (env, cls, "outremaining", "I"); + assert (outfid != 0); + } + + /* to "name" from java, native java format depends on endianness */ +#ifdef WORDS_BIGENDIAN + iconv_object = iconv_open (name, "UTF-16BE"); +#else + iconv_object = iconv_open (name, "UTF-16LE"); +#endif + + JCL_free_cstring (env, jname, name); + if ((long) iconv_object == -1L) + { + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "Charset not available"); + return; + } + createRawData (env, obj, (void *) iconv_object); +#else + JCL_ThrowException (env, "java/lang/IllegalArgumentException", + "iconv not available"); +#endif +} + +JNIEXPORT jint JNICALL +Java_gnu_java_nio_charset_iconv_IconvEncoder_encode (JNIEnv * env, + jobject obj, + jcharArray inArr, + jbyteArray outArr, + jint posIn, jint remIn, + jint posOut, jint remOut) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object = getData (env, obj); + size_t retval; + union char_union in, out; + jchar *input, *inputcopy; + jbyte *output, *outputcopy; + size_t lenIn = (size_t) remIn * 2; + size_t lenOut = (size_t) remOut; + + inputcopy = input = (*env)->GetCharArrayElements (env, inArr, 0); + outputcopy = output = (*env)->GetByteArrayElements (env, outArr, 0); + + input += posIn; + output += posOut; + + in.jc = &input; + out.jb = &output; + retval = iconv (iconv_object, (ICONV_CONST char **) in.c, &lenIn, + out.c, &lenOut); + + /* XXX: Do we need to relase the input array? It's not modified. */ + (*env)->ReleaseCharArrayElements (env, inArr, inputcopy, 0); + (*env)->ReleaseByteArrayElements (env, outArr, outputcopy, 0); + + if (retval == (size_t) (-1)) + { + if (errno == EILSEQ || errno == EINVAL) + retval = 1; + else + retval = 0; + } + else + retval = 0; + + (*env)->SetIntField (env, obj, infid, (jint) (lenIn >> 1)); + (*env)->SetIntField (env, obj, outfid, (jint) lenOut); + + return (jint) retval; +#else + return -1; +#endif +} + +JNIEXPORT void JNICALL +Java_gnu_java_nio_charset_iconv_IconvEncoder_closeIconv (JNIEnv * env, + jobject obj) +{ +#if defined(HAVE_ICONV) + iconv_t iconv_object; + iconv_object = getData (env, obj); + iconv_close (iconv_object); +#endif +} + + +static void +createRawData (JNIEnv * env, jobject obj, void *ptr) +{ + jclass cls; + jmethodID method; + jobject data; + jfieldID data_fid; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/RawData;"); + assert (data_fid != 0); + +#ifdef POINTERS_ARE_64BIT + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + method = (*env)->GetMethodID (env, cls, "<init>", "(J)V"); + data = (*env)->NewObject (env, cls, method, (jlong) ptr); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + method = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); + data = (*env)->NewObject (env, cls, method, (jint) ptr); +#endif + + (*env)->SetObjectField (env, obj, data_fid, data); +} + +static void * +getData (JNIEnv * env, jobject obj) +{ + jclass cls; + jfieldID field; + jfieldID data_fid; + jobject data; + + cls = (*env)->GetObjectClass (env, obj); + data_fid = (*env)->GetFieldID (env, cls, "data", "Lgnu/classpath/RawData;"); + assert (data_fid != 0); + data = (*env)->GetObjectField (env, obj, data_fid); + +#if SIZEOF_VOID_P == 8 + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + field = (*env)->GetFieldID (env, cls, "data", "J"); + return (void *) (*env)->GetLongField (env, data, field); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + field = (*env)->GetFieldID (env, cls, "data", "I"); + return (void *) (*env)->GetIntField (env, data, field); +#endif +} diff --git a/libjava/classpath/native/jni/java-nio/java_nio.c b/libjava/classpath/native/jni/java-nio/java_nio.c new file mode 100644 index 00000000000..a25f38a6d2a --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/java_nio.c @@ -0,0 +1,328 @@ +/* java_nio.c - Native methods for gnu.java.nio.FileChannelImpl class + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +/* do not move; needed here because of some macro definitions */ +#include <config.h> + +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif + +#include <jni.h> +#include <jcl.h> + +#include "target_native.h" +#ifndef WITHOUT_NETWORK +#include "target_native_network.h" +#endif /* WITHOUT_NETWORK */ + +#include "java_nio_channels_FileChannelImpl.h" + +#include "javaio.h" + +#define NIO_DEBUG(X) /* no debug */ +//#define NIO_DEBUG(X) X + +/*************************************** + * + * File Channel implementation + * + *************/ + + +static char * +compare (int i, int lim, char *buffer) +{ + sprintf (buffer, "(%d >= %d)", i, lim); + return buffer; +} + +static inline int +convert_Int (int X) +{ + unsigned char *a = (unsigned char *) &X; + int res = + (((int) a[0]) << 24) + + (((int) a[1]) << 16) + (((int) a[2]) << 8) + (((int) a[3]) << 0); + return res; +} + +static inline jlong +convert_Long (jlong X) +{ + unsigned char *a = (unsigned char *) &X; + int res1 = + (((int) a[0]) << 24) + + (((int) a[1]) << 16) + (((int) a[2]) << 8) + (((int) a[3]) << 0); + int res2; + a += 4; + res2 = + (((int) a[0]) << 24) + + (((int) a[1]) << 16) + (((int) a[2]) << 8) + (((int) a[3]) << 0); + return ((jlong) res1) | ((jlong) res2) << 32LL; +} + +static inline short +convert_Short (short X) +{ + unsigned char *a = (unsigned char *) &X; + int res = (((int) a[2]) << 8) + (((int) a[3]) << 0); + return res; +} +static inline short +convert_Char (short X) +{ + unsigned char *a = (unsigned char *) &X; + int res = (((int) a[2]) << 8) + (((int) a[3]) << 0); + return res; +} + +static inline unsigned char +convert_Byte (unsigned char X) +{ + return X; +} + +static inline float +convert_Float (float X) +{ + return X; +} + +static inline double +convert_Double (double X) +{ + return X; +} + + +// Note: do to many get()'s on a buffer and you should throw a BufferUnderflowException +// Alas, I only found this out during testing.... + +#define READ_WRITE_MMAPED_FILE(TYPE,ELT) \ + \ +ELT Java_gnu_java_nio_MappedByteFileBuffer_nio_1read_1 ## TYPE ## _1file_1channel(JNIEnv *env, \ + jclass c, jobject b, \ + int index, int limit, jlong jaddress) \ +{ \ + char *address = *(void **) &jaddress; char buffer[128]; \ + if (index >= limit) JCL_ThrowException(env, "java/nio/BufferUnderflowException", compare(index,limit, buffer)); \ + NIO_DEBUG( fprintf(stderr, "READ:index = %d [0]=%c [1]=%c\n", index, address[0],address[1]); ) \ + address += index; \ + return convert_ ## TYPE (*(ELT *) address); \ +} \ + \ +void Java_gnu_java_nio_MappedByteFileBuffer_nio_1write_1 ## TYPE ## _1file_1channel(JNIEnv *env, \ + jclass c, jobject b, \ + int index, int limit, ELT value, jlong jaddress) \ +{ \ + \ + char *address = *(void **) &jaddress; char buffer[128]; \ + if (index >= limit) JCL_ThrowException(env, "java/nio/BufferUnderflowException", compare(index,limit, buffer)); \ +NIO_DEBUG( fprintf(stderr, "WRITE:index = %d [0]=%c [1]=%c\n", index, address[0],address[1]); ) \ + address += index; \ + *(ELT *) address = value; \ +} \ + \ +ELT Java_gnu_java_nio_MappedByteFileBuffer_nio_1get_1 ## TYPE(JNIEnv *env, jclass c, jobject b, \ + int index, int limit, jlong jaddress) \ +{ \ + fprintf(stderr, "unimplemented\n"); return 0; \ +} \ + \ +void Java_gnu_java_nio_MappedByteFileBuffer_nio_1put_1 ## TYPE(JNIEnv *env, jclass c, jobject b, \ + int index, int limit, \ + ELT value, jlong jaddress) \ +{ \ + fprintf(stderr, "unimplemented\n"); \ +} + +READ_WRITE_MMAPED_FILE (Byte, u_int8_t); +READ_WRITE_MMAPED_FILE (Char, u_int16_t); +READ_WRITE_MMAPED_FILE (Short, u_int16_t); +READ_WRITE_MMAPED_FILE (Int, u_int32_t); +READ_WRITE_MMAPED_FILE (Long, u_int64_t); +READ_WRITE_MMAPED_FILE (Float, float); +READ_WRITE_MMAPED_FILE (Double, double); + +u_int64_t +nio_mmap_file (jint fd, jlong pos, jint size, jint jflags) +{ +#ifdef HAVE_MMAP + u_int64_t ret = 0; + void *address; + + int flags = (jflags != 2) ? MAP_SHARED : MAP_PRIVATE; + int prot = PROT_READ; + + if (jflags == 1) + prot |= PROT_WRITE; + + // fprintf(stderr, "mapping file: %d\n", fd); + + address = mmap (0, size, prot, flags, fd, pos); + + if (address == (void *) -1) + { + perror ("mapping file failed"); + return 0; + } + + // fprintf(stderr, "address = %p, fd = %d, pos=%lld, size=%d\n", address, fd, pos, size); + + *(void **) &ret = address; + + return ret; +#else /* not HAVE_MMAP */ + return (TARGET_NATIVE_MATH_INT_INT64_CONST_0); +#endif /* not HAVE_MMAP */ +} + + +void +nio_msync (int fd, jlong jaddress, int size) +{ +#ifdef HAVE_MMAP + int res; + char *address = *(void **) &jaddress; + + // fprintf(stderr, "synchronizing with file (%p -> %d bytes (%s))\n", address, size, address); + + res = msync (address, size, MS_SYNC | MS_INVALIDATE); + + if (res == -1) + { + perror ("synchronize with file failed"); + } +#else /* not HAVE_MMAP */ +#endif /* not HAVE_MMAP */ +} + +void +nio_unmmap_file (int fd, jlong jaddress, int size) +{ +#ifdef HAVE_MMAP + int res = 0; + char *address = *(void **) &jaddress; + + // nio_msync(fd, jaddress, size); + + // fprintf(stderr, "unmapping (%p -> %d bytes)\n", address, size); + + res = munmap (address, size); + if (res == -1) + { + perror ("un-mapping file failed"); + } +#else /* not HAVE_MMAP */ +#endif /* not HAVE_MMAP */ +} + + +/*************************************** + * + * Socket Channel implementation + * + *************/ + +/*************************************************************************/ + +/* + * Returns a 32 bit Internet address for the passed in InetAddress object + * Ronald: This is a verbatim copy from javanet.c. + * It's a copy to avoid a link error in orp. + */ + +static int +socket_channel_get_net_addr (JNIEnv * env, jobject addr) +{ +#ifndef WITHOUT_NETWORK + jclass cls = 0; + jmethodID mid; + jarray arr = 0; + jbyte *octets; + int netaddr, len; + + DBG + ("socket_channel_get_net_addr(): Entered socket_channel_get_net_addr\n"); + + /* Call the getAddress method on the object to retrieve the IP address */ + cls = (*env)->GetObjectClass (env, addr); + if (cls == NULL) + return (0); + + mid = (*env)->GetMethodID (env, cls, "getAddress", "()[B"); + if (mid == NULL) + return (0); + + DBG ("socket_channel_get_net_addr(): Got getAddress method\n"); + + arr = (*env)->CallObjectMethod (env, addr, mid); + if (arr == NULL) + return (0); + + DBG ("socket_channel_get_net_addr(): Got the address\n"); + + /* Turn the IP address into a 32 bit Internet address in network byte order */ + len = (*env)->GetArrayLength (env, arr); + if (len != 4) + { + JCL_ThrowException (env, "java/io/IOException", + "Internal Error: invalid byte array length"); + return (0); + } + DBG ("socket_channel_get_net_addr(): Length ok\n"); + + octets = (*env)->GetByteArrayElements (env, arr, 0); + if (octets == NULL) + return (0); + + DBG ("socket_channel_get_net_addr(): Grabbed bytes\n"); + + TARGET_NATIVE_NETWORK_IPADDRESS_BYTES_TO_INT (octets[0], + octets[1], + octets[2], + octets[3], netaddr); + + (*env)->ReleaseByteArrayElements (env, arr, octets, 0); + DBG ("socket_channel_get_net_addr(): Done getting addr\n"); + + return netaddr; +#else /* not WITHOUT_NETWORK */ + return (0); +#endif /* not WITHOUT_NETWORK */ +} diff --git a/libjava/classpath/native/jni/java-nio/java_nio_MappedByteBufferImpl.c b/libjava/classpath/native/jni/java-nio/java_nio_MappedByteBufferImpl.c new file mode 100644 index 00000000000..e1ba1e454f0 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/java_nio_MappedByteBufferImpl.c @@ -0,0 +1,83 @@ +/* java_nio_MappedByteBufferImpl.c - Native methods for MappedByteBufferImpl + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <errno.h> + +#include <jni.h> +#include <jcl.h> + +#include "java_nio_MappedByteBufferImpl.h" + +#define IO_EXCEPTION "java/io/IOException" + +JNIEXPORT void JNICALL +Java_java_nio_MappedByteBufferImpl_unmapImpl (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.nio.MappedByteBufferImpl.unmapImpl(): not implemented"); +} + +JNIEXPORT jboolean JNICALL +Java_java_nio_MappedByteBufferImpl_isLoadedImpl (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.nio.MappedByteBufferImpl.isLoadedImpl(): not implemented"); + return 0; +} + +JNIEXPORT void JNICALL +Java_java_nio_MappedByteBufferImpl_loadImpl (JNIEnv * env, + jclass clazz + __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.nio.MappedByteBufferImpl.loadImpl(): not implemented"); +} + +JNIEXPORT void JNICALL +Java_java_nio_MappedByteBufferImpl_forceImpl (JNIEnv * env, + jclass class + __attribute__ ((__unused__))) +{ + JCL_ThrowException (env, IO_EXCEPTION, + "java.nio.MappedByteBufferImpl.forceImpl(): not implemented"); +} diff --git a/libjava/classpath/native/jni/java-nio/java_nio_VMDirectByteBuffer.c b/libjava/classpath/native/jni/java-nio/java_nio_VMDirectByteBuffer.c new file mode 100644 index 00000000000..3eb5677e646 --- /dev/null +++ b/libjava/classpath/native/jni/java-nio/java_nio_VMDirectByteBuffer.c @@ -0,0 +1,216 @@ +/* java_nio_VMDirectByteBuffer.c - Native methods for VMDirectByteBuffer + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 <config.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <jni.h> +#include <jcl.h> + +#include "java_nio_VMDirectByteBuffer.h" + +static jclass classRawData; +static jmethodID methodRawDataInit; +static jfieldID fieldNativePointer; + +static void *NIOGetPointer (JNIEnv *, jobject); +static jobject NIOGetRawData (JNIEnv *, void *pointer); + +static void * +NIOGetPointer (JNIEnv * env, jobject rawdata) +{ +#if SIZEOF_VOID_P == 4 + return (void *) (*env)->GetIntField (env, rawdata, fieldNativePointer); +#elif SIZEOF_VOID_P == 8 + return (void *) (*env)->GetLongField (env, rawdata, fieldNativePointer); +#else +#error unsupported pointer size +#endif +} + +static jobject +NIOGetRawData (JNIEnv * env, void *pointer) +{ +#if SIZEOF_VOID_P == 4 + return (*env)->NewObject (env, classRawData, methodRawDataInit, + (jint) pointer); +#elif SIZEOF_VOID_P == 8 + return (*env)->NewObject (env, classRawData, methodRawDataInit, + (jlong) pointer); +#else +#error unsupported pointer size +#endif +} + +JNIEXPORT void JNICALL +Java_java_nio_VMDirectByteBuffer_init + (JNIEnv * env, jclass clazz __attribute__ ((__unused__))) +{ +#if SIZEOF_VOID_P == 4 + classRawData = (*env)->FindClass (env, "gnu/classpath/RawData32"); + if (classRawData == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal class"); + return; + } + + methodRawDataInit = (*env)->GetMethodID (env, classRawData, + "<init>", "(I)V"); + if (methodRawDataInit == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal constructor"); + return; + } + + fieldNativePointer = (*env)->GetFieldID (env, classRawData, "data", "I"); + if (fieldNativePointer == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal field"); + return; + } +#elif SIZEOF_VOID_P == 8 + classRawData = (*env)->FindClass (env, "gnu/classpath/RawData64"); + if (classRawData == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal class"); + return; + } + + methodRawDataInit = (*env)->GetMethodID (env, classRawData, + "<init>", "(J)V"); + if (methodRawDataInit == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal constructor"); + return; + } + + fieldNativePointer = (*env)->GetFieldID (env, classRawData, "data", "J"); + if (fieldNativePointer == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "unable to find internal field"); + return; + } +#else +#error unsupported pointer size +#endif + + /* We need to wrap the jclass in global reference to make it persistent */ + if ((classRawData = (*env)->NewGlobalRef (env, classRawData)) == NULL) + { + JCL_ThrowException (env, "java/lang/InternalError", + "failed to create global reference"); + return; + } +} + +JNIEXPORT jobject JNICALL +Java_java_nio_VMDirectByteBuffer_allocate + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), jint capacity) +{ + void *buffer; + + buffer = malloc (capacity); + + if (buffer == NULL) + { + JCL_ThrowException (env, "java/lang/OutOfMemoryError", + "unable to allocate memory for direct byte buffer"); + return 0; + } + + return NIOGetRawData (env, buffer); +} + +JNIEXPORT void JNICALL +Java_java_nio_VMDirectByteBuffer_free + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), jobject address) +{ + free (NIOGetPointer (env, address)); +} + +JNIEXPORT jbyte JNICALL +Java_java_nio_VMDirectByteBuffer_get__Lgnu_classpath_RawData_2I + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), + jobject address, jint index) +{ + return ((jbyte *) NIOGetPointer (env, address))[index]; +} + +JNIEXPORT void JNICALL +Java_java_nio_VMDirectByteBuffer_put + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), + jobject address, jint index, jbyte value) +{ + jbyte *pointer = (jbyte *) NIOGetPointer (env, address) + index; + *pointer = value; +} + +JNIEXPORT void JNICALL +Java_java_nio_VMDirectByteBuffer_get__Lgnu_classpath_RawData_2I_3BII + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), + jobject address, jint index, jbyteArray dst, jint dst_offset, jint dst_len) +{ + jbyte *src = (jbyte *) NIOGetPointer (env, address) + index; + memcpy ((*env)->GetByteArrayElements (env, dst, NULL) + dst_offset, src, + dst_len); +} + +JNIEXPORT void JNICALL +Java_java_nio_VMDirectByteBuffer_shiftDown + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), + jobject address, jint dst_offset, jint src_offset, jint count) +{ + jbyte *dst = (jbyte *) NIOGetPointer (env, address) + dst_offset; + jbyte *src = (jbyte *) NIOGetPointer (env, address) + src_offset; + memmove (dst, src, count); +} + +JNIEXPORT jobject JNICALL +Java_java_nio_VMDirectByteBuffer_adjustAddress + (JNIEnv * env, jclass clazz __attribute__ ((__unused__)), + jobject address, jint offset) +{ + return NIOGetRawData (env, (jbyte *) NIOGetPointer (env, address) + offset); +} diff --git a/libjava/classpath/native/jni/java-util/.cvsignore b/libjava/classpath/native/jni/java-util/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/java-util/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/java-util/Makefile.am b/libjava/classpath/native/jni/java-util/Makefile.am new file mode 100644 index 00000000000..da617f6a2b8 --- /dev/null +++ b/libjava/classpath/native/jni/java-util/Makefile.am @@ -0,0 +1,7 @@ +pkglib_LTLIBRARIES = libjavautil.la + +libjavautil_la_SOURCES = java_util_VMTimeZone.c + +AM_LDFLAGS = @CLASSPATH_MODULE@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @ERROR_CFLAGS@ diff --git a/libjava/classpath/native/jni/java-util/java_util_VMTimeZone.c b/libjava/classpath/native/jni/java-util/java_util_VMTimeZone.c new file mode 100644 index 00000000000..a3a986d36bc --- /dev/null +++ b/libjava/classpath/native/jni/java-util/java_util_VMTimeZone.c @@ -0,0 +1,223 @@ +/* VMTimeZone.c - Native method for java.util.VMTimeZone + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "config.h" + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <jni.h> + +#include "java_util_VMTimeZone.h" + +static size_t jint_to_charbuf (char *bufend, jint num); + +/** + * This method returns a time zone id string which is in the form + * (standard zone name) or (standard zone name)(GMT offset) or + * (standard zone name)(GMT offset)(daylight time zone name). The + * GMT offset can be in seconds, or where it is evenly divisible by + * 3600, then it can be in hours. The offset must be the time to + * add to the local time to get GMT. If a offset is given and the + * time zone observes daylight saving then the (daylight time zone + * name) must also be given (otherwise it is assumed the time zone + * does not observe any daylight savings). + * <p> + * The result of this method is given to getDefaultTimeZone(String) + * which tries to map the time zone id to a known TimeZone. See + * that method on how the returned String is mapped to a real + * TimeZone object. + */ +JNIEXPORT jstring JNICALL +Java_java_util_VMTimeZone_getSystemTimeZoneId (JNIEnv * env, + jclass clazz + __attribute__ ((__unused__))) +{ + struct tm tim; +#ifndef HAVE_LOCALTIME_R + struct tm *lt_tim; +#endif +#ifdef HAVE_TM_ZONE + int month; +#endif + time_t current_time; + long tzoffset; + const char *tz1, *tz2; + char tzoff[11]; + size_t tz1_len, tz2_len, tzoff_len; + char *tzid; + jstring retval; + + time (¤t_time); +#ifdef HAVE_LOCALTIME_R + localtime_r (¤t_time, &tim); +#else + /* Fall back on non-thread safe localtime. */ + lt_tim = localtime (¤t_time); + memcpy (&tim, lt_tim, sizeof (struct tm)); +#endif + mktime (&tim); + +#ifdef HAVE_STRUCT_TM_TM_ZONE + /* We will cycle through the months to make sure we hit dst. */ + month = tim.tm_mon; + tz1 = tz2 = NULL; + while (tz1 == NULL || tz2 == NULL) + { + if (tim.tm_isdst > 0) + tz2 = tim.tm_zone; + else if (tz1 == NULL) + { + tz1 = tim.tm_zone; + month = tim.tm_mon; + } + + if (tz1 == NULL || tz2 == NULL) + { + tim.tm_mon++; + tim.tm_mon %= 12; + } + + if (tim.tm_mon == month && tz2 == NULL) + tz2 = ""; + else + mktime (&tim); + } + /* We want to make sure the tm struct we use later on is not dst. */ + tim.tm_mon = month; + mktime (&tim); +#elif defined (HAVE_TZNAME) + /* If dst is never used, tzname[1] is the empty string. */ + tzset (); + tz1 = tzname[0]; + tz2 = tzname[1]; +#else + /* Some targets have no concept of timezones. Assume GMT without dst. */ + tz1 = "GMT"; + tz2 = ""; +#endif + +#ifdef STRUCT_TM_HAS_GMTOFF + /* tm_gmtoff is the number of seconds that you must add to GMT to get + local time, we need the number of seconds to add to the local time + to get GMT. */ + tzoffset = -1L * tim.tm_gmtoff; +#elif HAVE_UNDERSCORE_TIMEZONE + /* On some systems _timezone is actually defined as time_t. */ + tzoffset = (long) _timezone; +#elif HAVE_TIMEZONE + /* timezone is secs WEST of UTC. */ + tzoffset = timezone; +#else + /* FIXME: there must be another global if neither tm_gmtoff nor timezone + is available, esp. if tzname is valid. + Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to + calculate between gmtime and localtime (and accounting for possible + daylight savings time) as an alternative. */ + tzoffset = 0L; +#endif + + if ((tzoffset % 3600) == 0) + tzoffset = tzoffset / 3600; + + tz1_len = strlen (tz1); + tz2_len = strlen (tz2); + tzoff_len = jint_to_charbuf (tzoff + 11, tzoffset); + tzid = (char *) malloc (tz1_len + tz2_len + tzoff_len + 1); /* FIXME alloc */ + memcpy (tzid, tz1, tz1_len); + memcpy (tzid + tz1_len, tzoff + 11 - tzoff_len, tzoff_len); + memcpy (tzid + tz1_len + tzoff_len, tz2, tz2_len); + tzid[tz1_len + tzoff_len + tz2_len] = '\0'; + + retval = (*env)->NewStringUTF (env, tzid); + free (tzid); + + return retval; +} + +/* Put printed (decimal) representation of NUM in a buffer. + BUFEND marks the end of the buffer, which must be at least 11 chars long. + Returns the COUNT of chars written. The result is in + (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). + + Note that libgcj has a slightly different version called _Jv_FormatInt + that works on jchar buffers. +*/ + +static size_t +jint_to_charbuf (char *bufend, jint num) +{ + register char *ptr = bufend; + jboolean isNeg; + if (num < 0) + { + isNeg = JNI_TRUE; + num = -(num); + if (num < 0) + { + /* Must be MIN_VALUE, so handle this special case. + FIXME use 'unsigned jint' for num. */ + *--ptr = '8'; + num = 214748364; + } + } + else + isNeg = JNI_FALSE; + + do + { + *--ptr = (char) ((int) '0' + (num % 10)); + num /= 10; + } + while (num > 0); + + if (isNeg) + *--ptr = '-'; + return bufend - ptr; +} diff --git a/libjava/classpath/native/jni/xmlj/.cvsignore b/libjava/classpath/native/jni/xmlj/.cvsignore new file mode 100644 index 00000000000..e9f2658a694 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/.cvsignore @@ -0,0 +1,8 @@ +*.o +*.a +*.lo +*.la +.libs +.deps +Makefile +Makefile.in diff --git a/libjava/classpath/native/jni/xmlj/BUGS b/libjava/classpath/native/jni/xmlj/BUGS new file mode 100644 index 00000000000..801700cf1b0 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/BUGS @@ -0,0 +1,35 @@ +GNU Jaxp +------------------------------------------------------------------------ + +These bugs are for the gnu.xml.libxmlj package. + +CAVEAT: LibxmlJ's current incarnation is incomplete and partly +incorrect. Highly experimental. + +- Thread-safe, but effectively runs single-threaded. + +- Native code passes incorrect URIs to URIResolver.resolve. + +- Default output properties accessible through JAXP always assume XML + output (in violation of the XSLT 1.0 specification, section 16) + Correction: LibxmlJ always assumes XML output. + +- OutputProperties are not properly implemented, compare code and API + documentation. + +- TransformerFactory.getAttribute() and + TransformerFactory.setAttribute() not implemented, i.e. low-level + libxslt settings can currently not be accessed from Java. + +- TransformerFactory.getFeature() not implemented, i.e. currently no + low-level features of libxslt are advertised. + +FIXME: + +- Make LRU caching configurable. + +- Check whether <?xml encoding="..."?> headers are honored. + +- DefaultURIResolver uses naive approach. + +- TransformerFactory.getAssociatedStyleSheet() unfinished. diff --git a/libjava/classpath/native/jni/xmlj/Makefile.am b/libjava/classpath/native/jni/xmlj/Makefile.am new file mode 100644 index 00000000000..b0f1f9104de --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/Makefile.am @@ -0,0 +1,25 @@ +pkglib_LTLIBRARIES = libxmlj.la + +libxmlj_la_SOURCES = \ +xmlj_dom.c \ +xmlj_dom.h \ +xmlj_error.c \ +xmlj_error.h \ +xmlj_io.c \ +xmlj_io.h \ +xmlj_node.c \ +xmlj_node.h \ +xmlj_sax.c \ +xmlj_sax.h \ +xmlj_transform.c \ +xmlj_util.c \ +xmlj_util.h \ +xmlj_xpath.c + +AM_LDFLAGS = @CLASSPATH_MODULE@ @XML_LIBS@ @XSLT_LIBS@ +AM_CPPFLAGS = @CLASSPATH_INCLUDES@ + +# Don't enable ERROR flags. Code isn't warning free yet. +AM_CFLAGS = @WARNING_CFLAGS@ @STRICT_WARNING_CFLAGS@ @XML_CFLAGS@ @XSLT_CFLAGS@ + +EXTRA_DIST = BUGS diff --git a/libjava/classpath/native/jni/xmlj/xmlj_dom.c b/libjava/classpath/native/jni/xmlj/xmlj_dom.c new file mode 100644 index 00000000000..b9bd372b17b --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_dom.c @@ -0,0 +1,2617 @@ +/* xmlj_dom.c - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_dom.h" +#include "xmlj_error.h" +#include "xmlj_io.h" +#include "xmlj_node.h" +#include "xmlj_sax.h" +#include "xmlj_util.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +JNIEnv *dom_cb_env; +jobject dom_cb_obj; + +typedef struct +{ + int index; + int count; + xmlNodePtr node; +} +xmljHashScanData; + +/* Prototypes for local functions */ + +void +xmljAddAttribute (xmlNodePtr node, xmlAttrPtr attr); + +void +xmljHashScanner (void *payload, void *vdata, xmlChar *name); + +xmlChar * +xmljGetNodeValue (xmlNodePtr node); + +/* + * Determines whether a child node is suitable for insertion in the list of + * children for a given parent node. + * Returns 0 on success, a DOMException code otherwise. + */ +void +xmljValidateChildNode (JNIEnv *env, xmlNodePtr parent, xmlNodePtr child) +{ + xmlNodePtr cur; + + if (child == NULL || parent == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return; + } + if (child->doc != parent->doc) + { + xmljThrowDOMException (env, 4, NULL); /* WRONG_DOCUMENT_ERR */ + return; + } + /* Check that new parent is of an allowed type */ + switch (parent->type) + { + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_ENTITY_NODE: + case XML_ENTITY_REF_NODE: + case XML_NOTATION_NODE: + case XML_PI_NODE: + /* these can't have any children */ + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "parent type does not allow children"); + return; + case XML_ATTRIBUTE_NODE: + if (child->type != XML_TEXT_NODE && + child->type != XML_ENTITY_REF_NODE) + { + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "attributes may only contain text or entity reference nodes"); + return; + } + break; + case XML_DOCUMENT_FRAG_NODE: + case XML_ELEMENT_NODE: + if (child->type == XML_DTD_NODE || + child->type == XML_DOCUMENT_TYPE_NODE || + child->type == XML_ENTITY_NODE || + child->type == XML_NOTATION_NODE || + child->type == XML_PI_NODE) + { + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "parent type does not allow child of this type"); + return; + } + /* fall through */ + default: + if (child->type == XML_ATTRIBUTE_NODE || + child->type == XML_DOCUMENT_NODE || + child->type == XML_DOCUMENT_FRAG_NODE) + { + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "node type may not be a child"); + return; + } + /* TODO others? */ + } + /* Check that new parent is not self or an ancestor */ + for (cur = parent; cur != NULL; cur = cur->parent) + { + if (cur == child) + { + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "child cannot be an ancestor of itself"); + return; + } + } + /* Check that new parent does not add a second doctype or root element + * to a document parent */ + if (parent->type == XML_DOCUMENT_NODE) + { + cur = parent->children; + while (cur != NULL) + { + if (cur->type == XML_DTD_NODE || + cur->type == XML_DOCUMENT_TYPE_NODE || + (cur->type == XML_ELEMENT_NODE && + parent->type == XML_DOCUMENT_NODE)) + { + if (child->type == cur->type && child != cur) + { + /* HIERARCHY_REQUEST_ERR */ + xmljThrowDOMException (env, 3, "cannot add a second doctype or root element"); + return; + } + } + cur = cur->next; + } + } +} + +/* + * Adds the specified attribute node to the list of attributes for the given + * element. + */ +void +xmljAddAttribute (xmlNodePtr node, xmlAttrPtr attr) +{ + xmlAttrPtr cur = node->properties; + + if (cur == NULL) + { + node->properties = attr; + attr->prev = NULL; + attr->next = NULL; + attr->parent = node; + attr->doc = node->doc; + } + else + { + while (cur->next != NULL) + { + cur = cur->next; + } + cur->next = attr; + attr->prev = cur; + attr->next = NULL; + attr->parent = node; + attr->doc = node->doc; + } +} + +/* -- GnomeAttr -- */ + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeAttr_getSpecified (JNIEnv * env, jobject self) +{ + xmlAttrPtr attr; + + attr = (xmlAttrPtr) xmljGetNodeID (env, self); + return (attr->atype != 0); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeAttr_getValue (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + xmlChar *text; + jstring ret; + + node = xmljGetNodeID (env, self); + text = xmlNodeGetContent (node); + ret = xmljNewString (env, (const xmlChar *) text); + if (text != NULL) + { + xmlFree (text); + } + return ret; +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeAttr_setValue (JNIEnv * env, + jobject self, jstring value) +{ + xmlNodePtr node; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_value = xmljGetStringChars (env, value); + xmlNodeSetContent (node, s_value); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeAttr_xmljIsId (JNIEnv * env, jobject self) +{ + xmlAttrPtr attr; + + attr = (xmlAttrPtr) xmljGetNodeID (env, self); + return (attr->atype == XML_ATTRIBUTE_ID); +} + +/* -- GnomeDocument -- */ + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_free (JNIEnv * env, + jobject self + __attribute__ ((__unused__)), + jobject id) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljAsPointer (env, id); + xmljFreeDoc (env, doc); + xmlFree (doc); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getDoctype (JNIEnv * env, jobject self) +{ + xmlDocPtr doc; + xmlDtdPtr dtd; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + dtd = doc->extSubset; + if (dtd == NULL) + { + dtd = doc->intSubset; + } + return xmljGetNodeInstance (env, (xmlNodePtr) dtd); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getDocumentElement (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, xmlDocGetRootElement (doc)); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createDocumentType (JNIEnv * env, + jobject self, + jstring name, + jstring publicId, + jstring systemId) +{ + xmlDocPtr doc; + xmlDtdPtr dtd; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + dtd = xmlNewDtd (doc, + xmljGetStringChars (env, name), + xmljGetStringChars (env, publicId), + xmljGetStringChars (env, systemId)); + return xmljGetNodeInstance (env, (xmlNodePtr) dtd); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createDocumentFragment (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, xmlNewDocFragment (doc)); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createTextNode (JNIEnv * env, + jobject self, + jstring data) +{ + xmlDocPtr doc; + xmlNodePtr text; + const xmlChar *s_data; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_data = xmljGetStringChars (env, data); + text = xmlNewDocText (doc, s_data); + return xmljGetNodeInstance (env, text); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createComment (JNIEnv * env, + jobject self, + jstring data) +{ + xmlDocPtr doc; + xmlNodePtr comment; + const xmlChar *s_data; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_data = xmljGetStringChars (env, data); + comment = xmlNewDocComment (doc, s_data); + return xmljGetNodeInstance (env, comment); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createCDATASection (JNIEnv * env, + jobject self, + jstring data) +{ + xmlDocPtr doc; + xmlNodePtr cdata; + const xmlChar *s_data; + int len; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_data = xmljGetStringChars (env, data); + len = xmlStrlen (s_data); + cdata = xmlNewCDataBlock (doc, s_data, len); + return xmljGetNodeInstance (env, cdata); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createProcessingInstruction (JNIEnv * + env, + jobject + self, + jstring + target, + jstring + data) +{ + xmlDocPtr doc; + xmlNodePtr pi; + const xmlChar *s_target; + const xmlChar *s_data; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_target = xmljGetStringChars (env, target); + s_data = xmljGetStringChars (env, data); + pi = xmlNewPI (s_target, s_data); + pi->doc = doc; + return xmljGetNodeInstance (env, pi); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createEntityReference (JNIEnv * env, + jobject self, + jstring name) +{ + xmlDocPtr doc; + xmlNodePtr ref; + const xmlChar *s_name; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_name = xmljGetStringChars (env, name); + ref = xmlNewReference (doc, s_name); + return xmljGetNodeInstance (env, ref); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_xmljImportNode (JNIEnv * env, + jobject self, + jobject importedNode, + jboolean deep) +{ + xmlDocPtr doc; + xmlNodePtr node; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + node = xmljGetNodeID (env, importedNode); + if (node == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + if (node->type == XML_DOCUMENT_NODE || + node->type == XML_DOCUMENT_TYPE_NODE) + { + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return NULL; + } + node = xmlDocCopyNode (node, doc, deep); + return xmljGetNodeInstance (env, node); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createElementNS (JNIEnv * env, + jobject self, + jstring uri, + jstring qName) +{ + xmlDocPtr doc; + xmlNodePtr element; + xmlNsPtr ns = NULL; + const xmlChar *s_uri; + const xmlChar *s_qName; + const xmlChar *s_prefix; + const xmlChar *s_localName; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_qName = xmljGetStringChars (env, qName); + if (xmlValidateQName (s_qName, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + return NULL; + } + if (uri != NULL) + { + s_uri = xmljGetStringChars (env, uri); + s_prefix = xmljGetPrefix (s_qName); + s_localName = xmljGetLocalName (s_qName); + ns = xmlNewNs ((xmlNodePtr) doc, s_uri, s_prefix); + } + element = xmlNewDocNode (doc, ns, s_qName, NULL); + return xmljGetNodeInstance (env, element); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_createAttributeNS (JNIEnv * env, + jobject self, + jstring uri, + jstring qName) +{ + xmlDocPtr doc; + xmlNodePtr attr; + xmlNsPtr ns = NULL; + const xmlChar *s_uri; + const xmlChar *s_qName; + const xmlChar *s_prefix; + const xmlChar *s_localName; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + s_qName = xmljGetStringChars (env, qName); + if (xmlValidateQName (s_qName, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + return NULL; + } + if (uri != NULL) + { + s_uri = xmljGetStringChars (env, uri); + s_prefix = xmljGetPrefix (s_qName); + s_localName = xmljGetLocalName (s_qName); + ns = xmlNewNs ((xmlNodePtr) doc, s_uri, s_prefix); + } + attr = (xmlNodePtr) xmlNewNsProp ((xmlNodePtr) doc, ns, s_qName, NULL); + attr->parent = NULL; + return xmljGetNodeInstance (env, attr); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_xmljGetElementById (JNIEnv * env, + jobject self, + jstring elementId) +{ + xmlDocPtr doc; + xmlNodePtr ctx, tmp; + xmlAttrPtr attr; + const xmlChar *id; + const xmlChar *val; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + id = xmljGetStringChars (env, elementId); + + ctx = xmlDocGetRootElement (doc); + while (ctx && ctx != (xmlNodePtr) doc) + { + if (ctx->type == XML_ELEMENT_NODE) + { + for (attr = ctx->properties; attr; + attr = (xmlAttrPtr) attr->next) + { + if (xmlIsID (doc, ctx, attr)) + { + val = xmlGetProp (ctx, attr->name); + if (val && xmlStrEqual (id, val)) + { + return xmljGetNodeInstance (env, ctx); + } + } + } + } + if (ctx->children) + { + ctx = ctx->children; + } + else + { + tmp = ctx->next; + if (tmp) + { + ctx = tmp; + } + else + { + do + { + tmp = ctx->parent; + if (!tmp) + { + return NULL; + } + ctx = tmp; + tmp = ctx->next; + } + while (!tmp); + ctx = tmp; + } + } + } + return NULL; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getInputEncoding (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + if (doc->encoding) + { + return xmljNewString (env, doc->encoding); + } + switch (doc->charset) + { + case XML_CHAR_ENCODING_ASCII: + return xmljNewString (env, BAD_CAST "US-ASCII"); + case XML_CHAR_ENCODING_UTF16LE: + return xmljNewString (env, BAD_CAST "UTF-16LE"); + case XML_CHAR_ENCODING_UTF16BE: + return xmljNewString (env, BAD_CAST "UTF-16BE"); + case XML_CHAR_ENCODING_8859_1: + return xmljNewString (env, BAD_CAST "ISO-8859-1"); + /* TODO others */ + default: + return xmljNewString (env, BAD_CAST "UTF-8"); + } +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getXmlEncoding (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return (doc->encoding == NULL) ? + xmljNewString (env, BAD_CAST "UTF-8") : + xmljNewString (env, doc->encoding); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getXmlStandalone (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return doc->standalone; +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_setXmlStandalone (JNIEnv * env, + jobject self, + jboolean xmlStandalone) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + doc->standalone = xmlStandalone; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getXmlVersion (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return (doc->version == NULL) ? + xmljNewString (env, BAD_CAST "1.0") : + xmljNewString (env, doc->version); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_setXmlVersion (JNIEnv * env, + jobject self, + jstring xmlVersion) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + if (xmlVersion == NULL) + { + doc->version = NULL; + } + else + { + const xmlChar *version = xmljGetStringChars (env, xmlVersion); + if (!xmlStrEqual (version, BAD_CAST "1.0") && + !xmlStrEqual (version, BAD_CAST "1.1")) + { + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return; + } + doc->version = version; + } +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getDocumentURI (JNIEnv * env, + jobject self) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + return (doc->name == NULL) ? NULL : + xmljNewString (env, (const xmlChar *) doc->URL); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_setDocumentURI (JNIEnv * env, + jobject self, + jstring documentURI) +{ + xmlDocPtr doc; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + if (documentURI == NULL) + { + doc->URL = NULL; + } + else + { + doc->URL = xmljGetStringChars (env, documentURI); + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_xmljAdoptNode (JNIEnv *env, + jobject self, + jobject jnode) +{ + xmlDocPtr doc; + xmlNodePtr node; + + doc = (xmlDocPtr) xmljGetNodeID (env, self); + node = xmljGetNodeID (env, jnode); + + if (node == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + if (node->type == XML_DOCUMENT_NODE || + node->type == XML_DOCUMENT_TYPE_NODE || + node->type == XML_ENTITY_NODE || + node->type == XML_NOTATION_NODE) + { + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return NULL; + } + xmlUnlinkNode (node); + node = xmlDocCopyNode (node, doc, 1); + return xmljGetNodeInstance (env, node); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_renameNode (JNIEnv * env, + jobject self + __attribute__ ((__unused__)), + jobject n + __attribute__ ((__unused__)), + jstring namespaceURI + __attribute__ ((__unused__)), + jstring qName + __attribute__ ((__unused__))) +{ + xmlNodePtr node; + xmlNsPtr ns; + const xmlChar *s_qName; + const xmlChar *href; + const xmlChar *prefix; + int *len; + + node = xmljGetNodeID (env, n); + if (node == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + s_qName = xmljGetStringChars (env, qName); + if (xmlValidateQName (s_qName, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + return NULL; + } + xmlNodeSetName (node, s_qName); + + href = xmljGetStringChars (env, namespaceURI); + len = (int *) malloc (sizeof (int)); + prefix = xmlSplitQName3 (s_qName, len); + ns = node->ns; + if (ns == NULL) + { + if (href != NULL) + { + ns = xmlNewNs (node, href, prefix); + xmlSetNs (node, ns); + } + } + else + { + node->ns = NULL; + /*xmlFreeNs (ns); FIXME this can segfault (?) */ + if (href != NULL) + { + ns = xmlNewNs (node, href, prefix); + xmlSetNs (node, ns); + } + } + free (len); + return n; +} + +/* -- GnomeDocumentBuilder -- */ + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocumentBuilder_parseStream (JNIEnv * env, + jobject self, + jobject in, + jbyteArray + detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean coalesce, + jboolean + expandEntities, + jboolean + entityResolver, + jboolean + errorHandler) +{ + xmlDocPtr doc; + + doc = xmljParseDocument(env, + self, + in, + detectBuffer, + publicId, + systemId, + base, + validate, + coalesce, + expandEntities, + 0, + 0, + entityResolver, + errorHandler, + 0, + 0, + 1); + return xmljCreateDocument (env, self, doc); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocumentBuilder_createDocument +(JNIEnv * env, + jobject self, + jstring namespaceURI, + jstring qualifiedName, + jobject doctype) +{ + xmlDocPtr doc; + xmlNodePtr root; + xmlNsPtr ns; + const xmlChar *href; + const xmlChar *prefix; + const xmlChar *qName; + + qName = xmljGetStringChars (env, qualifiedName); + href = xmljGetStringChars (env, namespaceURI); + if (qName == NULL) + { + prefix = NULL; + } + else + { + int *len; + + len = (int *) malloc (sizeof (int)); + prefix = xmlSplitQName3 (qName, len); + free (len); + } + + /* Create the document node */ + doc = xmlNewDoc (BAD_CAST "1.0"); + + /* doctype */ + if (doctype != NULL) + { + jclass cls; + jmethodID method; + jstring ret; + const xmlChar *name; + const xmlChar *publicId; + const xmlChar *systemId; + const xmlChar *internalSubset; + xmlDtdPtr dtd; + + cls = (*env)->FindClass (env, "org/w3c/dom/DocumentType"); + if (cls == NULL) + { + return NULL; + } + /* name */ + method = (*env)->GetMethodID (env, cls, "getName", + "()Ljava/lang/String;"); + if (method == NULL) + { + return NULL; + } + ret = (jstring) (*env)->CallObjectMethod (env, doctype, method); + name = xmljGetStringChars (env, ret); + + /* publicId */ + method = (*env)->GetMethodID (env, cls, "getPublicId", + "()Ljava/lang/String;"); + if (method == NULL) + { + return NULL; + } + ret = (jstring) (*env)->CallObjectMethod (env, doctype, method); + publicId = xmljGetStringChars (env, ret); + + /* systemId */ + method = (*env)->GetMethodID (env, cls, "getSystemId", + "()Ljava/lang/String;"); + if (method == NULL) + { + return NULL; + } + ret = (jstring) (*env)->CallObjectMethod (env, doctype, method); + systemId = xmljGetStringChars (env, ret); + + /* internalSubset */ + method = (*env)->GetMethodID (env, cls, "getInternalSubset", + "()Ljava/lang/String;"); + if (method == NULL) + { + return NULL; + } + ret = (jstring) (*env)->CallObjectMethod (env, doctype, method); + internalSubset = xmljGetStringChars (env, ret); + + /* TODO notations */ + /* TODO entities */ + if (internalSubset == NULL) + { + dtd = xmlNewDtd (doc, name, publicId, systemId); + } + else + { + dtd = xmlCreateIntSubset (doc, name, publicId, systemId); + /* TODO parse internal subset? */ + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return NULL; + } + } + + /* Create the root element */ + root = xmlNewNode (NULL, qName); + xmlDocSetRootElement (doc, root); + ns = xmlNewNs (root, href, prefix); + xmlSetNs (root, ns); + + return xmljCreateDocument (env, self, doc); +} + +/* -- GnomeDocumentType -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocumentType_getPublicId (JNIEnv * env, + jobject self) +{ + xmlDtdPtr dtd; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + return xmljNewString (env, dtd->ExternalID); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocumentType_getSystemId (JNIEnv * env, + jobject self) +{ + xmlDtdPtr dtd; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + return xmljNewString (env, dtd->SystemID); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocumentType_getInternalSubset (JNIEnv * env, + jobject self + __attribute__ ((__unused__))) +{ + /* TODO */ + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return NULL; +} + +/* -- GnomeElement -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getAttribute (JNIEnv * env, + jobject self, + jstring name) +{ + xmlNodePtr node; + const xmlChar *s_name; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_name = xmljGetStringChars (env, name); + s_value = xmlGetProp (node, s_name); + xmlFree ((xmlChar *) s_name); + return (s_value == NULL) ? + xmljNewString (env, BAD_CAST "") : + xmljNewString (env, s_value); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_setAttribute (JNIEnv * env, + jobject self, + jstring name, + jstring value) +{ + xmlNodePtr node; + const xmlChar *s_name; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_name = xmljGetStringChars (env, name); + if (xmlValidateName (s_name, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + return; + } + s_value = xmljGetStringChars (env, value); + xmlSetProp (node, s_name, s_value); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getAttributeNode (JNIEnv * env, + jobject self, + jstring name) +{ + xmlNodePtr node; + const xmlChar *s_name; + xmlAttrPtr attr; + + node = xmljGetNodeID (env, self); + s_name = xmljGetStringChars (env, name); + attr = xmlHasProp (node, s_name); + if (attr == NULL) + { + return NULL; + } + xmlFree ((xmlChar *) s_name); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_setAttributeNode (JNIEnv * env, + jobject self, + jobject newAttr) +{ + xmlNodePtr node; + xmlAttrPtr new_attr; + xmlAttrPtr old_attr; + + node = xmljGetNodeID (env, self); + new_attr = (xmlAttrPtr) xmljGetNodeID (env, newAttr); + if (new_attr->parent != NULL) + { + xmljThrowDOMException (env, 10, NULL); /* INUSE_ATTRIBUTE_ERR */ + return NULL; + } + if (new_attr->doc != node->doc) + { + xmljThrowDOMException (env, 4, NULL); /* WRONG_DOCUMENT_ERR */ + return NULL; + } + old_attr = xmlHasProp (node, new_attr->name); + if (old_attr) + { + xmlUnlinkNode ((xmlNodePtr) old_attr); + } + xmljAddAttribute (node, new_attr); + return xmljGetNodeInstance (env, (xmlNodePtr) old_attr); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_removeAttributeNode (JNIEnv * env, + jobject self + __attribute__ ((__unused__)), + jobject oldAttr) +{ + xmlNodePtr attr; + + attr = xmljGetNodeID (env, oldAttr); + xmlUnlinkNode (attr); + return oldAttr; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getAttributeNS (JNIEnv * env, + jobject self, + jstring uri, + jstring localName) +{ + xmlNodePtr node; + const xmlChar *s_uri; + const xmlChar *s_localName; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_localName = xmljGetStringChars (env, localName); + if (uri == NULL) + { + s_value = xmlGetNoNsProp (node, s_localName); + } + else + { + s_uri = xmljGetStringChars (env, uri); + s_value = xmlGetNsProp (node, s_localName, s_uri); + xmlFree ((xmlChar *) s_uri); + } + xmlFree ((xmlChar *) s_localName); + return (s_value == NULL) ? + xmljNewString (env, BAD_CAST "") : + xmljNewString (env, s_value); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_setAttributeNS (JNIEnv * env, + jobject self, + jstring uri, + jstring qName, + jstring value) +{ + xmlNodePtr node; + xmlNsPtr ns; + const xmlChar *s_uri; + const xmlChar *s_qName; + const xmlChar *s_prefix; + const xmlChar *s_localName; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_qName = xmljGetStringChars (env, qName); + if (xmlValidateQName (s_qName, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + return; + } + s_value = xmljGetStringChars (env, value); + if (uri == NULL) + { + xmlSetProp (node, s_qName, s_value); + } + else + { + s_prefix = xmljGetPrefix (s_qName); + s_localName = xmljGetLocalName (s_qName); + s_uri = xmljGetStringChars (env, uri); + ns = xmlNewNs (node, s_uri, s_prefix); + xmlSetNsProp (node, ns, s_localName, s_value); + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getAttributeNodeNS (JNIEnv * env, + jobject self, + jstring uri, + jstring localName) +{ + xmlNodePtr node; + xmlAttrPtr attr; + const xmlChar *s_uri; + const xmlChar *s_localName; + + node = xmljGetNodeID (env, self); + attr = node->properties; + s_uri = xmljGetStringChars (env, uri); + s_localName = xmljGetStringChars (env, localName); + while (attr != NULL) + { + if (uri == NULL) + { + if (xmljMatch (s_localName, (xmlNodePtr) attr)) + break; + } + else + { + if (xmljMatchNS (s_uri, s_localName, (xmlNodePtr) attr)) + break; + } + attr = attr->next; + } + xmlFree ((xmlChar *) s_uri); + xmlFree ((xmlChar *) s_localName); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_setAttributeNodeNS (JNIEnv * env, + jobject self, + jobject newAttr) +{ + xmlNodePtr node; + xmlAttrPtr new_attr; + xmlAttrPtr old_attr; + const xmlChar *uri; + + node = xmljGetNodeID (env, self); + new_attr = (xmlAttrPtr) xmljGetNodeID (env, newAttr); + if (new_attr->parent != NULL) + { + xmljThrowDOMException (env, 10, NULL); /* INUSE_ATTRIBUTE_ERR */ + return NULL; + } + if (new_attr->doc != node->doc) + { + xmljThrowDOMException (env, 4, NULL); /* WRONG_DOCUMENT_ERR */ + return NULL; + } + uri = (new_attr->ns != NULL) ? new_attr->ns->href : NULL; + old_attr = xmlHasNsProp (node, new_attr->name, uri); + if (old_attr) + { + xmlUnlinkNode ((xmlNodePtr) old_attr); + } + xmljAddAttribute (node, new_attr); + return xmljGetNodeInstance (env, (xmlNodePtr) old_attr); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_hasAttribute (JNIEnv * env, + jobject self, + jstring name) +{ + xmlNodePtr node; + const xmlChar *s_name; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_name = xmljGetStringChars (env, name); + s_value = xmlGetProp (node, s_name); + xmlFree ((xmlChar *) s_name); + return (s_value != NULL); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_hasAttributeNS (JNIEnv * env, + jobject self, + jstring uri, + jstring localName) +{ + xmlNodePtr node; + const xmlChar *s_uri; + const xmlChar *s_localName; + const xmlChar *s_value; + + node = xmljGetNodeID (env, self); + s_localName = xmljGetStringChars (env, localName); + if (uri == NULL) + { + s_value = xmlGetNoNsProp (node, s_localName); + } + else + { + s_uri = xmljGetStringChars (env, uri); + s_value = xmlGetNsProp (node, s_localName, s_uri); + xmlFree ((xmlChar *) s_uri); + } + xmlFree ((xmlChar *) s_localName); + return (s_value != NULL); +} + +/* -- GnomeEntity -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeEntity_getPublicId (JNIEnv * env, jobject self) +{ + xmlEntityPtr entity; + + entity = (xmlEntityPtr) xmljGetNodeID (env, self); + return xmljNewString (env, entity->ExternalID); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeEntity_getSystemId (JNIEnv * env, jobject self) +{ + xmlEntityPtr entity; + + entity = (xmlEntityPtr) xmljGetNodeID (env, self); + return xmljNewString (env, entity->SystemID); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeEntity_getNotationName (JNIEnv * env, + jobject self + __attribute__ ((__unused__))) +{ + /* TODO */ + xmljThrowDOMException (env, 9, NULL); /* NOT_SUPPORTED_ERR */ + return NULL; +} + +/* -- GnomeNamedNodeMap -- */ + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_getNamedItem (JNIEnv * env, + jobject self, + jstring name) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlAttrPtr attr; + + attr = xmljGetNamedItem (env, self, name); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); + } + else + { + xmlDtdPtr dtd; + xmlHashTablePtr hash; + const xmlChar *s_name; + xmlNodePtr ret; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + hash = (xmlHashTablePtr) ((type == 1) ? dtd->entities : dtd->notations); + if (hash == NULL) + { + return NULL; + } + s_name = xmljGetStringChars (env, name); + ret = (xmlNodePtr) xmlHashLookup (hash, s_name); + xmlFree ((xmlChar *) s_name); + return xmljGetNodeInstance (env, ret); + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_setNamedItem (JNIEnv * env, + jobject self, + jobject arg) +{ + jclass cls; + jfieldID field; + jint type; + xmlNodePtr node; + xmlNodePtr argNode; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + node = xmljGetNodeID (env, self); + argNode = xmljGetNodeID (env, arg); + + if (argNode->doc != node->doc) + { + xmljThrowDOMException (env, 4, NULL); /* WRONG_DOCUMENT_ERR */ + } + xmljValidateChildNode (env, node, argNode); + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + if (type == 0) + { + if (argNode->parent != NULL) + { + xmljThrowDOMException (env, 10, NULL); /* INUSE_ATTRIBUTE_ERR */ + return NULL; + } + xmlAddChild (node, argNode); + } + else + { + xmlDtdPtr dtd; + xmlHashTablePtr hash; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + hash = (xmlHashTablePtr) ((type == 1) ? dtd->entities : dtd->notations); + if (hash == NULL) + { + hash = xmlHashCreate (10); + if (type == 1) + { + dtd->entities = hash; + } + else + { + dtd->notations = hash; + } + } + xmlHashAddEntry (hash, argNode->name, argNode); + } + return arg; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_removeNamedItem (JNIEnv * env, + jobject self, + jstring name) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlAttrPtr attr; + + attr = xmljGetNamedItem (env, self, name); + if (attr == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + xmlUnlinkNode ((xmlNodePtr) attr); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); + } + else + { + xmlDtdPtr dtd; + xmlHashTablePtr hash; + const xmlChar *s_name; + xmlNodePtr ret; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + hash = (xmlHashTablePtr) ((type == 1) ? dtd->entities : dtd->notations); + if (hash == NULL) + { + return NULL; + } + s_name = xmljGetStringChars (env, name); + ret = (xmlNodePtr) xmlHashLookup (hash, s_name); + if (ret != NULL) + { + xmlHashRemoveEntry (hash, s_name, NULL); + } + xmlFree ((xmlChar *) s_name); + return xmljGetNodeInstance (env, ret); + } +} + +void +xmljHashScanner (void *payload, void *vdata, xmlChar *name) +{ + xmljHashScanData *data; + + data = (xmljHashScanData *) vdata; + if (data->count <= data->index) + { + data->node = (xmlNodePtr) payload; + } + data->count++; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_item (JNIEnv * env, + jobject self, jint index) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlNodePtr node; + xmlAttrPtr attr; + jint count; + + node = xmljGetNodeID (env, self); + switch (node->type) + { + case XML_ELEMENT_NODE: + attr = node->properties; + for (count = 0; attr != NULL && count < index; count++) + { + attr = attr->next; + } + if (attr == NULL) + { + char msg[1024]; + sprintf (msg, "No attribute at index %d\n", (int) index); + xmljThrowException (env, "java/lang/NullPointerException", msg); + return NULL; + } + return xmljGetNodeInstance (env, (xmlNodePtr) attr); + default: + return NULL; + } + } + else + { + xmlDtdPtr dtd; + xmlHashTablePtr hash; + xmljHashScanData *data; + xmlNodePtr ret; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + hash = (xmlHashTablePtr) ((type == 1) ? dtd->entities : dtd->notations); + if (hash == NULL) + { + return NULL; + } + data = (xmljHashScanData *) malloc (sizeof (xmljHashScanData)); + if (data == NULL) + { + return NULL; + } + data->index = index; + data->count = 0; + data->node = NULL; + xmlHashScan (hash, xmljHashScanner, data); + ret = data->node; + free (data); + return xmljGetNodeInstance (env, ret); + } +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_getLength (JNIEnv * env, + jobject self) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlNodePtr node; + xmlAttrPtr attr; + jint count; + + node = xmljGetNodeID (env, self); + switch (node->type) + { + case XML_ELEMENT_NODE: + count = 0; + attr = node->properties; + while (attr != NULL) + { + count++; + attr = attr->next; + } + return count; + default: + return -1; + } + } + else + { + xmlDtdPtr dtd; + xmlHashTablePtr hash; + xmljHashScanData *data; + jint ret; + + dtd = (xmlDtdPtr) xmljGetNodeID (env, self); + hash = (xmlHashTablePtr) ((type == 1) ? dtd->entities : dtd->notations); + if (hash == NULL) + { + return 0; + } + data = (xmljHashScanData *) malloc (sizeof (xmljHashScanData)); + if (data == NULL) + { + return 0; + } + data->index = -1; + data->count = 0; + data->node = NULL; + xmlHashScan (hash, xmljHashScanner, data); + ret = data->count; + free (data); + return ret; + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_getNamedItemNS (JNIEnv * env, + jobject self, + jstring uri, + jstring localName) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlAttrPtr attr; + + attr = xmljGetNamedItemNS (env, self, uri, localName); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); + } + else + { + return NULL; + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_setNamedItemNS (JNIEnv * env, + jobject self, + jobject arg) +{ + return Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_setNamedItem (env, self, + arg); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNamedNodeMap_removeNamedItemNS (JNIEnv * env, + jobject self, + jstring uri, + jstring + localName) +{ + jclass cls; + jfieldID field; + jint type; + + cls = (*env)->GetObjectClass (env, self); + field = (*env)->GetFieldID (env, cls, "type", "I"); + type = (*env)->GetIntField (env, self, field); + + if (type == 0) + { + xmlAttrPtr attr; + + attr = xmljGetNamedItemNS (env, self, uri, localName); + if (attr == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + else + { + xmlUnlinkNode ((xmlNodePtr) attr); + return xmljGetNodeInstance (env, (xmlNodePtr) attr); + } + } + else + { + return NULL; + } +} + +/* -- GnomeNode -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getNodeName (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + if (node == NULL) + { + return NULL; + } + return xmljNewString (env, node->name); +} + +xmlChar * +xmljGetNodeValue (xmlNodePtr node) +{ + /* If not character data, return null */ + switch (node->type) + { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_ATTRIBUTE_NODE: + return xmlNodeGetContent (node); + default: + return NULL; + } +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getNodeValue (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + xmlChar *text; + jstring ret; + + node = xmljGetNodeID (env, self); + text = xmljGetNodeValue (node); + ret = xmljNewString (env, (const xmlChar *) text); + if (text != NULL) + { + xmlFree (text); + } + return ret; +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_setNodeValue (JNIEnv * env, + jobject self, + jstring nodeValue) +{ + xmlNodePtr node; + const xmlChar *s_nodeValue; + + node = xmljGetNodeID (env, self); + + /* If not character data, return */ + if (node->type != XML_TEXT_NODE && + node->type != XML_CDATA_SECTION_NODE && node->type != XML_COMMENT_NODE) + return; + + s_nodeValue = xmljGetStringChars (env, nodeValue); + xmlNodeSetContent (node, s_nodeValue); +} + +JNIEXPORT jshort JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getNodeType (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + switch (node->type) + { + case XML_DTD_NODE: + return XML_DOCUMENT_TYPE_NODE; + case XML_ATTRIBUTE_DECL: + return XML_ATTRIBUTE_NODE; + case XML_ENTITY_DECL: + return XML_ENTITY_NODE; + default: + return node->type; + } +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getParentNode (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, node->parent); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getFirstChild (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, node->children); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getLastChild (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, node->last); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getPreviousSibling (JNIEnv * env, + jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, node->prev); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getNextSibling (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, node->next); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getOwnerDocument (JNIEnv * env, + jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return xmljGetNodeInstance (env, (xmlNodePtr) node->doc); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljInsertBefore (JNIEnv * env, + jobject self, + jobject newChild, + jobject refChild) +{ + xmlNodePtr node; + xmlNodePtr newChildNode; + xmlNodePtr refChildNode; + + node = xmljGetNodeID (env, self); + newChildNode = xmljGetNodeID (env, newChild); + refChildNode = xmljGetNodeID (env, refChild); + + /* Is refChildNode a child of this node? */ + if (refChildNode == NULL || + refChildNode->parent == NULL || + refChildNode->parent != node) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + /* Check new child */ + xmljValidateChildNode (env, node, newChildNode); + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + + newChildNode = xmlAddPrevSibling (refChildNode, newChildNode); + return xmljGetNodeInstance (env, newChildNode); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljReplaceChild (JNIEnv * env, + jobject self, + jobject newChild, + jobject oldChild) +{ + xmlNodePtr node; + xmlNodePtr newChildNode; + xmlNodePtr oldChildNode; + + node = xmljGetNodeID (env, self); + newChildNode = xmljGetNodeID (env, newChild); + oldChildNode = xmljGetNodeID (env, oldChild); + + /* Is oldChildNode a child of this node? */ + if (oldChildNode == NULL || + oldChildNode->parent == NULL || + oldChildNode->parent != node) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + /* Check new child */ + xmljValidateChildNode (env, node, newChildNode); + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + + newChildNode = xmlReplaceNode (oldChildNode, newChildNode); + return xmljGetNodeInstance (env, newChildNode); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljRemoveChild (JNIEnv * env, + jobject self, + jobject oldChild) +{ + xmlNodePtr node; + xmlNodePtr oldChildNode; + + node = xmljGetNodeID (env, self); + oldChildNode = xmljGetNodeID (env, oldChild); + + if (oldChildNode == NULL || + oldChildNode->parent == NULL || + oldChildNode->parent != node) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + xmlUnlinkNode (oldChildNode); + return oldChild; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljAppendChild (JNIEnv * env, + jobject self, + jobject newChild) +{ + xmlNodePtr node; + xmlNodePtr newChildNode; + + node = xmljGetNodeID (env, self); + newChildNode = xmljGetNodeID (env, newChild); + + /* Check new child */ + xmljValidateChildNode (env, node, newChildNode); + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + + newChildNode = xmlAddChild (node, newChildNode); + return xmljGetNodeInstance (env, newChildNode); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_hasChildNodes (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return (node->children != NULL); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljCloneNode (JNIEnv * env, + jobject self, jboolean deep) +{ + xmlNodePtr node; + xmlNodePtr clone; + + node = xmljGetNodeID (env, self); + clone = xmlCopyNode (node, deep); + clone->parent = NULL; + clone->doc = node->doc; + return xmljGetNodeInstance (env, clone); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_normalize (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + xmljNormalizeNode (node); +} + +void +xmljNormalizeNode (xmlNodePtr node) +{ + xmlNodePtr cur; + xmlNodePtr last = NULL; + + cur = node->children; + while (cur != NULL) + { + switch (cur->type) + { + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + if (xmlIsBlankNode (cur)) + { + xmlNodePtr next = cur->next; + xmlUnlinkNode (cur); + xmlFreeNode (cur); + cur = next; + continue; + } + if (last != NULL) + { + last = xmlTextMerge (last, cur); + xmlUnlinkNode (cur); + xmlFreeNode (cur); + cur = last; + } + else + { + last = cur; + } + break; + default: + last = NULL; + xmljNormalizeNode (cur); + } + cur = cur->next; + } +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getNamespaceURI (JNIEnv * env, + jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + if (node->type != XML_ELEMENT_NODE && + node->type != XML_ATTRIBUTE_NODE) + { + return NULL; + } + if (node->ns == NULL) + { + return NULL; + } + return xmljNewString (env, node->ns->href); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getPrefix (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + if (node->type != XML_ELEMENT_NODE && + node->type != XML_ATTRIBUTE_NODE) + { + return NULL; + } + if (node->ns == NULL) + { + return NULL; + } + return xmljNewString (env, node->ns->prefix); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_setPrefix (JNIEnv * env, + jobject self, jstring prefix) +{ + xmlNodePtr node; + const xmlChar *s_prefix; + + s_prefix = xmljGetStringChars (env, prefix); + if (xmlValidateName (s_prefix, 0)) + { + xmljThrowDOMException (env, 5, NULL); /* INVALID_CHARACTER_ERR */ + } + node = xmljGetNodeID (env, self); + if (node->type != XML_ELEMENT_NODE && + node->type != XML_ATTRIBUTE_NODE) + { + xmljThrowDOMException (env, 3, NULL); /* HIERARCHY_REQUEST_ERR */ + return; + } + if (node->ns == NULL) + { + xmljThrowDOMException (env, 14, NULL); /* NAMESPACE_ERR */ + return; + } + node->ns->prefix = s_prefix; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getLocalName (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + int *len; + jstring ret; + + node = xmljGetNodeID (env, self); + if (node->name == NULL) + { + return NULL; + } + len = (int *) malloc (sizeof (int)); + if (xmlSplitQName3 (node->name, len) != NULL) + { + ret = xmljNewString (env, node->name + (*len)); + } + else + { + ret = xmljNewString (env, node->name); + } + free (len); + return ret; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_hasAttributes (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + + node = xmljGetNodeID (env, self); + return (node->properties != NULL); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_getBaseURI (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + xmlChar *baseURI; + jstring ret; + + node = xmljGetNodeID (env, self); + baseURI = xmlNodeGetBase (node->doc, node); + ret = xmljNewString (env, (const xmlChar *) baseURI); + if (baseURI != NULL) + { + xmlFree (baseURI); + } + return ret; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_lookupPrefix (JNIEnv * env, jobject self, + jstring namespaceURI) +{ + xmlNodePtr node; + xmlNsPtr ns; + xmlDocPtr doc; + const xmlChar *s_uri; + + node = xmljGetNodeID (env, self); + doc = node->doc; + /* If this is a document node, search from the root element */ + if (node->type == XML_DOCUMENT_NODE) + { + doc = (xmlDocPtr) node; + node = xmlDocGetRootElement (doc); + } + s_uri = xmljGetStringChars (env, namespaceURI); + ns = xmlSearchNsByHref (doc, node, s_uri); + xmlFree ((xmlChar *) s_uri); + if (ns == NULL) + { + return NULL; + } + return xmljNewString (env, ns->prefix); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_isDefaultNamespace (JNIEnv * env, + jobject self, + jstring namespaceURI) +{ + xmlNodePtr node; + xmlNsPtr ns; + const xmlChar *s_uri; + + node = xmljGetNodeID (env, self); + s_uri = xmljGetStringChars (env, namespaceURI); + ns = xmlSearchNsByHref (node->doc, node, s_uri); + xmlFree ((xmlChar *) s_uri); + if (ns == NULL) + { + return 0; + } + return (ns->prefix == NULL || xmlStrlen (ns->prefix) == 0); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_lookupNamespaceURI (JNIEnv * env, + jobject self, + jstring prefix) +{ + xmlNodePtr node; + xmlDocPtr doc; + xmlNsPtr ns; + const xmlChar *s_prefix; + + node = xmljGetNodeID (env, self); + doc = node->doc; + /* If this is a document node, search from the root element */ + if (node->type == XML_DOCUMENT_NODE) + { + doc = (xmlDocPtr) node; + node = xmlDocGetRootElement (doc); + } + s_prefix = xmljGetStringChars (env, prefix); + ns = xmlSearchNs (doc, node, s_prefix); + xmlFree ((xmlChar *) s_prefix); + if (ns == NULL) + { + return NULL; + } + return xmljNewString (env, ns->href); +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_xmljCompareTo (JNIEnv * env, + jobject self, + jobject other) +{ + xmlNodePtr n1, n2, x; + int d1, d2, delta, c; + + n1 = xmljGetNodeID (env, self); + n2 = xmljGetNodeID (env, other); + if (n1->doc != n2->doc) + { + return 0; + } + if (n1->type == XML_ATTRIBUTE_NODE || n2->type == XML_ATTRIBUTE_NODE) + { + return 0; + } + d1 = 0; + for (x = n1->parent; x && x->type != XML_DOCUMENT_NODE; x = x->parent) + { + d1++; + } + d2 = 0; + for (x = n2->parent; x && x->type != XML_DOCUMENT_NODE; x = x->parent) + { + d2++; + } + delta = d1 - d2; + while (d1 > d2) + { + n1 = n1->parent; + d1--; + } + while (d2 > d1) + { + n2 = n2->parent; + d2--; + } + c = xmljCompare (n1, n2); + return (c != 0) ? c : delta; +} + +/* Compare at same level */ +int +xmljCompare (xmlNodePtr n1, xmlNodePtr n2) +{ + int c, i1, i2; + + if (n1->parent == NULL || n1->type == XML_DOCUMENT_NODE || + n2->parent == NULL || n2->type == XML_DOCUMENT_NODE || + n1 == n2) + { + return 0; + } + c = xmljCompare (n1->parent, n2->parent); + if (c != 0) + { + return c; + } + i1 = 0; + for (n1 = n1->prev; n1; n1 = n1->prev) + { + i1++; + } + i2 = 0; + for (n2 = n2->prev; n2; n2 = n2->prev) + { + i2++; + } + return i1 - i2; +} + +int +xmljIsEqualNodeList (xmlNodePtr node1, xmlNodePtr node2) +{ + while (node1 != NULL) + { + if (!xmljIsEqualNode (node1, node2)) + { + return 0; + } + node1 = node1->next; + node2 = node2->next; + } + return 1; +} + +int +xmljIsEqualNode (xmlNodePtr node1, xmlNodePtr node2) +{ + const xmlChar *val1; + const xmlChar *val2; + + if (node1 == node2) + { + return 1; + } + if (node1 == NULL || node2 == NULL) + { + return 0; + } + /* Check node type */ + if (node1->type != node2->type) + { + return 0; + } + /* Check node name */ + if (!xmlStrEqual (node1->name, node2->name)) + { + return 0; + } + /* Check node namespace */ + if (node1->type == XML_ELEMENT_NODE || + node1->type == XML_ATTRIBUTE_NODE) + { + xmlNsPtr ns1, ns2; + + ns1 = node1->ns; + if (ns1 != NULL) + { + ns2 = node2->ns; + if (ns2 == NULL) + { + return 0; + } + val1 = ns1->href; + val2 = ns2->href; + if (!xmlStrEqual (val1, val2)) + { + return 0; + } + } + } + /* Check node value */ + val1 = xmljGetNodeValue (node1); + val2 = xmljGetNodeValue (node2); + if (!xmlStrEqual (val1, val2)) + { + return 0; + } + /* Check attributes */ + if (node1->type == XML_ELEMENT_NODE && + !xmljIsEqualNodeList ((xmlNodePtr) node1->properties, + (xmlNodePtr) node2->properties)) + { + return 0; + } + /* Check doctype */ + if (node1->type == XML_DOCUMENT_NODE) + { + xmlDocPtr doc1 = (xmlDocPtr) node1; + xmlDocPtr doc2 = (xmlDocPtr) node2; + + if (!xmljIsEqualNode ((xmlNodePtr) doc1->intSubset, + (xmlNodePtr) doc2->intSubset) || + !xmljIsEqualNode ((xmlNodePtr) doc1->extSubset, + (xmlNodePtr) doc2->extSubset)) + { + return 0; + } + } + /* Check child nodes */ + if (!xmljIsEqualNodeList (node1->children, node2->children)) + { + return 0; + } + return 1; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNode_isEqualNode (JNIEnv * env, + jobject self, + jobject arg) +{ + xmlNodePtr node1; + xmlNodePtr node2; + + node1 = xmljGetNodeID (env, self); + node2 = xmljGetNodeID (env, arg); + return xmljIsEqualNode (node1, node2); +} + +/* -- GnomeNodeList -- */ + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNodeList_item (JNIEnv * env, + jobject self, jint index) +{ + xmlNodePtr node; + jint count; + + node = xmljGetNodeID (env, self); + node = node->children; + count = 0; + for (count = 0; node != NULL && count < index; count++) + { + node = node->next; + } + return xmljGetNodeInstance (env, node); +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNodeList_getLength (JNIEnv * env, jobject self) +{ + xmlNodePtr node; + jint count; + + node = xmljGetNodeID (env, self); + count = 0; + node = node->children; + while (node != NULL) + { + count++; + node = node->next; + } + return count; +} + +/* -- GnomeNotation -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNotation_getPublicId (JNIEnv * env, + jobject self) +{ + xmlNotationPtr notation; + + notation = (xmlNotationPtr) xmljGetNodeID (env, self); + if (notation->PublicID == NULL) + { + return NULL; + } + return xmljNewString (env, notation->PublicID); +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeNotation_getSystemId (JNIEnv * env, + jobject self) +{ + xmlNotationPtr notation; + + notation = (xmlNotationPtr) xmljGetNodeID (env, self); + if (notation->SystemID == NULL) + { + return NULL; + } + return xmljNewString (env, notation->SystemID); +} + +/* -- GnomeProcessingInstruction -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeProcessingInstruction_getData (JNIEnv * env, + jobject self) +{ + xmlNodePtr node; + xmlChar *text; + jstring ret; + + node = xmljGetNodeID (env, self); + text = xmlNodeGetContent (node); + ret = xmljNewString (env, (const xmlChar *) text); + if (text != NULL) + { + xmlFree (text); + } + return ret; +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeProcessingInstruction_setData (JNIEnv * env, + jobject self, + jstring data) +{ + xmlNodePtr node; + const xmlChar *s_data; + + node = xmljGetNodeID (env, self); + s_data = xmljGetStringChars (env, data); + xmlNodeSetContent (node, s_data); +} + +/* -- GnomeTypeInfo -- */ + +xmlDtdPtr xmljGetDtd (xmlDocPtr doc) +{ + xmlNodePtr ctx; + + for (ctx = doc->children; ctx; ctx = ctx->next) + { + if (ctx->type == XML_DOCUMENT_TYPE_NODE) + { + return (xmlDtdPtr) ctx; + } + } + return NULL; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeTypeInfo_getTypeName (JNIEnv *env, jobject self) +{ + xmlNodePtr node; + xmlDtdPtr dtd; + xmlAttributePtr attribute; + + node = xmljGetNodeID (env, self); + dtd = xmljGetDtd (node->doc); + if (dtd) + { + switch (node->type) + { + case XML_ATTRIBUTE_NODE: + attribute = xmlGetDtdAttrDesc (dtd, node->parent->name, node->name); + if (attribute) + { + switch (attribute->type) + { + case XML_ATTRIBUTE_CDATA: + return xmljNewString (env, BAD_CAST "CDATA"); + case XML_ATTRIBUTE_ID: + return xmljNewString (env, BAD_CAST "ID"); + case XML_ATTRIBUTE_IDREF: + return xmljNewString (env, BAD_CAST "IDREF"); + case XML_ATTRIBUTE_IDREFS: + return xmljNewString (env, BAD_CAST "IDREFS"); + case XML_ATTRIBUTE_ENTITY: + return xmljNewString (env, BAD_CAST "ENTITY"); + case XML_ATTRIBUTE_ENTITIES: + return xmljNewString (env, BAD_CAST "ENTITIES"); + case XML_ATTRIBUTE_NMTOKEN: + return xmljNewString (env, BAD_CAST "NMTOKEN"); + case XML_ATTRIBUTE_NMTOKENS: + return xmljNewString (env, BAD_CAST "NMTOKENS"); + default: + return NULL; + } + } + return NULL; + default: + return NULL; + } + } + /* TODO when XML Schema support is available */ + return NULL; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeTypeInfo_getTypeNamespace (JNIEnv *env, + jobject self) +{ + xmlNodePtr node; + xmlDtdPtr dtd; + xmlAttributePtr attribute; + + node = xmljGetNodeID (env, self); + dtd = xmljGetDtd (node->doc); + if (dtd) + { + switch (node->type) + { + case XML_ATTRIBUTE_NODE: + attribute = xmlGetDtdAttrDesc (dtd, node->parent->name, node->name); + if (attribute) + { + return xmljNewString (env, + BAD_CAST "http://www.w3.org/TR/REC-xml"); + } + return NULL; + default: + return NULL; + } + } + /* TODO when XML Schema support is available */ + return NULL; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeTypeInfo_isDerivedFrom (JNIEnv *env + __attribute__ ((__unused__)), + jobject self + __attribute__ ((__unused__)), + jstring typeNS + __attribute__ ((__unused__)), + jstring typeName + __attribute__ ((__unused__)), + jint method + __attribute__ ((__unused__))) +{ + /* TODO when XML Schema support is available */ + return 0; +} + +/* -- Utility -- */ + +/* + * Create GnomeDocument object from the given xmlDocPtr + */ +jobject +xmljCreateDocument (JNIEnv * env, jobject self, xmlDocPtr doc) +{ + jclass cls; + jfieldID field; + jobject ret; + + if (!doc) + { + return NULL; + } + + /* Get document object */ + ret = xmljGetNodeInstance (env, (xmlNodePtr) doc); + + /* Set DOM implementation field */ + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeDocument"); + field = (*env)->GetFieldID (env, cls, "dom", + "Lorg/w3c/dom/DOMImplementation;"); + (*env)->SetObjectField (env, ret, field, self); + return ret; +} + +xmlAttrPtr +xmljGetNamedItem (JNIEnv * env, jobject self, jstring name) +{ + xmlNodePtr node; + xmlAttrPtr attr; + const xmlChar *s_name; + + s_name = xmljGetStringChars (env, name); + + node = xmljGetNodeID (env, self); + attr = node->properties; + while (attr != NULL) + { + if (xmljMatch (s_name, (xmlNodePtr) attr)) + break; + attr = attr->next; + } + xmlFree ((xmlChar *) s_name); + + return attr; +} + +xmlAttrPtr +xmljGetNamedItemNS (JNIEnv * env, jobject self, jstring uri, jstring localName) +{ + xmlNodePtr node; + xmlAttrPtr attr; + const xmlChar *s_uri; + const xmlChar *s_localName; + + s_uri = xmljGetStringChars (env, uri); + s_localName = xmljGetStringChars (env, localName); + + node = xmljGetNodeID (env, self); + attr = node->properties; + while (attr != NULL) + { + if (xmljMatchNS (s_uri, s_localName, (xmlNodePtr) attr)) + break; + attr = attr->next; + } + xmlFree ((xmlChar *) s_uri); + xmlFree ((xmlChar *) s_localName); + + return attr; +} diff --git a/libjava/classpath/native/jni/xmlj/xmlj_dom.h b/libjava/classpath/native/jni/xmlj/xmlj_dom.h new file mode 100644 index 00000000000..d4a1dff420c --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_dom.h @@ -0,0 +1,70 @@ +/* xmlj_dom.h - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_DOM_H +#define XMLJ_DOM_H + +#include "gnu_xml_libxmlj_dom_GnomeAttr.h" +#include "gnu_xml_libxmlj_dom_GnomeDocument.h" +#include "gnu_xml_libxmlj_dom_GnomeDocumentBuilder.h" +#include "gnu_xml_libxmlj_dom_GnomeDocumentType.h" +#include "gnu_xml_libxmlj_dom_GnomeElement.h" +#include "gnu_xml_libxmlj_dom_GnomeEntity.h" +#include "gnu_xml_libxmlj_dom_GnomeNamedNodeMap.h" +#include "gnu_xml_libxmlj_dom_GnomeNode.h" +#include "gnu_xml_libxmlj_dom_GnomeNodeList.h" +#include "gnu_xml_libxmlj_dom_GnomeNotation.h" +#include "gnu_xml_libxmlj_dom_GnomeProcessingInstruction.h" +#include "gnu_xml_libxmlj_dom_GnomeTypeInfo.h" + +#include <libxml/parser.h> +#include <libxml/valid.h> + +void xmljValidateChildNode (JNIEnv *env, xmlNodePtr parent, xmlNodePtr child); +int xmljIsEqualNode (xmlNodePtr node1, xmlNodePtr node2); +int xmljIsEqualNodeList (xmlNodePtr node1, xmlNodePtr node2); +void xmljNormalizeNode (xmlNodePtr node); +xmlDtdPtr xmljGetDtd (xmlDocPtr doc); +int xmljCompare (xmlNodePtr n1, xmlNodePtr n2); + +/* Utility */ +jobject xmljCreateDocument (JNIEnv * env, jobject self, xmlDocPtr doc); +xmlAttrPtr xmljGetNamedItem (JNIEnv * env, jobject self, jstring name); +xmlAttrPtr xmljGetNamedItemNS (JNIEnv * env, jobject self, jstring uri, + jstring localName); + +#endif /* !defined XMLJ_DOM_H */ diff --git a/libjava/classpath/native/jni/xmlj/xmlj_error.c b/libjava/classpath/native/jni/xmlj/xmlj_error.c new file mode 100644 index 00000000000..5dd90552c35 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_error.c @@ -0,0 +1,169 @@ +/* xmlj_error.c - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_error.h" +#include "xmlj_io.h" +#include "xmlj_util.h" + +void +xmljXsltErrorFunc (void *ctx, const char *msg, ...) +{ + if (NULL != ctx) + { + SAXParseContext *sax = ((SAXParseContext *) ctx); + + if (NULL != sax) + { + JNIEnv *env = sax->env; + + if (!(*env)->ExceptionOccurred (env)) + { + jobject target = sax->obj; + xmlChar *x_msg; + jstring j_msg; + va_list args; + + if (sax->error == NULL) + { + sax->error = + xmljGetMethodID (env, + target, + "error", + "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V"); + if (sax->error == NULL) + { + return; + } + } + + va_start (args, msg); + x_msg = (msg == NULL) ? NULL : xmlCharStrdup (msg); + va_end (args); + j_msg = xmljNewString (env, x_msg); + + (*env)->CallVoidMethod (env, + target, + sax->error, + j_msg, + -1, + -1, + NULL, + NULL); + } + } + } + else + { + va_list va; + va_start (va, msg); + fprintf (stderr, "libxslt error: "); + vfprintf (stderr, msg, va); + fflush (stderr); + va_end (va); + } +} + +void +xmljThrowException (JNIEnv *env, + const char *classname, + const char *message) +{ + jclass cls; + jmethodID method; + jthrowable ex; + jstring jmsg; + + /*fprintf(stderr, "Throwing exception %s %s\n", classname, message);*/ + cls = (*env)->FindClass (env, classname); + if (cls == NULL) + { + fprintf (stderr, "Can't find class %s\n", classname); + fflush (stderr); + return; + } + method = (*env)->GetMethodID (env, cls, "<init>", "(Ljava/lang/String;)V"); + if (method == NULL) + { + fprintf (stderr, "Can't find method %s.<init>\n", classname); + fflush (stderr); + return; + } + jmsg = (message == NULL) ? NULL : (*env)->NewStringUTF (env, message); + ex = (jthrowable) (*env)->NewObject (env, cls, method, jmsg); + if (ex == NULL) + { + fprintf (stderr, "Can't instantiate new %s\n", classname); + fflush (stderr); + return; + } + (*env)->Throw (env, ex); +} + +void +xmljThrowDOMException (JNIEnv *env, + int code, + const char *message) +{ + jclass cls; + jmethodID method; + jthrowable ex; + jstring jmsg; + + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeDOMException"); + if (cls == NULL) + { + fprintf (stderr, "Can't find DOMException class!\n"); + fflush (stderr); + return; + } + method = (*env)->GetMethodID (env, cls, "<init>", "(SLjava/lang/String;)V"); + if (method == NULL) + { + fprintf (stderr, "Can't find DOMException constructor!\n"); + fflush (stderr); + return; + } + jmsg = (message == NULL) ? NULL : (*env)->NewStringUTF (env, message); + ex = (jthrowable) (*env)->NewObject (env, cls, method, code, jmsg); + (*env)->Throw (env, ex); +} + diff --git a/libjava/classpath/native/jni/xmlj/xmlj_error.h b/libjava/classpath/native/jni/xmlj/xmlj_error.h new file mode 100644 index 00000000000..a0c9fcc8042 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_error.h @@ -0,0 +1,85 @@ +/* xmlj_error.h - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_ERROR_H +#define XMLJ_ERROR_H + +#include <jni.h> +#include <libxml/xmlIO.h> + +/* +typedef struct SaxErrorContext_ +{ + JNIEnv * env; + jobject saxErrorAdapter; + jmethodID saxCommentMethodID; + jmethodID saxWarningMethodID; + jmethodID saxErrorMethodID; + jmethodID saxFatalErrorMethodID; + jclass sourceLocatorClass; + jmethodID sourceLocatorConstructor; + xmlSAXLocatorPtr locator; + jstring publicId; + jstring systemId; + const char *publicIdCstr; + const char *systemIdCstr; + jmethodID resolveURIMethodID; + jmethodID resolveURIAndOpenMethodID; + jmethodID getInputStreamMethodID; + jmethodID xsltGenericErrorMethodID; + jobject theTransformerException; + jmethodID getNativeHandleMethodID; +} SaxErrorContext; + +SaxErrorContext * xmljCreateSaxErrorContext (JNIEnv * env, + jobject errorContext, + jstring systemId, + jstring publicId); + +void xmljFreeSaxErrorContext (SaxErrorContext * errorContext); + +void xmljInitErrorHandling (xmlSAXHandler * saxHandler); +*/ + +void xmljXsltErrorFunc (void *ctx, const char *msg, ...); + +void xmljThrowException (JNIEnv *, const char *classname, const char *message); + +void xmljThrowDOMException (JNIEnv *, int code, const char *message); + +#endif /* !defined XMLJ_ERROR_H */ + diff --git a/libjava/classpath/native/jni/xmlj/xmlj_io.c b/libjava/classpath/native/jni/xmlj/xmlj_io.c new file mode 100644 index 00000000000..aa2964dc312 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_io.c @@ -0,0 +1,799 @@ +/* xmlj_io.c - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_io.h" +#include "xmlj_error.h" +#include "xmlj_node.h" +#include "xmlj_sax.h" +#include "xmlj_util.h" + +#include <math.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + +#include <libxml/xmlIO.h> +#include <libxml/parserInternals.h> + +#include <pthread.h> + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define UNSIGN(a) (((a) < 0) ? ((a) + 0x100) : (a)) + +#define DETECT_BUFFER_SIZE 50 + +typedef struct _OutputStreamContext +{ + + JNIEnv *env; + jobject outputStream; + jmethodID outputStreamWriteFunc; + jmethodID outputStreamCloseFunc; + +} +OutputStreamContext; + +typedef struct _InputStreamContext +{ + + JNIEnv *env; + jobject inputStream; + jmethodID inputStreamReadFunc; + jmethodID inputStreamCloseFunc; + jobject bufferByteArray; + jint bufferLength; + +} +InputStreamContext; + +InputStreamContext *xmljNewInputStreamContext (JNIEnv * env, + jobject inputStream); + +void xmljFreeInputStreamContext (InputStreamContext * inContext); + +int xmljInputReadCallback (void *context, char *buffer, int len); + +int xmljInputCloseCallback (void *context); + +int xmljOutputWriteCallback (void *context, const char *buffer, int len); + +int xmljOutputCloseCallback (void *context); + +OutputStreamContext *xmljNewOutputStreamContext (JNIEnv * env, + jobject outputStream); + +void +xmljFreeOutputStreamContext (OutputStreamContext * outContext); + +xmlCharEncoding +xmljDetectCharEncoding (JNIEnv * env, jbyteArray buffer); + +int +xmljOutputWriteCallback (void *context, const char *buffer, int len) +{ + OutputStreamContext *outContext; + JNIEnv *env; + jbyteArray byteArray; + + outContext = (OutputStreamContext *) context; + env = outContext->env; + byteArray = (*env)->NewByteArray (env, len); + + if (0 != byteArray) + { + (*env)->SetByteArrayRegion (env, byteArray, 0, len, (jbyte *) buffer); + + (*env)->CallVoidMethod (env, + outContext->outputStream, + outContext->outputStreamWriteFunc, byteArray); + + (*env)->DeleteLocalRef (env, byteArray); + + return (*env)->ExceptionOccurred (env) ? -1 : len; + } + else + { + /* Out of memory, signal error */ + return -1; + } +} + +int +xmljOutputCloseCallback (void *context) +{ + OutputStreamContext *outContext; + JNIEnv *env; + + outContext = (OutputStreamContext *) context; + env = outContext->env; + (*env)->CallVoidMethod (env, + outContext->outputStream, + outContext->outputStreamCloseFunc); + + return (*env)->ExceptionOccurred (env) ? -1 : 0; +} + +int +xmljInputReadCallback (void *context, char *buffer, int len) +{ + InputStreamContext *inContext; + JNIEnv *env; + jint nread; + int offset; + + inContext = (InputStreamContext *) context; + env = inContext->env; + nread = 0; + + for (offset = 0; offset < len && nread >= 0;) + { + nread = (*env)->CallIntMethod (env, + inContext->inputStream, + inContext->inputStreamReadFunc, + inContext->bufferByteArray, + 0, MIN (len - offset, + inContext->bufferLength)); + + if (nread > 0) + { + (*env)->GetByteArrayRegion (env, + inContext->bufferByteArray, + 0, nread, ((jbyte *) buffer) + offset); + + offset += nread; + } + } + + return (*env)->ExceptionOccurred (env) ? -1 : offset; +} + +int +xmljInputCloseCallback (void *context) +{ + InputStreamContext *inContext; + JNIEnv *env; + + inContext = (InputStreamContext *) context; + env = inContext->env; + (*env)->CallVoidMethod (env, inContext->inputStream, + inContext->inputStreamCloseFunc); + + return (*env)->ExceptionOccurred (env) ? -1 : 0; +} + +InputStreamContext * +xmljNewInputStreamContext (JNIEnv * env, jobject inputStream) +{ + jclass inputStreamClass; + InputStreamContext *result; + + inputStreamClass = (*env)->FindClass (env, "java/io/InputStream"); + if (inputStreamClass == NULL) + { + return NULL; + } + result = (InputStreamContext *) malloc (sizeof (InputStreamContext)); + if (result == NULL) + { + return NULL; + } + + result->env = env; + result->inputStream = inputStream; + result->inputStreamReadFunc = + (*env)->GetMethodID (env, inputStreamClass, "read", "([BII)I"); + result->inputStreamCloseFunc = + (*env)->GetMethodID (env, inputStreamClass, "close", "()V"); + result->bufferLength = 4096; + result->bufferByteArray = (*env)->NewByteArray (env, result->bufferLength); + return result; +} + +void +xmljFreeInputStreamContext (InputStreamContext * inContext) +{ + JNIEnv *env; + + env = inContext->env; + (*env)->DeleteLocalRef (env, inContext->bufferByteArray); + free (inContext); +} + +OutputStreamContext * +xmljNewOutputStreamContext (JNIEnv * env, jobject outputStream) +{ + jclass outputStreamClass; + OutputStreamContext *result; + + outputStreamClass = (*env)->FindClass (env, "java/io/OutputStream"); + if (outputStreamClass == NULL) + { + return NULL; + } + result = (OutputStreamContext *) malloc (sizeof (OutputStreamContext)); + if (result == NULL) + { + return NULL; + } + + result->env = env; + result->outputStream = outputStream; + result->outputStreamWriteFunc = + (*env)->GetMethodID (env, outputStreamClass, "write", "([B)V"); + result->outputStreamCloseFunc = + (*env)->GetMethodID (env, outputStreamClass, "close", "()V"); + return result; +} + + +void +xmljFreeOutputStreamContext (OutputStreamContext * outContext) +{ + free (outContext); +} + +SAXParseContext * +xmljNewSAXParseContext (JNIEnv * env, jobject obj, xmlParserCtxtPtr ctx, + jstring publicId, jstring systemId) +{ + SAXParseContext *ret; + + ret = (SAXParseContext *) malloc (sizeof (SAXParseContext)); + ret->env = env; + ret->obj = obj; + ret->ctx = ctx; + ret->sax = ctx->sax; + ret->loc = NULL; + ret->publicId = publicId; + ret->systemId = systemId; + + ret->startDTD = NULL; + ret->externalEntityDecl = NULL; + ret->internalEntityDecl = NULL; + ret->resolveEntity = NULL; + ret->notationDecl = NULL; + ret->attributeDecl = NULL; + ret->elementDecl = NULL; + ret->unparsedEntityDecl = NULL; + ret->setDocumentLocator = NULL; + ret->startDocument = NULL; + ret->endDocument = NULL; + ret->startElement = NULL; + ret->endElement = NULL; + ret->characters = NULL; + ret->ignorableWhitespace = NULL; + ret->processingInstruction = NULL; + ret->comment = NULL; + ret->cdataBlock = NULL; + ret->warning = NULL; + ret->error = NULL; + ret->fatalError = NULL; + + ret->resolveURIAndOpen = NULL; + ret->stringClass = NULL; + return ret; +} + +void +xmljFreeSAXParseContext (SAXParseContext * saxCtx) +{ + free (saxCtx); +} + +xmlCharEncoding +xmljDetectCharEncoding (JNIEnv * env, jbyteArray buffer) +{ + xmlCharEncoding ret; + jint nread; + + if (buffer == NULL) + { + return XML_CHAR_ENCODING_ERROR; + } + nread = (*env)->GetArrayLength (env, buffer); + if (nread >= 5) + { + jbyte nativeBuffer[DETECT_BUFFER_SIZE + 1]; + unsigned char converted[DETECT_BUFFER_SIZE + 1]; + int i; + + memset (nativeBuffer, 0, DETECT_BUFFER_SIZE + 1); + (*env)->GetByteArrayRegion (env, buffer, 0, nread, nativeBuffer); + /* Convert from signed to unsigned */ + for (i = 0; i < DETECT_BUFFER_SIZE + 1; i++) + { + converted[i] = UNSIGN (nativeBuffer[i]); + } + ret = xmlDetectCharEncoding (converted, nread); + } + else + { + ret = XML_CHAR_ENCODING_NONE; + } + return ret; +} + +xmlParserCtxtPtr +xmljNewParserContext (JNIEnv * env, + jobject inputStream, + jbyteArray detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean coalesce, + jboolean expandEntities, + jboolean loadEntities) +{ + InputStreamContext *inputContext; + xmlCharEncoding encoding; + xmlParserCtxtPtr ctx; + int options; + + encoding = xmljDetectCharEncoding (env, detectBuffer); + if (encoding != XML_CHAR_ENCODING_ERROR) + { + inputContext = xmljNewInputStreamContext (env, inputStream); + if (NULL != inputContext) + { + /* NOTE: userdata must be NULL for DOM to work */ + ctx = xmlCreateIOParserCtxt (NULL, + NULL, + xmljInputReadCallback, + xmljInputCloseCallback, + inputContext, + encoding); + if (NULL != ctx) + { + ctx->userData = ctx; + + /* Set parsing options */ + options = 0; + if (validate) + { + options |= XML_PARSE_DTDVALID; + } + if (coalesce) + { + options |= XML_PARSE_NOCDATA; + } + if (expandEntities) + { + options |= XML_PARSE_NOENT; + } + if (loadEntities) + { + options |= XML_PARSE_DTDLOAD; + } + if (xmlCtxtUseOptions (ctx, options)) + { + xmljThrowException (env, + "java/lang/RuntimeException", + "Unable to set xmlParserCtxtPtr options"); + } + if (base != NULL) + { + ctx->input->directory = + (*env)->GetStringUTFChars (env, base, 0); + } + return ctx; + } + xmljFreeInputStreamContext (inputContext); + } + } + return NULL; +} + +void +xmljFreeParserContext (xmlParserCtxtPtr ctx) +{ + InputStreamContext *inputStreamContext = NULL; + + if (ctx->input != NULL && ctx->input->buf != NULL) + { + inputStreamContext + = (InputStreamContext *) ctx->input->buf->context; + + } + xmlFreeParserCtxt (ctx); + if (inputStreamContext != NULL) + { + xmljFreeInputStreamContext (inputStreamContext); + } +} + +xmlDocPtr +xmljParseDocument (JNIEnv * env, + jobject self, + jobject in, + jbyteArray detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean coalesce, + jboolean expandEntities, + jboolean contentHandler, + jboolean dtdHandler, + jboolean entityResolver, + jboolean errorHandler, + jboolean declarationHandler, + jboolean lexicalHandler, + int mode) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *saxCtx; + xmlSAXHandlerPtr sax; + + ctx = xmljNewParserContext (env, in, detectBuffer, publicId, systemId, base, + validate, coalesce, expandEntities, + entityResolver); + if (ctx != NULL) + { + saxCtx = xmljNewSAXParseContext (env, self, ctx, publicId, systemId); + if (saxCtx != NULL) + { + sax = xmljNewSAXHandler (contentHandler, + dtdHandler, + entityResolver, + errorHandler, + declarationHandler, + lexicalHandler); + if (sax != NULL) + { + return xmljParseDocument2 (env, + ctx, + saxCtx, + sax, + mode); + } + xmljFreeSAXParseContext (saxCtx); + } + xmljFreeParserContext (ctx); + } + if (!(*env)->ExceptionOccurred (env)) + { + xmljThrowException (env, "java/io/IOException", + "Unable to create parser context"); + } + return NULL; +} + +xmlDocPtr +xmljParseDocument2 (JNIEnv * env, + xmlParserCtxtPtr ctx, + SAXParseContext *saxCtx, + xmlSAXHandlerPtr sax, + int mode) +{ + xmlSAXHandlerPtr orig; + xmlDocPtr doc; + int ret; + + ctx->_private = saxCtx; + ctx->userData = ctx; + orig = ctx->sax; + ctx->sax = sax; + + xmljSetThreadContext (saxCtx); + + ret = xmlParseDocument (ctx); + doc = ctx->myDoc; + if (ret || !doc) + { + const char *msg = ctx->lastError.message; + switch (mode) + { + case 0: + xmljSAXFatalError (ctx, msg); + break; + case 1: + xmljThrowDOMException (env, ret, msg); + break; + case 2: + xmljThrowException (env, + "javax/xml/transform/TransformerException", + msg); + } + } + + xmljClearThreadContext (); + + ctx->sax = orig; + free(sax); + xmljFreeSAXParseContext (saxCtx); + xmljFreeParserContext (ctx); + xmljClearStringCache (); + return doc; +} + +xmlParserInputPtr +xmljNewParserInput (JNIEnv * env, + jobject inputStream, + jbyteArray detectBuffer, + xmlParserCtxtPtr parserContext) +{ + xmlParserInputPtr ret; + xmlParserInputBufferPtr input; + xmlCharEncoding encoding; + + encoding = xmljDetectCharEncoding (env, detectBuffer); + if (encoding != XML_CHAR_ENCODING_ERROR) + { + input = xmljNewParserInputBuffer (env, inputStream, encoding); + if (input != NULL) + { + ret = xmlNewIOInputStream (parserContext, input, encoding); + return ret; + } + xmlFreeParserInputBuffer (input); + } + return NULL; +} + +xmlParserInputBufferPtr +xmljNewParserInputBuffer (JNIEnv * env, + jobject inputStream, xmlCharEncoding encoding) +{ + xmlParserInputBufferPtr ret; + InputStreamContext *inputContext; + + inputContext = xmljNewInputStreamContext (env, inputStream); + if (NULL != inputContext) + { + ret = xmlParserInputBufferCreateIO (&xmljInputReadCallback, + &xmljInputCloseCallback, + inputContext, encoding); + if (ret != NULL) + return ret; + xmljFreeInputStreamContext (inputContext); + } + return NULL; +} + +void +xmljSaveFileToJavaOutputStream (JNIEnv * env, jobject outputStream, + xmlDocPtr tree, + const char *outputEncodingName) +{ + OutputStreamContext *outputContext = + xmljNewOutputStreamContext (env, outputStream); + + xmlCharEncoding outputEncoding = xmlParseCharEncoding (outputEncodingName); + + xmlOutputBufferPtr outputBuffer = + xmlOutputBufferCreateIO (xmljOutputWriteCallback, + xmljOutputCloseCallback, + outputContext, + xmlGetCharEncodingHandler (outputEncoding)); + + /* Write result to output stream */ + + xmlSaveFileTo (outputBuffer, tree, outputEncodingName); + + xmljFreeOutputStreamContext (outputContext); +} + +/* +jobject +xmljResolveURI (SaxErrorContext * saxErrorContext, + const char *URL, const char *ID) +{ + JNIEnv *env = saxErrorContext->env; + + jstring hrefString = (*env)->NewStringUTF (env, URL); + jstring baseString = saxErrorContext->systemId; + + jobject sourceWrapper = (*env)->CallObjectMethod (env, + saxErrorContext-> + saxErrorAdapter, + saxErrorContext-> + resolveURIMethodID, + hrefString, + baseString); + (*env)->DeleteLocalRef (env, hrefString); + + if (NULL == sourceWrapper) + { + return NULL; + } + else + { + jobject sourceInputStream = (*env)->CallObjectMethod (env, + sourceWrapper, + saxErrorContext-> + getInputStreamMethodID); + + (*env)->DeleteLocalRef (env, sourceWrapper); + + if ((*env)->ExceptionOccurred (env)) + { + -* Report to ErrorAdapter here? *- + return NULL; + } + + return sourceInputStream; + } +}*/ + +xmlDocPtr +xmljResolveURIAndOpen (SAXParseContext *saxContext, + const char *URL, + const char *ID) +{ + jobject libxmlDocument; + xmlDocPtr doc; + JNIEnv *env = saxContext->env; + + jstring hrefString = (*env)->NewStringUTF (env, URL); + jstring baseString = saxContext->systemId; + + if (saxContext->resolveURIAndOpen == NULL) + { + jclass cls = (*env)->GetObjectClass (env, saxContext->obj); + saxContext->resolveURIAndOpen = + (*env)->GetMethodID (env, cls, "resolveURIAndOpen", + "Ljava/lang/String;Ljava/lang/String)Lgnu/xml/libxmlj/transform/LibxmlDocument;"); + } + libxmlDocument = + (*env)->CallObjectMethod (env, + saxContext->obj, + saxContext->resolveURIAndOpen, + hrefString, + baseString); + + doc = (xmlDocPtr) xmljGetNodeID (env, libxmlDocument); + + (*env)->DeleteLocalRef (env, libxmlDocument); + + if ((*env)->ExceptionOccurred (env)) + { + /* Report to ErrorAdapter here? */ + return NULL; + } + else + { + return doc; + } +} + +/*xmlParserInputPtr +xmljLoadExternalEntity (const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) +{ + SaxErrorContext *saxErrorContext = xmljGetThreadContext (); + + JNIEnv *env = saxErrorContext->env; + + jstring hrefString = (*env)->NewStringUTF (env, URL); + jstring baseString = saxErrorContext->systemId; + + jobject sourceWrapper = (*env)->CallObjectMethod (env, + saxErrorContext-> + saxErrorAdapter, + saxErrorContext-> + resolveURIMethodID, + hrefString, + baseString); + + (*env)->DeleteLocalRef (env, hrefString); + + if (NULL == sourceWrapper) + { + return NULL; + } + else + { + InputStreamContext *inputContext; + xmlParserInputBufferPtr inputBuffer; + xmlParserInputPtr inputStream; + + jobject sourceInputStream = (*env)->CallObjectMethod (env, + sourceWrapper, + saxErrorContext-> + getInputStreamMethodID); + + (*env)->DeleteLocalRef (env, sourceWrapper); + + if ((*env)->ExceptionOccurred (env)) + { + -* Report to ErrorAdapter *- + return NULL; + } + + inputContext = xmljNewInputStreamContext (env, sourceInputStream); + + inputBuffer + = xmlParserInputBufferCreateIO (xmljInputReadCallback, + xmljInputCloseCallback, + inputContext, XML_CHAR_ENCODING_NONE); + + inputStream = xmlNewInputStream (ctxt); + if (inputStream == NULL) + { + return (NULL); + } + + inputStream->filename = NULL; + inputStream->directory = NULL; + inputStream->buf = inputBuffer; + + inputStream->base = inputStream->buf->buffer->content; + inputStream->cur = inputStream->buf->buffer->content; + inputStream->end = &inputStream->base[inputStream->buf->buffer->use]; + if ((ctxt->directory == NULL) && (inputStream->directory != NULL)) + ctxt->directory = + (char *) xmlStrdup ((const xmlChar *) inputStream->directory); + return (inputStream); + } +}*/ + +/* Key for the thread-specific buffer */ +static pthread_key_t thread_context_key; + +/* Once-only initialisation of the key */ +static pthread_once_t thread_context_once = PTHREAD_ONCE_INIT; + +static void +thread_context_key_alloc (void); + +/* Allocate the key */ +static void +thread_context_key_alloc () +{ + pthread_key_create (&thread_context_key, NULL); +} + +void +xmljSetThreadContext (SAXParseContext * context) +{ + pthread_once (&thread_context_once, thread_context_key_alloc); + pthread_setspecific (thread_context_key, context); +} + +void +xmljClearThreadContext (void) +{ + pthread_setspecific (thread_context_key, NULL); +} + +/* Return the thread-specific buffer */ +SAXParseContext * +xmljGetThreadContext (void) +{ + return (SAXParseContext *) pthread_getspecific (thread_context_key); +} diff --git a/libjava/classpath/native/jni/xmlj/xmlj_io.h b/libjava/classpath/native/jni/xmlj/xmlj_io.h new file mode 100644 index 00000000000..871859aca51 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_io.h @@ -0,0 +1,170 @@ +/* xmlj_io.h - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_IO_H +#define XMLJ_IO_H + +#include <jni.h> +#include <libxml/xmlIO.h> +#include "xmlj_error.h" + +typedef struct _SAXParseContext +{ + + JNIEnv *env; /* Current JNI environment */ + jobject obj; /* The gnu.xml.libxmlj.sax.GnomeXmlReader instance */ + xmlParserCtxtPtr ctx; /* libxml2 parser context */ + xmlSAXLocatorPtr loc; /* libxml2 SAX locator */ + xmlSAXHandlerPtr sax; /* pristine SAX handler */ + jstring publicId; + jstring systemId; + + jmethodID startDTD; + jmethodID externalEntityDecl; + jmethodID internalEntityDecl; + jmethodID resolveEntity; + jmethodID notationDecl; + jmethodID attributeDecl; + jmethodID elementDecl; + jmethodID unparsedEntityDecl; + jmethodID setDocumentLocator; + jmethodID startDocument; + jmethodID endDocument; + jmethodID startElement; + jmethodID endElement; + jmethodID characters; + jmethodID ignorableWhitespace; + jmethodID processingInstruction; + jmethodID comment; + jmethodID cdataBlock; + jmethodID warning; + jmethodID error; + jmethodID fatalError; + + jmethodID resolveURIAndOpen; /* JavaProxy */ + jclass stringClass; +} +SAXParseContext; + +SAXParseContext * +xmljNewSAXParseContext (JNIEnv * env, jobject obj, xmlParserCtxtPtr ctx, + jstring publicId, jstring systemId); + +void +xmljFreeSAXParseContext (SAXParseContext * saxCtx); + +xmlParserCtxtPtr +xmljNewParserContext (JNIEnv * env, + jobject inputStream, + jbyteArray detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean coalesce, + jboolean expandEntities, + jboolean loadEntities); + +void +xmljFreeParserContext (xmlParserCtxtPtr parserContext); + +xmlDocPtr +xmljParseDocument (JNIEnv * env, + jobject self, + jobject in, + jbyteArray detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean coalesce, + jboolean expandEntities, + jboolean contentHandler, + jboolean dtdHandler, + jboolean entityResolver, + jboolean errorHandler, + jboolean declarationHandler, + jboolean lexicalHandler, + int saxMode); + +xmlDocPtr +xmljParseDocument2 (JNIEnv * env, + xmlParserCtxtPtr ctx, + SAXParseContext *saxCtx, + xmlSAXHandlerPtr sax, + int saxMode); + +xmlParserInputPtr +xmljNewParserInput (JNIEnv * env, + jobject inputStream, + jbyteArray detectBuffer, + xmlParserCtxtPtr parserContext); + +xmlParserInputBufferPtr +xmljNewParserInputBuffer (JNIEnv * env, + jobject inputStream, + xmlCharEncoding encoding); + +void +xmljSaveFileToJavaOutputStream (JNIEnv * env, jobject outputStream, + xmlDocPtr tree, + const char *outputEncoding); + +/* +xmlParserInputPtr +xmljLoadExternalEntity (const char *URL, const char *ID, + xmlParserCtxtPtr ctxt); + +jobject +xmljResolveURI (SaxErrorContext * saxErrorContext, const char *URL, + const char *ID); +*/ +xmlDocPtr +xmljResolveURIAndOpen (SAXParseContext *saxContext, + const char *URL, const char *ID); + + +void +xmljSetThreadContext (SAXParseContext * ctxt); + +SAXParseContext * +xmljGetThreadContext (void); + +void +xmljClearThreadContext (void); + +#endif /* !defined XMLJ_IO_H */ diff --git a/libjava/classpath/native/jni/xmlj/xmlj_node.c b/libjava/classpath/native/jni/xmlj/xmlj_node.c new file mode 100644 index 00000000000..20832678a25 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_node.c @@ -0,0 +1,203 @@ +/* xmlj_node.c - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_error.h" +#include "xmlj_node.h" +#include "xmlj_util.h" +#include <libxml/xmlstring.h> + +/* + * Returns the node ID for the given GnomeNode object. + */ +xmlNodePtr +xmljGetNodeID (JNIEnv * env, jobject self) +{ + jclass cls; + jfieldID field; + jobject id; + xmlNodePtr node; + + if (self == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + return NULL; + } + cls = (*env)->GetObjectClass (env, self); + if (cls == NULL) + { + return NULL; + } + field = (*env)->GetFieldID (env, cls, "id", "Ljava/lang/Object;"); + if (field == NULL) + { + return NULL; + } + id = (*env)->GetObjectField (env, self, field); + node = (xmlNodePtr) xmljAsPointer (env, id); + if (node == NULL) + { + xmljThrowDOMException (env, 8, NULL); /* NOT_FOUND_ERR */ + } + return node; +} + +/* + * Returns the Java node instanced corresponding to the specified node ID. + */ +jobject +xmljGetNodeInstance (JNIEnv * env, xmlNodePtr node) +{ + jclass cls; + jmethodID method; + xmlElementType type; + + if (node == NULL) + return NULL; + + /* Invoke the GnomeNode.newInstance class method */ + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeNode"); + if (cls == NULL) + { + return NULL; + } + method = (*env)->GetStaticMethodID (env, cls, "newInstance", + "(Ljava/lang/Object;Ljava/lang/Object;I)Lgnu/xml/libxmlj/dom/GnomeNode;"); + + if (method == NULL) + { + return NULL; + } + type = node->type; + switch (type) + { + case XML_DTD_NODE: + type = XML_DOCUMENT_TYPE_NODE; + break; + case XML_ATTRIBUTE_DECL: + type = XML_ATTRIBUTE_NODE; + break; + case XML_ENTITY_DECL: + type = XML_ENTITY_NODE; + break; + default: + break; + } + return (*env)->CallStaticObjectMethod (env, cls, method, + xmljAsField (env, node->doc), + xmljAsField (env, node), + type); +} + +void +xmljFreeDoc (JNIEnv * env, xmlDocPtr doc) +{ + jclass cls; + jmethodID method; + + /* Invoke the GnomeNode.freeDocument class method */ + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeNode"); + if (cls == NULL) + { + return; + } + method = (*env)->GetStaticMethodID (env, cls, "freeDocument", + "(Ljava/lang/Object;)V"); + if (method == NULL) + { + return; + } + (*env)->CallStaticVoidMethod (env, cls, method, xmljAsField (env, doc)); +} + +int +xmljMatch (const xmlChar * name, xmlNodePtr node) +{ + switch (node->type) + { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + return xmlStrcmp (node->name, name); + default: + return 1; + } +} + +int +xmljMatchNS (const xmlChar * uri, const xmlChar * localName, xmlNodePtr node) +{ + xmlNsPtr ns; + const xmlChar *nodeLocalName; + int *len; + int ret; + + switch (node->type) + { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + len = (int *) malloc (sizeof (int)); + if (xmlSplitQName3 (node->name, len) != NULL) + { + nodeLocalName = node->name + (*len); + } + else + { + nodeLocalName = node->name; + } + free (len); + ns = node->ns; + if (ns == NULL || ns->href == NULL) + { + if (uri != NULL) + { + return 0; + } + ret = xmlStrcmp (localName, nodeLocalName); + } + else + { + if (uri == NULL) + { + return 0; + } + ret = (xmlStrcmp (localName, nodeLocalName) && + xmlStrcmp (uri, ns->href)); + } + return ret; + default: + return 1; + } +} diff --git a/libjava/classpath/native/jni/xmlj/xmlj_node.h b/libjava/classpath/native/jni/xmlj/xmlj_node.h new file mode 100644 index 00000000000..11f5e308b82 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_node.h @@ -0,0 +1,72 @@ +/* xmlj_node.h - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_NODE_H +#define XMLJ_NODE_H + +#include <jni.h> +#include <libxml/tree.h> + +/* -- Utility method definitions -- */ + +/* + * Returns the node for the given Java node instance + */ +xmlNodePtr xmljGetNodeID (JNIEnv *, jobject); + +/* + * Returns the Java node instance for the given node + */ +jobject xmljGetNodeInstance (JNIEnv *, xmlNodePtr); + +/* + * Frees the specified document pointer, + * releasing all its nodes from the cache. + */ +void xmljFreeDoc (JNIEnv *, xmlDocPtr); + +/* + * Match a node name + */ +int xmljMatch (const xmlChar *, xmlNodePtr); + +/* + * Match a node name and namespace + */ +int xmljMatchNS (const xmlChar *, const xmlChar *, xmlNodePtr); + +#endif /* !defined XMLJ_NODE_H */ diff --git a/libjava/classpath/native/jni/xmlj/xmlj_sax.c b/libjava/classpath/native/jni/xmlj/xmlj_sax.c new file mode 100644 index 00000000000..78991bdad73 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_sax.c @@ -0,0 +1,1445 @@ +/* xmlj_sax.c - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_sax.h" +#include "xmlj_io.h" +#include "xmlj_util.h" +#include <unistd.h> +#include <string.h> + +xmlExternalEntityLoader defaultLoader = NULL; + +void +xmljDispatchError (xmlParserCtxtPtr ctx, + xmlSAXLocatorPtr loc, + JNIEnv *env, + jobject target, + jmethodID method, + const char *msg, + va_list args); + +/* -- GnomeLocator -- */ + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_sax_GnomeLocator_publicId (JNIEnv * env, + jobject self + __attribute__((__unused__)), + jobject j_ctx, + jobject j_loc) +{ + xmlParserCtxtPtr ctx; + xmlSAXLocatorPtr loc; + SAXParseContext *sax; + + ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx); + loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc); + sax = (SAXParseContext *) ctx->_private; + + return sax->publicId; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_sax_GnomeLocator_systemId (JNIEnv * env, + jobject self + __attribute__((__unused__)), + jobject j_ctx, + jobject j_loc) +{ + xmlParserCtxtPtr ctx; + xmlSAXLocatorPtr loc; + SAXParseContext *sax; + + ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx); + loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc); + sax = (SAXParseContext *) ctx->_private; + + return sax->systemId; +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_sax_GnomeLocator_lineNumber (JNIEnv * env, + jobject self + __attribute__((__unused__)), + jobject j_ctx, + jobject j_loc) +{ + xmlParserCtxtPtr ctx; + xmlSAXLocatorPtr loc; + + ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx); + loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc); + if (ctx == NULL || ctx->input == NULL) + { + return -1; + } + return ctx->input->line; +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_sax_GnomeLocator_columnNumber (JNIEnv * env, + jobject self + __attribute__((__unused__)), + jobject j_ctx, + jobject j_loc) +{ + xmlParserCtxtPtr ctx; + xmlSAXLocatorPtr loc; + + ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx); + loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc); + if (ctx == NULL || ctx->input == NULL) + { + return -1; + } + return ctx->input->col; +} + +/* -- GnomeXMLReader -- */ + +/* + * Entry point for SAX parsing. + */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_sax_GnomeXMLReader_parseStream (JNIEnv * env, + jobject self, + jobject in, + jbyteArray detectBuffer, + jstring publicId, + jstring systemId, + jstring base, + jboolean validate, + jboolean contentHandler, + jboolean dtdHandler, + jboolean entityResolver, + jboolean errorHandler, + jboolean + declarationHandler, + jboolean lexicalHandler) +{ + xmljParseDocument (env, + self, + in, + detectBuffer, + publicId, + systemId, + base, + validate, + 0, + 0, + contentHandler, + dtdHandler, + entityResolver, + errorHandler, + declarationHandler, + lexicalHandler, + 0); +} + +xmlParserInputPtr +xmljExternalEntityLoader (const char *url, const char *id, + xmlParserCtxtPtr ctx) +{ + const xmlChar *systemId; + const xmlChar *publicId; + xmlParserInputPtr ret; + + systemId = xmlCharStrdup (url); + publicId = xmlCharStrdup (id); + /* TODO convert systemId to absolute URI */ + ret = xmljSAXResolveEntity (ctx, publicId, systemId); + if (ret == NULL) + { + ret = defaultLoader (url, id, ctx); + } + return ret; +} + +/* + * Allocates and configures a SAX handler that can report the various + * classes of callback. + */ +xmlSAXHandlerPtr +xmljNewSAXHandler (jboolean contentHandler, + jboolean dtdHandler, + jboolean entityResolver, + jboolean errorHandler, + jboolean declarationHandler, + jboolean lexicalHandler) +{ + xmlSAXHandlerPtr sax; + + sax = (xmlSAXHandlerPtr) malloc (sizeof (xmlSAXHandler)); + if (sax == NULL) + { + return NULL; + } + memset (sax, 0, sizeof (xmlSAXHandler)); + xmlSAXVersion (sax, 1); /* TODO SAX2 */ + + if (dtdHandler) + { + sax->internalSubset = &xmljSAXInternalSubset; + } + if (defaultLoader == NULL) + { + defaultLoader = xmlGetExternalEntityLoader (); + xmlSetExternalEntityLoader (xmljExternalEntityLoader); + } + if (entityResolver) + { + sax->resolveEntity = &xmljSAXResolveEntity; + } + + if (declarationHandler) + { + sax->entityDecl = &xmljSAXEntityDecl; + sax->notationDecl = &xmljSAXNotationDecl; + sax->attributeDecl = &xmljSAXAttributeDecl; + sax->elementDecl = &xmljSAXElementDecl; + sax->unparsedEntityDecl = &xmljSAXUnparsedEntityDecl; + } + + /* We always listen for the locator callback */ + sax->setDocumentLocator = &xmljSAXSetDocumentLocator; + if (contentHandler) + { + sax->startDocument = &xmljSAXStartDocument; + sax->endDocument = &xmljSAXEndDocument; + sax->startElement = &xmljSAXStartElement; + sax->endElement = &xmljSAXEndElement; + sax->characters = &xmljSAXCharacters; + sax->ignorableWhitespace = &xmljSAXIgnorableWhitespace; + sax->processingInstruction = &xmljSAXProcessingInstruction; + } + + /* We always intercept getEntity */ + /* TODO this should only be if lexicalHandler */ + sax->getEntity = &xmljSAXGetEntity; + if (lexicalHandler) + { + sax->getEntity = &xmljSAXGetEntity; + sax->reference = &xmljSAXReference; + sax->comment = &xmljSAXComment; + sax->cdataBlock = &xmljSAXCDataBlock; + } + else if (contentHandler) + { + sax->cdataBlock = &xmljSAXCharacters; + } + + if (errorHandler) + { + sax->warning = &xmljSAXWarning; + sax->error = &xmljSAXError; + sax->fatalError = &xmljSAXFatalError; + } + + return sax; +} + +/* -- Callback functions -- */ + +void +xmljSAXInternalSubset (void *vctx, + const xmlChar * name, + const xmlChar * publicId, const xmlChar * systemId) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jstring j_publicId; + jstring j_systemId; + + xmlSAX2InternalSubset (vctx, name, publicId, systemId); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->startDTD == NULL) + { + sax->startDTD = + xmljGetMethodID (env, + target, + "startDTD", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->startDTD == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + j_publicId = xmljNewString (env, publicId); + j_systemId = xmljNewString (env, systemId); + + (*env)->CallVoidMethod (env, + target, + sax->startDTD, + j_name, + j_publicId, + j_systemId); +} + +xmlParserInputPtr +xmljSAXResolveEntity (void *vctx, + const xmlChar * publicId, const xmlChar * systemId) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_publicId; + jstring j_systemId; + jobject inputStream; + + /* xmlSAX2ResolveEntity (vctx, publicId, systemId); */ + + ctx = (xmlParserCtxtPtr) vctx; + if (ctx->_private == NULL) + { + /* Not in Kansas */ + return NULL; + } + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + if ((*env)->ExceptionOccurred (env)) + { + return NULL; + } + + if (sax->resolveEntity == NULL) + { + sax->resolveEntity = + xmljGetMethodID (env, + target, + "resolveEntity", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;"); + if (sax->resolveEntity == NULL) + { + return NULL; + } + } + + j_publicId = xmljNewString (env, publicId); + j_systemId = xmljNewString (env, systemId); + + inputStream = (*env)->CallObjectMethod (env, + target, + sax->resolveEntity, + j_publicId, + j_systemId, + sax->systemId); + + /* Return an xmlParserInputPtr corresponding to the input stream */ + if (inputStream != NULL) + { + jbyteArray detectBuffer; + jmethodID getDetectBuffer; + + /* Get the detect buffer from the NamedInputStream */ + getDetectBuffer = xmljGetMethodID (env, inputStream, "getDetectBuffer", + "()[B"); + if (getDetectBuffer == NULL) + { + return NULL; + } + detectBuffer = (*env)->CallObjectMethod (env, inputStream, + getDetectBuffer); + + return xmljNewParserInput (env, inputStream, detectBuffer, ctx); + } + else + { + return NULL; + } +} + +xmlEntityPtr +xmljSAXGetEntity (void *vctx __attribute__((__unused__)), const xmlChar * name) +{ + xmlEntityPtr ret; + + /* TODO */ + /* ret = xmlSAX2GetEntity (vctx, name); */ + ret = NULL; + return ret; +} + +void +xmljSAXEntityDecl (void *vctx, + const xmlChar * name, + int type, + const xmlChar * publicId, + const xmlChar * systemId, + xmlChar * content) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jstring j_publicId; + jstring j_systemId; + jstring j_value; + + xmlSAX2EntityDecl (vctx, name, type, publicId, systemId, content); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + j_name = xmljNewString (env, name); + switch (type) + { + case XML_INTERNAL_GENERAL_ENTITY: + case XML_INTERNAL_PARAMETER_ENTITY: + case XML_INTERNAL_PREDEFINED_ENTITY: + if (sax->internalEntityDecl == NULL) + { + sax->internalEntityDecl = + xmljGetMethodID (env, + target, + "internalEntityDecl", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->internalEntityDecl == NULL) + { + return; + } + } + j_value = xmljNewString (env, content); + (*env)->CallVoidMethod (env, + target, + sax->internalEntityDecl, + j_name, + j_value); + break; + default: + if (sax->externalEntityDecl == NULL) + { + sax->externalEntityDecl = + xmljGetMethodID (env, + target, + "externalEntityDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->externalEntityDecl == NULL) + { + return; + } + } + j_publicId = xmljNewString (env, publicId); + j_systemId = xmljNewString (env, systemId); + (*env)->CallVoidMethod (env, + target, + sax->externalEntityDecl, + j_name, + j_publicId, + j_systemId); + } +} + +void +xmljSAXNotationDecl (void *vctx, + const xmlChar * name, + const xmlChar * publicId, + const xmlChar * systemId) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jstring j_publicId; + jstring j_systemId; + + xmlSAX2NotationDecl (vctx, name, publicId, systemId); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->notationDecl == NULL) + { + sax->notationDecl = + xmljGetMethodID (env, + target, + "notationDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->notationDecl == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + j_publicId = xmljNewString (env, publicId); + j_systemId = xmljNewString (env, systemId); + + /* Invoke the method */ + (*env)->CallVoidMethod (env, + target, + sax->notationDecl, + j_name, + j_publicId, + j_systemId); +} + +void +xmljSAXAttributeDecl (void *vctx, + const xmlChar * elem, + const xmlChar * fullName, + int type, + int def, + const xmlChar * defaultValue, + xmlEnumerationPtr tree) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_eName; + jstring j_aName; + jstring j_type; + jstring j_mode; + jstring j_value; + + xmlSAX2AttributeDecl (vctx, elem, fullName, type, def, defaultValue, tree); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->attributeDecl == NULL) + { + sax->attributeDecl = + xmljGetMethodID (env, + target, + "attributeDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->attributeDecl == NULL) + { + return; + } + } + + j_eName = xmljNewString (env, elem); + j_aName = xmljNewString (env, fullName); + j_type = xmljAttributeTypeName (env, type); + j_mode = xmljAttributeModeName (env, def); + j_value = xmljNewString (env, defaultValue); + + (*env)->CallVoidMethod (env, + target, + sax->attributeDecl, + j_eName, + j_aName, + j_type, + j_mode, + j_value); +} + +void +xmljSAXElementDecl (void *vctx, + const xmlChar * name, + int type, + xmlElementContentPtr content) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jstring j_model; + + xmlSAX2ElementDecl (vctx, name, type, content); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->elementDecl == NULL) + { + sax->elementDecl = + xmljGetMethodID (env, + target, + "elementDecl", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->elementDecl == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + j_model = NULL; /* TODO */ + + (*env)->CallVoidMethod (env, + target, + sax->elementDecl, + j_name, + j_model); +} + +void +xmljSAXUnparsedEntityDecl (void *vctx, + const xmlChar * name, + const xmlChar * publicId, + const xmlChar * systemId, + const xmlChar * notationName) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jstring j_publicId; + jstring j_systemId; + jstring j_notationName; + + xmlSAX2UnparsedEntityDecl (vctx, name, publicId, systemId, notationName); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->unparsedEntityDecl == NULL) + { + sax->unparsedEntityDecl = + xmljGetMethodID (env, + target, + "unparsedEntityDecl", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->unparsedEntityDecl == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + j_publicId = xmljNewString (env, publicId); + j_systemId = xmljNewString (env, systemId); + j_notationName = xmljNewString (env, notationName); + + (*env)->CallVoidMethod (env, + target, + sax->unparsedEntityDecl, + j_name, + j_publicId, + j_systemId, + j_notationName); +} + +void +xmljSAXSetDocumentLocator (void *vctx, xmlSAXLocatorPtr loc) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + + xmlSAX2SetDocumentLocator (vctx, loc); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + if (target == NULL) + { + /* No Java parse context */ + return; + } + + /* Update locator on sax context */ + sax->loc = loc; + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->setDocumentLocator == NULL) + { + sax->setDocumentLocator = xmljGetMethodID (env, + target, + "setDocumentLocator", + "(Ljava/lang/Object;Ljava/lang/Object;)V"); + if (sax->setDocumentLocator == NULL) + { + return; + } + } + + (*env)->CallVoidMethod (env, + target, + sax->setDocumentLocator, + xmljAsField (env, ctx), + xmljAsField (env, loc)); +} + +void +xmljSAXStartDocument (void *vctx) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + + xmlSAX2StartDocument (vctx); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->startDocument == NULL) + { + sax->startDocument = xmljGetMethodID (env, + target, + "startDocument", + "(Z)V"); + if (sax->startDocument == NULL) + { + return; + } + } + + (*env)->CallVoidMethod (env, + target, + sax->startDocument, + ctx->standalone); +} + +void +xmljSAXEndDocument (void *vctx) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + + xmlSAX2EndDocument (vctx); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->endDocument == NULL) + { + sax->endDocument = xmljGetMethodID (env, + target, + "endDocument", + "()V"); + if (sax->endDocument == NULL) + { + return; + } + } + + (*env)->CallVoidMethod (env, + target, + sax->endDocument); +} + +void +xmljSAXStartElement (void *vctx, + const xmlChar * name, + const xmlChar ** attrs) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + jobjectArray j_attrs; + jstring j_attr; + jsize len; + + xmlSAX2StartElement (vctx, name, attrs); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->startElement == NULL) + { + sax->startElement = + xmljGetMethodID (env, + target, + "startElement", + "(Ljava/lang/String;[Ljava/lang/String;)V"); + if (sax->startElement == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + /* build attributes array */ + len = 0; + for (len = 0; attrs && attrs[len]; len++) + { + } + if (len) + { + if (sax->stringClass == NULL) + { + sax->stringClass = (*env)->FindClass (env, "java/lang/String"); + if (sax->stringClass == NULL) + { + fprintf (stderr, "Can't find java.lang.String class!\n"); + return; + } + } + j_attrs = (*env)->NewObjectArray (env, len, sax->stringClass, NULL); + if (j_attrs == NULL) + { + fprintf (stderr, "Can't allocate attributes array!\n"); + return; + } + len = 0; + for (len = 0; attrs && attrs[len]; len++) + { + j_attr = xmljNewString (env, attrs[len]); + (*env)->SetObjectArrayElement (env, j_attrs, len, j_attr); + } + + (*env)->CallVoidMethod (env, + target, + sax->startElement, + j_name, + j_attrs); + (*env)->DeleteLocalRef (env, j_attrs); + } + else + { + (*env)->CallVoidMethod (env, + target, + sax->startElement, + j_name, + NULL); + + } +} + +void +xmljSAXEndElement (void *vctx, + const xmlChar * name) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_name; + + xmlSAX2EndElement (vctx, name); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->endElement == NULL) + { + sax->endElement = xmljGetMethodID (env, + target, + "endElement", + "(Ljava/lang/String;)V"); + if (sax->endElement == NULL) + { + return; + } + } + + j_name = xmljNewString (env, name); + + (*env)->CallVoidMethod (env, + target, + sax->endElement, + j_name); +} + +void +xmljSAXReference (void *vctx, + const xmlChar * name) +{ + xmlSAX2Reference (vctx, name); +} + +void +xmljSAXCharacters (void *vctx, + const xmlChar * ch, + int len) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_ch; + xmlChar *dup; + + xmlSAX2Characters (vctx, ch, len); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->characters == NULL) + { + sax->characters = xmljGetMethodID (env, + target, + "characters", + "(Ljava/lang/String;)V"); + if (sax->characters == NULL) + { + return; + } + } + + dup = xmlStrndup (ch, len); + j_ch = xmljNewString (env, dup); + + (*env)->CallVoidMethod (env, + target, + sax->characters, + j_ch); + xmlFree (dup); +} + +void +xmljSAXIgnorableWhitespace (void *vctx, + const xmlChar * ch, + int len) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_ch; + xmlChar *dup; + + xmlSAX2IgnorableWhitespace (vctx, ch, len); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->ignorableWhitespace == NULL) + { + sax->ignorableWhitespace = xmljGetMethodID (env, + target, + "ignorableWhitespace", + "(Ljava/lang/String;)V"); + if (sax->ignorableWhitespace == NULL) + { + return; + } + } + + dup = xmlStrndup (ch, len); + j_ch = xmljNewString (env, dup); + + (*env)->CallVoidMethod (env, + target, + sax->ignorableWhitespace, + j_ch); + xmlFree (dup); +} + +void +xmljSAXProcessingInstruction (void *vctx, + const xmlChar * targ, + const xmlChar * data) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_targ; + jstring j_data; + + xmlSAX2ProcessingInstruction (vctx, targ, data); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->processingInstruction == NULL) + { + sax->processingInstruction = + xmljGetMethodID (env, + target, + "processingInstruction", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (sax->processingInstruction == NULL) + { + return; + } + } + + j_targ = xmljNewString (env, targ); + j_data = xmljNewString (env, data); + + (*env)->CallVoidMethod (env, + target, + sax->processingInstruction, + j_targ, + j_data); +} + +void +xmljSAXComment (void *vctx, + const xmlChar * value) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_text; + + xmlSAX2Comment (vctx, value); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->comment == NULL) + { + sax->comment = + xmljGetMethodID (env, + target, + "comment", + "(Ljava/lang/String;)V"); + if (sax->comment == NULL) + { + return; + } + } + + j_text = xmljNewString (env, value); + + (*env)->CallVoidMethod (env, + target, + sax->comment, + j_text); +} + +void +xmljSAXCDataBlock (void *vctx, + const xmlChar * ch, + int len) +{ + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + JNIEnv *env; + jobject target; + jstring j_ch; + xmlChar *dup; + + xmlSAX2CDataBlock (vctx, ch, len); + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + env = sax->env; + target = sax->obj; + + xmljCheckWellFormed (ctx); + if ((*env)->ExceptionOccurred (env)) + { + return; + } + + if (sax->cdataBlock == NULL) + { + sax->cdataBlock = + xmljGetMethodID (env, + target, + "cdataBlock", + "(Ljava/lang/String;)V"); + if (sax->cdataBlock == NULL) + { + return; + } + } + + dup = xmlStrndup (ch, len); + j_ch = xmljNewString (env, dup); + + (*env)->CallVoidMethod (env, + target, + sax->cdataBlock, + j_ch); + xmlFree (dup); +} + +void +xmljDispatchError (xmlParserCtxtPtr ctx, + xmlSAXLocatorPtr loc, + JNIEnv *env, + jobject target, + jmethodID method, + const char *msg, + va_list args) +{ + jint lineNumber; + jint columnNumber; + jstring publicId; + jstring systemId; + char buffer[2048] = ""; + + if (msg != NULL) + { + vsnprintf (buffer, sizeof buffer, msg, args); + } + lineNumber = loc->getLineNumber (ctx); + columnNumber = loc->getColumnNumber (ctx); + publicId = xmljNewString (env, loc->getPublicId (ctx)); + systemId = xmljNewString (env, loc->getSystemId (ctx)); + (*env)->CallVoidMethod (env, + target, + method, + (*env)->NewStringUTF (env, buffer), + lineNumber, + columnNumber, + publicId, + systemId); +} + +void +xmljSAXWarning (void *vctx, + const char *msg, + ...) +{ + va_list args; + + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + xmlSAXLocatorPtr loc; + JNIEnv *env; + jobject target; + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + loc = (xmlSAXLocatorPtr) sax->loc; + env = sax->env; + target = sax->obj; + + if ((*env)->ExceptionOccurred (env)) + { + return; + } + if (sax->warning == NULL) + { + sax->warning = + xmljGetMethodID (env, + target, + "warning", + "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V"); + if (sax->warning == NULL) + { + return; + } + } + + va_start (args, msg); + /* xmlParserWarning (vctx, msg, args); */ + xmljDispatchError (ctx, loc, env, target, sax->warning, msg, args); + va_end (args); +} + +void +xmljSAXError (void *vctx, + const char *msg, + ...) +{ + va_list args; + + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + xmlSAXLocatorPtr loc; + JNIEnv *env; + jobject target; + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + loc = (xmlSAXLocatorPtr) sax->loc; + env = sax->env; + target = sax->obj; + + if ((*env)->ExceptionOccurred (env)) + { + return; + } + if (sax->error == NULL) + { + sax->error = + xmljGetMethodID (env, + target, + "error", + "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V"); + if (sax->error == NULL) + { + return; + } + } + + va_start (args, msg); + /* xmlParserError (vctx, msg, args); */ + xmljDispatchError (ctx, loc, env, target, sax->error, msg, args); + va_end (args); +} + +void +xmljSAXFatalError (void *vctx, + const char *msg, + ...) +{ + va_list args; + + xmlParserCtxtPtr ctx; + SAXParseContext *sax; + xmlSAXLocatorPtr loc; + JNIEnv *env; + jobject target; + + ctx = (xmlParserCtxtPtr) vctx; + sax = (SAXParseContext *) ctx->_private; + loc = (xmlSAXLocatorPtr) sax->loc; + env = sax->env; + target = sax->obj; + + if ((*env)->ExceptionOccurred (env)) + { + return; + } + if (sax->fatalError == NULL) + { + sax->fatalError = + xmljGetMethodID (env, + target, + "fatalError", + "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V"); + if (sax->fatalError == NULL) + { + return; + } + } + + va_start (args, msg); + /* xmlParserError (vctx, msg, args); */ + xmljDispatchError (ctx, loc, env, target, sax->fatalError, msg, args); + va_end (args); +} + +void +xmljCheckWellFormed (xmlParserCtxtPtr ctx) +{ + if (!ctx->wellFormed) + { + xmljSAXFatalError (ctx, "document is not well-formed"); + } + if (ctx->validate && !ctx->valid) + { + xmljSAXFatalError (ctx, "document is not valid"); + } +} + +/* + * Convert a libxml2 attribute type to a string. + */ +jstring +xmljAttributeTypeName (JNIEnv * env, int type) +{ + const char *text; + + switch (type) + { + case XML_ATTRIBUTE_CDATA: + text = "CDATA"; + break; + case XML_ATTRIBUTE_ID: + text = "ID"; + break; + case XML_ATTRIBUTE_IDREF: + text = "IDREF"; + break; + case XML_ATTRIBUTE_IDREFS: + text = "IDREFS"; + break; + case XML_ATTRIBUTE_NMTOKEN: + text = "NMTOKEN"; + break; + case XML_ATTRIBUTE_NMTOKENS: + text = "NMTOKENS"; + break; + case XML_ATTRIBUTE_ENTITY: + text = "ID"; + break; + case XML_ATTRIBUTE_ENTITIES: + text = "ID"; + break; + default: + return NULL; + } + + return (*env)->NewStringUTF (env, text); +} + +/* + * Convert a libxml2 attribute default value type to a string. + */ +jstring +xmljAttributeModeName (JNIEnv * env, int type) +{ + const char *text; + + switch (type) + { + case XML_ATTRIBUTE_IMPLIED: + text = "#IMPLIED"; + break; + case XML_ATTRIBUTE_REQUIRED: + text = "#REQUIRED"; + break; + case XML_ATTRIBUTE_FIXED: + text = "#FIXED"; + break; + default: + return NULL; + } + + return (*env)->NewStringUTF (env, text); +} diff --git a/libjava/classpath/native/jni/xmlj/xmlj_sax.h b/libjava/classpath/native/jni/xmlj/xmlj_sax.h new file mode 100644 index 00000000000..249929ce02a --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_sax.h @@ -0,0 +1,160 @@ +/* xmlj_sax.h - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_SAX_H +#define XMLJ_SAX_H + +#include "gnu_xml_libxmlj_sax_GnomeLocator.h" +#include "gnu_xml_libxmlj_sax_GnomeXMLReader.h" + +#include <libxml/SAX.h> +#include <libxml/parser.h> + +xmlSAXHandlerPtr +xmljNewSAXHandler (jboolean contentHandler, + jboolean dtdHandler, + jboolean entityResolver, + jboolean errorHandler, + jboolean declarationHandler, + jboolean lexicalHandler); + +xmlParserInputPtr +xmljExternalEntityLoader (const char *systemId, const char *publicId, + xmlParserCtxtPtr context); + +/* -- Function declarations for callback functions -- */ + +void xmljSAXInternalSubset(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); + +xmlParserInputPtr xmljSAXResolveEntity(void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +xmlEntityPtr xmljSAXGetEntity(void *ctx, + const xmlChar *name); + +void xmljSAXEntityDecl(void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); + +void xmljSAXNotationDecl(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); + +void xmljSAXAttributeDecl(void *ctx, + const xmlChar *elem, + const xmlChar *fullName, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); + +void xmljSAXElementDecl(void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); + +void xmljSAXUnparsedEntityDecl(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +void xmljSAXSetDocumentLocator(void *ctx, + xmlSAXLocatorPtr loc); + +void xmljSAXStartDocument(void *ctx); + +void xmljSAXEndDocument(void *ctx); + +void xmljSAXStartElement(void *ctx, + const xmlChar *name, + const xmlChar **atts); + +void xmljSAXEndElement(void *ctx, + const xmlChar *name); + +void xmljSAXReference(void *ctx, + const xmlChar *name); + +void xmljSAXCharacters(void *ctx, + const xmlChar *ch, + int len); + +void xmljSAXIgnorableWhitespace(void *ctx, + const xmlChar *ch, + int len); + +void xmljSAXProcessingInstruction(void *ctx, + const xmlChar *target, + const xmlChar *data); + +void xmljSAXComment(void *ctx, + const xmlChar *value); + +void xmljSAXCDataBlock(void *ctx, + const xmlChar *ch, + int len); + +void xmljSAXWarning(void *ctx, + const char *msg, + ...); + +void xmljSAXError(void *ctx, + const char *msg, + ...); + +void xmljSAXFatalError(void *ctx, + const char *msg, + ...); + +void xmljCheckWellFormed(xmlParserCtxtPtr ctx); + +jstring xmljAttributeTypeName (JNIEnv *env, + int type); + +jstring xmljAttributeModeName (JNIEnv *env, + int type); + +#endif /* !defined XMLJ_SAX_H */ diff --git a/libjava/classpath/native/jni/xmlj/xmlj_transform.c b/libjava/classpath/native/jni/xmlj/xmlj_transform.c new file mode 100644 index 00000000000..075409ad10a --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_transform.c @@ -0,0 +1,868 @@ +/* xmlj_transform.c - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gnu_xml_libxmlj_transform_GnomeTransformerFactory.h" +#include "gnu_xml_libxmlj_transform_GnomeTransformer.h" + +#include "xmlj_dom.h" +#include "xmlj_io.h" +#include "xmlj_error.h" +#include "xmlj_node.h" +#include "xmlj_sax.h" +#include "xmlj_util.h" + +#include <math.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/xmlmemory.h> +#include <libxml/debugXML.h> +#include <libxml/xmlIO.h> +#include <libxml/xinclude.h> +#include <libxml/parser.h> +#include <libxml/catalog.h> +#include <libxslt/keys.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> +#include <libxslt/functions.h> +#include <libxslt/extensions.h> +#include <libxslt/documents.h> + +/* Local function prototypes */ + +void +xmljDocumentFunction (xmlXPathParserContextPtr ctxt, int nargs); + +xsltStylesheetPtr +xmljGetStylesheetID (JNIEnv * env, jobject transformer); + +jobject +xmljGetTransformerProperties (JNIEnv *env, jobject transformer); + +const xmlChar * +xmljBooleanToString (int value); + +void +xmljSetOutputProperties (JNIEnv *env, jobject transformer, + xsltStylesheetPtr stylesheet); + +jobjectArray +xmljGetParameterArray (JNIEnv *env, jobject transformer); + +const char ** +xmljGetParameters (JNIEnv *env, jobjectArray pa); + +void +xmljFreeParameters (JNIEnv *env, jobjectArray pa, const char **parameters); + +xmlDocPtr +xmljTransform (JNIEnv *env, jobject transformer, xmlDocPtr source); + +void +xmljTransformToSAX (JNIEnv *env, jobject transformer, xmlDocPtr source, + jobject callback); + +xmlDocPtr +xmljDocLoader (const xmlChar *uri, xmlDictPtr dict, int options, + void *ctxt, xsltLoadType type); + +/* HACK: store stylesheet URL as context for resolving URIs in xmljDocLoader */ +static jstring stylesheetURL = NULL; + +/* + * -------------------------------------------------------------------------- + * + * Native implementation for class + * gnu.xml.libxmlj.transform.GnomeTransformer follows. + */ + +static void +xmljSetProperty (JNIEnv * env, jobject outputProperties, + jmethodID setPropertyMethodID, const char *name, + const xmlChar * value) +{ + if (NULL != value) + { + jstring nameString = (*env)->NewStringUTF (env, name); + jstring valueString = (*env)->NewStringUTF (env, (const char *) value); + + jobject prevValue = (*env)->CallObjectMethod (env, outputProperties, + setPropertyMethodID, + nameString, valueString); + if (NULL != prevValue) + { + (*env)->DeleteLocalRef (env, prevValue); + } + + (*env)->DeleteLocalRef (env, nameString); + (*env)->DeleteLocalRef (env, valueString); + } +} + +typedef struct CdataSectionScannerInfo_ +{ + JNIEnv *env; + jobject stringBuffer; + jmethodID appendMethodID; + int isFirst; +} CdataSectionScannerInfo; + +static void +cdataSectionScanner (void *payload, void *data, xmlChar * name) +{ + CdataSectionScannerInfo *info = (CdataSectionScannerInfo *) data; + JNIEnv *env = info->env; + jstring nameString = (*env)->NewStringUTF (env, (const char *) name); + jstring blankString = (*env)->NewStringUTF (env, " "); + jobject stringBuffer; + if (!info->isFirst) + { + stringBuffer + = (*env)->CallObjectMethod (env, + info->stringBuffer, + info->appendMethodID, blankString); + (*env)->DeleteLocalRef (env, stringBuffer); + } + info->isFirst = 0; + stringBuffer + = (*env)->CallObjectMethod (env, + info->stringBuffer, + info->appendMethodID, nameString); + (*env)->DeleteLocalRef (env, stringBuffer); + (*env)->DeleteLocalRef (env, blankString); + (*env)->DeleteLocalRef (env, nameString); +} + +void +xmljDocumentFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr obj, obj2 = NULL; + + if ((nargs < 1) || (nargs > 2)) + { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, + "document() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if (ctxt->value == NULL) + { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, + "document() : invalid arg value\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + + if (nargs == 2) + { + if (ctxt->value->type != XPATH_NODESET) + { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, + "document() : invalid arg expecting a nodeset\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + + obj2 = valuePop (ctxt); + } + + if (ctxt->value->type == XPATH_NODESET) + { + int i; + xmlXPathObjectPtr newobj, ret; + + obj = valuePop (ctxt); + ret = xmlXPathNewNodeSet (NULL); + + if (obj->nodesetval) + { + for (i = 0; i < obj->nodesetval->nodeNr; i++) + { + valuePush (ctxt, + xmlXPathNewNodeSet (obj->nodesetval->nodeTab[i])); + xmlXPathStringFunction (ctxt, 1); + if (nargs == 2) + { + valuePush (ctxt, xmlXPathObjectCopy (obj2)); + } + else + { + valuePush (ctxt, + xmlXPathNewNodeSet (obj->nodesetval-> + nodeTab[i])); + } + xsltDocumentFunction (ctxt, 2); + newobj = valuePop (ctxt); + ret->nodesetval = xmlXPathNodeSetMerge (ret->nodesetval, + newobj->nodesetval); + xmlXPathFreeObject (newobj); + } + } + + xmlXPathFreeObject (obj); + if (obj2 != NULL) + { + xmlXPathFreeObject (obj2); + } + valuePush (ctxt, ret); + return; + } + /* + * Make sure it's converted to a string + */ + xmlXPathStringFunction (ctxt, 1); + if (ctxt->value->type != XPATH_STRING) + { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, + "document() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + if (obj2 != NULL) + xmlXPathFreeObject (obj2); + return; + } + obj = valuePop (ctxt); + if (obj->stringval == NULL) + { + valuePush (ctxt, xmlXPathNewNodeSet (NULL)); + } + else + { + + xsltTransformContextPtr tctxt; + + tctxt = xsltXPathGetTransformContext (ctxt); + + { + SAXParseContext *saxContext = + (SAXParseContext *) tctxt->style->_private; + + xmlDocPtr tree = xmljResolveURIAndOpen (saxContext, + (const char*)obj->stringval, + NULL); + + xsltNewDocument (tctxt, tree); /* FIXME - free at a later point */ + + valuePush (ctxt, xmlXPathNewNodeSet ((xmlNodePtr) tree)); + } + } + xmlXPathFreeObject (obj); + if (obj2 != NULL) { + xmlXPathFreeObject (obj2); + } +} + +/* + * Returns the stylesheet pointer for the given GnomeTransformer. + */ +xsltStylesheetPtr +xmljGetStylesheetID (JNIEnv * env, jobject transformer) +{ + jclass cls; + jfieldID field; + jobject id; + xsltStylesheetPtr stylesheet; + + if (transformer == NULL) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "Transformer is null"); + return NULL; + } + cls = (*env)->GetObjectClass (env, transformer); + if (cls == NULL) + { + return NULL; + } + field = (*env)->GetFieldID (env, cls, "stylesheet", "Ljava/lang/Object;"); + if (field == NULL) + { + return NULL; + } + id = (*env)->GetObjectField (env, transformer, field); + stylesheet = (xsltStylesheetPtr) xmljAsPointer (env, id); + if (stylesheet == NULL) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "Stylesheet is null"); + return NULL; + } + return stylesheet; +} + +jobject +xmljGetTransformerProperties (JNIEnv *env, jobject transformer) +{ + jclass cls; + jfieldID field; + + cls = (*env)->GetObjectClass (env, transformer); + if (cls == NULL) + { + return NULL; + } + field = (*env)->GetFieldID (env, cls, "outputProperties", + "Ljava/util/Properties;"); + if (field == NULL) + { + return NULL; + } + return (*env)->GetObjectField (env, transformer, field); +} + +const xmlChar * +xmljBooleanToString (int value) +{ + return value ? BAD_CAST "yes" : BAD_CAST "no"; +} + +/* + * Sets the output properties for the given transformer, + * based on its stylesheet. + */ +void +xmljSetOutputProperties (JNIEnv *env, jobject transformer, + xsltStylesheetPtr stylesheet) +{ + jobject outputProperties; + jclass propertiesClass; + jmethodID setPropertyMethod; + + outputProperties = xmljGetTransformerProperties (env, transformer); + if (outputProperties == NULL) + { + return; + } + propertiesClass = (*env)->FindClass (env, "java/util/Properties"); + if (propertiesClass == NULL) + { + return; + } + setPropertyMethod = + (*env)->GetMethodID (env, propertiesClass, "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); + if (setPropertyMethod == NULL) + { + return; + } + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "encoding", stylesheet->encoding); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "media-type", stylesheet->mediaType); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "doctype-public", stylesheet->doctypePublic); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "doctype-system", stylesheet->doctypeSystem); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "indent", xmljBooleanToString (stylesheet->indent)); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "method", stylesheet->method); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "standalone", xmljBooleanToString (stylesheet->standalone)); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "version", stylesheet->version); + + xmljSetProperty (env, outputProperties, setPropertyMethod, + "omit-xml-declaration", + xmljBooleanToString (stylesheet->omitXmlDeclaration)); + + { + CdataSectionScannerInfo info; + jclass stringBufferClass + = + (*env)->FindClass (env, + "java/lang/StringBuffer"); + jmethodID stringBufferConstructorID = + (*env)->GetMethodID (env, stringBufferClass, + "<init>", "()V"); + jmethodID toStringMethodID = + (*env)->GetMethodID (env, stringBufferClass, + "toString", + "()Ljava/lang/String;"); + info.env = env; + info.isFirst = 1; + info.stringBuffer + = (*env)->AllocObject (env, stringBufferClass); + (*env)->CallVoidMethod (env, info.stringBuffer, + stringBufferConstructorID); + info.appendMethodID = + (*env)->GetMethodID (env, stringBufferClass, + "append", + "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); + + xmlHashScan (stylesheet->cdataSection, + cdataSectionScanner, &info); + + { + jstring result = (jstring) + (*env)->CallObjectMethod (env, + info.stringBuffer, + toStringMethodID); + + jstring nameString = + (*env)->NewStringUTF (env, + "cdata-section-elements"); + + jobject prevValue + = + (*env)->CallObjectMethod (env, + outputProperties, + setPropertyMethod, + nameString, result); + if (NULL != prevValue) + { + (*env)->DeleteLocalRef (env, prevValue); + } + (*env)->DeleteLocalRef (env, nameString); + } + + (*env)->DeleteLocalRef (env, info.stringBuffer); + } +} + +/* + * Returns the parameter array for the given GnomeTransformer. + */ +jobjectArray +xmljGetParameterArray (JNIEnv *env, jobject transformer) +{ + jclass cls; + jmethodID method; + + cls = (*env)->GetObjectClass (env, transformer); + if (cls == NULL) + { + return NULL; + } + method = (*env)->GetMethodID (env, cls, "getParameterArray", + "()[Ljava/lang/String;"); + if (method == NULL) + { + return NULL; + } + return (jobjectArray) (*env)->CallObjectMethod (env, transformer, method); +} + +/* Convert parameter array to xmlChar ** */ +const char ** +xmljGetParameters (JNIEnv *env, jobjectArray pa) +{ + int i, len; + const char **parameters; + + len = (*env)->GetArrayLength (env, pa); + parameters = (const char **) malloc ((len + 2) * sizeof (const char *)); + if (parameters == NULL) + { + return NULL; + } + + for (i = 0; i < len; i++) + { + jstring string = (jstring) (*env)->GetObjectArrayElement (env, pa, i); + + if (string != NULL) + { + parameters[i] = (*env)->GetStringUTFChars (env, string, NULL); + } + else + { + parameters[i] = NULL; + } + } + + parameters[len] = 0; + parameters[len + 1] = 0; + return parameters; +} + +/* Release parameter strings */ +void +xmljFreeParameters (JNIEnv *env, jobjectArray pa, const char **parameters) +{ + int i, len; + + len = (*env)->GetArrayLength (env, pa); + for (i = 0; i < len; i++) + { + jstring string = (jstring) (*env)->GetObjectArrayElement (env, pa, i); + if (string != NULL) + { + (*env)->ReleaseStringUTFChars (env, string, parameters[i]); + } + } + + free (parameters); +} + +xmlDocPtr +xmljTransform (JNIEnv *env, jobject transformer, xmlDocPtr source) +{ + xsltStylesheetPtr stylesheet; + xmlDocPtr result; + jobjectArray pa; + const char **parameters; + + stylesheet = xmljGetStylesheetID (env, transformer); + pa = xmljGetParameterArray (env, transformer); + parameters = xmljGetParameters (env, pa); + if (parameters == NULL) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "Couldn't allocate memory for parameters"); + return NULL; + } + result = xsltApplyStylesheet (stylesheet, source, parameters); + xmljFreeParameters (env, pa, parameters); + if (result == NULL) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "XSLT transformation failed"); + } + return result; +} + +void +xmljTransformToSAX (JNIEnv *env, jobject transformer, xmlDocPtr source, + jobject callback) +{ + xsltStylesheetPtr stylesheet; + int ret; + jobjectArray pa; + const char **parameters; + xmlSAXHandlerPtr sax; + + stylesheet = xmljGetStylesheetID (env, transformer); + pa = xmljGetParameterArray (env, transformer); + parameters = xmljGetParameters (env, pa); + if (parameters == NULL) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "Couldn't allocate memory for parameters"); + return; + } + sax = NULL; /* TODO link up sax and callback */ + ret = xsltRunStylesheet (stylesheet, source, parameters, NULL, sax, NULL); + xmljFreeParameters (env, pa, parameters); + if (ret == -1) + { + xmljThrowException (env, "javax/xml/transform/TransformerException", + "XSLT transformation failed"); + } +} + +xmlDocPtr +xmljDocLoader (const xmlChar *uri, xmlDictPtr dict, int options, + void *ctxt, xsltLoadType type) +{ + JNIEnv *env; + jclass xmljClass; + jclass inputStreamClass; + jmethodID getInputStream; + jmethodID getDetectBuffer; + jstring systemId; + jobject inputStream; + jbyteArray detectBuffer; + + fflush(stdout); + env = xmljGetJNIEnv (); + if (!env) + { + return NULL; + } + xmljClass = (*env)->FindClass (env, "gnu/xml/libxmlj/util/XMLJ"); + if (!xmljClass) + { + return NULL; + } + getInputStream = + (*env)->GetStaticMethodID (env, xmljClass, "xmljGetInputStream", + "(Ljava/lang/String;Ljava/lang/String;)Lgnu/xml/libxmlj/util/NamedInputStream;"); + if (!getInputStream) + { + return NULL; + } + systemId = xmljNewString (env, uri); + inputStream = (*env)->CallStaticObjectMethod (env, xmljClass, getInputStream, + stylesheetURL, systemId); + if (!inputStream) + { + return NULL; + } + inputStreamClass = (*env)->GetObjectClass (env, inputStream); + if (!inputStreamClass) + { + return NULL; + } + getDetectBuffer = (*env)->GetMethodID (env, inputStreamClass, + "getDetectBuffer", "()[B"); + if (!getDetectBuffer) + { + return NULL; + } + detectBuffer = (*env)->CallObjectMethod (env, inputStream, getDetectBuffer); + if (!detectBuffer) + { + return NULL; + } + return xmljParseDocument (env, NULL, inputStream, detectBuffer, + NULL, systemId, stylesheetURL, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2); +} + +/* GnomeTransformer.newStylesheet */ +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_newStylesheet (JNIEnv *env, + jobject self) +{ + xsltStylesheetPtr stylesheet; + jobject ret; + + stylesheetURL = NULL; + xsltSetLoaderFunc (xmljDocLoader); + stylesheet = xsltNewStylesheet (); + xmljSetOutputProperties (env, self, stylesheet); + ret = xmljAsField (env, stylesheet); + if (ret == NULL) + { + xmljThrowException (env, + "javax/xml/transform/TransformerConfigurationException", + "Can't create Java object for stylesheet"); + } + return ret; +} + +/* GnomeTransformer.newStylesheetFromStream */ +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_newStylesheetFromStream +(JNIEnv *env, jobject self, jobject in, jbyteArray detectBuffer, + jstring publicId, jstring systemId, jstring base, + jboolean entityResolver, jboolean errorHandler) +{ + xmlDocPtr doc; + xsltStylesheetPtr stylesheet; + jobject ret; + + doc = xmljParseDocument (env, self, in, detectBuffer, publicId, systemId, + base, 0, 0, 0, 0, 0, + entityResolver, errorHandler, 0, 0, 2); + if (doc == NULL) + { + return NULL; + } + stylesheetURL = systemId; + xsltSetLoaderFunc (xmljDocLoader); + stylesheet = xsltParseStylesheetDoc (doc); + if (stylesheet == NULL) + { + xmljThrowException (env, + "javax/xml/transform/TransformerConfigurationException", + "Error parsing XSLT stylesheet"); + return NULL; + } + xmljSetOutputProperties (env, self, stylesheet); + ret = xmljAsField (env, stylesheet); + if (ret == NULL) + { + xmljThrowException (env, + "javax/xml/transform/TransformerConfigurationException", + "Can't create Java object for stylesheet"); + } + return ret; +} + +/* GnomeTransformer.newStylesheetFromDoc */ +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_newStylesheetFromDoc +(JNIEnv *env, jobject self, jobject in) +{ + xmlDocPtr doc; + xsltStylesheetPtr stylesheet; + jobject ret; + + doc = (xmlDocPtr) xmljGetNodeID (env, in); + if (doc == NULL) + { + return NULL; + } + stylesheetURL = xmljNewString (env, doc->URL); + xsltSetLoaderFunc (xmljDocLoader); + stylesheet = xsltParseStylesheetDoc (doc); + if (stylesheet == NULL) + { + xmljThrowException (env, + "javax/xml/transform/TransformerConfigurationException", + "Error parsing XSLT stylesheet"); + } + xmljSetOutputProperties (env, self, stylesheet); + ret = xmljAsField (env, stylesheet); + if (ret == NULL) + { + xmljThrowException (env, + "javax/xml/transform/TransformerConfigurationException", + "Can't create Java object for stylesheet"); + } + return ret; +} + +/* GnomeTransformer.transformStreamToStream */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformStreamToStream +(JNIEnv *env, jobject self, jobject in, jbyteArray detectBuffer, + jstring publicId, jstring systemId, jstring base, + jboolean entityResolver, jboolean errorHandler, jobject out) +{ + xmlDocPtr source; + xmlDocPtr result; + + source = xmljParseDocument (env, self, in, detectBuffer, publicId, systemId, + base, 0, 0, 0, 0, 0, + entityResolver, errorHandler, 0, 0, 2); + result = xmljTransform (env, self, source); + xmljSaveFileToJavaOutputStream (env, out, result, + (const char*) result->encoding); + xmlFreeDoc (result); +} + +/* GnomeTransformer.transformStreamToDoc */ +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformStreamToDoc +(JNIEnv *env, jobject self, jobject in, jbyteArray detectBuffer, + jstring publicId, jstring systemId, jstring base, + jboolean entityResolver, jboolean errorHandler) +{ + xmlDocPtr source; + xmlDocPtr result; + + source = xmljParseDocument (env, self, in, detectBuffer, publicId, systemId, + base, 0, 0, 0, 0, 0, + entityResolver, errorHandler, 0, 0, 2); + result = xmljTransform (env, self, source); + return xmljGetNodeInstance (env, (xmlNodePtr) result); +} + +/* GnomeTransformer.transformStreamToSAX */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformStreamToSAX +(JNIEnv *env, jobject self, jobject in, jbyteArray detectBuffer, + jstring publicId, jstring systemId, jstring base, + jboolean entityResolver, jboolean errorHandler, jobject callback) +{ + xmlDocPtr source; + + source = xmljParseDocument (env, self, in, detectBuffer, publicId, systemId, + base, 0, 0, 0, 0, 0, + entityResolver, errorHandler, 0, 0, 2); + xmljTransformToSAX (env, self, source, callback); +} + +/* GnomeTransformer.transformDocToStream */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformDocToStream +(JNIEnv *env, jobject self, jobject doc, jobject out) +{ + xmlDocPtr source; + xmlDocPtr result; + + source = (xmlDocPtr) xmljGetNodeID (env, doc); + result = xmljTransform (env, self, source); + xmljSaveFileToJavaOutputStream (env, out, result, + (const char*) result->encoding); + xmlFreeDoc (result); +} + +/* GnomeTransformer.transformDocToDoc */ +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformDocToDoc +(JNIEnv *env, jobject self, jobject doc) +{ + xmlDocPtr source; + xmlDocPtr result; + + source = (xmlDocPtr) xmljGetNodeID (env, doc); + result = xmljTransform (env, self, source); + return xmljGetNodeInstance (env, (xmlNodePtr) result); +} + +/* GnomeTransformer.transformDocToSAX */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_transformDocToSAX +(JNIEnv *env, jobject self, jobject doc, jobject callback) +{ + xmlDocPtr source; + + source = (xmlDocPtr) xmljGetNodeID (env, doc); + xmljTransformToSAX (env, self, source, callback); +} + +/* GnomeTransformer.free */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformer_free (JNIEnv *env, + jobject self) +{ + xsltStylesheetPtr stylesheet; + + stylesheet = xmljGetStylesheetID (env, self); + xsltFreeStylesheet (stylesheet); +} + +/* + * -------------------------------------------------------------------------- + * Native implementation for class + * gnu.xml.libxmlj.transform.GnomeTransformerFactory follows. + */ + +/* GnomeTransformerFactory.freeLibxsltGlobal */ +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_transform_GnomeTransformerFactory_freeLibxsltGlobal ( + JNIEnv *env __attribute__((__unused__)), + jclass clazz __attribute__((__unused__))) +{ + xsltCleanupGlobals (); + xmlCleanupParser (); +} + diff --git a/libjava/classpath/native/jni/xmlj/xmlj_util.c b/libjava/classpath/native/jni/xmlj/xmlj_util.c new file mode 100644 index 00000000000..498cb70923c --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_util.c @@ -0,0 +1,301 @@ +/* xmlj_util.c + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "xmlj_util.h" +#include "xmlj_error.h" +#include <libxml/tree.h> +#include <unistd.h> + +/* xmlChar->jstring cache */ +#ifdef XMLJ_STRING_CACHE +#define XMLJ_STRING_CACHE_SIZE 1024 +xmlHashTablePtr xmljStringCache = NULL; + +void +xmljHashDeallocate (void *data, xmlChar *name); + +void +xmljHashDeallocate (void *data, xmlChar *name) +{ + /* NOOP */ +} +#endif /* XMLJ_STRING_CACHE */ + +jstring +xmljNewString (JNIEnv * env, const xmlChar * text) +{ + jstring ret; + + if (text == NULL || (*env)->ExceptionOccurred (env)) + { + return NULL; + } +#ifdef XMLJ_STRING_CACHE + if (xmljStringCache == NULL) /* Init cache */ + { + xmljStringCache = xmlHashCreate (XMLJ_STRING_CACHE_SIZE); + } + ret = (jstring) xmlHashLookup (xmljStringCache, text); + if (ret == NULL) + { + ret = (*env)->NewStringUTF (env, (char *) text); + if (ret == NULL) /* Why? */ + { + fprintf(stderr, "xmljNewString: ERROR: NewStringUTF returned null for \"%s\"\n", text); + fflush (stderr); + } + else + { + xmlHashAddEntry (xmljStringCache, text, ret); + } + } +#else + ret = (*env)->NewStringUTF (env, (char *) text); + if (ret == NULL) /* Why? */ + { + printf("xmljNewString: ERROR: NewStringUTF returned null for \"%s\"\n", text); + } +#endif /* XMLJ_STRING_CACHE */ + return ret; +} + +void +xmljClearStringCache () +{ +#ifdef XMLJ_STRING_CACHE + if (xmljStringCache != NULL) + { + xmlHashFree (xmljStringCache, &xmljHashDeallocate); + } +#endif /* XMLJ_STRING_CACHE */ +} + +const xmlChar * +xmljGetStringChars (JNIEnv * env, jstring text) +{ + const char *s_text; + xmlChar *x_text; + + if (text == NULL) + { + return NULL; + } + + s_text = (*env)->GetStringUTFChars (env, text, 0); + x_text = (s_text == NULL) ? NULL : xmlCharStrdup (s_text); + if (s_text != NULL && x_text == NULL) + { + /* TODO raise exception */ + } + (*env)->ReleaseStringUTFChars (env, text, s_text); + return x_text; +} + +const xmlChar * +xmljGetPrefix (const xmlChar * qName) +{ + const xmlChar *localName; + const xmlChar *ret; + xmlChar **prefix; + + prefix = (xmlChar **) malloc (sizeof (xmlChar *)); + localName = xmlSplitQName2 (qName, prefix); + if (localName == NULL) + { + return NULL; + } + ret = *prefix; + free (prefix); + return ret; +} + +const xmlChar * +xmljGetLocalName (const xmlChar * qName) +{ + const xmlChar *localName; + xmlChar **prefix; + + prefix = (xmlChar **) malloc (sizeof (xmlChar *)); + localName = xmlSplitQName2 (qName, prefix); + if (localName == NULL) + { + return qName; + } + free (prefix); + return localName; +} + +jmethodID xmljGetMethodID (JNIEnv *env, + jobject target, + const char *name, + const char *signature) +{ + jclass cls; + jmethodID ret; + + cls = (*env)->GetObjectClass (env, target); + if (cls == NULL) + { + xmljThrowException (env, + "java/lang/ClassNotFoundException", + NULL); + return NULL; + } + ret = (*env)->GetMethodID (env, + cls, + name, + signature); + if (ret == NULL) + { + jclass clscls; + jmethodID nm; + jstring clsname; + const char *c_clsName; + char cat[512] = "[method signature too long]"; + + clscls = (*env)->FindClass (env, "java/lang/Class"); + if (clscls == NULL) + { + return NULL; + } + nm = (*env)->GetMethodID (env, clscls, "getName", + "()Ljava/lang/String;"); + if (nm == NULL) + { + return NULL; + } + clsname = (jstring) (*env)->CallObjectMethod (env, + (jobject)cls, + nm); + if (clsname == NULL) + { + return NULL; + } + c_clsName = (*env)->GetStringUTFChars (env, clsname, 0); + sprintf (cat, "%s.%s %s", c_clsName, name, signature); + xmljThrowException (env, + "java/lang/NoSuchMethodException", + cat); + (*env)->ReleaseStringUTFChars (env, clsname, c_clsName); + } + return ret; +} + +void * +xmljAsPointer (JNIEnv *env, jobject ptr) +{ + jclass cls; + jfieldID field; + +#if defined XMLJ_64BIT_POINTER + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + field = (*env)->GetFieldID (env, cls, "data", "J"); + return (void *) (*env)->GetLongField (env, ptr, field); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + field = (*env)->GetFieldID (env, cls, "data", "I"); + return (void *) (*env)->GetIntField (env, ptr, field); +#endif +} + +jobject +xmljAsField (JNIEnv *env, void * ptr) +{ + jclass cls; + jmethodID method; + +#if defined XMLJ_64BIT_POINTER + cls = (*env)->FindClass (env, "gnu/classpath/RawData64"); + method = (*env)->GetMethodID (env, cls, "<init>", "(J)V"); + return (*env)->NewObject (env, cls, method, (jlong) ptr); +#else + cls = (*env)->FindClass (env, "gnu/classpath/RawData32"); + method = (*env)->GetMethodID (env, cls, "<init>", "(I)V"); + return (*env)->NewObject (env, cls, method, (jint) ptr); +#endif +} + +JNIEnv * +xmljGetJNIEnv () +{ + JavaVM **jvms; + jsize *jvm_count; + JavaVM *jvm; + JNIEnv **envs; + JNIEnv *env; + + jvms = (JavaVM **) malloc (sizeof (JavaVM *)); + if (!jvms) + { + return NULL; + } + jvm_count = (jsize *) malloc (sizeof (jsize)); + if (!jvm_count) + { + free (jvms); + return NULL; + } + if (JNI_GetCreatedJavaVMs (jvms, 1, jvm_count)) + { + free (jvms); + free (jvm_count); + return NULL; + } + jvm = *jvms; + envs = (JNIEnv **) malloc (sizeof (JNIEnv *)); + if (!envs) + { + free (jvms); + free (jvm_count); + return NULL; + } + (*jvm)->AttachCurrentThread (jvm, (void **) envs, NULL); + (*jvm)->GetEnv (jvm, (void **) envs, JNI_VERSION_1_2); + if (envs) + { + env = *envs; + free (envs); + } + else + { + env = NULL; + } + free (jvms); + free (jvm_count); + return env; +} + diff --git a/libjava/classpath/native/jni/xmlj/xmlj_util.h b/libjava/classpath/native/jni/xmlj/xmlj_util.h new file mode 100644 index 00000000000..7bbe78b8e1f --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_util.h @@ -0,0 +1,69 @@ +/* xmlj_util.h - + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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. */ + +#ifndef XMLJ_UTIL_H +#define XMLJ_UTIL_H + +#if defined __64BIT__ || defined __LP64 || defined _LP64 || defined __LP64__ || defined _ADDR64 +# define XMLJ_64BIT_POINTER 1 +#endif + +#include <jni.h> +#include <libxml/xmlstring.h> + +jstring xmljNewString (JNIEnv *, const xmlChar *); + +void xmljClearStringCache (void); + +const xmlChar *xmljGetStringChars (JNIEnv *, jstring); + +const xmlChar *xmljGetPrefix (const xmlChar * qName); + +const xmlChar *xmljGetLocalName (const xmlChar * qName); + +jmethodID xmljGetMethodID (JNIEnv *env, + jobject target, + const char *name, + const char *signature); + +void * xmljAsPointer (JNIEnv *env, jobject field); + +jobject xmljAsField (JNIEnv *env, void * ptr); + +JNIEnv * xmljGetJNIEnv (void); + +#endif /* !defined XMLJ_UTIL_H */ diff --git a/libjava/classpath/native/jni/xmlj/xmlj_xpath.c b/libjava/classpath/native/jni/xmlj/xmlj_xpath.c new file mode 100644 index 00000000000..6d014cefc91 --- /dev/null +++ b/libjava/classpath/native/jni/xmlj/xmlj_xpath.c @@ -0,0 +1,625 @@ +/* xmlj_xpath.c - + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +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 GNU General Public License cover the whole +combination. + +As a special 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 +this 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 "gnu_xml_libxmlj_dom_GnomeDocument.h" +#include "gnu_xml_libxmlj_dom_GnomeElement.h" +#include "gnu_xml_libxmlj_dom_GnomeXPathExpression.h" +#include "gnu_xml_libxmlj_dom_GnomeXPathNodeList.h" +#include "gnu_xml_libxmlj_dom_GnomeXPathNSResolver.h" +#include "gnu_xml_libxmlj_dom_GnomeXPathResult.h" +#include "xmlj_node.h" +#include "xmlj_util.h" +#include <libxml/xpath.h> + +/* Local function prototypes */ + +xmlXPathContextPtr +xmljCreateXPathContextPtr (xmlNodePtr node); + +jobject +xmljGetXPathResult (JNIEnv *env, xmlXPathObjectPtr obj); + +jobject +xmljGetXPathNodeList (JNIEnv *env, xmlXPathObjectPtr obj); + +xmlXPathObjectPtr +xmljGetXPathObjectID (JNIEnv *env, jobject obj); + +/** + * Creates an XPath context for the given node. + */ +xmlXPathContextPtr +xmljCreateXPathContextPtr (xmlNodePtr node) +{ + xmlXPathContextPtr ctx; + + ctx = xmlXPathNewContext (node->doc); + ctx->node = node; + return ctx; +} + +/** + * Converts an xmlXPathObjectPtr to a Java XPathResult. + */ +jobject +xmljGetXPathResult (JNIEnv *env, xmlXPathObjectPtr obj) +{ + jclass cls; + jmethodID method; + jobject ret; + jobject val; + + if (obj == NULL) + { + return NULL; + } + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeXPathResult"); + if (cls == NULL) + { + return NULL; + } + method = (*env)->GetMethodID (env, cls, "<init>", "(Ljava/lang/Object;)V"); + if (method == NULL) + { + return NULL; + } + val = xmljAsField (env, obj); + ret = (*env)->NewObject (env, cls, method, val); + + return ret; +} + +/** + * Converts an xmlXPathObjectPtr to a Java XPathNodeList. + */ +jobject +xmljGetXPathNodeList (JNIEnv *env, xmlXPathObjectPtr obj) +{ + jclass cls; + jmethodID method; + jobject ret; + jobject val; + + if (obj == NULL) + { + return NULL; + } + cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeXPathNodeList"); + if (cls == NULL) + { + return NULL; + } + method = (*env)->GetMethodID (env, cls, "<init>", "(Ljava/lang/Object;)V"); + if (method == NULL) + { + return NULL; + } + val = xmljAsField (env, obj); + ret = (*env)->NewObject (env, cls, method, val); + + return ret; +} + +xmlXPathObjectPtr +xmljGetXPathObjectID (JNIEnv *env, jobject obj) +{ + jclass cls; + jfieldID field; + jobject val; + xmlXPathObjectPtr ret; + + cls = (*env)->GetObjectClass (env, obj); + if (cls == NULL) + { + return NULL; + } + field = (*env)->GetFieldID (env, cls, "obj", "Ljava/lang/Object;"); + if (field == NULL) + { + return NULL; + } + val = (*env)->GetObjectField (env, obj, field); + ret = (xmlXPathObjectPtr) xmljAsPointer (env, val); + + return ret; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_evaluate (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jstring expression, + jobject contextNode, + jobject resolver, + jshort type, + jobject result) +{ + const xmlChar *str; + xmlNodePtr node; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr eval = NULL; + + str = xmljGetStringChars (env, expression); + node = xmljGetNodeID (env, contextNode); + if (node == NULL) + { + return NULL; + } + ctx = xmljCreateXPathContextPtr (node); + if (ctx != NULL) + { + eval = xmlXPathEval (str, ctx); + xmlXPathFreeContext (ctx); + } + xmlFree ((xmlChar *) str); + return xmljGetXPathResult (env, eval); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_init (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jstring expression) +{ + const xmlChar *str; + xmlXPathCompExprPtr ptr; + + str = xmljGetStringChars (env, expression); + ptr = xmlXPathCompile (str); + xmlFree ((xmlChar *) str); + return xmljAsField (env, ptr); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_free (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jobject ptr) +{ + xmlXPathCompExprPtr expr; + + expr = (xmlXPathCompExprPtr) xmljAsPointer (env, ptr); + xmlXPathFreeCompExpr (expr); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_doEvaluate (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jobject ptr, + jobject contextNode, + jshort type, + jobject result) +{ + xmlXPathCompExprPtr expr; + xmlNodePtr node; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr eval = NULL; + + expr = (xmlXPathCompExprPtr) xmljAsPointer (env, ptr); + node = xmljGetNodeID (env, contextNode); + if (node == NULL) + { + return NULL; + } + ctx = xmljCreateXPathContextPtr (node); + if (ctx != NULL) + { + eval = xmlXPathCompiledEval (expr, ctx); + xmlXPathFreeContext (ctx); + } + return xmljGetXPathResult (env, eval); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_free (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jobject obj) +{ + xmlXPathFreeObject ((xmlXPathObjectPtr) xmljAsPointer (env, obj)); +} + +JNIEXPORT jshort JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getResultType (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + switch (obj->type) + { + case XPATH_UNDEFINED: + return 0; /* ANY_TYPE */ + case XPATH_NUMBER: + return 1; /* NUMBER_TYPE */ + case XPATH_STRING: + return 2; /* STRING_TYPE */ + case XPATH_BOOLEAN: + return 3; /* BOOLEAN_TYPE */ + case XPATH_NODESET: + return 6; /* UNORDERED_NODE_SNAPSHOT_TYPE */ + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + case XPATH_USERS: + case XPATH_XSLT_TREE: + /* TODO */ + default: + return -1; /* TODO */ + } +} + +JNIEXPORT jdouble JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getNumberValue (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return 0.0; + } + return obj->floatval; +} + +JNIEXPORT jstring JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getStringValue (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return NULL; + } + return xmljNewString (env, obj->stringval); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getBooleanValue (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + return obj->boolval; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSingleNodeValue (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return NULL; + } + if (obj->nodesetval == NULL) + { + return NULL; + } + if (obj->nodesetval->nodeNr > 0) + { + return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[0]); + } + else + { + return NULL; + } +} + +JNIEXPORT jboolean JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getInvalidIteratorState (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + return 0; /* TODO */ +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSnapshotLength (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return -1; + } + if (obj->nodesetval == NULL) + { + return -1; + } + return obj->nodesetval->nodeNr; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_iterateNext (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + return NULL; /* TODO */ +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathResult_snapshotItem (JNIEnv *env, + jobject self, + jint index) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return NULL; + } + if (obj->nodesetval == NULL) + { + return NULL; + } + if (obj->nodesetval->nodeNr > 0) + { + return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[index]); + } + else + { + return NULL; + } +} + +/* -- GnomeXPathNodeList -- */ + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagName (JNIEnv *env, + jobject self, + jstring name) +{ + return Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagName (env, + self, + name); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagName (JNIEnv *env, + jobject self, + jstring name) +{ + const xmlChar *s_name; + const xmlChar *format; + xmlChar expr[256]; + xmlNodePtr node; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr eval = NULL; + + node = xmljGetNodeID (env, self); + if (node == NULL) + { + return NULL; + } + s_name = xmljGetStringChars (env, name); + if (xmlStrEqual (s_name, BAD_CAST "*")) + { + format = xmlCharStrdup ("descendant-or-self::*[node-type()=1]"); + if (xmlStrPrintf (expr, 256, format) == -1) + { + return NULL; + } + } + else + { + format = xmlCharStrdup ("descendant-or-self::*[name()='%s']"); + if (xmlStrPrintf (expr, 256, format, s_name) == -1) + { + return NULL; + } + } + xmlFree ((xmlChar *) s_name); + ctx = xmljCreateXPathContextPtr (node); + if (ctx != NULL) + { + eval = xmlXPathEval (expr, ctx); + xmlXPathFreeContext (ctx); + } + return xmljGetXPathNodeList (env, eval); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagNameNS (JNIEnv *env, + jobject self, + jstring uri, + jstring localName) +{ + return Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagNameNS (env, + self, + uri, + localName); +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagNameNS (JNIEnv *env, + jobject self, + jstring uri, + jstring localName) +{ + const xmlChar *s_uri; + const xmlChar *s_localName; + const xmlChar *format; + xmlChar expr[256]; + xmlNodePtr node; + xmlXPathContextPtr ctx; + xmlXPathObjectPtr eval = NULL; + + node = xmljGetNodeID (env, self); + if (node == NULL) + { + return NULL; + } + s_uri = xmljGetStringChars (env, uri); + s_localName = xmljGetStringChars (env, localName); + if (uri == NULL) + { + /* namespace URI is empty */ + if (xmlStrEqual (s_localName, BAD_CAST "*")) + { + format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='' and node-type()=1]"); + if (xmlStrPrintf (expr, 256, format) == -1) + { + return NULL; + } + } + else + { + format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='' and local-name()='%s']"); + if (xmlStrPrintf (expr, 256, format, s_localName) == -1) + { + return NULL; + } + } + } + else if (xmlStrEqual (s_uri, BAD_CAST "*")) + { + /* matches all namespaces */ + if (xmlStrEqual (s_localName, BAD_CAST "*")) + { + format = xmlCharStrdup ("descendant-or-self::*[node-type()=1]"); + if (xmlStrPrintf (expr, 256, format) == -1) + { + return NULL; + } + } + else + { + format = xmlCharStrdup ("descendant-or-self::*[local-name()='%s']"); + if (xmlStrPrintf (expr, 256, format, s_localName) == -1) + { + return NULL; + } + } + } + else + { + if (xmlStrEqual (s_localName, BAD_CAST "*")) + { + format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='%s' and node-type()=1]"); + if (xmlStrPrintf (expr, 256, format, s_uri) == -1) + { + return NULL; + } + } + else + { + format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='%s' and local-name()='%s']"); + if (xmlStrPrintf (expr, 256, format, s_uri, s_localName) == -1) + { + return NULL; + } + } + } + xmlFree ((xmlChar *) s_uri); + xmlFree ((xmlChar *) s_localName); + ctx = xmljCreateXPathContextPtr (node); + if (ctx != NULL) + { + eval = xmlXPathEval (expr, ctx); + xmlXPathFreeContext (ctx); + } + return xmljGetXPathNodeList (env, eval); +} + +JNIEXPORT void JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_free (JNIEnv *env, + jobject self + __attribute__((__unused__)), + jobject obj) +{ + xmlXPathFreeObject ((xmlXPathObjectPtr) xmljAsPointer (env, obj)); +} + +JNIEXPORT jint JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_getLength (JNIEnv *env, + jobject self) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return 0; + } + if (obj->nodesetval == NULL) + { + return 0; + } + return obj->nodesetval->nodeNr; +} + +JNIEXPORT jobject JNICALL +Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_item (JNIEnv *env, + jobject self, + jint index) +{ + xmlXPathObjectPtr obj; + + obj = xmljGetXPathObjectID (env, self); + if (obj == NULL) + { + return NULL; + } + if (obj->nodesetval == NULL) + { + return NULL; + } + if (obj->nodesetval->nodeNr > 0) + { + return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[index]); + } + else + { + return NULL; + } +} + |