summaryrefslogtreecommitdiffstats
path: root/src/gui_mac.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/gui_mac.c
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/gui_mac.c')
-rw-r--r--src/gui_mac.c5820
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
+