OSDN Git Service

Imported GNU Classpath 0.20
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkClipboard.c
1 /* gtkclipboard.c
2    Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 #include "jcl.h"
40 #include "gtkpeer.h"
41 #include "gnu_java_awt_peer_gtk_GtkClipboard.h"
42
43 #define OBJECT_TARGET 1
44 #define TEXT_TARGET   2
45 #define IMAGE_TARGET  3
46 #define URI_TARGET    4
47
48 /* 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. */
56 static gint current_selection = 0;
57
58 /* Whether we "own" the clipboard. And may clear it. */
59 static int owner = 0;
60
61 static jclass gtk_clipboard_class;
62 static jmethodID setSystemContentsID;
63
64 static jobject gtk_clipboard_instance = NULL;
65 static jmethodID provideContentID;
66 static jmethodID provideTextID;
67 static jmethodID provideImageID;
68 static jmethodID provideURIsID;
69
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)))
76 {
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);
83 }
84 #endif
85
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)
92 {
93   GdkDisplay* display;
94   jboolean can_cache;
95
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;
102
103   cp_gtk_stringTarget = (*env)->NewGlobalRef(env, string);
104   cp_gtk_imageTarget = (*env)->NewGlobalRef(env, image);
105   cp_gtk_filesTarget = (*env)->NewGlobalRef(env, files);
106
107   gdk_threads_enter ();
108   cp_gtk_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
109
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))
114     {
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;
120     }
121   else
122 #endif
123     can_cache = JNI_FALSE;
124   gdk_threads_leave ();
125
126   return can_cache;
127 }
128
129 static void
130 clipboard_get_func (GtkClipboard *clipboard __attribute__((unused)),
131                     GtkSelectionData *selection,
132                     guint info,
133                     gpointer user_data __attribute__((unused)))
134 {
135   JNIEnv *env = cp_gtk_gdk_env ();
136   
137   if (info == OBJECT_TARGET)
138     {
139       const gchar *target_name;
140       jstring target_string;
141       jbyteArray bytes;
142       jint len;
143       jbyte *barray;
144
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);
165
166       (*env)->ReleaseByteArrayElements(env, bytes, barray, 0);
167
168     }
169   else if (info == TEXT_TARGET)
170     {
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;
185
186       gtk_selection_data_set_text (selection, text, len);
187       (*env)->ReleaseStringUTFChars (env, string, text);
188     }
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)
192     {
193       jobject gtkimage;
194       GdkPixbuf *pixbuf = NULL;
195       
196       gtkimage = (*env)->CallObjectMethod(env,
197                                           gtk_clipboard_instance,
198                                           provideImageID);
199       if (gtkimage == NULL)
200         return;
201       
202       pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage);
203       if (pixbuf != NULL)
204         {
205           gtk_selection_data_set_pixbuf (selection, pixbuf);
206
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);
211         }
212     }
213   else if (info == URI_TARGET)
214     {
215       jobjectArray uris;
216       jint count;
217       int i;
218       gchar **list;
219
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;
228
229       list = (gchar **) JCL_malloc (env, (count + 1) * sizeof (gchar *));
230       for (i = 0; i < count; i++)
231         {
232           const char *text;
233           jstring uri;
234           
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);
245         }
246
247       if (i == count)
248         {
249           list[count] = NULL;
250           gtk_selection_data_set_uris (selection, list);
251         }
252
253       for (i = 0; list[i] != NULL; i++)
254         free (list[i]);
255       JCL_free (env, list);
256     }
257 #endif
258 }
259
260 static void
261 clipboard_clear_func (GtkClipboard *clipboard __attribute__((unused)),
262                       gpointer user_data)
263 {
264   if (owner && GPOINTER_TO_INT(user_data) == current_selection)
265     {
266       JNIEnv *env = cp_gtk_gdk_env();
267       owner = 0;
268       (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
269                                     setSystemContentsID);
270     }
271 }
272
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
285 {
286   GtkTargetList *target_list;
287   GList *list;
288   GtkTargetEntry *targets;
289   gint n, i;
290
291   gdk_threads_enter ();
292   target_list = gtk_target_list_new (NULL, 0);
293
294   if (mime_array != NULL)
295     {
296       n = (*env)->GetArrayLength (env, mime_array);
297       for (i = 0; i < n; i++)
298         {
299           const char *text;
300           jstring target;
301           GdkAtom atom;
302
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;
309
310           atom = gdk_atom_intern (text, FALSE);
311           gtk_target_list_add (target_list, atom, 0, OBJECT_TARGET);
312
313           (*env)->ReleaseStringUTFChars (env, target, text);
314         }
315     }
316
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
331
332
333   /* Turn list into a target table. */
334   n = g_list_length (target_list->list);
335   if (n > 0)
336     {
337       targets = g_new (GtkTargetEntry, n);
338       for (list = target_list->list, i = 0;
339            list != NULL;
340            list = list->next, i++)
341         {
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;
346         }
347
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)))
355         {
356           owner = 1;
357           if (gtk_clipboard_instance == NULL)
358             {
359               JNIEnv *env = cp_gtk_gdk_env ();
360               gtk_clipboard_instance =  (*env)->NewGlobalRef(env, instance);
361
362               provideContentID
363                 = (*env)->GetMethodID (env, gtk_clipboard_class,
364                                        "provideContent",
365                                        "(Ljava/lang/String;)[B");
366               if (provideContentID == NULL)
367                 return;
368
369               provideTextID
370                 = (*env)->GetMethodID (env, gtk_clipboard_class,
371                                        "provideText", "()Ljava/lang/String;");
372               if (provideTextID == NULL)
373                 return;
374
375               provideImageID
376                 = (*env)->GetMethodID (env, gtk_clipboard_class,
377                                        "provideImage",
378                                        "()Lgnu/java/awt/peer/gtk/GtkImage;");
379               if (provideImageID == NULL)
380                 return;
381
382               provideURIsID
383                 = (*env)->GetMethodID (env, gtk_clipboard_class,
384                                        "provideURIs",
385                                        "()[Ljava/lang/String;");
386               if (provideURIsID == NULL)
387                 return;
388             }
389 #if GTK_MINOR_VERSION > 4
390           gtk_clipboard_set_can_store (cp_gtk_clipboard, NULL, 0);
391 #endif
392         }
393       else
394         {
395           owner = 0;
396           (*env)->CallStaticVoidMethod (env, gtk_clipboard_class,
397                                         setSystemContentsID);
398         }
399
400       for (i = 0; i < n; i++)
401         g_free (targets[i].target);
402       g_free (targets);
403     }
404   else if (owner)
405     {
406       gtk_clipboard_clear (cp_gtk_clipboard);
407       owner = 0;
408     }
409
410   gtk_target_list_unref (target_list);
411   gdk_threads_leave ();
412 }