diff options
Diffstat (limited to 'src/gui_mac.c')
-rw-r--r-- | src/gui_mac.c | 5820 |
1 files changed, 5820 insertions, 0 deletions
diff --git a/src/gui_mac.c b/src/gui_mac.c new file mode 100644 index 0000000000..2b74c63281 --- /dev/null +++ b/src/gui_mac.c @@ -0,0 +1,5820 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * GUI/Motif support by Robert Webb + * Macintosh port by Dany St-Amant + * and Axel Kielhorn + * Port to MPW by Bernhard PrŸmmer + * Initial Carbon port by Ammon Skidmore + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * NOTE: Comment mentionning FAQ refer to the book: + * "Macworld Mac Programming FAQs" from "IDG Books" + */ + +/* + * WARNING: Vim must be able to compile without Carbon + * As the desired minimum requirement are circa System 7 + * (I want to run it on my Mac Classic) (Dany) + */ + +/* + * TODO: Change still to merge from the macvim's iDisk + * + * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse + * uses of MenuItemIndex, changes in gui_mch_set_shellsize, + * ScrapManager error handling. + * Comments about function remaining to Carbonize. + * + */ + +/* TODO: find the best place for this (Dany) */ +#if 0 +# if ! TARGET_API_MAC_CARBON +/* Enable the new API functions even when not compiling for Carbon */ +/* Apple recomends Universal Interface 3.3.2 or later */ +# define OPAQUE_TOOLBOX_STRUCTS 1 +# define ACCESSOR_CALLS_ARE_FUNCTIONS 1 +/* Help Menu not supported by Carbon */ +# define USE_HELPMENU +# endif +#endif + +#include <Devices.h> /* included first to avoid CR problems */ +#include "vim.h" + +/* Enable Contextual Menu Support */ +#if UNIVERSAL_INTERFACES_VERSION >= 0x0320 +# define USE_CTRLCLICKMENU +#endif + +/* Put Vim Help in MacOS Help */ +#define USE_HELPMENU + +/* Enable AEVENT */ +#define USE_AEVENT + +/* Compile as CodeWarior External Editor */ +#if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT) +# define USE_AEVENT /* Need Apple Event Support */ +#endif + +/* The VIM creator is CodeWarior specific */ +#if !(defined(__MRC__) || defined(__SC__) || defined(__APPLE_CC__)) +# define USE_VIM_CREATOR_ID +#else +# if 0 /* Was this usefull for some compiler? (Dany) */ +static OSType _fcreator = 'VIM!'; +static OSType _ftype = 'TEXT'; +# endif +#endif + +/* CARBON version only tested with Project Builder under MacOS X */ +#undef USE_CARBONIZED +#if (defined(__APPLE_CC__) || defined(__MRC__)) && defined(TARGET_API_MAC_CARBON) +# if TARGET_API_MAC_CARBON +# define USE_CARBONIZED +# endif +#endif + +#undef USE_MOUSEWHEEL +#if defined(MACOS_X) && defined(USE_CARBONIZED) +# define USE_MOUSEWHEEL +static EventHandlerUPP mouseWheelHandlerUPP = NULL; +#endif + +/* Debugging feature: start Vim window OFFSETed */ +#undef USE_OFFSETED_WINDOW + +/* Debugging feature: use CodeWarior SIOUX */ +#undef USE_SIOUX + + +/* Include some file. TODO: move into os_mac.h */ +#include <Menus.h> +#include <Resources.h> +#if !TARGET_API_MAC_CARBON +#include <StandardFile.h> +#include <Traps.h> +#endif +#include <Balloons.h> +#include <Processes.h> +#ifdef USE_AEVENT +# include <AppleEvents.h> +# include <AERegistry.h> +#endif +#ifdef USE_CTRLCLICKMENU +# include <Gestalt.h> +#endif +#ifdef USE_SIOUX +# include <stdio.h> +# include <sioux.h> +# include <console.h> +#endif +#if UNIVERSAL_INTERFACES_VERSION >= 0x0330 +# include <ControlDefinitions.h> +# include <Navigation.h> /* Navigation only part of ?? */ +#endif + +#if TARGET_API_MAC_CARBON && 0 +/* New Help Interface for Mac, not implemented yet.*/ +# include <MacHelp.h> +#endif + +/* + * Translate new name to old ones + * New function only available in MacOS 8.5, + * So use old one to be compatible back to System 7 + */ +#ifndef USE_CARBONIZED +# undef EnableMenuItem +# define EnableMenuItem EnableItem +# undef DisableMenuItem +# define DisableMenuItem DisableItem +#endif + +/* Carbon does not support the Get/SetControll functions, + * use Get/SetControl32Bit instead and rename for non-carbon + * systems. + */ + +#ifndef USE_CARBONIZED +# undef SetControl32BitMaximum +# define SetControl32BitMaximum SetControlMaximum +# undef SetControl32BitMinimum +# define SetControl32BitMinimum SetControlMinimum +# undef SetControl32BitValue +# define SetControl32BitValue SetControlValue +# undef GetControl32BitValue +# define GetControl32BitValue GetControlValue +#endif + +/* + * ??? + */ + +#define kNothing 0 +#define kCreateEmpty 2 /*1*/ +#define kCreateRect 2 +#define kDestroy 3 + +/* + * Dany: Don't like those... + */ + +#define topLeft(r) (((Point*)&(r))[0]) +#define botRight(r) (((Point*)&(r))[1]) + + +/* Time of last mouse click, to detect double-click */ +static long lastMouseTick = 0; + +/* ??? */ +static RgnHandle cursorRgn; +static RgnHandle dragRgn; +static Rect dragRect; +static short dragRectEnbl; +static short dragRectControl; + +/* This variable is set when waiting for an event, which is the only moment + * scrollbar dragging can be done directly. It's not allowed while commands + * are executed, because it may move the cursor and that may cause unexpected + * problems (e.g., while ":s" is working). + */ +static int allow_scrollbar = FALSE; + +/* Last mouse click caused contextual menu, (to provide proper release) */ +#ifdef USE_CTRLCLICKMENU +static short clickIsPopup; +#endif + +/* Feedback Action for Scrollbar */ +ControlActionUPP gScrollAction; +ControlActionUPP gScrollDrag; + +/* Keeping track of which scrollbar is being dragged */ +static ControlHandle dragged_sb = NULL; + +/* + * The Quickdraw global is predefined in CodeWarior + * but is not in Apple MPW + */ +#if (defined(__MRC__) || defined(__SC__)) +# if !(defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON) +QDGlobals qd; +# endif +#endif + +/* Colors Macros */ +#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b) +#define Red(c) ((c & 0x00FF0000) >> 16) +#define Green(c) ((c & 0x0000FF00) >> 8) +#define Blue(c) ((c & 0x000000FF) >> 0) + +/* Key mapping */ + +#define vk_Esc 0x35 /* -> 1B */ + +#define vk_F1 0x7A /* -> 10 */ +#define vk_F2 0x78 /*0x63*/ +#define vk_F3 0x63 /*0x76*/ +#define vk_F4 0x76 /*0x60*/ +#define vk_F5 0x60 /*0x61*/ +#define vk_F6 0x61 /*0x62*/ +#define vk_F7 0x62 /*0x63*/ /*?*/ +#define vk_F8 0x64 +#define vk_F9 0x65 +#define vk_F10 0x6D +#define vk_F11 0x67 +#define vk_F12 0x6F +#define vk_F13 0x69 +#define vk_F14 0x6B +#define vk_F15 0x71 + +#define vk_Clr 0x47 /* -> 1B (ESC) */ +#define vk_Enter 0x4C /* -> 03 */ + +#define vk_Space 0x31 /* -> 20 */ +#define vk_Tab 0x30 /* -> 09 */ +#define vk_Return 0x24 /* -> 0D */ +/* This is wrong for OSX, what is it for? */ +#define vk_Delete 0X08 /* -> 08 BackSpace */ + +#define vk_Help 0x72 /* -> 05 */ +#define vk_Home 0x73 /* -> 01 */ +#define vk_PageUp 0x74 /* -> 0D */ +#define vk_FwdDelete 0x75 /* -> 7F */ +#define vk_End 0x77 /* -> 04 */ +#define vk_PageDown 0x79 /* -> 0C */ + +#define vk_Up 0x7E /* -> 1E */ +#define vk_Down 0x7D /* -> 1F */ +#define vk_Left 0x7B /* -> 1C */ +#define vk_Right 0x7C /* -> 1D */ + +#define vk_Undo vk_F1 +#define vk_Cut vk_F2 +#define vk_Copy vk_F3 +#define vk_Paste vk_F4 +#define vk_PrintScreen vk_F13 +#define vk_SCrollLock vk_F14 +#define vk_Pause vk_F15 +#define vk_NumLock vk_Clr +#define vk_Insert vk_Help + +#define KeySym char + +static struct +{ + KeySym key_sym; + char_u vim_code0; + char_u vim_code1; +} special_keys[] = +{ + {vk_Up, 'k', 'u'}, + {vk_Down, 'k', 'd'}, + {vk_Left, 'k', 'l'}, + {vk_Right, 'k', 'r'}, + + {vk_F1, 'k', '1'}, + {vk_F2, 'k', '2'}, + {vk_F3, 'k', '3'}, + {vk_F4, 'k', '4'}, + {vk_F5, 'k', '5'}, + {vk_F6, 'k', '6'}, + {vk_F7, 'k', '7'}, + {vk_F8, 'k', '8'}, + {vk_F9, 'k', '9'}, + {vk_F10, 'k', ';'}, + + {vk_F11, 'F', '1'}, + {vk_F12, 'F', '2'}, + {vk_F13, 'F', '3'}, + {vk_F14, 'F', '4'}, + {vk_F15, 'F', '5'}, + +/* {XK_Help, '%', '1'}, */ +/* {XK_Undo, '&', '8'}, */ +/* {XK_BackSpace, 'k', 'b'}, */ +#ifndef MACOS_X + {vk_Delete, 'k', 'b'}, +#endif + {vk_Insert, 'k', 'I'}, + {vk_FwdDelete, 'k', 'D'}, + {vk_Home, 'k', 'h'}, + {vk_End, '@', '7'}, +/* {XK_Prior, 'k', 'P'}, */ +/* {XK_Next, 'k', 'N'}, */ +/* {XK_Print, '%', '9'}, */ + + {vk_PageUp, 'k', 'P'}, + {vk_PageDown, 'k', 'N'}, + + /* End of list marker: */ + {(KeySym)0, 0, 0} +}; + +/* + * ------------------------------------------------------------ + * Forward declaration (for those needed) + * ------------------------------------------------------------ + */ + +#ifdef USE_AEVENT +OSErr HandleUnusedParms (const AppleEvent *theAEvent); +#endif + +/* + * ------------------------------------------------------------ + * Conversion Utility + * ------------------------------------------------------------ + */ + +/* + * C2Pascal_save + * + * Allocate memory and convert the C-String passed in + * into a pascal string + * + */ + +char_u *C2Pascal_save(char_u *Cstring) +{ + char_u *PascalString; + int len; + + if (Cstring == NULL) + return NULL; + + len = STRLEN(Cstring); + + if (len > 255) /* Truncate if necessary */ + len = 255; + + PascalString = alloc(len + 1); + if (PascalString != NULL) + { + mch_memmove(PascalString + 1, Cstring, len); + PascalString[0] = len; + } + + return PascalString; +} + +/* + * C2Pascal_save_and_remove_backslash + * + * Allocate memory and convert the C-String passed in + * into a pascal string. Also remove the backslash at the same time + * + */ + +char_u *C2Pascal_save_and_remove_backslash(char_u *Cstring) +{ + char_u *PascalString; + int len; + char_u *p, *c; + + len = STRLEN(Cstring); + + if (len > 255) /* Truncate if necessary */ + len = 255; + + PascalString = alloc(len + 1); + if (PascalString != NULL) + { + for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++) + { + if ((*c == '\\') && (c[1] != 0)) + { + c++; + } + *p = *c; + p++; + len++; + } + PascalString[0] = len; + } + + return PascalString; +} + +/* + * Convert the modifiers of an Event into vim's modifiers (mouse) + */ + + int_u +EventModifiers2VimMouseModifiers(EventModifiers macModifiers) +{ + int_u vimModifiers = 0x00; + + if (macModifiers & (shiftKey | rightShiftKey)) + vimModifiers |= MOUSE_SHIFT; + if (macModifiers & (controlKey | rightControlKey)) + vimModifiers |= MOUSE_CTRL; + if (macModifiers & (optionKey | rightOptionKey)) + vimModifiers |= MOUSE_ALT; +#if 0 + /* Not yet supported */ + if (macModifiers & (cmdKey)) /* There's no rightCmdKey */ + vimModifiers |= MOUSE_CMD; +#endif + return (vimModifiers); +} + +/* + * Convert the modifiers of an Event into vim's modifiers (keys) + */ + + static int_u +EventModifiers2VimModifiers(EventModifiers macModifiers) +{ + int_u vimModifiers = 0x00; + + if (macModifiers & (shiftKey | rightShiftKey)) + vimModifiers |= MOD_MASK_SHIFT; + if (macModifiers & (controlKey | rightControlKey)) + vimModifiers |= MOD_MASK_CTRL; + if (macModifiers & (optionKey | rightOptionKey)) + vimModifiers |= MOD_MASK_ALT; +#ifdef USE_CMD_KEY + if (macModifiers & (cmdKey)) /* There's no rightCmdKey */ + vimModifiers |= MOD_MASK_CMD; +#endif + return (vimModifiers); +} + +/* Convert a string representing a point size into pixels. The string should + * be a positive decimal number, with an optional decimal point (eg, "12", or + * "10.5"). The pixel value is returned, and a pointer to the next unconverted + * character is stored in *end. The flag "vertical" says whether this + * calculation is for a vertical (height) size or a horizontal (width) one. + * + * From gui_w48.c + */ + static int +points_to_pixels(char_u *str, char_u **end, int vertical) +{ + int pixels; + int points = 0; + int divisor = 0; + + while (*str) + { + if (*str == '.' && divisor == 0) + { + /* Start keeping a divisor, for later */ + divisor = 1; + continue; + } + + if (!isdigit(*str)) + break; + + points *= 10; + points += *str - '0'; + divisor *= 10; + + ++str; + } + + if (divisor == 0) + divisor = 1; + + pixels = points/divisor; + *end = str; + return pixels; +} + +/* + * Convert a list of FSSpec aliases into a list of fullpathname + * character strings. + */ + +char_u **new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error) +{ + char_u **fnames = NULL; + OSErr newError; + long fileCount; + FSSpec fileToOpen; + long actualSize; + AEKeyword dummyKeyword; + DescType dummyType; + + /* Get number of files in list */ + *error = AECountItems(theList, numFiles); + if (*error) + { +#ifdef USE_SIOUX + printf ("fname_from_AEDesc: AECountItems error: %d\n", error); +#endif + return(fnames); + } + + /* Allocate the pointer list */ + fnames = (char_u **) alloc(*numFiles * sizeof(char_u *)); + + /* Empty out the list */ + for (fileCount = 0; fileCount < *numFiles; fileCount++) + fnames[fileCount] = NULL; + + /* Scan the list of FSSpec */ + for (fileCount = 1; fileCount <= *numFiles; fileCount++) + { + /* Get the alias for the nth file, convert to an FSSpec */ + newError = AEGetNthPtr(theList, fileCount, typeFSS, + &dummyKeyword, &dummyType, + (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize); + if (newError) + { + /* Caller is able to clean up */ + /* TODO: Should be clean up or not? For safety. */ +#ifdef USE_SIOUX + printf ("aevt_odoc: AEGetNthPtr error: %d\n", newError); +#endif + return(fnames); + } + + /* Convert the FSSpec to a pathname */ + fnames[fileCount - 1] = FullPathFromFSSpec_save (fileToOpen); + } + + return (fnames); +} + +/* + * ------------------------------------------------------------ + * CodeWarrior External Editor Support + * ------------------------------------------------------------ + */ +#ifdef FEAT_CW_EDITOR + +/* + * Handle the Window Search event from CodeWarrior + * + * Description + * ----------- + * + * The IDE sends the Window Search AppleEvent to the editor when it + * needs to know whether a particular file is open in the editor. + * + * Event Reply + * ----------- + * + * None. Put data in the location specified in the structure received. + * + * Remarks + * ------- + * + * When the editor receives this event, determine whether the specified + * file is open. If it is, return the modification date/time for that file + * in the appropriate location specified in the structure. If the file is + * not opened, put the value fnfErr (file not found) in that location. + * + */ + +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=mac68k +#endif +typedef struct WindowSearch WindowSearch; +struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/ +{ + FSSpec theFile; // identifies the file + long *theDate; // where to put the modification date/time +}; +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=reset +#endif + +pascal OSErr Handle_KAHL_SRCH_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) +{ + OSErr error = noErr; + buf_T *buf; + int foundFile = false; + DescType typeCode; + WindowSearch SearchData; + Size actualSize; + + error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize); + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_SRCH: AEGetParamPtr error: %d\n", error); +#endif + return(error); + } + + error = HandleUnusedParms (theAEvent); + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_SRCH: HandleUnusedParms error: %d\n", error); +#endif + return(error); + } + + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + if (buf->b_ml.ml_mfp != NULL + && SearchData.theFile.parID == buf->b_FSSpec.parID + && SearchData.theFile.name[0] == buf->b_FSSpec.name[0] + && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0) + { + foundFile = true; + break; + } + + if (foundFile == false) + *SearchData.theDate = fnfErr; + else + *SearchData.theDate = buf->b_mtime; + +#ifdef USE_SIOUX + printf ("KAHL_SRCH: file \"%#s\" {%d}", SearchData.theFile.name,SearchData.theFile.parID); + if (foundFile == false) + printf (" NOT"); + printf (" found. [date %lx, %lx]\n", *SearchData.theDate, buf->b_mtime_read); +#endif + + return error; +}; + +/* + * Handle the Modified (from IDE to Editor) event from CodeWarrior + * + * Description + * ----------- + * + * The IDE sends this event to the external editor when it wants to + * know which files that are open in the editor have been modified. + * + * Parameters None. + * ---------- + * + * Event Reply + * ----------- + * The reply for this event is: + * + * keyDirectObject typeAEList required + * each element in the list is a structure of typeChar + * + * Remarks + * ------- + * + * When building the reply event, include one element in the list for + * each open file that has been modified. + * + */ + +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=mac68k +#endif +typedef struct ModificationInfo ModificationInfo; +struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/ +{ + FSSpec theFile; // identifies the file + long theDate; // the date/time the file was last modified + short saved; // set this to zero when replying, unused +}; +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=reset +#endif + +pascal OSErr Handle_KAHL_MOD_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) +{ + OSErr error = noErr; + AEDescList replyList; + long numFiles; + ModificationInfo theFile; + buf_T *buf; + + theFile.saved = 0; + + error = HandleUnusedParms (theAEvent); + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_MOD: HandleUnusedParms error: %d\n", error); +#endif + return(error); + } + + /* Send the reply */ +/* replyObject.descriptorType = typeNull; + replyObject.dataHandle = nil;*/ + +/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */ + error = AECreateList(nil, 0, false, &replyList); + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_MOD: AECreateList error: %d\n", error); +#endif + return(error); + } + +#if 0 + error = AECountItems(&replyList, &numFiles); +#ifdef USE_SIOUX + printf ("KAHL_MOD ReplyList: %x %x\n", replyList.descriptorType, replyList.dataHandle); + printf ("KAHL_MOD ItemInList: %d\n", numFiles); +#endif + + /* AEPutKeyDesc (&replyList, keyAEPnject, &aDesc) + * AEPutKeyPtr (&replyList, keyAEPosition, typeChar, (Ptr)&theType, + * sizeof(DescType)) + */ + + /* AEPutDesc */ +#endif + + numFiles = 0; + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + if (buf->b_ml.ml_mfp != NULL) + { + /* Add this file to the list */ + theFile.theFile = buf->b_FSSpec; + theFile.theDate = buf->b_mtime; +/* theFile.theDate = time (NULL) & (time_t) 0xFFFFFFF0; */ + error = AEPutPtr (&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile)); +#ifdef USE_SIOUX + if (numFiles == 0) + printf ("KAHL_MOD: "); + else + printf (", "); + printf ("\"%#s\" {%d} [date %lx, %lx]", theFile.theFile.name, theFile.theFile.parID, theFile.theDate, buf->b_mtime_read); + if (error) + printf (" (%d)", error); + numFiles++; +#endif + }; + +#ifdef USE_SIOUX + printf ("\n"); +#endif + +#if 0 + error = AECountItems(&replyList, &numFiles); +#ifdef USE_SIOUX + printf ("KAHL_MOD ItemInList: %d\n", numFiles); +#endif +#endif + + /* We can add data only if something to reply */ + error = AEPutParamDesc (theReply, keyDirectObject, &replyList); + +#ifdef USE_SIOUX + if (error) + printf ("KAHL_MOD: AEPutParamDesc error: %d\n", error); +#endif + + if (replyList.dataHandle) + AEDisposeDesc(&replyList); + + return error; +}; + +/* + * Handle the Get Text event from CodeWarrior + * + * Description + * ----------- + * + * The IDE sends the Get Text AppleEvent to the editor when it needs + * the source code from a file. For example, when the user issues a + * Check Syntax or Compile command, the compiler needs access to + * the source code contained in the file. + * + * Event Reply + * ----------- + * + * None. Put data in locations specified in the structure received. + * + * Remarks + * ------- + * + * When the editor receives this event, it must set the size of the handle + * in theText to fit the data in the file. It must then copy the entire + * contents of the specified file into the memory location specified in + * theText. + * + */ + +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=mac68k +#endif +typedef struct CW_GetText CW_GetText; +struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/ +{ + FSSpec theFile; /* identifies the file */ + Handle theText; /* the location where you return the text (must be resized properly) */ + long *unused; /* 0 (not used) */ + long *theDate; /* where to put the modification date/time */ +}; +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=reset +#endif + +pascal OSErr Handle_KAHL_GTTX_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) +{ + OSErr error = noErr; + buf_T *buf; + int foundFile = false; + DescType typeCode; + CW_GetText GetTextData; + Size actualSize; + char_u *line; + char_u *fullbuffer = NULL; + long linesize; + long lineStart; + long BufferSize; + long lineno; + + error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize); + + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_GTTX: AEGetParamPtr error: %d\n", error); +#endif + return(error); + } + + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + if (buf->b_ml.ml_mfp != NULL) + if (GetTextData.theFile.parID == buf->b_FSSpec.parID) + { + foundFile = true; + break; + } + + if (foundFile) + { + BufferSize = 0; /* GetHandleSize (GetTextData.theText); */ + for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++) + { + /* Must use the right buffer */ + line = ml_get_buf(buf, (linenr_T) lineno, FALSE); + linesize = STRLEN(line) + 1; + lineStart = BufferSize; + BufferSize += linesize; + /* Resize handle to linesize+1 to include the linefeed */ + SetHandleSize (GetTextData.theText, BufferSize); + if (GetHandleSize (GetTextData.theText) != BufferSize) + { + #ifdef USE_SIOUX + printf ("KAHL_GTTX: SetHandleSize increase: %d, size %d\n", + linesize, BufferSize); + #endif + break; /* Simple handling for now */ + } + else + { + HLock (GetTextData.theText); + fullbuffer = (char_u *) *GetTextData.theText; + STRCPY ((char_u *) (fullbuffer + lineStart), line); + fullbuffer[BufferSize-1] = '\r'; + HUnlock (GetTextData.theText); + } + } + if (fullbuffer != NULL) + { + HLock (GetTextData.theText); + fullbuffer[BufferSize-1] = 0; + HUnlock (GetTextData.theText); + } + if (foundFile == false) + *GetTextData.theDate = fnfErr; + else +/* *GetTextData.theDate = time (NULL) & (time_t) 0xFFFFFFF0;*/ + *GetTextData.theDate = buf->b_mtime; + } +#ifdef USE_SIOUX + printf ("KAHL_GTTX: file \"%#s\" {%d} [date %lx, %lx]", GetTextData.theFile.name, GetTextData.theFile.parID, *GetTextData.theDate, buf->b_mtime_read); + if (foundFile == false) + printf (" NOT"); + printf (" found. (BufferSize = %d)\n", BufferSize); +#endif + + error = HandleUnusedParms (theAEvent); + if (error) + { +#ifdef USE_SIOUX + printf ("KAHL_GTTX: HandleUnusedParms error: %d\n", error); +#endif + return(error); + } + + return(error); +} + +/* + * + */ + +/* Taken from MoreAppleEvents:ProcessHelpers*/ +pascal OSErr FindProcessBySignature( const OSType targetType, + const OSType targetCreator, + ProcessSerialNumberPtr psnPtr ) +{ + OSErr anErr = noErr; + Boolean lookingForProcess = true; + + ProcessInfoRec infoRec; + + infoRec.processInfoLength = sizeof( ProcessInfoRec ); + infoRec.processName = nil; + infoRec.processAppSpec = nil; + + psnPtr->lowLongOfPSN = kNoProcess; + psnPtr->highLongOfPSN = kNoProcess; + + while ( lookingForProcess ) + { + anErr = GetNextProcess( psnPtr ); + if ( anErr != noErr ) + { + lookingForProcess = false; + } + else + { + anErr = GetProcessInformation( psnPtr, &infoRec ); + if ( ( anErr == noErr ) + && ( infoRec.processType == targetType ) + && ( infoRec.processSignature == targetCreator ) ) + { + lookingForProcess = false; + } + } + } + + return anErr; +}//end FindProcessBySignature + +void Send_KAHL_MOD_AE (buf_T *buf) +{ + OSErr anErr = noErr; + AEDesc targetAppDesc = { typeNull, nil }; + ProcessSerialNumber psn = { kNoProcess, kNoProcess }; + AppleEvent theReply = { typeNull, nil }; + AESendMode sendMode; + AppleEvent theEvent = {typeNull, nil }; + AEIdleUPP idleProcUPP = nil; + ModificationInfo ModData; + + + anErr = FindProcessBySignature( 'APPL', 'CWIE', &psn ); +#ifdef USE_SIOUX + printf ("CodeWarrior is"); + if (anErr != noErr) + printf (" NOT"); + printf (" running\n"); +#endif + if ( anErr == noErr ) + { + anErr = AECreateDesc (typeProcessSerialNumber, &psn, + sizeof( ProcessSerialNumber ), &targetAppDesc); + + if ( anErr == noErr ) + { + anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc, + kAutoGenerateReturnID, kAnyTransactionID, &theEvent); + } + + AEDisposeDesc( &targetAppDesc ); + + /* Add the parms */ + ModData.theFile = buf->b_FSSpec; + ModData.theDate = buf->b_mtime; + + if (anErr == noErr) + anErr =AEPutParamPtr (&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData)); + + if ( idleProcUPP == nil ) + sendMode = kAENoReply; + else + sendMode = kAEWaitReply; + + if ( anErr == noErr ) + anErr = AESend( &theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil ); + if ( anErr == noErr && sendMode == kAEWaitReply ) + { +#ifdef USE_SIOUX + printf ("KAHL_MOD: Send error: %d\n", anErr); +#endif +/* anErr = AEHGetHandlerError( &theReply );*/ + } + (void) AEDisposeDesc( &theReply ); + } +} +#endif /* FEAT_CW_EDITOR */ + +/* + * ------------------------------------------------------------ + * Apple Event Handling procedure + * ------------------------------------------------------------ + */ +#ifdef USE_AEVENT + +/* + * Handle the Unused parms of an AppleEvent + */ + +OSErr HandleUnusedParms (const AppleEvent *theAEvent) +{ + OSErr error; + long actualSize; + DescType dummyType; + AEKeyword missedKeyword; + + /* Get the "missed keyword" attribute from the AppleEvent. */ + error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr, + typeKeyword, &dummyType, + (Ptr)&missedKeyword, sizeof(missedKeyword), + &actualSize); + + /* If the descriptor isn't found, then we got the required parameters. */ + if (error == errAEDescNotFound) + { + error = noErr; + } + else + { +#if 0 + /* Why is this removed? */ + error = errAEEventNotHandled; +#endif + } + + return error; +} + + +/* + * Handle the ODoc AppleEvent + * + * Deals with all files dragged to the application icon. + * + */ + +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=mac68k +#endif +typedef struct SelectionRange SelectionRange; +struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */ +{ + short unused1; // 0 (not used) + short lineNum; // line to select (<0 to specify range) + long startRange; // start of selection range (if line < 0) + long endRange; // end of selection range (if line < 0) + long unused2; // 0 (not used) + long theDate; // modification date/time +}; +#if defined(__MWERKS__) /* only in Codewarrior */ +# pragma options align=reset +#endif + +/* The IDE uses the optional keyAEPosition parameter to tell the ed- + itor the selection range. If lineNum is zero or greater, scroll the text + to the specified line. If lineNum is less than zero, use the values in + startRange and endRange to select the specified characters. Scroll + the text to display the selection. If lineNum, startRange, and + endRange are all negative, there is no selection range specified. + */ + +pascal OSErr HandleODocAE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) +{ + /* + * TODO: Clean up the code with convert the AppleEvent into + * a ":args" + */ + OSErr error = noErr; +// OSErr firstError = noErr; +// short numErrors = 0; + AEDesc theList; + DescType typeCode; + long numFiles; + // long fileCount; + char_u **fnames; +// char_u fname[256]; + Size actualSize; + SelectionRange thePosition; + short gotPosition = false; + long lnum; + +#ifdef USE_SIOUX + printf ("aevt_odoc:\n"); +#endif + + /* the direct object parameter is the list of aliases to files (one or more) */ + error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList); + if (error) + { +#ifdef USE_SIOUX + printf ("aevt_odoc: AEGetParamDesc error: %d\n", error); +#endif + return(error); + } + + + error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize); + if (error == noErr) + gotPosition = true; + if (error == errAEDescNotFound) + error = noErr; + if (error) + { +#ifdef USE_SIOUX + printf ("aevt_odoc: AEGetParamPtr error: %d\n", error); +#endif + return(error); + } + +#ifdef USE_SIOUX + printf ("aevt_odoc: lineNum: %d, startRange %d, endRange %d, [date %lx]\n", + thePosition.lineNum, thePosition.startRange, thePosition.endRange, + thePosition.theDate); +#endif +/* + error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition); + + if (^error) then + { + if (thePosition.lineNum >= 0) + { + // Goto this line + } + else + { + // Set the range char wise + } + } + */ + + +#ifdef FEAT_VISUAL + reset_VIsual(); +#endif + + fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error); + + if (error) + { + /* TODO: empty fnames[] first */ + vim_free(fnames); + return (error); + } + + if (starting > 0) + { + int i; + char_u *p; + + /* these are the initial files dropped on the Vim icon */ + for (i = 0 ; i < numFiles; i++) + { + if (ga_grow(&global_alist.al_ga, 1) == FAIL + || (p = vim_strsave(fnames[i])) == NULL) + mch_exit(2); + else + alist_add(&global_alist, p, 2); + } + goto finished; + } + + /* Handle the drop, :edit to get to the file */ + handle_drop(numFiles, fnames, FALSE); + + /* TODO: Handle the goto/select line more cleanly */ + if ((numFiles == 1) & (gotPosition)) + { + if (thePosition.lineNum >= 0) + { + lnum = thePosition.lineNum; + /* oap->motion_type = MLINE; + setpcmark();*/ + if (lnum < 1L) + lnum = 1L; + else if (lnum > curbuf->b_ml.ml_line_count) + lnum = curbuf->b_ml.ml_line_count; + curwin->w_cursor.lnum = lnum; + /* beginline(BL_SOL | BL_FIX);*/ + } + else + goto_byte(thePosition.startRange + 1); + } + + /* Update the screen display */ + update_screen(NOT_VALID); + setcursor(); + out_flush(); + + finished: + AEDisposeDesc(&theList); /* dispose what we allocated */ + + error = HandleUnusedParms (theAEvent); + if (error) + { +#ifdef USE_SIOUX + printf ("aevt_odoc: HandleUnusedParms error: %d\n", error); +#endif + return(error); + } + return(error); +} + +/* + * + */ + +pascal OSErr Handle_aevt_oapp_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) +{ + OSErr error = noErr; + +#ifdef USE_SIOUX + printf ("aevt_oapp:\n"); +#endif + + error = HandleUnusedParms |