| 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 | } |