diff options
Diffstat (limited to 'gtk')
| -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 | 
