File: | cdk/x11/cdkselection-x11.c |
Warning: | line 478, column 9 Access of the heap area at negative byte offset -8 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* CDK - 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 CTK+ Team and others 1997-2000. See the AUTHORS | ||||
20 | * file for a list of people on the CTK+ Team. See the ChangeLog | ||||
21 | * files for a list of changes. These files are distributed with | ||||
22 | * CTK+ at ftp://ftp.ctk.org/pub/ctk/. | ||||
23 | */ | ||||
24 | |||||
25 | #include "config.h" | ||||
26 | |||||
27 | #include "cdkselection.h" | ||||
28 | #include "cdkproperty.h" | ||||
29 | #include "cdkprivate.h" | ||||
30 | #include "cdkprivate-x11.h" | ||||
31 | #include "cdkdisplay-x11.h" | ||||
32 | |||||
33 | #include <X11/Xlib.h> | ||||
34 | #include <X11/Xatom.h> | ||||
35 | #include <string.h> | ||||
36 | |||||
37 | |||||
38 | typedef struct _OwnerInfo OwnerInfo; | ||||
39 | |||||
40 | struct _OwnerInfo | ||||
41 | { | ||||
42 | CdkAtom selection; | ||||
43 | CdkWindow *owner; | ||||
44 | gulong serial; | ||||
45 | }; | ||||
46 | |||||
47 | static GSList *owner_list; | ||||
48 | |||||
49 | /* When a window is destroyed we check if it is the owner | ||||
50 | * of any selections. This is somewhat inefficient, but | ||||
51 | * owner_list is typically short, and it is a low memory, | ||||
52 | * low code solution | ||||
53 | */ | ||||
54 | void | ||||
55 | _cdk_x11_selection_window_destroyed (CdkWindow *window) | ||||
56 | { | ||||
57 | GSList *tmp_list = owner_list; | ||||
58 | while (tmp_list) | ||||
59 | { | ||||
60 | OwnerInfo *info = tmp_list->data; | ||||
61 | tmp_list = tmp_list->next; | ||||
62 | |||||
63 | if (info->owner == window) | ||||
64 | { | ||||
65 | owner_list = g_slist_remove (owner_list, info); | ||||
66 | g_free (info); | ||||
67 | } | ||||
68 | } | ||||
69 | } | ||||
70 | |||||
71 | /* We only pass through those SelectionClear events that actually | ||||
72 | * reflect changes to the selection owner that we didn’t make ourself. | ||||
73 | */ | ||||
74 | gboolean | ||||
75 | _cdk_x11_selection_filter_clear_event (XSelectionClearEvent *event) | ||||
76 | { | ||||
77 | GSList *tmp_list = owner_list; | ||||
78 | CdkDisplay *display = cdk_x11_lookup_xdisplay (event->display); | ||||
79 | |||||
80 | while (tmp_list) | ||||
81 | { | ||||
82 | OwnerInfo *info = tmp_list->data; | ||||
83 | |||||
84 | if (cdk_window_get_display (info->owner) == display && | ||||
85 | info->selection == cdk_x11_xatom_to_atom_for_display (display, event->selection)) | ||||
86 | { | ||||
87 | if ((CDK_WINDOW_XID (info->owner)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((info->owner)), ((cdk_window_get_type ( )))))))->impl)), ((cdk_window_impl_x11_get_type ()))))))-> xid) == event->window && | ||||
88 | event->serial >= info->serial)) | ||||
89 | { | ||||
90 | owner_list = g_slist_remove (owner_list, info); | ||||
91 | g_free (info); | ||||
92 | return TRUE(!(0)); | ||||
93 | } | ||||
94 | else | ||||
95 | return FALSE(0); | ||||
96 | } | ||||
97 | tmp_list = tmp_list->next; | ||||
98 | } | ||||
99 | |||||
100 | return FALSE(0); | ||||
101 | } | ||||
102 | |||||
103 | gboolean | ||||
104 | _cdk_x11_display_set_selection_owner (CdkDisplay *display, | ||||
105 | CdkWindow *owner, | ||||
106 | CdkAtom selection, | ||||
107 | guint32 time, | ||||
108 | gboolean send_event G_GNUC_UNUSED__attribute__ ((__unused__))) | ||||
109 | { | ||||
110 | Display *xdisplay; | ||||
111 | Window xwindow; | ||||
112 | Atom xselection; | ||||
113 | GSList *tmp_list; | ||||
114 | OwnerInfo *info; | ||||
115 | |||||
116 | if (cdk_display_is_closed (display)) | ||||
117 | return FALSE(0); | ||||
118 | |||||
119 | if (owner) | ||||
120 | { | ||||
121 | if (CDK_WINDOW_DESTROYED (owner)(((CdkWindow *)(owner))->destroyed) || !CDK_WINDOW_IS_X11 (owner)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (((owner)->impl)); GType __t = ((cdk_window_impl_x11_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) | ||||
122 | return FALSE(0); | ||||
123 | |||||
124 | cdk_window_ensure_native (owner); | ||||
125 | xdisplay = CDK_WINDOW_XDISPLAY (owner)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((cdk_window_get_screen (owner)))), ((cdk_x11_screen_get_type ()))))))->xdisplay); | ||||
126 | xwindow = CDK_WINDOW_XID (owner)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((owner)), ((cdk_window_get_type ()))))))-> impl)), ((cdk_window_impl_x11_get_type ()))))))->xid); | ||||
127 | } | ||||
128 | else | ||||
129 | { | ||||
130 | xdisplay = CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay ); | ||||
131 | xwindow = None0L; | ||||
132 | } | ||||
133 | |||||
134 | xselection = cdk_x11_atom_to_xatom_for_display (display, selection); | ||||
135 | |||||
136 | tmp_list = owner_list; | ||||
137 | while (tmp_list) | ||||
138 | { | ||||
139 | info = tmp_list->data; | ||||
140 | if (info->selection == selection) | ||||
141 | { | ||||
142 | owner_list = g_slist_remove (owner_list, info); | ||||
143 | g_free (info); | ||||
144 | break; | ||||
145 | } | ||||
146 | tmp_list = tmp_list->next; | ||||
147 | } | ||||
148 | |||||
149 | if (owner) | ||||
150 | { | ||||
151 | info = g_new (OwnerInfo, 1)((OwnerInfo *) g_malloc_n ((1), sizeof (OwnerInfo))); | ||||
152 | info->owner = owner; | ||||
153 | info->serial = NextRequest (CDK_WINDOW_XDISPLAY (owner))(((_XPrivDisplay)((((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance*) (((cdk_window_get_screen (owner)))), ((cdk_x11_screen_get_type ()))))))->xdisplay)))->request + 1); | ||||
154 | info->selection = selection; | ||||
155 | |||||
156 | owner_list = g_slist_prepend (owner_list, info); | ||||
157 | } | ||||
158 | |||||
159 | XSetSelectionOwner (xdisplay, xselection, xwindow, time); | ||||
160 | |||||
161 | return (XGetSelectionOwner (xdisplay, xselection) == xwindow); | ||||
162 | } | ||||
163 | |||||
164 | CdkWindow * | ||||
165 | _cdk_x11_display_get_selection_owner (CdkDisplay *display, | ||||
166 | CdkAtom selection) | ||||
167 | { | ||||
168 | Window xwindow; | ||||
169 | |||||
170 | if (cdk_display_is_closed (display)) | ||||
171 | return NULL((void*)0); | ||||
172 | |||||
173 | xwindow = XGetSelectionOwner (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay ), | ||||
174 | cdk_x11_atom_to_xatom_for_display (display, | ||||
175 | selection)); | ||||
176 | if (xwindow == None0L) | ||||
177 | return NULL((void*)0); | ||||
178 | |||||
179 | return cdk_x11_window_lookup_for_display (display, xwindow); | ||||
180 | } | ||||
181 | |||||
182 | void | ||||
183 | _cdk_x11_display_convert_selection (CdkDisplay *display, | ||||
184 | CdkWindow *requestor, | ||||
185 | CdkAtom selection, | ||||
186 | CdkAtom target, | ||||
187 | guint32 time) | ||||
188 | { | ||||
189 | g_return_if_fail (selection != CDK_NONE)do { if ((selection != ((CdkAtom)((gpointer) (gulong) (0))))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) ( __func__)), "selection != CDK_NONE"); return; } } while (0); | ||||
190 | |||||
191 | if (CDK_WINDOW_DESTROYED (requestor)(((CdkWindow *)(requestor))->destroyed) || !CDK_WINDOW_IS_X11 (requestor)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (((requestor)->impl)); GType __t = ((cdk_window_impl_x11_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) | ||||
192 | return; | ||||
193 | |||||
194 | cdk_window_ensure_native (requestor); | ||||
195 | |||||
196 | XConvertSelection (CDK_WINDOW_XDISPLAY (requestor)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((cdk_window_get_screen (requestor)))), ((cdk_x11_screen_get_type ()))))))->xdisplay), | ||||
197 | cdk_x11_atom_to_xatom_for_display (display, selection), | ||||
198 | cdk_x11_atom_to_xatom_for_display (display, target), | ||||
199 | cdk_x11_get_xatom_by_name_for_display (display, "CDK_SELECTION"), | ||||
200 | CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((requestor)), ((cdk_window_get_type ()))) )))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid ), time); | ||||
201 | } | ||||
202 | |||||
203 | gint | ||||
204 | _cdk_x11_display_get_selection_property (CdkDisplay *display, | ||||
205 | CdkWindow *requestor, | ||||
206 | guchar **data, | ||||
207 | CdkAtom *ret_type, | ||||
208 | gint *ret_format) | ||||
209 | { | ||||
210 | gulong nitems; | ||||
211 | gulong nbytes; | ||||
212 | gulong length = 0; | ||||
213 | Atom prop_type; | ||||
214 | gint prop_format; | ||||
215 | guchar *t = NULL((void*)0); | ||||
216 | |||||
217 | if (CDK_WINDOW_DESTROYED (requestor)(((CdkWindow *)(requestor))->destroyed) || !CDK_WINDOW_IS_X11 (requestor)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (((requestor)->impl)); GType __t = ((cdk_window_impl_x11_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) | ||||
218 | goto err; | ||||
219 | |||||
220 | t = NULL((void*)0); | ||||
221 | |||||
222 | /* We can't delete the selection here, because it might be the INCR | ||||
223 | protocol, in which case the client has to make sure they'll be | ||||
224 | notified of PropertyChange events _before_ the property is deleted. | ||||
225 | Otherwise there's no guarantee we'll win the race ... */ | ||||
226 | if (XGetWindowProperty (CDK_WINDOW_XDISPLAY (requestor)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((cdk_window_get_screen (requestor)))), ((cdk_x11_screen_get_type ()))))))->xdisplay), | ||||
227 | CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((requestor)), ((cdk_window_get_type ()))) )))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid ), | ||||
228 | cdk_x11_get_xatom_by_name_for_display (display, "CDK_SELECTION"), | ||||
229 | 0, 0x1FFFFFFF /* MAXINT32 / 4 */, False0, | ||||
230 | AnyPropertyType0L, &prop_type, &prop_format, | ||||
231 | &nitems, &nbytes, &t) != Success0) | ||||
232 | goto err; | ||||
233 | |||||
234 | if (prop_type != None0L) | ||||
235 | { | ||||
236 | if (ret_type) | ||||
237 | *ret_type = cdk_x11_xatom_to_atom_for_display (display, prop_type); | ||||
238 | if (ret_format) | ||||
239 | *ret_format = prop_format; | ||||
240 | |||||
241 | if (prop_type == XA_ATOM((Atom) 4) || | ||||
242 | prop_type == cdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR")) | ||||
243 | { | ||||
244 | Atom* atoms = (Atom*) t; | ||||
245 | CdkAtom* atoms_dest; | ||||
246 | gint num_atom, i; | ||||
247 | |||||
248 | if (prop_format != 32) | ||||
249 | goto err; | ||||
250 | |||||
251 | num_atom = nitems; | ||||
252 | length = sizeof (CdkAtom) * num_atom + 1; | ||||
253 | |||||
254 | if (data) | ||||
255 | { | ||||
256 | *data = g_malloc (length); | ||||
257 | (*data)[length - 1] = '\0'; | ||||
258 | atoms_dest = (CdkAtom *)(*data); | ||||
259 | |||||
260 | for (i=0; i < num_atom; i++) | ||||
261 | atoms_dest[i] = cdk_x11_xatom_to_atom_for_display (display, atoms[i]); | ||||
262 | } | ||||
263 | } | ||||
264 | else | ||||
265 | { | ||||
266 | switch (prop_format) | ||||
267 | { | ||||
268 | case 8: | ||||
269 | length = nitems; | ||||
270 | break; | ||||
271 | case 16: | ||||
272 | length = sizeof(short) * nitems; | ||||
273 | break; | ||||
274 | case 32: | ||||
275 | length = sizeof(long) * nitems; | ||||
276 | break; | ||||
277 | default: | ||||
278 | g_assert_not_reached ()do { g_assertion_message_expr ("Cdk", "cdkselection-x11.c", 278 , ((const char*) (__func__)), ((void*)0)); } while (0); | ||||
279 | break; | ||||
280 | } | ||||
281 | |||||
282 | /* Add on an extra byte to handle null termination. X guarantees | ||||
283 | that t will be 1 longer than nitems and null terminated */ | ||||
284 | length += 1; | ||||
285 | |||||
286 | if (data) | ||||
287 | *data = g_memdup2 (t, length); | ||||
288 | } | ||||
289 | |||||
290 | if (t) | ||||
291 | XFree (t); | ||||
292 | |||||
293 | return length - 1; | ||||
294 | } | ||||
295 | |||||
296 | err: | ||||
297 | if (ret_type) | ||||
298 | *ret_type = CDK_NONE((CdkAtom)((gpointer) (gulong) (0))); | ||||
299 | if (ret_format) | ||||
300 | *ret_format = 0; | ||||
301 | if (data) | ||||
302 | *data = NULL((void*)0); | ||||
303 | |||||
304 | return 0; | ||||
305 | } | ||||
306 | |||||
307 | void | ||||
308 | _cdk_x11_display_send_selection_notify (CdkDisplay *display, | ||||
309 | CdkWindow *requestor, | ||||
310 | CdkAtom selection, | ||||
311 | CdkAtom target, | ||||
312 | CdkAtom property, | ||||
313 | guint32 time) | ||||
314 | { | ||||
315 | XSelectionEvent xevent; | ||||
316 | |||||
317 | xevent.type = SelectionNotify31; | ||||
318 | xevent.serial = 0; | ||||
319 | xevent.send_event = True1; | ||||
320 | xevent.requestor = CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((requestor)), ((cdk_window_get_type ()))) )))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid ); | ||||
321 | xevent.selection = cdk_x11_atom_to_xatom_for_display (display, selection); | ||||
322 | xevent.target = cdk_x11_atom_to_xatom_for_display (display, target); | ||||
323 | if (property == CDK_NONE((CdkAtom)((gpointer) (gulong) (0)))) | ||||
324 | xevent.property = None0L; | ||||
325 | else | ||||
326 | xevent.property = cdk_x11_atom_to_xatom_for_display (display, property); | ||||
327 | xevent.time = time; | ||||
328 | |||||
329 | _cdk_x11_display_send_xevent (display, xevent.requestor, False0, NoEventMask0L, (XEvent*) & xevent); | ||||
330 | } | ||||
331 | |||||
332 | /** | ||||
333 | * cdk_x11_display_text_property_to_text_list: | ||||
334 | * @display: (type CdkX11Display): The #CdkDisplay where the encoding is defined | ||||
335 | * @encoding: an atom representing the encoding. The most | ||||
336 | * common values for this are STRING, or COMPOUND_TEXT. | ||||
337 | * This is value used as the type for the property | ||||
338 | * @format: the format of the property | ||||
339 | * @text: The text data | ||||
340 | * @length: The number of items to transform | ||||
341 | * @list: location to store an array of strings in | ||||
342 | * the encoding of the current locale. This array should be | ||||
343 | * freed using cdk_free_text_list(). | ||||
344 | * | ||||
345 | * Convert a text string from the encoding as it is stored | ||||
346 | * in a property into an array of strings in the encoding of | ||||
347 | * the current locale. (The elements of the array represent the | ||||
348 | * nul-separated elements of the original text string.) | ||||
349 | * | ||||
350 | * Returns: the number of strings stored in list, or 0, | ||||
351 | * if the conversion failed | ||||
352 | * | ||||
353 | * Since: 2.24 | ||||
354 | */ | ||||
355 | gint | ||||
356 | cdk_x11_display_text_property_to_text_list (CdkDisplay *display, | ||||
357 | CdkAtom encoding, | ||||
358 | gint format, | ||||
359 | const guchar *text, | ||||
360 | gint length, | ||||
361 | gchar ***list) | ||||
362 | { | ||||
363 | XTextProperty property; | ||||
364 | gint count = 0; | ||||
365 | gint res; | ||||
366 | gchar **local_list; | ||||
367 | g_return_val_if_fail (CDK_IS_DISPLAY (display), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((display)); GType __t = ((cdk_display_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__ )), "CDK_IS_DISPLAY (display)"); return (0); } } while (0); | ||||
368 | |||||
369 | if (list) | ||||
370 | *list = NULL((void*)0); | ||||
371 | |||||
372 | if (cdk_display_is_closed (display)) | ||||
373 | return 0; | ||||
374 | |||||
375 | property.value = (guchar *)text; | ||||
376 | property.encoding = cdk_x11_atom_to_xatom_for_display (display, encoding); | ||||
377 | property.format = format; | ||||
378 | property.nitems = length; | ||||
379 | res = XmbTextPropertyToTextList (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay ), &property, | ||||
380 | &local_list, &count); | ||||
381 | if (res == XNoMemory-1 || res == XLocaleNotSupported-2 || res == XConverterNotFound-3) | ||||
382 | return 0; | ||||
383 | else | ||||
384 | { | ||||
385 | if (list) | ||||
386 | *list = local_list; | ||||
387 | else | ||||
388 | XFreeStringList (local_list); | ||||
389 | |||||
390 | return count; | ||||
391 | } | ||||
392 | } | ||||
393 | |||||
394 | /** | ||||
395 | * cdk_x11_free_text_list: | ||||
396 | * @list: the value stored in the @list parameter by | ||||
397 | * a call to cdk_x11_display_text_property_to_text_list(). | ||||
398 | * | ||||
399 | * Frees the array of strings created by | ||||
400 | * cdk_x11_display_text_property_to_text_list(). | ||||
401 | * | ||||
402 | * Since: 2.24 | ||||
403 | */ | ||||
404 | void | ||||
405 | cdk_x11_free_text_list (gchar **list) | ||||
406 | { | ||||
407 | g_return_if_fail (list != NULL)do { if ((list != ((void*)0))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__)), "list != NULL"); return; } } while (0); | ||||
408 | |||||
409 | XFreeStringList (list); | ||||
410 | } | ||||
411 | |||||
412 | static gint | ||||
413 | make_list (const gchar *text, | ||||
414 | gint length, | ||||
415 | gboolean latin1, | ||||
416 | gchar ***list) | ||||
417 | { | ||||
418 | GSList *strings = NULL((void*)0); | ||||
419 | gint n_strings = 0; | ||||
420 | gint i; | ||||
421 | const gchar *p = text; | ||||
422 | const gchar *q; | ||||
423 | GSList *tmp_list; | ||||
424 | GError *error = NULL((void*)0); | ||||
425 | |||||
426 | while (p < text + length) | ||||
427 | { | ||||
428 | gchar *str; | ||||
429 | |||||
430 | q = p; | ||||
431 | while (*q && q < text + length) | ||||
432 | q++; | ||||
433 | |||||
434 | if (latin1
| ||||
435 | { | ||||
436 | str = g_convert (p, q - p, | ||||
437 | "UTF-8", "ISO-8859-1", | ||||
438 | NULL((void*)0), NULL((void*)0), &error); | ||||
439 | |||||
440 | if (!str) | ||||
441 | { | ||||
442 | g_warning ("Error converting selection from STRING: %s", | ||||
443 | error->message); | ||||
444 | g_error_free (error); | ||||
445 | } | ||||
446 | } | ||||
447 | else | ||||
448 | { | ||||
449 | str = g_strndup (p, q - p); | ||||
450 | if (!g_utf8_validate (str, -1, NULL((void*)0))) | ||||
451 | { | ||||
452 | g_warning ("Error converting selection from UTF8_STRING"); | ||||
453 | g_free (str); | ||||
454 | str = NULL((void*)0); | ||||
455 | } | ||||
456 | } | ||||
457 | |||||
458 | if (str
| ||||
459 | { | ||||
460 | strings = g_slist_prepend (strings, str); | ||||
461 | n_strings++; | ||||
462 | } | ||||
463 | |||||
464 | p = q + 1; | ||||
465 | } | ||||
466 | |||||
467 | if (list) | ||||
468 | { | ||||
469 | *list = g_new (gchar *, n_strings + 1)((gchar * *) g_malloc_n ((n_strings + 1), sizeof (gchar *))); | ||||
470 | (*list)[n_strings] = NULL((void*)0); | ||||
471 | } | ||||
472 | |||||
473 | i = n_strings; | ||||
474 | tmp_list = strings; | ||||
475 | while (tmp_list) | ||||
476 | { | ||||
477 | if (list
| ||||
478 | (*list)[--i] = tmp_list->data; | ||||
| |||||
479 | else | ||||
480 | g_free (tmp_list->data); | ||||
481 | |||||
482 | tmp_list = tmp_list->next; | ||||
483 | } | ||||
484 | |||||
485 | g_slist_free (strings); | ||||
486 | |||||
487 | return n_strings; | ||||
488 | } | ||||
489 | |||||
490 | gint | ||||
491 | _cdk_x11_display_text_property_to_utf8_list (CdkDisplay *display, | ||||
492 | CdkAtom encoding, | ||||
493 | gint format, | ||||
494 | const guchar *text, | ||||
495 | gint length, | ||||
496 | gchar ***list) | ||||
497 | { | ||||
498 | if (encoding == CDK_TARGET_STRING((CdkAtom)((gpointer) (gulong) (31)))) | ||||
| |||||
499 | { | ||||
500 | return make_list ((gchar *)text, length, TRUE(!(0)), list); | ||||
501 | } | ||||
502 | else if (encoding == cdk_atom_intern_static_string ("UTF8_STRING")) | ||||
503 | { | ||||
504 | return make_list ((gchar *)text, length, FALSE(0), list); | ||||
505 | } | ||||
506 | else | ||||
507 | { | ||||
508 | gchar **local_list; | ||||
509 | gint local_count; | ||||
510 | gint i; | ||||
511 | const gchar *charset = NULL((void*)0); | ||||
512 | gboolean need_conversion = !g_get_charset (&charset); | ||||
513 | gint count = 0; | ||||
514 | GError *error = NULL((void*)0); | ||||
515 | |||||
516 | /* Probably COMPOUND text, we fall back to Xlib routines | ||||
517 | */ | ||||
518 | local_count = cdk_x11_display_text_property_to_text_list (display, | ||||
519 | encoding, | ||||
520 | format, | ||||
521 | text, | ||||
522 | length, | ||||
523 | &local_list); | ||||
524 | if (list) | ||||
525 | *list = g_new (gchar *, local_count + 1)((gchar * *) g_malloc_n ((local_count + 1), sizeof (gchar *)) ); | ||||
526 | |||||
527 | for (i=0; i<local_count; i++) | ||||
528 | { | ||||
529 | /* list contains stuff in our default encoding | ||||
530 | */ | ||||
531 | if (need_conversion) | ||||
532 | { | ||||
533 | gchar *utf = g_convert (local_list[i], -1, | ||||
534 | "UTF-8", charset, | ||||
535 | NULL((void*)0), NULL((void*)0), &error); | ||||
536 | if (utf) | ||||
537 | { | ||||
538 | if (list) | ||||
539 | (*list)[count++] = utf; | ||||
540 | else | ||||
541 | g_free (utf); | ||||
542 | } | ||||
543 | else | ||||
544 | { | ||||
545 | g_warning ("Error converting to UTF-8 from '%s': %s", | ||||
546 | charset, error->message); | ||||
547 | g_error_free (error); | ||||
548 | error = NULL((void*)0); | ||||
549 | } | ||||
550 | } | ||||
551 | else | ||||
552 | { | ||||
553 | if (list) | ||||
554 | { | ||||
555 | if (g_utf8_validate (local_list[i], -1, NULL((void*)0))) | ||||
556 | (*list)[count++] = g_strdup (local_list[i])g_strdup_inline (local_list[i]); | ||||
557 | else | ||||
558 | g_warning ("Error converting selection"); | ||||
559 | } | ||||
560 | } | ||||
561 | } | ||||
562 | |||||
563 | if (local_count) | ||||
564 | cdk_x11_free_text_list (local_list); | ||||
565 | |||||
566 | if (list) | ||||
567 | (*list)[count] = NULL((void*)0); | ||||
568 | |||||
569 | return count; | ||||
570 | } | ||||
571 | } | ||||
572 | |||||
573 | /** | ||||
574 | * cdk_x11_display_string_to_compound_text: | ||||
575 | * @display: (type CdkX11Display): the #CdkDisplay where the encoding is defined | ||||
576 | * @str: a nul-terminated string | ||||
577 | * @encoding: (out) (transfer none): location to store the encoding atom | ||||
578 | * (to be used as the type for the property) | ||||
579 | * @format: (out): location to store the format of the property | ||||
580 | * @ctext: (out) (array length=length): location to store newly | ||||
581 | * allocated data for the property | ||||
582 | * @length: the length of @ctext, in bytes | ||||
583 | * | ||||
584 | * Convert a string from the encoding of the current | ||||
585 | * locale into a form suitable for storing in a window property. | ||||
586 | * | ||||
587 | * Returns: 0 upon success, non-zero upon failure | ||||
588 | * | ||||
589 | * Since: 2.24 | ||||
590 | */ | ||||
591 | gint | ||||
592 | cdk_x11_display_string_to_compound_text (CdkDisplay *display, | ||||
593 | const gchar *str, | ||||
594 | CdkAtom *encoding, | ||||
595 | gint *format, | ||||
596 | guchar **ctext, | ||||
597 | gint *length) | ||||
598 | { | ||||
599 | gint res; | ||||
600 | XTextProperty property; | ||||
601 | |||||
602 | g_return_val_if_fail (CDK_IS_DISPLAY (display), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((display)); GType __t = ((cdk_display_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__ )), "CDK_IS_DISPLAY (display)"); return (0); } } while (0); | ||||
603 | |||||
604 | if (cdk_display_is_closed (display)) | ||||
605 | res = XLocaleNotSupported-2; | ||||
606 | else | ||||
607 | res = XmbTextListToTextProperty (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay ), | ||||
608 | (char **)&str, 1, XCompoundTextStyle, | ||||
609 | &property); | ||||
610 | if (res != Success0) | ||||
611 | { | ||||
612 | property.encoding = None0L; | ||||
613 | property.format = None0L; | ||||
614 | property.value = NULL((void*)0); | ||||
615 | property.nitems = 0; | ||||
616 | } | ||||
617 | |||||
618 | if (encoding) | ||||
619 | *encoding = cdk_x11_xatom_to_atom_for_display (display, property.encoding); | ||||
620 | if (format) | ||||
621 | *format = property.format; | ||||
622 | if (ctext) | ||||
623 | *ctext = property.value; | ||||
624 | if (length) | ||||
625 | *length = property.nitems; | ||||
626 | |||||
627 | return res; | ||||
628 | } | ||||
629 | |||||
630 | /* The specifications for COMPOUND_TEXT and STRING specify that C0 and | ||||
631 | * C1 are not allowed except for \n and \t, however the X conversions | ||||
632 | * routines for COMPOUND_TEXT only enforce this in one direction, | ||||
633 | * causing cut-and-paste of \r and \r\n separated text to fail. | ||||
634 | * This routine strips out all non-allowed C0 and C1 characters | ||||
635 | * from the input string and also canonicalizes \r, and \r\n to \n | ||||
636 | */ | ||||
637 | static gchar * | ||||
638 | sanitize_utf8 (const gchar *src, | ||||
639 | gboolean return_latin1) | ||||
640 | { | ||||
641 | gint len = strlen (src); | ||||
642 | GString *result = g_string_sized_new (len); | ||||
643 | const gchar *p = src; | ||||
644 | |||||
645 | while (*p) | ||||
646 | { | ||||
647 | if (*p == '\r') | ||||
648 | { | ||||
649 | p++; | ||||
650 | if (*p == '\n') | ||||
651 | p++; | ||||
652 | |||||
653 | g_string_append_c (result, '\n')g_string_append_c_inline (result, '\n'); | ||||
654 | } | ||||
655 | else | ||||
656 | { | ||||
657 | gunichar ch = g_utf8_get_char (p); | ||||
658 | |||||
659 | if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0))) | ||||
660 | { | ||||
661 | if (return_latin1) | ||||
662 | { | ||||
663 | if (ch <= 0xff) | ||||
664 | g_string_append_c (result, ch)g_string_append_c_inline (result, ch); | ||||
665 | else | ||||
666 | g_string_append_printf (result, | ||||
667 | ch < 0x10000 ? "\\u%04x" : "\\U%08x", | ||||
668 | ch); | ||||
669 | } | ||||
670 | else | ||||
671 | { | ||||
672 | char buf[7]; | ||||
673 | gint buflen; | ||||
674 | |||||
675 | buflen = g_unichar_to_utf8 (ch, buf); | ||||
676 | g_string_append_len (result, buf, buflen)g_string_append_len_inline (result, buf, buflen); | ||||
677 | } | ||||
678 | } | ||||
679 | |||||
680 | p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]); | ||||
681 | } | ||||
682 | } | ||||
683 | |||||
684 | return g_string_free (result, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((result ), ((0))) : g_string_free_and_steal (result)) : (g_string_free ) ((result), ((0)))); | ||||
685 | } | ||||
686 | |||||
687 | gchar * | ||||
688 | _cdk_x11_display_utf8_to_string_target (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)), | ||||
689 | const gchar *str) | ||||
690 | { | ||||
691 | return sanitize_utf8 (str, TRUE(!(0))); | ||||
692 | } | ||||
693 | |||||
694 | /** | ||||
695 | * cdk_x11_display_utf8_to_compound_text: | ||||
696 | * @display: (type CdkX11Display): a #CdkDisplay | ||||
697 | * @str: a UTF-8 string | ||||
698 | * @encoding: (out): location to store resulting encoding | ||||
699 | * @format: (out): location to store format of the result | ||||
700 | * @ctext: (out) (array length=length): location to store the data of the result | ||||
701 | * @length: location to store the length of the data | ||||
702 | * stored in @ctext | ||||
703 | * | ||||
704 | * Converts from UTF-8 to compound text. | ||||
705 | * | ||||
706 | * Returns: %TRUE if the conversion succeeded, | ||||
707 | * otherwise %FALSE | ||||
708 | * | ||||
709 | * Since: 2.24 | ||||
710 | */ | ||||
711 | gboolean | ||||
712 | cdk_x11_display_utf8_to_compound_text (CdkDisplay *display, | ||||
713 | const gchar *str, | ||||
714 | CdkAtom *encoding, | ||||
715 | gint *format, | ||||
716 | guchar **ctext, | ||||
717 | gint *length) | ||||
718 | { | ||||
719 | gboolean need_conversion; | ||||
720 | const gchar *charset; | ||||
721 | gchar *locale_str, *tmp_str; | ||||
722 | GError *error = NULL((void*)0); | ||||
723 | gboolean result; | ||||
724 | |||||
725 | g_return_val_if_fail (str != NULL, FALSE)do { if ((str != ((void*)0))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__)), "str != NULL"); return ( (0)); } } while (0); | ||||
726 | g_return_val_if_fail (CDK_IS_DISPLAY (display), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((display)); GType __t = ((cdk_display_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__ )), "CDK_IS_DISPLAY (display)"); return ((0)); } } while (0); | ||||
727 | |||||
728 | need_conversion = !g_get_charset (&charset); | ||||
729 | |||||
730 | tmp_str = sanitize_utf8 (str, FALSE(0)); | ||||
731 | |||||
732 | if (need_conversion) | ||||
733 | { | ||||
734 | locale_str = g_convert (tmp_str, -1, | ||||
735 | charset, "UTF-8", | ||||
736 | NULL((void*)0), NULL((void*)0), &error); | ||||
737 | g_free (tmp_str); | ||||
738 | |||||
739 | if (!locale_str) | ||||
740 | { | ||||
741 | if (!g_error_matches (error, G_CONVERT_ERRORg_convert_error_quark(), G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) | ||||
742 | { | ||||
743 | g_warning ("Error converting from UTF-8 to '%s': %s", | ||||
744 | charset, error->message); | ||||
745 | } | ||||
746 | g_error_free (error); | ||||
747 | |||||
748 | if (encoding) | ||||
749 | *encoding = None0L; | ||||
750 | if (format) | ||||
751 | *format = None0L; | ||||
752 | if (ctext) | ||||
753 | *ctext = NULL((void*)0); | ||||
754 | if (length) | ||||
755 | *length = 0; | ||||
756 | |||||
757 | return FALSE(0); | ||||
758 | } | ||||
759 | } | ||||
760 | else | ||||
761 | locale_str = tmp_str; | ||||
762 | |||||
763 | result = cdk_x11_display_string_to_compound_text (display, locale_str, | ||||
764 | encoding, format, | ||||
765 | ctext, length); | ||||
766 | result = (result == Success0? TRUE(!(0)) : FALSE(0)); | ||||
767 | |||||
768 | g_free (locale_str); | ||||
769 | |||||
770 | return result; | ||||
771 | } | ||||
772 | |||||
773 | /** | ||||
774 | * cdk_x11_free_compound_text: | ||||
775 | * @ctext: The pointer stored in @ctext from a call to | ||||
776 | * cdk_x11_display_string_to_compound_text(). | ||||
777 | * | ||||
778 | * Frees the data returned from cdk_x11_display_string_to_compound_text(). | ||||
779 | * | ||||
780 | * Since: 2.24 | ||||
781 | */ | ||||
782 | void | ||||
783 | cdk_x11_free_compound_text (guchar *ctext) | ||||
784 | { | ||||
785 | if (ctext) | ||||
786 | XFree (ctext); | ||||
787 | } |