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, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gdkprivate-x11.h"
28#include "gdkdisplay-x11.h"
29
30#include <X11/Xlib.h>
31#include <X11/Xatom.h>
32#include <string.h>
33
34
35/**
36 * gdk_x11_display_text_property_to_text_list:
37 * @display: (type GdkX11Display): The `GdkDisplay` where the encoding is defined
38 * @encoding: a string representing the encoding. The most
39 * common values for this are "STRING", or "COMPOUND_TEXT".
40 * This is value used as the type for the property
41 * @format: the format of the property
42 * @text: The text data
43 * @length: The number of items to transform
44 * @list: location to store an array of strings in
45 * the encoding of the current locale. This array should be
46 * freed using gdk_x11_free_text_list().
47 *
48 * Convert a text string from the encoding as it is stored
49 * in a property into an array of strings in the encoding of
50 * the current locale. (The elements of the array represent the
51 * nul-separated elements of the original text string.)
52 *
53 * Returns: the number of strings stored in list, or 0,
54 * if the conversion failed
55 */
56int
57gdk_x11_display_text_property_to_text_list (GdkDisplay *display,
58 const char *encoding,
59 int format,
60 const guchar *text,
61 int length,
62 char ***list)
63{
64 XTextProperty property;
65 int count = 0;
66 int res;
67 char **local_list;
68 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
69
70 if (list)
71 *list = NULL;
72
73 if (gdk_display_is_closed (display))
74 return 0;
75
76 property.value = (guchar *)text;
77 property.encoding = gdk_x11_get_xatom_by_name_for_display (display, atom_name: encoding);
78 property.format = format;
79 property.nitems = length;
80 res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), text_prop: &property,
81 list_return: &local_list, count_return: &count);
82 if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
83 return 0;
84 else
85 {
86 if (list)
87 *list = local_list;
88 else
89 XFreeStringList (local_list);
90
91 return count;
92 }
93}
94
95/**
96 * gdk_x11_free_text_list:
97 * @list: the value stored in the @list parameter by
98 * a call to gdk_x11_display_text_property_to_text_list().
99 *
100 * Frees the array of strings created by
101 * gdk_x11_display_text_property_to_text_list().
102 */
103void
104gdk_x11_free_text_list (char **list)
105{
106 g_return_if_fail (list != NULL);
107
108 XFreeStringList (list);
109}
110
111static int
112make_list (const char *text,
113 int length,
114 gboolean latin1,
115 char ***list)
116{
117 GSList *strings = NULL;
118 int n_strings = 0;
119 int i;
120 const char *p = text;
121 const char *q;
122 GSList *tmp_list;
123 GError *error = NULL;
124
125 while (p < text + length)
126 {
127 char *str;
128
129 q = p;
130 while (*q && q < text + length)
131 q++;
132
133 if (latin1)
134 {
135 str = g_convert (str: p, len: q - p,
136 to_codeset: "UTF-8", from_codeset: "ISO-8859-1",
137 NULL, NULL, error: &error);
138
139 if (!str)
140 {
141 g_warning ("Error converting selection from STRING: %s",
142 error->message);
143 g_error_free (error);
144 }
145 }
146 else
147 {
148 str = g_strndup (str: p, n: q - p);
149 if (!g_utf8_validate (str, max_len: -1, NULL))
150 {
151 g_warning ("Error converting selection from UTF8_STRING");
152 g_free (mem: str);
153 str = NULL;
154 }
155 }
156
157 if (str)
158 {
159 strings = g_slist_prepend (list: strings, data: str);
160 n_strings++;
161 }
162
163 p = q + 1;
164 }
165
166 if (list)
167 {
168 *list = g_new (char *, n_strings + 1);
169 (*list)[n_strings] = NULL;
170 }
171
172 i = n_strings;
173 tmp_list = strings;
174 while (tmp_list)
175 {
176 if (list)
177 (*list)[--i] = tmp_list->data;
178 else
179 g_free (mem: tmp_list->data);
180
181 tmp_list = tmp_list->next;
182 }
183
184 g_slist_free (list: strings);
185
186 return n_strings;
187}
188
189int
190_gdk_x11_display_text_property_to_utf8_list (GdkDisplay *display,
191 const char *encoding,
192 int format,
193 const guchar *text,
194 int length,
195 char ***list)
196{
197 if (g_str_equal (v1: encoding, v2: "STRING"))
198 {
199 return make_list (text: (char *)text, length, TRUE, list);
200 }
201 else if (g_str_equal (v1: encoding, v2: "UTF8_STRING"))
202 {
203 return make_list (text: (char *)text, length, FALSE, list);
204 }
205 else
206 {
207 char **local_list;
208 int local_count;
209 int i;
210 const char *charset = NULL;
211 gboolean need_conversion = !g_get_charset (charset: &charset);
212 int count = 0;
213 GError *error = NULL;
214
215 /* Probably COMPOUND text, we fall back to Xlib routines
216 */
217 local_count = gdk_x11_display_text_property_to_text_list (display,
218 encoding,
219 format,
220 text,
221 length,
222 list: &local_list);
223 if (list)
224 *list = g_new (char *, local_count + 1);
225
226 for (i=0; i<local_count; i++)
227 {
228 /* list contains stuff in our default encoding
229 */
230 if (need_conversion)
231 {
232 char *utf = g_convert (str: local_list[i], len: -1,
233 to_codeset: "UTF-8", from_codeset: charset,
234 NULL, NULL, error: &error);
235 if (utf)
236 {
237 if (list)
238 (*list)[count++] = utf;
239 else
240 g_free (mem: utf);
241 }
242 else
243 {
244 g_warning ("Error converting to UTF-8 from '%s': %s",
245 charset, error->message);
246 g_error_free (error);
247 error = NULL;
248 }
249 }
250 else
251 {
252 if (list)
253 {
254 if (g_utf8_validate (str: local_list[i], max_len: -1, NULL))
255 (*list)[count++] = g_strdup (str: local_list[i]);
256 else
257 g_warning ("Error converting selection");
258 }
259 }
260 }
261
262 if (local_count)
263 gdk_x11_free_text_list (list: local_list);
264
265 if (list)
266 (*list)[count] = NULL;
267
268 return count;
269 }
270}
271
272/**
273 * gdk_x11_display_string_to_compound_text:
274 * @display: (type GdkX11Display): the `GdkDisplay` where the encoding is defined
275 * @str: a nul-terminated string
276 * @encoding: (out) (transfer none): location to store the encoding
277 * (to be used as the type for the property)
278 * @format: (out): location to store the format of the property
279 * @ctext: (out) (array length=length): location to store newly
280 * allocated data for the property
281 * @length: the length of @ctext, in bytes
282 *
283 * Convert a string from the encoding of the current
284 * locale into a form suitable for storing in a window property.
285 *
286 * Returns: 0 upon success, non-zero upon failure
287 */
288int
289gdk_x11_display_string_to_compound_text (GdkDisplay *display,
290 const char *str,
291 const char **encoding,
292 int *format,
293 guchar **ctext,
294 int *length)
295{
296 int res;
297 XTextProperty property;
298
299 g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
300
301 if (gdk_display_is_closed (display))
302 res = XLocaleNotSupported;
303 else
304 res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display),
305 list: (char **)&str, count: 1, style: XCompoundTextStyle,
306 text_prop_return: &property);
307 if (res != Success)
308 {
309 property.encoding = None;
310 property.format = None;
311 property.value = NULL;
312 property.nitems = 0;
313 }
314
315 if (encoding)
316 *encoding = gdk_x11_get_xatom_name_for_display (display, xatom: property.encoding);
317 if (format)
318 *format = property.format;
319 if (ctext)
320 *ctext = property.value;
321 if (length)
322 *length = property.nitems;
323
324 return res;
325}
326
327/**
328 * gdk_x11_display_utf8_to_compound_text:
329 * @display: (type GdkX11Display): a `GdkDisplay`
330 * @str: a UTF-8 string
331 * @encoding: (out) (transfer none): location to store resulting encoding
332 * @format: (out): location to store format of the result
333 * @ctext: (out) (array length=length): location to store the data of the result
334 * @length: location to store the length of the data stored in @ctext
335 *
336 * Converts from UTF-8 to compound text.
337 *
338 * Returns: %TRUE if the conversion succeeded, otherwise %FALSE
339 */
340gboolean
341gdk_x11_display_utf8_to_compound_text (GdkDisplay *display,
342 const char *str,
343 const char **encoding,
344 int *format,
345 guchar **ctext,
346 int *length)
347{
348 gboolean need_conversion;
349 const char *charset;
350 char *locale_str, *tmp_str;
351 GError *error = NULL;
352 gboolean result;
353
354 g_return_val_if_fail (str != NULL, FALSE);
355 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
356
357 need_conversion = !g_get_charset (charset: &charset);
358
359 tmp_str = gdk_x11_utf8_to_string_target (utf8_str: str, FALSE);
360
361 if (need_conversion)
362 {
363 locale_str = g_convert (str: tmp_str, len: -1,
364 to_codeset: charset, from_codeset: "UTF-8",
365 NULL, NULL, error: &error);
366 g_free (mem: tmp_str);
367
368 if (!locale_str)
369 {
370 if (!g_error_matches (error, G_CONVERT_ERROR, code: G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
371 {
372 g_warning ("Error converting from UTF-8 to '%s': %s",
373 charset, error->message);
374 }
375 g_error_free (error);
376
377 if (encoding)
378 *encoding = NULL;
379 if (format)
380 *format = None;
381 if (ctext)
382 *ctext = NULL;
383 if (length)
384 *length = 0;
385
386 return FALSE;
387 }
388 }
389 else
390 locale_str = tmp_str;
391
392 result = gdk_x11_display_string_to_compound_text (display, str: locale_str,
393 encoding, format,
394 ctext, length);
395 result = (result == Success? TRUE : FALSE);
396
397 g_free (mem: locale_str);
398
399 return result;
400}
401
402/**
403 * gdk_x11_free_compound_text:
404 * @ctext: The pointer stored in @ctext from a call to
405 * gdk_x11_display_string_to_compound_text().
406 *
407 * Frees the data returned from gdk_x11_display_string_to_compound_text().
408 */
409void
410gdk_x11_free_compound_text (guchar *ctext)
411{
412 if (ctext)
413 XFree (ctext);
414}
415

source code of gtk/gdk/x11/gdkselection-x11.c