aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authormixedpuppy <devnull@localhost>2007-12-05 23:06:58 +0000
committermixedpuppy <devnull@localhost>2007-12-05 23:06:58 +0000
commitffa2c5b99b0eb534498a550d11ac5debc1204c32 (patch)
tree7a56a2c74170e09c85b98ecdeebce310d001ad7d
parenta9e5e58a8d7875426b4d6d009254fc6ec191cbba (diff)
downloadscintilla-mirror-ffa2c5b99b0eb534498a550d11ac5debc1204c32.tar.gz
modified version of adobe OSX patches. Most of these patches are provided by Adobe, though I've
reorganized a lot of them - improved drag/drop - make copy/paste use modern pasteboard api's - optimized textlayout usage - reduce assertions for debug builds - implement IME support - other minor things patches are available in openkomodo, which is a good test ground for scintilla osx (until someone ports SCiTE).
-rw-r--r--macosx/ExtInput.cxx608
-rw-r--r--macosx/ExtInput.h64
-rw-r--r--macosx/PlatMacOSX.cxx395
-rw-r--r--macosx/PlatMacOSX.h6
-rw-r--r--macosx/QuartzTextLayout.h57
-rw-r--r--macosx/QuartzTextStyle.h27
-rw-r--r--macosx/QuartzTextStyleAttribute.h24
-rw-r--r--macosx/ScintillaMacOSX.cxx837
-rw-r--r--macosx/ScintillaMacOSX.h54
-rw-r--r--macosx/TView.cxx132
-rw-r--r--macosx/makefile15
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), &regionClass);
+ }
+ 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