diff options
Diffstat (limited to 'gtk/ScintillaGTK.cxx')
-rw-r--r-- | gtk/ScintillaGTK.cxx | 238 |
1 files changed, 161 insertions, 77 deletions
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 50f743f1d..913ee4f30 100644 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -54,7 +54,9 @@ #if GTK_MAJOR_VERSION < 2 #define INTERNATIONAL_INPUT -#else +#endif + +#if !PLAT_GTK_WIN32 #include <iconv.h> #endif @@ -87,7 +89,10 @@ class ScintillaGTK : public ScintillaBase { GtkWidgetClass *parentClass; - static GdkAtom clipboard_atom; + GdkAtom atomClipboard; + GdkAtom atomSought; + GdkAtom atomUTF8; + GdkAtom atomString; #if PLAT_GTK_WIN32 CLIPFORMAT cfColumnSelect; @@ -145,7 +150,7 @@ private: virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); bool OwnPrimarySelection(); virtual void ClaimSelection(); - char *GetGtkSelectionText(const GtkSelectionData *selectionData, unsigned int *len, bool *isRectangular); + void GetGtkSelectionText(const GtkSelectionData *selectionData, SelectionText &selText); void ReceivedSelection(GtkSelectionData *selection_data); void ReceivedDrop(GtkSelectionData *selection_data); void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected); @@ -225,12 +230,11 @@ enum { static gint scintilla_signals[LAST_SIGNAL] = { 0 }; static GtkWidgetClass* parent_class = NULL; -GdkAtom ScintillaGTK::clipboard_atom = GDK_NONE; - enum { TARGET_STRING, TARGET_TEXT, - TARGET_COMPOUND_TEXT + TARGET_COMPOUND_TEXT, + TARGET_UTF8_STRING }; static GtkWidget *PWidget(Window &w) { @@ -256,6 +260,11 @@ ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) : sci = sci_; wMain = GTK_WIDGET(sci); + atomClipboard = GDK_NONE; + atomSought = GDK_NONE; + atomUTF8 = GDK_NONE; + atomString = GDK_NONE; + #if PLAT_GTK_WIN32 // There does not seem to be a real standard for indicating that the clipboard // contains a rectangular selection, so copy Developer Studio. @@ -565,9 +574,10 @@ void ScintillaGTK::Initialise() { gtk_widget_grab_focus(PWidget(wMain)); static const GtkTargetEntry targets[] = { + { "UTF8_STRING", 0, TARGET_UTF8_STRING }, { "STRING", 0, TARGET_STRING }, - { "TEXT", 0, TARGET_TEXT }, - { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, +// { "TEXT", 0, TARGET_TEXT }, +// { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, { "text/uri-list", 0, 0 }, }; static const gint n_targets = sizeof(targets) / sizeof(targets[0]); @@ -575,10 +585,11 @@ void ScintillaGTK::Initialise() { gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY, targets, n_targets); - if (!clipboard_atom) - clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE); + atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE); + atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE); + atomString = gdk_atom_intern("STRING", FALSE); - gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), clipboard_atom, + gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), atomClipboard, targets, n_targets); gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)), @@ -860,7 +871,6 @@ void ScintillaGTK::NotifyURIDropped(const char *list) { const char *CharacterSetID(int characterSet); #if GTK_MAJOR_VERSION >= 2 - #define IS_ACC(x) \ ((x) >= 65103 && (x) <= 65111) #define IS_CHAR(x) \ @@ -972,7 +982,7 @@ int ScintillaGTK::KeyDefault(int key, int modifiers) { void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) { copyText.Copy(selectedText.s, selectedText.len); gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)), - clipboard_atom, + atomClipboard, GDK_CURRENT_TIME); } @@ -980,7 +990,7 @@ void ScintillaGTK::Copy() { if (currentPos != anchor) { CopySelectionRange(©Text); gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)), - clipboard_atom, + atomClipboard, GDK_CURRENT_TIME); #if PLAT_GTK_WIN32 if (selType == selRectangle) { @@ -993,9 +1003,9 @@ void ScintillaGTK::Copy() { } void ScintillaGTK::Paste() { + atomSought = atomUTF8; gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), - clipboard_atom, - gdk_atom_intern("STRING", FALSE), GDK_CURRENT_TIME); + atomClipboard, atomSought, GDK_CURRENT_TIME); } void ScintillaGTK::CreateCallTipWindow(PRectangle rc) { @@ -1066,74 +1076,124 @@ void ScintillaGTK::ClaimSelection() { } } -char *ScintillaGTK::GetGtkSelectionText(const GtkSelectionData *selectionData, - unsigned int* len, bool* isRectangular) { - char *dest; - unsigned int i; - const char *sptr; - char *dptr; +#if !PLAT_GTK_WIN32 +static char *ConvertText(size_t *lenResult, char *s, size_t len, const char *charSetDest, const char *charSetSource) { + *lenResult = 0; + char *destForm = 0; + iconv_t iconvh = iconv_open(charSetDest, charSetSource); + if (iconvh != ((iconv_t)(-1))) { + destForm = new char[len*3+1]; + char *pin = s; + size_t inLeft = len; + char *pout = destForm; + size_t outLeft = len*3+1; + size_t conversions = iconv(iconvh, &pin, &inLeft, &pout, &outLeft); + if (conversions == ((size_t)(-1))) { +fprintf(stderr, "iconv failed for %s\n", static_cast<char *>(s)); + delete []destForm; + destForm = 0; + } else { +//fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm); + *pout = '\0'; + *lenResult = pout - destForm; + } + iconv_close(iconvh); + } else { +//fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource); + } + if (!destForm) { + destForm = new char[1]; + destForm[0] = '\0'; + *lenResult = 0; + } + return destForm; +} +#endif + +// Detect rectangular text, convert line ends to current mode, convert from or to UTF-8 +void ScintillaGTK::GetGtkSelectionText(const GtkSelectionData *selectionData, SelectionText &selText) { + char *data = reinterpret_cast<char *>(selectionData->data); + size_t len = selectionData->length; + GdkAtom selectionType = selectionData->type; // Return empty string if selection is not a string - if (selectionData->type != GDK_TARGET_STRING) { - dest = new char[1]; - strcpy(dest, ""); - *isRectangular = false; - *len = 0; - return dest; + if ((selectionType != GDK_TARGET_STRING) && (selectionType != atomUTF8)) { + char *empty = new char[1]; + empty[0] = '\0'; + selText.Set(empty,0); + return; } + // Check for "\n\0" ending to string indicating that selection is rectangular + bool isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n')); + // Need to convert to correct newline form for this file: win32gtk *always* returns // only \n line delimiter from clipboard, and linux/unix gtk may also not send the // form that matches the document (this is probably not effectively standardized by X) - dest = new char[(2 * static_cast<unsigned int>(selectionData->length)) + 1]; - sptr = reinterpret_cast<const char *>(selectionData->data); - dptr = dest; - for (i = 0; i < static_cast<unsigned int>(selectionData->length) && *sptr != '\0'; i++) { + char *dest = new char[2 * len + 1]; + const char *sptr = data; + char *dptr = dest; + for (size_t i = 0; (i < len) && (*sptr != '\0'); i++) { if (*sptr == '\n' || *sptr == '\r') { if (pdoc->eolMode == SC_EOL_CR) { *dptr++ = '\r'; - } - else if (pdoc->eolMode == SC_EOL_LF) { + } else if (pdoc->eolMode == SC_EOL_LF) { *dptr++ = '\n'; - } - else { // pdoc->eolMode == SC_EOL_CRLF + } else { // pdoc->eolMode == SC_EOL_CRLF *dptr++ = '\r'; *dptr++ = '\n'; } - if (*sptr == '\r' && i+1 < static_cast<unsigned int>(selectionData->length) && *(sptr+1) == '\n') { + if ((*sptr == '\r') && (i+1 < len) && (*(sptr+1) == '\n')) { i++; sptr++; } sptr++; - } - else { + } else { *dptr++ = *sptr++; } } *dptr++ = '\0'; - - *len = (dptr - dest) - 1; - - // Check for "\n\0" ending to string indicating that selection is rectangular -#if PLAT_GTK_WIN32 - *isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0; -#else - *isRectangular = ((selectionData->length > 2) && - (selectionData->data[selectionData->length - 1] == 0 && - selectionData->data[selectionData->length - 2] == '\n')); + len = (dptr - dest) - 1; + selText.Set(dest, len, isRectangular); + +#if !PLAT_GTK_WIN32 + // Possible character set conversion + const char *charSetBuffer = + CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet); + if (*charSetBuffer) { + if (IsUnicodeMode()) { + if (selectionType == GDK_TARGET_STRING) { + // Convert to UTF-8 +//fprintf(stderr, "Convert to UTF-8 from %s\n", charSetBuffer); + dest = ConvertText(&len, dest, len, "UTF8", charSetBuffer); + selText.Set(dest, len, isRectangular); + } + } else { + if (selectionType == atomUTF8) { +//fprintf(stderr, "Convert to locale %s\n", charSetBuffer); + // Convert to locale + dest = ConvertText(&len, dest, len, charSetBuffer, "UTF8"); + selText.Set(dest, len, isRectangular); + } + } + } #endif - return dest; } void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) { - if (selection_data->type == GDK_TARGET_STRING) { - //Platform::DebugPrintf("Received String Selection %x %d\n", selection_data->selection, selection_data->length); - if (((selection_data->selection == clipboard_atom) || - (selection_data->selection == GDK_SELECTION_PRIMARY)) && - (selection_data->length > 0)) { - unsigned int len; - bool isRectangular; - char *ptr = GetGtkSelectionText(selection_data, &len, &isRectangular); + if ((selection_data->selection == atomClipboard) || + (selection_data->selection == GDK_SELECTION_PRIMARY)) { + if ((atomSought == atomUTF8) && (selection_data->length <= 0)) { + atomSought = atomString; + gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), + atomClipboard, atomSought, GDK_CURRENT_TIME); + } else if ((selection_data->length > 0) && + ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8))) { + SelectionText selText; + GetGtkSelectionText(selection_data, selText); +#if PLAT_GTK_WIN32 + selText.rectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0; +#endif pdoc->BeginUndoAction(); int selStart = SelectionStart(); @@ -1141,28 +1201,27 @@ void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) { ClearSelection(); } - if (isRectangular) { - PasteRectangular(selStart, ptr, len); + if (selText.rectangular) { + PasteRectangular(selStart, selText.s, selText.len); } else { - pdoc->InsertString(currentPos, ptr, len); - SetEmptySelection(currentPos + len); + pdoc->InsertString(currentPos, selText.s, selText.len); + SetEmptySelection(currentPos + selText.len); } pdoc->EndUndoAction(); - delete []ptr; } } +// else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type), +// (int)(atomUTF8)); Redraw(); } void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) { dragWasDropped = true; - if (selection_data->type == GDK_TARGET_STRING) { + if ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8)) { if (selection_data->length > 0) { - unsigned int len; - bool isRectangular; - char *ptr = GetGtkSelectionText(selection_data, &len, &isRectangular); - DropAt(posDrop, ptr, false, isRectangular); - delete []ptr; + SelectionText selText; + GetGtkSelectionText(selection_data, selText); + DropAt(posDrop, selText.s, false, selText.rectangular); } } else { char *ptr = reinterpret_cast<char *>(selection_data->data); @@ -1192,11 +1251,9 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se if (pdoc->eolMode == SC_EOL_CR && *sptr == '\r') { *dptr++ = '\n'; sptr++; - } - else if (pdoc->eolMode != SC_EOL_CR && *sptr == '\r') { + } else if (pdoc->eolMode != SC_EOL_CR && *sptr == '\r') { sptr++; - } - else { + } else { *dptr++ = *sptr++; } } @@ -1204,8 +1261,31 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se selBuffer = tmpstr; #endif - if (info == TARGET_STRING) { - int len = strlen(selBuffer); + char *tmputf = 0; + if ((info == TARGET_UTF8_STRING) || (info == TARGET_STRING)) { + size_t len = strlen(selBuffer); +#if !PLAT_GTK_WIN32 + // Possible character set conversion + const char *charSetBuffer = + CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet); + if (info == TARGET_UTF8_STRING) { + //fprintf(stderr, "Copy to clipboard as UTF-8\n"); + if (!IsUnicodeMode()) { + // Convert to UTF-8 + //fprintf(stderr, "Convert to UTF-8 from %s\n", charSetBuffer); + tmputf = ConvertText(&len, selBuffer, len, "UTF8", charSetBuffer); + selBuffer = tmputf; + } + } else if (info == TARGET_STRING) { + if (IsUnicodeMode()) { + //fprintf(stderr, "Convert to locale %s\n", charSetBuffer); + // Convert to locale + tmputf = ConvertText(&len, selBuffer, len, charSetBuffer, "UTF8"); + selBuffer = tmputf; + } + } +#endif + // Here is a somewhat evil kludge. // As I can not work out how to store data on the clipboard in multiple formats // and need some way to mark the clipping as being stream or rectangular, @@ -1217,7 +1297,9 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se if (text->rectangular) len++; #endif - gtk_selection_data_set(selection_data, GDK_SELECTION_TYPE_STRING, + gtk_selection_data_set(selection_data, + (info == TARGET_STRING) ? + GDK_SELECTION_TYPE_STRING : atomUTF8, 8, reinterpret_cast<unsigned char *>(selBuffer), len); } else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT)) { @@ -1232,6 +1314,7 @@ void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, Se gdk_free_compound_text(text); } + delete []tmputf; #if PLAT_GTK_WIN32 delete []tmpstr; #endif @@ -1356,8 +1439,9 @@ gint ScintillaGTK::PressThis(GdkEventButton *event) { CopySelectionRange(&primary); SetSelection(pos, pos); + atomSought = atomUTF8; gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY, - gdk_atom_intern("STRING", FALSE), event->time); + atomSought, event->time); } else if (event->button == 3) { if (displayPopupMenu) { // PopUp menu |