39 |
#include "jcl.h" |
#include "jcl.h" |
40 |
#include "gtkpeer.h" |
#include "gtkpeer.h" |
41 |
#include "gnu_java_awt_peer_gtk_GtkClipboard.h" |
#include "gnu_java_awt_peer_gtk_GtkClipboard.h" |
|
#include "gnu_java_awt_peer_gtk_GtkSelection.h" |
|
42 |
|
|
43 |
#define OBJECT_TARGET 1 |
#define OBJECT_TARGET 1 |
44 |
#define TEXT_TARGET 2 |
#define TEXT_TARGET 2 |
45 |
#define IMAGE_TARGET 3 |
#define IMAGE_TARGET 3 |
46 |
#define URI_TARGET 4 |
#define URI_TARGET 4 |
47 |
|
|
48 |
static GtkClipboard *clipboard; |
/* The clipboard and standard (string targets) shared with GtkSelection. */ |
49 |
|
GtkClipboard *cp_gtk_clipboard; |
50 |
|
|
51 |
|
jstring cp_gtk_stringTarget; |
52 |
|
jstring cp_gtk_imageTarget; |
53 |
|
jstring cp_gtk_filesTarget; |
54 |
|
|
55 |
/* Simple id to keep track of the selection we are currently managing. */ |
/* Simple id to keep track of the selection we are currently managing. */ |
56 |
static int current_selection = 0; |
static int current_selection = 0; |
67 |
static jmethodID provideImageID; |
static jmethodID provideImageID; |
68 |
static jmethodID provideURIsID; |
static jmethodID provideURIsID; |
69 |
|
|
|
static jstring stringTarget; |
|
|
static jstring imageTarget; |
|
|
static jstring filesTarget; |
|
|
|
|
70 |
static void |
static void |
71 |
cp_gtk_clipboard_owner_change_cb (GtkClipboard *clipboard __attribute__((unused)), |
clipboard_owner_change_cb (GtkClipboard *clipboard __attribute__((unused)), |
72 |
GdkEvent *event __attribute__((unused)), |
GdkEvent *event __attribute__((unused)), |
73 |
gpointer user_data __attribute__((unused))) |
gpointer user_data __attribute__((unused))) |
74 |
{ |
{ |
75 |
/* These are only interesting when we are not the owner. Otherwise |
/* These are only interesting when we are not the owner. Otherwise |
76 |
we will have the set and clear functions doing the updating. */ |
we will have the set and clear functions doing the updating. */ |
97 |
if (setSystemContentsID == NULL) |
if (setSystemContentsID == NULL) |
98 |
return JNI_FALSE; |
return JNI_FALSE; |
99 |
|
|
100 |
stringTarget = (*env)->NewGlobalRef(env, string); |
cp_gtk_stringTarget = (*env)->NewGlobalRef(env, string); |
101 |
imageTarget = (*env)->NewGlobalRef(env, image); |
cp_gtk_imageTarget = (*env)->NewGlobalRef(env, image); |
102 |
filesTarget = (*env)->NewGlobalRef(env, files); |
cp_gtk_filesTarget = (*env)->NewGlobalRef(env, files); |
103 |
|
|
104 |
gdk_threads_enter (); |
gdk_threads_enter (); |
105 |
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); |
cp_gtk_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); |
106 |
|
|
107 |
display = gtk_clipboard_get_display (clipboard); |
display = gtk_clipboard_get_display (cp_gtk_clipboard); |
108 |
if (gdk_display_supports_selection_notification (display)) |
if (gdk_display_supports_selection_notification (display)) |
109 |
{ |
{ |
110 |
g_signal_connect (clipboard, "owner-change", |
g_signal_connect (cp_gtk_clipboard, "owner-change", |
111 |
G_CALLBACK (cp_gtk_clipboard_owner_change_cb), NULL); |
G_CALLBACK (clipboard_owner_change_cb), NULL); |
112 |
gdk_display_request_selection_notification (display, |
gdk_display_request_selection_notification (display, |
113 |
GDK_SELECTION_CLIPBOARD); |
GDK_SELECTION_CLIPBOARD); |
114 |
can_cache = JNI_TRUE; |
can_cache = JNI_TRUE; |
121 |
} |
} |
122 |
|
|
123 |
static void |
static void |
124 |
cp_gtk_clipboard_get_func (GtkClipboard *clipboard __attribute__((unused)), |
clipboard_get_func (GtkClipboard *clipboard __attribute__((unused)), |
125 |
GtkSelectionData *selection, |
GtkSelectionData *selection, |
126 |
guint info, |
guint info, |
127 |
gpointer user_data __attribute__((unused))) |
gpointer user_data __attribute__((unused))) |
128 |
{ |
{ |
129 |
JNIEnv *env = cp_gtk_gdk_env (); |
JNIEnv *env = cp_gtk_gdk_env (); |
130 |
|
|
249 |
} |
} |
250 |
|
|
251 |
static void |
static void |
252 |
cp_gtk_clipboard_clear_func (GtkClipboard *clipboard __attribute__((unused)), |
clipboard_clear_func (GtkClipboard *clipboard __attribute__((unused)), |
253 |
gpointer user_data) |
gpointer user_data) |
254 |
{ |
{ |
255 |
if (owner && (int) user_data == current_selection) |
if (owner && (int) user_data == current_selection) |
256 |
{ |
{ |
327 |
/* Set the targets plus callback functions and ask for the clipboard |
/* Set the targets plus callback functions and ask for the clipboard |
328 |
to be stored when the application exists. */ |
to be stored when the application exists. */ |
329 |
current_selection++; |
current_selection++; |
330 |
if (gtk_clipboard_set_with_data (clipboard, targets, n, |
if (gtk_clipboard_set_with_data (cp_gtk_clipboard, targets, n, |
331 |
cp_gtk_clipboard_get_func, |
clipboard_get_func, |
332 |
cp_gtk_clipboard_clear_func, |
clipboard_clear_func, |
333 |
(gpointer) current_selection)) |
(gpointer) current_selection)) |
334 |
{ |
{ |
335 |
owner = 1; |
owner = 1; |
365 |
if (provideURIsID == NULL) |
if (provideURIsID == NULL) |
366 |
return; |
return; |
367 |
} |
} |
368 |
gtk_clipboard_set_can_store (clipboard, NULL, 0); |
gtk_clipboard_set_can_store (cp_gtk_clipboard, NULL, 0); |
369 |
} |
} |
370 |
else |
else |
371 |
{ |
{ |
380 |
} |
} |
381 |
else if (owner) |
else if (owner) |
382 |
{ |
{ |
383 |
gtk_clipboard_clear (clipboard); |
gtk_clipboard_clear (cp_gtk_clipboard); |
384 |
owner = 0; |
owner = 0; |
385 |
} |
} |
386 |
|
|
387 |
gtk_target_list_unref (target_list); |
gtk_target_list_unref (target_list); |
388 |
gdk_threads_leave (); |
gdk_threads_leave (); |
389 |
} |
} |
|
|
|
|
|
|
|
/* GtkSelection native methods. Put here for convenience since they |
|
|
need access to the current clipboard. */ |
|
|
|
|
|
static jmethodID mimeTypesAvailableID; |
|
|
|
|
|
/* Note this is actually just a GtkClipboardReceivedFunc, not a real |
|
|
GtkClipboardTargetsReceivedFunc, see requestMimeTypes. */ |
|
|
static void |
|
|
cp_gtk_clipboard_targets_received (GtkClipboard *clipboard |
|
|
__attribute__((unused)), |
|
|
GtkSelectionData *target_data, |
|
|
gpointer selection) |
|
|
{ |
|
|
GdkAtom *targets = NULL; |
|
|
gint targets_len = 0; |
|
|
gchar **target_strings = NULL; |
|
|
jobjectArray strings = NULL; |
|
|
int strings_len = 0; |
|
|
gboolean include_text = FALSE; |
|
|
gboolean include_image = FALSE; |
|
|
gboolean include_uris = FALSE; |
|
|
jobject selection_obj = (jobject) selection; |
|
|
JNIEnv *env = cp_gtk_gdk_env (); |
|
|
|
|
|
if (target_data != NULL && target_data->length > 0) |
|
|
{ |
|
|
include_text = gtk_selection_data_targets_include_text (target_data); |
|
|
include_image = gtk_selection_data_targets_include_image (target_data, |
|
|
TRUE); |
|
|
if (gtk_selection_data_get_targets (target_data, &targets, &targets_len)) |
|
|
{ |
|
|
int i; |
|
|
GdkAtom uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE); |
|
|
target_strings = g_new (gchar*, targets_len); |
|
|
if (target_strings != NULL) |
|
|
for (i = 0; i < targets_len; i++) |
|
|
{ |
|
|
gchar *name = gdk_atom_name (targets[i]); |
|
|
if (strchr (name, '/') != NULL) |
|
|
{ |
|
|
target_strings[i] = name; |
|
|
strings_len++; |
|
|
if (! include_uris && targets[i] == uri_list_atom) |
|
|
include_uris = TRUE; |
|
|
} |
|
|
else |
|
|
target_strings[i] = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
if (target_strings != NULL) |
|
|
{ |
|
|
int i = 0, j = 0; |
|
|
jclass stringClass; |
|
|
|
|
|
if (include_text) |
|
|
strings_len++; |
|
|
if (include_image) |
|
|
strings_len++; |
|
|
if (include_uris) |
|
|
strings_len++; |
|
|
|
|
|
stringClass = (*env)->FindClass (env, "java/lang/String"); |
|
|
strings = (*env)->NewObjectArray (env, strings_len, stringClass, |
|
|
NULL); |
|
|
if (strings != NULL) |
|
|
{ |
|
|
if (include_text) |
|
|
(*env)->SetObjectArrayElement (env, strings, i++, |
|
|
stringTarget); |
|
|
if (include_image) |
|
|
(*env)->SetObjectArrayElement (env, strings, i++, |
|
|
imageTarget); |
|
|
if (include_uris) |
|
|
(*env)->SetObjectArrayElement (env, strings, i++, |
|
|
filesTarget); |
|
|
|
|
|
while(i < strings_len) |
|
|
{ |
|
|
if (target_strings[j] == NULL) |
|
|
j++; |
|
|
else |
|
|
{ |
|
|
jstring string; |
|
|
string = (*env)->NewStringUTF (env, |
|
|
target_strings[j++]); |
|
|
if (string == NULL) |
|
|
break; |
|
|
(*env)->SetObjectArrayElement (env, strings, i++, |
|
|
string); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
for (i = 0; i < targets_len; i++) |
|
|
g_free (target_strings[i]); |
|
|
g_free (target_strings); |
|
|
} |
|
|
} |
|
|
|
|
|
(*env)->CallVoidMethod (env, selection_obj, |
|
|
mimeTypesAvailableID, |
|
|
strings); |
|
|
(*env)->DeleteGlobalRef (env, selection_obj); |
|
|
} |
|
|
|
|
|
JNIEXPORT void JNICALL |
|
|
Java_gnu_java_awt_peer_gtk_GtkSelection_requestMimeTypes |
|
|
(JNIEnv *env, jobject selection) |
|
|
{ |
|
|
jobject selection_obj; |
|
|
selection_obj = (*env)->NewGlobalRef(env, selection); |
|
|
if (selection_obj == NULL) |
|
|
return; |
|
|
|
|
|
if (mimeTypesAvailableID == NULL) |
|
|
{ |
|
|
jclass gtk_selection_class; |
|
|
gtk_selection_class = (*env)->GetObjectClass (env, selection_obj); |
|
|
mimeTypesAvailableID = (*env)->GetMethodID (env, gtk_selection_class, |
|
|
"mimeTypesAvailable", |
|
|
"([Ljava/lang/String;)V"); |
|
|
if (mimeTypesAvailableID == NULL) |
|
|
return; |
|
|
} |
|
|
|
|
|
/* We would have liked to call gtk_clipboard_request_targets () |
|
|
since that is more general. But the result of that, an array of |
|
|
GdkAtoms, cannot be used with the |
|
|
gtk_selection_data_targets_include_<x> functions (despite what |
|
|
the name suggests). */ |
|
|
gdk_threads_enter (); |
|
|
gtk_clipboard_request_contents (clipboard, |
|
|
gdk_atom_intern ("TARGETS", FALSE), |
|
|
cp_gtk_clipboard_targets_received, |
|
|
(gpointer) selection_obj); |
|
|
gdk_threads_leave (); |
|
|
} |
|
|
|
|
|
|
|
|
static jmethodID textAvailableID; |
|
|
|
|
|
static void |
|
|
cp_gtk_clipboard_text_received (GtkClipboard *clipboard |
|
|
__attribute__((unused)), |
|
|
const gchar *text, |
|
|
gpointer selection) |
|
|
{ |
|
|
jstring string; |
|
|
jobject selection_obj = (jobject) selection; |
|
|
|
|
|
JNIEnv *env = cp_gtk_gdk_env (); |
|
|
if (text != NULL) |
|
|
string = (*env)->NewStringUTF (env, text); |
|
|
else |
|
|
string = NULL; |
|
|
|
|
|
(*env)->CallVoidMethod (env, selection_obj, |
|
|
textAvailableID, |
|
|
string); |
|
|
(*env)->DeleteGlobalRef (env, selection_obj); |
|
|
} |
|
|
|
|
|
JNIEXPORT void JNICALL |
|
|
Java_gnu_java_awt_peer_gtk_GtkSelection_requestText |
|
|
(JNIEnv *env, jobject selection) |
|
|
{ |
|
|
jobject selection_obj; |
|
|
selection_obj = (*env)->NewGlobalRef(env, selection); |
|
|
if (selection_obj == NULL) |
|
|
return; |
|
|
|
|
|
if (textAvailableID == NULL) |
|
|
{ |
|
|
jclass gtk_selection_class; |
|
|
gtk_selection_class = (*env)->GetObjectClass (env, selection_obj); |
|
|
textAvailableID = (*env)->GetMethodID (env, gtk_selection_class, |
|
|
"textAvailable", |
|
|
"(Ljava/lang/String;)V"); |
|
|
if (textAvailableID == NULL) |
|
|
return; |
|
|
} |
|
|
|
|
|
gdk_threads_enter (); |
|
|
gtk_clipboard_request_text (clipboard, |
|
|
cp_gtk_clipboard_text_received, |
|
|
(gpointer) selection_obj); |
|
|
gdk_threads_leave (); |
|
|
} |
|
|
|
|
|
static jmethodID imageAvailableID; |
|
|
|
|
|
static void |
|
|
cp_gtk_clipboard_image_received (GtkClipboard *clipboard |
|
|
__attribute__((unused)), |
|
|
GdkPixbuf *pixbuf, |
|
|
gpointer selection) |
|
|
{ |
|
|
jobject pointer = NULL; |
|
|
jobject selection_obj = (jobject) selection; |
|
|
JNIEnv *env = cp_gtk_gdk_env (); |
|
|
|
|
|
if (pixbuf != NULL) |
|
|
{ |
|
|
g_object_ref (pixbuf); |
|
|
pointer = JCL_NewRawDataObject (env, (void *) pixbuf); |
|
|
} |
|
|
|
|
|
(*env)->CallVoidMethod (env, selection_obj, |
|
|
imageAvailableID, |
|
|
pointer); |
|
|
(*env)->DeleteGlobalRef (env, selection_obj); |
|
|
} |
|
|
|
|
|
JNIEXPORT void JNICALL |
|
|
Java_gnu_java_awt_peer_gtk_GtkSelection_requestImage (JNIEnv *env, jobject obj) |
|
|
{ |
|
|
jobject selection_obj; |
|
|
selection_obj = (*env)->NewGlobalRef(env, obj); |
|
|
if (selection_obj == NULL) |
|
|
return; |
|
|
|
|
|
if (imageAvailableID == NULL) |
|
|
{ |
|
|
jclass gtk_selection_class; |
|
|
gtk_selection_class = (*env)->GetObjectClass (env, selection_obj); |
|
|
imageAvailableID = (*env)->GetMethodID (env, gtk_selection_class, |
|
|
"imageAvailable", |
|
|
"(Lgnu/classpath/Pointer;)V"); |
|
|
if (imageAvailableID == NULL) |
|
|
return; |
|
|
} |
|
|
|
|
|
gdk_threads_enter (); |
|
|
gtk_clipboard_request_image (clipboard, |
|
|
cp_gtk_clipboard_image_received, |
|
|
(gpointer) selection_obj); |
|
|
gdk_threads_leave (); |
|
|
} |
|
|
|
|
|
static jmethodID urisAvailableID; |
|
|
|
|
|
static void |
|
|
cp_gtk_clipboard_uris_received (GtkClipboard *clipboard |
|
|
__attribute__((unused)), |
|
|
GtkSelectionData *uri_data, |
|
|
gpointer selection) |
|
|
{ |
|
|
gchar **uris = NULL; |
|
|
jobjectArray strings = NULL; |
|
|
jobject selection_obj = (jobject) selection; |
|
|
JNIEnv *env = cp_gtk_gdk_env (); |
|
|
|
|
|
if (uri_data != NULL) |
|
|
uris = gtk_selection_data_get_uris (uri_data); |
|
|
|
|
|
if (uris != NULL) |
|
|
{ |
|
|
int len, i; |
|
|
gchar **count = uris; |
|
|
jclass stringClass = (*env)->FindClass (env, "java/lang/String"); |
|
|
|
|
|
len = 0; |
|
|
while (count[len]) |
|
|
len++; |
|
|
|
|
|
strings = (*env)->NewObjectArray (env, len, stringClass, NULL); |
|
|
if (strings != NULL) |
|
|
{ |
|
|
for (i = 0; i < len; i++) |
|
|
{ |
|
|
jstring string = (*env)->NewStringUTF (env, uris[i]); |
|
|
if (string == NULL) |
|
|
break; |
|
|
(*env)->SetObjectArrayElement (env, strings, i, string); |
|
|
} |
|
|
} |
|
|
g_strfreev (uris); |
|
|
} |
|
|
|
|
|
(*env)->CallVoidMethod (env, selection_obj, |
|
|
urisAvailableID, |
|
|
strings); |
|
|
(*env)->DeleteGlobalRef (env, selection_obj); |
|
|
} |
|
|
|
|
|
JNIEXPORT void JNICALL |
|
|
Java_gnu_java_awt_peer_gtk_GtkSelection_requestURIs (JNIEnv *env, jobject obj) |
|
|
{ |
|
|
GdkAtom uri_atom; |
|
|
jobject selection_obj; |
|
|
selection_obj = (*env)->NewGlobalRef(env, obj); |
|
|
if (selection_obj == NULL) |
|
|
return; |
|
|
|
|
|
if (urisAvailableID == NULL) |
|
|
{ |
|
|
jclass gtk_selection_class; |
|
|
gtk_selection_class = (*env)->GetObjectClass (env, selection_obj); |
|
|
urisAvailableID = (*env)->GetMethodID (env, gtk_selection_class, |
|
|
"urisAvailable", |
|
|
"([Ljava/lang/String;)V"); |
|
|
if (urisAvailableID == NULL) |
|
|
return; |
|
|
} |
|
|
|
|
|
/* There is no real request_uris so we have to make one ourselves. */ |
|
|
gdk_threads_enter (); |
|
|
uri_atom = gdk_atom_intern ("text/uri-list", FALSE); |
|
|
gtk_clipboard_request_contents (clipboard, |
|
|
uri_atom, |
|
|
cp_gtk_clipboard_uris_received, |
|
|
(gpointer) selection_obj); |
|
|
gdk_threads_leave (); |
|
|
} |
|
|
|
|
|
static jmethodID bytesAvailableID; |
|
|
|
|
|
static void |
|
|
cp_gtk_clipboard_bytes_received (GtkClipboard *clipboard |
|
|
__attribute__((unused)), |
|
|
GtkSelectionData *selection_data, |
|
|
gpointer selection) |
|
|
{ |
|
|
jbyteArray bytes = NULL; |
|
|
jobject selection_obj = (jobject) selection; |
|
|
JNIEnv *env = cp_gtk_gdk_env (); |
|
|
|
|
|
if (selection_data != NULL && selection_data->length > 0) |
|
|
{ |
|
|
bytes = (*env)->NewByteArray (env, selection_data->length); |
|
|
if (bytes != NULL) |
|
|
(*env)->SetByteArrayRegion(env, bytes, 0, selection_data->length, |
|
|
(jbyte *) selection_data->data); |
|
|
} |
|
|
|
|
|
(*env)->CallVoidMethod (env, selection_obj, |
|
|
bytesAvailableID, |
|
|
bytes); |
|
|
(*env)->DeleteGlobalRef (env, selection_obj); |
|
|
} |
|
|
|
|
|
JNIEXPORT void JNICALL |
|
|
Java_gnu_java_awt_peer_gtk_GtkSelection_requestBytes (JNIEnv *env, |
|
|
jobject obj, |
|
|
jstring target_string) |
|
|
{ |
|
|
int len; |
|
|
const gchar *target_text; |
|
|
GdkAtom target_atom; |
|
|
jobject selection_obj; |
|
|
selection_obj = (*env)->NewGlobalRef(env, obj); |
|
|
if (selection_obj == NULL) |
|
|
return; |
|
|
|
|
|
if (bytesAvailableID == NULL) |
|
|
{ |
|
|
jclass gtk_selection_class; |
|
|
gtk_selection_class = (*env)->GetObjectClass (env, selection_obj); |
|
|
bytesAvailableID = (*env)->GetMethodID (env, gtk_selection_class, |
|
|
"bytesAvailable", |
|
|
"([B)V"); |
|
|
if (bytesAvailableID == NULL) |
|
|
return; |
|
|
} |
|
|
|
|
|
len = (*env)->GetStringUTFLength (env, target_string); |
|
|
if (len == -1) |
|
|
return; |
|
|
target_text = (*env)->GetStringUTFChars (env, target_string, NULL); |
|
|
if (target_text == NULL) |
|
|
return; |
|
|
|
|
|
gdk_threads_enter (); |
|
|
target_atom = gdk_atom_intern (target_text, FALSE); |
|
|
gtk_clipboard_request_contents (clipboard, |
|
|
target_atom, |
|
|
cp_gtk_clipboard_bytes_received, |
|
|
(gpointer) selection_obj); |
|
|
gdk_threads_leave (); |
|
|
|
|
|
(*env)->ReleaseStringUTFChars (env, target_string, target_text); |
|
|
} |
|