diff options
| -rw-r--r-- | macosx/ExtInput.cxx | 608 | ||||
| -rw-r--r-- | macosx/ExtInput.h | 64 | ||||
| -rw-r--r-- | macosx/PlatMacOSX.cxx | 395 | ||||
| -rw-r--r-- | macosx/PlatMacOSX.h | 6 | ||||
| -rw-r--r-- | macosx/QuartzTextLayout.h | 57 | ||||
| -rw-r--r-- | macosx/QuartzTextStyle.h | 27 | ||||
| -rw-r--r-- | macosx/QuartzTextStyleAttribute.h | 24 | ||||
| -rw-r--r-- | macosx/ScintillaMacOSX.cxx | 837 | ||||
| -rw-r--r-- | macosx/ScintillaMacOSX.h | 54 | ||||
| -rw-r--r-- | macosx/TView.cxx | 132 | ||||
| -rw-r--r-- | macosx/makefile | 15 | 
11 files changed, 1482 insertions, 737 deletions
| diff --git a/macosx/ExtInput.cxx b/macosx/ExtInput.cxx new file mode 100644 index 000000000..677a82c3f --- /dev/null +++ b/macosx/ExtInput.cxx @@ -0,0 +1,608 @@ +/******************************************************************************* + +Copyright (c) 2007 Adobe Systems Incorporated + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +********************************************************************************/ + +#include "ScintillaMacOSX.h" +#include "ExtInput.h" + +using namespace Scintilla; + +// uncomment this for a log to /dev/console +// #define LOG_TSM 1 + +#if LOG_TSM +FILE* logFile = NULL; +#endif + +static EventHandlerUPP tsmHandler; + +static EventTypeSpec	tsmSpecs[] = { +	{ kEventClassTextInput, kEventTextInputUpdateActiveInputArea }, +//	{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, +	{ kEventClassTextInput, kEventTextInputOffsetToPos }, +	{ kEventClassTextInput, kEventTextInputPosToOffset }, +	{ kEventClassTextInput, kEventTextInputGetSelectedText } +}; + +#define kScintillaTSM	'ScTs' + +// The following structure is attached to the HIViewRef as property kScintillaTSM + +struct TSMData +{ +	HIViewRef			view;				// this view +	TSMDocumentID		docid;				// the TSM document ID +	EventHandlerRef		handler;			// the event handler +	ScintillaMacOSX*	scintilla;			// the Scintilla pointer +	int					styleMask;			// the document style mask +	int					indicStyle [3];		// indicator styles save +	int					indicColor [3];		// indicator colors save +	int					selStart;			// starting position of selection (Scintilla offset) +	int					selLength;			// UTF-8 number of characters +	int					selCur;				// current position (Scintilla offset) +	int					inhibitRecursion;	// true to stop recursion +	bool				active;				// true if this is active +}; + +static const int numSpecs = 5; + + +// Fetch a range of text as UTF-16; delete the buffer after use + +static char* getTextPortion (TSMData* data, UInt32 start, UInt32 size) +{ +	Scintilla::TextRange range; +	range.chrg.cpMin = start; +	range.chrg.cpMax = start + size; +	range.lpstrText = new char [size + 1]; +	range.lpstrText [size] = 0; +	data->scintilla->WndProc (SCI_GETTEXTRANGE, 0, (uptr_t) &range); +	return range.lpstrText; +} + +static pascal OSStatus doHandleTSM (EventHandlerCallRef, EventRef inEvent, void* userData); + +void ExtInput::attach (HIViewRef viewRef) +{ +	if (NULL == tsmHandler) +		tsmHandler = NewEventHandlerUPP (doHandleTSM); +	::UseInputWindow (NULL, FALSE); + +#ifdef LOG_TSM +	if (NULL == logFile) +		logFile = fopen ("/dev/console", "a"); +#endif + +	// create and attach the TSM data +	TSMData* data = new TSMData; + +	data->view				= viewRef; +	data->active			= false; +	data->inhibitRecursion	= 0; +	 +	::GetControlProperty (viewRef, scintillaMacOSType, 0, sizeof( data->scintilla ), NULL, &data->scintilla); +	 +	if (NULL != data->scintilla) +	{ +		// create the TSM document ref +		InterfaceTypeList interfaceTypes; +		interfaceTypes[0] = kUnicodeDocumentInterfaceType; +		::NewTSMDocument (1, interfaceTypes, &data->docid, (long) viewRef); +		// install my event handler +		::InstallControlEventHandler (viewRef, tsmHandler, numSpecs, tsmSpecs, data, &data->handler); + +		::SetControlProperty (viewRef, kScintillaTSM, 0, sizeof (data), &data); +	} +	else +		delete data; +} + +static TSMData* getTSMData (HIViewRef viewRef) +{ +	TSMData* data = NULL; +	UInt32 n; +	::GetControlProperty (viewRef, kScintillaTSM, 0, sizeof (data), &n, (UInt32*) &data); +	return data; +} + +void ExtInput::detach (HIViewRef viewRef) +{ +	TSMData* data = getTSMData (viewRef); +	if (NULL != data) +	{ +		::DeleteTSMDocument (data->docid); +		::RemoveEventHandler (data->handler); +		delete data; +	} +} + +void ExtInput::activate (HIViewRef viewRef, bool on) +{ +	TSMData* data = getTSMData (viewRef); +	if (NULL == data) +		return; + +	if (on) +	{ +		::ActivateTSMDocument (data->docid); +		HIRect bounds; +		::HIViewGetBounds (viewRef, &bounds); +		::HIViewConvertRect (&bounds, viewRef, NULL); +		RgnHandle hRgn = ::NewRgn(); +		::SetRectRgn (hRgn, (short) bounds.origin.x, (short) bounds.origin.y,  +							(short) (bounds.origin.x + bounds.size.width),  +							(short) (bounds.origin.y + bounds.size.height)); +#if LOG_TSM +		fprintf (logFile, "TSMSetInlineInputRegion (%08lX, %ld:%ld-%ld:%ld)\n",  +						 (long) data->docid, (long) bounds.origin.x, (long) bounds.origin.y, +						 (long) (bounds.origin.x + bounds.size.width), (long) (bounds.origin.y + bounds.size.height)); +		fflush (logFile); +#endif +		::TSMSetInlineInputRegion (data->docid, HIViewGetWindow (data->view), hRgn); +		::DisposeRgn (hRgn); +		::UseInputWindow (NULL, FALSE); +	} +	else +	{ +#if LOG_TSM +		fprintf (logFile, "DeactivateTSMDocument (%08lX)\n", (long) data->docid); +		fflush (logFile); +#endif +		::DeactivateTSMDocument (data->docid); +	} +} + +static void startInput (TSMData* data, bool delSelection = true) +{ +	if (!data->active && 0 == data->inhibitRecursion) +	{ +		data->active = true; +		 +		// Delete any selection +		if( delSelection ) +			data->scintilla->WndProc (SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>("")); +		  +		// need all style bits because we do indicators +		data->styleMask = data->scintilla->WndProc (SCI_GETSTYLEBITS, 0, 0); +		data->scintilla->WndProc (SCI_SETSTYLEBITS, 5, 0); +		 +		// Set the target range for successive replacements +		data->selStart	= +		data->selCur	= data->scintilla->WndProc (SCI_GETCURRENTPOS, 0, 0); +		data->selLength	= 0; +		 +		// save needed styles +		for (int i = 0; i < 2; i++) +		{ +			data->indicStyle [i] = data->scintilla->WndProc (SCI_INDICGETSTYLE, i, 0); +			data->indicColor [i] = data->scintilla->WndProc (SCI_INDICGETFORE, i, 0); +		} +		// set styles and colors +		data->scintilla->WndProc (SCI_INDICSETSTYLE, 0, INDIC_SQUIGGLE); +		data->scintilla->WndProc (SCI_INDICSETFORE,  0, 0x808080); +		data->scintilla->WndProc (SCI_INDICSETSTYLE, 1, INDIC_PLAIN);	// selected converted +		data->scintilla->WndProc (SCI_INDICSETFORE,  1, 0x808080); +		data->scintilla->WndProc (SCI_INDICSETSTYLE, 2, INDIC_PLAIN);	// selected raw +		data->scintilla->WndProc (SCI_INDICSETFORE,  2, 0x0000FF); +		// stop Undo +		data->scintilla->WndProc (SCI_BEGINUNDOACTION, 0, 0); +	} +} + +static void stopInput (TSMData* data, int pos) +{ +	if (data->active && 0 == data->inhibitRecursion) +	{ +		// First fix the doc - this may cause more messages +		// but do not fall into recursion +		data->inhibitRecursion++; +		::FixTSMDocument (data->docid); +		data->inhibitRecursion--; +		data->active = false; +		 +		// Remove indicator styles +		data->scintilla->WndProc (SCI_STARTSTYLING, data->selStart, INDICS_MASK); +		data->scintilla->WndProc (SCI_SETSTYLING, pos - data->selStart, 0); +		// Restore old indicator styles and colors +		data->scintilla->WndProc (SCI_SETSTYLEBITS, data->styleMask, 0); +		for (int i = 0; i < 2; i++) +		{ +			data->scintilla->WndProc (SCI_INDICSETSTYLE, i, data->indicStyle [i]); +			data->scintilla->WndProc (SCI_INDICSETFORE, i, data->indicColor [i]); +		} + +		// remove selection and re-allow selections to display +		data->scintilla->WndProc (SCI_SETSEL, pos, pos); +		data->scintilla->WndProc (SCI_TARGETFROMSELECTION, 0, 0); +		data->scintilla->WndProc (SCI_HIDESELECTION, 0, 0); + +		// move the caret behind the current area +		data->scintilla->WndProc (SCI_SETCURRENTPOS, pos, 0); +		// re-enable Undo +		data->scintilla->WndProc (SCI_ENDUNDOACTION, 0, 0); +		// re-colorize +		int32_t startLine = data->scintilla->WndProc (SCI_LINEFROMPOSITION, data->selStart, 0); +		int32_t startPos  = data->scintilla->WndProc (SCI_POSITIONFROMLINE, startLine, 0); +		int32_t endLine   = data->scintilla->WndProc (SCI_LINEFROMPOSITION, pos, 0); +		if (endLine == startLine) +			endLine++; +		int32_t endPos    = data->scintilla->WndProc (SCI_POSITIONFROMLINE, endLine, 0); +		 +		data->scintilla->WndProc (SCI_COLOURISE, startPos, endPos); +	} +} + +void ExtInput::stop (HIViewRef viewRef) +{ +	TSMData* data = getTSMData (viewRef); +	if (NULL != data) +		stopInput (data, data->selStart + data->selLength); +} + +static char* UTF16toUTF8 (const UniChar* buf, int len, int& utf8len) +{ +	CFStringRef str = CFStringCreateWithCharactersNoCopy (NULL, buf, (UInt32) len, kCFAllocatorNull); +	CFRange range = { 0, len }; +	CFIndex bufLen; +	CFStringGetBytes (str, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &bufLen); +	UInt8* utf8buf = new UInt8 [bufLen+1]; +	CFStringGetBytes (str, range, kCFStringEncodingUTF8, '?', false, utf8buf, bufLen, NULL); +	utf8buf [bufLen] = 0; +	CFRelease (str); +	utf8len = (int) bufLen; +	return (char*) utf8buf; +} + +static int UCS2Length (const char* buf, int len) +{ +	int n = 0; +	while (len > 0) +	{ +		int bytes = 0; +		char ch = *buf; +		while (ch & 0x80) +			bytes++, ch <<= 1; +		len -= bytes; +		n += bytes; +	} +	return n; +} + +static int UTF8Length (const UniChar* buf, int len) +{ +	int n = 0; +	while (len > 0) +	{ +		UInt32 uch = *buf++; +		len--; +		if (uch >= 0xD800 && uch <= 0xDBFF && len > 0) +		{ +			UInt32 uch2 = *buf; +			if (uch2 >= 0xDC00 && uch2 <= 0xDFFF) +			{ +				buf++; +				len--; +				uch = ((uch & 0x3FF) << 10) + (uch2 & 0x3FF); +			} +		} +		n++; +		if (uch > 0x7F) +			n++; +		if (uch > 0x7FF) +			n++; +		if (uch > 0xFFFF) +			n++; +		if (uch > 0x1FFFFF) +			n++; +		if (uch > 0x3FFFFFF) +			n++; +	} +	return n; +} + +static OSStatus handleTSMUpdateActiveInputArea (TSMData* data, EventRef inEvent) +{ +	UInt32				fixLength; +	int					caretPos = -1; +	UInt32				actualSize; +	::TextRangeArray*	hiliteRanges = NULL; +	char*				hiliteBuffer = NULL; +	bool				done; +	 +	// extract the text +	UniChar* buffer = NULL; +	UniChar temp [128]; +	UniChar* text = temp; +	 +	// get the fix length (in bytes) +	OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendFixLen, +								   typeLongInteger, NULL, sizeof (long), NULL, &fixLength); +	// need the size (in bytes) +	if (noErr == err) +		err = ::GetEventParameter (inEvent, kEventParamTextInputSendText, +										typeUnicodeText, NULL, 256, &actualSize, temp); +										 +	// then allocate and fetch if necessary +	UInt32 textLength = actualSize / sizeof (UniChar); +	fixLength /= sizeof (UniChar); + +	if (noErr == err) +	{ +		// this indicates that we are completely done +		done = (fixLength == textLength || fixLength < 0); +		if (textLength >= 128) +		{ +			buffer = text = new UniChar [textLength]; +			err = ::GetEventParameter (inEvent, kEventParamTextInputSendText, +									   typeUnicodeText, NULL, actualSize, NULL, (void*) text); +		} +		 +		// set the text now, but convert it to UTF-8 first +		int utf8len; +		char* utf8 = UTF16toUTF8 (text, textLength, utf8len); +		data->scintilla->WndProc (SCI_SETTARGETSTART, data->selStart, 0); +		data->scintilla->WndProc (SCI_SETTARGETEND, data->selStart + data->selLength, 0); +		data->scintilla->WndProc (SCI_HIDESELECTION, 1, 0); +		data->scintilla->WndProc (SCI_REPLACETARGET, utf8len, (sptr_t) utf8); +		data->selLength = utf8len; +		delete [] utf8; +	} +	 +	// attempt to extract the array of hilite ranges +	if (noErr == err) +	{ +		::TextRangeArray tempTextRangeArray; +		OSStatus tempErr = ::GetEventParameter (inEvent, kEventParamTextInputSendHiliteRng, +											 typeTextRangeArray, NULL, sizeof (::TextRangeArray), &actualSize, &tempTextRangeArray); +		if (noErr == tempErr) +		{ +			// allocate memory and get the stuff! +			hiliteBuffer = new char [actualSize]; +			hiliteRanges = (::TextRangeArray*) hiliteBuffer; +			err = ::GetEventParameter (inEvent, kEventParamTextInputSendHiliteRng, +									   typeTextRangeArray, NULL, actualSize, NULL, hiliteRanges); +			if (noErr != err) +			{ +				delete [] hiliteBuffer; +				hiliteBuffer = NULL; +				hiliteRanges = NULL; +			} +		} +	} +#if LOG_TSM +	fprintf (logFile, "kEventTextInputUpdateActiveInputArea:\n" +					 "  TextLength = %ld\n" +					 "  FixLength = %ld\n", +					 (long) textLength, (long) fixLength); +	fflush (logFile); +#endif + +	if (NULL != hiliteRanges) +	{ +		for (int i = 0; i < hiliteRanges->fNumOfRanges; i++) +		{ +#if LOG_TSM +			fprintf (logFile, "  Range #%d: %ld-%ld (%d)\n", +								i+1, +								hiliteRanges->fRange[i].fStart, +								hiliteRanges->fRange[i].fEnd, +								hiliteRanges->fRange[i].fHiliteStyle); +			fflush (logFile); +#endif +			// start and end of range, zero based +			long bgn = long (hiliteRanges->fRange[i].fStart) / sizeof (UniChar); +			long end = long (hiliteRanges->fRange[i].fEnd) / sizeof (UniChar); +			if (bgn >= 0 && end >= 0) +			{ +				// move the caret if this is requested +				if (hiliteRanges->fRange[i].fHiliteStyle == kTSMHiliteCaretPosition) +					caretPos = bgn; +				else +				{ +					// determine which style to use +					int style; +					switch (hiliteRanges->fRange[i].fHiliteStyle) +					{ +						case kTSMHiliteRawText:					style = INDIC0_MASK; break; +						case kTSMHiliteSelectedRawText:			style = INDIC0_MASK; break; +						case kTSMHiliteConvertedText:			style = INDIC1_MASK; break; +						case kTSMHiliteSelectedConvertedText:	style = INDIC2_MASK; break; +						default:								style = INDIC0_MASK; +					} +					// bgn and end are Unicode offsets from the starting pos +					// use the text buffer to determine the UTF-8 offsets +					long utf8bgn  = data->selStart + UTF8Length (text, bgn); +					long utf8size = UTF8Length (text + bgn, end - bgn); +					// set indicators +					int oldEnd = data->scintilla->WndProc (SCI_GETENDSTYLED, 0, 0); +					data->scintilla->WndProc (SCI_STARTSTYLING, utf8bgn, INDICS_MASK); +					data->scintilla->WndProc (SCI_SETSTYLING, utf8size, style & ~1); +					data->scintilla->WndProc (SCI_STARTSTYLING, oldEnd, 31); +				} +			} +		} +	} +	if (noErr == err) +	{ +		// if the fixed length is == to the new text, we are done +		if (done) +			stopInput (data, data->selStart + UTF8Length (text, textLength)); +		else if (caretPos >= 0) +		{ +			data->selCur = data->selStart + UTF8Length (text, caretPos); +			data->scintilla->WndProc (SCI_SETCURRENTPOS, data->selCur, 0); +		} +	} +	 +	delete [] hiliteBuffer; +	delete [] buffer; +	return err; +} + +struct MacPoint { +  short               v; +  short               h; +}; + +static OSErr handleTSMOffset2Pos (TSMData* data, EventRef inEvent) +{ +	long offset; +	 +	// get the offfset to convert +	OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendTextOffset, +										typeLongInteger, NULL, sizeof (long), NULL, &offset); +	if (noErr == err) +	{ +		// where is the caret now? +		HIPoint where; + +		int line = (int) data->scintilla->WndProc (SCI_LINEFROMPOSITION, data->selCur, 0); +		where.x = data->scintilla->WndProc (SCI_POINTXFROMPOSITION, 0, data->selCur); +		where.y = data->scintilla->WndProc (SCI_POINTYFROMPOSITION, 0, data->selCur) +				+ data->scintilla->WndProc (SCI_TEXTHEIGHT, line, 0); +		// convert to window coords +		::HIViewConvertPoint (&where, data->view, NULL); +		// convert to screen coords +		Rect global; +		GetWindowBounds (HIViewGetWindow (data->view), kWindowStructureRgn, &global); +		MacPoint pt; +		pt.h = (short) where.x + global.left; +		pt.v = (short) where.y + global.top; + +		// set the result +		err = ::SetEventParameter (inEvent, kEventParamTextInputReplyPoint, typeQDPoint, sizeof (MacPoint), &pt); +#if LOG_TSM +		fprintf (logFile, "kEventTextInputOffsetToPos:\n" +						 "  Offset: %ld\n" +						 "  Pos: %ld:%ld (orig = %ld:%ld)\n", offset,  +						 (long) pt.h, (long) pt.v, +						 (long) where.x, (long) where.y); +		fflush (logFile); +#endif +	} +	return err; +} + +static OSErr handleTSMPos2Offset (TSMData* data, EventRef inEvent) +{ +	MacPoint		qdPosition; +	long			offset; +	short			regionClass; +	 +	// retrieve the global point to convert +	OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendCurrentPoint, +										typeQDPoint, NULL, sizeof (MacPoint), NULL, &qdPosition); +	if (noErr == err) +	{ +#if LOG_TSM +		fprintf (logFile, "kEventTextInputPosToOffset:\n" +						 "  Pos: %ld:%ld\n", (long) qdPosition.v, (long) qdPosition.h); +		fflush (logFile); +#endif +		// convert to local coordinates +		HIRect rect; +		rect.origin.x = qdPosition.h; +		rect.origin.y = qdPosition.v; +		rect.size.width = +		rect.size.height = 1; +		::HIViewConvertRect (&rect, NULL, data->view); + +		// we always report the position to be within the composition; +		// coords inside the same pane are clipped to the composition, +		// and if the position is outside, then we deactivate this instance +		// this leaves the edit open and active so we can edit multiple panes +		regionClass = kTSMInsideOfActiveInputArea; +		 +		// compute the offset (relative value) +		offset = data->scintilla->WndProc (SCI_POSITIONFROMPOINTCLOSE, (uptr_t) rect.origin.x, (sptr_t) rect.origin.y); +		if (offset >= 0) +		{ +			// convert to a UTF-16 offset (Brute Force) +			char* buf = getTextPortion (data, 0, offset); +			offset = UCS2Length (buf, offset); +			delete [] buf; +			 +#if LOG_TSM +			fprintf (logFile, "  Offset: %ld (class %ld)\n", offset, (long) regionClass); +			fflush (logFile); +#endif +			// store the offset +			err = ::SetEventParameter (inEvent, kEventParamTextInputReplyTextOffset, typeLongInteger, sizeof (long), &offset); +			if (noErr == err) +				err = ::SetEventParameter (inEvent, kEventParamTextInputReplyRegionClass, typeShortInteger, sizeof (short), ®ionClass); +		} +		else +		{ +			// not this pane! +			err = eventNotHandledErr; +			ExtInput::activate (data->view, false); +		} +			 +	} +	return err;	 +} + +static OSErr handleTSMGetText (TSMData* data, EventRef inEvent) +{ +	char* buf = getTextPortion (data, data->selStart, data->selLength); +		 +#if LOG_TSM +		fprintf (logFile, "kEventTextInputGetSelectedText:\n" +						  "  Text: \"%s\"\n", buf); +		fflush (logFile); +#endif +	OSStatus status = ::SetEventParameter (inEvent, kEventParamTextInputReplyText, typeUTF8Text, data->selLength, buf); +	delete [] buf; +	return status; +}		 + +static pascal OSStatus doHandleTSM (EventHandlerCallRef, EventRef inEvent, void* userData) +{ +	TSMData* data = (TSMData*) userData; +	 +	OSStatus err = eventNotHandledErr; + +	switch (::GetEventKind (inEvent)) +	{ +		case kEventTextInputUpdateActiveInputArea: +			// Make sure that input has been started +			startInput (data); +			err = handleTSMUpdateActiveInputArea (data, inEvent); +			break; +//		case kEventTextInputUnicodeForKeyEvent: +//			err = handleTSMUnicodeInput (inEvent); +//			break; +		case kEventTextInputOffsetToPos: +			err = handleTSMOffset2Pos (data, inEvent); +			break; +		case kEventTextInputPosToOffset: +			err = handleTSMPos2Offset (data, inEvent); +			break; +		case kEventTextInputGetSelectedText: +			// Make sure that input has been started +			startInput (data, false); +			err = handleTSMGetText (data, inEvent); +			break; +	} +	return err; +} + diff --git a/macosx/ExtInput.h b/macosx/ExtInput.h new file mode 100644 index 000000000..0179e83b9 --- /dev/null +++ b/macosx/ExtInput.h @@ -0,0 +1,64 @@ +/******************************************************************************* + +Copyright (c) 2007 Adobe Systems Incorporated + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +********************************************************************************/ + +#ifndef _ExtInput_h +#define _ExtInput_h + +#include <Carbon/Carbon.h> +#include "Scintilla.h" + +namespace Scintilla +{ + +/** +The ExtInput class provides TSM input services to Scintilla. +It uses the indicators 0 and 1 (see SCI_INDICSETSTYLE) to apply +underlines to partially converted text. +*/ + +class ExtInput +{ +public: +	/** +	Attach extended input to a HIView with attached Scintilla. This installs the needed +	event handlers etc. +	*/ +	static	void		attach (HIViewRef ref); +	/** +	Detach extended input from a HIViewwith attached Scintilla.  +	*/ +	static	void		detach (HIViewRef ref); +	/** +	Activate or deactivate extended input. This method should be called whenever +	the view gains or loses focus. +	*/ +	static	void		activate (HIViewRef ref, bool on); +	/** +	Terminate extended input. +	*/ +	static	void		stop (HIViewRef ref); +}; + +}	// end namespace + +#endif diff --git a/macosx/PlatMacOSX.cxx b/macosx/PlatMacOSX.cxx index 631e0d95e..f8282c5f8 100644 --- a/macosx/PlatMacOSX.cxx +++ b/macosx/PlatMacOSX.cxx @@ -109,29 +109,24 @@ void Font::Release() {  SurfaceImpl::SurfaceImpl() {      bitmapData = NULL; // Release will try and delete bitmapData if != NULL -#ifdef SUPPORT_PORT -    port = NULL; -#endif      gc = NULL; +    textLayout = new QuartzTextLayout(NULL);      Release();  }  SurfaceImpl::~SurfaceImpl() {      Release(); +    delete textLayout;  }  void SurfaceImpl::Release() { +    textLayout->setContext (NULL);      if ( bitmapData != NULL )          {          delete[] bitmapData;          // We only "own" the graphics context if we are a bitmap context          if ( gc != NULL ) CGContextRelease( gc );          } -#ifdef SUPPORT_PORT -    if ( port != NULL && gc != NULL) { -      QDEndCGContext(port, &gc); -    } -#endif      bitmapData = NULL;      gc = NULL; @@ -155,20 +150,13 @@ void SurfaceImpl::Init(WindowID /*wid*/) {      // aquire/release of the context.      Release(); -#ifdef SUPPORT_PORT -    // Note, this seems to be unecessary, I have not seen any functionality loss by -    // doing nothing in this method. - -    WindowRef window = GetControlOwner(reinterpret_cast<HIViewRef>(wid)); -    port = GetWindowPort(window); -    QDBeginCGContext(port, &gc); -#endif  }  void SurfaceImpl::Init(SurfaceID sid, WindowID /*wid*/) {      Release();      gc = reinterpret_cast<CGContextRef>( sid );      CGContextSetLineWidth( gc, 1.0 ); +    textLayout->setContext (gc);  }  void SurfaceImpl::InitPixMap(int width, int height, Surface* /*surface_*/, WindowID /*wid*/) { @@ -182,13 +170,12 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface* /*surface_*/, Windo      // create an RGB color space      CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); -    assert( colorSpace != NULL ); +    if( colorSpace == NULL ) +        return;      // create the bitmap      bitmapData = new uint8_t[ bitmapByteCount ]; -    assert( bitmapData != NULL ); -    if( bitmapData != NULL ) -        { +    if( bitmapData != NULL ) {          // create the context          gc = CGBitmapContextCreate( bitmapData,                                      width, @@ -198,24 +185,25 @@ void SurfaceImpl::InitPixMap(int width, int height, Surface* /*surface_*/, Windo                                      colorSpace,                                      kCGImageAlphaPremultipliedLast); -        if( gc == NULL ) -            { +        if( gc == NULL ) {              // the context couldn't be created for some reason,              // and we have no use for the bitmap without the context              delete[] bitmapData;              bitmapData = NULL; -            }          } +        textLayout->setContext (gc); +    }      // the context retains the color space, so we can release it      CGColorSpaceRelease( colorSpace ); -    assert( gc != NULL && bitmapData != NULL ); - -    // "Erase" to white -    CGContextClearRect( gc, CGRectMake( 0, 0, width, height ) ); -    CGContextSetRGBFillColor( gc, 1.0, 1.0, 1.0, 1.0 ); -    CGContextFillRect( gc, CGRectMake( 0, 0, width, height ) ); +    if ( gc != NULL && bitmapData != NULL ) +    { +        // "Erase" to white +        CGContextClearRect( gc, CGRectMake( 0, 0, width, height ) ); +        CGContextSetRGBFillColor( gc, 1.0, 1.0, 1.0, 1.0 ); +        CGContextFillRect( gc, CGRectMake( 0, 0, width, height ) ); +    }  }  void SurfaceImpl::PenColour(ColourAllocated fore) { @@ -244,28 +232,30 @@ CGImageRef SurfaceImpl::GetImage() {      // create an RGB color space      CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); -    assert( colorSpace != NULL ); +    if( colorSpace == NULL ) +        return NULL;      const int bitmapBytesPerRow   = ((int) bitmapWidth * BYTES_PER_PIXEL);      const int bitmapByteCount     = (bitmapBytesPerRow * (int) bitmapHeight);      // Create a data provider      CGDataProviderRef dataProvider = CGDataProviderCreateWithData( NULL, bitmapData, bitmapByteCount, NULL ); -    assert( dataProvider != NULL ); - -    // create the CGImage -    CGImageRef image = CGImageCreate( bitmapWidth, -                                   bitmapHeight, -                                   BITS_PER_COMPONENT, -                                   BITS_PER_PIXEL, -                                   bitmapBytesPerRow, -                                   colorSpace, -                                   kCGImageAlphaPremultipliedLast, -                                   dataProvider, -                                   NULL, -                                   0, -                                   kCGRenderingIntentDefault ); -    assert( image != NULL ); +    CGImageRef image = NULL; +    if ( dataProvider != NULL ) +    { +        // create the CGImage +        image = CGImageCreate( bitmapWidth, +                            bitmapHeight, +                            BITS_PER_COMPONENT, +                            BITS_PER_PIXEL, +                            bitmapBytesPerRow, +                            colorSpace, +                            kCGImageAlphaPremultipliedLast, +                            dataProvider, +                            NULL, +                            0, +                            kCGRenderingIntentDefault ); +    }      // the image retains the color space, so we can release it      CGColorSpaceRelease( colorSpace ); @@ -379,8 +369,6 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {          return;          } -    assert( image != NULL ); -      const CGPatternCallbacks drawImageCallbacks = { 0, reinterpret_cast<CGPatternDrawPatternCallback>( drawImageRefCallback ), NULL };      CGPatternRef pattern = CGPatternCreate( image, @@ -392,30 +380,30 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {                                           true,                                           &drawImageCallbacks                                           ); -    assert( pattern != NULL ); - -    // Create a pattern color space -    CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern( NULL ); -    assert( colorSpace != NULL ); - -    CGContextSaveGState( gc ); -    CGContextSetFillColorSpace( gc, colorSpace ); - -    // Unlike the documentation, you MUST pass in a "components" parameter: -    // For coloured patterns it is the alpha value. -    const float alpha = 1.0; -    CGContextSetFillPattern( gc, pattern, &alpha ); -    CGContextFillRect( gc, PRectangleToCGRect( rc ) ); - -    CGContextRestoreGState( gc ); - -    // Free the color space, the pattern and image -    CGColorSpaceRelease( colorSpace ); -    colorSpace = NULL; -    CGPatternRelease( pattern ); -    pattern = NULL; -    CGImageRelease( image ); -    image = NULL; +    if( pattern != NULL ) { + +        // Create a pattern color space +        CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern( NULL ); +        if( colorSpace != NULL ) { + +            CGContextSaveGState( gc ); +            CGContextSetFillColorSpace( gc, colorSpace ); + +            // Unlike the documentation, you MUST pass in a "components" parameter: +            // For coloured patterns it is the alpha value. +            const float alpha = 1.0; +            CGContextSetFillPattern( gc, pattern, &alpha ); +            CGContextFillRect( gc, PRectangleToCGRect( rc ) ); +            CGContextRestoreGState( gc ); +            // Free the color space, the pattern and image +            CGColorSpaceRelease( colorSpace ); +        } /* colorSpace != NULL */ +        colorSpace = NULL; +        CGPatternRelease( pattern ); +        pattern = NULL; +        CGImageRelease( image ); +        image = NULL; +    } /* pattern != NULL */  }  void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { @@ -480,20 +468,16 @@ void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAl      CGContextDrawPath( gc, kCGPathFillStroke );  } -void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, -        ColourAllocated outline, int alphaOutline, int flags) { -    // XXX TODO +void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, ColourAllocated fill, int alphaFill, +                                            ColourAllocated /*outline*/, int /*alphaOutline*/, int /*flags*/) +{      if ( gc ) { -        CGContextBeginPath( gc ); -        //FillColour(fill); -        PenColour(outline); +        ColourDesired colour( fill.AsLong() ); -        // Quartz integer -> float point conversion fun (see comment in SurfaceImpl::LineTo) -        // We subtract 1 from the Width() and Height() so that all our drawing is within the area defined -        // by the PRectangle. Otherwise, we draw one pixel too far to the right and bottom. -        // TODO: Create some version of PRectangleToCGRect to do this conversion for us? -        CGContextAddRect( gc, CGRectMake( rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1 ) ); -        CGContextDrawPath( gc, kCGPathFill ); +        // Set the Fill color to match +        CGContextSetRGBFillColor( gc, colour.GetRed() / 255.0, colour.GetGreen() / 255.0, colour.GetBlue() / 255.0, alphaFill / 100.0 ); +        CGRect rect = PRectangleToCGRect( rc ); +        CGContextFillRect( gc, rect );      }  } @@ -597,8 +581,6 @@ void SurfaceImpl::Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSou          return;          } -    assert( image != NULL ); -      // Now draw the image on the surface      // Some fancy clipping work is required here: draw only inside of rc @@ -616,29 +598,6 @@ void SurfaceImpl::Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSou      image = NULL;  } -QuartzTextLayout* SurfaceImpl::GetTextLayout( Font &font_, const char *s, int len ) -{ -    // create the text layout -    QuartzTextLayout* textLayout = new QuartzTextLayout( gc ); -    OSStatus err = textLayout->setText( reinterpret_cast<const UInt8*>( s ), len, ( unicodeMode ? kCFStringEncodingUTF8 : kCFStringEncodingASCII ) ); -    if (err != noErr) { -        fprintf(stderr, "SurfaceImpl::GetTextLayout error calling textLayout->setText %d %s\n", err, unicodeMode?"Invalid UTF8":"Unknown error"); -        if (unicodeMode) -            err = textLayout->setText( reinterpret_cast<const UInt8*>( s ), len, kCFStringEncodingASCII ); -        if (err != noErr) -            return NULL; -    } - -    textLayout->setStyle( *reinterpret_cast<QuartzTextStyle*>( font_.GetID() ) ); - -    // TODO: If I could modify Scintilla to use ATSUHighlightText, this would not be required. -    // However, using this setting makes Scintilla's rendering match TextEdit's (except for the antialiasing rules) -    ATSLineLayoutOptions rendering = kATSLineUseDeviceMetrics; -    textLayout->setControl( kATSULineLayoutOptionsTag, sizeof( rendering ), &rendering ); - -    return textLayout; -} -  void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,                                   ColourAllocated fore, ColourAllocated back) { @@ -656,89 +615,80 @@ void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const c  }  void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { -    PLATFORM_ASSERT( gc != NULL ); -    QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); -    if (!textLayout) return; +    textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); +      // The Quartz RGB fill color influences the ATSUI color      FillColour(fore); -      // Draw the text, with the Y axis flipped      textLayout->draw( rc.left, ybase, true ); - -    // Get rid of the layout object -    delete textLayout; -    textLayout = NULL;  }  void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {      // sample at http://developer.apple.com/samplecode/ATSUICurveAccessDemo/listing1.html      // sample includes use of ATSUGetGlyphInfo which would be better for older      // OSX systems.  We should expand to using that on older systems as well. -    QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); -    if (!textLayout) return; - -    // Get the UNICODE character length -    UniCharCount unicodeLength, unicodePosition; -    OSStatus err; -    err = ATSUGetTextLocation( textLayout->getLayout(), NULL, NULL, NULL, &unicodeLength, NULL ); -    assert( err == noErr ); - -    ATSLayoutRecord *layoutRecords; -    ItemCount numRecords; -    // Get the arrays of glyph information -    verify_noerr( ATSUDirectGetLayoutDataArrayPtrFromTextLayout( -                textLayout->getLayout(), 0, -                kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, -                (void **)&layoutRecords, &numRecords) ); - -    int i, count; -    long position; -    unsigned char uch; -    unsigned char mask; -    FontID fontid = font_.GetID(); - -    for ( unicodePosition = 0, i = 0; i < len && unicodePosition < numRecords; unicodePosition ++ ) { -        if (fontid) { - -            // note: an extra layoutRecord is provided (eg. numRecords will be one -            //       more than unicodeLength).  Each record contains the left x -            //       coordinate, but we need the right x coordinate, so we skip -            //       the first layoutRecord, thus unicodePosition+1. -            position = Fix2Long( layoutRecords[unicodePosition+1].realPos ); -            uch = s[i]; -            positions[i++] = position; - -            // If we are using unicode (UTF8), map the Unicode position back to the UTF8 characters, -            // as 1 unicode character can map to multiple UTF8 characters. -            // See: http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF -            // Or: http://www.cl.cam.ac.uk/~mgk25/unicode.html -            if ( unicodeMode ) { -                mask = 0xc0; -                count = 1; -                // Add one additonal byte for each extra high order one in the byte -                while ( uch >= mask && count < 8 ) { -                    assert( i < len ); +    for (int i = 0; i < len; i++) +            positions [i] = 0; +             +    // We need the right X coords, so we have to append a char to get the left coord of thast extra char +    char* buf = (char*) malloc (len+1); +    if (!buf) +            return; +             +    memcpy (buf, s, len); +    buf [len] = '.'; +     +    textLayout->setText (reinterpret_cast<const UInt8*>(buf), len+1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); +    ATSUGlyphInfoArray* theGlyphInfoArrayPtr; +    ByteCount theArraySize; + +    // Get the GlyphInfoArray +    ATSUTextLayout layout = textLayout->getLayout(); +    if ( noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, NULL)) +    { +        theGlyphInfoArrayPtr = (ATSUGlyphInfoArray *) malloc (theArraySize + sizeof(ItemCount) + sizeof(ATSUTextLayout)); +        if (theGlyphInfoArrayPtr) +        { +            if (noErr == ATSUGetGlyphInfo (layout, 0, textLayout->getLength(), &theArraySize, theGlyphInfoArrayPtr)) +            { +                // do not count the first item, which is at the beginning of the line +                for ( UniCharCount unicodePosition = 1, i = 0; i < len && unicodePosition < theGlyphInfoArrayPtr->numGlyphs; unicodePosition ++ ) +                { +                    // The ideal position is the x coordinate of the glyph, relative to the beginning of the line +                    int position = (int)( theGlyphInfoArrayPtr->glyphs[unicodePosition].idealX + 0.5 );    // These older APIs return float values +                    unsigned char uch = s[i];                      positions[i++] = position; -                    count ++; -                    mask = mask >> 1 | 0x80; // add an additional one in the highest order position + +                    // If we are using unicode (UTF8), map the Unicode position back to the UTF8 characters, +                    // as 1 unicode character can map to multiple UTF8 characters. +                    // See: http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF +                    // Or: http://www.cl.cam.ac.uk/~mgk25/unicode.html +                    if ( unicodeMode )  +                    { +                        unsigned char mask = 0xc0; +                        int count = 1; +                        // Add one additonal byte for each extra high order one in the byte +                        while ( uch >= mask && count < 8 )  +                        { +                            positions[i++] = position; +                            count ++; +                            mask = mask >> 1 | 0x80; // add an additional one in the highest order position +                        } +                    }                  } -                assert( count <= 8 );              } -        } else { -        positions[i++] = (i == 0) ? 1 : positions[i-1] + 1; + +            // Free the GlyphInfoArray +            free (theGlyphInfoArrayPtr);          }      } -    verify_noerr( ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords) ); -    // Get rid of the layout object -    delete textLayout; -    textLayout = NULL; +    free (buf);  }  int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {      if (font_.GetID())      { -        QuartzTextLayout* textLayout = GetTextLayout( font_, s, len ); -        if (!textLayout) return 0; +        textLayout->setText (reinterpret_cast<const UInt8*>(s), len, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));          // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout?          unsigned long actualNumberOfBounds = 0; @@ -748,17 +698,10 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {          if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 )          {              Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthText" ); -            // Get rid of the layout object -            delete textLayout; -            textLayout = NULL;              return 0;          }          //Platform::DebugPrintf( "WidthText: \"%*s\" = %ld\n", len, s, Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ) ); - -        // Get rid of the layout object -        delete textLayout; -        textLayout = NULL;          return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );      }      return 1; @@ -768,8 +711,7 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) {      char str[2] = { ch, '\0' };      if (font_.GetID())      { -        QuartzTextLayout* textLayout = GetTextLayout( font_, str, 1 ); -        if (!textLayout) return 0; +        textLayout->setText (reinterpret_cast<const UInt8*>(str), 1, *reinterpret_cast<QuartzTextStyle*>(font_.GetID()));          // TODO: Maybe I should add some sort of text measurement features to QuartzTextLayout?          unsigned long actualNumberOfBounds = 0; @@ -779,15 +721,9 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) {          if ( ATSUGetGlyphBounds( textLayout->getLayout(), 0, 0, kATSUFromTextBeginning, kATSUToTextEnd, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds ) != noErr || actualNumberOfBounds != 1 )          {              Platform::DebugDisplay( "ATSUGetGlyphBounds failed in WidthChar" ); -            // Get rid of the layout object -            delete textLayout; -            textLayout = NULL;              return 0;          } -        // Get rid of the layout object -        delete textLayout; -        textLayout = NULL;          return Fix2Long( glyphBounds.upperRight.x - glyphBounds.upperLeft.x );      }      else @@ -893,14 +829,15 @@ void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {  }  void SurfaceImpl::SetDBCSMode(int codePage) { -    // TODO: Implement this +    // TODO: Implement this for code pages != UTF-8  }  Surface *Surface::Allocate() {      return new SurfaceImpl(  );  } -Window::~Window() {} +Window::~Window() { +}  void Window::Destroy() {      if (windowRef) { @@ -996,9 +933,7 @@ void Window::Show(bool show) {  void Window::InvalidateAll() {      if ( id ) { -        OSStatus err; -        err = HIViewSetNeedsDisplay( reinterpret_cast<HIViewRef>( id ), true ); -        assert( err == noErr ); +        HIViewSetNeedsDisplay( reinterpret_cast<HIViewRef>( id ), true );      }  } @@ -1006,13 +941,10 @@ void Window::InvalidateRectangle(PRectangle rc) {      if (id) {          // Create a rectangular region          RgnHandle region = NewRgn(); -        assert( region != NULL );          SetRectRgn( region, rc.left, rc.top, rc.right, rc.bottom );          // Make that region invalid -        OSStatus err; -        err = HIViewSetNeedsDisplayInRegion( reinterpret_cast<HIViewRef>( id ), region, true ); -        assert( err == noErr ); +        HIViewSetNeedsDisplayInRegion( reinterpret_cast<HIViewRef>( id ), region, true );          DisposeRgn( region );      }  } @@ -1041,6 +973,8 @@ void Window::SetCursor(Cursor curs) {                  cursor = kThemeResizeLeftRightCursor;                  break;              case cursorVert: +                cursor = kThemeResizeUpDownCursor; +                break;              case cursorReverseArrow:              case cursorUp:              default: @@ -1148,7 +1082,7 @@ private:      int lineHeight;      bool unicodeMode;      int desiredVisibleRows; -    unsigned int maxItemCharacters; +    unsigned int maxItemWidth;      unsigned int aveCharWidth;      Font font;      int maxWidth; @@ -1170,7 +1104,7 @@ public:      void *doubleClickActionData;      ListBoxImpl() : lb(NULL), lineHeight(10), unicodeMode(false), -            desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(8), +            desiredVisibleRows(5), maxItemWidth(0), aveCharWidth(8),              doubleClickAction(NULL), doubleClickActionData(NULL)      {        if (kScrollBarWidth == 0) @@ -1223,7 +1157,7 @@ void ListBoxImpl::Create(Window &/*parent*/, int /*ctrlID*/, Scintilla::Point /*                           int lineHeight_, bool unicodeMode_) {      lineHeight = lineHeight_;      unicodeMode = unicodeMode_; -    maxWidth = 1000; +    maxWidth = 2000;      WindowClass windowClass = kHelpWindowClass;      WindowAttributes attributes = kWindowNoAttributes; @@ -1501,13 +1435,14 @@ void ListBoxImpl::SetFont(Font &font_) {  #endif      // !@&^#%$ we cant copy Font, but we need one for our custom drawing -    Str255 fontName; -    if (FMGetFontFamilyName(style.font, fontName) != kFMInvalidFontFamilyErr) { -      // make sure we conver to a proper C string first. -      char cFontName[255]; -      CopyPascalStringToC(fontName, cFontName); -      font.Create((const char *)cFontName, 0, style.size, false, false); -    } +    Str255 fontName255; +    char fontName[256]; +    FMGetFontFamilyName(style.font, fontName255); + +    CFStringRef fontNameCF = ::CFStringCreateWithPascalString( kCFAllocatorDefault, fontName255, kCFStringEncodingMacRoman ); +    ::CFStringGetCString( fontNameCF, fontName, (CFIndex)255, kCFStringEncodingMacRoman ); + +    font.Create((const char *)fontName, 0, style.size, false, false);  }  void ListBoxImpl::SetAverageCharWidth(int width) { @@ -1545,17 +1480,14 @@ PRectangle ListBoxImpl::GetDesiredRect() {          rows = desiredVisibleRows;      rcDesired.bottom = itemHeight * rows; -    int width = maxItemCharacters; -    if (width < 12) -        width = 12; -    // XXX use the quartz text stuff to figure out the correct string width -    rcDesired.right = rcDesired.left + width * (aveCharWidth+aveCharWidth/4); -    if (rcDesired.right > maxWidth) { -        rcDesired.right = maxWidth; -    } -    if (Length() > rows) +    rcDesired.right = rcDesired.left + maxItemWidth + aveCharWidth; + +    if (Length() > rows)           rcDesired.right += kScrollBarWidth;      rcDesired.right += IconWidth(); + +    // Set the column width +    ::SetDataBrowserTableViewColumnWidth (lb, UInt16 (rcDesired.right - rcDesired.left));      return rcDesired;  } @@ -1578,7 +1510,7 @@ int ListBoxImpl::CaretFromEdge() {  void ListBoxImpl::Clear() {      // passing NULL to "items" arg 4 clears the list -    maxItemCharacters = 0; +    maxItemWidth = 0;      ld.Clear();      AddDataBrowserItems (lb, kDataBrowserNoItem, 0, NULL, kDataBrowserItemNoProperty);  } @@ -1588,15 +1520,15 @@ void ListBoxImpl::Append(char *s, int type) {      CFStringRef r = CFStringCreateWithCString(NULL, s, kTextEncodingMacRoman);      ld.Add(count, type, r); +    Scintilla::SurfaceImpl surface; +    unsigned int width = surface.WidthText (font, s, strlen (s)); +    if (width > maxItemWidth) +        maxItemWidth = width; +      DataBrowserItemID items[1];      items[0] = count + 1;      AddDataBrowserItems (lb, kDataBrowserNoItem, 1, items, kDataBrowserItemNoProperty);      ShowHideScrollbar(); - -    size_t len = strlen(s); -    if (maxItemCharacters < len) -            maxItemCharacters = len; -  }  void ListBoxImpl::SetList(const char* list, char separator, char typesep) { @@ -1721,7 +1653,6 @@ void Menu::CreatePopUp() {      Destroy();      OSStatus err;      err = CreateNewMenu( nextMenuID++, 0, reinterpret_cast<MenuRef*>( &id ) ); -    assert( noErr == err && id != NULL );  }  void Menu::Destroy() { @@ -1746,8 +1677,6 @@ void Menu::Show(Point pt, Window &) {                                  &menuId,                                  &menuItem                                  ); -    // The system should always handle the command for us, so we should get userCanceledErr -    assert( /*noErr == err ||*/ userCanceledErr == err );  }  // TODO: Consider if I should be using GetCurrentEventTime instead of gettimeoday @@ -1755,7 +1684,6 @@ ElapsedTime::ElapsedTime() {      struct timeval curTime;      int retVal;      retVal = gettimeofday( &curTime, NULL ); -    assert( retVal == 0 );      bigBit = curTime.tv_sec;      littleBit = curTime.tv_usec; @@ -1765,7 +1693,6 @@ double ElapsedTime::Duration(bool reset) {      struct timeval curTime;      int retVal;      retVal = gettimeofday( &curTime, NULL ); -    assert( retVal == 0 );      long endBigBit = curTime.tv_sec;      long endLittleBit = curTime.tv_usec;      double result = 1000000.0 * (endBigBit - bigBit); @@ -1794,7 +1721,11 @@ static Str255 PlatformDefaultFontName;  const char *Platform::DefaultFont() {      long id = HighShortFromLong(GetScriptVariable(smCurrentScript, smScriptAppFondSize));      FMGetFontFamilyName(id, PlatformDefaultFontName); -    return (const char *)PlatformDefaultFontName; +    char* defaultFontName = (char*) PlatformDefaultFontName; +    defaultFontName[defaultFontName[0]+1] = 0; +    ++defaultFontName; + +    return defaultFontName;  }  int Platform::DefaultFontSize() { @@ -1836,17 +1767,17 @@ long Platform::SendScintilla(WindowID w, unsigned int msg, unsigned long wParam,  }  bool Platform::IsDBCSLeadByte(int /*codePage*/, char /*ch*/) { -    // TODO: Implement this +    // TODO: Implement this for code pages != UTF-8      return false;  }  int Platform::DBCSCharLength(int /*codePage*/, const char* /*s*/) { -    // TODO: Implement this +    // TODO: Implement this for code pages != UTF-8      return 1;  }  int Platform::DBCSCharMaxLength() { -    // TODO: Implement this +    // TODO: Implement this for code pages != UTF-8      //return CFStringGetMaximumSizeForEncoding( 1, CFStringEncoding encoding );      return 2;  } @@ -1906,11 +1837,13 @@ void Platform::Assert(const char *c, const char *file, int line) {      sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);      strcat(buffer, "\r\n");      Platform::DebugDisplay(buffer); -    abort(); +#ifdef DEBUG  +    // Jump into debugger in assert on Mac (CL269835) +    ::Debugger(); +#endif  }  int Platform::Clamp(int val, int minVal, int maxVal) { -    assert( minVal <= maxVal );      if (val > maxVal)          val = maxVal;      if (val < minVal) diff --git a/macosx/PlatMacOSX.h b/macosx/PlatMacOSX.h index 168ba74ee..58e1bc6d7 100644 --- a/macosx/PlatMacOSX.h +++ b/macosx/PlatMacOSX.h @@ -23,12 +23,11 @@ private:      float x;      float y; -#ifdef SUPPORT_PORT -    CGrafPtr port; -#endif      CGContextRef gc; +    /** The text layout instance */ +    QuartzTextLayout*	textLayout;      /** If the surface is a bitmap context, contains a reference to the bitmap data. */      uint8_t* bitmapData;      /** If the surface is a bitmap context, stores the dimensions of the bitmap. */ @@ -74,7 +73,6 @@ public:      void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);      void Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource); -    QuartzTextLayout* GetTextLayout( Font &font_, const char *s, int len );      void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);      void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);      void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); diff --git a/macosx/QuartzTextLayout.h b/macosx/QuartzTextLayout.h index 1461a078f..d65d45290 100644 --- a/macosx/QuartzTextLayout.h +++ b/macosx/QuartzTextLayout.h @@ -1,9 +1,10 @@  /*   *  QuartzTextLayout.h - *  wtf   * - *  Created by Evan Jones on Wed Oct 02 2002. - *  Copyright (c) 2002 __MyCompanyName__. All rights reserved. + *  Original Code by Evan Jones on Wed Oct 02 2002. + *  Contributors: + *  Shane Caraveo, ActiveState + *  Bernd Paradies, Adobe   *   */ @@ -20,26 +21,23 @@ public:      /** Create a text layout for drawing on the specified context. */      QuartzTextLayout( CGContextRef context ) : layout( NULL ), unicode_string( NULL ), unicode_length( 0 )      { -        gc = context; - -        OSStatus err; -        err = ATSUCreateTextLayout( &layout ); -        assert( err == noErr && layout != NULL ); +        OSStatus err = ATSUCreateTextLayout( &layout ); +        if (0 != err) +                layout = NULL; -        setControl( kATSUCGContextTag, sizeof( gc ), &gc ); +        setContext(context); -        /*ATSUAttributeTag tag = kATSULineLayoutOptionsTag; +        ATSUAttributeTag tag = kATSULineLayoutOptionsTag;          ByteCount size = sizeof( ATSLineLayoutOptions ); -        ATSLineLayoutOptions rendering = kATSLineHasNoOpticalAlignment; // kATSLineUseDeviceMetrics; | kATSLineFractDisable | kATSLineUseQDRendering +        ATSLineLayoutOptions rendering = kATSLineUseDeviceMetrics; //| kATSLineFractDisable | kATSLineUseQDRendering          ATSUAttributeValuePtr valuePtr = &rendering;          err = ATSUSetLayoutControls( layout, 1, &tag, &size, &valuePtr ); -        assert( err == noErr );*/      }      ~QuartzTextLayout()      { -        assert( layout != NULL ); -        ATSUDisposeTextLayout( layout ); +        if (NULL != layout) +            ATSUDisposeTextLayout( layout );          layout = NULL;          if ( unicode_string != NULL ) @@ -55,13 +53,15 @@ public:      // TODO: Optimise the ASCII version by not copying so much      OSStatus setText( const UInt8* buffer, size_t byteLength, CFStringEncoding encoding )      { -        assert( buffer != NULL && byteLength > 0 ); -         +        if (NULL == layout) +                return -1;          CFStringRef str = CFStringCreateWithBytes( NULL, buffer, byteLength, encoding, false );          if (!str)              return -1;          unicode_length = CFStringGetLength( str ); +        if (unicode_string) +            delete[] unicode_string;          unicode_string = new UniChar[ unicode_length ];          CFStringGetCharacters( str, CFRangeMake( 0, unicode_length ), unicode_string ); @@ -76,12 +76,16 @@ public:          return ATSUSetTransientFontMatching( layout, true );      } +    inline void setText( const UInt8* buffer, size_t byteLength, const QuartzTextStyle& r ) +    { +        this->setText( buffer, byteLength, kCFStringEncodingUTF8 ); +        ATSUSetRunStyle( layout, r.getATSUStyle(), 0, unicode_length ); +    } +      /** Apply the specified text style on the entire range of text. */      void setStyle( const QuartzTextStyle& style )      { -        OSStatus err; -        err = ATSUSetRunStyle( layout, style.getATSUStyle(), kATSUFromTextBeginning, kATSUToTextEnd ); -        assert( err == noErr ); +        ATSUSetRunStyle( layout, style.getATSUStyle(), kATSUFromTextBeginning, kATSUToTextEnd );      }      /** Draw the text layout into the current CGContext at the specified position, flipping the CGContext's Y axis if required. @@ -90,6 +94,8 @@ public:      * @param flipTextYAxis If true, the CGContext's Y axis will be flipped before drawing the text, and restored afterwards. Use this when drawing in an HIView's CGContext, where the origin is the top left corner. */      void draw( float x, float y, bool flipTextYAxis = false )      { +        if (NULL == layout || 0 == unicode_length) +                return;          if ( flipTextYAxis )          {              CGContextSaveGState( gc ); @@ -99,7 +105,6 @@ public:          OSStatus err;          err = ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix( x ), X2Fix( y ) ); -        assert( err == noErr );          if ( flipTextYAxis ) CGContextRestoreGState( gc );      } @@ -111,15 +116,21 @@ public:      */      void setControl( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value )      { -        OSStatus err; -        err = ATSUSetLayoutControls( layout, 1, &tag, &size, &value ); -        assert( noErr == err ); +        ATSUSetLayoutControls( layout, 1, &tag, &size, &value );      }      ATSUTextLayout getLayout() {          return layout;      } +    inline CFIndex getLength() const { return unicode_length; } +    inline void setContext (CGContextRef context) +    { +        gc = context; +        if (NULL != layout) +            setControl( kATSUCGContextTag, sizeof( gc ), &gc ); +    } +  private:      ATSUTextLayout layout;      UniChar* unicode_string; diff --git a/macosx/QuartzTextStyle.h b/macosx/QuartzTextStyle.h index d3a5db5dc..80c06b76e 100644 --- a/macosx/QuartzTextStyle.h +++ b/macosx/QuartzTextStyle.h @@ -19,23 +19,19 @@ class QuartzTextStyle  public:      QuartzTextStyle()      { -        OSStatus err; -        err = ATSUCreateStyle( &style ); -        assert( err == noErr ); +        ATSUCreateStyle( &style );      }      ~QuartzTextStyle()      { -        assert( style != NULL ); -        ATSUDisposeStyle( style ); +        if ( style != NULL ) +            ATSUDisposeStyle( style );          style = NULL;      }      void setAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value )      { -        OSStatus err; -        err = ATSUSetAttributes( style, 1, &tag, &size, &value ); -        assert( err == noErr ); +        ATSUSetAttributes( style, 1, &tag, &size, &value );      }      void setAttribute( QuartzTextStyleAttribute& attribute ) @@ -45,8 +41,7 @@ public:      void getAttribute( ATSUAttributeTag tag, ByteCount size, ATSUAttributeValuePtr value, ByteCount* actualSize )      { -        OSStatus err; err = ATSUGetAttribute( style, tag, size, value, actualSize ); -        assert( err == noErr ); +        ATSUGetAttribute( style, tag, size, value, actualSize );      }      template <class T> @@ -54,9 +49,7 @@ public:      {          T value;          ByteCount actualSize; -        OSStatus err; -        err = ATSUGetAttribute( style, tag, sizeof( T ), &value, &actualSize ); -        assert( (err == noErr || err == kATSUNotSetErr) && actualSize == sizeof( T ) ); +        ATSUGetAttribute( style, tag, sizeof( T ), &value, &actualSize );          return value;      } @@ -75,9 +68,7 @@ public:              values[i] = attributes[i]->getValuePtr();          } -        OSStatus err; -        err = ATSUSetAttributes( style, number, tags, sizes, values ); -        //assert( err == noErr ); +        ATSUSetAttributes( style, number, tags, sizes, values );          // Free the arrays that were allocated          delete[] tags; @@ -87,9 +78,7 @@ public:      void setFontFeature( ATSUFontFeatureType featureType, ATSUFontFeatureSelector selector )      { -        OSStatus err; -        err = ATSUSetFontFeatures( style, 1, &featureType, &selector ); -        assert( err == noErr ); +        ATSUSetFontFeatures( style, 1, &featureType, &selector );      }      const ATSUStyle& getATSUStyle() const diff --git a/macosx/QuartzTextStyleAttribute.h b/macosx/QuartzTextStyleAttribute.h index 490ef7d02..89b43721e 100644 --- a/macosx/QuartzTextStyleAttribute.h +++ b/macosx/QuartzTextStyleAttribute.h @@ -1,9 +1,10 @@  /*   *  QuartzTextStyleAttribute.h - *  wtf   * - *  Created by Evan Jones on Wed Oct 02 2002. - *  Copyright (c) 2002 __MyCompanyName__. All rights reserved. + *  Original Code by Evan Jones on Wed Oct 02 2002. + *  Contributors: + *  Shane Caraveo, ActiveState + *  Bernd Paradies, Adobe   *   */ @@ -16,6 +17,8 @@  class QuartzTextStyleAttribute  {  public: +    QuartzTextStyleAttribute() {} +    virtual ~QuartzTextStyleAttribute() {}      virtual ByteCount getSize() const = 0;      virtual ATSUAttributeValuePtr getValuePtr() = 0;      virtual ATSUAttributeTag getTag() const = 0; @@ -104,17 +107,12 @@ public:      QuartzFont( const char* name, int length )      {          assert( name != NULL && length > 0 && name[length] == '\0' ); -        /*CFStringRef fontName = CFStringCreateWithCString( NULL, name, kCFStringEncodingMacRoman ); -         -        ATSFontRef fontRef = ATSFontFindFromName( fontName, kATSOptionFlagsDefault ); -        assert( fontRef != NULL ); -        fontid = fontRef; +        // try to create font +        OSStatus err = ATSUFindFontFromName( const_cast<char*>( name ), length, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid ); -        CFRelease( fontName );*/ - -        OSStatus err; -        err = ATSUFindFontFromName( const_cast<char*>( name ), length, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid ); -        //assert( err == noErr && fontid != kATSUInvalidFontID ); +        // need a fallback if font isn't installed +        if( err != noErr || fontid == kATSUInvalidFontID ) +                ::ATSUFindFontFromName( "Lucida Grande", 13, kFontFullName, (unsigned) kFontNoPlatform, kFontRomanScript, (unsigned) kFontNoLanguage, &fontid );      }      ByteCount getSize() const diff --git a/macosx/ScintillaMacOSX.cxx b/macosx/ScintillaMacOSX.cxx index 9ac746f4b..410d105d9 100644 --- a/macosx/ScintillaMacOSX.cxx +++ b/macosx/ScintillaMacOSX.cxx @@ -6,7 +6,12 @@  #include "ScintillaMacOSX.h" +#ifdef EXT_INPUT +// External Input Editor +#include "ExtInput.h" +#else  #include "UniConversion.h" +#endif  using namespace Scintilla; @@ -59,9 +64,103 @@ static int BOMlen(unsigned char *cstr) {    return 0;  } +#ifdef EXT_INPUT +#define SCI_CMD ( SCI_ALT | SCI_CTRL | SCI_SHIFT) + +static const KeyToCommand macMapDefault[] = { +    {SCK_DOWN,		SCI_CMD,	SCI_DOCUMENTEND}, +    {SCK_UP,		SCI_CMD,	SCI_DOCUMENTSTART}, +    {SCK_LEFT,		SCI_CMD,	SCI_VCHOME}, +    {SCK_RIGHT,		SCI_CMD,	SCI_LINEEND}, +    {SCK_DOWN,		SCI_NORM,	SCI_LINEDOWN}, +    {SCK_DOWN,		SCI_SHIFT,	SCI_LINEDOWNEXTEND}, +    {SCK_DOWN,		SCI_CTRL,	SCI_LINESCROLLDOWN}, +    {SCK_DOWN,		SCI_ASHIFT,	SCI_LINEDOWNRECTEXTEND}, +    {SCK_UP,		SCI_NORM,	SCI_LINEUP}, +    {SCK_UP,			SCI_SHIFT,	SCI_LINEUPEXTEND}, +    {SCK_UP,			SCI_CTRL,	SCI_LINESCROLLUP}, +    {SCK_UP,		SCI_ASHIFT,	SCI_LINEUPRECTEXTEND}, +    {'[',			SCI_CTRL,		SCI_PARAUP}, +    {'[',			SCI_CSHIFT,	SCI_PARAUPEXTEND}, +    {']',			SCI_CTRL,		SCI_PARADOWN}, +    {']',			SCI_CSHIFT,	SCI_PARADOWNEXTEND}, +    {SCK_LEFT,		SCI_NORM,	SCI_CHARLEFT}, +    {SCK_LEFT,		SCI_SHIFT,	SCI_CHARLEFTEXTEND}, +    {SCK_LEFT,		SCI_ALT,	SCI_WORDLEFT}, +    {SCK_LEFT,		SCI_CSHIFT,	SCI_WORDLEFTEXTEND}, +    {SCK_LEFT,		SCI_ASHIFT,	SCI_CHARLEFTRECTEXTEND}, +    {SCK_RIGHT,		SCI_NORM,	SCI_CHARRIGHT}, +    {SCK_RIGHT,		SCI_SHIFT,	SCI_CHARRIGHTEXTEND}, +    {SCK_RIGHT,		SCI_ALT,	SCI_WORDRIGHT}, +    {SCK_RIGHT,		SCI_CSHIFT,	SCI_WORDRIGHTEXTEND}, +    {SCK_RIGHT,		SCI_ASHIFT,	SCI_CHARRIGHTRECTEXTEND}, +    {'/',		SCI_CTRL,		SCI_WORDPARTLEFT}, +    {'/',		SCI_CSHIFT,	SCI_WORDPARTLEFTEXTEND}, +    {'\\',		SCI_CTRL,		SCI_WORDPARTRIGHT}, +    {'\\',		SCI_CSHIFT,	SCI_WORDPARTRIGHTEXTEND}, +    {SCK_HOME,		SCI_NORM,	SCI_VCHOME}, +    {SCK_HOME, 		SCI_SHIFT, 	SCI_VCHOMEEXTEND}, +    {SCK_HOME, 		SCI_CTRL, 	SCI_DOCUMENTSTART}, +    {SCK_HOME, 		SCI_CSHIFT, 	SCI_DOCUMENTSTARTEXTEND}, +    {SCK_HOME, 		SCI_ALT, 	SCI_HOMEDISPLAY}, +//    {SCK_HOME,		SCI_ASHIFT,	SCI_HOMEDISPLAYEXTEND}, +    {SCK_HOME,		SCI_ASHIFT,	SCI_VCHOMERECTEXTEND}, +    {SCK_END,	 	SCI_NORM,	SCI_LINEEND}, +    {SCK_END,	 	SCI_SHIFT, 	SCI_LINEENDEXTEND}, +    {SCK_END, 		SCI_CTRL, 	SCI_DOCUMENTEND}, +    {SCK_END, 		SCI_CSHIFT, 	SCI_DOCUMENTENDEXTEND}, +    {SCK_END, 		SCI_ALT, 	SCI_LINEENDDISPLAY}, +//    {SCK_END,		SCI_ASHIFT,	SCI_LINEENDDISPLAYEXTEND}, +    {SCK_END,		SCI_ASHIFT,	SCI_LINEENDRECTEXTEND}, +    {SCK_PRIOR,		SCI_NORM,	SCI_PAGEUP}, +    {SCK_PRIOR,		SCI_SHIFT, 	SCI_PAGEUPEXTEND}, +    {SCK_PRIOR,		SCI_ASHIFT,	SCI_PAGEUPRECTEXTEND}, +    {SCK_NEXT, 		SCI_NORM, 	SCI_PAGEDOWN}, +    {SCK_NEXT, 		SCI_SHIFT, 	SCI_PAGEDOWNEXTEND}, +    {SCK_NEXT,		SCI_ASHIFT,	SCI_PAGEDOWNRECTEXTEND}, +    {SCK_DELETE, 	SCI_NORM,	SCI_CLEAR}, +    {SCK_DELETE, 	SCI_SHIFT,	SCI_CUT}, +    {SCK_DELETE, 	SCI_CTRL,	SCI_DELWORDRIGHT}, +    {SCK_DELETE,	SCI_CSHIFT,	SCI_DELLINERIGHT}, +    {SCK_INSERT, 		SCI_NORM,	SCI_EDITTOGGLEOVERTYPE}, +    {SCK_INSERT, 		SCI_SHIFT,	SCI_PASTE}, +    {SCK_INSERT, 		SCI_CTRL,	SCI_COPY}, +    {SCK_ESCAPE,  	SCI_NORM,	SCI_CANCEL}, +    {SCK_BACK,		SCI_NORM, 	SCI_DELETEBACK}, +    {SCK_BACK,		SCI_SHIFT, 	SCI_DELETEBACK}, +    {SCK_BACK,		SCI_CTRL, 	SCI_DELWORDLEFT}, +    {SCK_BACK, 		SCI_ALT,	SCI_UNDO}, +    {SCK_BACK,		SCI_CSHIFT,	SCI_DELLINELEFT}, +    {'Z', 			SCI_CTRL,	SCI_UNDO}, +    {'Y', 			SCI_CTRL,	SCI_REDO}, +    {'X', 			SCI_CTRL,	SCI_CUT}, +    {'C', 			SCI_CTRL,	SCI_COPY}, +    {'V', 			SCI_CTRL,	SCI_PASTE}, +    {'A', 			SCI_CTRL,	SCI_SELECTALL}, +    {SCK_TAB,		SCI_NORM,	SCI_TAB}, +    {SCK_TAB,		SCI_SHIFT,	SCI_BACKTAB}, +    {SCK_RETURN, 	SCI_NORM,	SCI_NEWLINE}, +    {SCK_RETURN, 	SCI_SHIFT,	SCI_NEWLINE}, +    {SCK_ADD, 		SCI_CTRL,	SCI_ZOOMIN}, +    {SCK_SUBTRACT,	SCI_CTRL,	SCI_ZOOMOUT}, +    {SCK_DIVIDE,	SCI_CTRL,	SCI_SETZOOM}, +    //'L', 			SCI_CTRL,		SCI_FORMFEED, +    {'L', 			SCI_CTRL,	SCI_LINECUT}, +    {'L', 			SCI_CSHIFT,	SCI_LINEDELETE}, +    {'T', 			SCI_CSHIFT,	SCI_LINECOPY}, +    {'T', 			SCI_CTRL,	SCI_LINETRANSPOSE}, +    {'D', 			SCI_CTRL,	SCI_SELECTIONDUPLICATE}, +    {'U', 			SCI_CTRL,	SCI_LOWERCASE}, +    {'U', 			SCI_CSHIFT,	SCI_UPPERCASE}, +    {0,0,0}, +}; +#endif +  ScintillaMacOSX::ScintillaMacOSX( void* windowid ) :          TView( reinterpret_cast<HIViewRef>( windowid ) )  { +    notifyObj = NULL; +    notifyProc = NULL;      wMain = windowid;      OSStatus err;      err = GetThemeMetric( kThemeMetricScrollBarWidth, &scrollBarFixedSize ); @@ -123,7 +222,13 @@ ScintillaMacOSX::ScintillaMacOSX( void* windowid ) :                     GetEventTypeCount( commandEventInfo ),                      commandEventInfo,                     this, NULL); -    assert( err == noErr ); +#ifdef EXT_INPUT +    ExtInput::attach (GetViewRef()); +    for (int i = 0; macMapDefault[i].key; i++)  +    { +        this->kmap.AssignCmdKey(macMapDefault[i].key, macMapDefault[i].modifiers, macMapDefault[i].msg); +    } +#endif  }  ScintillaMacOSX::~ScintillaMacOSX() { @@ -134,6 +239,9 @@ ScintillaMacOSX::~ScintillaMacOSX() {      }      mouseTrackingRef = NULL;      SetTicking(false); +#ifdef EXT_INPUT +    ExtInput::detach (GetViewRef()); +#endif  }  void ScintillaMacOSX::Initialise() { @@ -226,43 +334,12 @@ HIPoint ScintillaMacOSX::GetLocalPoint(::Point pt)  }  void ScintillaMacOSX::StartDrag() { -#define DRAG_DROP_PASTEBOARD      if (currentPos == anchor) return; -    SelectionText selectedText; -    CopySelectionRange(&selectedText); - -    // some of this taken from copytoclipboard -    if (selectedText.len == 0) -        return; - -    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); - -    // Create a CFString from the ASCII/UTF8 data, convert it to UTF16 -    CFStringRef string = CFStringCreateWithBytes( NULL, reinterpret_cast<UInt8*>( selectedText.s ), selectedText.len - 1, encoding, false ); -    assert( string != NULL ); - -#ifndef DRAG_DROP_PASTEBOARD -    CFIndex numUniChars = CFStringGetLength( string ); -    UniChar* buffer = new UniChar[ numUniChars ]; -    CFStringGetCharacters( string, CFRangeMake( 0, numUniChars ), buffer ); - -    // Create an c string byte buffer -    CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; -    char* cstring = new char[maximumByteLength]; -    CFIndex usedBufferLength = 0; -    CFIndex numCharsConverted; -    numCharsConverted = CFStringGetBytes( string, CFRangeMake( 0, numUniChars ), encoding, -                              '?', false, reinterpret_cast<UInt8*>( cstring ), -                              maximumByteLength, &usedBufferLength ); -    cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string -    assert( numCharsConverted == numUniChars ); -#endif -          // calculate the bounds of the selection          PRectangle client = GetTextRectangle(); -    int selStart = Platform::Minimum(anchor, currentPos); -    int selEnd = Platform::Maximum(anchor, currentPos); +    int selStart = SelectionStart(); +    int selEnd = SelectionEnd();      int startLine = pdoc->LineFromPosition(selStart);      int endLine = pdoc->LineFromPosition(selEnd);      Point pt; @@ -318,7 +395,7 @@ void ScintillaMacOSX::StartDrag() {              client = GetClientRectangle();              paintState = painting;              sw->InitPixMap( client.Width(), client.Height(), NULL, NULL ); -             +            paintingAllText = true;              Paint(sw, imageRect);              paintState = notPainting; @@ -354,28 +431,12 @@ void ScintillaMacOSX::StartDrag() {      RectRgn(dragRegion, &rcSel); -#ifdef DRAG_DROP_PASTEBOARD +    SelectionText selectedText; +    CopySelectionRange(&selectedText);      PasteboardRef theClipboard; -    PasteboardCreate( kPasteboardClipboard, &theClipboard ); -    PasteboardClear( theClipboard ); - -    CFDataRef data = NULL; -    data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingMacRoman, 0 ); -    PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1,  -                            CFSTR("com.apple.traditional-mac-plain-text"), -                            data, 0 ); -    CFRelease(data); -    data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingUnicode, 0 ); -    PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1,  -                            CFSTR("public.utf16-plain-text"), -                            data, 0 ); -    CFRelease(data); +    SetPasteboardData(theClipboard, selectedText);      NewDragWithPasteboard( theClipboard, &inDrag); -#else -    NewDrag(&inDrag); -    AddDragItemFlavor(inDrag, 1, 'utxt', buffer, sizeof( UniChar ) * numUniChars, 0); -    AddDragItemFlavor(inDrag, 1, 'txt', cstring, sizeof( char ) * usedBufferLength, 0); -#endif +    CFRelease( theClipboard );      //  Set the item's bounding rectangle in global coordinates.      SetDragItemBounds(inDrag, 1, &rcSel); @@ -394,9 +455,9 @@ void ScintillaMacOSX::StartDrag() {      }      //  Drag the text. TrackDrag will return userCanceledErr if the drop whooshed back for any reason. -    inDragSession = true; +    inDragDrop = ddDragging;      OSErr error = TrackDrag(inDrag, &mouseDownEvent, dragRegion); -    inDragSession = false; +    inDragDrop = ddNone;      //  Check to see if the drop occurred in the Finder's Trash. If the drop occurred      //  in the Finder's Trash and a copy operation wasn't specified, delete the @@ -424,23 +485,12 @@ void ScintillaMacOSX::StartDrag() {      // Dispose of this drag, 'cause we're done.      DisposeDrag(inDrag);      DisposeRgn(dragRegion); -    CFRelease( string );      if (pixmap) {          CGImageRelease(image);          pixmap->Release();          delete pixmap;      } - -    // Done with the UniChar* buffer -#ifdef DRAG_DROP_PASTEBOARD -    CFRelease( theClipboard ); -#else -    delete[] buffer; -    buffer = NULL;   -    delete[] cstring; -    cstring = NULL; -#endif  }  void ScintillaMacOSX::SetDragCursor(DragRef inDrag) @@ -504,8 +554,7 @@ Scintilla::Point ScintillaMacOSX::GetDragPoint(DragRef inDrag)  {      ::Point mouse, globalMouse;      GetDragMouse(inDrag, &mouse, &globalMouse); -    QDGlobalToLocalPoint(GetWindowPort(GetOwner()), &globalMouse); -    HIPoint hiPoint = {globalMouse.h, globalMouse.v}; +    HIPoint hiPoint = GetLocalPoint (globalMouse);      return Point(static_cast<int>(hiPoint.x), static_cast<int>(hiPoint.y));  } @@ -548,22 +597,13 @@ void ScintillaMacOSX::DragScroll()  bool ScintillaMacOSX::DragWithin(DragRef inDrag )  {      PasteboardRef pasteBoard; -    OSStatus status = GetDragData(inDrag, pasteBoard, NULL); -    if (status != noErr) { -        return false; -    } - -    ::Point mouse, globalMouse; -    GetDragMouse(inDrag, &mouse, &globalMouse); -    QDGlobalToLocalPoint(GetWindowPort(GetOwner()), &globalMouse); -    HIPoint globalHit = {globalMouse.h, globalMouse.v}; -    // HIPoint localHit = {mouse.h, mouse.v}; - -    if (!CGRectContainsPoint( Bounds(), globalHit )) { +    bool isFileURL = false; +    if (!GetDragData(inDrag, pasteBoard, NULL, &isFileURL)) {          return false;      } -    SetDragPosition(PositionFromLocation(Point(static_cast<int>(globalHit.x),static_cast<int>(globalHit.y)))); +    Point pt = GetDragPoint (inDrag); +    SetDragPosition(PositionFromLocation(pt));      SetDragCursor(inDrag);      return true; @@ -577,21 +617,84 @@ bool ScintillaMacOSX::DragLeave(DragRef inDrag )      return true;  } -OSStatus ScintillaMacOSX::GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, CFStringRef *textString) +enum +{ +    kFormatBad, +    kFormatText, +    kFormatUnicode, +    kFormatUTF8, +    kFormatFile +}; + +bool ScintillaMacOSX::GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, +                                  SelectionText *selectedText, bool *isFileURL)  {    // TODO: add support for special flavors: flavorTypeHFS and flavorTypePromiseHFS so we    //       can handle files being dropped on the editor      OSStatus status;      status = GetDragPasteboard(inDrag, &pasteBoard);      if (status != noErr) { -        return dragNotAcceptedErr; +        return false; +    } +    return GetPasteboardData(pasteBoard, selectedText, isFileURL); +} + +void ScintillaMacOSX::SetPasteboardData(PasteboardRef &theClipboard, const SelectionText &selectedText) +{ +    if (selectedText.len == 0) +        return; + +    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingMacRoman); + +    // Create a CFString from the ASCII/UTF8 data, convert it to UTF16 +    CFStringRef string = CFStringCreateWithBytes( NULL, reinterpret_cast<UInt8*>( selectedText.s ), selectedText.len - 1, encoding, false ); + +    PasteboardCreate( kPasteboardClipboard, &theClipboard ); +    PasteboardClear( theClipboard ); + +    CFDataRef data = NULL; +    if (selectedText.rectangular) { +        // This is specific to scintilla, allows us to drag rectangular selections +        // around the document +        data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingUnicode, 0 ); +        if (data) { +            PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1,  +                              CFSTR("com.scintilla.utf16-plain-text.rectangular"), +                              data, 0 ); +            CFRelease(data); +        }      } +    data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingUnicode, 0 ); +    if (data) { +        PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1,  +                                CFSTR("public.utf16-plain-text"), +                                data, 0 ); +        CFRelease(data); +        data = NULL; +    } +    data = CFStringCreateExternalRepresentation ( kCFAllocatorDefault, string, kCFStringEncodingMacRoman, 0 ); +    if (data) { +        PasteboardPutItemFlavor( theClipboard, (PasteboardItemID)1,  +                                CFSTR("com.apple.traditional-mac-plain-text"), +                                data, 0 ); +        CFRelease(data); +        data = NULL; +    } +    CFRelease(string); +} +bool ScintillaMacOSX::GetPasteboardData(PasteboardRef &pasteBoard, +                                        SelectionText *selectedText, +                                        bool *isFileURL) +{      // how many items in the pasteboard? +    CFDataRef data; +    CFStringRef textString = NULL; +    bool isRectangular = selectedText ? selectedText->rectangular : false;      ItemCount i, itemCount; -    status = PasteboardGetItemCount(pasteBoard, &itemCount); +    OSStatus status = PasteboardGetItemCount(pasteBoard, &itemCount);      if (status != noErr) { -        return dragNotAcceptedErr; +        return false;      }      // as long as we didn't get our text, let's loop on the items. We stop as soon as we get it @@ -604,13 +707,13 @@ OSStatus ScintillaMacOSX::GetDragData(DragRef inDrag, PasteboardRef &pasteBoard,          status = PasteboardGetItemIdentifier(pasteBoard, i, &itemID);          if (status != noErr) { -            return dragNotAcceptedErr; +            return false;          }          // how many flavors in this item?          status = PasteboardCopyItemFlavors(pasteBoard, itemID, &flavorTypeArray);          if (status != noErr) { -            return dragNotAcceptedErr; +            return false;          }          if (flavorTypeArray != NULL) @@ -621,57 +724,83 @@ OSStatus ScintillaMacOSX::GetDragData(DragRef inDrag, PasteboardRef &pasteBoard,          {              CFDataRef flavorData;              CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, j); -            if (flavorType != NULL) { -                if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))) // this is 'utxt' +            if (flavorType != NULL)  +            { +                int format = kFormatBad; +                if (UTTypeConformsTo(flavorType, CFSTR("public.file-url"))) { +                    format = kFormatFile; +                    *isFileURL = true; +                } +                else if (UTTypeConformsTo(flavorType, CFSTR("com.scintilla.utf16-plain-text.rectangular"))) { +                    format = kFormatUnicode; +                    isRectangular = true; +                } +                else if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))) { // this is 'utxt' +                    format = kFormatUnicode; +                } +                else if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) { +                    format = kFormatUTF8; +                } +                else if (UTTypeConformsTo(flavorType, CFSTR("com.apple.traditional-mac-plain-text"))) { // this is 'TEXT' +                    format = kFormatText; +                } +                if (format == kFormatBad) +                    continue; +                 +                // if we got a flavor match, and we have no textString, we just want +                // to know that we can accept this data, so jump out now +                if (selectedText == NULL) { +                    haveMatch = true; +                    goto PasteboardDataRetrieved; +                } +                if (PasteboardCopyItemFlavorData(pasteBoard, itemID, flavorType, &flavorData) == noErr)                  { -                    // if we got a flavor match, and we have no textString, we just want -                    // to know that we can accept this drag data, so jump out now -                    if (textString == NULL) { -                        haveMatch = true; -                        goto DragDataRetrieved; -                    } -                    if (PasteboardCopyItemFlavorData(pasteBoard, itemID, flavorType, &flavorData) == noErr) +                    CFIndex dataSize = CFDataGetLength (flavorData); +                    const UInt8* dataBytes = CFDataGetBytePtr (flavorData); +                    switch (format)                      { -                        CFIndex flavorDataSize = CFDataGetLength(flavorData); -                     -                        // getting the text -                        *textString = CFStringCreateWithCharacters(NULL,  -                                  (UniChar *)CFDataGetBytePtr(flavorData),  -                                  flavorDataSize >> 1); -                        CFRelease(flavorData); -                        goto DragDataRetrieved; +                        case kFormatFile: +                        case kFormatText: +                            data = CFDataCreate (NULL, dataBytes, dataSize); +                            textString = CFStringCreateFromExternalRepresentation (NULL, data, kCFStringEncodingMacRoman); +                            break; +                        case kFormatUnicode: +                            data = CFDataCreate (NULL, dataBytes, dataSize); +                            textString = CFStringCreateFromExternalRepresentation (NULL, data, kCFStringEncodingUnicode); +                            break; +                        case kFormatUTF8: +                            data = CFDataCreate (NULL, dataBytes, dataSize); +                            textString = CFStringCreateFromExternalRepresentation (NULL, data, kCFStringEncodingUTF8); +                            break;                      } +                    CFRelease (flavorData); +                    goto PasteboardDataRetrieved;                  }              }          }      } -DragDataRetrieved: +PasteboardDataRetrieved:      if (flavorTypeArray != NULL) CFRelease(flavorTypeArray); -    if (haveMatch || textString != NULL && *textString != NULL)  -        return noErr; -    return dragNotAcceptedErr; -} - -OSStatus ScintillaMacOSX::DragReceive(DragRef inDrag ) -{ -    OSStatus status; -    PasteboardRef pasteBoard; -    CFStringRef textString = NULL; -    status = GetDragData(inDrag, pasteBoard, &textString); -    if (status != noErr) { -        return dragNotAcceptedErr; +        int newlen = 0; +    if (textString != NULL) { +        selectedText->s = GetStringFromCFString(textString, &selectedText->len); +        selectedText->rectangular = isRectangular; +        // Default allocator releases both the CFString and the UniChar buffer (text) +        CFRelease( textString ); +        textString = NULL;      } - -    // getting the length of the text and setting the value -    if (textString == NULL) { -        return noErr; +    if (haveMatch || selectedText != NULL && selectedText->s != NULL) { +        return true;      } +    return false; +} -    // XXX the following is identical (ALMOST) to code in Paste +char *ScintillaMacOSX::GetStringFromCFString(CFStringRef &textString, int *textLen) +{      // Allocate a buffer, plus the null byte      CFIndex numUniChars = CFStringGetLength( textString ); -    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); +    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingMacRoman);      CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1;      char* cstring = new char[maximumByteLength];      CFIndex usedBufferLength = 0; @@ -680,84 +809,84 @@ OSStatus ScintillaMacOSX::DragReceive(DragRef inDrag )                                '?', false, reinterpret_cast<UInt8*>( cstring ),                                maximumByteLength, &usedBufferLength );      cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string -    assert( numCharsConverted == numUniChars ); - -    // Default allocator releases both the CFString and the UniChar buffer (text) -    CFRelease( textString ); -    textString = NULL;            // determine whether a BOM is in the string.  Apps like Emacs prepends a BOM      // to the string, CFStrinGetBytes reflects that (though it may change in the conversion)      // so we need to remove it before pasting into our buffer.  TextWrangler has no      // problem dealing with BOM when pasting into it.      int bomLen = BOMlen((unsigned char *)cstring); -     +      // convert line endings to the document line ending -    int droppedLen = 0; -    char *droppedText = Document::TransformLineEnds(&droppedLen, -                                                cstring + bomLen, -                                                usedBufferLength - bomLen, -                                                pdoc->eolMode); -     -    pdoc->BeginUndoAction(); +    *textLen = 0; +    char *result = Document::TransformLineEnds(textLen, +                                      cstring + bomLen, +                                      usedBufferLength - bomLen, +                                      pdoc->eolMode); +    delete[] cstring; +    return result; +} -    // figure out if this is a move or a paste -    DragAttributes attributes; -    SInt16 modifiers = 0;  -    GetDragAttributes( inDrag, &attributes ); +OSStatus ScintillaMacOSX::DragReceive(DragRef inDrag ) +{ +    // dragleave IS called, but for some reason (probably to do with inDrag) +    // the hide hilite does not happen unless we do it here +    HideDragHilite( inDrag ); -    int position = PositionFromLocation(GetDragPoint(inDrag)); -    int selStart = Platform::Minimum(anchor, currentPos); -    int selEnd = Platform::Maximum(anchor, currentPos); -    if ( attributes & kDragInsideSenderWindow ) { -        if (position >= selStart && position <= selEnd) { -            // droping on top of what we dragged, we should ignore this -            goto endDrag; -        } -        GetDragModifiers(inDrag, NULL, NULL, &modifiers); -        switch (modifiers & ~btnState)  // Filter out btnState (on for drop) -        { -        case optionKey: -            // default is copy text -            break; -       -        case cmdKey: -        case cmdKey | optionKey: -        default: -            // what to do with these?  rectangular drag? -            position = selStart; -            ClearSelection(); -            break; -        } +    PasteboardRef pasteBoard; +    SelectionText selectedText; +    CFStringRef textString = NULL; +    bool isFileURL = false; +    if (!GetDragData(inDrag, pasteBoard, &selectedText, &isFileURL)) { +        return dragNotAcceptedErr; +    } + +    if (isFileURL) { +        NotifyURIDropped(selectedText.s);      } else { -        if (position >= selStart && position <= selEnd) { -            // droping on top of a selection from another app or control, clear it -            position = selStart; -            ClearSelection(); +        // figure out if this is a move or a paste +        DragAttributes attributes; +        SInt16 modifiers = 0;  +        GetDragAttributes( inDrag, &attributes ); +        bool moving = true; +     +        int position = PositionFromLocation(GetDragPoint(inDrag)); +        if ( attributes & kDragInsideSenderWindow ) { +            GetDragModifiers(inDrag, NULL, NULL, &modifiers); +            switch (modifiers & ~btnState)  // Filter out btnState (on for drop) +            { +            case optionKey: +                // default is copy text +                moving = false; +                break; +            case cmdKey: +            case cmdKey | optionKey: +            default: +                // what to do with these?  rectangular drag? +                break; +            }          } -    } -    // lets put the text in our document now -    if ( pdoc->InsertString( position, droppedText, droppedLen ) ) -    { -        SetEmptySelection( currentPos + droppedLen ); +        DropAt(position, selectedText.s, moving, selectedText.rectangular);      } -endDrag: -    delete[] droppedText; -    delete[] cstring; -    cstring = NULL; -     -    pdoc->EndUndoAction(); -    NotifyChange(); -     -    // dragleave IS called, but for some reason (probably to do with inDrag) -    // the hide hilite does not happen unless we do it here -    HideDragHilite( inDrag ); -      return noErr;  } +// Extended UTF8-UTF6-conversion to handle surrogate pairs correctly (CL265070) +void ScintillaMacOSX::InsertCharacters (const UniChar* buf, int len) +{ +    CFStringRef str = CFStringCreateWithCharactersNoCopy (NULL, buf, (UInt32) len, kCFAllocatorNull); +    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingMacRoman); +    CFRange range = { 0, len }; +    CFIndex bufLen; +    CFStringGetBytes (str, range, encoding, '?', false, NULL, 0, &bufLen); +    UInt8* utf8buf = new UInt8 [bufLen]; +    CFStringGetBytes (str, range, encoding, '?', false, utf8buf, bufLen, NULL); +    AddCharUTF ((char*) utf8buf, bufLen, false); +    delete [] utf8buf; +    CFRelease (str); +} +  /** The simulated message loop. */  sptr_t ScintillaMacOSX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {      switch (iMessage) { @@ -774,11 +903,9 @@ sptr_t ScintillaMacOSX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPa           break;      case WM_UNICHAR:          if (IsUnicodeMode()) { -            char utfval[4]; -            wchar_t wcs[2] = {wParam, 0}; -            unsigned int len = UTF8Length(wcs, 1); -            UTF8FromUTF16(wcs, 1, utfval, len); -            AddCharUTF(utfval, len); +            // Extended UTF8-UTF6-conversion to handle surrogate pairs correctly (CL265070) +            UniChar wcs[1] = { (UniChar) wParam}; +            InsertCharacters(wcs, 1);              return 1;          } else {              return 0; @@ -892,11 +1019,11 @@ void ScintillaMacOSX::SyncPaint(void* gc, PRectangle rc) {          sw->Init( gc, wMain.GetID() );          Paint(sw, rc);          if (paintState == paintAbandoned) { -          // XXX a bit of a hack to avoid excesive flashing when typing. +          // do a FULL paint. +          rcPaint = GetClientRectangle();            paintState = painting;            paintingAllText = true; -          Paint(sw, rc); -          // TODO: There is a chance that this causes an infinite drawing loop... +          Paint(sw, rcPaint);            wMain.InvalidateAll();          }          sw->Release(); @@ -1004,18 +1131,39 @@ void ScintillaMacOSX::Resize(int width, int height) {      }      ChangeSize(); -} -void ScintillaMacOSX::NotifyChange() { -    // TODO: How should this be implemented on OS X? Should it be? +    // fixup mouse tracking regions, this causes mouseenter/exit to work +    if (HIViewGetSuperview(GetViewRef()) != NULL) { +        RgnHandle rgn = NewRgn(); +        HIRect r; +        HIViewGetFrame( reinterpret_cast<HIViewRef>( GetViewRef() ), &r ); +        SetRectRgn(rgn, short (r.origin.x), short (r.origin.y),  +                  short (r.origin.x + r.size.width - (verticalScrollBarVisible ? scrollBarFixedSize : 0)),  +                  short (r.origin.y + r.size.height - (showSBHorizontal ? scrollBarFixedSize : 0))); +        if (mouseTrackingRef == NULL) { +            CreateMouseTrackingRegion(GetOwner(), rgn, NULL,  +                                        kMouseTrackingOptionsLocalClip, +                                        mouseTrackingID, NULL,  +                                        GetControlEventTarget( GetViewRef() ),  +                                        &mouseTrackingRef); +        } else { +            ChangeMouseTrackingRegion(mouseTrackingRef, rgn, NULL); +        } +        DisposeRgn(rgn); +    } else { +        if (mouseTrackingRef != NULL) { +            ReleaseMouseTrackingRegion(mouseTrackingRef); +        } +        mouseTrackingRef = NULL; +    }  }  pascal void ScintillaMacOSX::LiveScrollHandler( HIViewRef control, SInt16 part )  { -    SInt16 currentValue = GetControl32BitValue( control ); -    SInt16 min = GetControl32BitMinimum( control ); -    SInt16 max = GetControl32BitMaximum( control ); -    SInt16 page = GetControlViewSize( control ); +    int currentValue = GetControl32BitValue( control ); +    int min = GetControl32BitMinimum( control ); +    int max = GetControl32BitMaximum( control ); +    int page = GetControlViewSize( control );      // Get a reference to the Scintilla C++ object      ScintillaMacOSX* scintilla = NULL; @@ -1066,6 +1214,7 @@ pascal void ScintillaMacOSX::LiveScrollHandler( HIViewRef control, SInt16 part )          break;      case kControlIndicatorPart: +    case kControlNoPart:          newValue = currentValue;          break; @@ -1139,30 +1288,34 @@ bool ScintillaMacOSX::ScrollBarHit(HIPoint location) {  	return false;  } - -void ScintillaMacOSX::NotifyFocus(bool /*focus*/) { -    // TODO: How should this be implemented on OS X? Should it be? +void ScintillaMacOSX::NotifyFocus(bool focus) { +#ifdef EXT_INPUT +    ExtInput::activate (GetViewRef(), focus); +#endif +    if (NULL != notifyProc) +        notifyProc (notifyObj, WM_COMMAND,  +                (uintptr_t) ((focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS) << 16), +                (uintptr_t) GetViewRef());  } -typedef void (*SciNotifyFunc)(sptr_t *, long); -void ScintillaMacOSX::NotifyParent(SCNotification scn) { -    OSStatus err; -    sptr_t *ptr = NULL; -    SciNotifyFunc fn = NULL; +void ScintillaMacOSX::NotifyChange() { +    if (NULL != notifyProc) +        notifyProc (notifyObj, WM_COMMAND,  +                (uintptr_t) (SCEN_CHANGE << 16), +                (uintptr_t) GetViewRef()); +} -    // XXX do this at some other point, or otherwise cache the results -    err = GetControlProperty(GetViewRef(),  -                             scintillaNotifyObject, 0, -                             sizeof( sptr_t * ), NULL, &ptr ); -    if (err != noErr) return; -    err = GetControlProperty(GetViewRef(),  -                             scintillaNotifyFN, 0, -                             sizeof( SciNotifyFunc ), NULL, &fn ); -    if (err != noErr || !fn) return; +void ScintillaMacOSX::registerNotifyCallback(intptr_t windowid, SciNotifyFunc callback) { +    notifyObj = windowid; +    notifyProc = callback; +} -    scn.nmhdr.hwndFrom = GetViewRef(); -    scn.nmhdr.idFrom = (unsigned int)wMain.GetID(); -    fn(ptr, (long int)&scn); +void ScintillaMacOSX::NotifyParent(SCNotification scn) {  +    if (NULL != notifyProc) { +        scn.nmhdr.hwndFrom = (void*) this; +        scn.nmhdr.idFrom = (unsigned int)wMain.GetID(); +        notifyProc (notifyObj, WM_NOTIFY, (uintptr_t) 0, (uintptr_t) &scn); +    }  }  void ScintillaMacOSX::NotifyKey(int key, int modifiers) { @@ -1182,6 +1335,8 @@ void ScintillaMacOSX::NotifyURIDropped(const char *list) {      NotifyParent(scn);  } +#ifndef EXT_INPUT +// Extended UTF8-UTF6-conversion to handle surrogate pairs correctly (CL265070)  int ScintillaMacOSX::KeyDefault(int key, int modifiers) {      if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT) && (key < 256)) {          AddChar(key); @@ -1193,6 +1348,7 @@ int ScintillaMacOSX::KeyDefault(int key, int modifiers) {      }      //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);  } +#endif  template <class T, class U>  struct StupidMap @@ -1254,6 +1410,10 @@ pascal OSStatus ScintillaMacOSX::CommandEventHandler( EventHandlerCallRef /*inCa      if ( kind == kEventProcessCommand )      { +#ifdef EXT_INPUT +        // We are getting a HI command, so stop extended input +        ExtInput::stop (scintilla->GetViewRef()); +#endif          // Find the method pointer that matches this command          void (ScintillaMacOSX::*methodPtr)() = StupidMapFind( processCommands, command.commandID ); @@ -1316,60 +1476,37 @@ bool ScintillaMacOSX::AlwaysTrue()  }  void ScintillaMacOSX::CopyToClipboard(const SelectionText &selectedText) { -    if (selectedText.len == 0) -        return; - -    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); - -    // Create a CFString from the ASCII/UTF8 data, convert it to UTF16 -    CFStringRef string = CFStringCreateWithBytes( NULL, reinterpret_cast<UInt8*>( selectedText.s ), selectedText.len - 1, encoding, false ); -    assert( string != NULL ); - -    CFIndex numUniChars = CFStringGetLength( string ); -    UniChar* buffer = new UniChar[ numUniChars ]; -    CFStringGetCharacters( string, CFRangeMake( 0, numUniChars ), buffer ); - +    PasteboardRef theClipboard; +    SetPasteboardData(theClipboard, selectedText);      // Done with the CFString -    CFRelease( string ); -    string = NULL; - -    OSStatus err; -    err = ClearCurrentScrap(); -    assert( err == noErr ); - -    ScrapRef scrap = NULL; -    err = GetCurrentScrap( &scrap ); -    assert( err == noErr && scrap != NULL ); - -    err = PutScrapFlavor( scrap, kScrapFlavorTypeUnicode, 0, sizeof( UniChar ) * numUniChars, buffer ); -    assert( err == noErr ); -    err = PutScrapFlavor( scrap, kScrapFlavorTypeText, 0, sizeof( char ) * selectedText.len, reinterpret_cast<UInt8*>( selectedText.s ) ); -    assert( err == noErr ); - -    // Done with the UniChar* buffer -    delete[] buffer; -    buffer = NULL;   +    CFRelease( theClipboard );  }  void ScintillaMacOSX::Copy()  {      if (currentPos != anchor) { +#ifdef EXT_INPUT +        ExtInput::stop (GetViewRef());  +#endif          SelectionText selectedText;          CopySelectionRange(&selectedText); +        fprintf(stderr, "copied text is rectangular? %d\n", selectedText.rectangular);          CopyToClipboard(selectedText);      }  }  bool ScintillaMacOSX::CanPaste()  { -    ScrapRef scrap = NULL; -    OSStatus err; -    err = GetCurrentScrap( &scrap ); -    assert( err == noErr && scrap != NULL ); +    if (!Editor::CanPaste()) +        return false; + +    PasteboardRef theClipboard; +    bool isFileURL = false; -    ScrapFlavorFlags flavorFlags; -    return GetScrapFlavorFlags ( scrap, kScrapFlavorTypeUnicode, &flavorFlags ) == noErr || -          GetScrapFlavorFlags ( scrap, kScrapFlavorTypeText, &flavorFlags ) == noErr; +    PasteboardCreate( kPasteboardClipboard, &theClipboard ); +    bool ok = GetPasteboardData(theClipboard, NULL, &isFileURL); +    CFRelease( theClipboard ); +    return ok;  }  void ScintillaMacOSX::Paste() @@ -1380,112 +1517,34 @@ void ScintillaMacOSX::Paste()  // XXX there is no system flag (I can find) to tell us that a paste is rectangular, so   //     applications must implement an additional command (eg. option-V like BBEdit)  //     in order to provide rectangular paste -void ScintillaMacOSX::Paste(bool isRectangular) +void ScintillaMacOSX::Paste(bool forceRectangular)  { -    // Make sure that we CAN paste -    if ( ! CanPaste() ) return; - -    // Get the clipboard reference -    ScrapRef scrap = NULL; -    OSStatus err; -    err = GetCurrentScrap( &scrap ); -    assert( err == noErr && scrap != NULL ); - -    ScrapFlavorFlags flavorFlags; -    Size bytes = 0; -    CFStringRef string = NULL; -    if (GetScrapFlavorFlags ( scrap, kScrapFlavorTypeUnicode, &flavorFlags ) == noErr) -    { -        // No error, we have unicode data in a Scrap. Find out how many bytes of data it is. -        err = GetScrapFlavorSize( scrap, kScrapFlavorTypeUnicode, &bytes ); -        assert( err == noErr && bytes != 0 ); -        Size numUniChars = bytes / sizeof( UniChar ); -     -        // Allocate a buffer for the text using Core Foundation -        UniChar* buffer = reinterpret_cast<UniChar*>( CFAllocatorAllocate( NULL, bytes, 0 ) ); -        assert( buffer != NULL ); -     -        // Get a copy of the text -        Size nextBytes = bytes; -        err = GetScrapFlavorData( scrap, kScrapFlavorTypeUnicode, &nextBytes, buffer ); -        assert( err == noErr && nextBytes == bytes ); -     -        // Create a CFString which wraps and takes ownership of the buffer -        string = CFStringCreateWithCharactersNoCopy( NULL, buffer, numUniChars, NULL ); -        assert( string != NULL ); -        buffer = NULL; // string now owns this buffer -    } else if (GetScrapFlavorFlags ( scrap, kScrapFlavorTypeText, &flavorFlags ) == noErr) { -        // No error, we have unicode data in a Scrap. Find out how many bytes of data it is. -        err = GetScrapFlavorSize( scrap, kScrapFlavorTypeText, &bytes ); -        assert( err == noErr && bytes != 0 ); -     -        // Allocate a buffer for the text using Core Foundation -        char* buffer = reinterpret_cast<char*>( CFAllocatorAllocate( NULL, bytes + 1, 0 ) ); -        assert( buffer != NULL ); -     -        // Get a copy of the text -        Size nextBytes = bytes; -        err = GetScrapFlavorData( scrap, kScrapFlavorTypeText, &nextBytes, buffer ); -        assert( err == noErr && nextBytes == bytes ); -        buffer[bytes]=0; -        // Create a CFString which wraps and takes ownership of the buffer -        string = CFStringCreateWithCStringNoCopy( NULL, buffer, kCFStringEncodingMacRoman, NULL ); -        assert( string != NULL ); -        buffer = NULL; // string now owns this buffer -    } else { -        // a flavor we do not understand +    PasteboardRef theClipboard; +    SelectionText selectedText; +    selectedText.rectangular = forceRectangular; +    bool isFileURL = false; +    PasteboardCreate( kPasteboardClipboard, &theClipboard ); +    bool ok = GetPasteboardData(theClipboard, &selectedText, &isFileURL); +    CFRelease( theClipboard ); +    fprintf(stderr, "paste is rectangular? %d\n", selectedText.rectangular); +    if (!ok || !selectedText.s) +        // no data or no flavor we support          return; -    } - - -    // Allocate a buffer, plus the null byte -    CFIndex numUniChars = CFStringGetLength( string ); -    CFStringEncoding encoding = ( IsUnicodeMode() ? kCFStringEncodingUTF8 : kCFStringEncodingASCII); -    CFIndex maximumByteLength = CFStringGetMaximumSizeForEncoding( numUniChars, encoding ) + 1; -    char* cstring = new char[maximumByteLength]; -    CFIndex usedBufferLength = 0; -    CFIndex numCharsConverted; -    numCharsConverted = CFStringGetBytes( string, CFRangeMake( 0, numUniChars ), encoding, -                              '?', false, reinterpret_cast<UInt8*>( cstring ), -                              maximumByteLength, &usedBufferLength ); -    cstring[usedBufferLength] = '\0'; // null terminate the ASCII/UTF8 string -    assert( numCharsConverted == numUniChars ); - -    // Default allocator releases both the CFString and the UniChar buffer (text) -    CFRelease( string ); -    string = NULL;       - -    // determine whether a BOM is in the string.  Apps like Emacs prepends a BOM -    // to the string, CFStrinGetBytes reflects that (though it may change in the conversion) -    // so we need to remove it before pasting into our buffer.  TextWrangler has no -    // problem dealing with BOM when pasting into it. -    int bomLen = BOMlen((unsigned char *)cstring); -    // convert line endings to the document line ending -    int newlen = 0; -    char *pasted = Document::TransformLineEnds(&newlen, -                                                cstring + bomLen, -                                                usedBufferLength - bomLen, -                                                pdoc->eolMode); -          pdoc->BeginUndoAction();      ClearSelection(); - -    if (isRectangular) { +    if (selectedText.rectangular) {          int selStart = SelectionStart(); -        PasteRectangular(selStart, pasted, newlen); +        PasteRectangular(selStart, selectedText.s, selectedText.len);      } else  -    if ( pdoc->InsertString( currentPos, pasted, newlen ) ) { -        SetEmptySelection( currentPos + newlen ); +    if ( pdoc->InsertString( currentPos, selectedText.s, selectedText.len ) ) { +        SetEmptySelection( currentPos + selectedText.len );      } -    delete[] pasted; -    delete[] cstring; -    cstring = NULL; -          pdoc->EndUndoAction(); -    NotifyChange(); +      Redraw(); +    EnsureCaretVisible();  }  void ScintillaMacOSX::CreateCallTipWindow(PRectangle rc) { @@ -1602,7 +1661,7 @@ void ScintillaMacOSX::AddToPopUp( const char *label, int cmd, bool enabled )          return;      } -    CFStringRef string = CFStringCreateWithCString( NULL, label, kTextEncodingMacRoman ); +    CFStringRef string = CFStringCreateWithCString( NULL, label,  kCFStringEncodingUTF8 );      OSStatus err;      err = AppendMenuItemTextWithCFString( reinterpret_cast<MenuRef>( popup.GetID() ),                                 string, attributes, macCommand, NULL ); @@ -1702,10 +1761,12 @@ static inline int KeyTranslate( UniChar unicodeChar )          return SCK_HOME;      case kEndCharCode:          return SCK_END; +#ifndef EXT_INPUT      case kPageUpCharCode:          return SCK_PRIOR;      case kPageDownCharCode:          return SCK_NEXT; +#endif      case kDeleteCharCode:          return SCK_DELETE;      // TODO: Is there an insert key in the mac world? My insert key is the "help" key @@ -1714,6 +1775,30 @@ static inline int KeyTranslate( UniChar unicodeChar )      case kEnterCharCode:      case kReturnCharCode:          return SCK_RETURN; +#ifdef EXT_INPUT +    // BP 2006-08-22: These codes below should not be translated. Otherwise TextInput() will fail for keys like SCK_ADD, which is '+'. +    case kBackspaceCharCode: +        return SCK_BACK; +    case kFunctionKeyCharCode: +    case kBellCharCode: +    case kVerticalTabCharCode: +    case kFormFeedCharCode: +    case 14: +    case 15: +    case kCommandCharCode: +    case kCheckCharCode: +    case kAppleLogoCharCode: +    case 21: +    case 22: +    case 23: +    case 24: +    case 25: +    case 26: +    case kEscapeCharCode: +        return 0; // ignore +    default: +        return unicodeChar; +#else      case kEscapeCharCode:          return SCK_ESCAPE;      case kBackspaceCharCode: @@ -1730,6 +1815,7 @@ static inline int KeyTranslate( UniChar unicodeChar )          return kFunctionKeyCharCode;      default:          return 0; +#endif      }  } @@ -1775,6 +1861,39 @@ OSStatus ScintillaMacOSX::TextInput( TCarbonEvent& event )      const int numUniChars = actualSize / sizeof( UniChar ); +#ifdef EXT_INPUT +    UniChar* text = new UniChar [numUniChars]; +    err = event.GetParameter( kEventParamTextInputSendText, typeUnicodeText, actualSize, text ); +    PLATFORM_ASSERT( err == noErr ); + +    int modifiers = GetCurrentEventKeyModifiers(); +     +    // Loop over all characters in sequence +    for (int i = 0; i < numUniChars; i++) +    { +        UniChar key = KeyTranslate( text[i] ); +        if (!key) +            continue; + +        bool consumed = false; + +        // need to go here first so e.g. Tab indentation works +        KeyDown ((int) key, (modifiers & shiftKey) != 0 || (modifiers & cmdKey) != 0, (modifiers & controlKey) != 0 || (modifiers & cmdKey) != 0, +                 (modifiers & optionKey) != 0 || (modifiers & cmdKey) != 0, &consumed); + +        // BP 2007-01-08: 1452623 Second Cmd+s to save doc inserts an "s" into the text on Mac. +        // At this point we need to ignore all cmd/option keys with char value smaller than 32 +        if( !consumed ) +            consumed = ( modifiers & ( cmdKey | optionKey ) ) != 0 && text[i] < 32; + +        // If not consumed, insert the original key +        if (!consumed) +            InsertCharacters (text+i, 1); +    } + +    delete[] text; +    return noErr; +#else      // Allocate a buffer for the text using Core Foundation      UniChar* text = reinterpret_cast<UniChar*>( CFAllocatorAllocate( CFAllocatorGetDefault(), actualSize, 0 ) );      assert( text != NULL ); @@ -1873,6 +1992,7 @@ OSStatus ScintillaMacOSX::TextInput( TCarbonEvent& event )      string = NULL;        return err; +#endif  }  UInt32 ScintillaMacOSX::GetBehaviors() @@ -1891,6 +2011,7 @@ OSStatus ScintillaMacOSX::MouseEntered(HIPoint& location, UInt32 /*inKeyModifier          } else {              // reset to normal, buttonmove will change for other area's in the editor              WndProc(SCI_SETCURSOR, (long int)SC_CURSORNORMAL, 0); +            ButtonMove( Point( static_cast<int>( location.x ), static_cast<int>( location.y ) ) );          }          return noErr;      } @@ -1945,7 +2066,7 @@ OSStatus ScintillaMacOSX::MouseDown( HIPoint& location, UInt32 modifiers, EventM  #if !defined(CONTAINER_HANDLES_EVENTS)      OSStatus err;      err = SetKeyboardFocus( this->GetOwner(), this->GetViewRef(), 1 ); -    assert( err == noErr ); +    ::SetUserFocusWindow(::HIViewGetWindow( this->GetViewRef() ));      return noErr;  #else      return eventNotHandledErr; // allow event to go to container diff --git a/macosx/ScintillaMacOSX.h b/macosx/ScintillaMacOSX.h index 1b386b48b..66d4f0f68 100644 --- a/macosx/ScintillaMacOSX.h +++ b/macosx/ScintillaMacOSX.h @@ -2,8 +2,10 @@   *  ScintillaMacOSX.h   *  tutorial   * - *  Created by Evan Jones on Sun Sep 01 2002. - *  Copyright (c) 2002 __MyCompanyName__. All rights reserved. + *  Original code by Evan Jones on Sun Sep 01 2002. + *  Contributors: + *  Shane Caraveo, ActiveState + *  Bernd Paradies, Adobe   *   */  #include "TView.h" @@ -50,20 +52,41 @@  #include "ScintillaCallTip.h"  static const OSType scintillaMacOSType = 'Scin'; -static const OSType scintillaNotifyObject = 'Snob'; -static const OSType scintillaNotifyFN = 'Snfn';  namespace Scintilla { +/** +On the Mac, there is no WM_COMMAND or WM_NOTIFY message that can be sent +back to the parent. Therefore, there must be a callback handler that acts +like a Windows WndProc, where Scintilla can send notifications to. Use +ScintillaMacOSX::registerNotifyHandler() to register such a handler. +Messgae format is: +<br> +WM_COMMAND: HIWORD (wParam) = notification code, LOWORD (wParam) = 0 (no control ID), lParam = ScintillaMacOSX* +<br> +WM_NOTIFY: wParam = 0 (no control ID), lParam = ptr to SCNotification structure, with hwndFrom set to ScintillaMacOSX* +*/ +typedef void(*SciNotifyFunc) (intptr_t windowid, unsigned int iMessage, uintptr_t wParam, uintptr_t lParam); + +/** +Scintilla sends these two messages to the nofity handler. Please refer +to the Windows API doc for details about the message format. +*/ +#define	WM_COMMAND	1001 +#define WM_NOTIFY	1002 +  class ScintillaMacOSX : public ScintillaBase, public TView  {   public:      HIViewRef vScrollBar;      HIViewRef hScrollBar;      SInt32 scrollBarFixedSize; +    SciNotifyFunc	notifyProc; +    intptr_t		notifyObj;      bool capturedMouse; -    bool inDragSession; // true if scintilla initiated the drag session +    // true if scintilla initiated the drag session +    bool inDragSession() { return inDragDrop == ddDragging; };       bool isTracking;       // Private so ScintillaMacOSX objects can not be copied @@ -82,15 +105,26 @@ public:      /** Returns the HIView object kind, needed to subclass TView. */      virtual ControlKind GetKind() { return kScintillaKind; } +    /// Register the notify callback +    void registerNotifyCallback(intptr_t windowid, SciNotifyFunc callback);  private:      virtual void Initialise();      virtual void Finalise(); +     +    // pasteboard support +    bool GetPasteboardData(PasteboardRef &pasteBoard, +                           SelectionText *selectedText, bool *isFileURL); +    void SetPasteboardData(PasteboardRef &pasteBoard, +                           const SelectionText &selectedText); +    char *GetStringFromCFString(CFStringRef &textString, int *textLen); + +    // Drag and drop      virtual void StartDrag();      Scintilla::Point GetDragPoint(DragRef inDrag); -    OSStatus GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, CFStringRef *textString); +    bool GetDragData(DragRef inDrag, PasteboardRef &pasteBoard, +                         SelectionText *selectedText, +                         bool *isFileURL);      void SetDragCursor(DragRef inDrag); - -    // Drag and drop      virtual bool DragEnter(DragRef inDrag );      virtual bool DragWithin(DragRef inDrag );      virtual bool DragLeave(DragRef inDrag ); @@ -104,6 +138,7 @@ private:      MouseTrackingRegionID mouseTrackingID;      HIPoint GetLocalPoint(::Point pt); +    void InsertCharacters (const UniChar* buf, int len);      static pascal void IdleTimerEventHandler(EventLoopTimerRef inTimer,                                               EventLoopIdleTimerMessage inState,                                               void *scintilla ); @@ -136,7 +171,10 @@ public: // Public for scintilla_send_message      virtual void NotifyParent(SCNotification scn);      void NotifyKey(int key, int modifiers);      void NotifyURIDropped(const char *list); +#ifndef EXT_INPUT +    // Extended UTF8-UTF6-conversion to handle surrogate pairs correctly (CL265070)      virtual int KeyDefault(int key, int modifiers); +#endif      static pascal OSStatus CommandEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* data );      bool HasSelection(); diff --git a/macosx/TView.cxx b/macosx/TView.cxx index 9ed02b110..00a354ae7 100644 --- a/macosx/TView.cxx +++ b/macosx/TView.cxx @@ -111,12 +111,8 @@ TView::~TView()  	// If we have installed our custom mouse events handler on the window,  	// go forth and remove it. Note: -1 is used to indicate that no handler has  	// been installed yet, but we want to once we get a window. -	if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast<void*>( -1 ) ) -		{ -		OSStatus err; -		err = RemoveEventHandler( mouseEventHandler ); -		assert( err == noErr ); -		} +	if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast<void*>( -1 ) )  +		RemoveEventHandler( mouseEventHandler );  	mouseEventHandler = NULL;  } @@ -549,7 +545,6 @@ OSStatus TView::ActivateInterface(  					result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ),  									  kControlMouseEvents ); -					assert( result == noErr );  					}  				if ( this->GetOwner() != NULL ) @@ -558,7 +553,6 @@ OSStatus TView::ActivateInterface(  					if ( mouseEventHandler != NULL &&  mouseEventHandler != reinterpret_cast<void*>( -1 ) )  						{  						result = RemoveEventHandler( mouseEventHandler ); -						assert( result != NULL );  						}  					mouseEventHandler = NULL; @@ -570,11 +564,9 @@ OSStatus TView::ActivateInterface(  						{ kEventClassMouse, kEventMouseDragged },  					}; -					assert( mouseEventHandler == NULL );  					result = InstallEventHandler( GetWindowEventTarget( this->GetOwner() ), WindowEventHandler,  								      GetEventTypeCount( kWindowMouseEvents ), kWindowMouseEvents,   								      this, &mouseEventHandler ); -					assert( result == noErr && mouseEventHandler != NULL );  					}  				// If we have no window yet. Set the mouseEventHandler to -1 so when we get one we  				// will install the event handler @@ -595,7 +587,6 @@ OSStatus TView::ActivateInterface(  		      result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ),  						       kControlMouseEvents ); -		      assert( result == noErr );  		    }  		  } @@ -697,8 +688,8 @@ pascal OSStatus TView::ViewEventHandler(  	OSStatus			result;  	TView*				view = (TView*) inUserData;  	TCarbonEvent		event( inEvent ); -	if (view->debugPrint) -	  fprintf(stderr,"TView::ViewEventHandler\n"); +	//if (view->debugPrint) +	//  fprintf(stderr,"TView::ViewEventHandler\n");  	result = view->HandleEvent( inCallRef, event );  	return result; @@ -714,7 +705,8 @@ pascal OSStatus TView::WindowEventHandler(  	TCarbonEvent event( inEvent );  	const WindowRef window = view->GetOwner(); -	assert( window != NULL ); +	if (NULL == window) +		return eventNotHandledErr;  	// If the window is not active, let the standard window handler execute.  	if ( ! IsWindowActive( window ) ) return eventNotHandledErr; @@ -722,7 +714,8 @@ pascal OSStatus TView::WindowEventHandler(  	  fprintf(stderr,"TView::WindowEventHandler\n");  	const HIViewRef rootView = HIViewGetRoot( window ); -	assert( rootView != NULL ); +	if (NULL == rootView) +		return eventNotHandledErr;  	// TODO: On OS X 10.3, test if this bug still exists  	// This is a hack to work around a bug in the OS. See: @@ -739,19 +732,18 @@ pascal OSStatus TView::WindowEventHandler(  		// convert screen coords to window relative  		Rect bounds;  		err = GetWindowBounds( window, kWindowStructureRgn, &bounds ); -		assert( err == noErr ); - -		ptMouse.x -= bounds.left; -		ptMouse.y -= bounds.top; - -		event.SetParameter( kEventParamWindowMouseLocation, ptMouse ); +		if( err == noErr ) +		{ +			ptMouse.x -= bounds.left; +			ptMouse.y -= bounds.top; +			event.SetParameter( kEventParamWindowMouseLocation, ptMouse ); +		}  	}  	HIViewRef targetView = NULL;  	err = HIViewGetViewForMouseEvent( rootView, inEvent, &targetView ); -	assert( err == noErr && targetView != NULL ); -	if (view->debugPrint) -	  fprintf(stderr,"TView::WindowEventHandler root[%08X] viewRef[%08X] targetView[%08X]\n", rootView, view->GetViewRef(), targetView); +	//if (view->debugPrint) +	//  fprintf(stderr,"TView::WindowEventHandler root[%08X] viewRef[%08X] targetView[%08X]\n", rootView, view->GetViewRef(), targetView);  	if ( targetView == view->GetViewRef() || event.GetKind() == kEventMouseDragged )  		{  		return view->HandleEvent( inCallRef, event ); @@ -1076,7 +1068,6 @@ OSStatus TView::HandleEvent(  				// some other kind of Control event  				default: -					assert( false );  					break;  			}  			break; @@ -1086,70 +1077,59 @@ OSStatus TView::HandleEvent(  			break;  		case kEventClassMouse: +		{  			result = inEvent.GetParameter<HIPoint>( kEventParamWindowMouseLocation, typeHIPoint, &where );  			HIViewConvertPoint( &where, NULL, fViewRef ); -			assert( result == noErr );  			UInt32 inKeyModifiers;  			result = inEvent.GetParameter( kEventParamKeyModifiers, &inKeyModifiers ); -			assert( result == noErr ); -			 +			if( result != noErr ) +				inKeyModifiers = 0; +			EventMouseButton inMouseButton = 0; +			result = inEvent.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton, &inMouseButton ); +			if (noErr != result) +				// assume no button is pressed if there is no button info +				inMouseButton = 0; +			UInt32 inClickCount; +			result = inEvent.GetParameter( kEventParamClickCount, &inClickCount ); +			if( result != noErr ) +				inClickCount = 0; +				  			switch ( inEvent.GetKind() ) -				{ +			{  				case kEventMouseWheelMoved: -					{ -						EventMouseWheelAxis inAxis; -						result = inEvent.GetParameter<EventMouseWheelAxis>( kEventParamMouseWheelAxis, typeMouseWheelAxis, &inAxis ); -						assert( noErr == result ); +				{ +					EventMouseWheelAxis inAxis; +					result = inEvent.GetParameter<EventMouseWheelAxis>( kEventParamMouseWheelAxis, typeMouseWheelAxis, &inAxis ); -						SInt32 inDelta; -						result = inEvent.GetParameter<SInt32>( kEventParamMouseWheelDelta, typeSInt32, &inDelta ); -						assert( noErr == result ); +					SInt32 inDelta; +					result = inEvent.GetParameter<SInt32>( kEventParamMouseWheelDelta, typeSInt32, &inDelta ); -						result = MouseWheelMoved( inAxis, inDelta, inKeyModifiers );					 -					} +					result = MouseWheelMoved( inAxis, inDelta, inKeyModifiers ); +					break;				 +				} +				case kEventMouseDown: +					result = MouseDown( where, inKeyModifiers, inMouseButton, inClickCount, inEvent );  					break; -					 -					 -				// some other kind of Mouse event: This is (in my opinion) an error -				// TODO: There is also a MouseMoved event that we do not handle -				default: -					{ -						EventMouseButton inMouseButton; -						result = inEvent.GetParameter<EventMouseButton>( kEventParamMouseButton, typeMouseButton, &inMouseButton ); -						assert( result == noErr ); - -						UInt32 inClickCount; -						result = inEvent.GetParameter( kEventParamClickCount, &inClickCount ); -						assert( result == noErr ); - -						switch ( inEvent.GetKind() ) -						  { -						  case kEventMouseDown: -						    result = MouseDown( where, inKeyModifiers, inMouseButton, inClickCount, inEvent ); -						    break; -						  case kEventMouseUp: -						    result = MouseUp( where, inKeyModifiers, inMouseButton, inClickCount ); -						    break; -						  case kEventMouseExited: -						    result = MouseExited( where, inKeyModifiers, inMouseButton, inClickCount ); -						    break; -						  case kEventMouseEntered: -						    result = MouseEntered( where, inKeyModifiers, inMouseButton, inClickCount ); -						    break; -						  case kEventMouseMoved: -						  case kEventMouseDragged: -						    result = MouseDragged( where, inKeyModifiers, inMouseButton, inClickCount ); -						    break; -						  } -					} +				case kEventMouseUp: +					result = MouseUp( where, inKeyModifiers, inMouseButton, inClickCount );  					break; -				} -				break; -			 +				case kEventMouseExited: +					result = MouseExited( where, inKeyModifiers, inMouseButton, inClickCount ); +					break; +				case kEventMouseEntered: +					result = MouseEntered( where, inKeyModifiers, inMouseButton, inClickCount ); +					break; +				case kEventMouseMoved: +				case kEventMouseDragged: +					result = MouseDragged( where, inKeyModifiers, inMouseButton, inClickCount ); +					break; +				default:; +			} +			break; +                }  		// some other event class  		default: -			assert( false );  			break;  	} diff --git a/macosx/makefile b/macosx/makefile index 02ff7998a..73342ce3e 100644 --- a/macosx/makefile +++ b/macosx/makefile @@ -50,10 +50,15 @@ ifdef CONTAINER_HANDLES_EVENTS  CONTAINER=-DCONTAINER_HANDLES_EVENTS=1  endif +ifdef EXT_INPUT +EXT_INPUT=-DEXT_INPUT +EXTOBS=ExtInput.o +endif +  .cxx.o: -	$(CC) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(INCLUDEDIRS) -c $< +	$(CC) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(EXT_INPUT) $(INCLUDEDIRS) -c $<  .c.o: -	$(CCOMP) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(INCLUDEDIRS) -w -c $< +	$(CCOMP) $(CXXFLAGS) $(OPTIONS) $(DFLAGS) $(CONTAINER) $(ARCHFLAGS) $(EXT_INPUT) $(INCLUDEDIRS) -w -c $<  #++Autogenerated -- run src/LexGen.py to regenerate  #**LEXOBJS=\\\n\(\*.o \) @@ -87,13 +92,13 @@ COMPLIB=DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \  	ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatMacOSX.o \  	KeyMap.o LineMarker.o ScintillaMacOSX.o CellBuffer.o ViewStyle.o \  	RESearch.o RunStyles.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \ -        TCarbonEvent.o TView.o ScintillaCallTip.o \ +        TCarbonEvent.o TView.o ScintillaCallTip.o $(EXTOBS) \  	$(LEXOBJS) -$(STATICLIB): $(COMPLIB) +$(STATICLIB): $(COMPLIB)   	$(LIBTOOL) -static -o $@ $^ -$(DYNAMICLIB): $(COMPLIB) +$(DYNAMICLIB): $(COMPLIB)   	$(CC) -dynamic -o $@ $(DYN_FLAGS) $^  # Generate header files from Scintilla.iface | 
