1 /* gtkselection.c -- Native C functions for GtkSelection class using gtk+.
2    Copyright (C) 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_GtkSelection.h"
42 
43 static jmethodID mimeTypesAvailableID;
44 
45 /* Note this is actually just a GtkClipboardReceivedFunc, not a real
46    GtkClipboardTargetsReceivedFunc, see requestMimeTypes. */
47 static void
clipboard_targets_received(GtkClipboard * clipboard,GtkSelectionData * target_data,gpointer selection)48 clipboard_targets_received (GtkClipboard *clipboard
49 			    __attribute__((unused)),
50 			    GtkSelectionData *target_data,
51 			    gpointer selection)
52 {
53   GdkAtom *targets = NULL;
54   gint targets_len = 0;
55   gchar **target_strings = NULL;
56   jobjectArray strings = NULL;
57   int strings_len = 0;
58   gboolean include_text = FALSE;
59   gboolean include_image = FALSE;
60   gboolean include_uris = FALSE;
61   jobject selection_obj = (jobject) selection;
62   JNIEnv *env = cp_gtk_gdk_env ();
63 
64   if (target_data != NULL && target_data->length > 0)
65     {
66       include_text = gtk_selection_data_targets_include_text (target_data);
67 
68 #if GTK_MINOR_VERSION > 4
69       include_image = gtk_selection_data_targets_include_image (target_data,
70 								TRUE);
71 #endif
72       if (gtk_selection_data_get_targets (target_data, &targets, &targets_len))
73 	{
74 	  int i;
75 	  GdkAtom uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
76 	  target_strings = g_new (gchar*, targets_len);
77 	  if (target_strings != NULL)
78 	    for (i = 0; i < targets_len; i++)
79 	      {
80 		gchar *name =  gdk_atom_name (targets[i]);
81 		if (strchr (name, '/') != NULL)
82 		  {
83 		    target_strings[i] = name;
84 		    strings_len++;
85 		    if (! include_uris && targets[i] == uri_list_atom)
86 		      include_uris = TRUE;
87 		  }
88 		else
89 		  target_strings[i] = NULL;
90 	      }
91 	}
92 
93       if (target_strings != NULL)
94 	{
95 	  int i = 0, j = 0;
96 	  jclass stringClass;
97 
98 	  if (include_text)
99 	    strings_len++;
100 	  if (include_image)
101 	    strings_len++;
102 	  if (include_uris)
103 	    strings_len++;
104 
105 	  stringClass = (*env)->FindClass (env, "java/lang/String");
106 	  strings = (*env)->NewObjectArray (env, strings_len, stringClass,
107 					    NULL);
108 	  (*env)->DeleteLocalRef(env, stringClass);
109 
110 	  if (strings != NULL)
111 	    {
112 	      if (include_text)
113 		(*env)->SetObjectArrayElement (env, strings, i++,
114 					       cp_gtk_stringTarget);
115 	      if (include_image)
116 		(*env)->SetObjectArrayElement (env, strings, i++,
117 					       cp_gtk_imageTarget);
118 	      if (include_uris)
119 		(*env)->SetObjectArrayElement (env, strings, i++,
120 					       cp_gtk_filesTarget);
121 
122 	      while(i < strings_len)
123 		{
124 		  if (target_strings[j] == NULL)
125 		    j++;
126 		  else
127 		    {
128 		      jstring string;
129 		      string = (*env)->NewStringUTF (env,
130 						     target_strings[j++]);
131 		      if (string == NULL)
132 			break;
133 		      (*env)->SetObjectArrayElement (env, strings, i++,
134 						     string);
135 		      (*env)->DeleteLocalRef (env, string);
136 		    }
137 		}
138 
139 	      (*env)->DeleteLocalRef(env, strings);
140 	    }
141 
142 	  for (i = 0; i < targets_len; i++)
143 	    g_free (target_strings[i]);
144 	  g_free (target_strings);
145 	}
146     }
147 
148   (*env)->CallVoidMethod (env, selection_obj,
149 			  mimeTypesAvailableID,
150 			  strings);
151   (*env)->DeleteGlobalRef (env, selection_obj);
152 }
153 
154 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkSelection_requestMimeTypes(JNIEnv * env,jobject selection,jboolean clipboard)155 Java_gnu_java_awt_peer_gtk_GtkSelection_requestMimeTypes
156 (JNIEnv *env, jobject selection, jboolean clipboard)
157 {
158   jobject selection_obj;
159   GtkClipboard *gtk_clipboard;
160   selection_obj = (*env)->NewGlobalRef(env, selection);
161   if (selection_obj == NULL)
162     return;
163 
164   if (mimeTypesAvailableID == NULL)
165     {
166       jclass gtk_selection_class;
167       gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
168       mimeTypesAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
169 						"mimeTypesAvailable",
170 						"([Ljava/lang/String;)V");
171       if (mimeTypesAvailableID == NULL)
172 	return;
173     }
174 
175   if (clipboard)
176     gtk_clipboard = cp_gtk_clipboard;
177   else
178     gtk_clipboard = cp_gtk_selection;
179 
180   /* We would have liked to call gtk_clipboard_request_targets ()
181      since that is more general. But the result of that, an array of
182      GdkAtoms, cannot be used with the
183      gtk_selection_data_targets_include_<x> functions (despite what
184      the name suggests). */
185   gdk_threads_enter ();
186   gtk_clipboard_request_contents (gtk_clipboard,
187 				  gdk_atom_intern ("TARGETS", FALSE),
188 				  clipboard_targets_received,
189 				  (gpointer) selection_obj);
190   gdk_threads_leave ();
191 }
192 
193 
194 static jmethodID textAvailableID;
195 
196 static void
clipboard_text_received(GtkClipboard * clipboard,const gchar * text,gpointer selection)197 clipboard_text_received (GtkClipboard *clipboard
198 			 __attribute__((unused)),
199 			 const gchar *text,
200 			 gpointer selection)
201 {
202   jstring string;
203   jobject selection_obj = (jobject) selection;
204 
205   JNIEnv *env = cp_gtk_gdk_env ();
206   if (text != NULL)
207     string = (*env)->NewStringUTF (env, text);
208   else
209     string = NULL;
210 
211   (*env)->CallVoidMethod (env, selection_obj,
212                           textAvailableID,
213                           string);
214   (*env)->DeleteGlobalRef (env, selection_obj);
215 
216   if (string != NULL)
217     (*env)->DeleteLocalRef (env, string);
218 
219 }
220 
221 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkSelection_requestText(JNIEnv * env,jobject selection,jboolean clipboard)222 Java_gnu_java_awt_peer_gtk_GtkSelection_requestText
223 (JNIEnv *env, jobject selection, jboolean clipboard)
224 {
225   jobject selection_obj;
226   GtkClipboard *gtk_clipboard;
227   selection_obj = (*env)->NewGlobalRef(env, selection);
228   if (selection_obj == NULL)
229     return;
230 
231   if (textAvailableID == NULL)
232     {
233       jclass gtk_selection_class;
234       gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
235       textAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
236 					     "textAvailable",
237 					     "(Ljava/lang/String;)V");
238       if (textAvailableID == NULL)
239         return;
240     }
241 
242   if (clipboard)
243     gtk_clipboard = cp_gtk_clipboard;
244   else
245     gtk_clipboard = cp_gtk_selection;
246 
247   gdk_threads_enter ();
248   gtk_clipboard_request_text (gtk_clipboard,
249 			      clipboard_text_received,
250 			      (gpointer) selection_obj);
251   gdk_threads_leave ();
252 }
253 
254 static jmethodID imageAvailableID;
255 
256 static void
clipboard_image_received(GtkClipboard * clipboard,GdkPixbuf * pixbuf,gpointer selection)257 clipboard_image_received (GtkClipboard *clipboard
258 			  __attribute__((unused)),
259 			  GdkPixbuf *pixbuf,
260 			  gpointer selection)
261 {
262   jobject pointer = NULL;
263   jobject selection_obj = (jobject) selection;
264   JNIEnv *env = cp_gtk_gdk_env ();
265 
266   if (pixbuf != NULL)
267     {
268       g_object_ref (pixbuf);
269       pointer = JCL_NewRawDataObject (env, (void *) pixbuf);
270     }
271 
272   (*env)->CallVoidMethod (env, selection_obj,
273 			  imageAvailableID,
274                           pointer);
275   (*env)->DeleteGlobalRef (env, selection_obj);
276 }
277 
278 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkSelection_requestImage(JNIEnv * env,jobject obj,jboolean clipboard)279 Java_gnu_java_awt_peer_gtk_GtkSelection_requestImage (JNIEnv *env,
280 						      jobject obj,
281 						      jboolean clipboard)
282 {
283   jobject selection_obj;
284   GtkClipboard *gtk_clipboard;
285   selection_obj = (*env)->NewGlobalRef(env, obj);
286   if (selection_obj == NULL)
287     return;
288 
289   if (imageAvailableID == NULL)
290     {
291       jclass gtk_selection_class;
292       gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
293       imageAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
294 					     "imageAvailable",
295 					     "(Lgnu/classpath/Pointer;)V");
296       if (imageAvailableID == NULL)
297         return;
298     }
299 
300   if (clipboard)
301     gtk_clipboard = cp_gtk_clipboard;
302   else
303     gtk_clipboard = cp_gtk_selection;
304 
305 #if GTK_MINOR_VERSION > 4
306   gdk_threads_enter ();
307   gtk_clipboard_request_image (gtk_clipboard,
308 			       clipboard_image_received,
309 			       (gpointer) selection_obj);
310   gdk_threads_leave ();
311 #else
312   clipboard_image_received (gtk_clipboard, NULL, (gpointer) selection_obj);
313 #endif
314 }
315 
316 static jmethodID urisAvailableID;
317 
318 static void
clipboard_uris_received(GtkClipboard * clipboard,GtkSelectionData * uri_data,gpointer selection)319 clipboard_uris_received (GtkClipboard *clipboard
320 			 __attribute__((unused)),
321 			 GtkSelectionData *uri_data,
322 			 gpointer selection)
323 {
324   gchar **uris = NULL;
325   jobjectArray strings = NULL;
326   jobject selection_obj = (jobject) selection;
327   JNIEnv *env = cp_gtk_gdk_env ();
328 
329 #if GTK_MINOR_VERSION > 4
330   if (uri_data != NULL)
331     uris = gtk_selection_data_get_uris (uri_data);
332 #else
333   if (uri_data != NULL)
334     uris = NULL;
335 #endif
336 
337   if (uris != NULL)
338     {
339       int len, i;
340       gchar **count = uris;
341       jclass stringClass = (*env)->FindClass (env, "java/lang/String");
342 
343       len = 0;
344       while (count[len])
345 	len++;
346 
347       strings = (*env)->NewObjectArray (env, len, stringClass, NULL);
348       (*env)->DeleteLocalRef(env, stringClass);
349 
350       if (strings != NULL)
351 	{
352 	  for (i = 0; i < len; i++)
353 	    {
354 	      jstring string = (*env)->NewStringUTF (env, uris[i]);
355 	      if (string == NULL)
356 		break;
357 	      (*env)->SetObjectArrayElement (env, strings, i, string);
358 	      (*env)->DeleteLocalRef (env, string);
359 	    }
360 
361 	  (*env)->DeleteLocalRef(env, strings);
362 	}
363       g_strfreev (uris);
364     }
365 
366   (*env)->CallVoidMethod (env, selection_obj,
367                           urisAvailableID,
368                           strings);
369   (*env)->DeleteGlobalRef (env, selection_obj);
370 }
371 
372 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkSelection_requestURIs(JNIEnv * env,jobject obj,jboolean clipboard)373 Java_gnu_java_awt_peer_gtk_GtkSelection_requestURIs (JNIEnv *env,
374 						     jobject obj,
375 						     jboolean clipboard)
376 {
377 #if GTK_MINOR_VERSION > 4
378   GdkAtom uri_atom;
379 #endif
380   jobject selection_obj;
381   GtkClipboard *gtk_clipboard;
382   selection_obj = (*env)->NewGlobalRef(env, obj);
383   if (selection_obj == NULL)
384     return;
385 
386   if (urisAvailableID == NULL)
387     {
388       jclass gtk_selection_class;
389       gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
390       urisAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
391 					     "urisAvailable",
392                                              "([Ljava/lang/String;)V");
393       if (urisAvailableID == NULL)
394         return;
395     }
396 
397   if (clipboard)
398     gtk_clipboard = cp_gtk_clipboard;
399   else
400     gtk_clipboard = cp_gtk_selection;
401 
402 #if GTK_MINOR_VERSION > 4
403   /* There is no real request_uris so we have to make one ourselves. */
404   gdk_threads_enter ();
405   uri_atom = gdk_atom_intern ("text/uri-list", FALSE);
406   gtk_clipboard_request_contents (gtk_clipboard,
407 				  uri_atom,
408 				  clipboard_uris_received,
409 				  (gpointer) selection_obj);
410   gdk_threads_leave ();
411 #else
412   clipboard_uris_received (gtk_clipboard, NULL, (gpointer) selection_obj);
413 #endif
414 }
415 
416 static jmethodID bytesAvailableID;
417 
418 static void
clipboard_bytes_received(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer selection)419 clipboard_bytes_received (GtkClipboard *clipboard
420 			  __attribute__((unused)),
421 			  GtkSelectionData *selection_data,
422 			  gpointer selection)
423 {
424   jbyteArray bytes = NULL;
425   jobject selection_obj = (jobject) selection;
426   JNIEnv *env = cp_gtk_gdk_env ();
427 
428    if (selection_data != NULL && selection_data->length > 0)
429     {
430       bytes = (*env)->NewByteArray (env, selection_data->length);
431       if (bytes != NULL)
432 	(*env)->SetByteArrayRegion(env, bytes, 0, selection_data->length,
433 				   (jbyte *) selection_data->data);
434     }
435 
436   (*env)->CallVoidMethod (env, selection_obj,
437                           bytesAvailableID,
438                           bytes);
439   (*env)->DeleteGlobalRef (env, selection_obj);
440 }
441 
442 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkSelection_requestBytes(JNIEnv * env,jobject obj,jboolean clipboard,jstring target_string)443 Java_gnu_java_awt_peer_gtk_GtkSelection_requestBytes (JNIEnv *env,
444 						      jobject obj,
445 						      jboolean clipboard,
446 						      jstring target_string)
447 {
448   int len;
449   const gchar *target_text;
450   GdkAtom target_atom;
451   jobject selection_obj;
452   GtkClipboard *gtk_clipboard;
453   selection_obj = (*env)->NewGlobalRef(env, obj);
454   if (selection_obj == NULL)
455     return;
456 
457   if (bytesAvailableID == NULL)
458     {
459       jclass gtk_selection_class;
460       gtk_selection_class = (*env)->GetObjectClass (env, selection_obj);
461       bytesAvailableID = (*env)->GetMethodID (env, gtk_selection_class,
462 					      "bytesAvailable",
463 					      "([B)V");
464       if (bytesAvailableID == NULL)
465         return;
466     }
467 
468   len = (*env)->GetStringUTFLength (env, target_string);
469   if (len == -1)
470     return;
471   target_text = (*env)->GetStringUTFChars (env, target_string, NULL);
472   if (target_text == NULL)
473     return;
474 
475   if (clipboard)
476     gtk_clipboard = cp_gtk_clipboard;
477   else
478     gtk_clipboard = cp_gtk_selection;
479 
480   gdk_threads_enter ();
481   target_atom = gdk_atom_intern (target_text, FALSE);
482   gtk_clipboard_request_contents (gtk_clipboard,
483                                   target_atom,
484                                   clipboard_bytes_received,
485                                   (gpointer) selection_obj);
486   gdk_threads_leave ();
487 
488   (*env)->ReleaseStringUTFChars (env, target_string, target_text);
489 }
490