Merge from mainline
[official-gcc.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkClipboard.c
blob3b62dc3357f936b784eaf704a62dead921dfce50
1 /* gtkclipboard.c
2 Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 #include "jcl.h"
40 #include "gtkpeer.h"
41 #include "gnu_java_awt_peer_gtk_GtkClipboard.h"
43 #define OBJECT_TARGET 1
44 #define TEXT_TARGET 2
45 #define IMAGE_TARGET 3
46 #define URI_TARGET 4
48 /* The clipboard and standard (string targets) shared with GtkSelection. */
49 GtkClipboard *cp_gtk_clipboard;
51 jstring cp_gtk_stringTarget;
52 jstring cp_gtk_imageTarget;
53 jstring cp_gtk_filesTarget;
55 /* Simple id to keep track of the selection we are currently managing. */
56 static gint current_selection = 0;
58 /* Whether we "own" the clipboard. And may clear it. */
59 static int owner = 0;
61 static jclass gtk_clipboard_class;
62 static jmethodID setSystemContentsID;
64 static jobject gtk_clipboard_instance = NULL;
65 static jmethodID provideContentID;
66 static jmethodID provideTextID;
67 static jmethodID provideImageID;
68 static jmethodID provideURIsID;
70 /* Called when clipboard owner changes. Used to update available targets. */
71 #if GTK_MINOR_VERSION > 4
72 static void
73 clipboard_owner_change_cb (GtkClipboard *clipboard __attribute__((unused)),
74 GdkEvent *event __attribute__((unused)),
75 gpointer user_data __attribute__((unused)))
77 /* These are only interesting when we are not the owner. Otherwise
78 we will have the set and clear functions doing the updating. */
79 JNIEnv *env = cp_gtk_gdk_env ();
80 if (!owner)
81 (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
82 setSystemContentsID);
84 #endif
86 JNIEXPORT jboolean JNICALL
87 Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env,
88 jclass gtkclipboard,
89 jstring string,
90 jstring image,
91 jstring files)
93 GdkDisplay* display;
94 jboolean can_cache;
96 gtk_clipboard_class = gtkclipboard;
97 setSystemContentsID = (*env)->GetStaticMethodID (env, gtk_clipboard_class,
98 "setSystemContents",
99 "()V");
100 if (setSystemContentsID == NULL)
101 return JNI_FALSE;
103 cp_gtk_stringTarget = (*env)->NewGlobalRef(env, string);
104 cp_gtk_imageTarget = (*env)->NewGlobalRef(env, image);
105 cp_gtk_filesTarget = (*env)->NewGlobalRef(env, files);
107 gdk_threads_enter ();
108 cp_gtk_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
110 display = gtk_clipboard_get_display (cp_gtk_clipboard);
111 /* Check for support for clipboard owner changes. */
112 #if GTK_MINOR_VERSION > 4
113 if (gdk_display_supports_selection_notification (display))
115 g_signal_connect (cp_gtk_clipboard, "owner-change",
116 G_CALLBACK (clipboard_owner_change_cb), NULL);
117 gdk_display_request_selection_notification (display,
118 GDK_SELECTION_CLIPBOARD);
119 can_cache = JNI_TRUE;
121 else
122 #endif
123 can_cache = JNI_FALSE;
124 gdk_threads_leave ();
126 return can_cache;
129 static void
130 clipboard_get_func (GtkClipboard *clipboard __attribute__((unused)),
131 GtkSelectionData *selection,
132 guint info,
133 gpointer user_data __attribute__((unused)))
135 JNIEnv *env = cp_gtk_gdk_env ();
137 if (info == OBJECT_TARGET)
139 const gchar *target_name;
140 jstring target_string;
141 jbyteArray bytes;
142 jint len;
143 jbyte *barray;
145 target_name = gdk_atom_name (selection->target);
146 if (target_name == NULL)
147 return;
148 target_string = (*env)->NewStringUTF (env, target_name);
149 if (target_string == NULL)
150 return;
151 bytes = (*env)->CallObjectMethod(env,
152 gtk_clipboard_instance,
153 provideContentID,
154 target_string);
155 if (bytes == NULL)
156 return;
157 len = (*env)->GetArrayLength(env, bytes);
158 if (len <= 0)
159 return;
160 barray = (*env)->GetByteArrayElements(env, bytes, NULL);
161 if (barray == NULL)
162 return;
163 gtk_selection_data_set (selection, selection->target, 8,
164 (guchar *) barray, len);
166 (*env)->ReleaseByteArrayElements(env, bytes, barray, 0);
169 else if (info == TEXT_TARGET)
171 jstring string;
172 const gchar *text;
173 int len;
174 string = (*env)->CallObjectMethod(env,
175 gtk_clipboard_instance,
176 provideTextID);
177 if (string == NULL)
178 return;
179 len = (*env)->GetStringUTFLength (env, string);
180 if (len == -1)
181 return;
182 text = (*env)->GetStringUTFChars (env, string, NULL);
183 if (text == NULL)
184 return;
186 gtk_selection_data_set_text (selection, text, len);
187 (*env)->ReleaseStringUTFChars (env, string, text);
189 /* Images and URIs/Files support only available with gtk+2.6 or higher. */
190 #if GTK_MINOR_VERSION > 4
191 else if (info == IMAGE_TARGET)
193 jobject gtkimage;
194 GdkPixbuf *pixbuf = NULL;
196 gtkimage = (*env)->CallObjectMethod(env,
197 gtk_clipboard_instance,
198 provideImageID);
199 if (gtkimage == NULL)
200 return;
202 pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage);
203 if (pixbuf != NULL)
205 gtk_selection_data_set_pixbuf (selection, pixbuf);
207 /* if the GtkImage is offscreen, this is a temporary pixbuf
208 which should be thrown out. */
209 if(cp_gtk_image_is_offscreen (env, gtkimage) == JNI_TRUE)
210 gdk_pixbuf_unref (pixbuf);
213 else if (info == URI_TARGET)
215 jobjectArray uris;
216 jint count;
217 int i;
218 gchar **list;
220 uris = (*env)->CallObjectMethod(env,
221 gtk_clipboard_instance,
222 provideURIsID);
223 if (uris == NULL)
224 return;
225 count = (*env)->GetArrayLength (env, uris);
226 if (count <= 0)
227 return;
229 list = (gchar **) JCL_malloc (env, (count + 1) * sizeof (gchar *));
230 for (i = 0; i < count; i++)
232 const char *text;
233 jstring uri;
235 /* Mark NULL in so case of some error we can find the end. */
236 list[i] = NULL;
237 uri = (*env)->GetObjectArrayElement (env, uris, i);
238 if (uri == NULL)
239 break;
240 text = (*env)->GetStringUTFChars (env, uri, NULL);
241 if (text == NULL)
242 break;
243 list[i] = strdup (text);
244 (*env)->ReleaseStringUTFChars (env, uri, text);
247 if (i == count)
249 list[count] = NULL;
250 gtk_selection_data_set_uris (selection, list);
253 for (i = 0; list[i] != NULL; i++)
254 free (list[i]);
255 JCL_free (env, list);
257 #endif
260 static void
261 clipboard_clear_func (GtkClipboard *clipboard __attribute__((unused)),
262 gpointer user_data)
264 if (owner && GPOINTER_TO_INT(user_data) == current_selection)
266 JNIEnv *env = cp_gtk_gdk_env();
267 owner = 0;
268 (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
269 setSystemContentsID);
273 JNIEXPORT void JNICALL
274 Java_gnu_java_awt_peer_gtk_GtkClipboard_advertiseContent
275 (JNIEnv *env,
276 jobject instance,
277 jobjectArray mime_array,
278 #if GTK_MINOR_VERSION > 4
279 jboolean add_text, jboolean add_images, jboolean add_uris)
280 #else
281 jboolean add_text __attribute__((unused)),
282 jboolean add_images __attribute__((unused)),
283 jboolean add_uris __attribute__((unused)))
284 #endif
286 GtkTargetList *target_list;
287 GList *list;
288 GtkTargetEntry *targets;
289 gint n, i;
291 gdk_threads_enter ();
292 target_list = gtk_target_list_new (NULL, 0);
294 if (mime_array != NULL)
296 n = (*env)->GetArrayLength (env, mime_array);
297 for (i = 0; i < n; i++)
299 const char *text;
300 jstring target;
301 GdkAtom atom;
303 target = (*env)->GetObjectArrayElement (env, mime_array, i);
304 if (target == NULL)
305 break;
306 text = (*env)->GetStringUTFChars (env, target, NULL);
307 if (text == NULL)
308 break;
310 atom = gdk_atom_intern (text, FALSE);
311 gtk_target_list_add (target_list, atom, 0, OBJECT_TARGET);
313 (*env)->ReleaseStringUTFChars (env, target, text);
317 /* Add extra targets that gtk+ can provide/translate for us. */
318 #if GTK_MINOR_VERSION > 4
319 if (add_text)
320 gtk_target_list_add_text_targets (target_list, TEXT_TARGET);
321 if (add_images)
322 gtk_target_list_add_image_targets (target_list, IMAGE_TARGET, TRUE);
323 if (add_uris)
324 gtk_target_list_add_uri_targets (target_list, URI_TARGET);
325 #else
326 if (add_text)
327 gtk_target_list_add (target_list,
328 gdk_atom_intern ("STRING", FALSE),
329 0, TEXT_TARGET);
330 #endif
333 /* Turn list into a target table. */
334 n = g_list_length (target_list->list);
335 if (n > 0)
337 targets = g_new (GtkTargetEntry, n);
338 for (list = target_list->list, i = 0;
339 list != NULL;
340 list = list->next, i++)
342 GtkTargetPair *pair = (GtkTargetPair *) list->data;
343 targets[i].target = gdk_atom_name (pair->target);
344 targets[i].flags = pair->flags;
345 targets[i].info = pair->info;
348 /* Set the targets plus callback functions and ask for the clipboard
349 to be stored when the application exists if supported. */
350 current_selection++;
351 if (gtk_clipboard_set_with_data (cp_gtk_clipboard, targets, n,
352 clipboard_get_func,
353 clipboard_clear_func,
354 GINT_TO_POINTER(current_selection)))
356 owner = 1;
357 if (gtk_clipboard_instance == NULL)
359 JNIEnv *env = cp_gtk_gdk_env ();
360 gtk_clipboard_instance = (*env)->NewGlobalRef(env, instance);
362 provideContentID
363 = (*env)->GetMethodID (env, gtk_clipboard_class,
364 "provideContent",
365 "(Ljava/lang/String;)[B");
366 if (provideContentID == NULL)
367 return;
369 provideTextID
370 = (*env)->GetMethodID (env, gtk_clipboard_class,
371 "provideText", "()Ljava/lang/String;");
372 if (provideTextID == NULL)
373 return;
375 provideImageID
376 = (*env)->GetMethodID (env, gtk_clipboard_class,
377 "provideImage",
378 "()Lgnu/java/awt/peer/gtk/GtkImage;");
379 if (provideImageID == NULL)
380 return;
382 provideURIsID
383 = (*env)->GetMethodID (env, gtk_clipboard_class,
384 "provideURIs",
385 "()[Ljava/lang/String;");
386 if (provideURIsID == NULL)
387 return;
389 #if GTK_MINOR_VERSION > 4
390 gtk_clipboard_set_can_store (cp_gtk_clipboard, NULL, 0);
391 #endif
393 else
395 owner = 0;
396 (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
397 setSystemContentsID);
400 for (i = 0; i < n; i++)
401 g_free (targets[i].target);
402 g_free (targets);
404 else if (owner)
406 gtk_clipboard_clear (cp_gtk_clipboard);
407 owner = 0;
410 gtk_target_list_unref (target_list);
411 gdk_threads_leave ();