mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
Real COMPOUND_TEXT support! I was expecting to have to read the spec
and implement the required subset of ISO-2022 in libcharset, but it turns out that Xlib provides conversion functions between UTF-8 and compound text, which are just about ideal for us. So now we can paste multilingual stuff both to and from emacs21. Rock on. [originally from svn r3193]
This commit is contained in:
parent
ef2ccb56cf
commit
d49e6e1476
84
unix/pterm.c
84
unix/pterm.c
@ -58,8 +58,8 @@ struct gui_data {
|
|||||||
wchar_t *pastein_data;
|
wchar_t *pastein_data;
|
||||||
int direct_to_font;
|
int direct_to_font;
|
||||||
int pastein_data_len;
|
int pastein_data_len;
|
||||||
char *pasteout_data, *pasteout_data_utf8;
|
char *pasteout_data, *pasteout_data_ctext, *pasteout_data_utf8;
|
||||||
int pasteout_data_len, pasteout_data_utf8_len;
|
int pasteout_data_len, pasteout_data_ctext_len, pasteout_data_utf8_len;
|
||||||
int font_width, font_height;
|
int font_width, font_height;
|
||||||
int width, height;
|
int width, height;
|
||||||
int ignore_sbar;
|
int ignore_sbar;
|
||||||
@ -1327,16 +1327,20 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
|
|||||||
struct gui_data *inst = (struct gui_data *)frontend;
|
struct gui_data *inst = (struct gui_data *)frontend;
|
||||||
if (inst->pasteout_data)
|
if (inst->pasteout_data)
|
||||||
sfree(inst->pasteout_data);
|
sfree(inst->pasteout_data);
|
||||||
|
if (inst->pasteout_data_ctext)
|
||||||
|
sfree(inst->pasteout_data_ctext);
|
||||||
if (inst->pasteout_data_utf8)
|
if (inst->pasteout_data_utf8)
|
||||||
sfree(inst->pasteout_data_utf8);
|
sfree(inst->pasteout_data_utf8);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up UTF-8 paste data. This only happens if we aren't in
|
* Set up UTF-8 and compound text paste data. This only happens
|
||||||
* direct-to-font mode using the D800 hack.
|
* if we aren't in direct-to-font mode using the D800 hack.
|
||||||
*/
|
*/
|
||||||
if (!inst->direct_to_font) {
|
if (!inst->direct_to_font) {
|
||||||
wchar_t *tmp = data;
|
wchar_t *tmp = data;
|
||||||
int tmplen = len;
|
int tmplen = len;
|
||||||
|
XTextProperty tp;
|
||||||
|
char *list[1];
|
||||||
|
|
||||||
inst->pasteout_data_utf8 = snewn(len*6, char);
|
inst->pasteout_data_utf8 = snewn(len*6, char);
|
||||||
inst->pasteout_data_utf8_len = len*6;
|
inst->pasteout_data_utf8_len = len*6;
|
||||||
@ -1350,11 +1354,26 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
|
|||||||
} else {
|
} else {
|
||||||
inst->pasteout_data_utf8 =
|
inst->pasteout_data_utf8 =
|
||||||
sresize(inst->pasteout_data_utf8,
|
sresize(inst->pasteout_data_utf8,
|
||||||
inst->pasteout_data_utf8_len, char);
|
inst->pasteout_data_utf8_len + 1, char);
|
||||||
|
inst->pasteout_data_utf8[inst->pasteout_data_utf8_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now let Xlib convert our UTF-8 data into compound text.
|
||||||
|
*/
|
||||||
|
list[0] = inst->pasteout_data_utf8;
|
||||||
|
if (Xutf8TextListToTextProperty(GDK_DISPLAY(), list, 1,
|
||||||
|
XCompoundTextStyle, &tp) == 0) {
|
||||||
|
inst->pasteout_data_ctext = snewn(tp.nitems+1, char);
|
||||||
|
memcpy(inst->pasteout_data_ctext, tp.value, tp.nitems);
|
||||||
|
inst->pasteout_data_ctext_len = tp.nitems;
|
||||||
|
XFree(tp.value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inst->pasteout_data_utf8 = NULL;
|
inst->pasteout_data_utf8 = NULL;
|
||||||
inst->pasteout_data_utf8_len = 0;
|
inst->pasteout_data_utf8_len = 0;
|
||||||
|
inst->pasteout_data_ctext = NULL;
|
||||||
|
inst->pasteout_data_ctext_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->pasteout_data = snewn(len*6, char);
|
inst->pasteout_data = snewn(len*6, char);
|
||||||
@ -1375,6 +1394,7 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
|
|||||||
GDK_CURRENT_TIME)) {
|
GDK_CURRENT_TIME)) {
|
||||||
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
|
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
|
||||||
GDK_SELECTION_TYPE_STRING, 1);
|
GDK_SELECTION_TYPE_STRING, 1);
|
||||||
|
if (inst->pasteout_data_ctext)
|
||||||
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
|
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
|
||||||
compound_text_atom, 1);
|
compound_text_atom, 1);
|
||||||
if (inst->pasteout_data_utf8)
|
if (inst->pasteout_data_utf8)
|
||||||
@ -1394,6 +1414,10 @@ void selection_get(GtkWidget *widget, GtkSelectionData *seldata,
|
|||||||
gtk_selection_data_set(seldata, seldata->target, 8,
|
gtk_selection_data_set(seldata, seldata->target, 8,
|
||||||
inst->pasteout_data_utf8,
|
inst->pasteout_data_utf8,
|
||||||
inst->pasteout_data_utf8_len);
|
inst->pasteout_data_utf8_len);
|
||||||
|
else if (seldata->target == compound_text_atom)
|
||||||
|
gtk_selection_data_set(seldata, seldata->target, 8,
|
||||||
|
inst->pasteout_data_ctext,
|
||||||
|
inst->pasteout_data_ctext_len);
|
||||||
else
|
else
|
||||||
gtk_selection_data_set(seldata, seldata->target, 8,
|
gtk_selection_data_set(seldata, seldata->target, 8,
|
||||||
inst->pasteout_data, inst->pasteout_data_len);
|
inst->pasteout_data, inst->pasteout_data_len);
|
||||||
@ -1406,10 +1430,14 @@ gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,
|
|||||||
term_deselect(inst->term);
|
term_deselect(inst->term);
|
||||||
if (inst->pasteout_data)
|
if (inst->pasteout_data)
|
||||||
sfree(inst->pasteout_data);
|
sfree(inst->pasteout_data);
|
||||||
|
if (inst->pasteout_data_ctext)
|
||||||
|
sfree(inst->pasteout_data_ctext);
|
||||||
if (inst->pasteout_data_utf8)
|
if (inst->pasteout_data_utf8)
|
||||||
sfree(inst->pasteout_data_utf8);
|
sfree(inst->pasteout_data_utf8);
|
||||||
inst->pasteout_data = NULL;
|
inst->pasteout_data = NULL;
|
||||||
inst->pasteout_data_len = 0;
|
inst->pasteout_data_len = 0;
|
||||||
|
inst->pasteout_data_ctext = NULL;
|
||||||
|
inst->pasteout_data_ctext_len = 0;
|
||||||
inst->pasteout_data_utf8 = NULL;
|
inst->pasteout_data_utf8 = NULL;
|
||||||
inst->pasteout_data_utf8_len = 0;
|
inst->pasteout_data_utf8_len = 0;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1450,6 +1478,12 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
|
|||||||
guint time, gpointer data)
|
guint time, gpointer data)
|
||||||
{
|
{
|
||||||
struct gui_data *inst = (struct gui_data *)data;
|
struct gui_data *inst = (struct gui_data *)data;
|
||||||
|
XTextProperty tp;
|
||||||
|
char **list;
|
||||||
|
char *text;
|
||||||
|
int length, count, ret;
|
||||||
|
int free_list_required = 0;
|
||||||
|
int charset;
|
||||||
|
|
||||||
if (seldata->target == utf8_string_atom && seldata->length <= 0) {
|
if (seldata->target == utf8_string_atom && seldata->length <= 0) {
|
||||||
/*
|
/*
|
||||||
@ -1480,21 +1514,51 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
|
|||||||
seldata->type != utf8_string_atom))
|
seldata->type != utf8_string_atom))
|
||||||
return; /* Nothing happens. */
|
return; /* Nothing happens. */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert COMPOUND_TEXT into UTF-8.
|
||||||
|
*/
|
||||||
|
if (seldata->type == compound_text_atom) {
|
||||||
|
tp.value = seldata->data;
|
||||||
|
tp.encoding = (Atom) seldata->type;
|
||||||
|
tp.format = seldata->format;
|
||||||
|
tp.nitems = seldata->length;
|
||||||
|
ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp, &list, &count);
|
||||||
|
if (ret != 0 || count != 1) {
|
||||||
|
/*
|
||||||
|
* Compound text failed; fall back to STRING.
|
||||||
|
*/
|
||||||
|
gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,
|
||||||
|
GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
text = list[0];
|
||||||
|
length = strlen(list[0]);
|
||||||
|
charset = CS_UTF8;
|
||||||
|
free_list_required = 1;
|
||||||
|
} else {
|
||||||
|
text = (char *)seldata->data;
|
||||||
|
length = seldata->length;
|
||||||
|
charset = (seldata->type == utf8_string_atom ?
|
||||||
|
CS_UTF8 : inst->ucsdata.line_codepage);
|
||||||
|
}
|
||||||
|
|
||||||
if (inst->pastein_data)
|
if (inst->pastein_data)
|
||||||
sfree(inst->pastein_data);
|
sfree(inst->pastein_data);
|
||||||
|
|
||||||
inst->pastein_data = snewn(seldata->length, wchar_t);
|
inst->pastein_data = snewn(length, wchar_t);
|
||||||
inst->pastein_data_len = seldata->length;
|
inst->pastein_data_len = length;
|
||||||
inst->pastein_data_len =
|
inst->pastein_data_len =
|
||||||
mb_to_wc((seldata->type == utf8_string_atom ?
|
mb_to_wc(charset, 0, text, length,
|
||||||
CS_UTF8 : inst->ucsdata.line_codepage),
|
|
||||||
0, seldata->data, seldata->length,
|
|
||||||
inst->pastein_data, inst->pastein_data_len);
|
inst->pastein_data, inst->pastein_data_len);
|
||||||
|
|
||||||
term_do_paste(inst->term);
|
term_do_paste(inst->term);
|
||||||
|
|
||||||
if (term_paste_pending(inst->term))
|
if (term_paste_pending(inst->term))
|
||||||
inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
|
inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
|
||||||
|
|
||||||
|
if (free_list_required)
|
||||||
|
XFreeStringList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
gint idle_paste_func(gpointer data)
|
gint idle_paste_func(gpointer data)
|
||||||
|
Loading…
Reference in New Issue
Block a user