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