OSDN Git Service

2006-08-02 Sven de Marothy <sven@physto.se>
[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, 2006 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 selection plus corresponding GtkClipboard objects. */
49 GtkClipboard *cp_gtk_clipboard;
50 GtkClipboard *cp_gtk_selection;
51
52 jobject cp_gtk_clipboard_instance;
53 jobject cp_gtk_selection_instance;
54
55 /* Standard (string targets) shared with GtkSelection. */
56 jstring cp_gtk_stringTarget;
57 jstring cp_gtk_imageTarget;
58 jstring cp_gtk_filesTarget;
59
60 static jclass gtk_clipboard_class;
61
62 static jmethodID setSystemContentsID;
63 static jmethodID provideContentID;
64 static jmethodID provideTextID;
65 static jmethodID provideImageID;
66 static jmethodID provideURIsID;
67
68 /* Called when clipboard owner changes. Used to update available targets. */
69 #if GTK_MINOR_VERSION > 4
70 static void
71 clipboard_owner_change_cb (GtkClipboard *clipboard,
72                            GdkEvent *event __attribute__((unused)),
73                            gpointer user_data __attribute__((unused)))
74 {
75   JNIEnv *env = cp_gtk_gdk_env ();
76   if (clipboard == cp_gtk_clipboard)
77     (*env)->CallVoidMethod (env, cp_gtk_clipboard_instance,
78                             setSystemContentsID, JNI_FALSE);
79   else
80     (*env)->CallVoidMethod (env, cp_gtk_selection_instance,
81                             setSystemContentsID, JNI_FALSE);
82
83 }
84 #endif
85
86 JNIEXPORT jboolean JNICALL 
87 Java_gnu_java_awt_peer_gtk_GtkClipboard_initNativeState (JNIEnv *env,
88                                                          jclass clz,
89                                                          jobject gtkclipboard,
90                                                          jobject gtkselection,
91                                                          jstring string,
92                                                          jstring image,
93                                                          jstring files)
94 {
95   GdkDisplay* display;
96   jboolean can_cache;
97
98   gtk_clipboard_class = clz;
99   setSystemContentsID = (*env)->GetMethodID (env, gtk_clipboard_class,
100                                              "setSystemContents",
101                                              "(Z)V");
102   if (setSystemContentsID == NULL)
103     return JNI_FALSE;
104
105   provideContentID = (*env)->GetMethodID (env, gtk_clipboard_class,
106                                           "provideContent",
107                                           "(Ljava/lang/String;)[B");
108   if (provideContentID == NULL)
109     return JNI_FALSE;
110   
111   provideTextID = (*env)->GetMethodID (env, gtk_clipboard_class,
112                                        "provideText",
113                                        "()Ljava/lang/String;");
114   if (provideTextID == NULL)
115     return JNI_FALSE;
116   
117   provideImageID = (*env)->GetMethodID (env, gtk_clipboard_class,
118                                         "provideImage",
119                                         "()Lgnu/java/awt/peer/gtk/GtkImage;");
120   if (provideImageID == NULL)
121     return JNI_FALSE;
122   
123   provideURIsID = (*env)->GetMethodID (env, gtk_clipboard_class,
124                                        "provideURIs",
125                                        "()[Ljava/lang/String;");
126   if (provideURIsID == NULL)
127     return JNI_FALSE;
128   
129   cp_gtk_clipboard_instance = (*env)->NewGlobalRef(env, gtkclipboard);
130   cp_gtk_selection_instance = (*env)->NewGlobalRef(env, gtkselection);
131   
132   cp_gtk_stringTarget = (*env)->NewGlobalRef(env, string);
133   cp_gtk_imageTarget = (*env)->NewGlobalRef(env, image);
134   cp_gtk_filesTarget = (*env)->NewGlobalRef(env, files);
135
136   gdk_threads_enter ();
137   cp_gtk_clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
138   cp_gtk_selection = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
139
140   display = gtk_clipboard_get_display (cp_gtk_clipboard);
141   /* Check for support for clipboard owner changes. */
142 #if GTK_MINOR_VERSION > 4
143   if (gdk_display_supports_selection_notification (display))
144     {
145       g_signal_connect (cp_gtk_clipboard, "owner-change",
146                         G_CALLBACK (clipboard_owner_change_cb), NULL);
147       g_signal_connect (cp_gtk_selection, "owner-change",
148                         G_CALLBACK (clipboard_owner_change_cb), NULL);
149       gdk_display_request_selection_notification (display,
150                                                   GDK_SELECTION_CLIPBOARD);
151       gdk_display_request_selection_notification (display,
152                                                   GDK_SELECTION_PRIMARY);
153       can_cache = JNI_TRUE;
154     }
155   else
156 #endif
157     can_cache = JNI_FALSE;
158
159   gdk_threads_leave ();
160
161   return can_cache;
162 }
163
164 static void
165 clipboard_get_func (GtkClipboard *clipboard,
166                     GtkSelectionData *selection,
167                     guint info,
168                     gpointer user_data __attribute__((unused)))
169 {
170   jobject gtk_clipboard_instance;
171   JNIEnv *env = cp_gtk_gdk_env ();
172   
173   if (clipboard == cp_gtk_clipboard)
174     gtk_clipboard_instance = cp_gtk_clipboard_instance;
175   else
176     gtk_clipboard_instance = cp_gtk_selection_instance;
177
178   if (info == OBJECT_TARGET)
179     {
180       const gchar *target_name;
181       jstring target_string;
182       jbyteArray bytes;
183       jint len;
184       jbyte *barray;
185
186       target_name = gdk_atom_name (selection->target);
187       if (target_name == NULL)
188         return;
189       target_string = (*env)->NewStringUTF (env, target_name);
190       if (target_string == NULL)
191         return;
192       bytes = (*env)->CallObjectMethod(env,
193                                        gtk_clipboard_instance,
194                                        provideContentID,
195                                        target_string);
196       if (bytes == NULL)
197         return;
198       len = (*env)->GetArrayLength(env, bytes);
199       if (len <= 0)
200         return;
201       barray = (*env)->GetByteArrayElements(env, bytes, NULL);
202       if (barray == NULL)
203         return;
204       gtk_selection_data_set (selection, selection->target, 8,
205                               (guchar *) barray, len);
206
207       (*env)->ReleaseByteArrayElements(env, bytes, barray, 0);
208
209     }
210   else if (info == TEXT_TARGET)
211     {
212       jstring string;
213       const gchar *text;
214       int len;
215       string = (*env)->CallObjectMethod(env,
216                                         gtk_clipboard_instance,
217                                         provideTextID);
218       if (string == NULL)
219         return;
220       len = (*env)->GetStringUTFLength (env, string);
221       if (len == -1)
222         return;
223       text = (*env)->GetStringUTFChars (env, string, NULL);
224       if (text == NULL)
225         return;
226
227       gtk_selection_data_set_text (selection, text, len);
228       (*env)->ReleaseStringUTFChars (env, string, text);
229     }
230   /* Images and URIs/Files support only available with gtk+2.6 or higher. */
231 #if GTK_MINOR_VERSION > 4
232   else if (info == IMAGE_TARGET)
233     {
234       jobject gtkimage;
235       GdkPixbuf *pixbuf = NULL;
236       
237       gtkimage = (*env)->CallObjectMethod(env,
238                                           gtk_clipboard_instance,
239                                           provideImageID);
240       if (gtkimage == NULL)
241         return;
242       
243       pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage);
244       if (pixbuf != NULL)
245         gtk_selection_data_set_pixbuf (selection, pixbuf);
246     }
247   else if (info == URI_TARGET)
248     {
249       jobjectArray uris;
250       jint count;
251       int i;
252       gchar **list;
253
254       uris = (*env)->CallObjectMethod(env,
255                                       gtk_clipboard_instance,
256                                       provideURIsID);
257       if (uris == NULL)
258         return;
259       count = (*env)->GetArrayLength (env, uris);
260       if (count <= 0)
261         return;
262
263       list = (gchar **) JCL_malloc (env, (count + 1) * sizeof (gchar *));
264       for (i = 0; i < count; i++)
265         {
266           const char *text;
267           jstring uri;
268           
269           /* Mark NULL in so case of some error we can find the end. */
270           list[i] = NULL;
271           uri = (*env)->GetObjectArrayElement (env, uris, i);
272           if (uri == NULL)
273             break;
274           text = (*env)->GetStringUTFChars (env, uri, NULL);
275           if (text == NULL)
276             break;
277           list[i] = strdup (text);
278           (*env)->ReleaseStringUTFChars (env, uri, text);
279         }
280
281       if (i == count)
282         {
283           list[count] = NULL;
284           gtk_selection_data_set_uris (selection, list);
285         }
286
287       for (i = 0; list[i] != NULL; i++)
288         free (list[i]);
289       JCL_free (env, list);
290     }
291 #endif
292 }
293
294 static void
295 clipboard_clear_func (GtkClipboard *clipboard,
296                       gpointer user_data __attribute__((unused)))
297 {
298   JNIEnv *env = cp_gtk_gdk_env();
299   if (clipboard == cp_gtk_clipboard)
300     (*env)->CallVoidMethod (env, cp_gtk_clipboard_instance,
301                             setSystemContentsID, JNI_TRUE);
302   else
303     (*env)->CallVoidMethod (env, cp_gtk_selection_instance,
304                             setSystemContentsID, JNI_TRUE);
305
306 }
307
308 JNIEXPORT void JNICALL
309 Java_gnu_java_awt_peer_gtk_GtkClipboard_advertiseContent
310 (JNIEnv *env,
311  jobject instance,
312  jobjectArray mime_array,
313 #if GTK_MINOR_VERSION > 4
314  jboolean add_text, jboolean add_images, jboolean add_uris)
315 #else
316  jboolean add_text __attribute__((unused)),
317  jboolean add_images __attribute__((unused)),
318  jboolean add_uris __attribute__((unused)))
319 #endif
320 {
321   GtkTargetList *target_list;
322   GList *list;
323   GtkTargetEntry *targets;
324   gint n, i;
325
326   gdk_threads_enter ();
327   target_list = gtk_target_list_new (NULL, 0);
328
329   if (mime_array != NULL)
330     {
331       n = (*env)->GetArrayLength (env, mime_array);
332       for (i = 0; i < n; i++)
333         {
334           const char *text;
335           jstring target;
336           GdkAtom atom;
337
338           target = (*env)->GetObjectArrayElement (env, mime_array, i);
339           if (target == NULL)
340             break;
341           text = (*env)->GetStringUTFChars (env, target, NULL);
342           if (text == NULL)
343             break;
344
345           atom = gdk_atom_intern (text, FALSE);
346           gtk_target_list_add (target_list, atom, 0, OBJECT_TARGET);
347
348           (*env)->ReleaseStringUTFChars (env, target, text);
349         }
350     }
351
352   /* Add extra targets that gtk+ can provide/translate for us. */
353 #if GTK_MINOR_VERSION > 4
354   if (add_text)
355     gtk_target_list_add_text_targets (target_list, TEXT_TARGET);
356   if (add_images)
357     gtk_target_list_add_image_targets (target_list, IMAGE_TARGET, TRUE);
358   if (add_uris)
359     gtk_target_list_add_uri_targets (target_list, URI_TARGET);
360 #else
361   if (add_text)
362     gtk_target_list_add (target_list,
363                          gdk_atom_intern ("STRING", FALSE),
364                          0, TEXT_TARGET);
365 #endif
366
367
368   /* Turn list into a target table. */
369   n = g_list_length (target_list->list);
370   if (n > 0)
371     {
372       targets = g_new (GtkTargetEntry, n);
373       for (list = target_list->list, i = 0;
374            list != NULL;
375            list = list->next, i++)
376         {
377           GtkTargetPair *pair = (GtkTargetPair *) list->data;
378           targets[i].target = gdk_atom_name (pair->target);
379           targets[i].flags = pair->flags;
380           targets[i].info = pair->info;
381         }
382
383       /* Set the targets plus callback functions and ask for the clipboard
384          to be stored when the application exists if supported. */
385       if ((*env)->IsSameObject(env, instance, cp_gtk_clipboard_instance))
386         {
387           if (gtk_clipboard_set_with_data (cp_gtk_clipboard, targets, n,
388                                            clipboard_get_func,
389                                            clipboard_clear_func,
390                                            NULL))
391             {
392 #if GTK_MINOR_VERSION > 4
393               gtk_clipboard_set_can_store (cp_gtk_clipboard, NULL, 0);
394 #endif
395             }
396         }
397       else
398         {
399           if (gtk_clipboard_set_with_data (cp_gtk_selection, targets, n,
400                                            clipboard_get_func,
401                                            clipboard_clear_func,
402                                            NULL))
403             {
404 #if GTK_MINOR_VERSION > 4
405               gtk_clipboard_set_can_store (cp_gtk_selection, NULL, 0);
406 #endif
407             }
408         }
409
410       for (i = 0; i < n; i++)
411         g_free (targets[i].target);
412       g_free (targets);
413     }
414
415   gtk_target_list_unref (target_list);
416   gdk_threads_leave ();
417 }