summaryrefslogtreecommitdiff
path: root/src/gui_mac.c
diff options
context:
space:
mode:
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 000000000..2b74c6328
--- /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 (theAEvent);
+ if (error)
+ {
+ return(error);
+ }
+
+ return(error);
+}
+
+/*
+ *
+ */
+
+pascal OSErr Handle_aevt_quit_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
+{
+ OSErr error = noErr;
+
+#ifdef USE_SIOUX
+ printf ("aevt_quit\n");
+#endif
+
+ error = HandleUnusedParms (theAEvent);
+ if (error)
+ {
+ return(error);
+ }
+
+ /* Need to fake a :confirm qa */
+ do_cmdline_cmd((char_u *)"confirm qa");
+
+ return(error);
+}
+
+/*
+ *
+ */
+
+pascal OSErr Handle_aevt_pdoc_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
+{
+ OSErr error = noErr;
+
+#ifdef USE_SIOUX
+ printf ("aevt_pdoc:\n");
+#endif
+
+ error = HandleUnusedParms (theAEvent);
+ if (error)
+ {
+ return(error);
+ }
+
+ return(error);
+}
+
+/*
+ * Handling of unknown AppleEvent
+ *
+ * (Just get rid of all the parms)
+ */
+pascal OSErr Handle_unknown_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
+{
+ OSErr error = noErr;
+
+#ifdef USE_SIOUX
+ printf ("Unknown Event: %x\n", theAEvent->descriptorType);
+#endif
+
+ error = HandleUnusedParms (theAEvent);
+ if (error)
+ {
+ return(error);
+ }
+
+ return(error);
+}
+
+
+
+#if TARGET_API_MAC_CARBON
+# define NewAEEventHandlerProc(x) NewAEEventHandlerUPP(x)
+#endif
+
+/*
+ * Install the various AppleEvent Handlers
+ */
+OSErr InstallAEHandlers (void)
+{
+ OSErr error;
+
+ /* install open application handler */
+ error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
+ NewAEEventHandlerProc(Handle_aevt_oapp_AE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+
+ /* install quit application handler */
+ error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerProc(Handle_aevt_quit_AE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+
+ /* install open document handler */
+ error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
+ NewAEEventHandlerProc(HandleODocAE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+
+ /* install print document handler */
+ error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
+ NewAEEventHandlerProc(Handle_aevt_pdoc_AE), 0, false);
+
+/* Install Core Suite */
+/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEClose,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
+ NewAEEventHandlerProc(Handle_unknown_AE), kAEGetData, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
+ NewAEEventHandlerProc(Handle_unknown_AE), kAEGetDataSize, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAEMove,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAESave,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+
+ error = AEInstallEventHandler(kAECoreSuite, kAESetData,
+ NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
+*/
+
+#ifdef FEAT_CW_EDITOR
+ /*
+ * Bind codewarrior support handlers
+ */
+ error = AEInstallEventHandler('KAHL', 'GTTX',
+ NewAEEventHandlerProc(Handle_KAHL_GTTX_AE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+ error = AEInstallEventHandler('KAHL', 'SRCH',
+ NewAEEventHandlerProc(Handle_KAHL_SRCH_AE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+ error = AEInstallEventHandler('KAHL', 'MOD ',
+ NewAEEventHandlerProc(Handle_KAHL_MOD_AE), 0, false);
+ if (error)
+ {
+ return error;
+ }
+#endif
+
+ return error;
+
+}
+#endif /* USE_AEVENT */
+
+/*
+ * ------------------------------------------------------------
+ * Unfiled yet
+ * ------------------------------------------------------------
+ */
+
+/*
+ * gui_mac_get_menu_item_index
+ *
+ * Returns the index inside the menu wher
+ */
+ short /* Shoulde we return MenuItemIndex? */
+gui_mac_get_menu_item_index (pMenu)
+ vimmenu_T *pMenu;
+{
+ short index;
+ short itemIndex = -1;
+ vimmenu_T *pBrother;
+
+ /* Only menu without parent are the:
+ * -menu in the menubar
+ * -popup menu
+ * -toolbar (guess)
+ *
+ * Which are not items anyway.
+ */
+ if (pMenu->parent)
+ {
+ /* Start from the Oldest Brother */
+ pBrother = pMenu->parent->children;
+ index = 1;
+ while ((pBrother) && (itemIndex == -1))
+ {
+ if (pBrother == pMenu)
+ itemIndex = index;
+ index++;
+ pBrother = pBrother->next;
+ }
+#ifdef USE_HELPMENU
+ /* Adjust index in help menu (for predefined ones) */
+ if (itemIndex != -1)
+ if (pMenu->parent->submenu_id == kHMHelpMenuID)
+ itemIndex += gui.MacOSHelpItems;
+#endif
+ }
+ return itemIndex;
+}
+
+ static vimmenu_T *
+gui_mac_get_vim_menu (menuID, itemIndex, pMenu)
+ short menuID;
+ short itemIndex;
+ vimmenu_T *pMenu;
+{
+ short index;
+ vimmenu_T *pChildMenu;
+ vimmenu_T *pElder = pMenu->parent;
+
+
+ /* Only menu without parent are the:
+ * -menu in the menubar
+ * -popup menu
+ * -toolbar (guess)
+ *
+ * Which are not items anyway.
+ */
+
+ if ((pElder) && (pElder->submenu_id == menuID))
+ {
+#ifdef USE_HELPMENU
+ if (menuID == kHMHelpMenuID)
+ itemIndex -= gui.MacOSHelpItems;
+#endif
+
+ for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
+ pMenu = pMenu->next;
+ }
+ else
+ {
+ for (; pMenu != NULL; pMenu = pMenu->next)
+ {
+ if (pMenu->children != NULL)
+ {
+ pChildMenu = gui_mac_get_vim_menu
+ (menuID, itemIndex, pMenu->children);
+ if (pChildMenu)
+ {
+ pMenu = pChildMenu;
+ break;
+ }
+ }
+ }
+ }
+ return pMenu;
+}
+
+/*
+ * ------------------------------------------------------------
+ * MacOS Feedback procedures
+ * ------------------------------------------------------------
+ */
+ pascal
+ void
+gui_mac_drag_thumb (ControlHandle theControl, short partCode)
+{
+ scrollbar_T *sb;
+ int value, dragging;
+ ControlHandle theControlToUse;
+ int dont_scroll_save = dont_scroll;
+
+ theControlToUse = dragged_sb;
+
+ sb = gui_find_scrollbar((long) GetControlReference (theControlToUse));
+
+ if (sb == NULL)
+ return;
+
+ /* Need to find value by diff between Old Poss New Pos */
+ value = GetControl32BitValue (theControlToUse);
+ dragging = (partCode != 0);
+
+ /* When "allow_scrollbar" is FALSE still need to remember the new
+ * position, but don't actually scroll by setting "dont_scroll". */
+ dont_scroll = !allow_scrollbar;
+ gui_drag_scrollbar(sb, value, dragging);
+ dont_scroll = dont_scroll_save;
+}
+
+ pascal
+ void
+gui_mac_scroll_action (ControlHandle theControl, short partCode)
+{
+ /* TODO: have live support */
+ scrollbar_T *sb, *sb_info;
+ long data;
+ long value;
+ int page;
+ int dragging = FALSE;
+ int dont_scroll_save = dont_scroll;
+
+ sb = gui_find_scrollbar((long) GetControlReference (theControl));
+
+ if (sb == NULL)
+ return;
+
+ if (sb->wp != NULL) /* Left or right scrollbar */
+ {
+ /*
+ * Careful: need to get scrollbar info out of first (left) scrollbar
+ * for window, but keep real scrollbar too because we must pass it to
+ * gui_drag_scrollbar().
+ */
+ sb_info = &sb->wp->w_scrollbars[0];
+
+ if (sb_info->size > 5)
+ page = sb_info->size - 2; /* use two lines of context */
+ else
+ page = sb_info->size;
+ }
+ else /* Bottom scrollbar */
+ {
+ sb_info = sb;
+ page = W_WIDTH(curwin) - 5;
+ }
+
+ switch (partCode)
+ {
+ case kControlUpButtonPart: data = -1; break;
+ case kControlDownButtonPart: data = 1; break;
+ case kControlPageDownPart: data = page; break;
+ case kControlPageUpPart: data = -page; break;
+ default: data = 0; break;
+ }
+
+ value = sb_info->value + data;
+/* if (value > sb_info->max)
+ value = sb_info->max;
+ else if (value < 0)
+ value = 0;*/
+
+ /* When "allow_scrollbar" is FALSE still need to remember the new
+ * position, but don't actually scroll by setting "dont_scroll". */
+ dont_scroll = !allow_scrollbar;
+ gui_drag_scrollbar(sb, value, dragging);
+ dont_scroll = dont_scroll_save;
+
+ out_flush();
+ gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
+
+/* if (sb_info->wp != NULL)
+ {
+ win_T *wp;
+ int sb_num;
+
+ sb_num = 0;
+ for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
+ sb_num++;
+
+ if (wp != NULL)
+ {
+ current_scrollbar = sb_num;
+ scrollbar_value = value;
+ gui_do_scroll();
+ gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
+ }
+ }*/
+}
+
+/*
+ * ------------------------------------------------------------
+ * MacOS Click Handling procedures
+ * ------------------------------------------------------------
+ */
+
+
+/*
+ * Handle a click inside the window, it may happens in the
+ * scrollbar or the contents.
+ *
+ * TODO: Add support for potential TOOLBAR
+ */
+ void
+gui_mac_doInContentClick (theEvent, whichWindow)
+ EventRecord *theEvent;
+ WindowPtr whichWindow;
+{
+ Point thePoint;
+ int_u vimModifiers;
+ short thePortion;
+ ControlHandle theControl;
+ int vimMouseButton;
+ short dblClick;
+
+ thePoint = theEvent->where;
+ GlobalToLocal (&thePoint);
+ SelectWindow (whichWindow);
+
+ thePortion = FindControl (thePoint, whichWindow, &theControl);
+
+ if (theControl != NUL)
+ {
+ /* We hit a scollbar */
+
+ if (thePortion != kControlIndicatorPart)
+ {
+ dragged_sb = theControl;
+ TrackControl(theControl, thePoint, gScrollAction);
+ dragged_sb = NULL;
+ }
+ else
+ {
+ dragged_sb = theControl;
+#if 1
+ TrackControl(theControl, thePoint, gScrollDrag);
+#else
+ TrackControl(theControl, thePoint, NULL);
+#endif
+ /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
+ * button has been released */
+ gui_mac_drag_thumb (theControl, 0); /* Should it be thePortion ? (Dany) */
+ dragged_sb = NULL;
+ }
+ }
+ else
+ {
+ /* We are inside the contents */
+
+ /* Convert the CTRL, OPTION, SHIFT and CMD key */
+ vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
+
+ /* Defaults to MOUSE_LEFT as there's only one mouse button */
+ vimMouseButton = MOUSE_LEFT;
+
+#ifdef USE_CTRLCLICKMENU
+ /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
+ clickIsPopup = FALSE;
+
+ if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup()))
+ if (IsShowContextualMenuClick(theEvent))
+ {
+ vimMouseButton = MOUSE_RIGHT;
+ vimModifiers &= ~MOUSE_CTRL;
+ clickIsPopup = TRUE;
+ }
+#endif
+
+ /* Is it a double click ? */
+ dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
+
+ /* Send the mouse clicj to Vim */
+ gui_send_mouse_event(vimMouseButton, thePoint.h,
+ thePoint.v, dblClick, vimModifiers);
+
+ /* Create the rectangle around the cursor to detect
+ * the mouse dragging
+ */
+#ifdef USE_CTRLCLICKMENU
+#if 0
+ /* TODO: Do we need to this even for the contextual menu?
+ * It may be require for popup_setpos, but for popup?
+ */
+ if (vimMouseButton == MOUSE_LEFT)
+#endif
+#endif
+ {
+ SetRect (&dragRect, FILL_X(X_2_COL(thePoint.h)),
+ FILL_Y(Y_2_ROW(thePoint.v)),
+ FILL_X(X_2_COL(thePoint.h)+1),
+ FILL_Y(Y_2_ROW(thePoint.v)+1));
+
+ dragRectEnbl = TRUE;
+ dragRectControl = kCreateRect;
+ }
+ }
+}
+
+/*
+ * Handle the click in the titlebar (to move the window)
+ */
+ void
+gui_mac_doInDragClick (where, whichWindow)
+ Point where;
+ WindowPtr whichWindow;
+{
+ Rect movingLimits;
+ Rect *movingLimitsPtr = &movingLimits;
+
+ /* TODO: may try to prevent move outside screen? */
+#ifdef USE_CARBONIZED
+ movingLimitsPtr = GetRegionBounds ( GetGrayRgn(), &movingLimits );
+#else
+ movingLimitsPtr = &(*GetGrayRgn())->rgnBBox;
+#endif
+ DragWindow (whichWindow, where, movingLimitsPtr);
+}
+
+/*
+ * Handle the click in the grow box
+ */
+ void
+gui_mac_doInGrowClick(where, whichWindow)
+ Point where;
+ WindowPtr whichWindow;
+{
+
+ long newSize;
+ unsigned short newWidth;
+ unsigned short newHeight;
+ Rect resizeLimits;
+ Rect *resizeLimitsPtr = &resizeLimits;
+#ifdef USE_CARBONIZED
+ Rect NewContentRect;
+
+ resizeLimitsPtr = GetRegionBounds ( GetGrayRgn(), &resizeLimits );
+#else
+ resizeLimits = qd.screenBits.bounds;
+#endif
+
+ /* Set the minimun size */
+ /* TODO: Should this come from Vim? */
+ resizeLimits.top = 100;
+ resizeLimits.left = 100;
+
+#ifdef USE_CARBONIZED
+ newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
+ newWidth = NewContentRect.right - NewContentRect.left;
+ newHeight = NewContentRect.bottom - NewContentRect.top;
+ gui_resize_shell(newWidth, newHeight);
+ gui_mch_set_bg_color(gui.back_pixel);
+ gui_set_shellsize(TRUE, FALSE);
+#else
+ newSize = GrowWindow(whichWindow, where, &resizeLimits);
+ if (newSize != 0)
+ {
+ newWidth = newSize & 0x0000FFFF;
+ newHeight = (newSize >> 16) & 0x0000FFFF;
+
+ gui_mch_set_bg_color(gui.back_pixel);
+
+ gui_resize_shell(newWidth, newHeight);
+
+ /*
+ * We need to call gui_set_shellsize as the size
+ * used by Vim may be smaller than the size selected
+ * by the user. This cause some overhead
+ * TODO: add a check inside gui_resize_shell?
+ */
+ gui_set_shellsize(TRUE, FALSE);
+
+ /*
+ * Origin of the code below is unknown.
+ * Functionality is unknown.
+ * Time of commented out is unknown.
+ */
+/* SetPort(wp);
+ InvalRect(&wp->portRect);
+ if (isUserWindow(wp)) {
+ DrawingWindowPeek aWindow = (DrawingWindowPeek)wp;
+
+ if (aWindow->toolRoutines.toolWindowResizedProc)
+ CallToolWindowResizedProc(aWindow->toolRoutines.toolWindowResizedProc, wp);
+ }*/
+ };
+#endif
+
+}
+
+/*
+ * Handle the click in the zoom box
+ */
+#ifdef USE_CARBONIZED
+ static void
+gui_mac_doInZoomClick(theEvent, whichWindow)
+ EventRecord *theEvent;
+ WindowPtr whichWindow;
+{
+ Rect r;
+ Point p;
+ short thePart;
+
+ /* ideal width is current */
+ p.h = Columns * gui.char_width + 2 * gui.border_offset;
+ if (gui.which_scrollbars[SBAR_LEFT])
+ p.h += gui.scrollbar_width;
+ if (gui.which_scrollbars[SBAR_RIGHT])
+ p.h += gui.scrollbar_width;
+ /* ideal height is as heigh as we can get */
+ p.v = 15 * 1024;
+
+ thePart = IsWindowInStandardState(whichWindow, &p, &r)
+ ? inZoomIn : inZoomOut;
+
+ if (!TrackBox(whichWindow, theEvent->where, thePart))
+ return;
+
+ /* use returned width */
+ p.h = r.right - r.left;
+ /* adjust returned height */
+ p.v = r.bottom - r.top - 2 * gui.border_offset;
+ if (gui.which_scrollbars[SBAR_BOTTOM])
+ p.v -= gui.scrollbar_height;
+ p.v -= p.v % gui.char_height;
+ p.v += 2 * gui.border_width;
+ if (gui.which_scrollbars[SBAR_BOTTOM]);
+ p.v += gui.scrollbar_height;
+
+ ZoomWindowIdeal(whichWindow, thePart, &p);
+
+ GetWindowBounds(whichWindow, kWindowContentRgn, &r);
+ gui_resize_shell(r.right - r.left, r.bottom - r.top);
+ gui_mch_set_bg_color(gui.back_pixel);
+ gui_set_shellsize(TRUE, FALSE);
+}
+#endif /* defined(USE_CARBONIZED) */
+
+/*
+ * ------------------------------------------------------------
+ * MacOS Event Handling procedure
+ * ------------------------------------------------------------
+ */
+
+/*
+ * Handle the Update Event
+ */
+
+ void
+gui_mac_doUpdateEvent(event)
+ EventRecord *event;
+{
+ WindowPtr whichWindow;
+ GrafPtr savePort;
+ RgnHandle updateRgn;
+#ifdef USE_CARBONIZED
+ Rect updateRect;
+#endif
+ Rect *updateRectPtr;
+ Rect rc;
+ Rect growRect;
+ RgnHandle saveRgn;
+
+
+#ifdef USE_CARBONIZED
+ updateRgn = NewRgn();
+ if (updateRgn == NULL)
+ return;
+#endif
+
+ /* This could be done by the caller as we
+ * don't require anything else out of the event
+ */
+ whichWindow = (WindowPtr) event->message;
+
+ /* Save Current Port */
+ GetPort (&savePort);
+
+ /* Select the Window's Port */
+#ifdef USE_CARBONIZED
+ SetPortWindowPort (whichWindow);
+#else
+ SetPort (whichWindow);
+#endif
+
+ /* Let's update the window */
+ BeginUpdate (whichWindow);
+ /* Redraw the biggest rectangle covering the area
+ * to be updated.
+ */
+#ifdef USE_CARBONIZED
+ GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
+# if 0
+ /* Would be more appropriate to use the follwing but doesn't
+ * seem to work under MacOS X (Dany)
+ */
+ GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
+# endif
+#else
+ updateRgn = whichWindow->visRgn;
+#endif
+ /* Use the HLock useless in Carbon? Is it harmful?*/
+ HLock ((Handle) updateRgn);
+#ifdef USE_CARBONIZED
+ updateRectPtr = GetRegionBounds ( updateRgn, &updateRect );
+# if 0
+ /* Code from original Carbon Port (using GetWindowRegion.
+ * I believe the UpdateRgn is already in local (Dany)
+ */
+ GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
+ GlobalToLocal(&botRight(updateRect));
+# endif
+#else
+ updateRectPtr = &(*updateRgn)->rgnBBox;
+#endif
+ /* Update the content (i.e. the text) */
+ gui_redraw(updateRectPtr->left, updateRectPtr->top,
+ updateRectPtr->right - updateRectPtr->left,
+ updateRectPtr->bottom - updateRectPtr->top);
+ /* Clear the border areas if needed */
+ gui_mch_set_bg_color(gui.back_pixel);
+ if (updateRectPtr->left < FILL_X(0))
+ {
+ SetRect (&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
+ EraseRect (&rc);
+ }
+ if (updateRectPtr->top < FILL_Y(0))
+ {
+ SetRect (&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
+ EraseRect (&rc);
+ }
+ if (updateRectPtr->right > FILL_X(Columns))
+ {
+ SetRect (&rc, FILL_X(Columns), 0,
+ FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
+ EraseRect (&rc);
+ }
+ if (updateRectPtr->bottom > FILL_Y(Rows))
+ {
+ SetRect (&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
+ FILL_Y(Rows) + gui.border_offset);
+ EraseRect (&rc);
+ }
+ HUnlock ((Handle) updateRgn);
+#ifdef USE_CARBONIZED
+ DisposeRgn (updateRgn);
+#endif
+
+ /* Update scrollbars */
+ DrawControls (whichWindow);
+
+ /* Update the GrowBox */
+ /* Taken from FAQ 33-27 */
+ saveRgn = NewRgn();
+#ifdef USE_CARBONIZED
+ GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
+#else
+ growRect = whichWindow->portRect;
+ growRect.top = growRect.bottom - 15;
+ growRect.left = growRect.right - 15;
+#endif
+ GetClip (saveRgn);
+ ClipRect (&growRect);
+ DrawGrowIcon (whichWindow);
+ SetClip (saveRgn);
+ DisposeRgn (saveRgn);
+ EndUpdate (whichWindow);
+
+ /* Restore original Port */
+ SetPort (savePort);
+}
+
+/*
+ * Handle the activate/deactivate event
+ * (apply to a window)
+ */
+ void
+gui_mac_doActivateEvent(event)
+ EventRecord *event;
+{
+ WindowPtr whichWindow;
+
+ whichWindow = (WindowPtr) event->message;
+ if ((event->modifiers) & activeFlag)
+ /* Activate */
+ gui_focus_change(TRUE);
+ else
+ {
+ /* Deactivate */
+ gui_focus_change(FALSE);
+/* DON'T KNOW what the code below was doing
+ found in the deactivate clause, but the
+ clause writting TRUE into in_focus (BUG)
+ */
+
+#if 0 /* Removed by Dany as per above June 2001 */
+ a_bool = false;
+ SetPreserveGlyph (a_bool);
+ SetOutlinePreferred (a_bool);
+#endif
+ }
+}
+
+
+/*
+ * Handle the suspend/resume event
+ * (apply to the application)
+ */
+ void
+gui_mac_doSuspendEvent(event)
+ EventRecord *event;
+{
+ /* The frontmost application just changed */
+
+ /* NOTE: the suspend may happen before the deactivate
+ * seen on MacOS X
+ */
+
+ /* May not need to change focus as the window will
+ * get an activate/desactivate event
+ */
+ if (event->message & 1)
+ /* Resume */
+ gui_focus_change(TRUE);
+ else
+ /* Suspend */
+ gui_focus_change(FALSE);
+}
+
+/*
+ * Handle the key
+ */
+
+ void
+gui_mac_doKeyEvent(EventRecord *theEvent)
+{
+ /* TODO: add support for COMMAND KEY */
+ long menu;
+ unsigned char string[20];
+ short num, i;
+ short len = 0;
+ KeySym key_sym;
+ int key_char;
+ int modifiers;
+
+ /* Mask the mouse (as per user setting) */
+ if (p_mh)
+ ObscureCursor();
+
+ /* Get the key code and it's ASCII representation */
+ key_sym = ((theEvent->message & keyCodeMask) >> 8);
+ key_char = theEvent->message & charCodeMask;
+ num = 1;
+
+ /* Intercept CTRL-C */
+ if (theEvent->modifiers & controlKey)
+ if (key_char == Ctrl_C && ctrl_c_interrupts)
+ got_int = TRUE;
+
+ /* Intercept CMD-. */
+ if (theEvent->modifiers & cmdKey)
+ if (key_char == '.')
+ got_int = TRUE;
+
+ /* Handle command key as per menu */
+ /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
+ if (theEvent->modifiers & cmdKey)
+ /* Only accept CMD alone or with CAPLOCKS and the mouse button.
+ * Why the mouse button? */
+ if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
+ {
+ menu = MenuKey(key_char);
+ if (HiWord(menu))
+ {
+ gui_mac_handle_menu(menu);
+ return;
+ }
+ }
+
+ /* Convert the modifiers */
+ modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
+
+
+ /* Handle special keys. */
+#if 0
+ /* Why have this been removed? */
+ if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
+#endif
+ {
+ /* Find the special key (for non-printable keyt_char) */
+ if ((key_char < 0x20) || (key_char == 0x7f))
+ for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
+ if (special_keys[i].key_sym == key_sym)
+ {
+# if 0
+ /* We currently don't have not so special key */
+ if (special_keys[i].vim_code1 == NUL)
+ key_char = special_keys[i].vim_code0;
+ else
+# endif
+ key_char = TO_SPECIAL( special_keys[i].vim_code0,
+ special_keys[i].vim_code1 );
+ key_char = simplify_key(key_char,&modifiers);
+ break;
+ }
+ }
+
+
+ /* Add the modifier to the input bu if needed */
+ /* Do not want SHIFT-A or CTRL-A with modifier */
+ if (!IS_SPECIAL(key_char)
+ && key_sym != vk_Space
+ && key_sym != vk_Tab
+ && key_sym != vk_Return
+ && key_sym != vk_Enter
+ && key_sym != vk_Esc)
+ {
+#if 1
+ /* Clear modifiers when only one modifier is set */
+ if( (modifiers == MOD_MASK_SHIFT) ||
+ (modifiers == MOD_MASK_CTRL) ||
+ (modifiers == MOD_MASK_ALT))
+ modifiers = 0;
+#else
+ if( modifiers & MOD_MASK_CTRL)
+ modifiers = modifiers & ~MOD_MASK_CTRL;
+ if( modifiers & MOD_MASK_ALT)
+ modifiers = modifiers & ~MOD_MASK_ALT;
+ if( modifiers & MOD_MASK_SHIFT)
+ modifiers = modifiers & ~MOD_MASK_SHIFT;
+#endif
+ }
+ if( modifiers )
+ {
+ string[ len++ ] = CSI;
+ string[ len++ ] = KS_MODIFIER;
+ string[ len++ ] = modifiers;
+ }
+
+ if( IS_SPECIAL( key_char ) )
+ {
+ string[ len++ ] = CSI;
+ string[ len++ ] = K_SECOND( key_char );
+ string[ len++ ] = K_THIRD( key_char );
+ }
+ else
+ {
+#ifdef FEAT_MBYTE
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ char_u from[2], *to;
+ int l;
+
+ from[0] = key_char;
+ from[1] = NUL;
+ l = 1;
+ to = string_convert(&input_conv, from, &l);
+ if (to != NULL)
+ {
+ for (i = 0; i < l && len < 19; i++)
+ {
+ if (to[i] == CSI)
+ {
+ string[len++] = KS_EXTRA;
+ string[len++] = KE_CSI;
+ }
+ else
+ string[len++] = to[i];
+ }
+ vim_free(to);
+ }
+ else
+ string[len++] = key_char;
+ }
+ else
+#endif
+ string[len++] = key_char;
+ }
+
+ if (len == 1 && string[0] == CSI)
+ {
+ /* Turn CSI into K_CSI. */
+ string[ len++ ] = KS_EXTRA;
+ string[ len++ ] = KE_CSI;
+ }
+
+ add_to_input_buf(string, len);
+}
+
+/*
+ * Handle MouseClick
+ */
+ void
+gui_mac_doMouseDownEvent (theEvent)
+ EventRecord *theEvent;
+{
+ short thePart;
+ WindowPtr whichWindow;
+
+ thePart = FindWindow (theEvent->where, &whichWindow);
+
+ switch (thePart)
+ {
+ case (inDesk):
+ /* TODO: what to do? */
+ break;
+
+ case (inMenuBar):
+ gui_mac_handle_menu(MenuSelect (theEvent->where));
+ break;
+
+ case (inContent):
+ gui_mac_doInContentClick (theEvent, whichWindow);
+ break;
+
+ case (inDrag):
+ gui_mac_doInDragClick (theEvent->where, whichWindow);
+ break;
+
+ case (inGrow):
+ gui_mac_doInGrowClick (theEvent->where, whichWindow);
+ break;
+
+ case (inGoAway):
+ if (TrackGoAway(whichWindow, theEvent->where))
+ gui_shell_closed();
+ break;
+
+ case (inZoomIn):
+ case (inZoomOut):
+#ifdef USE_CARBONIZED
+ gui_mac_doInZoomClick(theEvent, whichWindow);
+#endif
+ break;
+ }
+}
+
+/*
+ * Handle MouseMoved
+ * [this event is a moving in and out of a region]
+ */
+ void
+gui_mac_doMouseMovedEvent (event)
+ EventRecord *event;
+{
+ Point thePoint;
+ int_u vimModifiers;
+
+ thePoint = event->where;
+ GlobalToLocal (&thePoint);
+ vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
+
+ if (!Button())
+ gui_mouse_moved (thePoint.h, thePoint.v);
+ else
+#ifdef USE_CTRLCLICKMENU
+ if (!clickIsPopup)
+#endif
+ gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
+ thePoint.v, FALSE, vimModifiers);
+
+ /* Reset the region from which we move in and out */
+ SetRect (&dragRect, FILL_X(X_2_COL(thePoint.h)),
+ FILL_Y(Y_2_ROW(thePoint.v)),
+ FILL_X(X_2_COL(thePoint.h)+1),
+ FILL_Y(Y_2_ROW(thePoint.v)+1));
+
+ if (dragRectEnbl)
+ dragRectControl = kCreateRect;
+
+}
+
+/*
+ * Handle the mouse release
+ */
+ void
+gui_mac_doMouseUpEvent (theEvent)
+ EventRecord *theEvent;
+{
+ Point thePoint;
+ int_u vimModifiers;
+
+ /* TODO: Properly convert the Contextual menu mouse-up */
+ /* Potential source of the double menu */
+ lastMouseTick = theEvent->when;
+ dragRectEnbl = FALSE;
+ dragRectControl = kCreateEmpty;
+ thePoint = theEvent->where;
+ GlobalToLocal (&thePoint);
+
+ vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
+#ifdef USE_CTRLCLICKMENU
+ if (clickIsPopup)
+ {
+ vimModifiers &= ~MOUSE_CTRL;
+ clickIsPopup = FALSE;
+ }
+#endif
+ gui_send_mouse_event
+ (MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
+}
+
+#ifdef USE_MOUSEWHEEL
+ static pascal OSStatus
+gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
+ void *data)
+{
+ EventRef bogusEvent;
+ Point point;
+ Rect bounds;
+ UInt32 mod;
+ SInt32 delta;
+ int_u vim_mod;
+
+ if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
+ typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
+ goto bail;
+ if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
+ typeQDPoint, NULL, sizeof(Point), NULL, &point))
+ goto bail;
+ if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
+ typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
+ goto bail;
+
+ vim_mod = 0;
+ if (mod & shiftKey)
+ vim_mod |= MOUSE_SHIFT;
+ if (mod & controlKey)
+ vim_mod |= MOUSE_CTRL;
+ if (mod & optionKey)
+ vim_mod |= MOUSE_ALT;
+
+ /* post a bogus event to wake up WaitNextEvent */
+ if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
+ kEventAttributeNone, &bogusEvent))
+ goto bail;
+ if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
+ kEventPriorityLow))
+ goto bail;
+
+ if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
+ {
+ point.h -= bounds.left;
+ point.v -= bounds.top;
+ }
+
+ gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
+ point.h, point.v, FALSE, vim_mod);
+
+ return noErr;
+
+ bail:
+ /*
+ * when we fail give any additional callback handler a chance to perform
+ * it's actions
+ */
+ return CallNextEventHandler(nextHandler, theEvent);
+}
+#endif /* defined(USE_MOUSEWHEEL) */
+
+#if 0
+
+/*
+ * This would be the normal way of invoking the contextual menu
+ * but the Vim API doesn't seem to a support a request to get
+ * the menu that we should display
+ */
+ void
+gui_mac_handle_contextual_menu(event)
+ EventRecord *event;
+{
+/*
+ * Clone PopUp to use menu
+ * Create a object descriptor for the current selection
+ * Call the procedure
+ */
+
+// Call to Handle Popup
+ OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
+
+ if (status != noErr)
+ return;
+
+ if (CntxType == kCMMenuItemSelected)
+ {
+ /* Handle the menu CntxMenuID, CntxMenuItem */
+ /* The submenu can be handle directly by gui_mac_handle_menu */
+ /* But what about the current menu, is the meny changed by ContextualMenuSelect */
+ gui_mac_handle_menu ((CntxMenuID << 16) + CntxMenuItem);
+ }
+ else if (CntxMenuID == kCMShowHelpSelected)
+ {
+ /* Should come up with the help */
+ }
+
+}
+#endif
+
+/*
+ * Handle menubar selection
+ */
+ void
+gui_mac_handle_menu(menuChoice)
+ long menuChoice;
+{
+ short menu = HiWord(menuChoice);
+ short item = LoWord(menuChoice);
+ vimmenu_T *theVimMenu = root_menu;
+#ifndef USE_CARBONIZED
+ MenuHandle appleMenu;
+ Str255 itemName;
+#endif
+
+ if (menu == 256) /* TODO: use constant or gui.xyz */
+ {
+ if (item == 1)
+ gui_mch_beep(); /* TODO: Popup dialog or do :intro */
+ else
+ {
+#ifndef USE_CARBONIZED
+ /* Desk Accessory doesn't exist in Carbon */
+ appleMenu = GetMenuHandle (menu);
+ GetMenuItemText (appleMenu, item, itemName);
+ (void) OpenDeskAcc (itemName);
+#endif
+ }
+ }
+ else if (item != 0)
+ {
+ theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
+
+ if (theVimMenu)
+ gui_menu_cb(theVimMenu);
+ }
+ HiliteMenu (0);
+}
+
+/*
+ * Dispatch the event to proper handler
+ */
+
+ void
+gui_mac_handle_event (event)
+ EventRecord *event;
+{
+ OSErr error;
+
+ /* Handle contextual menu right now (if needed) */
+#ifdef USE_CTRLCLICKMENU
+ if (gui.MacOSHaveCntxMenu)
+ if (IsShowContextualMenuClick(event))
+ {
+# if 0
+ gui_mac_handle_contextual_menu(event);
+# else
+ gui_mac_doMouseDownEvent(event);
+# endif
+ return;
+ }
+#endif
+
+ /* Handle normal event */
+ switch (event->what)
+ {
+ case (keyDown):
+ case (autoKey):
+ gui_mac_doKeyEvent (event);
+ break;
+
+ case (keyUp):
+ /* We don't care about when the key get release */
+ break;
+
+ case (mouseDown):
+ gui_mac_doMouseDownEvent(event);
+ break;
+
+ case (mouseUp):
+ gui_mac_doMouseUpEvent(event);
+ break;
+
+ case (updateEvt):
+ gui_mac_doUpdateEvent (event);
+ break;
+
+ case (diskEvt):
+ /* We don't need special handling for disk insertion */
+ break;
+
+ case (activateEvt):
+ gui_mac_doActivateEvent (event);
+ break;
+
+ case (osEvt):
+ switch ((event->message >> 24) & 0xFF)
+ {
+ case (0xFA): /* mouseMovedMessage */
+ gui_mac_doMouseMovedEvent (event);
+ break;
+ case (0x01): /* suspendResumeMessage */
+ gui_mac_doSuspendEvent (event);
+ break;
+ }
+ break;
+
+#ifdef USE_AEVENT
+ case (kHighLevelEvent):
+ /* Someone's talking to us, through AppleEvents */
+ error = AEProcessAppleEvent(event); /* TODO: Error Handling */
+ break;
+#endif
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Unknown Stuff
+ * ------------------------------------------------------------
+ */
+
+
+ GuiFont
+gui_mac_find_font (font_name)
+ char_u *font_name;
+{
+ char_u c;
+ char_u *p;
+ char_u pFontName[256];
+ Str255 systemFontname;
+ short font_id;
+ short size=9;
+ GuiFont font;
+#if 0
+ char_u *fontNamePtr;
+#endif
+
+ for (p = font_name; ((*p != 0) && (*p != ':')); p++)
+ ;
+
+ c = *p;
+ *p = 0;
+
+#if 1
+ STRCPY(&pFontName[1], font_name);
+ pFontName[0] = STRLEN(font_name);
+ *p = c;
+
+ GetFNum (pFontName, &font_id);
+#else
+ /* name = C2Pascal_save(menu->dname); */
+ fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
+
+ GetFNum (fontNamePtr, &font_id);
+#endif
+
+
+ if (font_id == 0)
+ {
+ /* Oups, the system font was it the one the user want */
+
+ GetFontName (0, systemFontname);
+ if (!EqualString(pFontName, systemFontname, false, false))
+ return NOFONT;
+ }
+ if (*p == ':')
+ {
+ p++;
+ /* Set the values found after ':' */
+ while (*p)
+ {
+ switch (*p++)
+ {
+ case 'h':
+ size = points_to_pixels(p, &p, TRUE);
+ break;
+ /*
+ * TODO: Maybe accept width and styles
+ */
+ }
+ while (*p == ':')
+ p++;
+ }
+ }
+
+ if (size < 1)
+ size = 1; /* Avoid having a size of 0 with system font */
+
+ font = (size << 16) + ((long) font_id & 0xFFFF);
+
+ return font;
+}
+
+/*
+ * ------------------------------------------------------------
+ * GUI_MCH functionnality
+ * ------------------------------------------------------------
+ */
+
+/*
+ * Parse the GUI related command-line arguments. Any arguments used are
+ * deleted from argv, and *argc is decremented accordingly. This is called
+ * when vim is started, whether or not the GUI has been started.
+ */
+ void
+gui_mch_prepare(argc, argv)
+ int *argc;
+ char **argv;
+{
+ /* TODO: Move most of this stuff toward gui_mch_init */
+#ifdef USE_EXE_NAME
+ FSSpec applDir;
+# ifndef USE_FIND_BUNDLE_PATH
+ short applVRefNum;
+ long applDirID;
+ Str255 volName;
+# else
+ ProcessSerialNumber psn;
+ FSRef applFSRef;
+# endif
+#endif
+
+#ifndef USE_CARBONIZED
+ MaxApplZone(); /* What could replace thos */
+ /* In Carbon, all shared library are automatically load in
+ * there's no need to init them
+ */
+ InitGraf(&qd.thePort);
+ InitFonts();
+ InitWindows();
+ InitMenus();
+ TEInit();
+ InitDialogs(nil);
+#else
+ /* Why did I put that in? (Dany) */
+ MoreMasterPointers (0x40 * 3); /* we love handles */
+#endif
+
+#if 0
+ InitCursor();
+
+#ifdef USE_CARBONIZED
+ RegisterAppearanceClient();
+#endif
+
+#ifdef USE_AEVENT
+ (void) InstallAEHandlers();
+#endif
+
+#ifdef USE_CTRLCLICKMENU
+ if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
+ gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
+ else
+ gui.MacOSHaveCntxMenu = false;
+
+ if (gui.MacOSHaveCntxMenu)
+ gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
+#endif
+
+#ifdef USE_SIOUX
+ SIOUXSettings.standalone = false;
+ SIOUXSettings.initializeTB = false;
+ SIOUXSettings.setupmenus = false;
+ SIOUXSettings.asktosaveonclose = false;
+ SIOUXSettings.showstatusline = true;
+ SIOUXSettings.toppixel = 300;
+ SIOUXSettings.leftpixel = 10;
+ InstallConsole (1); /* fileno(stdout) = 1, on page 430 of MSL C */
+ printf ("Debugging console enabled\n");
+ /* SIOUXSetTitle ((char_u *) "Vim Stdout"); */
+#endif
+
+ pomme = NewMenu (256, "\p\024"); /* 0x14= = Apple Menu */
+
+ AppendMenu (pomme, "\pAbout VIM");
+#ifndef USE_CARBONIZED
+ AppendMenu (pomme, "\p-");
+ AppendResMenu (pomme, 'DRVR');
+#endif
+
+ InsertMenu (pomme, 0);
+
+ DrawMenuBar();
+
+
+#ifndef USE_OFFSETED_WINDOW
+ SetRect (&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
+#else
+ SetRect (&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
+#endif
+
+
+#ifdef USE_CARBONIZED
+ CreateNewWindow(kDocumentWindowClass,
+ kWindowResizableAttribute | kWindowCollapseBoxAttribute,
+ &windRect, &gui.VimWindow );
+ SetPortWindowPort ( gui.VimWindow );
+#else
+ gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, documentProc,
+ (WindowPtr) -1L, false, 0);
+ SetPort(gui.VimWindow);
+#endif
+
+ gui.char_width = 7;
+ gui.char_height = 11;
+ gui.char_ascent = 6;
+ gui.num_rows = 24;
+ gui.num_cols = 80;
+ gui.in_focus = TRUE; /* For the moment -> syn. of front application */
+
+#if TARGET_API_MAC_CARBON
+ gScrollAction = NewControlActionUPP (gui_mac_scroll_action);
+ gScrollDrag = NewControlActionUPP (gui_mac_drag_thumb);
+#else
+ gScrollAction = NewControlActionProc (gui_mac_scroll_action);
+ gScrollDrag = NewControlActionProc (gui_mac_drag_thumb);
+#endif
+
+ /* Getting a handle to the Help menu */
+#ifdef USE_HELPMENU
+# ifdef USE_CARBONIZED
+ HMGetHelpMenu(&gui.MacOSHelpMenu, NULL);
+# else
+ (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu);
+# endif
+
+ if (gui.MacOSHelpMenu != nil)
+ gui.MacOSHelpItems = CountMenuItems (gui.MacOSHelpMenu);
+ else
+ gui.MacOSHelpItems = 0;
+#endif
+
+ dragRectEnbl = FALSE;
+ dragRgn = NULL;
+ dragRectControl = kCreateEmpty;
+ cursorRgn = NewRgn();
+#endif
+#ifdef USE_EXE_NAME
+# ifndef USE_FIND_BUNDLE_PATH
+ HGetVol (volName, &applVRefNum, &applDirID);
+ /* TN2015: mention a possible bad VRefNum */
+ FSMakeFSSpec (applVRefNum, applDirID, "\p", &applDir);
+# else
+ /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
+ * of TN2015
+ * This technic remove the ../Contents/MacOS/etc part
+ */
+ (void) GetCurrentProcess(&psn);
+ /* if (err != noErr) return err; */
+
+ (void) GetProcessBundleLocation(&psn, &applFSRef);
+ /* if (err != noErr) return err; */
+
+ (void) FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
+
+ /* This technic return NIL when we disallow_gui */
+# endif
+ exe_name = FullPathFromFSSpec_save (applDir);
+#endif
+
+#ifdef USE_VIM_CREATOR_ID
+ _fcreator = 'VIM!';
+ _ftype = 'TEXT';
+#endif
+}
+
+#ifndef ALWAYS_USE_GUI
+/*
+ * Check if the GUI can be started. Called before gvimrc is sourced.
+ * Return OK or FAIL.
+ */
+ int
+gui_mch_init_check(void)
+{
+ /* TODO: For MacOS X find a way to return FAIL, if the user logged in
+ * using the >console
+ */
+ if (disallow_gui) /* see main.c for reason to disallow */
+ return FAIL;
+ return OK;
+}
+#endif
+
+ static OSErr
+receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag)
+{
+ int x, y;
+ int_u modifiers;
+ char_u **fnames = NULL;
+ int count;
+ int i, j;
+
+ /* Get drop position, modifiers and count of items */
+ {
+ Point point;
+ SInt16 mouseUpModifiers;
+ UInt16 countItem;
+
+ GetDragMouse(theDrag, &point, NULL);
+ GlobalToLocal(&point);
+ x = point.h;
+ y = point.v;
+ GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
+ modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
+ CountDragItems(theDrag, &countItem);
+ count = countItem;
+ }
+
+ fnames = (char_u **)alloc(count * sizeof(char_u *));
+ if (fnames == NULL)
+ return dragNotAcceptedErr;
+
+ /* Get file names dropped */
+ for (i = j = 0; i < count; ++i)
+ {
+ DragItemRef item;
+ OSErr err;
+ Size size;
+ FlavorType type = flavorTypeHFS;
+ HFSFlavor hfsFlavor;
+
+ fnames[i] = NULL;
+ GetDragItemReferenceNumber(theDrag, i + 1, &item);
+ err = GetFlavorDataSize(theDrag, item, type, &size);
+ if (err != noErr || size > sizeof(hfsFlavor))
+ continue;
+ err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
+ if (err != noErr)
+ continue;
+ fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
+ }
+ count = j;
+
+ gui_handle_drop(x, y, modifiers, fnames, count);
+ return noErr;
+}
+
+/*
+ * Initialise the GUI. Create all the windows, set up all the call-backs
+ * etc.
+ */
+ int
+gui_mch_init()
+{
+ /* TODO: Move most of this stuff toward gui_mch_init */
+ Rect windRect;
+ MenuHandle pomme;
+#ifdef USE_CTRLCLICKMENU
+ long gestalt_rc;
+#endif
+#ifdef USE_MOUSEWHEEL
+ EventTypeSpec eventTypeSpec;
+ EventHandlerRef mouseWheelHandlerRef;
+#endif
+#if 1
+ InitCursor();
+
+#ifdef USE_CARBONIZED
+ RegisterAppearanceClient();
+#endif
+
+#ifdef USE_AEVENT
+ (void) InstallAEHandlers();
+#endif
+
+#ifdef USE_CTRLCLICKMENU
+ if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
+ gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
+ else
+ gui.MacOSHaveCntxMenu = false;
+
+ if (gui.MacOSHaveCntxMenu)
+ gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
+#endif
+
+#ifdef USE_SIOUX
+ SIOUXSettings.standalone = false;
+ SIOUXSettings.initializeTB = false;
+ SIOUXSettings.setupmenus = false;
+ SIOUXSettings.asktosaveonclose = false;
+ SIOUXSettings.showstatusline = true;
+ SIOUXSettings.toppixel = 300;
+ SIOUXSettings.leftpixel = 10;
+ InstallConsole (1); /* fileno(stdout) = 1, on page 430 of MSL C */
+ printf ("Debugging console enabled\n");
+ /* SIOUXSetTitle ((char_u *) "Vim Stdout"); */
+#endif
+
+ pomme = NewMenu (256, "\p\024"); /* 0x14= = Apple Menu */
+
+ AppendMenu (pomme, "\pAbout VIM");
+#ifndef USE_CARBONIZED
+ AppendMenu (pomme, "\p-");
+ AppendResMenu (pomme, 'DRVR');
+#endif
+
+ InsertMenu (pomme, 0);
+
+ DrawMenuBar();
+
+
+#ifndef USE_OFFSETED_WINDOW
+ SetRect (&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
+#else
+ SetRect (&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
+#endif
+
+ gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
+#ifdef USE_CARBONIZED
+ zoomDocProc,
+#else
+ documentProc,
+#endif
+ (WindowPtr)-1L, true, 0);
+ InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
+ gui.VimWindow, NULL);
+#ifdef USE_CARBONIZED
+ SetPortWindowPort ( gui.VimWindow );
+#else
+ SetPort(gui.VimWindow);
+#endif
+
+ gui.char_width = 7;
+ gui.char_height = 11;
+ gui.char_ascent = 6;
+ gui.num_rows = 24;
+ gui.num_cols = 80;
+ gui.in_focus = TRUE; /* For the moment -> syn. of front application */
+
+#if TARGET_API_MAC_CARBON
+ gScrollAction = NewControlActionUPP (gui_mac_scroll_action);
+ gScrollDrag = NewControlActionUPP (gui_mac_drag_thumb);
+#else
+ gScrollAction = NewControlActionProc (gui_mac_scroll_action);
+ gScrollDrag = NewControlActionProc (gui_mac_drag_thumb);
+#endif
+
+ /* Getting a handle to the Help menu */
+#ifdef USE_HELPMENU
+# ifdef USE_CARBONIZED
+ HMGetHelpMenu(&gui.MacOSHelpMenu, NULL);
+# else
+ (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu);
+# endif
+
+ if (gui.MacOSHelpMenu != nil)
+ gui.MacOSHelpItems = CountMenuItems (gui.MacOSHelpMenu);
+ else
+ gui.MacOSHelpItems = 0;
+#endif
+
+ dragRectEnbl = FALSE;
+ dragRgn = NULL;
+ dragRectControl = kCreateEmpty;
+ cursorRgn = NewRgn();
+#endif
+ /* Display any pending error messages */
+ display_errors();
+
+ /* Get background/foreground colors from system */
+ /* TODO: do the approriate call to get real defaults */
+ gui.norm_pixel = 0x00000000;
+ gui.back_pixel = 0x00FFFFFF;
+
+ /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
+ * file). */
+ set_normal_colors();
+
+ /*
+ * Check that none of the colors are the same as the background color.
+ * Then store the current values as the defaults.
+ */
+ gui_check_colors();
+ gui.def_norm_pixel = gui.norm_pixel;
+ gui.def_back_pixel = gui.back_pixel;
+
+ /* Get the colors for the highlight groups (gui_check_colors() might have
+ * changed them) */
+ highlight_gui_started();
+
+ /*
+ * Setting the gui constants
+ */
+#ifdef FEAT_MENU
+ gui.menu_height = 0;
+#endif
+ gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
+ gui.border_offset = gui.border_width = 2;
+
+#if defined(FEAT_GUI) && defined(MACOS_X)
+ /* If Quartz-style text antialiasing is available (see
+ gui_mch_draw_string() below), enable it for all font sizes. */
+ vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
+#endif
+
+#ifdef USE_MOUSEWHEEL
+ eventTypeSpec.eventClass = kEventClassMouse;
+ eventTypeSpec.eventKind = kEventMouseWheelMoved;
+ mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
+ if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
+ &eventTypeSpec, NULL, &mouseWheelHandlerRef))
+ {
+ mouseWheelHandlerRef = NULL;
+ DisposeEventHandlerUPP(mouseWheelHandlerUPP);
+ mouseWheelHandlerUPP = NULL;
+ }
+#endif
+
+#ifdef FEAT_MBYTE
+ set_option_value((char_u *)"termencoding", 0L, (char_u *)"macroman", 0);
+#endif
+
+ /* TODO: Load bitmap if using TOOLBAR */
+ return OK;
+}
+
+/*
+ * Called when the foreground or background color has been changed.
+ */
+ void
+gui_mch_new_colors()
+{
+ /* TODO:
+ * This proc is called when Normal is set to a value
+ * so what msut be done? I don't know
+ */
+}
+
+/*
+ * Open the GUI window which was created by a call to gui_mch_init().
+ */
+ int
+gui_mch_open()
+{
+ ShowWindow(gui.VimWindow);
+
+ if (gui_win_x != -1 && gui_win_y != -1)
+ gui_mch_set_winpos(gui_win_x, gui_win_y);
+
+#ifdef USE_CARBONIZED
+ /*
+ * Make the GUI the foreground process (in case it was launched
+ * from the Terminal or via :gui).
+ */
+ {
+ ProcessSerialNumber psn;
+ if (GetCurrentProcess(&psn) == noErr)
+ SetFrontProcess(&psn);
+ }
+#endif
+
+ return OK;
+}
+
+ void
+gui_mch_exit(int rc)
+{
+ /* TODO: find out all what is missing here? */
+ DisposeRgn(cursorRgn);
+
+#ifdef USE_MOUSEWHEEL
+ if (mouseWheelHandlerUPP != NULL)
+ DisposeEventHandlerUPP(mouseWheelHandlerUPP);
+#endif
+
+ /* Exit to shell? */
+ exit(rc);
+}
+
+/*
+ * Get the position of the top left corner of the window.
+ */
+ int
+gui_mch_get_winpos(int *x, int *y)
+{
+ /* TODO */
+#ifdef USE_CARBONIZED
+ Rect bounds;
+ OSStatus status;
+
+ /* Carbon >= 1.0.2, MacOS >= 8.5 */
+ status = GetWindowBounds (gui.VimWindow, kWindowStructureRgn, &bounds);
+
+ if (status != noErr)
+ return FAIL;
+ *x = bounds.left;
+ *y = bounds.top;
+ return OK;
+#endif
+ return FAIL;
+}
+
+/*
+ * Set the position of the top left corner of the window to the given
+ * coordinates.
+ */
+ void
+gui_mch_set_winpos(int x, int y)
+{
+ /* TODO: Should make sure the window is move within range
+ * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
+ */
+ MoveWindow(gui.VimWindow, x, y, TRUE);
+}
+
+ void
+gui_mch_set_shellsize(
+ int width,
+ int height,
+ int min_width,
+ int min_height,
+ int base_width,
+ int base_height)
+{
+#ifdef USE_CARBONIZED
+ CGrafPtr VimPort;
+ Rect VimBound;
+#endif
+
+ if (gui.which_scrollbars[SBAR_LEFT])
+ {
+#ifdef USE_CARBONIZED
+ VimPort = GetWindowPort ( gui.VimWindow );
+ GetPortBounds (VimPort, &VimBound);
+ VimBound.left = -gui.scrollbar_width; /* + 1;*/
+ SetPortBounds (VimPort, &VimBound);
+ /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
+#else
+ gui.VimWindow->portRect.left = -gui.scrollbar_width; /* + 1;*/
+ /* SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
+#endif
+ }
+ else
+ {
+#ifdef USE_CARBONIZED
+ VimPort = GetWindowPort ( gui.VimWindow );
+ GetPortBounds (VimPort, &VimBound);
+ VimBound.left = 0;
+ SetPortBounds (VimPort, &VimBound);
+#else
+ gui.VimWindow->portRect.left = 0;
+#endif;
+ }
+
+ SizeWindow(gui.VimWindow, width, height, TRUE);
+
+ gui_resize_shell(width, height);
+}
+
+/*
+ * Get the screen dimensions.
+ * Allow 10 pixels for horizontal borders, 40 for vertical borders.
+ * Is there no way to find out how wide the borders really are?
+ * TODO: Add live udate of those value on suspend/resume.
+ */
+ void
+gui_mch_get_screen_dimensions(screen_w, screen_h)
+ int *screen_w;
+ int *screen_h;
+{
+ GDHandle dominantDevice = GetMainDevice();
+ Rect screenRect = (**dominantDevice).gdRect;
+
+ *screen_w = screenRect.right - 10;
+ *screen_h = screenRect.bottom - 40;
+}
+
+
+
+/*
+ * Initialise vim to use the font with the given name. Return FAIL if the font
+ * could not be loaded, OK otherwise.
+ */
+ int
+gui_mch_init_font(font_name, fontset)
+ char_u *font_name;
+ int fontset; /* not used */
+{
+ /* TODO: Add support for bold italic underline proportional etc... */
+ Str255 suggestedFont = "\pMonaco";
+ int suggestedSize = 9;
+ FontInfo font_info;
+ short font_id;
+ GuiFont font;
+
+ if (font_name == NULL)
+ {
+ /* First try to get the suggested font */
+ GetFNum(suggestedFont, &font_id);
+
+ if (font_id == 0)
+ {
+ /* Then pickup the standard application font */
+ font_id = GetAppFont();
+ }
+ font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
+ }
+ else
+ {
+ font = gui_mac_find_font (font_name);
+
+ if (font == NOFONT)
+ return FAIL;
+ }
+ gui.norm_font = font;
+
+ TextSize (font >> 16);
+ TextFont (font & 0xFFFF);
+
+ GetFontInfo (&font_info);
+
+ gui.char_ascent = font_info.ascent;
+ gui.char_width = CharWidth ('_');
+ gui.char_height = font_info.ascent + font_info.descent + p_linespace;
+
+ return OK;
+
+}
+
+ int
+gui_mch_adjust_charsize()
+{
+ FontInfo font_info;
+
+ GetFontInfo (&font_info);
+ gui.char_height = font_info.ascent + font_info.descent + p_linespace;
+ gui.char_ascent = font_info.ascent + p_linespace / 2;
+ return OK;
+}
+
+/*
+ * Get a font structure for highlighting.
+ */
+ GuiFont
+gui_mch_get_font(name, giveErrorIfMissing)
+ char_u *name;
+ int giveErrorIfMissing;
+{
+ GuiFont font;
+
+ font = gui_mac_find_font(name);
+
+ if (font == NOFONT)
+ {
+ if (giveErrorIfMissing)
+ EMSG2(_(e_font), name);
+ return NOFONT;
+ }
+ /*
+ * TODO : Accept only monospace
+ */
+
+ return font;
+}
+
+/*
+ * Set the current text font.
+ */
+ void
+gui_mch_set_font(font)
+ GuiFont font;
+{
+ /*
+ * TODO: maybe avoid set again the current font.
+ */
+ TextSize(font >> 16);
+ TextFont(font & 0xFFFF);
+}
+
+#if 0 /* not used */
+/*
+ * Return TRUE if the two fonts given are equivalent.
+ */
+ int
+gui_mch_same_font(f1, f2)
+ GuiFont f1;
+ GuiFont f2;
+{
+ return f1 == f2;
+}
+#endif
+
+/*
+ * If a font is not going to be used, free its structure.
+ */
+ void
+gui_mch_free_font(font)
+ GuiFont font;
+{
+ /*
+ * Free font when "font" is not 0.
+ * Nothing to do in the current implementation, since
+ * nothing is allocated for each font used.
+ */
+}
+
+ static int
+hex_digit(c)
+ int c;
+{
+ if (isdigit(c))
+ return c - '0';
+ c = TOLOWER_ASC(c);
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1000;
+}
+
+/*
+ * Return the Pixel value (color) for the given color name. This routine was
+ * pretty much taken from example code in the Silicon Graphics OSF/Motif
+ * Programmer's Guide.
+ * Return INVALCOLOR when failed.
+ */
+ guicolor_T
+gui_mch_get_color(name)
+ char_u *name;
+{
+ /* TODO: Add support for the new named color of MacOS 8
+ */
+ RGBColor MacColor;
+// guicolor_T color = 0;
+
+ typedef struct guicolor_tTable
+ {
+ char *name;
+ guicolor_T color;
+ } guicolor_tTable;
+
+ /*
+ * The comment at the end of each line is the source
+ * (Mac, Window, Unix) and the number is the unix rgb.txt value
+ */
+ static guicolor_tTable table[] =
+ {
+ {"Black", RGB(0x00, 0x00, 0x00)},
+ {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
+ {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
+ {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
+ {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
+ {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
+ {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
+ {"white", RGB(0xFF, 0xFF, 0xFF)},
+ {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
+ {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
+ {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
+ {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
+ {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
+ {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
+ {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
+ {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
+ {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
+ {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
+ {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
+ {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
+ {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
+ {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
+ {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
+ {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
+ {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
+ {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
+ {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
+ {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
+ {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
+ {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
+ {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
+ };
+
+ int r, g, b;
+ int i;
+
+ if (name[0] == '#' && strlen((char *) name) == 7)
+ {
+ /* Name is in "#rrggbb" format */
+ r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
+ g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
+ b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
+ if (r < 0 || g < 0 || b < 0)
+ return INVALCOLOR;
+ return RGB(r, g, b);
+ }
+ else
+ {
+ if (STRICMP (name, "hilite") == 0)
+ {
+ LMGetHiliteRGB (&MacColor);
+ return (RGB (MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
+ }
+ /* Check if the name is one of the colors we know */
+ for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
+ if (STRICMP(name, table[i].name) == 0)
+ return table[i].color;
+ }
+
+
+ /*
+ * Last attempt. Look in the file "$VIM/rgb.txt".
+ */
+ {
+#define LINE_LEN 100
+ FILE *fd;
+ char line[LINE_LEN];
+ char_u *fname;
+
+#ifdef COLON_AS_PATHSEP
+ fname = expand_env_save((char_u *)"$VIMRUNTIME:rgb.txt");
+#else
+ fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
+#endif
+ if (fname == NULL)
+ return INVALCOLOR;
+
+ fd = fopen((char *)fname, "rt");
+ vim_free(fname);
+ if (fd == NULL)
+ return INVALCOLOR;
+
+ while (!feof(fd))
+ {
+ int len;
+ int pos;
+ char *color;
+
+ fgets(line, LINE_LEN, fd);
+ len = strlen(line);
+
+ if (len <= 1 || line[len-1] != '\n')
+ continue;
+
+ line[len-1] = '\0';
+
+ i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
+ if (i != 3)
+ continue;
+
+ color = line + pos;
+
+ if (STRICMP(color, name) == 0)
+ {
+ fclose(fd);
+ return (guicolor_T) RGB(r, g, b);
+ }
+ }
+ fclose(fd);
+ }
+
+ return INVALCOLOR;
+}
+
+/*
+ * Set the current text foreground color.
+ */
+ void
+gui_mch_set_fg_color(color)
+ guicolor_T color;
+{
+ RGBColor TheColor;
+
+ TheColor.red = Red(color) * 0x0101;
+ TheColor.green = Green(color) * 0x0101;
+ TheColor.blue = Blue(color) * 0x0101;
+
+ RGBForeColor (&TheColor);
+}
+
+/*
+ * Set the current text background color.
+ */
+ void
+gui_mch_set_bg_color(color)
+ guicolor_T color;
+{
+ RGBColor TheColor;
+
+ TheColor.red = Red(color) * 0x0101;
+ TheColor.green = Green(color) * 0x0101;
+ TheColor.blue = Blue(color) * 0x0101;
+
+ RGBBackColor (&TheColor);
+}
+
+ void
+gui_mch_draw_string(row, col, s, len, flags)
+ int row;
+ int col;
+ char_u *s;
+ int len;
+ int flags;
+{
+#if defined(FEAT_GUI) && defined(MACOS_X)
+ SInt32 sys_version;
+#endif
+#ifdef FEAT_MBYTE
+ char_u *tofree = NULL;
+
+ if (output_conv.vc_type != CONV_NONE)
+ {
+ tofree = string_convert(&output_conv, s, &len);
+ if (tofree != NULL)
+ s = tofree;
+ }
+#endif
+
+#if defined(FEAT_GUI) && defined(MACOS_X)
+ /*
+ * On OS X, try using Quartz-style text antialiasing.
+ */
+ sys_version = 0;
+
+ Gestalt(gestaltSystemVersion, &sys_version);
+ if (sys_version >= 0x1020)
+ {
+ /* Quartz antialiasing is available only in OS 10.2 and later. */
+ UInt32 qd_flags = (p_antialias ?
+ kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
+ (void)SwapQDTextFlags(qd_flags);
+ }
+
+ if (sys_version >= 0x1020 && p_antialias)
+ {
+ StyleParameter face;
+
+ face = normal;
+ if (flags & DRAW_BOLD)
+ face |= bold;
+ if (flags & DRAW_UNDERL)
+ face |= underline;
+ TextFace(face);
+
+ /* Quartz antialiasing works only in srcOr transfer mode. */
+ TextMode(srcOr);
+
+ if (!(flags & DRAW_TRANSP))
+ {
+ /*
+ * Since we're using srcOr mode, we have to clear the block
+ * before drawing the text. The following is like calling
+ * gui_mch_clear_block(row, col, row, col + len - 1),
+ * but without setting the bg color to gui.back_pixel.
+ */
+ Rect rc;
+ rc.left = FILL_X(col);
+ rc.top = FILL_Y(row);
+ rc.right = FILL_X(col + len) + (col + len == Columns);
+ rc.bottom = FILL_Y(row + 1);
+ EraseRect(&rc);
+ }
+
+ MoveTo(TEXT_X(col), TEXT_Y(row));
+ DrawText((char*)s, 0, len);
+ }
+ else
+#endif
+ {
+ /* Use old-style, non-antialiased QuickDraw text rendering. */
+ TextMode (srcCopy);
+ TextFace (normal);
+
+ /* SelectFont(hdc, gui.currFont); */
+
+ if (flags & DRAW_TRANSP)
+ {
+ TextMode (srcOr);
+ }
+
+ MoveTo (TEXT_X(col), TEXT_Y(row));
+ DrawText ((char *)s, 0, len);
+
+
+ if (flags & DRAW_BOLD)
+ {
+ TextMode (srcOr);
+ MoveTo (TEXT_X(col) + 1, TEXT_Y(row));
+ DrawText ((char *)s, 0, len);
+ }
+
+ if (flags & DRAW_UNDERL)
+ {
+ MoveTo (FILL_X(col), FILL_Y(row + 1) - 1);
+ LineTo (FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
+ }
+ }
+
+#ifdef FEAT_MBYTE
+ vim_free(tofree);
+#endif
+}
+
+/*
+ * Return OK if the key with the termcap name "name" is supported.
+ */
+ int
+gui_mch_haskey(name)
+ char_u *name;
+{
+ int i;
+
+ for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
+ if (name[0] == special_keys[i].vim_code0 &&
+ name[1] == special_keys[i].vim_code1)
+ return OK;
+ return FAIL;
+}
+
+ void
+gui_mch_beep()
+{
+ SysBeep (1); /* Should this be 0? (????) */
+}
+
+ void
+gui_mch_flash(msec)
+ int msec;
+{
+ /* Do a visual beep by reversing the foreground and background colors */
+ Rect rc;
+
+ /*
+ * Note: InvertRect() excludes right and bottom of rectangle.
+ */
+ rc.left = 0;
+ rc.top = 0;
+ rc.right = gui.num_cols * gui.char_width;
+ rc.bottom = gui.num_rows * gui.char_height;
+ InvertRect(&rc);
+
+ ui_delay((long)msec, TRUE); /* wait for some msec */
+
+ InvertRect(&rc);
+}
+
+/*
+ * Invert a rectangle from row r, column c, for nr rows and nc columns.
+ */
+ void
+gui_mch_invert_rectangle(r, c, nr, nc)
+ int r;
+ int c;
+ int nr;
+ int nc;
+{
+ Rect rc;
+
+ /*
+ * Note: InvertRect() excludes right and bottom of rectangle.
+ */
+ rc.left = FILL_X(c);
+ rc.top = FILL_Y(r);
+ rc.right = rc.left + nc * gui.char_width;
+ rc.bottom = rc.top + nr * gui.char_height;
+ InvertRect(&rc);
+
+}
+
+/*
+ * Iconify the GUI window.
+ */
+ void
+gui_mch_iconify()
+{
+ /* TODO: find out what could replace iconify
+ * -window shade?
+ * -hide application?
+ */
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Bring the Vim window to the foreground.
+ */
+ void
+gui_mch_set_foreground()
+{
+ /* TODO */
+}
+#endif
+
+/*
+ * Draw a cursor without focus.
+ */
+ void
+gui_mch_draw_hollow_cursor(color)
+ guicolor_T color;
+{
+ Rect rc;
+
+ gui_mch_set_fg_color(color);
+
+ /*
+ * Note: FrameRect() excludes right and bottom of rectangle.
+ */
+ rc.left = FILL_X(gui.col);
+ rc.top = FILL_Y(gui.row);
+ rc.right = rc.left + gui.char_width;
+ rc.bottom = rc.top + gui.char_height;
+
+ gui_mch_set_fg_color(color);
+
+ FrameRect (&rc);
+}
+
+/*
+ * Draw part of a cursor, only w pixels wide, and h pixels high.
+ */
+ void
+gui_mch_draw_part_cursor(w, h, color)
+ int w;
+ int h;
+ guicolor_T color;
+{
+ Rect rc;
+
+#ifdef FEAT_RIGHTLEFT
+ /* vertical line should be on the right of current point */
+ if (CURSOR_BAR_RIGHT)
+ rc.left = FILL_X(gui.col + 1) - w;
+ else
+#endif
+ rc.left = FILL_X(gui.col);
+ rc.top = FILL_Y(gui.row) + gui.char_height - h;
+ rc.right = rc.left + w;
+ rc.bottom = rc.top + h;
+
+ gui_mch_set_fg_color(color);
+
+ PaintRect (&rc);
+}
+
+
+
+/*
+ * Catch up with any queued X events. This may put keyboard input into the
+ * input buffer, call resize call-backs, trigger timers etc. If there is
+ * nothing in the X event queue (& no timers pending), then we return
+ * immediately.
+ */
+ void
+gui_mch_update()
+{
+ /* TODO: find what to do
+ * maybe call gui_mch_wait_for_chars (0)
+ * more like look at EventQueue then
+ * call heart of gui_mch_wait_for_chars;
+ *
+ * if (eventther)
+ * gui_mac_handle_event(&event);
+ */
+ EventRecord theEvent;
+
+ if (EventAvail (everyEvent, &theEvent))
+ if (theEvent.what != nullEvent)
+ gui_mch_wait_for_chars(0);
+}
+
+/*
+ * Simple wrapper to neglect more easily the time
+ * spent inside WaitNextEvent while profiling.
+ */
+
+#if defined(__MWERKS__) /* only in Codewarrior */
+# pragma profile reset
+#endif
+ pascal
+ Boolean
+WaitNextEventWrp (EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
+{
+ if (((long) sleep) < -1)
+ sleep = 32767;
+ return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
+}
+
+/*
+ * GUI input routine called by gui_wait_for_chars(). Waits for a character
+ * from the keyboard.
+ * wtime == -1 Wait forever.
+ * wtime == 0 This should never happen.
+ * wtime > 0 Wait wtime milliseconds for a character.
+ * Returns OK if a character was found to be available within the given time,
+ * or FAIL otherwise.
+ */
+#if defined(__MWERKS__) /* only in Codewarrior */
+# pragma profile reset
+#endif
+ int
+gui_mch_wait_for_chars(wtime)
+ int wtime;
+{
+ EventMask mask = (everyEvent);
+ EventRecord event;
+ long entryTick;
+ long currentTick;
+ long sleeppyTick;
+
+ /* If we are providing life feedback with the scrollbar,
+ * we don't want to try to wait for an event, or else
+ * there won't be any life feedback.
+ */
+ if (dragged_sb != NULL)
+ return FAIL;
+ /* TODO: Check if FAIL is the proper return code */
+
+ entryTick = TickCount();
+
+ allow_scrollbar = TRUE;
+
+ do
+ {
+/* if (dragRectControl == kCreateEmpty)
+ {
+ dragRgn = NULL;
+ dragRectControl = kNothing;
+ }
+ else*/ if (dragRectControl == kCreateRect)
+ {
+ dragRgn = cursorRgn;
+ RectRgn (dragRgn, &dragRect);
+ dragRectControl = kNothing;
+ }
+ /*
+ * Don't use gui_mch_update() because then we will spin-lock until a
+ * char arrives, instead we use WaitNextEventWrp() to hang until an
+ * event arrives. No need to check for input_buf_full because we are
+ * returning as soon as it contains a single char.
+ */
+ /* TODO: reduce wtime accordinly??? */
+ if (wtime > -1)
+ sleeppyTick = 60*wtime/1000;
+ else
+ sleeppyTick = 32767;
+ if (WaitNextEventWrp (mask, &event, sleeppyTick, dragRgn))
+ {
+#ifdef USE_SIOUX
+ if (!SIOUXHandleOneEvent(&event))
+#endif
+ gui_mac_handle_event (&event);
+ if (input_available())
+ {
+ allow_scrollbar = FALSE;
+ return OK;
+ }
+ }
+ currentTick = TickCount();
+ }
+ while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
+
+ allow_scrollbar = FALSE;
+ return FAIL;
+}
+
+#if defined(__MWERKS__) /* only in Codewarrior */
+# pragma profile reset
+#endif
+
+/*
+ * Output routines.
+ */
+
+/* Flush any output to the screen */
+ void
+gui_mch_flush()
+{
+ /* TODO: Is anything needed here? */
+}
+
+/*
+ * Clear a rectangular region of the screen from text pos (row1, col1) to
+ * (row2, col2) inclusive.
+ */
+ void
+gui_mch_clear_block(row1, col1, row2, col2)
+ int row1;
+ int col1;
+ int row2;
+ int col2;
+{
+ Rect rc;
+
+ /*
+ * Clear one extra pixel at the far right, for when bold characters have
+ * spilled over to the next column.
+ */
+ rc.left = FILL_X(col1);
+ rc.top = FILL_Y(row1);
+ rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
+ rc.bottom = FILL_Y(row2 + 1);
+
+ gui_mch_set_bg_color(gui.back_pixel);
+ EraseRect (&rc);
+}
+
+/*
+ * Clear the whole text window.
+ */
+ void
+gui_mch_clear_all()
+{
+ Rect rc;
+
+ rc.left = 0;
+ rc.top = 0;
+ rc.right = Columns * gui.char_width + 2 * gui.border_width;
+ rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
+
+ gui_mch_set_bg_color(gui.back_pixel);
+ EraseRect(&rc);
+/* gui_mch_set_fg_color(gui.norm_pixel);
+ FrameRect(&rc);
+*/
+}
+
+/*
+ * Delete the given number of lines from the given row, scrolling up any
+ * text further down within the scroll region.
+ */
+ void
+gui_mch_delete_lines(row, num_lines)
+ int row;
+ int num_lines;
+{
+ Rect rc;
+
+ /* changed without checking! */
+ rc.left = FILL_X(gui.scroll_region_left);
+ rc.right = FILL_X(gui.scroll_region_right + 1);
+ rc.top = FILL_Y(row);
+ rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
+
+ gui_mch_set_bg_color(gui.back_pixel);
+ ScrollRect (&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
+
+ gui_clear_block(gui.scroll_region_bot - num_lines + 1,
+ gui.scroll_region_left,
+ gui.scroll_region_bot, gui.scroll_region_right);
+}
+
+/*
+ * Insert the given number of lines before the given row, scrolling down any
+ * following text within the scroll region.
+ */
+ void
+gui_mch_insert_lines(row, num_lines)
+ int row;
+ int num_lines;
+{
+ Rect rc;
+
+ rc.left = FILL_X(gui.scroll_region_left);
+ rc.right = FILL_X(gui.scroll_region_right + 1);
+ rc.top = FILL_Y(row);
+ rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
+
+ gui_mch_set_bg_color(gui.back_pixel);
+
+ ScrollRect (&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
+
+ /* Update gui.cursor_row if the cursor scrolled or copied over */
+ if (gui.cursor_row >= gui.row
+ && gui.cursor_col >= gui.scroll_region_left
+ && gui.cursor_col <= gui.scroll_region_right)
+ {
+ if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
+ gui.cursor_row += num_lines;
+ else if (gui.cursor_row <= gui.scroll_region_bot)
+ gui.cursor_is_valid = FALSE;
+ }
+
+ gui_clear_block(row, gui.scroll_region_left,
+ row + num_lines - 1, gui.scroll_region_right);
+}
+
+ /*
+ * TODO: add a vim format to the clipboard which remember
+ * LINEWISE, CHARWISE, BLOCKWISE
+ */
+
+ void
+clip_mch_request_selection(cbd)
+ VimClipboard *cbd;
+{
+
+ Handle textOfClip;
+#ifdef USE_CARBONIZED
+ Size scrapSize;
+ ScrapFlavorFlags scrapFlags;
+ ScrapRef scrap = nil;
+ OSStatus error;
+#else
+ long scrapOffset;
+ long scrapSize;
+#endif
+ int type;
+ char *searchCR;
+ char_u *tempclip;
+
+
+#ifdef USE_CARBONIZED
+ error = GetCurrentScrap (&scrap);
+ if (error != noErr)
+ return;
+
+ error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeText, &scrapFlags);
+ if (error != noErr)
+ return;
+
+ error = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &scrapSize);
+ if (error != noErr)
+ return;
+
+ ReserveMem (scrapSize);
+#else
+ /* Call to LoadScrap seem to avoid problem with crash on first paste */
+ scrapSize = LoadScrap();
+ scrapSize = GetScrap(nil, 'TEXT', &scrapOffset);
+
+ if (scrapSize > 0)
+#endif
+ {
+#ifdef USE_CARBONIZED
+ /* In CARBON we don't need a Handle, a pointer is good */
+ textOfClip = NewHandle (scrapSize);
+ /* tempclip = lalloc(scrapSize+1, TRUE); */
+#else
+ textOfClip = NewHandle(0);
+#endif
+ HLock (textOfClip);
+#ifdef USE_CARBONIZED
+ error = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &scrapSize, *textOfClip);
+#else
+ scrapSize = GetScrap(textOfClip, 'TEXT', &scrapOffset);
+#endif
+
+ type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
+
+ tempclip = lalloc(scrapSize+1, TRUE);
+ STRNCPY(tempclip, *textOfClip, scrapSize);
+ tempclip[scrapSize] = 0;
+
+ searchCR = (char *)tempclip;
+ while (searchCR != NULL)
+ {
+ searchCR = strchr(searchCR, '\r');
+
+ if (searchCR != NULL)
+ searchCR[0] = '\n';
+
+ }
+
+#ifdef FEAT_MBYTE
+ if (input_conv.vc_type != CONV_NONE)
+ {
+ char_u *to;
+ int l = scrapSize;
+
+ to = string_convert(&input_conv, tempclip, &l);
+ if (to != NULL)
+ {
+ vim_free(tempclip);
+ tempclip = to;
+ scrapSize = l;
+ }
+ }
+#endif
+ clip_yank_selection(type, tempclip, scrapSize, cbd);
+
+ vim_free(tempclip);
+ HUnlock(textOfClip);
+
+ DisposeHandle(textOfClip);
+ }
+}
+
+ void
+clip_mch_lose_selection(cbd)
+ VimClipboard *cbd;
+{
+ /*
+ * TODO: Really nothing to do?
+ */
+}
+
+ int
+clip_mch_own_selection(cbd)
+ VimClipboard *cbd;
+{
+ return OK;
+}
+
+/*
+ * Send the current selection to the clipboard.
+ */
+ void
+clip_mch_set_selection(cbd)
+ VimClipboard *cbd;
+{
+ Handle textOfClip;
+ long scrapSize;
+ int type;
+#ifdef USE_CARBONIZED
+ ScrapRef scrap;
+#endif
+
+ char_u *str = NULL;
+
+ if (!cbd->owned)
+ return;
+
+ clip_get_selection(cbd);
+
+ /*
+ * Once we set the clipboard, lose ownership. If another application sets
+ * the clipboard, we don't want to think that we still own it.
+ *
+ */
+
+ cbd->owned = FALSE;
+
+ type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd);
+
+#ifdef FEAT_MBYTE
+ if (str != NULL && output_conv.vc_type != CONV_NONE)
+ {
+ char_u *to;
+ int l = scrapSize;
+
+ to = string_convert(&output_conv, str, &l);
+ if (to != NULL)
+ {
+ vim_free(str);
+ str = to;
+ scrapSize = l;
+ }
+ }
+#endif
+
+ if (type >= 0)
+ {
+#ifdef USE_CARBONIZED
+ ClearCurrentScrap();
+#else
+ ZeroScrap();
+#endif
+
+ textOfClip = NewHandle(scrapSize);
+ HLock(textOfClip);
+
+ STRNCPY(*textOfClip, str, scrapSize);
+#ifdef USE_CARBONIZED
+ GetCurrentScrap (&scrap);
+ PutScrapFlavor(scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone,
+ scrapSize, *textOfClip);
+#else
+ PutScrap(scrapSize, 'TEXT', *textOfClip);
+#endif
+ HUnlock(textOfClip);
+ DisposeHandle(textOfClip);
+ }
+
+ vim_free(str);
+}
+
+ void
+gui_mch_set_text_area_pos(x, y, w, h)
+ int x;
+ int y;
+ int w;
+ int h;
+{
+ Rect VimBound;
+
+/* HideWindow (gui.VimWindow); */
+#ifdef USE_CARBONIZED
+ GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
+#else
+ VimBound = gui.VimWindow->portRect;
+#endif
+
+ if (gui.which_scrollbars[SBAR_LEFT])
+ {
+ VimBound.left = -gui.scrollbar_width + 1;
+ }
+ else
+ {
+ VimBound.left = 0;
+ }
+
+#ifdef USE_CARBONIZED
+ SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
+#endif
+
+ ShowWindow (gui.VimWindow);
+}
+
+/*
+ * Menu stuff.
+ */
+
+ void
+gui_mch_enable_menu(flag)
+ int flag;
+{
+ /*
+ * Menu is always active in itself
+ * (maybe we should only disable a vim menu
+ * and keep standard menu)
+ *
+ */
+}
+
+ void
+gui_mch_set_menu_pos(x, y, w, h)
+ int x;
+ int y;
+ int w;
+ int h;
+{
+ /*
+ * The menu is always at the top of the screen
+ * Maybe a futur version will permit a menu in the window
+ *
+ */
+}
+
+/*
+ * Add a sub menu to the menu bar.
+ */
+ void
+gui_mch_add_menu(menu, idx)
+ vimmenu_T *menu;
+ int idx;
+{
+ /*
+ * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
+ * TODO: use menu->mnemonic and menu->actext
+ * TODO: Try to reuse menu id
+ * Carbon Help suggest to use only id between 1 and 235
+ */
+ static long next_avail_id = 128;
+ long menu_after_me = 0; /* Default to the end */
+ char_u *name;
+ short index;
+ vimmenu_T *parent = menu->parent;
+ vimmenu_T *brother = menu->next;
+
+ /* Cannot add a menu if ... */
+ if ((parent != NULL && parent->submenu_id == 0))
+ return;
+
+ /* menu ID greater than 1024 are reserved for ??? */
+ if (next_avail_id == 1024)
+ return;
+
+ /* My brother could be the PopUp, find my real brother */
+ while ((brother != NULL) && (!menu_is_menubar(brother->name)))
+ brother = brother->next;
+
+ /* Find where to insert the menu (for MenuBar) */
+ if ((parent == NULL) && (brother != NULL))
+ menu_after_me = brother->submenu_id;
+
+ /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
+ if (!menu_is_menubar(menu->name))
+ menu_after_me = hierMenu;
+
+ /* Convert the name */
+ name = C2Pascal_save(menu->dname);
+ if (name == NULL)
+ return;
+
+ /* Create the menu unless it's the help menu */
+#ifdef USE_HELPMENU
+ if (STRNCMP(name, "\4Help", 5) == 0)
+ {
+ menu->submenu_id = kHMHelpMenuID;
+ menu->submenu_handle = gui.MacOSHelpMenu;
+ }
+ else
+#endif
+ {
+ /* Carbon suggest use of
+ * OSStatus CreateNewMenu ( MenuID, MenuAttributes, MenuRef *);
+ * OSStatus SetMenuTitle ( MenuRef, ConstStr255Param title );
+ */
+ menu->submenu_id = next_avail_id;
+ menu->submenu_handle = NewMenu (menu->submenu_id, name);
+ next_avail_id++;
+ }
+
+ if (parent == NULL)
+ {
+ /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
+
+ /* TODO: Verify if we could only Insert Menu if really part of the
+ * menubar The Inserted menu are scanned or the Command-key combos
+ */
+
+ /* Insert the menu unless it's the Help menu */
+#ifdef USE_HELPMENU
+ if (menu->submenu_id != kHMHelpMenuID)
+#endif
+ InsertMenu (menu->submenu_handle, menu_after_me); /* insert before */
+#if 1
+ /* Vim should normally update it. TODO: verify */
+ DrawMenuBar();
+#endif
+ }
+ else
+ {
+ /* Adding as a submenu */
+
+ index = gui_mac_get_menu_item_index (menu);
+
+ /* Call InsertMenuItem followed by SetMenuItemText
+ * to avoid special character recognition by InsertMenuItem
+ */
+ InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
+ SetMenuItemText(parent->submenu_handle, idx+1, name);
+ SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
+ SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
+ InsertMenu(menu->submenu_handle, hierMenu);
+ }
+
+ vim_free (name);
+
+#if 0
+ /* Done by Vim later on */
+ DrawMenuBar();
+#endif
+}
+
+/*
+ * Add a menu item to a menu
+ */
+ void
+gui_mch_add_menu_item(menu, idx)
+ vimmenu_T *menu;
+ int idx;
+{
+ char_u *name;
+ vimmenu_T *parent = menu->parent;
+ int menu_inserted;
+
+ /* Cannot add item, if the menu have not been created */
+ if (parent->submenu_id == 0)
+ return;
+
+ /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
+ for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
+
+ /* Convert the name */
+ name = C2Pascal_save(menu->dname);
+
+ /* Where are just a menu item, so no handle, no id */
+ menu->submenu_id = 0;
+ menu->submenu_handle = NULL;
+
+#ifdef USE_HELPMENU
+ /* The index in the help menu are offseted */
+ if (parent->submenu_id == kHMHelpMenuID)
+ idx += gui.MacOSHelpItems;
+#endif
+
+ menu_inserted = 0;
+ if (menu->actext)
+ {
+ /* If the accelerator text for the menu item looks like it describes
+ * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
+ * item's command equivalent.
+ */
+ int key = 0;
+ int modifiers = 0;
+ char_u *p_actext;
+
+ p_actext = menu->actext;
+ key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
+ if (*p_actext != 0)
+ key = 0; /* error: trailing text */
+ /* find_special_key() returns a keycode with as many of the
+ * specified modifiers as appropriate already applied (e.g., for
+ * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
+ * as the only modifier). Since we want to display all of the
+ * modifiers, we need to convert the keycode back to a printable
+ * character plus modifiers.
+ * TODO: Write an alternative find_special_key() that doesn't
+ * apply modifiers.
+ */
+ if (key > 0 && key < 32)
+ {
+ /* Convert a control key to an uppercase letter. Note that
+ * by this point it is no longer possible to distinguish
+ * between, e.g., Ctrl-S and Ctrl-Shift-S.
+ */
+ modifiers |= MOD_MASK_CTRL;
+ key += '@';
+ }
+ /* If the keycode is an uppercase letter, set the Shift modifier.
+ * If it is a lowercase letter, don't set the modifier, but convert
+ * the letter to uppercase for display in the menu.
+ */
+ else if (key >= 'A' && key <= 'Z')
+ modifiers |= MOD_MASK_SHIFT;
+ else if (key >= 'a' && key <= 'z')
+ key += 'A' - 'a';
+ /* Note: keycodes below 0x22 are reserved by Apple. */
+ if (key >= 0x22 && vim_isprintc_strict(key))
+ {
+ int valid = 1;
+ char_u mac_mods = kMenuNoModifiers;
+ /* Convert Vim modifier codes to Menu Manager equivalents. */
+ if (modifiers & MOD_MASK_SHIFT)
+ mac_mods |= kMenuShiftModifier;
+ if (modifiers & MOD_MASK_CTRL)
+ mac_mods |= kMenuControlModifier;
+ if (!(modifiers & MOD_MASK_CMD))
+ mac_mods |= kMenuNoCommandModifier;
+ if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
+ valid = 0; /* TODO: will Alt someday map to Option? */
+ if (valid)
+ {
+ char_u item_txt[10];
+ /* Insert the menu item after idx, with its command key. */
+ item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
+ item_txt[3] = key;
+ InsertMenuItem(parent->submenu_handle, item_txt, idx);
+ /* Set the modifier keys. */
+ SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
+ menu_inserted = 1;
+ }
+ }
+ }
+ /* Call InsertMenuItem followed by SetMenuItemText
+ * to avoid special character recognition by InsertMenuItem
+ */
+ if (!menu_inserted)
+ InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
+ /* Set the menu item name. */
+ SetMenuItemText(parent->submenu_handle, idx+1, name);
+
+#if 0
+ /* Called by Vim */
+ DrawMenuBar();
+#endif
+
+ /* TODO: Can name be freed? */
+ vim_free(name);
+}
+
+ void
+gui_mch_toggle_tearoffs(enable)
+ int enable;
+{
+ /* no tearoff menus */
+}
+
+/*
+ * Destroy the machine specific menu widget.
+ */
+ void
+gui_mch_destroy_menu(menu)
+ vimmenu_T *menu;
+{
+ short index = gui_mac_get_menu_item_index (menu);
+
+ if (index > 0)
+ {
+ if (menu->parent)
+ {
+#ifdef USE_HELPMENU
+ if (menu->parent->submenu_handle != nil) /*gui.MacOSHelpMenu)*/
+#endif
+ {
+ /* For now just don't delete help menu items. (Huh? Dany) */
+ DeleteMenuItem (menu->parent->submenu_handle, index);
+
+ /* Delete the Menu if it was a hierarchical Menu */
+ if (menu->submenu_id != 0)
+ {
+ DeleteMenu (menu->submenu_id);
+ DisposeMenu (menu->submenu_handle);
+ }
+ }
+#ifdef USE_HELPMENU
+# ifdef DEBUG_MAC_MENU
+ else
+ {
+ printf ("gmdm 1\n");
+ }
+# endif
+#endif
+ }
+#ifdef DEBUG_MAC_MENU
+ else
+ {
+ printf ("gmdm 2\n");
+ }
+#endif
+ }
+ else
+ {
+ /* Do not delete the Help Menu */
+#ifdef USE_HELPMENU
+ if (menu->submenu_id != kHMHelpMenuID)
+#endif
+ {
+ DeleteMenu (menu->submenu_id);
+ DisposeMenu (menu->submenu_handle);
+ }
+ }
+ /* Shouldn't this be already done by Vim. TODO: Check */
+ DrawMenuBar();
+}
+
+/*
+ * Make a menu either grey or not grey.
+ */
+ void
+gui_mch_menu_grey(menu, grey)
+ vimmenu_T *menu;
+ int grey;
+{
+ /* TODO: Check if menu really exists */
+ short index = gui_mac_get_menu_item_index (menu);
+/*
+ index = menu->index;
+*/
+ if (grey)
+ {
+ if (menu->children)
+ DisableMenuItem(menu->submenu_handle, index);
+ if (menu->parent)
+ if (menu->parent->submenu_handle)
+ DisableMenuItem(menu->parent->submenu_handle, index);
+ }
+ else
+ {
+ if (menu->children)
+ EnableMenuItem(menu->submenu_handle, index);
+ if (menu->parent)
+ if (menu->parent->submenu_handle)
+ EnableMenuItem(menu->parent->submenu_handle, index);
+ }
+}
+
+/*
+ * Make menu item hidden or not hidden
+ */
+ void
+gui_mch_menu_hidden(menu, hidden)
+ vimmenu_T *menu;
+ int hidden;
+{
+ /* There's no hidden mode on MacOS */
+ gui_mch_menu_grey (menu, hidden);
+}
+
+
+/*
+ * This is called after setting all the menus to grey/hidden or not.
+ */
+ void
+gui_mch_draw_menubar()
+{
+ DrawMenuBar();
+}
+
+
+/*
+ * Scrollbar stuff.
+ */
+
+ void
+gui_mch_enable_scrollbar(sb, flag)
+ scrollbar_T *sb;
+ int flag;
+{
+ if (flag)
+ ShowControl(sb->id);
+ else
+ HideControl(sb->id);
+
+#ifdef DEBUG_MAC_SB
+ printf ("enb_sb (%x) %x\n",sb->id, flag);
+#endif
+}
+
+ void
+gui_mch_set_scrollbar_thumb(sb, val, size, max)
+ scrollbar_T *sb;
+ long val;
+ long size;
+ long max;
+{
+ SetControl32BitMaximum (sb->id, max);
+ SetControl32BitMinimum (sb->id, 0);
+ SetControl32BitValue (sb->id, val);
+#ifdef DEBUG_MAC_SB
+ printf ("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
+#endif
+}
+
+ void
+gui_mch_set_scrollbar_pos(sb, x, y, w, h)
+ scrollbar_T *sb;
+ int x;
+ int y;
+ int w;
+ int h;
+{
+ gui_mch_set_bg_color(gui.back_pixel);
+/* if (gui.which_scrollbars[SBAR_LEFT])
+ {
+ MoveControl (sb->id, x-16, y);
+ SizeControl (sb->id, w + 1, h);
+ }
+ else
+ {
+ MoveControl (sb->id, x, y);
+ SizeControl (sb->id, w + 1, h);
+ }*/
+ if (sb == &gui.bottom_sbar)
+ h += 1;
+ else
+ w += 1;
+
+ if (gui.which_scrollbars[SBAR_LEFT])
+ x -= 15;
+
+ MoveControl (sb->id, x, y);
+ SizeControl (sb->id, w, h);
+#ifdef DEBUG_MAC_SB
+ printf ("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
+#endif
+}
+
+ void
+gui_mch_create_scrollbar(sb, orient)
+ scrollbar_T *sb;
+ int orient; /* SBAR_VERT or SBAR_HORIZ */
+{
+ Rect bounds;
+
+ bounds.top = -16;
+ bounds.bottom = -10;
+ bounds.right = -10;
+ bounds.left = -16;
+
+ sb->id = NewControl (gui.VimWindow,
+ &bounds,
+ "\pScrollBar",
+ TRUE,
+ 0, /* current*/
+ 0, /* top */
+ 0, /* bottom */
+#ifdef USE_CARBONIZED
+ kControlScrollBarLiveProc,
+#else
+ scrollBarProc,
+#endif
+ (long) sb->ident);
+#ifdef DEBUG_MAC_SB
+ printf ("create_sb (%x) %x\n",sb->id, orient);
+#endif
+}
+
+ void
+gui_mch_destroy_scrollbar(sb)
+ scrollbar_T *sb;
+{
+ gui_mch_set_bg_color(gui.back_pixel);
+ DisposeControl (sb->id);
+#ifdef DEBUG_MAC_SB
+ printf ("dest_sb (%x) \n",sb->id);
+#endif
+}
+
+
+/*
+ * Cursor blink functions.
+ *
+ * This is a simple state machine:
+ * BLINK_NONE not blinking at all
+ * BLINK_OFF blinking, cursor is not shown
+ * BLINK_ON blinking, cursor is shown
+ */
+ void
+gui_mch_set_blinking(long wait, long on, long off)
+{
+ /* TODO: TODO: TODO: TODO: */
+/* blink_waittime = wait;
+ blink_ontime = on;
+ blink_offtime = off;*/
+}
+
+/*
+ * Stop the cursor blinking. Show the cursor if it wasn't shown.
+ */
+ void
+gui_mch_stop_blink()
+{
+ gui_update_cursor(TRUE, FALSE);
+ /* TODO: TODO: TODO: TODO: */
+/* gui_w32_rm_blink_timer();
+ if (blink_state == BLINK_OFF)
+ gui_update_cursor(TRUE, FALSE);
+ blink_state = BLINK_NONE;*/
+}
+
+/*
+ * Start the cursor blinking. If it was already blinking, this restarts the
+ * waiting time and shows the cursor.
+ */
+ void
+gui_mch_start_blink()
+{
+ gui_update_cursor(TRUE, FALSE);
+ /* TODO: TODO: TODO: TODO: */
+/* gui_w32_rm_blink_timer(); */
+
+ /* Only switch blinking on if none of the times is zero */
+/* if (blink_waittime && blink_ontime && blink_offtime)
+ {
+ blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
+ (TIMERPROC)_OnBlinkTimer);
+ blink_state = BLINK_ON;
+ gui_update_cursor(TRUE, FALSE);
+ }*/
+}
+
+/*
+ * Return the RGB value of a pixel as long.
+ */
+ long_u
+gui_mch_get_rgb(guicolor_T pixel)
+{
+ return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
+}
+
+
+
+#ifdef FEAT_BROWSE
+/*
+ * Pop open a file browser and return the file selected, in allocated memory,
+ * or NULL if Cancel is hit.
+ * saving - TRUE if the file will be saved to, FALSE if it will be opened.
+ * title - Title message for the file browser dialog.
+ * dflt - Default name of file.
+ * ext - Default extension to be added to files without extensions.
+ * initdir - directory in which to open the browser (NULL = current dir)
+ * filter - Filter for matched files to choose from.
+ * Has a format like this:
+ * "C Files (*.c)\0*.c\0"
+ * "All Files\0*.*\0\0"
+ * If these two strings were concatenated, then a choice of two file
+ * filters will be selectable to the user. Then only matching files will
+ * be shown in the browser. If NULL, the default allows all files.
+ *
+ * *NOTE* - the filter string must be terminated with TWO nulls.
+ */
+ char_u *
+gui_mch_browse(
+ int saving,
+ char_u *title,
+ char_u *dflt,
+ char_u *ext,
+ char_u *initdir,
+ char_u *filter)
+{
+#if defined (USE_NAVIGATION_SERVICE) || defined (USE_CARBONIZED)
+ /* TODO: Add Ammon's safety checl (Dany) */
+ NavReplyRecord reply;
+ char_u *fname = NULL;
+ char_u **fnames = NULL;
+ long numFiles;
+ NavDialogOptions navOptions;
+ OSErr error;
+
+ /* Get Navigation Service Defaults value */
+ NavGetDefaultDialogOptions (&navOptions);
+
+
+ /* TODO: If we get a :browse args, set the Multiple bit. */
+ navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
+ | kNavDontAutoTranslate
+ | kNavDontAddTranslateItems
+ /* | kNavAllowMultipleFiles */
+ | kNavAllowStationery;
+
+ (void) C2PascalString (title, &navOptions.message);
+ (void) C2PascalString (dflt, &navOptions.savedFileName);
+ /* Could set clientName?
+ * windowTitle? (there's no title bar?)
+ */
+
+ if (saving)
+ {
+ /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
+ NavPutFile (NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
+ if (!reply.validRecord)
+ return NULL;
+ }
+ else
+ {
+ /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
+ NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
+ if (!reply.validRecord)
+ return NULL;
+ }
+
+ fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
+
+ NavDisposeReply (&reply);
+
+ if (fnames)
+ {
+ fname = fnames[0];
+ vim_free(fnames);
+ }
+
+ /* TODO: Shorten the file name if possible */
+ return fname;
+#else
+ SFTypeList fileTypes;
+ StandardFileReply reply;
+ Str255 Prompt;
+ Str255 DefaultName;
+ Str255 Directory;
+
+ /* TODO: split dflt in path and filename */
+
+ (void) C2PascalString (title, &Prompt);
+ (void) C2PascalString (dflt, &DefaultName);
+ (void) C2PascalString (initdir, &Directory);
+
+ if (saving)
+ {
+ /* Use a custon filter instead of nil FAQ 9-4 */
+ StandardPutFile (Prompt, DefaultName, &reply);
+ if (!reply.sfGood)
+ return NULL;
+ }
+ else
+ {
+ StandardGetFile (nil, -1, fileTypes, &reply);
+ if (!reply.sfGood)
+ return NULL;
+ }
+
+ /* Work fine but append a : for new file */
+ return (FullPathFromFSSpec_save (reply.sfFile));
+
+ /* Shorten the file name if possible */
+/* mch_dirname(IObuff, IOSIZE);
+ p = shorten_fname(fileBuf, IObuff);
+ if (p == NULL)
+ p = fileBuf;
+ return vim_strsave(p);
+*/
+#endif
+}
+#endif /* FEAT_BROWSE */
+
+#ifdef FEAT_GUI_DIALOG
+/*
+ * Stuff for dialogues
+ */
+
+/*
+ * Create a dialogue dynamically from the parameter strings.
+ * type = type of dialogue (question, alert, etc.)
+ * title = dialogue title. may be NULL for default title.
+ * message = text to display. Dialogue sizes to accommodate it.
+ * buttons = '\n' separated list of button captions, default first.
+ * dfltbutton = number of default button.
+ *
+ * This routine returns 1 if the first button is pressed,
+ * 2 for the second, etc.
+ *
+ * 0 indicates Esc was pressed.
+ * -1 for unexpected error
+ *
+ * If stubbing out this fn, return 1.
+ */
+
+typedef struct
+{
+ short idx;
+ short width; /* Size of the text in pixel */
+ Rect box;
+} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
+
+#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
+
+ static void
+macMoveDialogItem(
+ DialogRef theDialog,
+ short itemNumber,
+ short X,
+ short Y,
+ Rect *inBox)
+{
+#if 0 /* USE_CARBONIZED */
+ /* Untested */
+ MoveDialogItem (theDialog, itemNumber, X, Y);
+ if (inBox != nil)
+ GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, inBox);
+#else
+ short itemType;
+ Handle itemHandle;
+ Rect localBox;
+ Rect *itemBox = &localBox;
+
+ if (inBox != nil)
+ itemBox = inBox;
+
+ GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, itemBox);
+ OffsetRect (itemBox, -itemBox->left, -itemBox->top);
+ OffsetRect (itemBox, X, Y);
+ /* To move a control (like a button) we need to call both
+ * MoveControl and SetDialogItem. FAQ 6-18 */
+ if (1) /*(itemType & kControlDialogItem) */
+ MoveControl ((ControlRef) itemHandle, X, Y);
+ SetDialogItem (theDialog, itemNumber, itemType, itemHandle, itemBox);
+#endif
+}
+
+ static void
+macSizeDialogItem(
+ DialogRef theDialog,
+ short itemNumber,
+ short width,
+ short height)
+{
+ short itemType;
+ Handle itemHandle;
+ Rect itemBox;
+
+ GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
+
+ /* When width or height is zero do not change it */
+ if (width == 0)
+ width = itemBox.right - itemBox.left;
+ if (height == 0)
+ height = itemBox.bottom - itemBox.top;
+
+#if 0 /* USE_CARBONIZED */
+ SizeDialogItem (theDialog, itemNumber, width, height); /* Untested */
+#else
+ /* Resize the bounding box */
+ itemBox.right = itemBox.left + width;
+ itemBox.bottom = itemBox.top + height;
+
+ /* To resize a control (like a button) we need to call both
+ * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
+ if (itemType & kControlDialogItem)
+ SizeControl ((ControlRef) itemHandle, width, height);
+
+ /* Configure back the item */
+ SetDialogItem (theDialog, itemNumber, itemType, itemHandle, &itemBox);
+#endif
+}
+
+ static void
+macSetDialogItemText(
+ DialogRef theDialog,
+ short itemNumber,
+ Str255 itemName)
+{
+ short itemType;
+ Handle itemHandle;
+ Rect itemBox;
+
+ GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
+
+ if (itemType & kControlDialogItem)
+ SetControlTitle ((ControlRef) itemHandle, itemName);
+ else
+ SetDialogItemText (itemHandle, itemName);
+}
+
+ int
+gui_mch_dialog(
+ int type,
+ char_u *title,
+ char_u *message,
+ char_u *buttons,
+ int dfltbutton,
+ char_u *textfield)
+{
+ Handle buttonDITL;
+ Handle iconDITL;
+ Handle inputDITL;
+ Handle messageDITL;
+ Handle itemHandle;
+ Handle iconHandle;
+ DialogPtr theDialog;
+ char_u len;
+ char_u PascalTitle[256]; /* place holder for the title */
+ char_u name[256];
+ GrafPtr oldPort;
+ short itemHit;
+ char_u *buttonChar;
+ Rect box;
+ short button;
+ short lastButton;
+ short itemType;
+ short useIcon;
+ short width;
+ short totalButtonWidth = 0; /* the width of all button together incuding spacing */
+ short widestButton = 0;
+ short dfltButtonEdge = 20; /* gut feeling */
+ short dfltElementSpacing = 13; /* from IM:V.2-29 */
+ short dfltIconSideSpace = 23; /* from IM:V.2-29 */
+ short maximumWidth = 400; /* gut feeling */
+ short maxButtonWidth = 175; /* gut feeling */
+
+ short vertical;
+ short dialogHeight;
+ short messageLines = 3;
+ FontInfo textFontInfo;
+
+ vgmDlgItm iconItm;
+ vgmDlgItm messageItm;
+ vgmDlgItm inputItm;
+ vgmDlgItm buttonItm;
+
+ WindowRef theWindow;
+
+ /* Check 'v' flag in 'guioptions': vertical button placement. */
+ vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
+
+ /* Create a new Dialog Box from template. */
+ theDialog = GetNewDialog (129, nil, (WindowRef) -1);
+
+ /* Get the WindowRef */
+ theWindow = GetDialogWindow(theDialog);
+
+ /* Hide the window.
+ * 1. to avoid seeing slow drawing
+ * 2. to prevent a problem seen while moving dialog item
+ * within a visible window. (non-Carbon MacOS 9)
+ * Could be avoided by changing the resource.
+ */
+ HideWindow (theWindow);
+
+ /* Change the graphical port to the dialog,
+ * so we can measure the text with the proper font */
+ GetPort (&oldPort);
+#ifdef USE_CARBONIZED
+ SetPortDialogPort (theDialog);
+#else
+ SetPort (theDialog);
+#endif
+
+ /* Get the info about the default text,
+ * used to calculate the height of the message
+ * and of the text field */
+ GetFontInfo(&textFontInfo);
+
+ /* Set the dialog title */
+ if (title != NULL)
+ {
+ (void) C2PascalString (title, &PascalTitle);
+ SetWTitle (theWindow, PascalTitle);
+ }
+
+ /* Creates the buttons and add them to the Dialog Box. */
+ buttonDITL = GetResource ('DITL', 130);
+ buttonChar = buttons;
+ button = 0;
+
+ for (;*buttonChar != 0;)
+ {
+ /* Get the name of the button */
+ button++;
+ len = 0;
+ for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
+ {
+ if (*buttonChar != DLG_HOTKEY_CHAR)
+ name[++len] = *buttonChar;
+ }
+ if (*buttonChar != 0)
+ buttonChar++;
+ name[0] = len;
+
+ /* Add the button */
+ AppendDITL (theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
+
+ /* Change the button's name */
+ macSetDialogItemText (theDialog, button, name);
+
+ /* Resize the button to fit its name */
+ width = StringWidth (name) + 2 * dfltButtonEdge;
+ /* Limite the size of any button to an acceptable value. */
+ /* TODO: Should be based on the message width */
+ if (width > maxButtonWidth)
+ width = maxButtonWidth;
+ macSizeDialogItem (theDialog, button, width, 0);
+
+ totalButtonWidth += width;
+
+ if (width > widestButton)
+ widestButton = width;
+ }
+ ReleaseResource (buttonDITL);
+ lastButton = button;
+
+ /* Add the icon to the Dialog Box. */
+ iconItm.idx = lastButton + 1;
+ iconDITL = GetResource ('DITL', 131);
+ switch (type)
+ {
+ case VIM_GENERIC: useIcon = kNoteIcon;
+ case VIM_ERROR: useIcon = kStopIcon;
+ case VIM_WARNING: useIcon = kCautionIcon;
+ case VIM_INFO: useIcon = kNoteIcon;
+ case VIM_QUESTION: useIcon = kNoteIcon;
+ default: useIcon = kStopIcon;
+ };
+ AppendDITL (theDialog, iconDITL, overlayDITL);
+ ReleaseResource (iconDITL);
+ GetDialogItem (theDialog, iconItm.idx, &itemType, &itemHandle, &box);
+ /* TODO: Should the item be freed? */
+ iconHandle = GetIcon (useIcon);
+ SetDialogItem (theDialog, iconItm.idx, itemType, iconHandle, &box);
+
+ /* Add the message to the Dialog box. */
+ messageItm.idx = lastButton + 2;
+ messageDITL = GetResource ('DITL', 132);
+ AppendDITL (theDialog, messageDITL, overlayDITL);
+ ReleaseResource (messageDITL);
+ GetDialogItem (theDialog, messageItm.idx, &itemType, &itemHandle, &box);
+ (void) C2PascalString (message, &name);
+ SetDialogItemText (itemHandle, name);
+ messageItm.width = StringWidth (name);
+
+ /* Add the input box if needed */
+ if (textfield != NULL)
+ {
+ /* Cheat for now reuse the message and convet to text edit */
+ inputItm.idx = lastButton + 3;
+ inputDITL = GetResource ('DITL', 132);
+ AppendDITL (theDialog, inputDITL, overlayDITL);
+ ReleaseResource (inputDITL);
+ GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &box);
+/* SetDialogItem (theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
+ (void) C2PascalString (textfield, &name);
+ SetDialogItemText (itemHandle, name);
+ inputItm.width = StringWidth (name);
+ }
+
+ /* Set the <ENTER> and <ESC> button. */
+ SetDialogDefaultItem (theDialog, dfltbutton);
+ SetDialogCancelItem (theDialog, 0);
+
+ /* Reposition element */
+
+ /* Check if we need to force vertical */
+ if (totalButtonWidth > maximumWidth)
+ vertical = TRUE;
+
+ /* Place icon */
+ macMoveDialogItem (theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
+ iconItm.box.right = box.right;
+ iconItm.box.bottom = box.bottom;
+
+ /* Place Message */
+ messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
+ macSizeDialogItem (theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
+ macMoveDialogItem (theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
+
+ /* Place Input */
+ if (textfield != NULL)
+ {
+ inputItm.box.left = messageItm.box.left;
+ inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
+ macSizeDialogItem (theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
+ macMoveDialogItem (theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
+ /* Convert the static text into a text edit.
+ * For some reason this change need to be done last (Dany) */
+ GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
+ SetDialogItem (theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
+ SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
+ }
+
+ /* Place Button */
+ if (textfield != NULL)
+ {
+ buttonItm.box.left = inputItm.box.left;
+ buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
+ }
+ else
+ {
+ buttonItm.box.left = messageItm.box.left;
+ buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
+ }
+
+ for (button=1; button <= lastButton; button++)
+ {
+
+ macMoveDialogItem (theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
+ /* With vertical, it's better to have all button the same lenght */
+ if (vertical)
+ {
+ macSizeDialogItem (theDialog, button, widestButton, 0);
+ GetDialogItem (theDialog, button, &itemType, &itemHandle, &box);
+ }
+ /* Calculate position of next button */
+ if (vertical)
+ buttonItm.box.top = box.bottom + dfltElementSpacing;
+ else
+ buttonItm.box.left = box.right + dfltElementSpacing;
+ }
+
+ /* Resize the dialog box */
+ dialogHeight = box.bottom + dfltElementSpacing;
+ SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
+
+#ifdef USE_CARBONIZED
+ /* Magic resize */
+ AutoSizeDialog (theDialog);
+ /* Need a horizontal resize anyway so not that useful */
+#endif
+
+ /* Display it */
+ ShowWindow(theWindow);
+/* BringToFront(theWindow); */
+ SelectWindow(theWindow);
+
+/* DrawDialog (theDialog); */
+#if 0
+ GetPort (&oldPort);
+#ifdef USE_CARBONIZED
+ SetPortDialogPort (theDialog);
+#else
+ SetPort (theDialog);
+#endif
+#endif
+
+ /* Hang until one of the button is hit */
+ do
+ {
+ ModalDialog (nil, &itemHit);
+ } while ((itemHit < 1) || (itemHit > lastButton));
+
+ /* Copy back the text entered by the user into the param */
+ if (textfield != NULL)
+ {
+ GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &box);
+ GetDialogItemText (itemHandle, (char_u *) &name);
+#if IOSIZE < 256
+ /* Truncate the name to IOSIZE if needed */
+ if (name[0] > IOSIZE)
+ name[0] = IOSIZE - 1;
+#endif
+ STRNCPY(textfield, &name[1], name[0]);
+ textfield[name[0]] = NUL;
+ }
+
+ /* Restore the original graphical port */
+ SetPort (oldPort);
+
+ /* Get ride of th edialog (free memory) */
+ DisposeDialog (theDialog);
+
+ return itemHit;
+/*
+ * Usefull thing which could be used
+ * SetDialogTimeout(): Auto click a button after timeout
+ * SetDialogTracksCursor() : Get the I-beam cursor over input box
+ * MoveDialogItem(): Probably better than SetDialogItem
+ * SizeDialogItem(): (but is it Carbon Only?)
+ * AutoSizeDialog(): Magic resize of dialog based on text lenght
+ */
+}
+#endif /* FEAT_DIALOG_GUI */
+
+/*
+ * Display the saved error message(s).
+ */
+#ifdef USE_MCH_ERRMSG
+ void
+display_errors()
+{
+ char *p;
+ char_u pError[256];
+
+ if (error_ga.ga_data != NULL)
+ {
+ /* avoid putting up a message box with blanks only */
+ for (p = (char *)error_ga.ga_data; *p; ++p)
+ if (!isspace(*p))
+ {
+ if (STRLEN(p) > 255)
+ pError[0] = 255;
+ else
+ pError[0] = STRLEN(p);
+
+ STRNCPY(&pError[1], p, pError[0]);
+ ParamText (pError, nil, nil, nil);
+ Alert (128, nil);
+ break;
+ /* TODO: handled message longer than 256 chars
+ * use auto-sizeable alert
+ * or dialog with scrollbars (TextEdit zone)
+ */
+ }
+ ga_clear(&error_ga);
+ }
+}
+#endif
+
+/*
+ * Get current y mouse coordinate in text window.
+ * Return -1 when unknown.
+ */
+ int
+gui_mch_get_mouse_x()
+{
+ Point where;
+
+ GetMouse(&where);
+
+ return (where.h);
+}
+
+ int
+gui_mch_get_mouse_y()
+{
+ Point where;
+
+ GetMouse(&where);
+
+ return (where.v);
+}
+
+ void
+gui_mch_setmouse(x, y)
+ int x;
+ int y;
+{
+ /* TODO */
+#if 0
+ /* From FAQ 3-11 */
+
+ CursorDevicePtr myMouse;
+ Point where;
+
+ if ( NGetTrapAddress (_CursorDeviceDispatch, ToolTrap)
+ != NGetTrapAddress (_Unimplemented, ToolTrap) )
+ {
+ /* New way */
+
+ /*
+ * Get first devoice with one button.
+ * This will probably be the standad mouse
+ * startat head of cursor dev list
+ *
+ */
+
+ myMouse = nil;
+
+ do
+ {
+ /* Get the next cursor device */
+ CursorDeviceNextDevice(&myMouse);
+ }
+ while ( (myMouse != nil) && (myMouse->cntButtons != 1) );
+
+ CursorDeviceMoveTo (myMouse, x, y);
+ }
+ else
+ {
+ /* Old way */
+ where.h = x;
+ where.v = y;
+
+ *(Point *)RawMouse = where;
+ *(Point *)MTemp = where;
+ *(Ptr) CrsrNew = 0xFFFF;
+ }
+#endif
+}
+
+ void
+gui_mch_show_popupmenu(menu)
+ vimmenu_T *menu;
+{
+#ifdef USE_CTRLCLICKMENU
+/*
+ * Clone PopUp to use menu
+ * Create a object descriptor for the current selection
+ * Call the procedure
+ */
+
+ MenuHandle CntxMenu;
+ Point where;
+ OSStatus status;
+ UInt32 CntxType;
+ SInt16 CntxMenuID;
+ UInt16 CntxMenuItem;
+ Str255 HelpName = "";
+ GrafPtr savePort;
+
+ /* Save Current Port: On MacOS X we seem to lose the port */
+ GetPort (&savePort); /*OSX*/
+
+ GetMouse (&where);
+ LocalToGlobal (&where); /*OSX*/
+ CntxMenu = menu->submenu_handle;
+
+ /* TODO: Get the text selection from Vim */
+
+ /* Call to Handle Popup */
+ status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemNoHelp, HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
+
+ if (status == noErr)
+ {
+ if (CntxType == kCMMenuItemSelected)
+ {
+ /* Handle the menu CntxMenuID, CntxMenuItem */
+ /* The submenu can be handle directly by gui_mac_handle_menu */
+ /* But what about the current menu, is the menu changed by ContextualMenuSelect */
+ gui_mac_handle_menu ((CntxMenuID << 16) + CntxMenuItem);
+ }
+ else if (CntxMenuID == kCMShowHelpSelected)
+ {
+ /* Should come up with the help */
+ }
+ }
+
+ /* Restore original Port */
+ SetPort (savePort); /*OSX*/
+#endif
+}
+
+#if defined(FEAT_CW_EDITOR) || defined(PROTO)
+/* TODO: Is it need for MACOS_X? (Dany) */
+ void
+mch_post_buffer_write(buf_T *buf)
+{
+# ifdef USE_SIOUX
+ printf ("Writing Buf...\n");
+# endif
+ GetFSSpecFromPath (buf->b_ffname, &buf->b_FSSpec);
+ Send_KAHL_MOD_AE (buf);
+}
+#endif
+
+#ifdef FEAT_TITLE
+/*
+ * Set the window title and icon.
+ * (The icon is not taken care of).
+ */
+ void
+gui_mch_settitle(title, icon)
+ char_u *title;
+ char_u *icon;
+{
+ /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
+ * that 256. Even better get it to fit nicely in the titlebar.
+ */
+ char_u *pascalTitle;
+
+ if (title == NULL) /* nothing to do */
+ return;
+
+ pascalTitle = C2Pascal_save(title);
+ if (pascalTitle != NULL)
+ {
+ SetWTitle(gui.VimWindow, pascalTitle);
+ vim_free(pascalTitle);
+ }
+}
+#endif
+
+/*
+ * Transfered from os_mac.c for MacOS X using os_unix.c prep work
+ */
+
+ int
+C2PascalString (CString, PascalString)
+ char_u *CString;
+ Str255 *PascalString;
+{
+ char_u *PascalPtr = (char_u *) PascalString;
+ int len;
+ int i;
+
+ PascalPtr[0] = 0;
+ if (CString == NULL)
+ return 0;
+
+ len = STRLEN(CString);
+ if (len > 255)
+ len = 255;
+
+ for (i = 0; i < len; i++)
+ PascalPtr[i+1] = CString[i];
+
+ PascalPtr[0] = len;
+
+ return 0;
+}
+
+ int
+GetFSSpecFromPath (file, fileFSSpec)
+ char_u *file;
+ FSSpec *fileFSSpec;
+{
+ /* From FAQ 8-12 */
+ Str255 filePascal;
+ CInfoPBRec myCPB;
+ OSErr err;
+
+ (void) C2PascalString (file, &filePascal);
+
+ myCPB.dirInfo.ioNamePtr = filePascal;
+ myCPB.dirInfo.ioVRefNum = 0;
+ myCPB.dirInfo.ioFDirIndex = 0;
+ myCPB.dirInfo.ioDrDirID = 0;
+
+ err= PBGetCatInfo (&myCPB, false);
+
+ /* vRefNum, dirID, name */
+ FSMakeFSSpec (0, 0, filePascal, fileFSSpec);
+
+ /* TODO: Use an error code mechanism */
+ return 0;
+}
+
+/*
+ * Convert a FSSpec to a fuill path
+ */
+
+char_u *FullPathFromFSSpec_save (FSSpec file)
+{
+ /*
+ * TODO: Add protection for 256 char max.
+ */
+
+ CInfoPBRec theCPB;
+ char_u fname[256];
+ char_u *filenamePtr = fname;
+ OSErr error;
+ int folder = 1;
+#ifdef USE_UNIXFILENAME
+ SInt16 dfltVol_vRefNum;
+ SInt32 dfltVol_dirID;
+ FSRef refFile;
+ OSStatus status;
+ UInt32 pathSize = 256;
+ char_u pathname[256];
+ char_u *path = pathname;
+#else
+ Str255 directoryName;
+ char_u temporary[255];
+ char_u *temporaryPtr = temporary;
+#endif
+
+#ifdef USE_UNIXFILENAME
+ /* Get the default volume */
+ /* TODO: Remove as this only work if Vim is on the Boot Volume*/
+ error=HGetVol ( NULL, &dfltVol_vRefNum, &dfltVol_dirID );
+
+ if (error)
+ return NULL;
+#endif
+
+ /* Start filling fname with file.name */
+ STRNCPY(filenamePtr, &file.name[1], file.name[0]);
+ filenamePtr[file.name[0]] = 0; /* NULL terminate the string */
+
+ /* Get the info about the file specified in FSSpec */
+ theCPB.dirInfo.ioFDirIndex = 0;
+ theCPB.dirInfo.ioNamePtr = file.name;
+ theCPB.dirInfo.ioVRefNum = file.vRefNum;
+ /*theCPB.hFileInfo.ioDirID = 0;*/
+ theCPB.dirInfo.ioDrDirID = file.parID;
+
+ /* As ioFDirIndex = 0, get the info of ioNamePtr,
+ which is relative to ioVrefNum, ioDirID */
+ error = PBGetCatInfo (&theCPB, false);
+
+ /* If we are called for a new file we expect fnfErr */
+ if ((error) && (error != fnfErr))
+ return NULL;
+
+ /* Check if it's a file or folder */
+ /* default to file if file don't exist */
+ if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
+ folder = 0; /* It's not a folder */
+ else
+ folder = 1;
+
+#ifdef USE_UNIXFILENAME
+ /*
+ * The function used here are available in Carbon, but
+ * do nothing une MacOS 8 and 9
+ */
+ if (error == fnfErr)
+ {
+ /* If the file to be saved does not already exist, it isn't possible
+ to convert its FSSpec into an FSRef. But we can construct an
+ FSSpec for the file's parent folder (since we have its volume and
+ directory IDs), and since that folder does exist, we can convert
+ that FSSpec into an FSRef, convert the FSRef in turn into a path,
+ and, finally, append the filename. */
+ FSSpec dirSpec;
+ FSRef dirRef;
+ Str255 emptyFilename = "\p";
+ error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
+ theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
+ if (error)
+ return NULL;
+
+ error = FSpMakeFSRef(&dirSpec, &dirRef);
+ if (error)
+ return NULL;
+
+ status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
+ if (status)
+ return NULL;
+
+ STRCAT(path, "/");
+ STRCAT(path, filenamePtr);
+ }
+ else
+ {
+ /* If the file to be saved already exists, we can get its full path
+ by converting its FSSpec into an FSRef. */
+ error=FSpMakeFSRef (&file, &refFile);
+ if (error)
+ return NULL;
+
+ status=FSRefMakePath (&refFile, (UInt8 *) path, pathSize);
+ if (status)
+ return NULL;
+ }
+
+ /* Add a slash at the end if needed */
+ if (folder)
+ STRCAT (path, "/");
+
+ return (vim_strsave (path));
+#else
+ /* TODO: Get rid of all USE_UNIXFILENAME below */
+ /* Set ioNamePtr, it's the same area which is always reused. */
+ theCPB.dirInfo.ioNamePtr = directoryName;
+
+ /* Trick for first entry, set ioDrParID to the first value
+ * we want for ioDrDirID*/
+ theCPB.dirInfo.ioDrParID = file.parID;
+ theCPB.dirInfo.ioDrDirID = file.parID;
+
+ if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/ ))
+ do
+ {
+ theCPB.dirInfo.ioFDirIndex = -1;
+ /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
+ theCPB.dirInfo.ioVRefNum = file.vRefNum;
+ /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
+ theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
+
+ /* As ioFDirIndex = -1, get the info of ioDrDirID, */
+ /* *ioNamePtr[0 TO 31] will be updated */
+ error = PBGetCatInfo (&theCPB,false);
+
+ if (error)
+ return NULL;
+
+ /* Put the new directoryName in front of the current fname */
+ STRCPY(temporaryPtr, filenamePtr);
+ STRNCPY(filenamePtr, &directoryName[1], directoryName[0]);
+ filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */
+ STRCAT(filenamePtr, ":");
+ STRCAT(filenamePtr, temporaryPtr);
+ }
+#if 1 /* def USE_UNIXFILENAME */
+ while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
+ /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
+#else
+ while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
+#endif
+
+ /* Get the information about the volume on which the file reside */
+ theCPB.dirInfo.ioFDirIndex = -1;
+ /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
+ theCPB.dirInfo.ioVRefNum = file.vRefNum;
+ /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
+ theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
+
+ /* As ioFDirIndex = -1, get the info of ioDrDirID, */
+ /* *ioNamePtr[0 TO 31] will be updated */
+ error = PBGetCatInfo (&theCPB,false);
+
+ if (error)
+ return NULL;
+
+ /* For MacOS Classic always add the volume name */
+ /* For MacOS X add the volume name preceded by "Volumes" */
+ /* when we are not refering to the boot volume */
+#ifdef USE_UNIXFILENAME
+ if (file.vRefNum != dfltVol_vRefNum)
+#endif
+ {
+ /* Add the volume name */
+ STRCPY(temporaryPtr, filenamePtr);
+ STRNCPY(filenamePtr, &directoryName[1], directoryName[0]);
+ filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */
+ STRCAT(filenamePtr, ":");
+ STRCAT(filenamePtr, temporaryPtr);
+
+#ifdef USE_UNIXFILENAME
+ STRCPY(temporaryPtr, filenamePtr);
+ filenamePtr[0] = 0; /* NULL terminate the string */
+ STRCAT(filenamePtr, "Volumes:");
+ STRCAT(filenamePtr, temporaryPtr);
+#endif
+ }
+
+ /* Append final path separator if it's a folder */
+ if (folder)
+ STRCAT (fname, ":");
+
+ /* As we use Unix File Name for MacOS X convert it */
+#ifdef USE_UNIXFILENAME
+ /* Need to insert leading / */
+ /* TODO: get the above code to use directly the / */
+ STRCPY(&temporaryPtr[1], filenamePtr);
+ temporaryPtr[0] = '/';
+ STRCPY(filenamePtr, temporaryPtr);
+ {
+ char *p;
+ for (p = fname; *p; p++)
+ if (*p == ':')
+ *p = '/';
+ }
+#endif
+
+ return (vim_strsave (fname));
+#endif
+}
+
+#if defined(USE_IM_CONTROL) || defined(PROTO)
+/*
+ * Input Method Control functions.
+ */
+
+/*
+ * Notify cursor position to IM.
+ */
+ void
+im_set_position(int row, int col)
+{
+ /* TODO: Implement me! */
+}
+
+/*
+ * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
+ */
+ void
+im_set_active(int active)
+{
+ KeyScript(active ? smKeySysScript : smKeyRoman);
+}
+
+/*
+ * Get IM status. When IM is on, return not 0. Else return 0.
+ */
+ int
+im_get_status()
+{
+ SInt32 script = GetScriptManagerVariable(smKeyScript);
+ return (script != smRoman
+ && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
+}
+#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */