Deal with property encoding functions

Move everything dealing with compound text to be X11 specific
Only gdk_text_property_to_utf8_list and gdk_utf8_to_string_target
are kept across backends, so add vfuncs for these.

Also, remove the non-multihead-safe variants of all these.
This commit is contained in:
Matthias Clasen
2010-12-16 23:44:50 -05:00
parent 61104d58ea
commit 572bb20011
10 changed files with 454 additions and 541 deletions

View File

@ -197,8 +197,6 @@ gdk_event_type_get_type G_GNUC_CONST
gdk_extension_mode_get_type G_GNUC_CONST gdk_extension_mode_get_type G_GNUC_CONST
gdk_filter_return_get_type G_GNUC_CONST gdk_filter_return_get_type G_GNUC_CONST
gdk_flush gdk_flush
gdk_free_compound_text
gdk_free_text_list
gdk_get_default_root_window gdk_get_default_root_window
gdk_get_display gdk_get_display
gdk_get_display_arg_name gdk_get_display_arg_name
@ -323,15 +321,10 @@ gdk_set_show_events
gdk_setting_action_get_type G_GNUC_CONST gdk_setting_action_get_type G_GNUC_CONST
gdk_setting_get gdk_setting_get
gdk_status_get_type G_GNUC_CONST gdk_status_get_type G_GNUC_CONST
gdk_string_to_compound_text
gdk_string_to_compound_text_for_display
gdk_synthesize_window_state gdk_synthesize_window_state
gdk_test_render_sync gdk_test_render_sync
gdk_test_simulate_button gdk_test_simulate_button
gdk_test_simulate_key gdk_test_simulate_key
gdk_text_property_to_text_list
gdk_text_property_to_text_list_for_display
gdk_text_property_to_utf8_list
gdk_text_property_to_utf8_list_for_display gdk_text_property_to_utf8_list_for_display
gdk_threads_add_idle gdk_threads_add_idle
gdk_threads_add_idle_full gdk_threads_add_idle_full
@ -344,8 +337,6 @@ gdk_threads_init
gdk_threads_leave gdk_threads_leave
gdk_threads_set_lock_functions gdk_threads_set_lock_functions
gdk_unicode_to_keyval G_GNUC_CONST gdk_unicode_to_keyval G_GNUC_CONST
gdk_utf8_to_compound_text
gdk_utf8_to_compound_text_for_display
gdk_utf8_to_string_target gdk_utf8_to_string_target
gdk_visibility_state_get_type G_GNUC_CONST gdk_visibility_state_get_type G_GNUC_CONST
gdk_visual_get_best gdk_visual_get_best
@ -539,7 +530,12 @@ gdk_x11_display_get_xdisplay
gdk_x11_display_grab gdk_x11_display_grab
gdk_x11_display_set_cursor_theme gdk_x11_display_set_cursor_theme
gdk_x11_display_set_startup_notification_id gdk_x11_display_set_startup_notification_id
gdk_x11_display_string_to_compound_text
gdk_x11_display_text_property_to_text_list
gdk_x11_display_ungrab gdk_x11_display_ungrab
gdk_x11_display_utf8_to_compound_text
gdk_x11_free_compound_text
gdk_x11_free_text_list
gdk_x11_get_default_root_xwindow gdk_x11_get_default_root_xwindow
gdk_x11_get_default_screen gdk_x11_get_default_screen
gdk_x11_get_default_xdisplay gdk_x11_get_default_xdisplay

View File

@ -220,6 +220,15 @@ struct _GdkDisplayClass
GdkAtom target, GdkAtom target,
guint32 time); guint32 time);
gint (*text_property_to_utf8_list) (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
gchar * (*utf8_to_string_target) (GdkDisplay *display,
const gchar *text);
/* Signals */ /* Signals */
void (*closed) (GdkDisplay *display, void (*closed) (GdkDisplay *display,
gboolean is_error); gboolean is_error);

View File

@ -54,83 +54,39 @@ typedef enum
GdkAtom gdk_atom_intern (const gchar *atom_name, GdkAtom gdk_atom_intern (const gchar *atom_name,
gboolean only_if_exists); gboolean only_if_exists);
GdkAtom gdk_atom_intern_static_string (const gchar *atom_name); GdkAtom gdk_atom_intern_static_string (const gchar *atom_name);
gchar* gdk_atom_name (GdkAtom atom); gchar* gdk_atom_name (GdkAtom atom);
gboolean gdk_property_get (GdkWindow *window, gboolean gdk_property_get (GdkWindow *window,
GdkAtom property, GdkAtom property,
GdkAtom type, GdkAtom type,
gulong offset, gulong offset,
gulong length, gulong length,
gint pdelete, gint pdelete,
GdkAtom *actual_property_type, GdkAtom *actual_property_type,
gint *actual_format, gint *actual_format,
gint *actual_length, gint *actual_length,
guchar **data); guchar **data);
void gdk_property_change (GdkWindow *window, void gdk_property_change (GdkWindow *window,
GdkAtom property, GdkAtom property,
GdkAtom type, GdkAtom type,
gint format, gint format,
GdkPropMode mode, GdkPropMode mode,
const guchar *data, const guchar *data,
gint nelements); gint nelements);
void gdk_property_delete (GdkWindow *window, void gdk_property_delete (GdkWindow *window,
GdkAtom property); GdkAtom property);
#ifndef GDK_MULTIHEAD_SAFE gint gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
gint gdk_text_property_to_text_list (GdkAtom encoding, GdkAtom encoding,
gint format, gint format,
const guchar *text, const guchar *text,
gint length, gint length,
gchar ***list); gchar ***list);
gint gdk_text_property_to_utf8_list (GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
gboolean gdk_utf8_to_compound_text (const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
gint gdk_string_to_compound_text (const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
#endif /* GDK_MULTIHEAD_SAFE */
gint gdk_text_property_to_text_list_for_display (GdkDisplay *display, gchar *gdk_utf8_to_string_target (const gchar *str);
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
gint gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
gchar *gdk_utf8_to_string_target (const gchar *str);
gint gdk_string_to_compound_text_for_display (GdkDisplay *display,
const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
gboolean gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
void gdk_free_text_list (gchar **list);
void gdk_free_compound_text (guchar *ctext);
G_END_DECLS G_END_DECLS

View File

@ -137,116 +137,6 @@ gdk_selection_send_notify (GdkNativeWindow requestor,
target, property, time); target, property, time);
} }
/**
* gdk_text_property_to_text_list:
* @encoding: an atom representing the encoding. The most common
* values for this are <literal>STRING</literal>,
* or <literal>COMPOUND_TEXT</literal>. This is
* value used as the type for the property.
* @format: the format of the property.
* @text: the text data.
* @length: the length of the property, in items.
* @list: location to store a terminated array of strings
* in the encoding of the current locale. This
* array should be freed using gdk_free_text_list().
*
* Converts a text string from the encoding as it is stored in
* a property into an array of strings in the encoding of
* the current local. (The elements of the array represent
* the nul-separated elements of the original text string.)
*
* Returns: the number of strings stored in @list, or 0,
* if the conversion failed.
*/
gint
gdk_text_property_to_text_list (GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list)
{
return gdk_text_property_to_text_list_for_display (gdk_display_get_default (),
encoding, format, text, length, list);
}
/**
* gdk_text_property_to_utf8_list:
* @encoding: an atom representing the encoding of the text
* @format: the format of the property
* @text: the text to convert
* @length: the length of @text, in bytes
* @list: (allow-none): location to store the list of strings or %NULL. The
* list should be freed with g_strfreev().
*
* Convert a text property in the giving encoding to
* a list of UTF-8 strings.
*
* Return value: the number of strings in the resulting
* list.
**/
gint
gdk_text_property_to_utf8_list (GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list)
{
return gdk_text_property_to_utf8_list_for_display (gdk_display_get_default (),
encoding, format, text, length, list);
}
/**
* gdk_string_to_compound_text:
* @str: a nul-terminated string.
* @encoding: location to store the encoding atom (to be used as
* the type for the property).
* @format: location to store the format for the property.
* @ctext: location to store newly allocated data for the property.
* @length: location to store the length of @ctext in items.
*
* Converts a string from the encoding of the current locale
* into a form suitable for storing in a window property.
*
* Returns: 0 upon sucess, non-zero upon failure.
*/
gint
gdk_string_to_compound_text (const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length)
{
return gdk_string_to_compound_text_for_display (gdk_display_get_default (),
str, encoding, format,
ctext, length);
}
/**
* gdk_utf8_to_compound_text:
* @str: a UTF-8 string
* @encoding: location to store resulting encoding
* @format: location to store format of the result
* @ctext: location to store the data of the result
* @length: location to store the length of the data
* stored in @ctext
*
* Convert from UTF-8 to compound text.
*
* Return value: %TRUE if the conversion succeeded, otherwise
* false.
**/
gboolean
gdk_utf8_to_compound_text (const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length)
{
return gdk_utf8_to_compound_text_for_display (gdk_display_get_default (),
str, encoding, format,
ctext, length);
}
/** /**
* gdk_selection_owner_set_for_display: * gdk_selection_owner_set_for_display:
* @display: the #GdkDisplay * @display: the #GdkDisplay
@ -386,3 +276,58 @@ gdk_selection_convert (GdkWindow *requestor,
GDK_DISPLAY_GET_CLASS (display) GDK_DISPLAY_GET_CLASS (display)
->convert_selection (display, requestor, selection, target, time); ->convert_selection (display, requestor, selection, target, time);
} }
/**
* gdk_text_property_to_utf8_list_for_display:
* @display: a #GdkDisplay
* @encoding: an atom representing the encoding of the text
* @format: the format of the property
* @text: the text to convert
* @length: the length of @text, in bytes
* @list: location to store the list of strings or %NULL. The
* list should be freed with g_strfreev().
*
* Converts a text property in the given encoding to
* a list of UTF-8 strings.
*
* Return value: the number of strings in the resulting list
*
* Since: 2.2
*/
gint
gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list)
{
g_return_val_if_fail (text != NULL, 0);
g_return_val_if_fail (length >= 0, 0);
g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
return GDK_DISPLAY_GET_CLASS (display)
->text_property_to_utf8_list (display, encoding, format, text, length, list);
}
/**
* gdk_utf8_to_string_target:
* @str: a UTF-8 string
*
* Converts an UTF-8 string into the best possible representation
* as a STRING. The representation of characters not in STRING
* is not specified; it may be as pseudo-escape sequences
* \x{ABCD}, or it may be in some other form of approximation.
*
* Return value: the newly-allocated string, or %NULL if the
* conversion failed. (It should not fail for
* any properly formed UTF-8 string unless system
* limits like memory or file descriptors are exceeded.)
**/
gchar *
gdk_utf8_to_string_target (const gchar *str)
{
GdkDisplay *display = gdk_display_get_default ();
return GDK_DISPLAY_GET_CLASS (display)->utf8_to_string_target (display, str);
}

View File

@ -2765,4 +2765,6 @@ _gdk_display_x11_class_init (GdkDisplayX11Class * class)
display_class->send_selection_notify = _gdk_x11_display_send_selection_notify; display_class->send_selection_notify = _gdk_x11_display_send_selection_notify;
display_class->get_selection_property = _gdk_x11_display_get_selection_property; display_class->get_selection_property = _gdk_x11_display_get_selection_property;
display_class->convert_selection = _gdk_x11_display_convert_selection; display_class->convert_selection = _gdk_x11_display_convert_selection;
display_class->text_property_to_utf8_list = _gdk_x11_display_text_property_to_utf8_list;
display_class->utf8_to_string_target = _gdk_x11_display_utf8_to_string_target;
} }

View File

@ -213,6 +213,15 @@ void _gdk_x11_display_convert_selection (GdkDisplay *display,
GdkAtom target, GdkAtom target,
guint32 time); guint32 time);
gint _gdk_x11_display_text_property_to_utf8_list (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
gchar * _gdk_x11_display_utf8_to_string_target (GdkDisplay *displayt,
const gchar *str);
void _gdk_x11_device_check_extension_events (GdkDevice *device); void _gdk_x11_device_check_extension_events (GdkDevice *device);
GdkDeviceManager *_gdk_x11_device_manager_new (GdkDisplay *display); GdkDeviceManager *_gdk_x11_device_manager_new (GdkDisplay *display);

View File

@ -21,7 +21,7 @@
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog * file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with * files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/. * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/ */
#include "config.h" #include "config.h"
@ -61,12 +61,12 @@ _gdk_x11_selection_window_destroyed (GdkWindow *window)
{ {
OwnerInfo *info = tmp_list->data; OwnerInfo *info = tmp_list->data;
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
if (info->owner == window) if (info->owner == window)
{ {
owner_list = g_slist_remove (owner_list, info); owner_list = g_slist_remove (owner_list, info);
g_free (info); g_free (info);
} }
} }
} }
@ -78,24 +78,24 @@ _gdk_x11_selection_filter_clear_event (XSelectionClearEvent *event)
{ {
GSList *tmp_list = owner_list; GSList *tmp_list = owner_list;
GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display); GdkDisplay *display = gdk_x11_lookup_xdisplay (event->display);
while (tmp_list) while (tmp_list)
{ {
OwnerInfo *info = tmp_list->data; OwnerInfo *info = tmp_list->data;
if (gdk_window_get_display (info->owner) == display && if (gdk_window_get_display (info->owner) == display &&
info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection)) info->selection == gdk_x11_xatom_to_atom_for_display (display, event->selection))
{ {
if ((GDK_WINDOW_XID (info->owner) == event->window && if ((GDK_WINDOW_XID (info->owner) == event->window &&
event->serial >= info->serial)) event->serial >= info->serial))
{ {
owner_list = g_slist_remove (owner_list, info); owner_list = g_slist_remove (owner_list, info);
g_free (info); g_free (info);
return TRUE; return TRUE;
} }
else else
return FALSE; return FALSE;
} }
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
} }
@ -127,24 +127,24 @@ _gdk_x11_display_set_selection_owner (GdkDisplay *display,
xdisplay = GDK_WINDOW_XDISPLAY (owner); xdisplay = GDK_WINDOW_XDISPLAY (owner);
xwindow = GDK_WINDOW_XID (owner); xwindow = GDK_WINDOW_XID (owner);
} }
else else
{ {
xdisplay = GDK_DISPLAY_XDISPLAY (display); xdisplay = GDK_DISPLAY_XDISPLAY (display);
xwindow = None; xwindow = None;
} }
xselection = gdk_x11_atom_to_xatom_for_display (display, selection); xselection = gdk_x11_atom_to_xatom_for_display (display, selection);
tmp_list = owner_list; tmp_list = owner_list;
while (tmp_list) while (tmp_list)
{ {
info = tmp_list->data; info = tmp_list->data;
if (info->selection == selection) if (info->selection == selection)
{ {
owner_list = g_slist_remove (owner_list, info); owner_list = g_slist_remove (owner_list, info);
g_free (info); g_free (info);
break; break;
} }
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
} }
@ -173,8 +173,8 @@ _gdk_x11_display_get_selection_owner (GdkDisplay *display,
return NULL; return NULL;
xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
gdk_x11_atom_to_xatom_for_display (display, gdk_x11_atom_to_xatom_for_display (display,
selection)); selection));
if (xwindow == None) if (xwindow == None)
return NULL; return NULL;
@ -232,66 +232,66 @@ _gdk_x11_display_get_selection_property (GdkDisplay *display,
AnyPropertyType, &prop_type, &prop_format, AnyPropertyType, &prop_type, &prop_format,
&nitems, &nbytes, &t) != Success) &nitems, &nbytes, &t) != Success)
goto err; goto err;
if (prop_type != None) if (prop_type != None)
{ {
if (ret_type) if (ret_type)
*ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type); *ret_type = gdk_x11_xatom_to_atom_for_display (display, prop_type);
if (ret_format) if (ret_format)
*ret_format = prop_format; *ret_format = prop_format;
if (prop_type == XA_ATOM || if (prop_type == XA_ATOM ||
prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR")) prop_type == gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
{ {
Atom* atoms = (Atom*) t; Atom* atoms = (Atom*) t;
GdkAtom* atoms_dest; GdkAtom* atoms_dest;
gint num_atom, i; gint num_atom, i;
if (prop_format != 32) if (prop_format != 32)
goto err; goto err;
num_atom = nitems;
length = sizeof (GdkAtom) * num_atom + 1;
if (data) num_atom = nitems;
{ length = sizeof (GdkAtom) * num_atom + 1;
*data = g_malloc (length);
(*data)[length - 1] = '\0'; if (data)
atoms_dest = (GdkAtom *)(*data); {
*data = g_malloc (length);
for (i=0; i < num_atom; i++) (*data)[length - 1] = '\0';
atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]); atoms_dest = (GdkAtom *)(*data);
}
} for (i=0; i < num_atom; i++)
atoms_dest[i] = gdk_x11_xatom_to_atom_for_display (display, atoms[i]);
}
}
else else
{ {
switch (prop_format) switch (prop_format)
{ {
case 8: case 8:
length = nitems; length = nitems;
break; break;
case 16: case 16:
length = sizeof(short) * nitems; length = sizeof(short) * nitems;
break; break;
case 32: case 32:
length = sizeof(long) * nitems; length = sizeof(long) * nitems;
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
break; break;
} }
/* Add on an extra byte to handle null termination. X guarantees /* Add on an extra byte to handle null termination. X guarantees
that t will be 1 longer than nitems and null terminated */ that t will be 1 longer than nitems and null terminated */
length += 1; length += 1;
if (data)
*data = g_memdup (t, length);
}
if (data)
*data = g_memdup (t, length);
}
if (t) if (t)
XFree (t); XFree (t);
return length - 1; return length - 1;
} }
@ -302,7 +302,7 @@ _gdk_x11_display_get_selection_property (GdkDisplay *display,
*ret_format = 0; *ret_format = 0;
if (data) if (data)
*data = NULL; *data = NULL;
return 0; return 0;
} }
@ -332,35 +332,35 @@ _gdk_x11_display_send_selection_notify (GdkDisplay *display,
} }
/** /**
* gdk_text_property_to_text_list_for_display: * gdk_x11_display_text_property_to_text_list:
* @display: The #GdkDisplay where the encoding is defined. * @display: The #GdkDisplay where the encoding is defined
* @encoding: an atom representing the encoding. The most * @encoding: an atom representing the encoding. The most
* common values for this are STRING, or COMPOUND_TEXT. * common values for this are STRING, or COMPOUND_TEXT.
* This is value used as the type for the property. * This is value used as the type for the property
* @format: the format of the property. * @format: the format of the property
* @text: The text data. * @text: The text data
* @length: The number of items to transform. * @length: The number of items to transform
* @list: location to store a terminated array of strings in * @list: location to store a terminated array of strings in
* the encoding of the current locale. This array should be * the encoding of the current locale. This array should be
* freed using gdk_free_text_list(). * freed using gdk_free_text_list().
* *
* Convert a text string from the encoding as it is stored * Convert a text string from the encoding as it is stored
* in a property into an array of strings in the encoding of * in a property into an array of strings in the encoding of
* the current locale. (The elements of the array represent the * the current locale. (The elements of the array represent the
* nul-separated elements of the original text string.) * nul-separated elements of the original text string.)
* *
* Returns: the number of strings stored in list, or 0, * Returns: the number of strings stored in list, or 0,
* if the conversion failed. * if the conversion failed
* *
* Since: 2.2 * Since: 3.0
*/ */
gint gint
gdk_text_property_to_text_list_for_display (GdkDisplay *display, gdk_x11_display_text_property_to_text_list (GdkDisplay *display,
GdkAtom encoding, GdkAtom encoding,
gint format, gint format,
const guchar *text, const guchar *text,
gint length, gint length,
gchar ***list) gchar ***list)
{ {
XTextProperty property; XTextProperty property;
gint count = 0; gint count = 0;
@ -378,31 +378,31 @@ gdk_text_property_to_text_list_for_display (GdkDisplay *display,
property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding); property.encoding = gdk_x11_atom_to_xatom_for_display (display, encoding);
property.format = format; property.format = format;
property.nitems = length; property.nitems = length;
res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property, res = XmbTextPropertyToTextList (GDK_DISPLAY_XDISPLAY (display), &property,
&local_list, &count); &local_list, &count);
if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound) if (res == XNoMemory || res == XLocaleNotSupported || res == XConverterNotFound)
return 0; return 0;
else else
{ {
if (list) if (list)
*list = local_list; *list = g_strdupv (local_list);
else else
XFreeStringList (local_list); XFreeStringList (local_list);
return count; return count;
} }
} }
/** /**
* gdk_free_text_list: * gdk_x11_free_text_list:
* @list: the value stored in the @list parameter by * @list: the value stored in the @list parameter by
* a call to gdk_text_property_to_text_list(). * a call to gdk_x11_display_text_property_to_text_list().
* *
* Frees the array of strings created by * Frees the array of strings created by
* gdk_text_property_to_text_list(). * gdk_x11_display_text_property_to_text_list().
*/ */
void void
gdk_free_text_list (gchar **list) gdk_x11_free_text_list (gchar **list)
{ {
g_return_if_fail (list != NULL); g_return_if_fail (list != NULL);
@ -411,9 +411,9 @@ gdk_free_text_list (gchar **list)
static gint static gint
make_list (const gchar *text, make_list (const gchar *text,
gint length, gint length,
gboolean latin1, gboolean latin1,
gchar ***list) gchar ***list)
{ {
GSList *strings = NULL; GSList *strings = NULL;
gint n_strings = 0; gint n_strings = 0;
@ -426,40 +426,40 @@ make_list (const gchar *text,
while (p < text + length) while (p < text + length)
{ {
gchar *str; gchar *str;
q = p; q = p;
while (*q && q < text + length) while (*q && q < text + length)
q++; q++;
if (latin1) if (latin1)
{ {
str = g_convert (p, q - p, str = g_convert (p, q - p,
"UTF-8", "ISO-8859-1", "UTF-8", "ISO-8859-1",
NULL, NULL, &error); NULL, NULL, &error);
if (!str) if (!str)
{ {
g_warning ("Error converting selection from STRING: %s", g_warning ("Error converting selection from STRING: %s",
error->message); error->message);
g_error_free (error); g_error_free (error);
} }
} }
else else
{ {
str = g_strndup (p, q - p); str = g_strndup (p, q - p);
if (!g_utf8_validate (str, -1, NULL)) if (!g_utf8_validate (str, -1, NULL))
{ {
g_warning ("Error converting selection from UTF8_STRING"); g_warning ("Error converting selection from UTF8_STRING");
g_free (str); g_free (str);
str = NULL; str = NULL;
} }
} }
if (str) if (str)
{ {
strings = g_slist_prepend (strings, str); strings = g_slist_prepend (strings, str);
n_strings++; n_strings++;
} }
p = q + 1; p = q + 1;
} }
@ -469,54 +469,32 @@ make_list (const gchar *text,
*list = g_new (gchar *, n_strings + 1); *list = g_new (gchar *, n_strings + 1);
(*list)[n_strings] = NULL; (*list)[n_strings] = NULL;
} }
i = n_strings; i = n_strings;
tmp_list = strings; tmp_list = strings;
while (tmp_list) while (tmp_list)
{ {
if (list) if (list)
(*list)[--i] = tmp_list->data; (*list)[--i] = tmp_list->data;
else else
g_free (tmp_list->data); g_free (tmp_list->data);
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
} }
g_slist_free (strings); g_slist_free (strings);
return n_strings; return n_strings;
} }
/** gint
* gdk_text_property_to_utf8_list_for_display: _gdk_x11_display_text_property_to_utf8_list (GdkDisplay *display,
* @display: a #GdkDisplay GdkAtom encoding,
* @encoding: an atom representing the encoding of the text gint format,
* @format: the format of the property const guchar *text,
* @text: the text to convert gint length,
* @length: the length of @text, in bytes gchar ***list)
* @list: location to store the list of strings or %NULL. The
* list should be freed with g_strfreev().
*
* Converts a text property in the given encoding to
* a list of UTF-8 strings.
*
* Return value: the number of strings in the resulting
* list.
*
* Since: 2.2
**/
gint
gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list)
{ {
g_return_val_if_fail (text != NULL, 0);
g_return_val_if_fail (length >= 0, 0);
g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
if (encoding == GDK_TARGET_STRING) if (encoding == GDK_TARGET_STRING)
{ {
return make_list ((gchar *)text, length, TRUE, list); return make_list ((gchar *)text, length, TRUE, list);
@ -534,88 +512,88 @@ gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
gboolean need_conversion = !g_get_charset (&charset); gboolean need_conversion = !g_get_charset (&charset);
gint count = 0; gint count = 0;
GError *error = NULL; GError *error = NULL;
/* Probably COMPOUND text, we fall back to Xlib routines /* Probably COMPOUND text, we fall back to Xlib routines
*/ */
local_count = gdk_text_property_to_text_list_for_display (display, local_count = gdk_x11_display_text_property_to_text_list (display,
encoding, encoding,
format, format,
text, text,
length, length,
&local_list); &local_list);
if (list) if (list)
*list = g_new (gchar *, local_count + 1); *list = g_new (gchar *, local_count + 1);
for (i=0; i<local_count; i++) for (i=0; i<local_count; i++)
{ {
/* list contains stuff in our default encoding /* list contains stuff in our default encoding
*/ */
if (need_conversion) if (need_conversion)
{ {
gchar *utf = g_convert (local_list[i], -1, gchar *utf = g_convert (local_list[i], -1,
"UTF-8", charset, "UTF-8", charset,
NULL, NULL, &error); NULL, NULL, &error);
if (utf) if (utf)
{ {
if (list) if (list)
(*list)[count++] = utf; (*list)[count++] = utf;
else else
g_free (utf); g_free (utf);
} }
else else
{ {
g_warning ("Error converting to UTF-8 from '%s': %s", g_warning ("Error converting to UTF-8 from '%s': %s",
charset, error->message); charset, error->message);
g_error_free (error); g_error_free (error);
error = NULL; error = NULL;
} }
} }
else else
{ {
if (list) if (list)
{ {
if (g_utf8_validate (local_list[i], -1, NULL)) if (g_utf8_validate (local_list[i], -1, NULL))
(*list)[count++] = g_strdup (local_list[i]); (*list)[count++] = g_strdup (local_list[i]);
else else
g_warning ("Error converting selection"); g_warning ("Error converting selection");
} }
} }
} }
if (local_count) if (local_count)
gdk_free_text_list (local_list); gdk_x11_free_text_list (local_list);
if (list) if (list)
(*list)[count] = NULL; (*list)[count] = NULL;
return count; return count;
} }
} }
/** /**
* gdk_string_to_compound_text_for_display: * gdk_x11_display_string_to_compound_text:
* @display: the #GdkDisplay where the encoding is defined. * @display: the #GdkDisplay where the encoding is defined
* @str: a nul-terminated string. * @str: a nul-terminated string
* @encoding: location to store the encoding atom * @encoding: location to store the encoding atom
* (to be used as the type for the property). * (to be used as the type for the property)
* @format: location to store the format of the property * @format: location to store the format of the property
* @ctext: location to store newly allocated data for the property. * @ctext: location to store newly allocated data for the property
* @length: the length of @text, in bytes * @length: the length of @text, in bytes
*
* Convert a string from the encoding of the current
* locale into a form suitable for storing in a window property.
*
* Returns: 0 upon success, non-zero upon failure.
* *
* Since: 2.2 * Convert a string from the encoding of the current
**/ * locale into a form suitable for storing in a window property.
*
* Returns: 0 upon success, non-zero upon failure
*
* Since: 3.0
*/
gint gint
gdk_string_to_compound_text_for_display (GdkDisplay *display, gdk_x11_display_string_to_compound_text (GdkDisplay *display,
const gchar *str, const gchar *str,
GdkAtom *encoding, GdkAtom *encoding,
gint *format, gint *format,
guchar **ctext, guchar **ctext,
gint *length) gint *length)
{ {
gint res; gint res;
XTextProperty property; XTextProperty property;
@ -625,9 +603,9 @@ gdk_string_to_compound_text_for_display (GdkDisplay *display,
if (gdk_display_is_closed (display)) if (gdk_display_is_closed (display))
res = XLocaleNotSupported; res = XLocaleNotSupported;
else else
res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display), res = XmbTextListToTextProperty (GDK_DISPLAY_XDISPLAY (display),
(char **)&str, 1, XCompoundTextStyle, (char **)&str, 1, XCompoundTextStyle,
&property); &property);
if (res != Success) if (res != Success)
{ {
property.encoding = None; property.encoding = None;
@ -655,9 +633,9 @@ gdk_string_to_compound_text_for_display (GdkDisplay *display,
* This routine strips out all non-allowed C0 and C1 characters * This routine strips out all non-allowed C0 and C1 characters
* from the input string and also canonicalizes \r, and \r\n to \n * from the input string and also canonicalizes \r, and \r\n to \n
*/ */
static gchar * static gchar *
sanitize_utf8 (const gchar *src, sanitize_utf8 (const gchar *src,
gboolean return_latin1) gboolean return_latin1)
{ {
gint len = strlen (src); gint len = strlen (src);
GString *result = g_string_sized_new (len); GString *result = g_string_sized_new (len);
@ -666,89 +644,76 @@ sanitize_utf8 (const gchar *src,
while (*p) while (*p)
{ {
if (*p == '\r') if (*p == '\r')
{ {
p++; p++;
if (*p == '\n') if (*p == '\n')
p++; p++;
g_string_append_c (result, '\n'); g_string_append_c (result, '\n');
} }
else else
{ {
gunichar ch = g_utf8_get_char (p); gunichar ch = g_utf8_get_char (p);
if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
{
if (return_latin1)
{
if (ch <= 0xff)
g_string_append_c (result, ch);
else
g_string_append_printf (result,
ch < 0x10000 ? "\\u%04x" : "\\U%08x",
ch);
}
else
{
char buf[7];
gint buflen;
buflen = g_unichar_to_utf8 (ch, buf);
g_string_append_len (result, buf, buflen);
}
}
p = g_utf8_next_char (p); if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
} {
if (return_latin1)
{
if (ch <= 0xff)
g_string_append_c (result, ch);
else
g_string_append_printf (result,
ch < 0x10000 ? "\\u%04x" : "\\U%08x",
ch);
}
else
{
char buf[7];
gint buflen;
buflen = g_unichar_to_utf8 (ch, buf);
g_string_append_len (result, buf, buflen);
}
}
p = g_utf8_next_char (p);
}
} }
return g_string_free (result, FALSE); return g_string_free (result, FALSE);
} }
/**
* gdk_utf8_to_string_target:
* @str: a UTF-8 string
*
* Converts an UTF-8 string into the best possible representation
* as a STRING. The representation of characters not in STRING
* is not specified; it may be as pseudo-escape sequences
* \x{ABCD}, or it may be in some other form of approximation.
*
* Return value: the newly-allocated string, or %NULL if the
* conversion failed. (It should not fail for
* any properly formed UTF-8 string unless system
* limits like memory or file descriptors are exceeded.)
**/
gchar * gchar *
gdk_utf8_to_string_target (const gchar *str) _gdk_x11_display_utf8_to_string_target (GdkDisplay *display,
const gchar *str)
{ {
return sanitize_utf8 (str, TRUE); return sanitize_utf8 (str, TRUE);
} }
/** /**
* gdk_utf8_to_compound_text_for_display: * gdk_x11_display_utf8_to_compound_text:
* @display: a #GdkDisplay * @display: a #GdkDisplay
* @str: a UTF-8 string * @str: a UTF-8 string
* @encoding: location to store resulting encoding * @encoding: location to store resulting encoding
* @format: location to store format of the result * @format: location to store format of the result
* @ctext: location to store the data of the result * @ctext: location to store the data of the result
* @length: location to store the length of the data * @length: location to store the length of the data
* stored in @ctext * stored in @ctext
*
* Converts from UTF-8 to compound text.
*
* Return value: %TRUE if the conversion succeeded, otherwise
* %FALSE.
* *
* Since: 2.2 * Converts from UTF-8 to compound text.
**/ *
* Return value: %TRUE if the conversion succeeded,
* otherwise %FALSE
*
* Since: 3.0
*/
gboolean gboolean
gdk_utf8_to_compound_text_for_display (GdkDisplay *display, gdk_x11_display_utf8_to_compound_text (GdkDisplay *display,
const gchar *str, const gchar *str,
GdkAtom *encoding, GdkAtom *encoding,
gint *format, gint *format,
guchar **ctext, guchar **ctext,
gint *length) gint *length)
{ {
gboolean need_conversion; gboolean need_conversion;
const gchar *charset; const gchar *charset;
@ -766,53 +731,56 @@ gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
if (need_conversion) if (need_conversion)
{ {
locale_str = g_convert (tmp_str, -1, locale_str = g_convert (tmp_str, -1,
charset, "UTF-8", charset, "UTF-8",
NULL, NULL, &error); NULL, NULL, &error);
g_free (tmp_str); g_free (tmp_str);
if (!locale_str) if (!locale_str)
{ {
if (!(error->domain = G_CONVERT_ERROR && if (!(error->domain = G_CONVERT_ERROR &&
error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
{ {
g_warning ("Error converting from UTF-8 to '%s': %s", g_warning ("Error converting from UTF-8 to '%s': %s",
charset, error->message); charset, error->message);
} }
g_error_free (error); g_error_free (error);
if (encoding) if (encoding)
*encoding = None; *encoding = None;
if (format) if (format)
*format = None; *format = None;
if (ctext) if (ctext)
*ctext = NULL; *ctext = NULL;
if (length) if (length)
*length = 0; *length = 0;
return FALSE; return FALSE;
} }
} }
else else
locale_str = tmp_str; locale_str = tmp_str;
result = gdk_string_to_compound_text_for_display (display, locale_str, result = gdk_x11_display_string_to_compound_text (display, locale_str,
encoding, format, encoding, format,
ctext, length); ctext, length);
result = (result == Success? TRUE : FALSE); result = (result == Success? TRUE : FALSE);
g_free (locale_str); g_free (locale_str);
return result; return result;
} }
/** /**
* gdk_free_compound_text: * gdk_x11_free_compound_text:
* @ctext: The pointer stored in @ctext from a call to * @ctext: The pointer stored in @ctext from a call to
* gdk_string_to_compound_text(). * gdk_x11_display_string_to_compound_text().
* *
* Frees the data returned from gdk_string_to_compound_text(). * Frees the data returned from gdk_x11_display_string_to_compound_text().
*
* Since: 3.0
*/ */
void gdk_free_compound_text (guchar *ctext) void
gdk_x11_free_compound_text (guchar *ctext)
{ {
if (ctext) if (ctext)
XFree (ctext); XFree (ctext);

View File

@ -2231,10 +2231,10 @@ set_text_property (GdkDisplay *display,
else else
{ {
GdkAtom gdk_type; GdkAtom gdk_type;
gdk_utf8_to_compound_text_for_display (display, gdk_x11_display_utf8_to_compound_text (display,
utf8_str, &gdk_type, &prop_format, utf8_str, &gdk_type, &prop_format,
(guchar **)&prop_text, &prop_length); (guchar **)&prop_text, &prop_length);
prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type); prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type);
is_compound_text = TRUE; is_compound_text = TRUE;
} }
@ -2249,7 +2249,7 @@ set_text_property (GdkDisplay *display,
prop_length); prop_length);
if (is_compound_text) if (is_compound_text)
gdk_free_compound_text ((guchar *)prop_text); gdk_x11_free_compound_text ((guchar *)prop_text);
else else
g_free (prop_text); g_free (prop_text);
} }

View File

@ -231,6 +231,30 @@ GdkWindow *gdk_x11_window_foreign_new_for_display (GdkDisplay *display,
GdkWindow *gdk_x11_window_lookup_for_display (GdkDisplay *display, GdkWindow *gdk_x11_window_lookup_for_display (GdkDisplay *display,
Window window); Window window);
gint gdk_x11_display_text_property_to_text_list (GdkDisplay *display,
GdkAtom encoding,
gint format,
const guchar *text,
gint length,
gchar ***list);
void gdk_x11_free_text_list (gchar **list);
gint gdk_x11_display_string_to_compound_text (GdkDisplay *display,
const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
gboolean gdk_x11_display_utf8_to_compound_text (GdkDisplay *display,
const gchar *str,
GdkAtom *encoding,
gint *format,
guchar **ctext,
gint *length);
void gdk_x11_free_compound_text (guchar *ctext);
G_END_DECLS G_END_DECLS
#endif /* __GDK_X_H__ */ #endif /* __GDK_X_H__ */

View File

@ -1318,18 +1318,22 @@ selection_set_compound_text (GtkSelectionData *selection_data,
gint format; gint format;
gint new_length; gint new_length;
gboolean result = FALSE; gboolean result = FALSE;
tmp = g_strndup (str, len);
if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
&encoding, &format, &text, &new_length))
{
gtk_selection_data_set (selection_data, encoding, format, text, new_length);
gdk_free_compound_text (text);
result = TRUE;
}
g_free (tmp); #ifdef GDK_WINDOWING_X11
if (GDK_IS_DISPLAY_X11 (selection_data->display))
{
tmp = g_strndup (str, len);
if (gdk_x11_display_utf8_to_compound_text (selection_data->display, tmp,
&encoding, &format, &text, &new_length))
{
gtk_selection_data_set (selection_data, encoding, format, text, new_length);
gdk_x11_free_compound_text (text);
result = TRUE;
}
g_free (tmp);
}
#endif
return result; return result;
} }