| /* gtkclipboard.c |
| Copyright (C) 1998, 1999, 2005, 2006 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 "jcl.h" |
| #include "gtkpeer.h" |
| #include "gnu_java_awt_peer_gtk_GtkClipboard.h" |
| |
| #define OBJECT_TARGET 1 |
| #define TEXT_TARGET 2 |
| #define IMAGE_TARGET 3 |
| #define URI_TARGET 4 |
| |
| /* The clipboard and selection plus corresponding GtkClipboard objects. */ |
| GtkClipboard *cp_gtk_clipboard; |
| GtkClipboard *cp_gtk_selection; |
| |
| jobject cp_gtk_clipboard_instance; |
| jobject cp_gtk_selection_instance; |
| |
| /* Standard (string targets) shared with GtkSelection. */ |
| jstring cp_gtk_stringTarget; |
| jstring cp_gtk_imageTarget; |
| jstring cp_gtk_filesTarget; |
| |
| static jclass gtk_clipboard_class; |
| |
| static jmethodID setSystemContentsID; |
| static jmethodID provideContentID; |
| static jmethodID provideTextID; |
| static jmethodID provideImageID; |
| static jmethodID provideURIsID; |
| |
| /* Called when clipboard owner changes. Used to update available targets. */ |
| #if GTK_MINOR_VERSION > 4 |
| static void |
| clipboard_owner_change_cb (GtkClipboard *clipboard, |
| GdkEvent *event __attribute__((unused)), |
| gpointer user_data __attribute__((unused))) |
| { |
| JNIEnv *env = cp_gtk_gdk_env (); |
| if (clipboard == cp_gtk_clipboard) |
| (*env)->CallVoidMethod (env, cp_gtk_clipboard_instance, |
| setSystemContentsID, JNI_FALSE); |
| else |
| (*env)->CallVoidMethod (env, cp_gtk_selection_instance, |
| setSystemContentsID, JNI_FALSE); |
| |
| } |
| #endif |
| |
| JNIEXPORT jboolean JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env, |
| jclass clz, |
| jobject gtkclipboard, |
| jobject gtkselection, |
| jstring string, |
| jstring image, |
| jstring files) |
| { |
| GdkDisplay* display; |
| jboolean can_cache; |
| |
| gtk_clipboard_class = clz; |
| setSystemContentsID = (*env)->GetMethodID (env, gtk_clipboard_class, |
| "setSystemContents", |
| "(Z)V"); |
| if (setSystemContentsID == NULL) |
| return JNI_FALSE; |
| |
| provideContentID = (*env)->GetMethodID (env, gtk_clipboard_class, |
| "provideContent", |
| "(Ljava/lang/String;)[B"); |
| if (provideContentID == NULL) |
| return JNI_FALSE; |
| |
| provideTextID = (*env)->GetMethodID (env, gtk_clipboard_class, |
| "provideText", |
| "()Ljava/lang/String;"); |
| if (provideTextID == NULL) |
| return JNI_FALSE; |
| |
| provideImageID = (*env)->GetMethodID (env, gtk_clipboard_class, |
| "provideImage", |
| "()Lgnu/java/awt/peer/gtk/GtkImage;"); |
| if (provideImageID == NULL) |
| return JNI_FALSE; |
| |
| provideURIsID = (*env)->GetMethodID (env, gtk_clipboard_class, |
| "provideURIs", |
| "()[Ljava/lang/String;"); |
| if (provideURIsID == NULL) |
| return JNI_FALSE; |
| |
| cp_gtk_clipboard_instance = (*env)->NewGlobalRef(env, gtkclipboard); |
| cp_gtk_selection_instance = (*env)->NewGlobalRef(env, gtkselection); |
| |
| cp_gtk_stringTarget = (*env)->NewGlobalRef(env, string); |
| cp_gtk_imageTarget = (*env)->NewGlobalRef(env, image); |
| cp_gtk_filesTarget = (*env)->NewGlobalRef(env, files); |
| |
| gdk_threads_enter (); |
| cp_gtk_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); |
| cp_gtk_selection = gtk_clipboard_get (GDK_SELECTION_PRIMARY); |
| |
| display = gtk_clipboard_get_display (cp_gtk_clipboard); |
| /* Check for support for clipboard owner changes. */ |
| #if GTK_MINOR_VERSION > 4 |
| if (gdk_display_supports_selection_notification (display)) |
| { |
| g_signal_connect (cp_gtk_clipboard, "owner-change", |
| G_CALLBACK (clipboard_owner_change_cb), NULL); |
| g_signal_connect (cp_gtk_selection, "owner-change", |
| G_CALLBACK (clipboard_owner_change_cb), NULL); |
| gdk_display_request_selection_notification (display, |
| GDK_SELECTION_CLIPBOARD); |
| gdk_display_request_selection_notification (display, |
| GDK_SELECTION_PRIMARY); |
| can_cache = JNI_TRUE; |
| } |
| else |
| #endif |
| can_cache = JNI_FALSE; |
| |
| gdk_threads_leave (); |
| |
| return can_cache; |
| } |
| |
| static void |
| clipboard_get_func (GtkClipboard *clipboard, |
| GtkSelectionData *selection, |
| guint info, |
| gpointer user_data __attribute__((unused))) |
| { |
| jobject gtk_clipboard_instance; |
| JNIEnv *env = cp_gtk_gdk_env (); |
| |
| if (clipboard == cp_gtk_clipboard) |
| gtk_clipboard_instance = cp_gtk_clipboard_instance; |
| else |
| gtk_clipboard_instance = cp_gtk_selection_instance; |
| |
| if (info == OBJECT_TARGET) |
| { |
| const gchar *target_name; |
| jstring target_string; |
| jbyteArray bytes; |
| jint len; |
| jbyte *barray; |
| |
| target_name = gdk_atom_name (selection->target); |
| if (target_name == NULL) |
| return; |
| target_string = (*env)->NewStringUTF (env, target_name); |
| if (target_string == NULL) |
| return; |
| bytes = (*env)->CallObjectMethod(env, |
| gtk_clipboard_instance, |
| provideContentID, |
| target_string); |
| if (bytes == NULL) |
| return; |
| len = (*env)->GetArrayLength(env, bytes); |
| if (len <= 0) |
| return; |
| barray = (*env)->GetByteArrayElements(env, bytes, NULL); |
| if (barray == NULL) |
| return; |
| gtk_selection_data_set (selection, selection->target, 8, |
| (guchar *) barray, len); |
| |
| (*env)->ReleaseByteArrayElements(env, bytes, barray, 0); |
| |
| } |
| else if (info == TEXT_TARGET) |
| { |
| jstring string; |
| const gchar *text; |
| int len; |
| string = (*env)->CallObjectMethod(env, |
| gtk_clipboard_instance, |
| provideTextID); |
| if (string == NULL) |
| return; |
| len = (*env)->GetStringUTFLength (env, string); |
| if (len == -1) |
| return; |
| text = (*env)->GetStringUTFChars (env, string, NULL); |
| if (text == NULL) |
| return; |
| |
| gtk_selection_data_set_text (selection, text, len); |
| (*env)->ReleaseStringUTFChars (env, string, text); |
| } |
| /* Images and URIs/Files support only available with gtk+2.6 or higher. */ |
| #if GTK_MINOR_VERSION > 4 |
| else if (info == IMAGE_TARGET) |
| { |
| jobject gtkimage; |
| GdkPixbuf *pixbuf = NULL; |
| |
| gtkimage = (*env)->CallObjectMethod(env, |
| gtk_clipboard_instance, |
| provideImageID); |
| if (gtkimage == NULL) |
| return; |
| |
| pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage); |
| if (pixbuf != NULL) |
| gtk_selection_data_set_pixbuf (selection, pixbuf); |
| } |
| else if (info == URI_TARGET) |
| { |
| jobjectArray uris; |
| jint count; |
| int i; |
| gchar **list; |
| |
| uris = (*env)->CallObjectMethod(env, |
| gtk_clipboard_instance, |
| provideURIsID); |
| if (uris == NULL) |
| return; |
| count = (*env)->GetArrayLength (env, uris); |
| if (count <= 0) |
| return; |
| |
| list = (gchar **) JCL_malloc (env, (count + 1) * sizeof (gchar *)); |
| for (i = 0; i < count; i++) |
| { |
| const char *text; |
| jstring uri; |
| |
| /* Mark NULL in so case of some error we can find the end. */ |
| list[i] = NULL; |
| uri = (*env)->GetObjectArrayElement (env, uris, i); |
| if (uri == NULL) |
| break; |
| text = (*env)->GetStringUTFChars (env, uri, NULL); |
| if (text == NULL) |
| break; |
| list[i] = strdup (text); |
| (*env)->ReleaseStringUTFChars (env, uri, text); |
| } |
| |
| if (i == count) |
| { |
| list[count] = NULL; |
| gtk_selection_data_set_uris (selection, list); |
| } |
| |
| for (i = 0; list[i] != NULL; i++) |
| free (list[i]); |
| JCL_free (env, list); |
| } |
| #endif |
| } |
| |
| static void |
| clipboard_clear_func (GtkClipboard *clipboard, |
| gpointer user_data __attribute__((unused))) |
| { |
| JNIEnv *env = cp_gtk_gdk_env(); |
| if (clipboard == cp_gtk_clipboard) |
| (*env)->CallVoidMethod (env, cp_gtk_clipboard_instance, |
| setSystemContentsID, JNI_TRUE); |
| else |
| (*env)->CallVoidMethod (env, cp_gtk_selection_instance, |
| setSystemContentsID, JNI_TRUE); |
| |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_gnu_java_awt_peer_gtk_GtkClipboard_advertiseContent |
| (JNIEnv *env, |
| jobject instance, |
| jobjectArray mime_array, |
| #if GTK_MINOR_VERSION > 4 |
| jboolean add_text, jboolean add_images, jboolean add_uris) |
| #else |
| jboolean add_text __attribute__((unused)), |
| jboolean add_images __attribute__((unused)), |
| jboolean add_uris __attribute__((unused))) |
| #endif |
| { |
| GtkTargetList *target_list; |
| GList *list; |
| GtkTargetEntry *targets; |
| gint n, i; |
| |
| gdk_threads_enter (); |
| target_list = gtk_target_list_new (NULL, 0); |
| |
| if (mime_array != NULL) |
| { |
| n = (*env)->GetArrayLength (env, mime_array); |
| for (i = 0; i < n; i++) |
| { |
| const char *text; |
| jstring target; |
| GdkAtom atom; |
| |
| target = (*env)->GetObjectArrayElement (env, mime_array, i); |
| if (target == NULL) |
| break; |
| text = (*env)->GetStringUTFChars (env, target, NULL); |
| if (text == NULL) |
| break; |
| |
| atom = gdk_atom_intern (text, FALSE); |
| gtk_target_list_add (target_list, atom, 0, OBJECT_TARGET); |
| |
| (*env)->ReleaseStringUTFChars (env, target, text); |
| } |
| } |
| |
| /* Add extra targets that gtk+ can provide/translate for us. */ |
| #if GTK_MINOR_VERSION > 4 |
| if (add_text) |
| gtk_target_list_add_text_targets (target_list, TEXT_TARGET); |
| if (add_images) |
| gtk_target_list_add_image_targets (target_list, IMAGE_TARGET, TRUE); |
| if (add_uris) |
| gtk_target_list_add_uri_targets (target_list, URI_TARGET); |
| #else |
| if (add_text) |
| gtk_target_list_add (target_list, |
| gdk_atom_intern ("STRING", FALSE), |
| 0, TEXT_TARGET); |
| #endif |
| |
| |
| /* Turn list into a target table. */ |
| n = g_list_length (target_list->list); |
| if (n > 0) |
| { |
| targets = g_new (GtkTargetEntry, n); |
| for (list = target_list->list, i = 0; |
| list != NULL; |
| list = list->next, i++) |
| { |
| GtkTargetPair *pair = (GtkTargetPair *) list->data; |
| targets[i].target = gdk_atom_name (pair->target); |
| targets[i].flags = pair->flags; |
| targets[i].info = pair->info; |
| } |
| |
| /* Set the targets plus callback functions and ask for the clipboard |
| to be stored when the application exists if supported. */ |
| if ((*env)->IsSameObject(env, instance, cp_gtk_clipboard_instance)) |
| { |
| if (gtk_clipboard_set_with_data (cp_gtk_clipboard, targets, n, |
| clipboard_get_func, |
| clipboard_clear_func, |
| NULL)) |
| { |
| #if GTK_MINOR_VERSION > 4 |
| gtk_clipboard_set_can_store (cp_gtk_clipboard, NULL, 0); |
| #endif |
| } |
| } |
| else |
| { |
| if (gtk_clipboard_set_with_data (cp_gtk_selection, targets, n, |
| clipboard_get_func, |
| clipboard_clear_func, |
| NULL)) |
| { |
| #if GTK_MINOR_VERSION > 4 |
| gtk_clipboard_set_can_store (cp_gtk_selection, NULL, 0); |
| #endif |
| } |
| } |
| |
| for (i = 0; i < n; i++) |
| g_free (targets[i].target); |
| g_free (targets); |
| } |
| |
| gtk_target_list_unref (target_list); |
| gdk_threads_leave (); |
| } |