]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/gdkselection-fb.c
Don't mangle sequences of consecutive \n or \r.
[~andy/gtk] / gdk / linux-fb / gdkselection-fb.c
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.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <string.h>
28
29 #include "gdkproperty.h"
30 #include "gdkselection.h"
31 #include "gdkprivate.h"
32 #include "gdkprivate-fb.h"
33
34
35 typedef struct _OwnerInfo OwnerInfo;
36
37 struct _OwnerInfo
38 {
39   GdkAtom    selection;
40   GdkWindow *owner;
41 };
42
43 GSList *owner_list;
44
45 /* When a window is destroyed we check if it is the owner
46  * of any selections. This is somewhat inefficient, but
47  * owner_list is typically short, and it is a low memory,
48  * low code solution
49  */
50 void
51 _gdk_selection_window_destroyed (GdkWindow *window)
52 {
53   GSList *tmp_list = owner_list;
54   while (tmp_list)
55     {
56       OwnerInfo *info = tmp_list->data;
57       tmp_list = tmp_list->next;
58       
59       if (info->owner == window)
60         {
61           owner_list = g_slist_remove (owner_list, info);
62           g_free (info);
63         }
64     }
65 }
66
67 gint
68 gdk_selection_owner_set (GdkWindow *owner,
69                          GdkAtom    selection,
70                          guint32    time,
71                          gint       send_event)
72 {
73   GSList *tmp_list;
74   OwnerInfo *info;
75
76   tmp_list = owner_list;
77   while (tmp_list)
78     {
79       info = tmp_list->data;
80       if (info->selection == selection)
81         {
82           owner_list = g_slist_remove (owner_list, info);
83           g_free (info);
84           break;
85         }
86       tmp_list = tmp_list->next;
87     }
88
89   if (owner)
90     {
91       info = g_new (OwnerInfo, 1);
92       info->owner = owner;
93       info->selection = selection;
94
95       owner_list = g_slist_prepend (owner_list, info);
96     }
97
98   return TRUE;
99 }
100
101 GdkWindow*
102 gdk_selection_owner_get (GdkAtom selection)
103 {
104   OwnerInfo *info;
105   GSList *tmp_list;
106   
107   tmp_list = owner_list;
108   while (tmp_list)
109     {
110       info = tmp_list->data;
111       if (info->selection == selection)
112         {
113           return info->owner;
114         }
115       tmp_list = tmp_list->next;
116     }
117   return NULL;
118 }
119
120 void
121 gdk_selection_convert (GdkWindow *requestor,
122                        GdkAtom    selection,
123                        GdkAtom    target,
124                        guint32    time)
125 {
126   GdkEvent *event;
127   GdkWindow *owner;
128   GdkWindow *event_window;
129   
130   owner = gdk_selection_owner_get (selection);
131   
132   if (owner)
133     {
134       event_window = gdk_fb_other_event_window (owner, GDK_SELECTION_REQUEST);
135       if (event_window)
136         {
137           event = gdk_event_make (event_window, GDK_SELECTION_REQUEST, TRUE);
138           event->selection.requestor = requestor;
139           event->selection.selection = selection;
140           event->selection.target = target;
141           event->selection.property = _gdk_selection_property;
142         }
143     }
144   else
145     {
146       /* If no owner for the specified selection exists, the X server
147        * generates a SelectionNotify event to the requestor with property None.
148        */
149       gdk_selection_send_notify ((guint32)requestor,
150                                  selection,
151                                  target,
152                                  GDK_NONE,
153                                  0);
154     }
155 }
156
157 gint
158 gdk_selection_property_get (GdkWindow  *requestor,
159                             guchar    **data,
160                             GdkAtom    *ret_type,
161                             gint       *ret_format)
162 {
163   guchar *t = NULL;
164   GdkAtom prop_type;
165   gint prop_format;
166   gint prop_len;
167   
168   g_return_val_if_fail (requestor != NULL, 0);
169   g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
170   
171   if (!gdk_property_get (requestor,
172                          _gdk_selection_property,
173                          0/*AnyPropertyType?*/,
174                          0, 0,
175                          FALSE,
176                          &prop_type, &prop_format, &prop_len,
177                          &t))
178     {
179       *data = NULL;
180       return 0;
181     }
182
183   if (ret_type)
184     *ret_type = prop_type;
185   if (ret_format)
186     *ret_format = prop_format;
187
188   if (!gdk_property_get (requestor,
189                          _gdk_selection_property,
190                          0/*AnyPropertyType?*/,
191                          0, prop_len + 1,
192                          FALSE,
193                          &prop_type, &prop_format, &prop_len,
194                          &t))
195     {
196       *data = NULL;
197       return 0;
198     }
199   
200   *data = t;
201   
202   return prop_len;
203 }
204
205
206 void
207 gdk_selection_send_notify (guint32  requestor,
208                            GdkAtom  selection,
209                            GdkAtom  target,
210                            GdkAtom  property,
211                            guint32  time)
212 {
213   GdkEvent *event;
214   GdkWindow *event_window;
215   
216   event_window = gdk_fb_other_event_window (gdk_window_lookup (requestor), GDK_SELECTION_NOTIFY);
217   if (event_window)
218     {
219       event = gdk_event_make (event_window, GDK_SELECTION_NOTIFY, TRUE);
220       event->selection.selection = selection;
221       event->selection.target = target;
222       event->selection.property = property;
223       event->selection.requestor = (GdkNativeWindow) requestor;
224     }
225 }
226
227 gint
228 gdk_text_property_to_text_list (GdkAtom encoding, gint format, 
229                                 const guchar *text, gint length,
230                                 gchar ***list)
231 {
232   g_warning ("gdk_text_property_to_text_list() not implemented\n");
233   return 0;
234 }
235
236 void
237 gdk_free_text_list (gchar **list)
238 {
239   g_return_if_fail (list != NULL);
240   g_warning ("gdk_free_text_list() not implemented\n");
241 }
242
243 gint
244 gdk_string_to_compound_text (const gchar *str,
245                              GdkAtom *encoding, gint *format,
246                              guchar **ctext, gint *length)
247 {
248   g_warning ("gdk_string_to_compound_text() not implemented\n");
249   return 0;
250 }
251
252 void gdk_free_compound_text (guchar *ctext)
253 {
254   g_warning ("gdk_free_compound_text() not implemented\n");
255 }
256
257 /**
258  * gdk_utf8_to_string_target:
259  * @str: a UTF-8 string
260  * 
261  * Convert an UTF-8 string into the best possible representation
262  * as a STRING. The representation of characters not in STRING
263  * is not specified; it may be as pseudo-escape sequences
264  * \x{ABCD}, or it may be in some other form of approximation.
265  * 
266  * Return value: the newly allocated string, or %NULL if the
267  *               conversion failed. (It should not fail for
268  *               any properly formed UTF-8 string.)
269  **/
270 gchar *
271 gdk_utf8_to_string_target (const gchar *str)
272 {
273   g_warning ("gdk_utf8_to_string_target() not implemented\n");
274   return 0;
275 }
276
277 /**
278  * gdk_utf8_to_compound_text:
279  * @str:      a UTF-8 string
280  * @encoding: location to store resulting encoding
281  * @format:   location to store format of the result
282  * @ctext:    location to store the data of the result
283  * @length:   location to store the length of the data
284  *            stored in @ctext
285  * 
286  * Convert from UTF-8 to compound text. 
287  * 
288  * Return value: %TRUE if the conversion succeeded, otherwise
289  *               false.
290  **/
291 gboolean
292 gdk_utf8_to_compound_text (const gchar *str,
293                            GdkAtom     *encoding,
294                            gint        *format,
295                            guchar     **ctext,
296                            gint        *length)
297 {
298   g_warning ("gdk_utf8_to_compound_text() not implemented\n");
299   return 0;
300 }
301
302 static gint
303 make_list (const gchar  *text,
304            gint          length,
305            gboolean      latin1,
306            gchar      ***list)
307 {
308   GSList *strings = NULL;
309   gint n_strings = 0;
310   gint i;
311   const gchar *p = text;
312   const gchar *q;
313   GSList *tmp_list;
314   GError *error = NULL;
315
316   while (p < text + length)
317     {
318       gchar *str;
319       
320       q = p;
321       while (*q && q < text + length)
322         q++;
323
324       if (latin1)
325         {
326           str = g_convert (p, q - p,
327                            "UTF-8", "ISO-8859-1",
328                            NULL, NULL, &error);
329
330           if (!str)
331             {
332               g_warning ("Error converting selection from STRING: %s",
333                          error->message);
334               g_error_free (error);
335             }
336         }
337       else
338         str = g_strndup (p, q - p);
339
340       if (str)
341         {
342           strings = g_slist_prepend (strings, str);
343           n_strings++;
344         }
345
346       p = q + 1;
347     }
348
349   if (list)
350     *list = g_new (gchar *, n_strings + 1);
351
352   (*list)[n_strings] = NULL;
353   
354   i = n_strings;
355   tmp_list = strings;
356   while (tmp_list)
357     {
358       if (list)
359         (*list)[--i] = tmp_list->data;
360       else
361         g_free (tmp_list->data);
362
363       tmp_list = tmp_list->next;
364     }
365
366   g_slist_free (strings);
367
368   return n_strings;
369 }
370
371
372 /**
373  * gdk_text_property_to_utf8_list:
374  * @encoding: an atom representing the encoding of the text
375  * @format:   the format of the property
376  * @text:     the text to convert
377  * @length:   the length of @text, in bytes
378  * @list:     location to store the list of strings or %NULL. The
379  *            list should be freed with g_strfreev().
380  * 
381  * Convert a text property in the giving encoding to
382  * a list of UTF-8 strings. 
383  * 
384  * Return value: the number of strings in the resulting
385  *               list.
386  **/
387 gint 
388 gdk_text_property_to_utf8_list (GdkAtom        encoding,
389                                 gint           format,
390                                 const guchar  *text,
391                                 gint           length,
392                                 gchar       ***list)
393 {
394   g_return_val_if_fail (text != NULL, 0);
395   g_return_val_if_fail (length >= 0, 0);
396   
397   if (encoding == GDK_TARGET_STRING)
398     {
399       return make_list ((gchar *)text, length, TRUE, list);
400     }
401   else if (encoding == gdk_atom_intern ("UTF8_STRING", FALSE))
402     {
403       return make_list ((gchar *)text, length, FALSE, list);
404     }
405   else
406     {
407       gchar **local_list;
408       gint local_count;
409       gint i;
410       const gchar *charset = NULL;
411       gboolean need_conversion = !g_get_charset (&charset);
412       gint count = 0;
413       GError *error = NULL;
414       
415       /* Probably COMPOUND text, we fall back to Xlib routines
416        */
417       local_count = gdk_text_property_to_text_list (encoding,
418                                                     format, 
419                                                     text,
420                                                     length,
421                                                     &local_list);
422       if (list)
423         *list = g_new (gchar *, local_count + 1);
424       
425       for (i = 0; i < local_count; i++)
426         {
427           /* list contains stuff in our default encoding
428            */
429           if (need_conversion)
430             {
431               gchar *utf = g_convert (local_list[i], -1,
432                                       "UTF-8", charset,
433                                       NULL, NULL, &error);
434               if (utf)
435                 {
436                   if (list)
437                     (*list)[count++] = utf;
438                   else
439                     g_free (utf);
440                 }
441               else
442                 {
443                   g_warning ("Error converting to UTF-8 from '%s': %s",
444                              charset, error->message);
445                   g_error_free (error);
446                   error = NULL;
447                 }
448             }
449           else
450             {
451               if (list)
452                 (*list)[count++] = g_strdup (local_list[i]);
453             }
454         }
455       
456       gdk_free_text_list (local_list);
457       (*list)[count] = NULL;
458
459       return count;
460     }
461 }