1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.
23  */
24 
25 /*
26  * GTK+ DirectFB backend
27  * Copyright (C) 2001-2002  convergence integrated media GmbH
28  * Copyright (C) 2002-2004  convergence GmbH
29  * Written by Denis Oliver Kropp <dok@convergence.de> and
30  *            Sven Neumann <sven@convergence.de>
31  */
32 
33 #include "config.h"
34 
35 #include <string.h>
36 
37 #include "gdkdirectfb.h"
38 #include "gdkprivate-directfb.h"
39 
40 #include "gdkproperty.h"
41 #include "gdkselection.h"
42 #include "gdkprivate.h"
43 #include "gdkalias.h"
44 
45 
46 typedef struct _OwnerInfo OwnerInfo;
47 
48 struct _OwnerInfo
49 {
50   GdkAtom    selection;
51   GdkWindow *owner;
52 };
53 
54 GSList *owner_list = NULL;
55 
56 /* When a window is destroyed we check if it is the owner
57  * of any selections. This is somewhat inefficient, but
58  * owner_list is typically short, and it is a low memory,
59  * low code solution
60  */
61 void
_gdk_selection_window_destroyed(GdkWindow * window)62 _gdk_selection_window_destroyed (GdkWindow *window)
63 {
64   GSList *tmp_list = owner_list;
65 
66   while (tmp_list)
67     {
68       OwnerInfo *info = tmp_list->data;
69 
70       tmp_list = tmp_list->next;
71 
72       if (info->owner == window)
73 	{
74 	  owner_list = g_slist_remove (owner_list, info);
75 	  g_free (info);
76 	}
77     }
78 }
79 
80 gint
gdk_selection_owner_set_for_display(GdkDisplay * display,GdkWindow * owner,GdkAtom selection,guint32 time,gint send_event)81 gdk_selection_owner_set_for_display (GdkDisplay *display,
82                                      GdkWindow  *owner,
83                                      GdkAtom     selection,
84                                      guint32     time,
85                                      gint        send_event)
86 {
87   GSList    *tmp_list;
88   OwnerInfo *info;
89 
90   tmp_list = owner_list;
91   while (tmp_list)
92     {
93       info = tmp_list->data;
94       if (info->selection == selection)
95 	{
96 	  owner_list = g_slist_remove (owner_list, info);
97 	  g_free (info);
98 	  break;
99 	}
100       tmp_list = tmp_list->next;
101     }
102 
103   if (owner)
104     {
105       info = g_new (OwnerInfo, 1);
106       info->owner = owner;
107       info->selection = selection;
108 
109       owner_list = g_slist_prepend (owner_list, info);
110     }
111 
112   return TRUE;
113 }
114 
115 GdkWindow *
gdk_selection_owner_get_for_display(GdkDisplay * display,GdkAtom selection)116 gdk_selection_owner_get_for_display (GdkDisplay *display,
117                                      GdkAtom     selection)
118 {
119   OwnerInfo *info;
120   GSList    *tmp_list;
121 
122   tmp_list = owner_list;
123   while (tmp_list)
124     {
125       info = tmp_list->data;
126       if (info->selection == selection)
127 	{
128 	  return info->owner;
129 	}
130       tmp_list = tmp_list->next;
131     }
132   return NULL;
133 }
134 
135 void
gdk_selection_convert(GdkWindow * requestor,GdkAtom selection,GdkAtom target,guint32 time)136 gdk_selection_convert (GdkWindow *requestor,
137 		       GdkAtom    selection,
138 		       GdkAtom    target,
139 		       guint32    time)
140 {
141   GdkEvent  *event;
142   GdkWindow *owner;
143   GdkWindow *event_window;
144 
145   owner = gdk_selection_owner_get (selection);
146 
147   if (owner)
148     {
149       event_window = gdk_directfb_other_event_window (owner,
150                                                       GDK_SELECTION_REQUEST);
151       if (event_window)
152 	{
153 	  event = gdk_directfb_event_make (event_window,
154                                            GDK_SELECTION_REQUEST);
155 	  event->selection.requestor = GDK_WINDOW_DFB_ID (requestor);
156 	  event->selection.selection = selection;
157 	  event->selection.target    = target;
158 	  event->selection.property  = _gdk_selection_property;
159 	}
160     }
161   else
162     {
163       /* If no owner for the specified selection exists, the X server
164        * generates a SelectionNotify event to the requestor with property None.
165        */
166       gdk_selection_send_notify (GDK_WINDOW_DFB_ID (requestor),
167 				 selection,
168 				 target,
169 				 GDK_NONE,
170 				 0);
171     }
172 }
173 
174 gint
gdk_selection_property_get(GdkWindow * requestor,guchar ** data,GdkAtom * ret_type,gint * ret_format)175 gdk_selection_property_get (GdkWindow  *requestor,
176 			    guchar    **data,
177 			    GdkAtom    *ret_type,
178 			    gint       *ret_format)
179 {
180   guchar *t = NULL;
181   GdkAtom prop_type;
182   gint prop_format;
183   gint prop_len;
184 
185   g_return_val_if_fail (requestor != NULL, 0);
186   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
187 
188   if (!gdk_property_get (requestor,
189 			 _gdk_selection_property,
190 			 0/*AnyPropertyType?*/,
191 			 0, 0,
192 			 FALSE,
193 			 &prop_type, &prop_format, &prop_len,
194 			 &t))
195     {
196       *data = NULL;
197       return 0;
198     }
199 
200   if (ret_type)
201     *ret_type = prop_type;
202   if (ret_format)
203     *ret_format = prop_format;
204 
205   if (!gdk_property_get (requestor,
206 			 _gdk_selection_property,
207 			 0/*AnyPropertyType?*/,
208 			 0, prop_len + 1,
209 			 FALSE,
210 			 &prop_type, &prop_format, &prop_len,
211 			 &t))
212     {
213       *data = NULL;
214       return 0;
215     }
216 
217   *data = t;
218 
219   return prop_len;
220 }
221 
222 
223 void
gdk_selection_send_notify_for_display(GdkDisplay * display,guint32 requestor,GdkAtom selection,GdkAtom target,GdkAtom property,guint32 time)224 gdk_selection_send_notify_for_display (GdkDisplay *display,
225                                        guint32     requestor,
226                                        GdkAtom     selection,
227                                        GdkAtom     target,
228                                        GdkAtom     property,
229                                        guint32     time)
230 {
231   GdkEvent  *event;
232   GdkWindow *event_window;
233 
234   event_window = gdk_window_lookup ((GdkNativeWindow) requestor);
235 
236   if (!event_window)
237     return;
238 
239   event_window = gdk_directfb_other_event_window (event_window,
240                                                   GDK_SELECTION_NOTIFY);
241 
242   if (event_window)
243     {
244       event = gdk_directfb_event_make (event_window, GDK_SELECTION_NOTIFY);
245       event->selection.selection = selection;
246       event->selection.target = target;
247       event->selection.property = property;
248       event->selection.requestor = (GdkNativeWindow) requestor;
249     }
250 }
251 
252 gint
gdk_text_property_to_text_list_for_display(GdkDisplay * display,GdkAtom encoding,gint format,const guchar * text,gint length,gchar *** list)253 gdk_text_property_to_text_list_for_display (GdkDisplay      *display,
254                                             GdkAtom          encoding,
255                                             gint             format,
256                                             const guchar    *text,
257                                             gint             length,
258                                             gchar         ***list)
259 {
260   g_warning ("gdk_text_property_to_text_list() not implemented\n");
261   return 0;
262 }
263 
264 void
gdk_free_text_list(gchar ** list)265 gdk_free_text_list (gchar **list)
266 {
267   g_return_if_fail (list != NULL);
268   g_warning ("gdk_free_text_list() not implemented\n");
269 }
270 
271 gint
gdk_string_to_compound_text_for_display(GdkDisplay * display,const gchar * str,GdkAtom * encoding,gint * format,guchar ** ctext,gint * length)272 gdk_string_to_compound_text_for_display (GdkDisplay   *display,
273                                          const gchar  *str,
274                                          GdkAtom      *encoding,
275                                          gint         *format,
276                                          guchar      **ctext,
277                                          gint         *length)
278 {
279   g_warning ("gdk_string_to_compound_text() not implemented\n");
280   return 0;
281 }
282 
283 void
gdk_free_compound_text(guchar * ctext)284 gdk_free_compound_text (guchar *ctext)
285 {
286   g_warning ("gdk_free_compound_text() not implemented\n");
287 }
288 
289 /**
290  * gdk_utf8_to_string_target:
291  * @str: a UTF-8 string
292  *
293  * Convert an UTF-8 string into the best possible representation
294  * as a STRING. The representation of characters not in STRING
295  * is not specified; it may be as pseudo-escape sequences
296  * \x{ABCD}, or it may be in some other form of approximation.
297  *
298  * Return value: the newly allocated string, or %NULL if the
299  *               conversion failed. (It should not fail for
300  *               any properly formed UTF-8 string.)
301  **/
302 gchar *
gdk_utf8_to_string_target(const gchar * str)303 gdk_utf8_to_string_target (const gchar *str)
304 {
305   g_warning ("gdk_utf8_to_string_target() not implemented\n");
306   return 0;
307 }
308 
309 /**
310  * gdk_utf8_to_compound_text:
311  * @str:      a UTF-8 string
312  * @encoding: location to store resulting encoding
313  * @format:   location to store format of the result
314  * @ctext:    location to store the data of the result
315  * @length:   location to store the length of the data
316  *            stored in @ctext
317  *
318  * Convert from UTF-8 to compound text.
319  *
320  * Return value: %TRUE if the conversion succeeded, otherwise
321  *               false.
322  **/
323 gboolean
gdk_utf8_to_compound_text_for_display(GdkDisplay * display,const gchar * str,GdkAtom * encoding,gint * format,guchar ** ctext,gint * length)324 gdk_utf8_to_compound_text_for_display (GdkDisplay   *display,
325                                        const gchar  *str,
326                                        GdkAtom      *encoding,
327                                        gint         *format,
328                                        guchar      **ctext,
329                                        gint         *length)
330 {
331   g_warning ("gdk_utf8_to_compound_text() not implemented\n");
332   return 0;
333 }
334 
335 static gint
make_list(const gchar * text,gint length,gboolean latin1,gchar *** list)336 make_list (const gchar  *text,
337 	   gint          length,
338 	   gboolean      latin1,
339 	   gchar      ***list)
340 {
341   GSList *strings = NULL;
342   gint n_strings = 0;
343   gint i;
344   const gchar *p = text;
345   const gchar *q;
346   GSList *tmp_list;
347   GError *error = NULL;
348 
349   while (p < text + length)
350     {
351       gchar *str;
352 
353       q = p;
354       while (*q && q < text + length)
355 	q++;
356 
357       if (latin1)
358 	{
359 	  str = g_convert (p, q - p,
360 			   "UTF-8", "ISO-8859-1",
361 			   NULL, NULL, &error);
362 
363 	  if (!str)
364 	    {
365 	      g_warning ("Error converting selection from STRING: %s",
366 			 error->message);
367 	      g_error_free (error);
368 	    }
369 	}
370       else
371 	str = g_strndup (p, q - p);
372 
373       if (str)
374 	{
375 	  strings = g_slist_prepend (strings, str);
376 	  n_strings++;
377 	}
378 
379       p = q + 1;
380     }
381 
382   if (list)
383     *list = g_new (gchar *, n_strings + 1);
384 
385   (*list)[n_strings] = NULL;
386 
387   i = n_strings;
388   tmp_list = strings;
389   while (tmp_list)
390     {
391       if (list)
392 	(*list)[--i] = tmp_list->data;
393       else
394 	g_free (tmp_list->data);
395 
396       tmp_list = tmp_list->next;
397     }
398 
399   g_slist_free (strings);
400 
401   return n_strings;
402 }
403 
404 
405 /**
406  * gdk_text_property_to_utf8_list:
407  * @encoding: an atom representing the encoding of the text
408  * @format:   the format of the property
409  * @text:     the text to convert
410  * @length:   the length of @text, in bytes
411  * @list:     location to store the list of strings or %NULL. The
412  *            list should be freed with g_strfreev().
413  *
414  * Convert a text property in the giving encoding to
415  * a list of UTF-8 strings.
416  *
417  * Return value: the number of strings in the resulting
418  *               list.
419  **/
420 gint
gdk_text_property_to_utf8_list_for_display(GdkDisplay * display,GdkAtom encoding,gint format,const guchar * text,gint length,gchar *** list)421 gdk_text_property_to_utf8_list_for_display (GdkDisplay     *display,
422                                             GdkAtom         encoding,
423                                             gint            format,
424                                             const guchar   *text,
425                                             gint            length,
426                                             gchar        ***list)
427 {
428   g_return_val_if_fail (text != NULL, 0);
429   g_return_val_if_fail (length >= 0, 0);
430 
431   if (encoding == GDK_TARGET_STRING)
432     {
433       return make_list ((gchar *)text, length, TRUE, list);
434     }
435   else if (encoding == gdk_atom_intern ("UTF8_STRING", FALSE))
436     {
437       return make_list ((gchar *)text, length, FALSE, list);
438     }
439   else
440     {
441       gchar **local_list;
442       gint local_count;
443       gint i;
444       const gchar *charset = NULL;
445       gboolean need_conversion = !g_get_charset (&charset);
446       gint count = 0;
447       GError *error = NULL;
448 
449       /* Probably COMPOUND text, we fall back to Xlib routines
450        */
451       local_count = gdk_text_property_to_text_list (encoding,
452 						    format,
453 						    text,
454 						    length,
455 						    &local_list);
456       if (list)
457 	*list = g_new (gchar *, local_count + 1);
458 
459       for (i = 0; i < local_count; i++)
460 	{
461 	  /* list contains stuff in our default encoding
462 	   */
463 	  if (need_conversion)
464 	    {
465 	      gchar *utf = g_convert (local_list[i], -1,
466 				      "UTF-8", charset,
467 				      NULL, NULL, &error);
468 	      if (utf)
469 		{
470 		  if (list)
471 		    (*list)[count++] = utf;
472 		  else
473 		    g_free (utf);
474 		}
475 	      else
476 		{
477 		  g_warning ("Error converting to UTF-8 from '%s': %s",
478 			     charset, error->message);
479 		  g_error_free (error);
480 		  error = NULL;
481 		}
482 	    }
483 	  else
484 	    {
485 	      if (list)
486 		(*list)[count++] = g_strdup (local_list[i]);
487 	    }
488 	}
489 
490       gdk_free_text_list (local_list);
491       (*list)[count] = NULL;
492 
493       return count;
494     }
495 }
496 
497 #define __GDK_SELECTION_X11_C__
498 #include "gdkaliasdef.c"
499