d83a1379a50fc9e66a2d811cadc252f7416a8b42
[platform/upstream/vim.git] / src / gui_mac.c
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved            by Bram Moolenaar
4  *                              GUI/Motif support by Robert Webb
5  *                              Macintosh port by Dany St-Amant
6  *                                            and Axel Kielhorn
7  *                              Port to MPW by Bernhard Pruemmer
8  *                              Initial Carbon port by Ammon Skidmore
9  *
10  * Do ":help uganda"  in Vim to read copying and usage conditions.
11  * Do ":help credits" in Vim to see a list of people who contributed.
12  * See README.txt for an overview of the Vim source code.
13  */
14
15 /*
16  * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x
17  *        - Comments mentioning FAQ refer to the book:
18  *          "Macworld Mac Programming FAQs" from "IDG Books"
19  */
20
21 /*
22  * TODO: Change still to merge from the macvim's iDisk
23  *
24  * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse
25  * uses of MenuItemIndex, changes in gui_mch_set_shellsize,
26  * ScrapManager error handling.
27  * Comments about function remaining to Carbonize.
28  *
29  */
30
31 /* TODO (Jussi)
32  *   * Clipboard does not work (at least some cases)
33  *   * ATSU font rendering has some problems
34  *   * Investigate and remove dead code (there is still lots of that)
35  */
36
37 #include <Devices.h> /* included first to avoid CR problems */
38 #include "vim.h"
39
40 #define USE_CARBONIZED
41 #define USE_AEVENT              /* Enable AEVENT */
42 #undef USE_OFFSETED_WINDOW      /* Debugging feature: start Vim window OFFSETed */
43
44 /* Compile as CodeWarior External Editor */
45 #if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46 # define USE_AEVENT /* Need Apple Event Support */
47 #endif
48
49 /* Vim's Scrap flavor. */
50 #define VIMSCRAPFLAVOR 'VIM!'
51 #ifdef FEAT_MBYTE
52 # define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
53 #else
54 # define SCRAPTEXTFLAVOR kScrapFlavorTypeText
55 #endif
56
57 static EventHandlerUPP mouseWheelHandlerUPP = NULL;
58 SInt32 gMacSystemVersion;
59
60 #ifdef MACOS_CONVERT
61 # define USE_CARBONKEYHANDLER
62
63 static int im_is_active = FALSE;
64 #if 0
65     /* TODO: Implement me! */
66 static int im_start_row = 0;
67 static int im_start_col = 0;
68 #endif
69
70 #define NR_ELEMS(x)     (sizeof(x) / sizeof(x[0]))
71
72 static TSMDocumentID gTSMDocument;
73
74 static void im_on_window_switch(int active);
75 static EventHandlerUPP keyEventHandlerUPP = NULL;
76 static EventHandlerUPP winEventHandlerUPP = NULL;
77
78 static pascal OSStatus gui_mac_handle_window_activate(
79         EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
80
81 static pascal OSStatus gui_mac_handle_text_input(
82         EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
83
84 static pascal OSStatus gui_mac_update_input_area(
85         EventHandlerCallRef nextHandler, EventRef theEvent);
86
87 static pascal OSStatus gui_mac_unicode_key_event(
88         EventHandlerCallRef nextHandler, EventRef theEvent);
89
90 #endif
91
92
93 /* Include some file. TODO: move into os_mac.h */
94 #include <Menus.h>
95 #include <Resources.h>
96 #include <Processes.h>
97 #ifdef USE_AEVENT
98 # include <AppleEvents.h>
99 # include <AERegistry.h>
100 #endif
101 # include <Gestalt.h>
102 #if UNIVERSAL_INTERFACES_VERSION >= 0x0330
103 # include <ControlDefinitions.h>
104 # include <Navigation.h>  /* Navigation only part of ?? */
105 #endif
106
107 /* Help Manager (balloon.h, HM prefixed functions) are not supported
108  * under Carbon (Jussi) */
109 #  if 0
110 /* New Help Interface for Mac, not implemented yet.*/
111 #    include <MacHelp.h>
112 #  endif
113
114 /*
115  * These seem to be rectangle options. Why are they not found in
116  * headers? (Jussi)
117  */
118 #define kNothing 0
119 #define kCreateEmpty 2 /*1*/
120 #define kCreateRect 2
121 #define kDestroy 3
122
123 /*
124  * Dany: Don't like those...
125  */
126 #define topLeft(r)      (((Point*)&(r))[0])
127 #define botRight(r)     (((Point*)&(r))[1])
128
129
130 /* Time of last mouse click, to detect double-click */
131 static long lastMouseTick = 0;
132
133 /* ??? */
134 static RgnHandle cursorRgn;
135 static RgnHandle dragRgn;
136 static Rect dragRect;
137 static short dragRectEnbl;
138 static short dragRectControl;
139
140 /* This variable is set when waiting for an event, which is the only moment
141  * scrollbar dragging can be done directly.  It's not allowed while commands
142  * are executed, because it may move the cursor and that may cause unexpected
143  * problems (e.g., while ":s" is working).
144  */
145 static int allow_scrollbar = FALSE;
146
147 /* Last mouse click caused contextual menu, (to provide proper release) */
148 static short clickIsPopup;
149
150 /* Feedback Action for Scrollbar */
151 ControlActionUPP gScrollAction;
152 ControlActionUPP gScrollDrag;
153
154 /* Keeping track of which scrollbar is being dragged */
155 static ControlHandle dragged_sb = NULL;
156
157 /* Vector of char_u --> control index for hotkeys in dialogs */
158 static short *gDialogHotKeys;
159
160 static struct
161 {
162     FMFontFamily family;
163     FMFontSize size;
164     FMFontStyle style;
165     Boolean isPanelVisible;
166 } gFontPanelInfo = { 0, 0, 0, false };
167
168 #ifdef MACOS_CONVERT
169 # define USE_ATSUI_DRAWING
170 int         p_macatsui_last;
171 ATSUStyle   gFontStyle;
172 # ifdef FEAT_MBYTE
173 ATSUStyle   gWideFontStyle;
174 # endif
175 Boolean     gIsFontFallbackSet;
176 UInt32      useAntialias_cached = 0x0;
177 #endif
178
179 /* Colors Macros */
180 #define RGB(r,g,b)      ((r) << 16) + ((g) << 8) + (b)
181 #define Red(c)          ((c & 0x00FF0000) >> 16)
182 #define Green(c)        ((c & 0x0000FF00) >>  8)
183 #define Blue(c)         ((c & 0x000000FF) >>  0)
184
185 /* Key mapping */
186
187 #define vk_Esc          0x35    /* -> 1B */
188
189 #define vk_F1           0x7A    /* -> 10 */
190 #define vk_F2           0x78  /*0x63*/
191 #define vk_F3           0x63  /*0x76*/
192 #define vk_F4           0x76  /*0x60*/
193 #define vk_F5           0x60  /*0x61*/
194 #define vk_F6           0x61  /*0x62*/
195 #define vk_F7           0x62  /*0x63*/  /*?*/
196 #define vk_F8           0x64
197 #define vk_F9           0x65
198 #define vk_F10          0x6D
199 #define vk_F11          0x67
200 #define vk_F12          0x6F
201 #define vk_F13          0x69
202 #define vk_F14          0x6B
203 #define vk_F15          0x71
204
205 #define vk_Clr          0x47    /* -> 1B (ESC) */
206 #define vk_Enter        0x4C    /* -> 03 */
207
208 #define vk_Space        0x31    /* -> 20 */
209 #define vk_Tab          0x30    /* -> 09 */
210 #define vk_Return       0x24    /* -> 0D */
211 /* This is wrong for OSX, what is it for? */
212 #define vk_Delete       0X08    /* -> 08 BackSpace */
213
214 #define vk_Help         0x72    /* -> 05 */
215 #define vk_Home         0x73    /* -> 01 */
216 #define vk_PageUp       0x74    /* -> 0D */
217 #define vk_FwdDelete    0x75    /* -> 7F */
218 #define vk_End          0x77    /* -> 04 */
219 #define vk_PageDown     0x79    /* -> 0C */
220
221 #define vk_Up           0x7E    /* -> 1E */
222 #define vk_Down         0x7D    /* -> 1F */
223 #define vk_Left         0x7B    /* -> 1C */
224 #define vk_Right        0x7C    /* -> 1D */
225
226 #define vk_Undo         vk_F1
227 #define vk_Cut          vk_F2
228 #define vk_Copy         vk_F3
229 #define vk_Paste        vk_F4
230 #define vk_PrintScreen  vk_F13
231 #define vk_SCrollLock   vk_F14
232 #define vk_Pause        vk_F15
233 #define vk_NumLock      vk_Clr
234 #define vk_Insert       vk_Help
235
236 #define KeySym  char
237
238 static struct
239 {
240     KeySym  key_sym;
241     char_u  vim_code0;
242     char_u  vim_code1;
243 } special_keys[] =
244 {
245     {vk_Up,             'k', 'u'},
246     {vk_Down,           'k', 'd'},
247     {vk_Left,           'k', 'l'},
248     {vk_Right,          'k', 'r'},
249
250     {vk_F1,             'k', '1'},
251     {vk_F2,             'k', '2'},
252     {vk_F3,             'k', '3'},
253     {vk_F4,             'k', '4'},
254     {vk_F5,             'k', '5'},
255     {vk_F6,             'k', '6'},
256     {vk_F7,             'k', '7'},
257     {vk_F8,             'k', '8'},
258     {vk_F9,             'k', '9'},
259     {vk_F10,            'k', ';'},
260
261     {vk_F11,            'F', '1'},
262     {vk_F12,            'F', '2'},
263     {vk_F13,            'F', '3'},
264     {vk_F14,            'F', '4'},
265     {vk_F15,            'F', '5'},
266
267 /*  {XK_Help,           '%', '1'}, */
268 /*  {XK_Undo,           '&', '8'}, */
269 /*  {XK_BackSpace,      'k', 'b'}, */
270 #ifndef MACOS_X
271     {vk_Delete,         'k', 'b'},
272 #endif
273     {vk_Insert,         'k', 'I'},
274     {vk_FwdDelete,      'k', 'D'},
275     {vk_Home,           'k', 'h'},
276     {vk_End,            '@', '7'},
277 /*  {XK_Prior,          'k', 'P'}, */
278 /*  {XK_Next,           'k', 'N'}, */
279 /*  {XK_Print,          '%', '9'}, */
280
281     {vk_PageUp,         'k', 'P'},
282     {vk_PageDown,       'k', 'N'},
283
284     /* End of list marker: */
285     {(KeySym)0,         0, 0}
286 };
287
288 /*
289  * ------------------------------------------------------------
290  * Forward declaration (for those needed)
291  * ------------------------------------------------------------
292  */
293
294 #ifdef USE_AEVENT
295 OSErr HandleUnusedParms(const AppleEvent *theAEvent);
296 #endif
297
298 #ifdef FEAT_GUI_TABLINE
299 static void initialise_tabline(void);
300 static WindowRef drawer = NULL; // TODO: put into gui.h
301 #endif
302
303 #ifdef USE_ATSUI_DRAWING
304 static void gui_mac_set_font_attributes(GuiFont font);
305 static void gui_mac_dispose_atsui_style(void);
306 #endif
307
308 /*
309  * ------------------------------------------------------------
310  * Conversion Utility
311  * ------------------------------------------------------------
312  */
313
314 /*
315  * C2Pascal_save
316  *
317  * Allocate memory and convert the C-String passed in
318  * into a pascal string
319  *
320  */
321
322     char_u *
323 C2Pascal_save(char_u *Cstring)
324 {
325     char_u  *PascalString;
326     int     len;
327
328     if (Cstring == NULL)
329         return NULL;
330
331     len = STRLEN(Cstring);
332
333     if (len > 255) /* Truncate if necessary */
334         len = 255;
335
336     PascalString = alloc(len + 1);
337     if (PascalString != NULL)
338     {
339         mch_memmove(PascalString + 1, Cstring, len);
340         PascalString[0] = len;
341     }
342
343     return PascalString;
344 }
345
346 /*
347  * C2Pascal_save_and_remove_backslash
348  *
349  * Allocate memory and convert the C-String passed in
350  * into a pascal string. Also remove the backslash at the same time
351  *
352  */
353
354     char_u *
355 C2Pascal_save_and_remove_backslash(char_u *Cstring)
356 {
357     char_u  *PascalString;
358     int     len;
359     char_u  *p, *c;
360
361     len = STRLEN(Cstring);
362
363     if (len > 255) /* Truncate if necessary */
364         len = 255;
365
366     PascalString = alloc(len + 1);
367     if (PascalString != NULL)
368     {
369         for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
370         {
371             if ((*c == '\\') && (c[1] != 0))
372             {
373                 c++;
374             }
375             *p = *c;
376             p++;
377             len++;
378         }
379         PascalString[0] = len;
380     }
381
382     return PascalString;
383 }
384
385 /*
386  * Convert the modifiers of an Event into vim's modifiers (mouse)
387  */
388
389     int_u
390 EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
391 {
392     int_u vimModifiers = 0x00;
393
394     if (macModifiers & (shiftKey | rightShiftKey))
395         vimModifiers |= MOUSE_SHIFT;
396     if (macModifiers & (controlKey | rightControlKey))
397         vimModifiers |= MOUSE_CTRL;
398     if (macModifiers & (optionKey | rightOptionKey))
399         vimModifiers |= MOUSE_ALT;
400 #if 0
401     /* Not yet supported */
402     if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
403         vimModifiers |= MOUSE_CMD;
404 #endif
405     return (vimModifiers);
406 }
407
408 /*
409  * Convert the modifiers of an Event into vim's modifiers (keys)
410  */
411
412     static int_u
413 EventModifiers2VimModifiers(EventModifiers macModifiers)
414 {
415     int_u vimModifiers = 0x00;
416
417     if (macModifiers & (shiftKey | rightShiftKey))
418         vimModifiers |= MOD_MASK_SHIFT;
419     if (macModifiers & (controlKey | rightControlKey))
420         vimModifiers |= MOD_MASK_CTRL;
421     if (macModifiers & (optionKey | rightOptionKey))
422         vimModifiers |= MOD_MASK_ALT;
423 #ifdef USE_CMD_KEY
424     if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
425         vimModifiers |= MOD_MASK_CMD;
426 #endif
427     return (vimModifiers);
428 }
429
430 /* Convert a string representing a point size into pixels. The string should
431  * be a positive decimal number, with an optional decimal point (eg, "12", or
432  * "10.5"). The pixel value is returned, and a pointer to the next unconverted
433  * character is stored in *end. The flag "vertical" says whether this
434  * calculation is for a vertical (height) size or a horizontal (width) one.
435  *
436  * From gui_w48.c
437  */
438     static int
439 points_to_pixels(char_u *str, char_u **end, int vertical)
440 {
441     int         pixels;
442     int         points = 0;
443     int         divisor = 0;
444
445     while (*str)
446     {
447         if (*str == '.' && divisor == 0)
448         {
449             /* Start keeping a divisor, for later */
450             divisor = 1;
451             continue;
452         }
453
454         if (!isdigit(*str))
455             break;
456
457         points *= 10;
458         points += *str - '0';
459         divisor *= 10;
460
461         ++str;
462     }
463
464     if (divisor == 0)
465         divisor = 1;
466
467     pixels = points/divisor;
468     *end = str;
469     return pixels;
470 }
471
472 #ifdef MACOS_CONVERT
473 /*
474  * Deletes all traces of any Windows-style mnemonic text (including any
475  * parentheses) from a menu item and returns the cleaned menu item title.
476  * The caller is responsible for releasing the returned string.
477  */
478     static CFStringRef
479 menu_title_removing_mnemonic(vimmenu_T *menu)
480 {
481     CFStringRef         name;
482     size_t              menuTitleLen;
483     CFIndex             displayLen;
484     CFRange             mnemonicStart;
485     CFRange             mnemonicEnd;
486     CFMutableStringRef  cleanedName;
487
488     menuTitleLen = STRLEN(menu->dname);
489     name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
490
491     if (name)
492     {
493         /* Simple mnemonic-removal algorithm, assumes single parenthesized
494          * mnemonic character towards the end of the menu text */
495         mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
496         displayLen = CFStringGetLength(name);
497
498         if (mnemonicStart.location != kCFNotFound
499                 && (mnemonicStart.location + 2) < displayLen
500                 && CFStringGetCharacterAtIndex(name,
501                        mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
502         {
503             if (CFStringFindWithOptions(name, CFSTR(")"),
504                         CFRangeMake(mnemonicStart.location + 1,
505                             displayLen - mnemonicStart.location - 1),
506                         kCFCompareBackwards, &mnemonicEnd) &&
507                     (mnemonicStart.location + 2) == mnemonicEnd.location)
508             {
509                 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
510                 if (cleanedName)
511                 {
512                     CFStringDelete(cleanedName,
513                             CFRangeMake(mnemonicStart.location,
514                                 mnemonicEnd.location + 1 -
515                                 mnemonicStart.location));
516
517                     CFRelease(name);
518                     name = cleanedName;
519                 }
520             }
521         }
522     }
523
524     return name;
525 }
526 #endif
527
528 /*
529  * Convert a list of FSSpec aliases into a list of fullpathname
530  * character strings.
531  */
532
533     char_u **
534 new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
535 {
536     char_u      **fnames = NULL;
537     OSErr       newError;
538     long        fileCount;
539     FSSpec      fileToOpen;
540     long        actualSize;
541     AEKeyword   dummyKeyword;
542     DescType    dummyType;
543
544     /* Get number of files in list */
545     *error = AECountItems(theList, numFiles);
546     if (*error)
547         return fnames;
548
549     /* Allocate the pointer list */
550     fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
551
552     /* Empty out the list */
553     for (fileCount = 0; fileCount < *numFiles; fileCount++)
554         fnames[fileCount] = NULL;
555
556     /* Scan the list of FSSpec */
557     for (fileCount = 1; fileCount <= *numFiles; fileCount++)
558     {
559         /* Get the alias for the nth file, convert to an FSSpec */
560         newError = AEGetNthPtr(theList, fileCount, typeFSS,
561                                 &dummyKeyword, &dummyType,
562                                 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
563         if (newError)
564         {
565             /* Caller is able to clean up */
566             /* TODO: Should be clean up or not? For safety. */
567             return fnames;
568         }
569
570         /* Convert the FSSpec to a pathname */
571         fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
572     }
573
574     return (fnames);
575 }
576
577 /*
578  * ------------------------------------------------------------
579  * CodeWarrior External Editor Support
580  * ------------------------------------------------------------
581  */
582 #ifdef FEAT_CW_EDITOR
583
584 /*
585  * Handle the Window Search event from CodeWarrior
586  *
587  * Description
588  * -----------
589  *
590  * The IDE sends the Window Search AppleEvent to the editor when it
591  * needs to know whether a particular file is open in the editor.
592  *
593  * Event Reply
594  * -----------
595  *
596  * None. Put data in the location specified in the structure received.
597  *
598  * Remarks
599  * -------
600  *
601  * When the editor receives this event, determine whether the specified
602  * file is open. If it is, return the modification date/time for that file
603  * in the appropriate location specified in the structure. If the file is
604  * not opened, put the value fnfErr(file not found) in that location.
605  *
606  */
607
608 typedef struct WindowSearch WindowSearch;
609 struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
610 {
611     FSSpec theFile; // identifies the file
612     long *theDate; // where to put the modification date/time
613 };
614
615     pascal OSErr
616 Handle_KAHL_SRCH_AE(
617         const AppleEvent    *theAEvent,
618         AppleEvent          *theReply,
619         long                refCon)
620 {
621     OSErr       error = noErr;
622     buf_T       *buf;
623     int         foundFile = false;
624     DescType    typeCode;
625     WindowSearch SearchData;
626     Size        actualSize;
627
628     error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
629     if (error)
630         return error;
631
632     error = HandleUnusedParms(theAEvent);
633     if (error)
634         return error;
635
636     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
637         if (buf->b_ml.ml_mfp != NULL
638                 && SearchData.theFile.parID == buf->b_FSSpec.parID
639                 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
640                 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
641             {
642                 foundFile = true;
643                 break;
644             }
645
646     if (foundFile == false)
647         *SearchData.theDate = fnfErr;
648     else
649         *SearchData.theDate = buf->b_mtime;
650
651     return error;
652 };
653
654 /*
655  * Handle the Modified (from IDE to Editor) event from CodeWarrior
656  *
657  * Description
658  * -----------
659  *
660  * The IDE sends this event to the external editor when it wants to
661  * know which files that are open in the editor have been modified.
662  *
663  * Parameters   None.
664  * ----------
665  *
666  * Event Reply
667  * -----------
668  * The reply for this event is:
669  *
670  * keyDirectObject typeAEList required
671  *  each element in the list is a structure of typeChar
672  *
673  * Remarks
674  * -------
675  *
676  * When building the reply event, include one element in the list for
677  * each open file that has been modified.
678  *
679  */
680
681 typedef struct ModificationInfo ModificationInfo;
682 struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
683 {
684     FSSpec theFile; // identifies the file
685     long theDate; // the date/time the file was last modified
686     short saved; // set this to zero when replying, unused
687 };
688
689     pascal OSErr
690 Handle_KAHL_MOD_AE(
691         const AppleEvent    *theAEvent,
692         AppleEvent          *theReply,
693         long                refCon)
694 {
695     OSErr       error = noErr;
696     AEDescList  replyList;
697     long        numFiles;
698     ModificationInfo theFile;
699     buf_T       *buf;
700
701     theFile.saved = 0;
702
703     error = HandleUnusedParms(theAEvent);
704     if (error)
705         return error;
706
707     /* Send the reply */
708 /*  replyObject.descriptorType = typeNull;
709     replyObject.dataHandle     = nil;*/
710
711 /* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
712     error = AECreateList(nil, 0, false, &replyList);
713     if (error)
714         return error;
715
716 #if 0
717     error = AECountItems(&replyList, &numFiles);
718
719     /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
720      * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
721      * sizeof(DescType))
722      */
723
724     /* AEPutDesc */
725 #endif
726
727     numFiles = 0;
728     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
729         if (buf->b_ml.ml_mfp != NULL)
730         {
731             /* Add this file to the list */
732             theFile.theFile = buf->b_FSSpec;
733             theFile.theDate = buf->b_mtime;
734 /*          theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
735             error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
736         };
737
738 #if 0
739     error = AECountItems(&replyList, &numFiles);
740 #endif
741
742     /* We can add data only if something to reply */
743     error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
744
745     if (replyList.dataHandle)
746         AEDisposeDesc(&replyList);
747
748     return error;
749 };
750
751 /*
752  * Handle the Get Text event from CodeWarrior
753  *
754  * Description
755  * -----------
756  *
757  * The IDE sends the Get Text AppleEvent to the editor when it needs
758  * the source code from a file. For example, when the user issues a
759  * Check Syntax or Compile command, the compiler needs access to
760  * the source code contained in the file.
761  *
762  * Event Reply
763  * -----------
764  *
765  * None. Put data in locations specified in the structure received.
766  *
767  * Remarks
768  * -------
769  *
770  * When the editor receives this event, it must set the size of the handle
771  * in theText to fit the data in the file. It must then copy the entire
772  * contents of the specified file into the memory location specified in
773  * theText.
774  *
775  */
776
777 typedef struct CW_GetText CW_GetText;
778 struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
779 {
780     FSSpec theFile; /* identifies the file */
781     Handle theText; /* the location where you return the text (must be resized properly) */
782     long *unused;   /* 0 (not used) */
783     long *theDate;  /* where to put the modification date/time */
784 };
785
786     pascal OSErr
787 Handle_KAHL_GTTX_AE(
788         const AppleEvent    *theAEvent,
789         AppleEvent          *theReply,
790         long                refCon)
791 {
792     OSErr       error = noErr;
793     buf_T       *buf;
794     int         foundFile = false;
795     DescType    typeCode;
796     CW_GetText  GetTextData;
797     Size        actualSize;
798     char_u      *line;
799     char_u      *fullbuffer = NULL;
800     long        linesize;
801     long        lineStart;
802     long        BufferSize;
803     long        lineno;
804
805     error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
806
807     if (error)
808         return error;
809
810     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
811         if (buf->b_ml.ml_mfp != NULL)
812             if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
813             {
814                 foundFile = true;
815                 break;
816             }
817
818     if (foundFile)
819     {
820         BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
821         for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
822         {
823             /* Must use the right buffer */
824             line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
825             linesize = STRLEN(line) + 1;
826             lineStart = BufferSize;
827             BufferSize += linesize;
828             /* Resize handle to linesize+1 to include the linefeed */
829             SetHandleSize(GetTextData.theText, BufferSize);
830             if (GetHandleSize(GetTextData.theText) != BufferSize)
831             {
832                 break; /* Simple handling for now */
833             }
834             else
835             {
836                 HLock(GetTextData.theText);
837                 fullbuffer = (char_u *) *GetTextData.theText;
838                 STRCPY((char_u *)(fullbuffer + lineStart), line);
839                 fullbuffer[BufferSize-1] = '\r';
840                 HUnlock(GetTextData.theText);
841             }
842         }
843         if (fullbuffer != NULL)
844         {
845             HLock(GetTextData.theText);
846             fullbuffer[BufferSize-1] = 0;
847             HUnlock(GetTextData.theText);
848         }
849         if (foundFile == false)
850             *GetTextData.theDate = fnfErr;
851         else
852 /*          *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
853             *GetTextData.theDate = buf->b_mtime;
854     }
855
856     error = HandleUnusedParms(theAEvent);
857
858     return error;
859 }
860
861 /*
862  *
863  */
864
865 /* Taken from MoreAppleEvents:ProcessHelpers*/
866     pascal      OSErr
867 FindProcessBySignature(
868         const OSType            targetType,
869         const OSType            targetCreator,
870         ProcessSerialNumberPtr  psnPtr)
871 {
872     OSErr       anErr = noErr;
873     Boolean     lookingForProcess = true;
874
875     ProcessInfoRec  infoRec;
876
877     infoRec.processInfoLength = sizeof(ProcessInfoRec);
878     infoRec.processName = nil;
879     infoRec.processAppSpec = nil;
880
881     psnPtr->lowLongOfPSN = kNoProcess;
882     psnPtr->highLongOfPSN = kNoProcess;
883
884     while (lookingForProcess)
885     {
886         anErr = GetNextProcess(psnPtr);
887         if (anErr != noErr)
888             lookingForProcess = false;
889         else
890         {
891             anErr = GetProcessInformation(psnPtr, &infoRec);
892             if ((anErr == noErr)
893                     && (infoRec.processType == targetType)
894                     && (infoRec.processSignature == targetCreator))
895                 lookingForProcess = false;
896         }
897     }
898
899     return anErr;
900 }//end FindProcessBySignature
901
902     void
903 Send_KAHL_MOD_AE(buf_T *buf)
904 {
905     OSErr       anErr = noErr;
906     AEDesc      targetAppDesc = { typeNull, nil };
907     ProcessSerialNumber     psn = { kNoProcess, kNoProcess };
908     AppleEvent  theReply = { typeNull, nil };
909     AESendMode  sendMode;
910     AppleEvent  theEvent = {typeNull, nil };
911     AEIdleUPP   idleProcUPP = nil;
912     ModificationInfo ModData;
913
914
915     anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
916     if (anErr == noErr)
917     {
918         anErr = AECreateDesc(typeProcessSerialNumber, &psn,
919                               sizeof(ProcessSerialNumber), &targetAppDesc);
920
921         if (anErr == noErr)
922         {
923             anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
924                                         kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
925         }
926
927         AEDisposeDesc(&targetAppDesc);
928
929         /* Add the parms */
930         ModData.theFile = buf->b_FSSpec;
931         ModData.theDate = buf->b_mtime;
932
933         if (anErr == noErr)
934             anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
935
936         if (idleProcUPP == nil)
937             sendMode = kAENoReply;
938         else
939             sendMode = kAEWaitReply;
940
941         if (anErr == noErr)
942             anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
943         if (anErr == noErr  &&  sendMode == kAEWaitReply)
944         {
945 /*          anErr =  AEHGetHandlerError(&theReply);*/
946         }
947         (void) AEDisposeDesc(&theReply);
948     }
949 }
950 #endif /* FEAT_CW_EDITOR */
951
952 /*
953  * ------------------------------------------------------------
954  * Apple Event Handling procedure
955  * ------------------------------------------------------------
956  */
957 #ifdef USE_AEVENT
958
959 /*
960  * Handle the Unused parms of an AppleEvent
961  */
962
963     OSErr
964 HandleUnusedParms(const AppleEvent *theAEvent)
965 {
966     OSErr       error;
967     long        actualSize;
968     DescType    dummyType;
969     AEKeyword   missedKeyword;
970
971     /* Get the "missed keyword" attribute from the AppleEvent. */
972     error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
973                               typeKeyword, &dummyType,
974                               (Ptr)&missedKeyword, sizeof(missedKeyword),
975                               &actualSize);
976
977     /* If the descriptor isn't found, then we got the required parameters. */
978     if (error == errAEDescNotFound)
979     {
980         error = noErr;
981     }
982     else
983     {
984 #if 0
985         /* Why is this removed? */
986         error = errAEEventNotHandled;
987 #endif
988     }
989
990     return error;
991 }
992
993
994 /*
995  * Handle the ODoc AppleEvent
996  *
997  * Deals with all files dragged to the application icon.
998  *
999  */
1000
1001 typedef struct SelectionRange SelectionRange;
1002 struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1003 {
1004     short unused1; // 0 (not used)
1005     short lineNum; // line to select (<0 to specify range)
1006     long startRange; // start of selection range (if line < 0)
1007     long endRange; // end of selection range (if line < 0)
1008     long unused2; // 0 (not used)
1009     long theDate; // modification date/time
1010 };
1011
1012 /* The IDE uses the optional keyAEPosition parameter to tell the ed-
1013    itor the selection range. If lineNum is zero or greater, scroll the text
1014    to the specified line. If lineNum is less than zero, use the values in
1015    startRange and endRange to select the specified characters. Scroll
1016    the text to display the selection. If lineNum, startRange, and
1017    endRange are all negative, there is no selection range specified.
1018  */
1019
1020     pascal OSErr
1021 HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
1022 {
1023     /*
1024      * TODO: Clean up the code with convert the AppleEvent into
1025      *       a ":args"
1026      */
1027     OSErr       error = noErr;
1028 //    OSErr     firstError = noErr;
1029 //    short     numErrors = 0;
1030     AEDesc      theList;
1031     DescType    typeCode;
1032     long        numFiles;
1033  //   long       fileCount;
1034     char_u      **fnames;
1035 //    char_u    fname[256];
1036     Size        actualSize;
1037     SelectionRange thePosition;
1038     short       gotPosition = false;
1039     long        lnum;
1040
1041     /* the direct object parameter is the list of aliases to files (one or more) */
1042     error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1043     if (error)
1044         return error;
1045
1046
1047     error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1048     if (error == noErr)
1049         gotPosition = true;
1050     if (error == errAEDescNotFound)
1051         error = noErr;
1052     if (error)
1053         return error;
1054
1055 /*
1056     error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1057
1058     if (^error) then
1059     {
1060         if (thePosition.lineNum >= 0)
1061         {
1062           // Goto this line
1063         }
1064         else
1065         {
1066           // Set the range char wise
1067         }
1068     }
1069  */
1070
1071
1072 #ifdef FEAT_VISUAL
1073     reset_VIsual();
1074 #endif
1075
1076     fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1077
1078     if (error)
1079     {
1080       /* TODO: empty fnames[] first */
1081       vim_free(fnames);
1082       return (error);
1083     }
1084
1085     if (starting > 0)
1086     {
1087         int i;
1088         char_u *p;
1089         int fnum = -1;
1090
1091         /* these are the initial files dropped on the Vim icon */
1092         for (i = 0 ; i < numFiles; i++)
1093         {
1094             if (ga_grow(&global_alist.al_ga, 1) == FAIL
1095                                       || (p = vim_strsave(fnames[i])) == NULL)
1096                 mch_exit(2);
1097             else
1098                 alist_add(&global_alist, p, 2);
1099             if (fnum == -1)
1100                 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1101         }
1102
1103         /* If the file name was already in the buffer list we need to switch
1104          * to it. */
1105         if (curbuf->b_fnum != fnum)
1106         {
1107             char_u cmd[30];
1108
1109             vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1110             do_cmdline_cmd(cmd);
1111         }
1112
1113         /* Change directory to the location of the first file. */
1114         if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1115             shorten_fnames(TRUE);
1116
1117         goto finished;
1118     }
1119
1120     /* Handle the drop, :edit to get to the file */
1121     handle_drop(numFiles, fnames, FALSE);
1122
1123     /* TODO: Handle the goto/select line more cleanly */
1124     if ((numFiles == 1) & (gotPosition))
1125     {
1126         if (thePosition.lineNum >= 0)
1127         {
1128             lnum = thePosition.lineNum + 1;
1129         /*  oap->motion_type = MLINE;
1130             setpcmark();*/
1131             if (lnum < 1L)
1132                 lnum = 1L;
1133             else if (lnum > curbuf->b_ml.ml_line_count)
1134                 lnum = curbuf->b_ml.ml_line_count;
1135             curwin->w_cursor.lnum = lnum;
1136             curwin->w_cursor.col = 0;
1137         /*  beginline(BL_SOL | BL_FIX);*/
1138         }
1139         else
1140             goto_byte(thePosition.startRange + 1);
1141     }
1142
1143     /* Update the screen display */
1144     update_screen(NOT_VALID);
1145 #ifdef FEAT_VISUAL
1146     /* Select the text if possible */
1147     if (gotPosition)
1148     {
1149         VIsual_active = TRUE;
1150         VIsual_select = FALSE;
1151         VIsual = curwin->w_cursor;
1152         if (thePosition.lineNum < 0)
1153         {
1154             VIsual_mode = 'v';
1155             goto_byte(thePosition.endRange);
1156         }
1157         else
1158         {
1159             VIsual_mode = 'V';
1160             VIsual.col = 0;
1161         }
1162     }
1163 #endif
1164     setcursor();
1165     out_flush();
1166
1167     /* Fake mouse event to wake from stall */
1168     PostEvent(mouseUp, 0);
1169
1170 finished:
1171     AEDisposeDesc(&theList); /* dispose what we allocated */
1172
1173     error = HandleUnusedParms(theAEvent);
1174     return error;
1175 }
1176
1177 /*
1178  *
1179  */
1180
1181     pascal OSErr
1182 Handle_aevt_oapp_AE(
1183         const AppleEvent    *theAEvent,
1184         AppleEvent          *theReply,
1185         long                refCon)
1186 {
1187     OSErr       error = noErr;
1188
1189     error = HandleUnusedParms(theAEvent);
1190     return error;
1191 }
1192
1193 /*
1194  *
1195  */
1196
1197     pascal OSErr
1198 Handle_aevt_quit_AE(
1199         const AppleEvent    *theAEvent,
1200         AppleEvent          *theReply,
1201         long                refCon)
1202 {
1203     OSErr       error = noErr;
1204
1205     error = HandleUnusedParms(theAEvent);
1206     if (error)
1207         return error;
1208
1209     /* Need to fake a :confirm qa */
1210     do_cmdline_cmd((char_u *)"confirm qa");
1211
1212     return error;
1213 }
1214
1215 /*
1216  *
1217  */
1218
1219     pascal OSErr
1220 Handle_aevt_pdoc_AE(
1221         const AppleEvent    *theAEvent,
1222         AppleEvent          *theReply,
1223         long                refCon)
1224 {
1225     OSErr       error = noErr;
1226
1227     error = HandleUnusedParms(theAEvent);
1228
1229     return error;
1230 }
1231
1232 /*
1233  * Handling of unknown AppleEvent
1234  *
1235  * (Just get rid of all the parms)
1236  */
1237     pascal OSErr
1238 Handle_unknown_AE(
1239         const AppleEvent    *theAEvent,
1240         AppleEvent          *theReply,
1241         long                refCon)
1242 {
1243     OSErr       error = noErr;
1244
1245     error = HandleUnusedParms(theAEvent);
1246
1247     return error;
1248 }
1249
1250
1251 /*
1252  * Install the various AppleEvent Handlers
1253  */
1254     OSErr
1255 InstallAEHandlers(void)
1256 {
1257     OSErr   error;
1258
1259     /* install open application handler */
1260     error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
1261                     NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
1262     if (error)
1263     {
1264         return error;
1265     }
1266
1267     /* install quit application handler */
1268     error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
1269                     NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
1270     if (error)
1271     {
1272         return error;
1273     }
1274
1275     /* install open document handler */
1276     error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
1277                     NewAEEventHandlerUPP(HandleODocAE), 0, false);
1278     if (error)
1279     {
1280         return error;
1281     }
1282
1283     /* install print document handler */
1284     error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
1285                     NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
1286
1287 /* Install Core Suite */
1288 /*  error = AEInstallEventHandler(kAECoreSuite, kAEClone,
1289                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1290
1291     error = AEInstallEventHandler(kAECoreSuite, kAEClose,
1292                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1293
1294     error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
1295                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1296
1297     error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
1298                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1299
1300     error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
1301                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1302
1303     error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
1304                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1305
1306     error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
1307                     NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
1308
1309     error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
1310                     NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
1311
1312     error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
1313                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1314
1315     error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
1316                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1317
1318     error = AEInstallEventHandler(kAECoreSuite, kAEMove,
1319                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1320
1321     error = AEInstallEventHandler(kAECoreSuite, kAESave,
1322                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1323
1324     error = AEInstallEventHandler(kAECoreSuite, kAESetData,
1325                     NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1326 */
1327
1328 #ifdef FEAT_CW_EDITOR
1329     /*
1330      * Bind codewarrior support handlers
1331      */
1332     error = AEInstallEventHandler('KAHL', 'GTTX',
1333                     NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
1334     if (error)
1335     {
1336         return error;
1337     }
1338     error = AEInstallEventHandler('KAHL', 'SRCH',
1339                     NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
1340     if (error)
1341     {
1342         return error;
1343     }
1344     error = AEInstallEventHandler('KAHL', 'MOD ',
1345                     NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
1346     if (error)
1347     {
1348         return error;
1349     }
1350 #endif
1351
1352     return error;
1353
1354 }
1355 #endif /* USE_AEVENT */
1356
1357
1358 /*
1359  * Callback function, installed by InstallFontPanelHandler(), below,
1360  * to handle Font Panel events.
1361  */
1362     static OSStatus
1363 FontPanelHandler(
1364         EventHandlerCallRef inHandlerCallRef,
1365         EventRef inEvent,
1366         void *inUserData)
1367 {
1368     if (GetEventKind(inEvent) == kEventFontPanelClosed)
1369     {
1370         gFontPanelInfo.isPanelVisible = false;
1371         return noErr;
1372     }
1373
1374     if (GetEventKind(inEvent) == kEventFontSelection)
1375     {
1376         OSStatus status;
1377         FMFontFamily newFamily;
1378         FMFontSize newSize;
1379         FMFontStyle newStyle;
1380
1381         /* Retrieve the font family ID number. */
1382         status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1383                 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1384                 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1385                 &newFamily);
1386         if (status == noErr)
1387             gFontPanelInfo.family = newFamily;
1388
1389         /* Retrieve the font size. */
1390         status = GetEventParameter(inEvent, kEventParamFMFontSize,
1391                 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1392         if (status == noErr)
1393             gFontPanelInfo.size = newSize;
1394
1395         /* Retrieve the font style (bold, etc.).  Currently unused. */
1396         status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1397                 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1398         if (status == noErr)
1399             gFontPanelInfo.style = newStyle;
1400     }
1401     return noErr;
1402 }
1403
1404
1405     static void
1406 InstallFontPanelHandler(void)
1407 {
1408     EventTypeSpec eventTypes[2];
1409     EventHandlerUPP handlerUPP;
1410     /* EventHandlerRef handlerRef; */
1411
1412     eventTypes[0].eventClass = kEventClassFont;
1413     eventTypes[0].eventKind  = kEventFontSelection;
1414     eventTypes[1].eventClass = kEventClassFont;
1415     eventTypes[1].eventKind  = kEventFontPanelClosed;
1416
1417     handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1418
1419     InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1420             /*userData=*/NULL, /*handlerRef=*/NULL);
1421 }
1422
1423
1424 /*
1425  * Fill the buffer pointed to by outName with the name and size
1426  * of the font currently selected in the Font Panel.
1427  */
1428 #define FONT_STYLE_BUFFER_SIZE 32
1429     static void
1430 GetFontPanelSelection(char_u *outName)
1431 {
1432     Str255          buf;
1433     ByteCount       fontNameLen = 0;
1434     ATSUFontID      fid;
1435     char_u          styleString[FONT_STYLE_BUFFER_SIZE];
1436
1437     if (!outName)
1438         return;
1439
1440     if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1441     {
1442         /* Canonicalize localized font names */
1443         if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1444                     gFontPanelInfo.style, &fid, NULL) != noErr)
1445             return;
1446
1447         /* Request font name with Mac encoding (otherwise we could
1448          * get an unwanted utf-16 name) */
1449         if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1450                     kFontNoScriptCode, kFontNoLanguageCode,
1451                     255, (char *)outName, &fontNameLen, NULL) != noErr)
1452             return;
1453
1454         /* Only encode font size, because style (bold, italic, etc) is
1455          * already part of the font full name */
1456         vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
1457                 gFontPanelInfo.size/*,
1458                 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1459                 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1460                 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1461
1462         if ((fontNameLen + STRLEN(styleString)) < 255)
1463             STRCPY(outName + fontNameLen, styleString);
1464     }
1465     else
1466     {
1467         *outName = NUL;
1468     }
1469 }
1470
1471
1472 /*
1473  * ------------------------------------------------------------
1474  * Unfiled yet
1475  * ------------------------------------------------------------
1476  */
1477
1478 /*
1479  *  gui_mac_get_menu_item_index
1480  *
1481  *  Returns the index inside the menu wher
1482  */
1483     short /* Shoulde we return MenuItemIndex? */
1484 gui_mac_get_menu_item_index(vimmenu_T *pMenu)
1485 {
1486     short       index;
1487     short       itemIndex = -1;
1488     vimmenu_T   *pBrother;
1489
1490     /* Only menu without parent are the:
1491      * -menu in the menubar
1492      * -popup menu
1493      * -toolbar (guess)
1494      *
1495      * Which are not items anyway.
1496      */
1497     if (pMenu->parent)
1498     {
1499         /* Start from the Oldest Brother */
1500         pBrother = pMenu->parent->children;
1501         index = 1;
1502         while ((pBrother) && (itemIndex == -1))
1503         {
1504             if (pBrother == pMenu)
1505                 itemIndex = index;
1506             index++;
1507             pBrother = pBrother->next;
1508         }
1509     }
1510     return itemIndex;
1511 }
1512
1513     static vimmenu_T *
1514 gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
1515 {
1516     short       index;
1517     vimmenu_T   *pChildMenu;
1518     vimmenu_T   *pElder = pMenu->parent;
1519
1520
1521     /* Only menu without parent are the:
1522      * -menu in the menubar
1523      * -popup menu
1524      * -toolbar (guess)
1525      *
1526      * Which are not items anyway.
1527      */
1528
1529     if ((pElder) && (pElder->submenu_id == menuID))
1530     {
1531         for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1532             pMenu = pMenu->next;
1533     }
1534     else
1535     {
1536         for (; pMenu != NULL; pMenu = pMenu->next)
1537         {
1538             if (pMenu->children != NULL)
1539             {
1540                 pChildMenu = gui_mac_get_vim_menu
1541                            (menuID, itemIndex, pMenu->children);
1542                 if (pChildMenu)
1543                 {
1544                     pMenu = pChildMenu;
1545                     break;
1546                 }
1547             }
1548         }
1549     }
1550     return pMenu;
1551 }
1552
1553 /*
1554  * ------------------------------------------------------------
1555  * MacOS Feedback procedures
1556  * ------------------------------------------------------------
1557  */
1558     pascal
1559     void
1560 gui_mac_drag_thumb(ControlHandle theControl, short partCode)
1561 {
1562     scrollbar_T         *sb;
1563     int                 value, dragging;
1564     ControlHandle       theControlToUse;
1565     int                 dont_scroll_save = dont_scroll;
1566
1567     theControlToUse = dragged_sb;
1568
1569     sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
1570
1571     if (sb == NULL)
1572         return;
1573
1574     /* Need to find value by diff between Old Poss New Pos */
1575     value = GetControl32BitValue(theControlToUse);
1576     dragging = (partCode != 0);
1577
1578     /* When "allow_scrollbar" is FALSE still need to remember the new
1579      * position, but don't actually scroll by setting "dont_scroll". */
1580     dont_scroll = !allow_scrollbar;
1581     gui_drag_scrollbar(sb, value, dragging);
1582     dont_scroll = dont_scroll_save;
1583 }
1584
1585     pascal
1586     void
1587 gui_mac_scroll_action(ControlHandle theControl, short partCode)
1588 {
1589     /* TODO: have live support */
1590     scrollbar_T *sb, *sb_info;
1591     long        data;
1592     long        value;
1593     int         page;
1594     int         dragging = FALSE;
1595     int         dont_scroll_save = dont_scroll;
1596
1597     sb = gui_find_scrollbar((long)GetControlReference(theControl));
1598
1599     if (sb == NULL)
1600         return;
1601
1602     if (sb->wp != NULL)         /* Left or right scrollbar */
1603     {
1604         /*
1605          * Careful: need to get scrollbar info out of first (left) scrollbar
1606          * for window, but keep real scrollbar too because we must pass it to
1607          * gui_drag_scrollbar().
1608          */
1609         sb_info = &sb->wp->w_scrollbars[0];
1610
1611         if (sb_info->size > 5)
1612             page = sb_info->size - 2;   /* use two lines of context */
1613         else
1614             page = sb_info->size;
1615     }
1616     else                        /* Bottom scrollbar */
1617     {
1618         sb_info = sb;
1619         page = W_WIDTH(curwin) - 5;
1620     }
1621
1622     switch (partCode)
1623     {
1624         case  kControlUpButtonPart:   data = -1;    break;
1625         case  kControlDownButtonPart: data = 1;     break;
1626         case  kControlPageDownPart:   data = page;  break;
1627         case  kControlPageUpPart:     data = -page; break;
1628                     default: data = 0; break;
1629     }
1630
1631     value = sb_info->value + data;
1632 /*  if (value > sb_info->max)
1633         value = sb_info->max;
1634     else if (value < 0)
1635         value = 0;*/
1636
1637     /* When "allow_scrollbar" is FALSE still need to remember the new
1638      * position, but don't actually scroll by setting "dont_scroll". */
1639     dont_scroll = !allow_scrollbar;
1640     gui_drag_scrollbar(sb, value, dragging);
1641     dont_scroll = dont_scroll_save;
1642
1643     out_flush();
1644     gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1645
1646 /*  if (sb_info->wp != NULL)
1647     {
1648         win_T   *wp;
1649         int     sb_num;
1650
1651         sb_num = 0;
1652         for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1653         sb_num++;
1654
1655         if (wp != NULL)
1656         {
1657             current_scrollbar = sb_num;
1658             scrollbar_value = value;
1659             gui_do_scroll();
1660             gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1661         }
1662     }*/
1663 }
1664
1665 /*
1666  * ------------------------------------------------------------
1667  * MacOS Click Handling procedures
1668  * ------------------------------------------------------------
1669  */
1670
1671
1672 /*
1673  * Handle a click inside the window, it may happens in the
1674  * scrollbar or the contents.
1675  *
1676  * TODO: Add support for potential TOOLBAR
1677  */
1678     void
1679 gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
1680 {
1681     Point               thePoint;
1682     int_u               vimModifiers;
1683     short               thePortion;
1684     ControlHandle       theControl;
1685     int                 vimMouseButton;
1686     short               dblClick;
1687
1688     thePoint = theEvent->where;
1689     GlobalToLocal(&thePoint);
1690     SelectWindow(whichWindow);
1691
1692     thePortion = FindControl(thePoint, whichWindow, &theControl);
1693
1694     if (theControl != NUL)
1695     {
1696         /* We hit a scollbar */
1697
1698         if (thePortion != kControlIndicatorPart)
1699         {
1700             dragged_sb = theControl;
1701             TrackControl(theControl, thePoint, gScrollAction);
1702             dragged_sb = NULL;
1703         }
1704         else
1705         {
1706             dragged_sb = theControl;
1707 #if 1
1708             TrackControl(theControl, thePoint, gScrollDrag);
1709 #else
1710             TrackControl(theControl, thePoint, NULL);
1711 #endif
1712             /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1713              * button has been released */
1714             gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
1715             dragged_sb = NULL;
1716         }
1717     }
1718     else
1719     {
1720         /* We are inside the contents */
1721
1722         /* Convert the CTRL, OPTION, SHIFT and CMD key */
1723         vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1724
1725         /* Defaults to MOUSE_LEFT as there's only one mouse button */
1726         vimMouseButton = MOUSE_LEFT;
1727
1728         /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
1729         /* TODO: NEEDED? */
1730         clickIsPopup = FALSE;
1731
1732         if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1733         {
1734             vimMouseButton = MOUSE_RIGHT;
1735             vimModifiers &= ~MOUSE_CTRL;
1736             clickIsPopup = TRUE;
1737         }
1738
1739         /* Is it a double click ? */
1740         dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1741
1742         /* Send the mouse click to Vim */
1743         gui_send_mouse_event(vimMouseButton, thePoint.h,
1744                                           thePoint.v, dblClick, vimModifiers);
1745
1746         /* Create the rectangle around the cursor to detect
1747          * the mouse dragging
1748          */
1749 #if 0
1750         /* TODO: Do we need to this even for the contextual menu?
1751          * It may be require for popup_setpos, but for popup?
1752          */
1753         if (vimMouseButton == MOUSE_LEFT)
1754 #endif
1755         {
1756             SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
1757                                 FILL_Y(Y_2_ROW(thePoint.v)),
1758                                 FILL_X(X_2_COL(thePoint.h)+1),
1759                                 FILL_Y(Y_2_ROW(thePoint.v)+1));
1760
1761             dragRectEnbl = TRUE;
1762             dragRectControl = kCreateRect;
1763         }
1764     }
1765 }
1766
1767 /*
1768  * Handle the click in the titlebar (to move the window)
1769  */
1770     void
1771 gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
1772 {
1773     Rect        movingLimits;
1774     Rect        *movingLimitsPtr = &movingLimits;
1775
1776     /* TODO: may try to prevent move outside screen? */
1777     movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
1778     DragWindow(whichWindow, where, movingLimitsPtr);
1779 }
1780
1781 /*
1782  * Handle the click in the grow box
1783  */
1784     void
1785 gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
1786 {
1787
1788     long            newSize;
1789     unsigned short  newWidth;
1790     unsigned short  newHeight;
1791     Rect            resizeLimits;
1792     Rect            *resizeLimitsPtr = &resizeLimits;
1793     Rect            NewContentRect;
1794
1795     resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
1796
1797     /* Set the minimum size */
1798     /* TODO: Should this come from Vim? */
1799     resizeLimits.top = 100;
1800     resizeLimits.left = 100;
1801
1802     newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1803     newWidth  = NewContentRect.right - NewContentRect.left;
1804     newHeight = NewContentRect.bottom - NewContentRect.top;
1805     gui_resize_shell(newWidth, newHeight);
1806     gui_mch_set_bg_color(gui.back_pixel);
1807     gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
1808 }
1809
1810 /*
1811  * Handle the click in the zoom box
1812  */
1813     static void
1814 gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
1815 {
1816     Rect        r;
1817     Point       p;
1818     short       thePart;
1819
1820     /* ideal width is current */
1821     p.h = Columns * gui.char_width + 2 * gui.border_offset;
1822     if (gui.which_scrollbars[SBAR_LEFT])
1823         p.h += gui.scrollbar_width;
1824     if (gui.which_scrollbars[SBAR_RIGHT])
1825         p.h += gui.scrollbar_width;
1826     /* ideal height is as heigh as we can get */
1827     p.v = 15 * 1024;
1828
1829     thePart = IsWindowInStandardState(whichWindow, &p, &r)
1830                                                        ? inZoomIn : inZoomOut;
1831
1832     if (!TrackBox(whichWindow, theEvent->where, thePart))
1833         return;
1834
1835     /* use returned width */
1836     p.h = r.right - r.left;
1837     /* adjust returned height */
1838     p.v = r.bottom - r.top - 2 * gui.border_offset;
1839     if (gui.which_scrollbars[SBAR_BOTTOM])
1840         p.v -= gui.scrollbar_height;
1841     p.v -= p.v % gui.char_height;
1842     p.v += 2 * gui.border_width;
1843     if (gui.which_scrollbars[SBAR_BOTTOM]);
1844         p.v += gui.scrollbar_height;
1845
1846     ZoomWindowIdeal(whichWindow, thePart, &p);
1847
1848     GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1849     gui_resize_shell(r.right - r.left, r.bottom - r.top);
1850     gui_mch_set_bg_color(gui.back_pixel);
1851     gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
1852 }
1853
1854 /*
1855  * ------------------------------------------------------------
1856  * MacOS Event Handling procedure
1857  * ------------------------------------------------------------
1858  */
1859
1860 /*
1861  * Handle the Update Event
1862  */
1863
1864     void
1865 gui_mac_doUpdateEvent(EventRecord *event)
1866 {
1867     WindowPtr   whichWindow;
1868     GrafPtr     savePort;
1869     RgnHandle   updateRgn;
1870     Rect        updateRect;
1871     Rect        *updateRectPtr;
1872     Rect        rc;
1873     Rect        growRect;
1874     RgnHandle   saveRgn;
1875
1876
1877     updateRgn = NewRgn();
1878     if (updateRgn == NULL)
1879         return;
1880
1881     /* This could be done by the caller as we
1882      * don't require anything else out of the event
1883      */
1884     whichWindow = (WindowPtr) event->message;
1885
1886     /* Save Current Port */
1887     GetPort(&savePort);
1888
1889     /* Select the Window's Port */
1890     SetPortWindowPort(whichWindow);
1891
1892     /* Let's update the window */
1893       BeginUpdate(whichWindow);
1894         /* Redraw the biggest rectangle covering the area
1895          * to be updated.
1896          */
1897         GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1898 # if 0
1899         /* Would be more appropriate to use the following but doesn't
1900          * seem to work under MacOS X (Dany)
1901          */
1902         GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1903 # endif
1904
1905         /* Use the HLock useless in Carbon? Is it harmful?*/
1906         HLock((Handle) updateRgn);
1907
1908           updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
1909 # if 0
1910           /* Code from original Carbon Port (using GetWindowRegion.
1911            * I believe the UpdateRgn is already in local (Dany)
1912            */
1913           GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1914           GlobalToLocal(&botRight(updateRect));
1915 # endif
1916           /* Update the content (i.e. the text) */
1917           gui_redraw(updateRectPtr->left, updateRectPtr->top,
1918                       updateRectPtr->right - updateRectPtr->left,
1919                       updateRectPtr->bottom   - updateRectPtr->top);
1920           /* Clear the border areas if needed */
1921           gui_mch_set_bg_color(gui.back_pixel);
1922           if (updateRectPtr->left < FILL_X(0))
1923           {
1924             SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1925             EraseRect(&rc);
1926           }
1927           if (updateRectPtr->top < FILL_Y(0))
1928           {
1929             SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1930             EraseRect(&rc);
1931           }
1932           if (updateRectPtr->right > FILL_X(Columns))
1933           {
1934             SetRect(&rc, FILL_X(Columns), 0,
1935                            FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
1936             EraseRect(&rc);
1937           }
1938           if (updateRectPtr->bottom > FILL_Y(Rows))
1939           {
1940             SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
1941                                             FILL_Y(Rows) + gui.border_offset);
1942             EraseRect(&rc);
1943           }
1944         HUnlock((Handle) updateRgn);
1945         DisposeRgn(updateRgn);
1946
1947         /* Update scrollbars */
1948         DrawControls(whichWindow);
1949
1950         /* Update the GrowBox */
1951         /* Taken from FAQ 33-27 */
1952         saveRgn = NewRgn();
1953         GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
1954         GetClip(saveRgn);
1955         ClipRect(&growRect);
1956         DrawGrowIcon(whichWindow);
1957         SetClip(saveRgn);
1958         DisposeRgn(saveRgn);
1959       EndUpdate(whichWindow);
1960
1961     /* Restore original Port */
1962     SetPort(savePort);
1963 }
1964
1965 /*
1966  * Handle the activate/deactivate event
1967  * (apply to a window)
1968  */
1969     void
1970 gui_mac_doActivateEvent(EventRecord *event)
1971 {
1972     WindowPtr   whichWindow;
1973
1974     whichWindow = (WindowPtr) event->message;
1975     /* Dim scrollbars */
1976     if (whichWindow == gui.VimWindow)
1977     {
1978         ControlRef rootControl;
1979         GetRootControl(gui.VimWindow, &rootControl);
1980         if ((event->modifiers) & activeFlag)
1981             ActivateControl(rootControl);
1982         else
1983             DeactivateControl(rootControl);
1984     }
1985
1986     /* Activate */
1987     gui_focus_change((event->modifiers) & activeFlag);
1988 }
1989
1990
1991 /*
1992  * Handle the suspend/resume event
1993  * (apply to the application)
1994  */
1995     void
1996 gui_mac_doSuspendEvent(EventRecord *event)
1997 {
1998     /* The frontmost application just changed */
1999
2000     /* NOTE: the suspend may happen before the deactivate
2001      *       seen on MacOS X
2002      */
2003
2004     /* May not need to change focus as the window will
2005      * get an activate/deactivate event
2006      */
2007     if (event->message & 1)
2008         /* Resume */
2009         gui_focus_change(TRUE);
2010     else
2011         /* Suspend */
2012         gui_focus_change(FALSE);
2013 }
2014
2015 /*
2016  * Handle the key
2017  */
2018 #ifdef USE_CARBONKEYHANDLER
2019     static pascal OSStatus
2020 gui_mac_handle_window_activate(
2021         EventHandlerCallRef nextHandler,
2022         EventRef            theEvent,
2023         void                *data)
2024 {
2025     UInt32 eventClass = GetEventClass(theEvent);
2026     UInt32 eventKind  = GetEventKind(theEvent);
2027
2028     if (eventClass == kEventClassWindow)
2029     {
2030         switch (eventKind)
2031         {
2032             case kEventWindowActivated:
2033 #if defined(USE_IM_CONTROL)
2034                 im_on_window_switch(TRUE);
2035 #endif
2036                 return noErr;
2037
2038             case kEventWindowDeactivated:
2039 #if defined(USE_IM_CONTROL)
2040                 im_on_window_switch(FALSE);
2041 #endif
2042                 return noErr;
2043         }
2044     }
2045
2046     return eventNotHandledErr;
2047 }
2048
2049     static pascal OSStatus
2050 gui_mac_handle_text_input(
2051         EventHandlerCallRef nextHandler,
2052         EventRef            theEvent,
2053         void                *data)
2054 {
2055     UInt32 eventClass = GetEventClass(theEvent);
2056     UInt32 eventKind  = GetEventKind(theEvent);
2057
2058     if (eventClass != kEventClassTextInput)
2059         return eventNotHandledErr;
2060
2061     if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2062         (kEventTextInputUnicodeForKeyEvent    != eventKind) &&
2063         (kEventTextInputOffsetToPos           != eventKind) &&
2064         (kEventTextInputPosToOffset           != eventKind) &&
2065         (kEventTextInputGetSelectedText       != eventKind))
2066               return eventNotHandledErr;
2067
2068     switch (eventKind)
2069     {
2070     case kEventTextInputUpdateActiveInputArea:
2071         return gui_mac_update_input_area(nextHandler, theEvent);
2072     case kEventTextInputUnicodeForKeyEvent:
2073         return gui_mac_unicode_key_event(nextHandler, theEvent);
2074
2075     case kEventTextInputOffsetToPos:
2076     case kEventTextInputPosToOffset:
2077     case kEventTextInputGetSelectedText:
2078         break;
2079     }
2080
2081     return eventNotHandledErr;
2082 }
2083
2084     static pascal
2085 OSStatus gui_mac_update_input_area(
2086         EventHandlerCallRef nextHandler,
2087         EventRef            theEvent)
2088 {
2089     return eventNotHandledErr;
2090 }
2091
2092 static int dialog_busy = FALSE;     /* TRUE when gui_mch_dialog() wants the
2093                                        keys */
2094
2095 # define INLINE_KEY_BUFFER_SIZE 80
2096     static pascal OSStatus
2097 gui_mac_unicode_key_event(
2098         EventHandlerCallRef nextHandler,
2099         EventRef            theEvent)
2100 {
2101     /* Multibyte-friendly key event handler */
2102     OSStatus    err = -1;
2103     UInt32      actualSize;
2104     UniChar     *text;
2105     char_u      result[INLINE_KEY_BUFFER_SIZE];
2106     short       len = 0;
2107     UInt32      key_sym;
2108     char        charcode;
2109     int         key_char;
2110     UInt32      modifiers, vimModifiers;
2111     size_t      encLen;
2112     char_u      *to = NULL;
2113     Boolean     isSpecial = FALSE;
2114     int         i;
2115     EventRef    keyEvent;
2116
2117     /* Mask the mouse (as per user setting) */
2118     if (p_mh)
2119         ObscureCursor();
2120
2121     /* Don't use the keys when the dialog wants them. */
2122     if (dialog_busy)
2123         return eventNotHandledErr;
2124
2125     if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2126                 typeUnicodeText, NULL, 0, &actualSize, NULL))
2127         return eventNotHandledErr;
2128
2129     text = (UniChar *)alloc(actualSize);
2130     if (!text)
2131         return eventNotHandledErr;
2132
2133     err = GetEventParameter(theEvent, kEventParamTextInputSendText,
2134             typeUnicodeText, NULL, actualSize, NULL, text);
2135     require_noerr(err, done);
2136
2137     err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
2138             typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
2139     require_noerr(err, done);
2140
2141     err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
2142             typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
2143     require_noerr(err, done);
2144
2145     err = GetEventParameter(keyEvent, kEventParamKeyCode,
2146             typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
2147     require_noerr(err, done);
2148
2149     err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
2150             typeChar, NULL, sizeof(char), NULL, &charcode);
2151     require_noerr(err, done);
2152
2153 #ifndef USE_CMD_KEY
2154     if (modifiers & cmdKey)
2155         goto done;  /* Let system handle Cmd+... */
2156 #endif
2157
2158     key_char = charcode;
2159     vimModifiers = EventModifiers2VimModifiers(modifiers);
2160
2161     /* Find the special key (eg., for cursor keys) */
2162     if (actualSize <= sizeof(UniChar) &&
2163             ((text[0] < 0x20) || (text[0] == 0x7f)))
2164     {
2165         for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2166             if (special_keys[i].key_sym == key_sym)
2167             {
2168                 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2169                         special_keys[i].vim_code1);
2170                 key_char = simplify_key(key_char,
2171                         (int *)&vimModifiers);
2172                 isSpecial = TRUE;
2173                 break;
2174             }
2175     }
2176
2177     /* Intercept CMD-. and CTRL-c */
2178     if (((modifiers & controlKey) && key_char == 'c') ||
2179             ((modifiers & cmdKey) && key_char == '.'))
2180         got_int = TRUE;
2181
2182     if (!isSpecial)
2183     {
2184         /* remove SHIFT for keys that are already shifted, e.g.,
2185          * '(' and '*' */
2186         if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2187             vimModifiers &= ~MOD_MASK_SHIFT;
2188
2189         /* remove CTRL from keys that already have it */
2190         if (key_char < 0x20)
2191             vimModifiers &= ~MOD_MASK_CTRL;
2192
2193         /* don't process unicode characters here */
2194         if (!IS_SPECIAL(key_char))
2195         {
2196             /* Following code to simplify and consolidate vimModifiers
2197              * taken liberally from gui_w48.c */
2198             key_char = simplify_key(key_char, (int *)&vimModifiers);
2199
2200             /* Interpret META, include SHIFT, etc. */
2201             key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2202             if (key_char == CSI)
2203                 key_char = K_CSI;
2204
2205             if (IS_SPECIAL(key_char))
2206                 isSpecial = TRUE;
2207         }
2208     }
2209
2210     if (vimModifiers)
2211     {
2212         result[len++] = CSI;
2213         result[len++] = KS_MODIFIER;
2214         result[len++] = vimModifiers;
2215     }
2216
2217     if (isSpecial && IS_SPECIAL(key_char))
2218     {
2219         result[len++] = CSI;
2220         result[len++] = K_SECOND(key_char);
2221         result[len++] = K_THIRD(key_char);
2222     }
2223     else
2224     {
2225         encLen = actualSize;
2226         to = mac_utf16_to_enc(text, actualSize, &encLen);
2227         if (to)
2228         {
2229             /* This is basically add_to_input_buf_csi() */
2230             for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2231             {
2232                 result[len++] = to[i];
2233                 if (to[i] == CSI)
2234                 {
2235                     result[len++] = KS_EXTRA;
2236                     result[len++] = (int)KE_CSI;
2237                 }
2238             }
2239             vim_free(to);
2240         }
2241     }
2242
2243     add_to_input_buf(result, len);
2244     err = noErr;
2245
2246 done:
2247     vim_free(text);
2248     if (err == noErr)
2249     {
2250         /* Fake event to wake up WNE (required to get
2251          * key repeat working */
2252         PostEvent(keyUp, 0);
2253         return noErr;
2254     }
2255
2256     return eventNotHandledErr;
2257 }
2258 #else
2259     void
2260 gui_mac_doKeyEvent(EventRecord *theEvent)
2261 {
2262     /* TODO: add support for COMMAND KEY */
2263     long                menu;
2264     unsigned char       string[20];
2265     short               num, i;
2266     short               len = 0;
2267     KeySym              key_sym;
2268     int                 key_char;
2269     int                 modifiers;
2270     int                 simplify = FALSE;
2271
2272     /* Mask the mouse (as per user setting) */
2273     if (p_mh)
2274         ObscureCursor();
2275
2276     /* Get the key code and it's ASCII representation */
2277     key_sym = ((theEvent->message & keyCodeMask) >> 8);
2278     key_char = theEvent->message & charCodeMask;
2279     num = 1;
2280
2281     /* Intercept CTRL-C */
2282     if (theEvent->modifiers & controlKey)
2283     {
2284         if (key_char == Ctrl_C && ctrl_c_interrupts)
2285             got_int = TRUE;
2286         else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2287                 && (key_char == '2' || key_char == '6'))
2288         {
2289             /* CTRL-^ and CTRL-@ don't work in the normal way. */
2290             if (key_char == '2')
2291                 key_char = Ctrl_AT;
2292             else
2293                 key_char = Ctrl_HAT;
2294             theEvent->modifiers = 0;
2295         }
2296     }
2297
2298     /* Intercept CMD-. */
2299     if (theEvent->modifiers & cmdKey)
2300         if (key_char == '.')
2301             got_int = TRUE;
2302
2303     /* Handle command key as per menu */
2304     /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2305     if (theEvent->modifiers & cmdKey)
2306         /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2307          * Why the mouse button? */
2308         if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2309         {
2310             menu = MenuKey(key_char);
2311             if (HiWord(menu))
2312             {
2313                 gui_mac_handle_menu(menu);
2314                 return;
2315             }
2316         }
2317
2318     /* Convert the modifiers */
2319     modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2320
2321
2322     /* Handle special keys. */
2323 #if 0
2324     /* Why has this been removed? */
2325     if  (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2326 #endif
2327     {
2328         /* Find the special key (for non-printable keyt_char) */
2329         if  ((key_char < 0x20) || (key_char == 0x7f))
2330             for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2331                 if (special_keys[i].key_sym == key_sym)
2332                 {
2333 # if 0
2334                     /* We currently don't have not so special key */
2335                     if (special_keys[i].vim_code1 == NUL)
2336                         key_char = special_keys[i].vim_code0;
2337                     else
2338 # endif
2339                         key_char = TO_SPECIAL(special_keys[i].vim_code0,
2340                                                 special_keys[i].vim_code1);
2341                     simplify = TRUE;
2342                     break;
2343                 }
2344     }
2345
2346     /* For some keys the modifier is included in the char itself. */
2347     if (simplify || key_char == TAB || key_char == ' ')
2348         key_char = simplify_key(key_char, &modifiers);
2349
2350     /* Add the modifier to the input bu if needed */
2351     /* Do not want SHIFT-A or CTRL-A with modifier */
2352     if (!IS_SPECIAL(key_char)
2353             && key_sym != vk_Space
2354             && key_sym != vk_Tab
2355             && key_sym != vk_Return
2356             && key_sym != vk_Enter
2357             && key_sym != vk_Esc)
2358     {
2359 #if 1
2360     /* Clear modifiers when only one modifier is set */
2361         if ((modifiers == MOD_MASK_SHIFT)
2362                 || (modifiers == MOD_MASK_CTRL)
2363                 || (modifiers == MOD_MASK_ALT))
2364             modifiers = 0;
2365 #else
2366         if (modifiers & MOD_MASK_CTRL)
2367             modifiers = modifiers & ~MOD_MASK_CTRL;
2368         if (modifiers & MOD_MASK_ALT)
2369             modifiers = modifiers & ~MOD_MASK_ALT;
2370         if (modifiers & MOD_MASK_SHIFT)
2371             modifiers = modifiers & ~MOD_MASK_SHIFT;
2372 #endif
2373     }
2374         if (modifiers)
2375         {
2376             string[len++] = CSI;
2377             string[len++] = KS_MODIFIER;
2378             string[len++] = modifiers;
2379         }
2380
2381         if (IS_SPECIAL(key_char))
2382         {
2383             string[len++] = CSI;
2384             string[len++] = K_SECOND(key_char);
2385             string[len++] = K_THIRD(key_char);
2386         }
2387         else
2388         {
2389 #ifdef FEAT_MBYTE
2390             /* Convert characters when needed (e.g., from MacRoman to latin1).
2391              * This doesn't work for the NUL byte. */
2392             if (input_conv.vc_type != CONV_NONE && key_char > 0)
2393             {
2394                 char_u  from[2], *to;
2395                 int     l;
2396
2397                 from[0] = key_char;
2398                 from[1] = NUL;
2399                 l = 1;
2400                 to = string_convert(&input_conv, from, &l);
2401                 if (to != NULL)
2402                 {
2403                     for (i = 0; i < l && len < 19; i++)
2404                     {
2405                         if (to[i] == CSI)
2406                         {
2407                             string[len++] = KS_EXTRA;
2408                             string[len++] = KE_CSI;
2409                         }
2410                         else
2411                             string[len++] = to[i];
2412                     }
2413                     vim_free(to);
2414                 }
2415                 else
2416                     string[len++] = key_char;
2417             }
2418             else
2419 #endif
2420                 string[len++] = key_char;
2421         }
2422
2423         if (len == 1 && string[0] == CSI)
2424         {
2425             /* Turn CSI into K_CSI. */
2426             string[ len++ ] = KS_EXTRA;
2427             string[ len++ ] = KE_CSI;
2428         }
2429
2430     add_to_input_buf(string, len);
2431 }
2432 #endif
2433
2434 /*
2435  * Handle MouseClick
2436  */
2437     void
2438 gui_mac_doMouseDownEvent(EventRecord *theEvent)
2439 {
2440     short               thePart;
2441     WindowPtr           whichWindow;
2442
2443     thePart = FindWindow(theEvent->where, &whichWindow);
2444
2445 #ifdef FEAT_GUI_TABLINE
2446     /* prevent that the vim window size changes if it's activated by a
2447        click into the tab pane */
2448     if (whichWindow == drawer)
2449         return;
2450 #endif
2451
2452     switch (thePart)
2453     {
2454         case (inDesk):
2455             /* TODO: what to do? */
2456             break;
2457
2458         case (inMenuBar):
2459             gui_mac_handle_menu(MenuSelect(theEvent->where));
2460             break;
2461
2462         case (inContent):
2463             gui_mac_doInContentClick(theEvent, whichWindow);
2464             break;
2465
2466         case (inDrag):
2467             gui_mac_doInDragClick(theEvent->where, whichWindow);
2468             break;
2469
2470         case (inGrow):
2471             gui_mac_doInGrowClick(theEvent->where, whichWindow);
2472             break;
2473
2474         case (inGoAway):
2475             if (TrackGoAway(whichWindow, theEvent->where))
2476                 gui_shell_closed();
2477             break;
2478
2479         case (inZoomIn):
2480         case (inZoomOut):
2481             gui_mac_doInZoomClick(theEvent, whichWindow);
2482             break;
2483     }
2484 }
2485
2486 /*
2487  * Handle MouseMoved
2488  * [this event is a moving in and out of a region]
2489  */
2490     void
2491 gui_mac_doMouseMovedEvent(EventRecord *event)
2492 {
2493     Point   thePoint;
2494     int_u   vimModifiers;
2495
2496     thePoint = event->where;
2497     GlobalToLocal(&thePoint);
2498     vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2499
2500     if (!Button())
2501         gui_mouse_moved(thePoint.h, thePoint.v);
2502     else
2503         if (!clickIsPopup)
2504             gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2505                                              thePoint.v, FALSE, vimModifiers);
2506
2507     /* Reset the region from which we move in and out */
2508     SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
2509                         FILL_Y(Y_2_ROW(thePoint.v)),
2510                         FILL_X(X_2_COL(thePoint.h)+1),
2511                         FILL_Y(Y_2_ROW(thePoint.v)+1));
2512
2513     if (dragRectEnbl)
2514         dragRectControl = kCreateRect;
2515
2516 }
2517
2518 /*
2519  * Handle the mouse release
2520  */
2521     void
2522 gui_mac_doMouseUpEvent(EventRecord *theEvent)
2523 {
2524     Point   thePoint;
2525     int_u   vimModifiers;
2526
2527     /* TODO: Properly convert the Contextual menu mouse-up */
2528     /*       Potential source of the double menu */
2529     lastMouseTick = theEvent->when;
2530     dragRectEnbl = FALSE;
2531     dragRectControl = kCreateEmpty;
2532     thePoint = theEvent->where;
2533     GlobalToLocal(&thePoint);
2534
2535     vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
2536     if (clickIsPopup)
2537     {
2538         vimModifiers &= ~MOUSE_CTRL;
2539         clickIsPopup = FALSE;
2540     }
2541     gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
2542 }
2543
2544     static pascal OSStatus
2545 gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2546                                                                    void *data)
2547 {
2548     Point       point;
2549     Rect        bounds;
2550     UInt32      mod;
2551     SInt32      delta;
2552     int_u       vim_mod;
2553     EventMouseWheelAxis axis;
2554
2555     if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2556                           typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2557             && axis != kEventMouseWheelAxisY)
2558         goto bail; /* Vim only does up-down scrolling */
2559
2560     if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2561                               typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2562         goto bail;
2563     if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2564                               typeQDPoint, NULL, sizeof(Point), NULL, &point))
2565         goto bail;
2566     if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2567                                 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2568         goto bail;
2569
2570     vim_mod = 0;
2571     if (mod & shiftKey)
2572         vim_mod |= MOUSE_SHIFT;
2573     if (mod & controlKey)
2574         vim_mod |= MOUSE_CTRL;
2575     if (mod & optionKey)
2576         vim_mod |= MOUSE_ALT;
2577
2578     if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2579     {
2580         point.h -= bounds.left;
2581         point.v -= bounds.top;
2582     }
2583
2584     gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2585                                             point.h, point.v, FALSE, vim_mod);
2586
2587     /* post a bogus event to wake up WaitNextEvent */
2588     PostEvent(keyUp, 0);
2589
2590     return noErr;
2591
2592 bail:
2593     /*
2594      * when we fail give any additional callback handler a chance to perform
2595      * it's actions
2596      */
2597     return CallNextEventHandler(nextHandler, theEvent);
2598 }
2599
2600      void
2601 gui_mch_mousehide(int hide)
2602 {
2603     /* TODO */
2604 }
2605
2606 #if 0
2607
2608 /*
2609  * This would be the normal way of invoking the contextual menu
2610  * but the Vim API doesn't seem to a support a request to get
2611  * the menu that we should display
2612  */
2613     void
2614 gui_mac_handle_contextual_menu(event)
2615     EventRecord *event;
2616 {
2617 /*
2618  *  Clone PopUp to use menu
2619  *  Create a object descriptor for the current selection
2620  *  Call the procedure
2621  */
2622
2623 //  Call to Handle Popup
2624     OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2625
2626     if (status != noErr)
2627         return;
2628
2629     if (CntxType == kCMMenuItemSelected)
2630     {
2631         /* Handle the menu CntxMenuID, CntxMenuItem */
2632         /* The submenu can be handle directly by gui_mac_handle_menu */
2633         /* But what about the current menu, is the meny changed by ContextualMenuSelect */
2634         gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
2635     }
2636     else if (CntxMenuID == kCMShowHelpSelected)
2637     {
2638         /* Should come up with the help */
2639     }
2640
2641 }
2642 #endif
2643
2644 /*
2645  * Handle menubar selection
2646  */
2647     void
2648 gui_mac_handle_menu(long menuChoice)
2649 {
2650     short       menu = HiWord(menuChoice);
2651     short       item = LoWord(menuChoice);
2652     vimmenu_T   *theVimMenu = root_menu;
2653
2654     if (menu == 256)  /* TODO: use constant or gui.xyz */
2655     {
2656         if (item == 1)
2657             gui_mch_beep(); /* TODO: Popup dialog or do :intro */
2658     }
2659     else if (item != 0)
2660     {
2661         theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2662
2663         if (theVimMenu)
2664             gui_menu_cb(theVimMenu);
2665     }
2666     HiliteMenu(0);
2667 }
2668
2669 /*
2670  * Dispatch the event to proper handler
2671  */
2672
2673     void
2674 gui_mac_handle_event(EventRecord *event)
2675 {
2676     OSErr       error;
2677
2678     /* Handle contextual menu right now (if needed) */
2679     if (IsShowContextualMenuClick(event))
2680     {
2681 # if 0
2682         gui_mac_handle_contextual_menu(event);
2683 # else
2684         gui_mac_doMouseDownEvent(event);
2685 # endif
2686         return;
2687     }
2688
2689     /* Handle normal event */
2690     switch (event->what)
2691     {
2692 #ifndef USE_CARBONKEYHANDLER
2693         case (keyDown):
2694         case (autoKey):
2695             gui_mac_doKeyEvent(event);
2696             break;
2697 #endif
2698         case (keyUp):
2699             /* We don't care about when the key is released */
2700             break;
2701
2702         case (mouseDown):
2703             gui_mac_doMouseDownEvent(event);
2704             break;
2705
2706         case (mouseUp):
2707             gui_mac_doMouseUpEvent(event);
2708             break;
2709
2710         case (updateEvt):
2711             gui_mac_doUpdateEvent(event);
2712             break;
2713
2714         case (diskEvt):
2715             /* We don't need special handling for disk insertion */
2716             break;
2717
2718         case (activateEvt):
2719             gui_mac_doActivateEvent(event);
2720             break;
2721
2722         case (osEvt):
2723             switch ((event->message >> 24) & 0xFF)
2724             {
2725                 case (0xFA): /* mouseMovedMessage */
2726                     gui_mac_doMouseMovedEvent(event);
2727                     break;
2728                 case (0x01): /* suspendResumeMessage */
2729                     gui_mac_doSuspendEvent(event);
2730                     break;
2731             }
2732             break;
2733
2734 #ifdef USE_AEVENT
2735         case (kHighLevelEvent):
2736             /* Someone's talking to us, through AppleEvents */
2737             error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2738             break;
2739 #endif
2740     }
2741 }
2742
2743 /*
2744  * ------------------------------------------------------------
2745  * Unknown Stuff
2746  * ------------------------------------------------------------
2747  */
2748
2749
2750     GuiFont
2751 gui_mac_find_font(char_u *font_name)
2752 {
2753     char_u      c;
2754     char_u      *p;
2755     char_u      pFontName[256];
2756     Str255      systemFontname;
2757     short       font_id;
2758     short       size=9;
2759     GuiFont     font;
2760 #if 0
2761     char_u      *fontNamePtr;
2762 #endif
2763
2764     for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2765         ;
2766
2767     c = *p;
2768     *p = 0;
2769
2770 #if 1
2771     STRCPY(&pFontName[1], font_name);
2772     pFontName[0] = STRLEN(font_name);
2773     *p = c;
2774
2775     /* Get the font name, minus the style suffix (:h, etc) */
2776     char_u fontName[256];
2777     char_u *styleStart = vim_strchr(font_name, ':');
2778     size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2779     vim_strncpy(fontName, font_name, fontNameLen);
2780
2781     ATSUFontID fontRef;
2782     FMFontStyle fontStyle;
2783     font_id = 0;
2784
2785     if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2786                 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2787                 &fontRef) == noErr)
2788     {
2789         if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2790             font_id = 0;
2791     }
2792
2793     if (font_id == 0)
2794     {
2795         /*
2796          * Try again, this time replacing underscores in the font name
2797          * with spaces (:set guifont allows the two to be used
2798          * interchangeably; the Font Manager doesn't).
2799          */
2800         int i, changed = FALSE;
2801
2802         for (i = pFontName[0]; i > 0; --i)
2803         {
2804             if (pFontName[i] == '_')
2805             {
2806                 pFontName[i] = ' ';
2807                 changed = TRUE;
2808             }
2809         }
2810         if (changed)
2811             if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2812                         kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2813                         kFontNoLanguageCode, &fontRef) == noErr)
2814             {
2815                 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2816                     font_id = 0;
2817             }
2818     }
2819
2820 #else
2821     /* name = C2Pascal_save(menu->dname); */
2822     fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2823
2824     GetFNum(fontNamePtr, &font_id);
2825 #endif
2826
2827
2828     if (font_id == 0)
2829     {
2830         /* Oups, the system font was it the one the user want */
2831
2832         if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2833             return NOFONT;
2834         if (!EqualString(pFontName, systemFontname, false, false))
2835             return NOFONT;
2836     }
2837     if (*p == ':')
2838     {
2839         p++;
2840         /* Set the values found after ':' */
2841         while (*p)
2842         {
2843             switch (*p++)
2844             {
2845                 case 'h':
2846                     size = points_to_pixels(p, &p, TRUE);
2847                     break;
2848                     /*
2849                      * TODO: Maybe accept width and styles
2850                      */
2851             }
2852             while (*p == ':')
2853                 p++;
2854         }
2855     }
2856
2857     if (size < 1)
2858         size = 1;   /* Avoid having a size of 0 with system font */
2859
2860     font = (size << 16) + ((long) font_id & 0xFFFF);
2861
2862     return font;
2863 }
2864
2865 /*
2866  * ------------------------------------------------------------
2867  * GUI_MCH functionality
2868  * ------------------------------------------------------------
2869  */
2870
2871 /*
2872  * Parse the GUI related command-line arguments.  Any arguments used are
2873  * deleted from argv, and *argc is decremented accordingly.  This is called
2874  * when vim is started, whether or not the GUI has been started.
2875  */
2876     void
2877 gui_mch_prepare(int *argc, char **argv)
2878 {
2879     /* TODO: Move most of this stuff toward gui_mch_init */
2880 #ifdef USE_EXE_NAME
2881     FSSpec      applDir;
2882 # ifndef USE_FIND_BUNDLE_PATH
2883     short       applVRefNum;
2884     long        applDirID;
2885     Str255      volName;
2886 # else
2887     ProcessSerialNumber psn;
2888     FSRef       applFSRef;
2889 # endif
2890 #endif
2891
2892 #if 0
2893     InitCursor();
2894
2895     RegisterAppearanceClient();
2896
2897 #ifdef USE_AEVENT
2898     (void) InstallAEHandlers();
2899 #endif
2900
2901     pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
2902
2903     AppendMenu(pomme, "\pAbout VIM");
2904
2905     InsertMenu(pomme, 0);
2906
2907     DrawMenuBar();
2908
2909
2910 #ifndef USE_OFFSETED_WINDOW
2911     SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
2912 #else
2913     SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
2914 #endif
2915
2916
2917     CreateNewWindow(kDocumentWindowClass,
2918                 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
2919                 &windRect, &gui.VimWindow);
2920     SetPortWindowPort(gui.VimWindow);
2921
2922     gui.char_width = 7;
2923     gui.char_height = 11;
2924     gui.char_ascent = 6;
2925     gui.num_rows = 24;
2926     gui.num_cols = 80;
2927     gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2928
2929     gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2930     gScrollDrag   = NewControlActionUPP(gui_mac_drag_thumb);
2931
2932     dragRectEnbl = FALSE;
2933     dragRgn = NULL;
2934     dragRectControl = kCreateEmpty;
2935     cursorRgn = NewRgn();
2936 #endif
2937 #ifdef USE_EXE_NAME
2938 # ifndef USE_FIND_BUNDLE_PATH
2939     HGetVol(volName, &applVRefNum, &applDirID);
2940     /* TN2015: mention a possible bad VRefNum */
2941     FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
2942 # else
2943     /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2944      * of TN2015
2945      */
2946     (void)GetCurrentProcess(&psn);
2947     /* if (err != noErr) return err; */
2948
2949     (void)GetProcessBundleLocation(&psn, &applFSRef);
2950     /* if (err != noErr) return err; */
2951
2952     (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
2953
2954     /* This technic return NIL when we disallow_gui */
2955 # endif
2956     exe_name = FullPathFromFSSpec_save(applDir);
2957 #endif
2958 }
2959
2960 #ifndef ALWAYS_USE_GUI
2961 /*
2962  * Check if the GUI can be started.  Called before gvimrc is sourced.
2963  * Return OK or FAIL.
2964  */
2965     int
2966 gui_mch_init_check(void)
2967 {
2968     /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2969      * using the >console
2970      */
2971     if (disallow_gui) /* see main.c for reason to disallow */
2972         return FAIL;
2973     return OK;
2974 }
2975 #endif
2976
2977     static OSErr
2978 receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
2979 {
2980     int         x, y;
2981     int_u       modifiers;
2982     char_u      **fnames = NULL;
2983     int         count;
2984     int         i, j;
2985
2986     /* Get drop position, modifiers and count of items */
2987     {
2988         Point   point;
2989         SInt16  mouseUpModifiers;
2990         UInt16  countItem;
2991
2992         GetDragMouse(theDrag, &point, NULL);
2993         GlobalToLocal(&point);
2994         x = point.h;
2995         y = point.v;
2996         GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2997         modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2998         CountDragItems(theDrag, &countItem);
2999         count = countItem;
3000     }
3001
3002     fnames = (char_u **)alloc(count * sizeof(char_u *));
3003     if (fnames == NULL)
3004         return dragNotAcceptedErr;
3005
3006     /* Get file names dropped */
3007     for (i = j = 0; i < count; ++i)
3008     {
3009         DragItemRef     item;
3010         OSErr           err;
3011         Size            size;
3012         FlavorType      type = flavorTypeHFS;
3013         HFSFlavor       hfsFlavor;
3014
3015         fnames[i] = NULL;
3016         GetDragItemReferenceNumber(theDrag, i + 1, &item);
3017         err = GetFlavorDataSize(theDrag, item, type, &size);
3018         if (err != noErr || size > sizeof(hfsFlavor))
3019             continue;
3020         err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3021         if (err != noErr)
3022             continue;
3023         fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3024     }
3025     count = j;
3026
3027     gui_handle_drop(x, y, modifiers, fnames, count);
3028
3029     /* Fake mouse event to wake from stall */
3030     PostEvent(mouseUp, 0);
3031
3032     return noErr;
3033 }
3034
3035 /*
3036  * Initialise the GUI.  Create all the windows, set up all the call-backs
3037  * etc.
3038  */
3039     int
3040 gui_mch_init(void)
3041 {
3042     /* TODO: Move most of this stuff toward gui_mch_init */
3043     Rect            windRect;
3044     MenuHandle      pomme;
3045     EventHandlerRef mouseWheelHandlerRef;
3046     EventTypeSpec   eventTypeSpec;
3047     ControlRef      rootControl;
3048
3049     if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
3050         gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
3051
3052 #if 1
3053     InitCursor();
3054
3055     RegisterAppearanceClient();
3056
3057 #ifdef USE_AEVENT
3058     (void) InstallAEHandlers();
3059 #endif
3060
3061     pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
3062
3063     AppendMenu(pomme, "\pAbout VIM");
3064
3065     InsertMenu(pomme, 0);
3066
3067     DrawMenuBar();
3068
3069
3070 #ifndef USE_OFFSETED_WINDOW
3071     SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
3072 #else
3073     SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
3074 #endif
3075
3076     gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
3077                         zoomDocProc,
3078                         (WindowPtr)-1L, true, 0);
3079     CreateRootControl(gui.VimWindow, &rootControl);
3080     InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3081             gui.VimWindow, NULL);
3082     SetPortWindowPort(gui.VimWindow);
3083
3084     gui.char_width = 7;
3085     gui.char_height = 11;
3086     gui.char_ascent = 6;
3087     gui.num_rows = 24;
3088     gui.num_cols = 80;
3089     gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3090
3091     gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3092     gScrollDrag   = NewControlActionUPP(gui_mac_drag_thumb);
3093
3094     /* Install Carbon event callbacks. */
3095     (void)InstallFontPanelHandler();
3096
3097     dragRectEnbl = FALSE;
3098     dragRgn = NULL;
3099     dragRectControl = kCreateEmpty;
3100     cursorRgn = NewRgn();
3101 #endif
3102     /* Display any pending error messages */
3103     display_errors();
3104
3105     /* Get background/foreground colors from system */
3106     /* TODO: do the appropriate call to get real defaults */
3107     gui.norm_pixel = 0x00000000;
3108     gui.back_pixel = 0x00FFFFFF;
3109
3110     /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3111      * file). */
3112     set_normal_colors();
3113
3114     /*
3115      * Check that none of the colors are the same as the background color.
3116      * Then store the current values as the defaults.
3117      */
3118     gui_check_colors();
3119     gui.def_norm_pixel = gui.norm_pixel;
3120     gui.def_back_pixel = gui.back_pixel;
3121
3122     /* Get the colors for the highlight groups (gui_check_colors() might have
3123      * changed them) */
3124     highlight_gui_started();
3125
3126     /*
3127      * Setting the gui constants
3128      */
3129 #ifdef FEAT_MENU
3130     gui.menu_height = 0;
3131 #endif
3132     gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3133     gui.border_offset = gui.border_width = 2;
3134
3135     /* If Quartz-style text anti aliasing is available (see
3136        gui_mch_draw_string() below), enable it for all font sizes. */
3137     vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
3138
3139     eventTypeSpec.eventClass = kEventClassMouse;
3140     eventTypeSpec.eventKind = kEventMouseWheelMoved;
3141     mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3142     if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3143                                  &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3144     {
3145         mouseWheelHandlerRef = NULL;
3146         DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3147         mouseWheelHandlerUPP = NULL;
3148     }
3149
3150 #ifdef USE_CARBONKEYHANDLER
3151     InterfaceTypeList supportedServices = { kUnicodeDocument };
3152     NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3153
3154     /* We don't support inline input yet, use input window by default */
3155     UseInputWindow(gTSMDocument, TRUE);
3156
3157     /* Should we activate the document by default? */
3158     // ActivateTSMDocument(gTSMDocument);
3159
3160     EventTypeSpec textEventTypes[] = {
3161         { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3162         { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3163         { kEventClassTextInput, kEventTextInputPosToOffset },
3164         { kEventClassTextInput, kEventTextInputOffsetToPos },
3165     };
3166
3167     keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3168     if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3169                                                 NR_ELEMS(textEventTypes),
3170                                                 textEventTypes, NULL, NULL))
3171     {
3172         DisposeEventHandlerUPP(keyEventHandlerUPP);
3173         keyEventHandlerUPP = NULL;
3174     }
3175
3176     EventTypeSpec windowEventTypes[] = {
3177         { kEventClassWindow, kEventWindowActivated },
3178         { kEventClassWindow, kEventWindowDeactivated },
3179     };
3180
3181     /* Install window event handler to support TSMDocument activate and
3182      * deactivate */
3183     winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3184     if (noErr != InstallWindowEventHandler(gui.VimWindow,
3185                                            winEventHandlerUPP,
3186                                            NR_ELEMS(windowEventTypes),
3187                                            windowEventTypes, NULL, NULL))
3188     {
3189         DisposeEventHandlerUPP(winEventHandlerUPP);
3190         winEventHandlerUPP = NULL;
3191     }
3192 #endif
3193
3194 /*
3195 #ifdef FEAT_MBYTE
3196     set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3197 #endif
3198 */
3199
3200 #ifdef FEAT_GUI_TABLINE
3201     /*
3202      * Create the tabline
3203      */
3204     initialise_tabline();
3205 #endif
3206
3207     /* TODO: Load bitmap if using TOOLBAR */
3208     return OK;
3209 }
3210
3211 /*
3212  * Called when the foreground or background color has been changed.
3213  */
3214     void
3215 gui_mch_new_colors(void)
3216 {
3217     /* TODO:
3218      * This proc is called when Normal is set to a value
3219      * so what msut be done? I don't know
3220      */
3221 }
3222
3223 /*
3224  * Open the GUI window which was created by a call to gui_mch_init().
3225  */
3226     int
3227 gui_mch_open(void)
3228 {
3229     ShowWindow(gui.VimWindow);
3230
3231     if (gui_win_x != -1 && gui_win_y != -1)
3232         gui_mch_set_winpos(gui_win_x, gui_win_y);
3233
3234     /*
3235      * Make the GUI the foreground process (in case it was launched
3236      * from the Terminal or via :gui).
3237      */
3238     {
3239         ProcessSerialNumber psn;
3240         if (GetCurrentProcess(&psn) == noErr)
3241             SetFrontProcess(&psn);
3242     }
3243
3244     return OK;
3245 }
3246
3247 #ifdef USE_ATSUI_DRAWING
3248     static void
3249 gui_mac_dispose_atsui_style(void)
3250 {
3251     if (p_macatsui && gFontStyle)
3252         ATSUDisposeStyle(gFontStyle);
3253 #ifdef FEAT_MBYTE
3254     if (p_macatsui && gWideFontStyle)
3255         ATSUDisposeStyle(gWideFontStyle);
3256 #endif
3257 }
3258 #endif
3259
3260     void
3261 gui_mch_exit(int rc)
3262 {
3263     /* TODO: find out all what is missing here? */
3264     DisposeRgn(cursorRgn);
3265
3266 #ifdef USE_CARBONKEYHANDLER
3267     if (keyEventHandlerUPP)
3268         DisposeEventHandlerUPP(keyEventHandlerUPP);
3269 #endif
3270
3271     if (mouseWheelHandlerUPP != NULL)
3272         DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3273
3274 #ifdef USE_ATSUI_DRAWING
3275     gui_mac_dispose_atsui_style();
3276 #endif
3277
3278 #ifdef USE_CARBONKEYHANDLER
3279     FixTSMDocument(gTSMDocument);
3280     DeactivateTSMDocument(gTSMDocument);
3281     DeleteTSMDocument(gTSMDocument);
3282 #endif
3283
3284     /* Exit to shell? */
3285     exit(rc);
3286 }
3287
3288 /*
3289  * Get the position of the top left corner of the window.
3290  */
3291     int
3292 gui_mch_get_winpos(int *x, int *y)
3293 {
3294     /* TODO */
3295     Rect        bounds;
3296     OSStatus    status;
3297
3298     /* Carbon >= 1.0.2, MacOS >= 8.5 */
3299     status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
3300
3301     if (status != noErr)
3302         return FAIL;
3303     *x = bounds.left;
3304     *y = bounds.top;
3305     return OK;
3306     return FAIL;
3307 }
3308
3309 /*
3310  * Set the position of the top left corner of the window to the given
3311  * coordinates.
3312  */
3313     void
3314 gui_mch_set_winpos(int x, int y)
3315 {
3316     /* TODO:  Should make sure the window is move within range
3317      *        e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3318      */
3319     MoveWindowStructure(gui.VimWindow, x, y);
3320 }
3321
3322     void
3323 gui_mch_set_shellsize(
3324     int         width,
3325     int         height,
3326     int         min_width,
3327     int         min_height,
3328     int         base_width,
3329     int         base_height,
3330     int         direction)
3331 {
3332     CGrafPtr    VimPort;
3333     Rect        VimBound;
3334
3335     if (gui.which_scrollbars[SBAR_LEFT])
3336     {
3337         VimPort = GetWindowPort(gui.VimWindow);
3338         GetPortBounds(VimPort, &VimBound);
3339         VimBound.left = -gui.scrollbar_width; /* + 1;*/
3340         SetPortBounds(VimPort, &VimBound);
3341     /*  GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
3342     }
3343     else
3344     {
3345         VimPort = GetWindowPort(gui.VimWindow);
3346         GetPortBounds(VimPort, &VimBound);
3347         VimBound.left = 0;
3348         SetPortBounds(VimPort, &VimBound);
3349     }
3350
3351     SizeWindow(gui.VimWindow, width, height, TRUE);
3352
3353     gui_resize_shell(width, height);
3354 }
3355
3356 /*
3357  * Get the screen dimensions.
3358  * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3359  * Is there no way to find out how wide the borders really are?
3360  * TODO: Add live update of those value on suspend/resume.
3361  */
3362     void
3363 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
3364 {
3365     GDHandle    dominantDevice = GetMainDevice();
3366     Rect        screenRect = (**dominantDevice).gdRect;
3367
3368     *screen_w = screenRect.right - 10;
3369     *screen_h = screenRect.bottom - 40;
3370 }
3371
3372
3373 /*
3374  * Open the Font Panel and wait for the user to select a font and
3375  * close the panel.  Then fill the buffer pointed to by font_name with
3376  * the name and size of the selected font and return the font's handle,
3377  * or NOFONT in case of an error.
3378  */
3379     static GuiFont
3380 gui_mac_select_font(char_u *font_name)
3381 {
3382     GuiFont                 selected_font = NOFONT;
3383     OSStatus                status;
3384     FontSelectionQDStyle    curr_font;
3385
3386     /* Initialize the Font Panel with the current font. */
3387     curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3388     curr_font.size = (gui.norm_font >> 16);
3389     /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3390     curr_font.instance.fontStyle = 0;
3391     curr_font.hasColor = false;
3392     curr_font.version = 0; /* version number of the style structure */
3393     status = SetFontInfoForSelection(kFontSelectionQDType,
3394             /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3395
3396     gFontPanelInfo.family = curr_font.instance.fontFamily;
3397     gFontPanelInfo.style = curr_font.instance.fontStyle;
3398     gFontPanelInfo.size = curr_font.size;
3399
3400     /* Pop up the Font Panel. */
3401     status = FPShowHideFontPanel();
3402     if (status == noErr)
3403     {
3404         /*
3405          * The Font Panel is modeless.  We really need it to be modal,
3406          * so we spin in an event loop until the panel is closed.
3407          */
3408         gFontPanelInfo.isPanelVisible = true;
3409         while (gFontPanelInfo.isPanelVisible)
3410         {
3411             EventRecord e;
3412             WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3413         }
3414
3415         GetFontPanelSelection(font_name);
3416         selected_font = gui_mac_find_font(font_name);
3417     }
3418     return selected_font;
3419 }
3420
3421 #ifdef USE_ATSUI_DRAWING
3422     static void
3423 gui_mac_create_atsui_style(void)
3424 {
3425     if (p_macatsui && gFontStyle == NULL)
3426     {
3427         if (ATSUCreateStyle(&gFontStyle) != noErr)
3428             gFontStyle = NULL;
3429     }
3430 #ifdef FEAT_MBYTE
3431     if (p_macatsui && gWideFontStyle == NULL)
3432     {
3433         if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3434             gWideFontStyle = NULL;
3435     }
3436 #endif
3437
3438     p_macatsui_last = p_macatsui;
3439 }
3440 #endif
3441
3442 /*
3443  * Initialise vim to use the font with the given name.  Return FAIL if the font
3444  * could not be loaded, OK otherwise.
3445  */
3446     int
3447 gui_mch_init_font(char_u *font_name, int fontset)
3448 {
3449     /* TODO: Add support for bold italic underline proportional etc... */
3450     Str255      suggestedFont = "\pMonaco";
3451     int         suggestedSize = 10;
3452     FontInfo    font_info;
3453     short       font_id;
3454     GuiFont     font;
3455     char_u      used_font_name[512];
3456
3457 #ifdef USE_ATSUI_DRAWING
3458     gui_mac_create_atsui_style();
3459 #endif
3460
3461     if (font_name == NULL)
3462     {
3463         /* First try to get the suggested font */
3464         GetFNum(suggestedFont, &font_id);
3465
3466         if (font_id == 0)
3467         {
3468             /* Then pickup the standard application font */
3469             font_id = GetAppFont();
3470             STRCPY(used_font_name, "default");
3471         }
3472         else
3473             STRCPY(used_font_name, "Monaco");
3474         font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3475     }
3476     else if (STRCMP(font_name, "*") == 0)
3477     {
3478         char_u *new_p_guifont;
3479
3480         font = gui_mac_select_font(used_font_name);
3481         if (font == NOFONT)
3482             return FAIL;
3483
3484         /* Set guifont to the name of the selected font. */
3485         new_p_guifont = alloc(STRLEN(used_font_name) + 1);
3486         if (new_p_guifont != NULL)
3487         {
3488             STRCPY(new_p_guifont, used_font_name);
3489             vim_free(p_guifont);
3490             p_guifont = new_p_guifont;
3491             /* Replace spaces in the font name with underscores. */
3492             for ( ; *new_p_guifont; ++new_p_guifont)
3493             {
3494                 if (*new_p_guifont == ' ')
3495                     *new_p_guifont = '_';
3496             }
3497         }
3498     }
3499     else
3500     {
3501         font = gui_mac_find_font(font_name);
3502         vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
3503
3504         if (font == NOFONT)
3505             return FAIL;
3506     }
3507
3508     gui.norm_font = font;
3509
3510     hl_set_font_name(used_font_name);
3511
3512     TextSize(font >> 16);
3513     TextFont(font & 0xFFFF);
3514
3515     GetFontInfo(&font_info);
3516
3517     gui.char_ascent = font_info.ascent;
3518     gui.char_width  = CharWidth('_');
3519     gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3520
3521 #ifdef USE_ATSUI_DRAWING
3522     if (p_macatsui && gFontStyle)
3523         gui_mac_set_font_attributes(font);
3524 #endif
3525
3526     return OK;
3527 }
3528
3529 /*
3530  * Adjust gui.char_height (after 'linespace' was changed).
3531  */
3532     int
3533 gui_mch_adjust_charheight(void)
3534 {
3535     FontInfo    font_info;
3536
3537     GetFontInfo(&font_info);
3538     gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3539     gui.char_ascent = font_info.ascent + p_linespace / 2;
3540     return OK;
3541 }
3542
3543 /*
3544  * Get a font structure for highlighting.
3545  */
3546     GuiFont
3547 gui_mch_get_font(char_u *name, int giveErrorIfMissing)
3548 {
3549     GuiFont font;
3550
3551     font = gui_mac_find_font(name);
3552
3553     if (font == NOFONT)
3554     {
3555         if (giveErrorIfMissing)
3556             EMSG2(_(e_font), name);
3557         return NOFONT;
3558     }
3559     /*
3560      * TODO : Accept only monospace
3561      */
3562
3563     return font;
3564 }
3565
3566 #if defined(FEAT_EVAL) || defined(PROTO)
3567 /*
3568  * Return the name of font "font" in allocated memory.
3569  * Don't know how to get the actual name, thus use the provided name.
3570  */
3571     char_u *
3572 gui_mch_get_fontname(GuiFont font, char_u *name)
3573 {
3574     if (name == NULL)
3575         return NULL;
3576     return vim_strsave(name);
3577 }
3578 #endif
3579
3580 #ifdef USE_ATSUI_DRAWING
3581     static void
3582 gui_mac_set_font_attributes(GuiFont font)
3583 {
3584     ATSUFontID  fontID;
3585     Fixed       fontSize;
3586     Fixed       fontWidth;
3587
3588     fontID    = font & 0xFFFF;
3589     fontSize  = Long2Fix(font >> 16);
3590     fontWidth = Long2Fix(gui.char_width);
3591
3592     ATSUAttributeTag attribTags[] =
3593     {
3594         kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3595         kATSUMaxATSUITagValue + 1
3596     };
3597
3598     ByteCount attribSizes[] =
3599     {
3600         sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3601         sizeof(font)
3602     };
3603
3604     ATSUAttributeValuePtr attribValues[] =
3605     {
3606         &fontID, &fontSize, &fontWidth, &font
3607     };
3608
3609     if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3610     {
3611         if (ATSUSetAttributes(gFontStyle,
3612                     (sizeof attribTags) / sizeof(ATSUAttributeTag),
3613                     attribTags, attribSizes, attribValues) != noErr)
3614         {
3615 # ifndef NDEBUG
3616             fprintf(stderr, "couldn't set font style\n");
3617 # endif
3618             ATSUDisposeStyle(gFontStyle);
3619             gFontStyle = NULL;
3620         }
3621
3622 #ifdef FEAT_MBYTE
3623         if (has_mbyte)
3624         {
3625             /* FIXME: we should use a more mbyte sensitive way to support
3626              * wide font drawing */
3627             fontWidth = Long2Fix(gui.char_width * 2);
3628
3629             if (ATSUSetAttributes(gWideFontStyle,
3630                         (sizeof attribTags) / sizeof(ATSUAttributeTag),
3631                         attribTags, attribSizes, attribValues) != noErr)
3632             {
3633                 ATSUDisposeStyle(gWideFontStyle);
3634                 gWideFontStyle = NULL;
3635             }
3636         }
3637 #endif
3638     }
3639 }
3640 #endif
3641
3642 /*
3643  * Set the current text font.
3644  */
3645     void
3646 gui_mch_set_font(GuiFont font)
3647 {
3648 #ifdef USE_ATSUI_DRAWING
3649     GuiFont                     currFont;
3650     ByteCount                   actualFontByteCount;
3651
3652     if (p_macatsui && gFontStyle)
3653     {
3654         /* Avoid setting same font again */
3655         if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3656                     sizeof(font), &currFont, &actualFontByteCount) == noErr
3657                 && actualFontByteCount == (sizeof font))
3658         {
3659             if (currFont == font)
3660                 return;
3661         }
3662
3663         gui_mac_set_font_attributes(font);
3664     }
3665
3666     if (p_macatsui && !gIsFontFallbackSet)
3667     {
3668         /* Setup automatic font substitution. The user's guifontwide
3669          * is tried first, then the system tries other fonts. */
3670 /*
3671         ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3672         ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3673         ATSUCreateFontFallbacks(&gFontFallbacks);
3674         ATSUSetObjFontFallbacks(gFontFallbacks, );
3675 */
3676         if (gui.wide_font)
3677         {
3678             ATSUFontID fallbackFonts;
3679             gIsFontFallbackSet = TRUE;
3680
3681             if (FMGetFontFromFontFamilyInstance(
3682                         (gui.wide_font & 0xFFFF),
3683                         0,
3684                         &fallbackFonts,
3685                         NULL) == noErr)
3686             {
3687                 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3688                                      &fallbackFonts,
3689                                      kATSUSequentialFallbacksPreferred);
3690             }
3691 /*
3692         ATSUAttributeValuePtr fallbackValues[] = { };
3693 */
3694         }
3695     }
3696 #endif
3697     TextSize(font >> 16);
3698     TextFont(font & 0xFFFF);
3699 }
3700
3701 /*
3702  * If a font is not going to be used, free its structure.
3703  */
3704     void
3705 gui_mch_free_font(font)
3706     GuiFont     font;
3707 {
3708     /*
3709      * Free font when "font" is not 0.
3710      * Nothing to do in the current implementation, since
3711      * nothing is allocated for each font used.
3712      */
3713 }
3714
3715     static int
3716 hex_digit(int c)
3717 {
3718     if (isdigit(c))
3719         return c - '0';
3720     c = TOLOWER_ASC(c);
3721     if (c >= 'a' && c <= 'f')
3722         return c - 'a' + 10;
3723     return -1000;
3724 }
3725
3726 /*
3727  * Return the Pixel value (color) for the given color name.  This routine was
3728  * pretty much taken from example code in the Silicon Graphics OSF/Motif
3729  * Programmer's Guide.
3730  * Return INVALCOLOR when failed.
3731  */
3732     guicolor_T
3733 gui_mch_get_color(char_u *name)
3734 {
3735     /* TODO: Add support for the new named color of MacOS 8
3736      */
3737     RGBColor    MacColor;
3738 //    guicolor_T        color = 0;
3739
3740     typedef struct guicolor_tTable
3741     {
3742         char        *name;
3743         guicolor_T  color;
3744     } guicolor_tTable;
3745
3746     /*
3747      * The comment at the end of each line is the source
3748      * (Mac, Window, Unix) and the number is the unix rgb.txt value
3749      */
3750     static guicolor_tTable table[] =
3751     {
3752         {"Black",       RGB(0x00, 0x00, 0x00)},
3753         {"darkgray",    RGB(0x80, 0x80, 0x80)}, /*W*/
3754         {"darkgrey",    RGB(0x80, 0x80, 0x80)}, /*W*/
3755         {"Gray",        RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3756         {"Grey",        RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3757         {"lightgray",   RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3758         {"lightgrey",   RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3759         {"gray10",      RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3760         {"grey10",      RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3761         {"gray20",      RGB(0x33, 0x33, 0x33)}, /*W*/
3762         {"grey20",      RGB(0x33, 0x33, 0x33)}, /*W*/
3763         {"gray30",      RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3764         {"grey30",      RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3765         {"gray40",      RGB(0x66, 0x66, 0x66)}, /*W*/
3766         {"grey40",      RGB(0x66, 0x66, 0x66)}, /*W*/
3767         {"gray50",      RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3768         {"grey50",      RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3769         {"gray60",      RGB(0x99, 0x99, 0x99)}, /*W*/
3770         {"grey60",      RGB(0x99, 0x99, 0x99)}, /*W*/
3771         {"gray70",      RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3772         {"grey70",      RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3773         {"gray80",      RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3774         {"grey80",      RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3775         {"gray90",      RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3776         {"grey90",      RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3777         {"white",       RGB(0xFF, 0xFF, 0xFF)},
3778         {"darkred",     RGB(0x80, 0x00, 0x00)}, /*W*/
3779         {"red",         RGB(0xDD, 0x08, 0x06)}, /*M*/
3780         {"lightred",    RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3781         {"DarkBlue",    RGB(0x00, 0x00, 0x80)}, /*W*/
3782         {"Blue",        RGB(0x00, 0x00, 0xD4)}, /*M*/
3783         {"lightblue",   RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3784         {"DarkGreen",   RGB(0x00, 0x80, 0x00)}, /*W*/
3785         {"Green",       RGB(0x00, 0x64, 0x11)}, /*M*/
3786         {"lightgreen",  RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3787         {"DarkCyan",    RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3788         {"cyan",        RGB(0x02, 0xAB, 0xEA)}, /*M*/
3789         {"lightcyan",   RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3790         {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3791         {"magenta",     RGB(0xF2, 0x08, 0x84)}, /*M*/
3792         {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3793         {"brown",       RGB(0x80, 0x40, 0x40)}, /*W*/
3794         {"yellow",      RGB(0xFC, 0xF3, 0x05)}, /*M*/
3795         {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
3796         {"darkyellow",  RGB(0xBB, 0xBB, 0x00)}, /*U*/
3797         {"SeaGreen",    RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3798         {"orange",      RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3799         {"Purple",      RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3800         {"SlateBlue",   RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3801         {"Violet",      RGB(0x8D, 0x38, 0xC9)}, /*U*/
3802     };
3803
3804     int         r, g, b;
3805     int         i;
3806
3807     if (name[0] == '#' && strlen((char *) name) == 7)
3808     {
3809         /* Name is in "#rrggbb" format */
3810         r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3811         g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3812         b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3813         if (r < 0 || g < 0 || b < 0)
3814             return INVALCOLOR;
3815         return RGB(r, g, b);
3816     }
3817     else
3818     {
3819         if (STRICMP(name, "hilite") == 0)
3820         {
3821             LMGetHiliteRGB(&MacColor);
3822             return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
3823         }
3824         /* Check if the name is one of the colors we know */
3825         for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3826             if (STRICMP(name, table[i].name) == 0)
3827                 return table[i].color;
3828     }
3829
3830     /*
3831      * Last attempt. Look in the file "$VIM/rgb.txt".
3832      */
3833     {
3834 #define LINE_LEN 100
3835         FILE    *fd;
3836         char    line[LINE_LEN];
3837         char_u  *fname;
3838
3839         fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
3840         if (fname == NULL)
3841             return INVALCOLOR;
3842
3843         fd = fopen((char *)fname, "rt");
3844         vim_free(fname);
3845         if (fd == NULL)
3846             return INVALCOLOR;
3847
3848         while (!feof(fd))
3849         {
3850             int         len;
3851             int         pos;
3852             char        *color;
3853
3854             fgets(line, LINE_LEN, fd);
3855             len = strlen(line);
3856
3857             if (len <= 1 || line[len-1] != '\n')
3858                 continue;
3859
3860             line[len-1] = '\0';
3861
3862             i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3863             if (i != 3)
3864                 continue;
3865
3866             color = line + pos;
3867
3868             if (STRICMP(color, name) == 0)
3869             {
3870                 fclose(fd);
3871                 return (guicolor_T) RGB(r, g, b);
3872             }
3873         }
3874         fclose(fd);
3875     }
3876
3877     return INVALCOLOR;
3878 }
3879
3880 /*
3881  * Set the current text foreground color.
3882  */
3883     void
3884 gui_mch_set_fg_color(guicolor_T color)
3885 {
3886     RGBColor TheColor;
3887
3888     TheColor.red = Red(color) * 0x0101;
3889     TheColor.green = Green(color) * 0x0101;
3890     TheColor.blue = Blue(color) * 0x0101;
3891
3892     RGBForeColor(&TheColor);
3893 }
3894
3895 /*
3896  * Set the current text background color.
3897  */
3898     void
3899 gui_mch_set_bg_color(guicolor_T color)
3900 {
3901     RGBColor TheColor;
3902
3903     TheColor.red = Red(color) * 0x0101;
3904     TheColor.green = Green(color) * 0x0101;
3905     TheColor.blue = Blue(color) * 0x0101;
3906
3907     RGBBackColor(&TheColor);
3908 }
3909
3910 RGBColor specialColor;
3911
3912 /*
3913  * Set the current text special color.
3914  */
3915     void
3916 gui_mch_set_sp_color(guicolor_T color)
3917 {
3918     specialColor.red = Red(color) * 0x0101;
3919     specialColor.green = Green(color) * 0x0101;
3920     specialColor.blue = Blue(color) * 0x0101;
3921 }
3922
3923 /*
3924  * Draw undercurl at the bottom of the character cell.
3925  */
3926     static void
3927 draw_undercurl(int flags, int row, int col, int cells)
3928 {
3929     int                 x;
3930     int                 offset;
3931     const static int    val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3932     int                 y = FILL_Y(row + 1) - 1;
3933
3934     RGBForeColor(&specialColor);
3935
3936     offset = val[FILL_X(col) % 8];
3937     MoveTo(FILL_X(col), y - offset);
3938
3939     for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
3940     {
3941         offset = val[x % 8];
3942         LineTo(x, y - offset);
3943     }
3944 }
3945
3946
3947     static void
3948 draw_string_QD(int row, int col, char_u *s, int len, int flags)
3949 {
3950 #ifdef FEAT_MBYTE
3951     char_u      *tofree = NULL;
3952
3953     if (output_conv.vc_type != CONV_NONE)
3954     {
3955         tofree = string_convert(&output_conv, s, &len);
3956         if (tofree != NULL)
3957             s = tofree;
3958     }
3959 #endif
3960
3961     /*
3962      * On OS X, try using Quartz-style text antialiasing.
3963      */
3964     if (gMacSystemVersion >= 0x1020)
3965     {
3966         /* Quartz antialiasing is available only in OS 10.2 and later. */
3967         UInt32 qd_flags = (p_antialias ?
3968                              kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
3969         QDSwapTextFlags(qd_flags);
3970     }
3971
3972     /*
3973      * When antialiasing we're using srcOr mode, we have to clear the block
3974      * before drawing the text.
3975      * Also needed when 'linespace' is non-zero to remove the cursor and
3976      * underlining.
3977      * But not when drawing transparently.
3978      * The following is like calling gui_mch_clear_block(row, col, row, col +
3979      * len - 1), but without setting the bg color to gui.back_pixel.
3980      */
3981     if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
3982             && !(flags & DRAW_TRANSP))
3983     {
3984         Rect rc;
3985
3986         rc.left = FILL_X(col);
3987         rc.top = FILL_Y(row);
3988 #ifdef FEAT_MBYTE
3989         /* Multibyte computation taken from gui_w32.c */
3990         if (has_mbyte)
3991         {
3992             /* Compute the length in display cells. */
3993             rc.right = FILL_X(col + mb_string2cells(s, len));
3994         }
3995         else
3996 #endif
3997         rc.right = FILL_X(col + len) + (col + len == Columns);
3998         rc.bottom = FILL_Y(row + 1);
3999         EraseRect(&rc);
4000     }
4001
4002     if (gMacSystemVersion >= 0x1020 && p_antialias)
4003     {
4004         StyleParameter face;
4005
4006         face = normal;
4007         if (flags & DRAW_BOLD)
4008             face |= bold;
4009         if (flags & DRAW_UNDERL)
4010             face |= underline;
4011         TextFace(face);
4012
4013         /* Quartz antialiasing works only in srcOr transfer mode. */
4014         TextMode(srcOr);
4015
4016         MoveTo(TEXT_X(col), TEXT_Y(row));
4017         DrawText((char*)s, 0, len);
4018     }
4019     else
4020     {
4021         /* Use old-style, non-antialiased QuickDraw text rendering. */
4022         TextMode(srcCopy);
4023         TextFace(normal);
4024
4025     /*  SelectFont(hdc, gui.currFont); */
4026
4027         if (flags & DRAW_TRANSP)
4028         {
4029             TextMode(srcOr);
4030         }
4031
4032         MoveTo(TEXT_X(col), TEXT_Y(row));
4033         DrawText((char *)s, 0, len);
4034
4035         if (flags & DRAW_BOLD)
4036         {
4037             TextMode(srcOr);
4038             MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4039             DrawText((char *)s, 0, len);
4040         }
4041
4042         if (flags & DRAW_UNDERL)
4043         {
4044             MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4045             LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4046         }
4047     }
4048
4049     if (flags & DRAW_UNDERC)
4050         draw_undercurl(flags, row, col, len);
4051
4052 #ifdef FEAT_MBYTE
4053     vim_free(tofree);
4054 #endif
4055 }
4056
4057 #ifdef USE_ATSUI_DRAWING
4058
4059     static void
4060 draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4061 {
4062     /* ATSUI requires utf-16 strings */
4063     UniCharCount utf16_len;
4064     UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4065     utf16_len /= sizeof(UniChar);
4066
4067     /* - ATSUI automatically antialiases text (Someone)
4068      * - for some reason it does not work... (Jussi) */
4069 #ifdef MAC_ATSUI_DEBUG
4070     fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4071             row, col, len, len == 1 ? s[0] : ' ');
4072 #endif
4073     /*
4074      * When antialiasing we're using srcOr mode, we have to clear the block
4075      * before drawing the text.
4076      * Also needed when 'linespace' is non-zero to remove the cursor and
4077      * underlining.
4078      * But not when drawing transparently.
4079      * The following is like calling gui_mch_clear_block(row, col, row, col +
4080      * len - 1), but without setting the bg color to gui.back_pixel.
4081      */
4082     if ((flags & DRAW_TRANSP) == 0)
4083     {
4084         Rect rc;
4085
4086         rc.left = FILL_X(col);
4087         rc.top = FILL_Y(row);
4088         /* Multibyte computation taken from gui_w32.c */
4089         if (has_mbyte)
4090         {
4091             /* Compute the length in display cells. */
4092             rc.right = FILL_X(col + mb_string2cells(s, len));
4093         }
4094         else
4095             rc.right = FILL_X(col + len) + (col + len == Columns);
4096
4097         rc.bottom = FILL_Y(row + 1);
4098         EraseRect(&rc);
4099     }
4100
4101     {
4102         TextMode(srcCopy);
4103         TextFace(normal);
4104
4105         /*  SelectFont(hdc, gui.currFont); */
4106         if (flags & DRAW_TRANSP)
4107         {
4108             TextMode(srcOr);
4109         }
4110
4111         MoveTo(TEXT_X(col), TEXT_Y(row));
4112
4113         if (gFontStyle && flags & DRAW_BOLD)
4114         {
4115             Boolean attValue = true;
4116             ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4117             ByteCount attribSizes[] = { sizeof(Boolean) };
4118             ATSUAttributeValuePtr attribValues[] = { &attValue };
4119
4120             ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4121         }
4122
4123         UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
4124                                           : kATSStyleNoAntiAliasing;
4125         if (useAntialias != useAntialias_cached)
4126         {
4127             ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
4128             ByteCount attribSizes[] = { sizeof(UInt32) };
4129             ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4130
4131             if (gFontStyle)
4132                 ATSUSetAttributes(gFontStyle, 1, attribTags,
4133                                                    attribSizes, attribValues);
4134             if (gWideFontStyle)
4135                 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4136                                                    attribSizes, attribValues);
4137
4138             useAntialias_cached = useAntialias;
4139         }
4140
4141 #ifdef FEAT_MBYTE
4142         if (has_mbyte)
4143         {
4144             int n, width_in_cell, last_width_in_cell;
4145             UniCharArrayOffset offset = 0;
4146             UniCharCount yet_to_draw = 0;
4147             ATSUTextLayout textLayout;
4148             ATSUStyle      textStyle;
4149
4150             last_width_in_cell = 1;
4151             ATSUCreateTextLayout(&textLayout);
4152             ATSUSetTextPointerLocation(textLayout, tofree,
4153                                        kATSUFromTextBeginning,
4154                                        kATSUToTextEnd, utf16_len);
4155             /*
4156                ATSUSetRunStyle(textLayout, gFontStyle,
4157                kATSUFromTextBeginning, kATSUToTextEnd); */
4158
4159             /* Compute the length in display cells. */
4160             for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4161             {
4162                 width_in_cell = (*mb_ptr2cells)(s + n);
4163
4164                 /* probably we are switching from single byte character
4165                  * to multibyte characters (which requires more than one
4166                  * cell to draw) */
4167                 if (width_in_cell != last_width_in_cell)
4168                 {
4169 #ifdef MAC_ATSUI_DEBUG
4170                     fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4171                             n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4172 #endif
4173                     textStyle = last_width_in_cell > 1 ? gWideFontStyle
4174                                                                  : gFontStyle;
4175
4176                     ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4177                     offset += yet_to_draw;
4178                     yet_to_draw = 0;
4179                     last_width_in_cell = width_in_cell;
4180                 }
4181
4182                 yet_to_draw++;
4183             }
4184
4185             if (yet_to_draw)
4186             {
4187 #ifdef MAC_ATSUI_DEBUG
4188                 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4189                         n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4190 #endif
4191                 /* finish the rest style */
4192                 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4193                 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4194             }
4195
4196             ATSUSetTransientFontMatching(textLayout, TRUE);
4197             ATSUDrawText(textLayout,
4198                          kATSUFromTextBeginning, kATSUToTextEnd,
4199                          kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4200             ATSUDisposeTextLayout(textLayout);
4201         }
4202         else
4203 #endif
4204         {
4205             ATSUTextLayout textLayout;
4206
4207             if (ATSUCreateTextLayoutWithTextPtr(tofree,
4208                         kATSUFromTextBeginning, kATSUToTextEnd,
4209                         utf16_len,
4210                         (gFontStyle ? 1 : 0), &utf16_len,
4211                         (gFontStyle ? &gFontStyle : NULL),
4212                         &textLayout) == noErr)
4213             {
4214                 ATSUSetTransientFontMatching(textLayout, TRUE);
4215
4216                 ATSUDrawText(textLayout,
4217                         kATSUFromTextBeginning, kATSUToTextEnd,
4218                         kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4219
4220                 ATSUDisposeTextLayout(textLayout);
4221             }
4222         }
4223
4224         /* drawing is done, now reset bold to normal */
4225         if (gFontStyle && flags & DRAW_BOLD)
4226         {
4227             Boolean attValue = false;
4228
4229             ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4230             ByteCount attribSizes[] = { sizeof(Boolean) };
4231             ATSUAttributeValuePtr attribValues[] = { &attValue };
4232
4233             ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4234                                                                 attribValues);
4235         }
4236     }
4237
4238     if (flags & DRAW_UNDERC)
4239         draw_undercurl(flags, row, col, len);
4240
4241     vim_free(tofree);
4242 }
4243 #endif
4244
4245     void
4246 gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4247 {
4248 #if defined(USE_ATSUI_DRAWING)
4249     if (p_macatsui == 0 && p_macatsui_last != 0)
4250         /* switch from macatsui to nomacatsui */
4251         gui_mac_dispose_atsui_style();
4252     else if (p_macatsui != 0 && p_macatsui_last == 0)
4253         /* switch from nomacatsui to macatsui */
4254         gui_mac_create_atsui_style();
4255
4256     if (p_macatsui)
4257         draw_string_ATSUI(row, col, s, len, flags);
4258     else
4259 #endif
4260         draw_string_QD(row, col, s, len, flags);
4261 }
4262
4263 /*
4264  * Return OK if the key with the termcap name "name" is supported.
4265  */
4266     int
4267 gui_mch_haskey(char_u *name)
4268 {
4269     int i;
4270
4271     for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4272         if (name[0] == special_keys[i].vim_code0 &&
4273                                          name[1] == special_keys[i].vim_code1)
4274             return OK;
4275     return FAIL;
4276 }
4277
4278     void
4279 gui_mch_beep(void)
4280 {
4281     SysBeep(1); /* Should this be 0? (????) */
4282 }
4283
4284     void
4285 gui_mch_flash(int msec)
4286 {
4287     /* Do a visual beep by reversing the foreground and background colors */
4288     Rect    rc;
4289
4290     /*
4291      * Note: InvertRect() excludes right and bottom of rectangle.
4292      */
4293     rc.left = 0;
4294     rc.top = 0;
4295     rc.right = gui.num_cols * gui.char_width;
4296     rc.bottom = gui.num_rows * gui.char_height;
4297     InvertRect(&rc);
4298
4299     ui_delay((long)msec, TRUE);         /* wait for some msec */
4300
4301     InvertRect(&rc);
4302 }
4303
4304 /*
4305  * Invert a rectangle from row r, column c, for nr rows and nc columns.
4306  */
4307     void
4308 gui_mch_invert_rectangle(int r, int c, int nr, int nc)
4309 {
4310     Rect        rc;
4311
4312     /*
4313      * Note: InvertRect() excludes right and bottom of rectangle.
4314      */
4315     rc.left = FILL_X(c);
4316     rc.top = FILL_Y(r);
4317     rc.right = rc.left + nc * gui.char_width;
4318     rc.bottom = rc.top + nr * gui.char_height;
4319     InvertRect(&rc);
4320 }
4321
4322 /*
4323  * Iconify the GUI window.
4324  */
4325     void
4326 gui_mch_iconify(void)
4327 {
4328     /* TODO: find out what could replace iconify
4329      *       -window shade?
4330      *       -hide application?
4331      */
4332 }
4333
4334 #if defined(FEAT_EVAL) || defined(PROTO)
4335 /*
4336  * Bring the Vim window to the foreground.
4337  */
4338     void
4339 gui_mch_set_foreground(void)
4340 {
4341     /* TODO */
4342 }
4343 #endif
4344
4345 /*
4346  * Draw a cursor without focus.
4347  */
4348     void
4349 gui_mch_draw_hollow_cursor(guicolor_T color)
4350 {
4351     Rect rc;
4352
4353     /*
4354      * Note: FrameRect() excludes right and bottom of rectangle.
4355      */
4356     rc.left = FILL_X(gui.col);
4357     rc.top = FILL_Y(gui.row);
4358     rc.right = rc.left + gui.char_width;
4359 #ifdef FEAT_MBYTE
4360     if (mb_lefthalve(gui.row, gui.col))
4361         rc.right += gui.char_width;
4362 #endif
4363     rc.bottom = rc.top + gui.char_height;
4364
4365     gui_mch_set_fg_color(color);
4366
4367     FrameRect(&rc);
4368 }
4369
4370 /*
4371  * Draw part of a cursor, only w pixels wide, and h pixels high.
4372  */
4373     void
4374 gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
4375 {
4376     Rect rc;
4377
4378 #ifdef FEAT_RIGHTLEFT
4379     /* vertical line should be on the right of current point */
4380     if (CURSOR_BAR_RIGHT)
4381         rc.left = FILL_X(gui.col + 1) - w;
4382     else
4383 #endif
4384         rc.left = FILL_X(gui.col);
4385     rc.top = FILL_Y(gui.row) + gui.char_height - h;
4386     rc.right = rc.left + w;
4387     rc.bottom = rc.top + h;
4388
4389     gui_mch_set_fg_color(color);
4390
4391     FrameRect(&rc);
4392 //    PaintRect(&rc);
4393 }
4394
4395
4396
4397 /*
4398  * Catch up with any queued X events.  This may put keyboard input into the
4399  * input buffer, call resize call-backs, trigger timers etc.  If there is
4400  * nothing in the X event queue (& no timers pending), then we return
4401  * immediately.
4402  */
4403     void
4404 gui_mch_update(void)
4405 {
4406     /* TODO: find what to do
4407      *       maybe call gui_mch_wait_for_chars (0)
4408      *       more like look at EventQueue then
4409      *       call heart of gui_mch_wait_for_chars;
4410      *
4411      *  if (eventther)
4412      *      gui_mac_handle_event(&event);
4413      */
4414     EventRecord theEvent;
4415
4416     if (EventAvail(everyEvent, &theEvent))
4417         if (theEvent.what != nullEvent)
4418             gui_mch_wait_for_chars(0);
4419 }
4420
4421 /*
4422  * Simple wrapper to neglect more easily the time
4423  * spent inside WaitNextEvent while profiling.
4424  */
4425
4426     pascal
4427     Boolean
4428 WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
4429 {
4430     if (((long) sleep) < -1)
4431         sleep = 32767;
4432     return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4433 }
4434
4435 /*
4436  * GUI input routine called by gui_wait_for_chars().  Waits for a character
4437  * from the keyboard.
4438  *  wtime == -1     Wait forever.
4439  *  wtime == 0      This should never happen.
4440  *  wtime > 0       Wait wtime milliseconds for a character.
4441  * Returns OK if a character was found to be available within the given time,
4442  * or FAIL otherwise.
4443  */
4444     int
4445 gui_mch_wait_for_chars(int wtime)
4446 {
4447     EventMask   mask  = (everyEvent);
4448     EventRecord event;
4449     long        entryTick;
4450     long        currentTick;
4451     long        sleeppyTick;
4452
4453     /* If we are providing life feedback with the scrollbar,
4454      * we don't want to try to wait for an event, or else
4455      * there won't be any life feedback.
4456      */
4457     if (dragged_sb != NULL)
4458         return FAIL;
4459         /* TODO: Check if FAIL is the proper return code */
4460
4461     entryTick = TickCount();
4462
4463     allow_scrollbar = TRUE;
4464
4465     do
4466     {
4467 /*      if (dragRectControl == kCreateEmpty)
4468         {
4469             dragRgn = NULL;
4470             dragRectControl = kNothing;
4471         }
4472         else*/ if (dragRectControl == kCreateRect)
4473         {
4474             dragRgn = cursorRgn;
4475             RectRgn(dragRgn, &dragRect);
4476             dragRectControl = kNothing;
4477         }
4478         /*
4479          * Don't use gui_mch_update() because then we will spin-lock until a
4480          * char arrives, instead we use WaitNextEventWrp() to hang until an
4481          * event arrives.  No need to check for input_buf_full because we are
4482          * returning as soon as it contains a single char.
4483          */
4484         /* TODO: reduce wtime accordinly???  */
4485         if (wtime > -1)
4486             sleeppyTick = 60 * wtime / 1000;
4487         else
4488             sleeppyTick = 32767;
4489
4490         if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
4491         {
4492             gui_mac_handle_event(&event);
4493             if (input_available())
4494             {
4495                 allow_scrollbar = FALSE;
4496                 return OK;
4497             }
4498         }
4499         currentTick = TickCount();
4500     }
4501     while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4502
4503     allow_scrollbar = FALSE;
4504     return FAIL;
4505 }
4506
4507 /*
4508  * Output routines.
4509  */
4510
4511 /* Flush any output to the screen */
4512     void
4513 gui_mch_flush(void)
4514 {
4515     /* TODO: Is anything needed here? */
4516 }
4517
4518 /*
4519  * Clear a rectangular region of the screen from text pos (row1, col1) to
4520  * (row2, col2) inclusive.
4521  */
4522     void
4523 gui_mch_clear_block(int row1, int col1, int row2, int col2)
4524 {
4525     Rect rc;
4526
4527     /*
4528      * Clear one extra pixel at the far right, for when bold characters have
4529      * spilled over to the next column.
4530      */
4531     rc.left = FILL_X(col1);
4532     rc.top = FILL_Y(row1);
4533     rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4534     rc.bottom = FILL_Y(row2 + 1);
4535
4536     gui_mch_set_bg_color(gui.back_pixel);
4537     EraseRect(&rc);
4538 }
4539
4540 /*
4541  * Clear the whole text window.
4542  */
4543     void
4544 gui_mch_clear_all(void)
4545 {
4546     Rect        rc;
4547
4548     rc.left = 0;
4549     rc.top = 0;
4550     rc.right = Columns * gui.char_width + 2 * gui.border_width;
4551     rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4552
4553     gui_mch_set_bg_color(gui.back_pixel);
4554     EraseRect(&rc);
4555 /*  gui_mch_set_fg_color(gui.norm_pixel);
4556     FrameRect(&rc);
4557 */
4558 }
4559
4560 /*
4561  * Delete the given number of lines from the given row, scrolling up any
4562  * text further down within the scroll region.
4563  */
4564     void
4565 gui_mch_delete_lines(int row, int num_lines)
4566 {
4567     Rect        rc;
4568
4569     /* changed without checking! */
4570     rc.left = FILL_X(gui.scroll_region_left);
4571     rc.right = FILL_X(gui.scroll_region_right + 1);
4572     rc.top = FILL_Y(row);
4573     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4574
4575     gui_mch_set_bg_color(gui.back_pixel);
4576     ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
4577
4578     gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4579                                                        gui.scroll_region_left,
4580         gui.scroll_region_bot, gui.scroll_region_right);
4581 }
4582
4583 /*
4584  * Insert the given number of lines before the given row, scrolling down any
4585  * following text within the scroll region.
4586  */
4587     void
4588 gui_mch_insert_lines(int row, int num_lines)
4589 {
4590     Rect rc;
4591
4592     rc.left = FILL_X(gui.scroll_region_left);
4593     rc.right = FILL_X(gui.scroll_region_right + 1);
4594     rc.top = FILL_Y(row);
4595     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4596
4597     gui_mch_set_bg_color(gui.back_pixel);
4598
4599     ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
4600
4601     /* Update gui.cursor_row if the cursor scrolled or copied over */
4602     if (gui.cursor_row >= gui.row
4603             && gui.cursor_col >= gui.scroll_region_left
4604             && gui.cursor_col <= gui.scroll_region_right)
4605     {
4606         if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4607             gui.cursor_row += num_lines;
4608         else if (gui.cursor_row <= gui.scroll_region_bot)
4609             gui.cursor_is_valid = FALSE;
4610     }
4611
4612     gui_clear_block(row, gui.scroll_region_left,
4613                                 row + num_lines - 1, gui.scroll_region_right);
4614 }
4615
4616     /*
4617      * TODO: add a vim format to the clipboard which remember
4618      *       LINEWISE, CHARWISE, BLOCKWISE
4619      */
4620
4621     void
4622 clip_mch_request_selection(VimClipboard *cbd)
4623 {
4624
4625     Handle      textOfClip;
4626     int         flavor = 0;
4627     Size        scrapSize;
4628     ScrapFlavorFlags    scrapFlags;
4629     ScrapRef    scrap = nil;
4630     OSStatus    error;
4631     int         type;
4632     char        *searchCR;
4633     char_u      *tempclip;
4634
4635
4636     error = GetCurrentScrap(&scrap);
4637     if (error != noErr)
4638         return;
4639
4640     error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4641     if (error == noErr)
4642     {
4643         error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4644         if (error == noErr && scrapSize > 1)
4645             flavor = 1;
4646     }
4647
4648     if (flavor == 0)
4649     {
4650         error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
4651         if (error != noErr)
4652             return;
4653
4654         error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
4655         if (error != noErr)
4656             return;
4657     }
4658
4659     ReserveMem(scrapSize);
4660
4661     /* In CARBON we don't need a Handle, a pointer is good */
4662     textOfClip = NewHandle(scrapSize);
4663
4664     /* tempclip = lalloc(scrapSize+1, TRUE); */
4665     HLock(textOfClip);
4666     error = GetScrapFlavorData(scrap,
4667             flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4668             &scrapSize, *textOfClip);
4669     scrapSize -= flavor;
4670
4671     if (flavor)
4672         type = **textOfClip;
4673     else
4674         type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4675
4676     tempclip = lalloc(scrapSize + 1, TRUE);
4677     mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4678     tempclip[scrapSize] = 0;
4679
4680 #ifdef MACOS_CONVERT
4681     {
4682         /* Convert from utf-16 (clipboard) */
4683         size_t encLen = 0;
4684         char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
4685
4686         if (to != NULL)
4687         {
4688             scrapSize = encLen;
4689             vim_free(tempclip);
4690             tempclip = to;
4691         }
4692     }
4693 #endif
4694
4695     searchCR = (char *)tempclip;
4696     while (searchCR != NULL)
4697     {
4698         searchCR = strchr(searchCR, '\r');
4699         if (searchCR != NULL)
4700             *searchCR = '\n';
4701     }
4702
4703     clip_yank_selection(type, tempclip, scrapSize, cbd);
4704
4705     vim_free(tempclip);
4706     HUnlock(textOfClip);
4707
4708     DisposeHandle(textOfClip);
4709 }
4710
4711     void
4712 clip_mch_lose_selection(VimClipboard *cbd)
4713 {
4714     /*
4715      * TODO: Really nothing to do?
4716      */
4717 }
4718
4719     int
4720 clip_mch_own_selection(VimClipboard *cbd)
4721 {
4722     return OK;
4723 }
4724
4725 /*
4726  * Send the current selection to the clipboard.
4727  */
4728     void
4729 clip_mch_set_selection(VimClipboard *cbd)
4730 {
4731     Handle      textOfClip;
4732     long        scrapSize;
4733     int         type;
4734     ScrapRef    scrap;
4735
4736     char_u      *str = NULL;
4737
4738     if (!cbd->owned)
4739         return;
4740
4741     clip_get_selection(cbd);
4742
4743     /*
4744      * Once we set the clipboard, lose ownership.  If another application sets
4745      * the clipboard, we don't want to think that we still own it.
4746      */
4747     cbd->owned = FALSE;
4748
4749     type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
4750
4751 #ifdef MACOS_CONVERT
4752     size_t utf16_len = 0;
4753     UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4754     if (to)
4755     {
4756         scrapSize = utf16_len;
4757         vim_free(str);
4758         str = (char_u *)to;
4759     }
4760 #endif
4761
4762     if (type >= 0)
4763     {
4764         ClearCurrentScrap();
4765
4766         textOfClip = NewHandle(scrapSize + 1);
4767         HLock(textOfClip);
4768
4769         **textOfClip = type;
4770         mch_memmove(*textOfClip + 1, str, scrapSize);
4771         GetCurrentScrap(&scrap);
4772         PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
4773                 scrapSize, *textOfClip + 1);
4774         PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4775                 scrapSize + 1, *textOfClip);
4776         HUnlock(textOfClip);
4777         DisposeHandle(textOfClip);
4778     }
4779
4780     vim_free(str);
4781 }
4782
4783     void
4784 gui_mch_set_text_area_pos(int x, int y, int w, int h)
4785 {
4786     Rect        VimBound;
4787
4788 /*  HideWindow(gui.VimWindow); */
4789     GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
4790
4791     if (gui.which_scrollbars[SBAR_LEFT])
4792     {
4793         VimBound.left = -gui.scrollbar_width + 1;
4794     }
4795     else
4796     {
4797         VimBound.left = 0;
4798     }
4799
4800     SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
4801
4802     ShowWindow(gui.VimWindow);
4803 }
4804
4805 /*
4806  * Menu stuff.
4807  */
4808
4809     void
4810 gui_mch_enable_menu(int flag)
4811 {
4812     /*
4813      * Menu is always active.
4814      */
4815 }
4816
4817     void
4818 gui_mch_set_menu_pos(int x, int y, int w, int h)
4819 {
4820     /*
4821      * The menu is always at the top of the screen.
4822      */
4823 }
4824
4825 /*
4826  * Add a sub menu to the menu bar.
4827  */
4828     void
4829 gui_mch_add_menu(vimmenu_T *menu, int idx)
4830 {
4831     /*
4832      * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4833      * TODO: use menu->mnemonic and menu->actext
4834      * TODO: Try to reuse menu id
4835      *       Carbon Help suggest to use only id between 1 and 235
4836      */
4837     static long  next_avail_id = 128;
4838     long         menu_after_me = 0; /* Default to the end */
4839 #if defined(FEAT_MBYTE)
4840     CFStringRef name;
4841 #else
4842     char_u      *name;
4843 #endif
4844     short        index;
4845     vimmenu_T   *parent = menu->parent;
4846     vimmenu_T   *brother = menu->next;
4847
4848     /* Cannot add a menu if ... */
4849     if ((parent != NULL && parent->submenu_id == 0))
4850         return;
4851
4852     /* menu ID greater than 1024 are reserved for ??? */
4853     if (next_avail_id == 1024)
4854         return;
4855
4856     /* My brother could be the PopUp, find my real brother */
4857     while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4858         brother = brother->next;
4859
4860     /*  Find where to insert the menu (for MenuBar) */
4861     if ((parent == NULL) && (brother != NULL))
4862         menu_after_me = brother->submenu_id;
4863
4864     /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4865     if (!menu_is_menubar(menu->name))
4866         menu_after_me = hierMenu;
4867
4868     /* Convert the name */
4869 #ifdef MACOS_CONVERT
4870     name = menu_title_removing_mnemonic(menu);
4871 #else
4872     name = C2Pascal_save(menu->dname);
4873 #endif
4874     if (name == NULL)
4875         return;
4876
4877     /* Create the menu unless it's the help menu */
4878     {
4879         /* Carbon suggest use of
4880          * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4881          * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
4882          */
4883         menu->submenu_id = next_avail_id;
4884 #if defined(FEAT_MBYTE)
4885         if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4886             SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4887 #else
4888         menu->submenu_handle = NewMenu(menu->submenu_id, name);
4889 #endif
4890         next_avail_id++;
4891     }
4892
4893     if (parent == NULL)
4894     {
4895         /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4896
4897         /* TODO: Verify if we could only Insert Menu if really part of the
4898          * menubar The Inserted menu are scanned or the Command-key combos
4899          */
4900
4901         /* Insert the menu */
4902         InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
4903 #if 1
4904         /* Vim should normally update it. TODO: verify */
4905         DrawMenuBar();
4906 #endif
4907     }
4908     else
4909     {
4910         /* Adding as a submenu */
4911
4912         index = gui_mac_get_menu_item_index(menu);
4913
4914         /* Call InsertMenuItem followed by SetMenuItemText
4915          * to avoid special character recognition by InsertMenuItem
4916          */
4917         InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4918 #if defined(FEAT_MBYTE)
4919         SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4920 #else
4921         SetMenuItemText(parent->submenu_handle, idx+1, name);
4922 #endif
4923         SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4924         SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4925         InsertMenu(menu->submenu_handle, hierMenu);
4926     }
4927
4928 #if defined(FEAT_MBYTE)
4929     CFRelease(name);
4930 #else
4931     vim_free(name);
4932 #endif
4933
4934 #if 0
4935     /* Done by Vim later on */
4936     DrawMenuBar();
4937 #endif
4938 }
4939
4940 /*
4941  * Add a menu item to a menu
4942  */
4943     void
4944 gui_mch_add_menu_item(vimmenu_T *menu, int idx)
4945 {
4946 #if defined(FEAT_MBYTE)
4947     CFStringRef name;
4948 #else
4949     char_u      *name;
4950 #endif
4951     vimmenu_T   *parent = menu->parent;
4952     int         menu_inserted;
4953
4954     /* Cannot add item, if the menu have not been created */
4955     if (parent->submenu_id == 0)
4956         return;
4957
4958     /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4959        for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4960
4961     /* Convert the name */
4962 #ifdef MACOS_CONVERT
4963     name = menu_title_removing_mnemonic(menu);
4964 #else
4965     name = C2Pascal_save(menu->dname);
4966 #endif
4967
4968     /* Where are just a menu item, so no handle, no id */
4969     menu->submenu_id = 0;
4970     menu->submenu_handle = NULL;
4971
4972     menu_inserted = 0;
4973     if (menu->actext)
4974     {
4975         /* If the accelerator text for the menu item looks like it describes
4976          * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4977          * item's command equivalent.
4978          */
4979         int         key = 0;
4980         int         modifiers = 0;
4981         char_u      *p_actext;
4982
4983         p_actext = menu->actext;
4984         key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
4985         if (*p_actext != 0)
4986             key = 0; /* error: trailing text */
4987         /* find_special_key() returns a keycode with as many of the
4988          * specified modifiers as appropriate already applied (e.g., for
4989          * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4990          * as the only modifier).  Since we want to display all of the
4991          * modifiers, we need to convert the keycode back to a printable
4992          * character plus modifiers.
4993          * TODO: Write an alternative find_special_key() that doesn't
4994          * apply modifiers.
4995          */
4996         if (key > 0 && key < 32)
4997         {
4998             /* Convert a control key to an uppercase letter.  Note that
4999              * by this point it is no longer possible to distinguish
5000              * between, e.g., Ctrl-S and Ctrl-Shift-S.
5001              */
5002             modifiers |= MOD_MASK_CTRL;
5003             key += '@';
5004         }
5005         /* If the keycode is an uppercase letter, set the Shift modifier.
5006          * If it is a lowercase letter, don't set the modifier, but convert
5007          * the letter to uppercase for display in the menu.
5008          */
5009         else if (key >= 'A' && key <= 'Z')
5010             modifiers |= MOD_MASK_SHIFT;
5011         else if (key >= 'a' && key <= 'z')
5012             key += 'A' - 'a';
5013         /* Note: keycodes below 0x22 are reserved by Apple. */
5014         if (key >= 0x22 && vim_isprintc_strict(key))
5015         {
5016             int         valid = 1;
5017             char_u      mac_mods = kMenuNoModifiers;
5018             /* Convert Vim modifier codes to Menu Manager equivalents. */
5019             if (modifiers & MOD_MASK_SHIFT)
5020                 mac_mods |= kMenuShiftModifier;
5021             if (modifiers & MOD_MASK_CTRL)
5022                 mac_mods |= kMenuControlModifier;
5023             if (!(modifiers & MOD_MASK_CMD))
5024                 mac_mods |= kMenuNoCommandModifier;
5025             if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5026                 valid = 0; /* TODO: will Alt someday map to Option? */
5027             if (valid)
5028             {
5029                 char_u      item_txt[10];
5030                 /* Insert the menu item after idx, with its command key. */
5031                 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5032                 item_txt[3] = key;
5033                 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5034                 /* Set the modifier keys. */
5035                 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5036                 menu_inserted = 1;
5037             }
5038         }
5039     }
5040     /* Call InsertMenuItem followed by SetMenuItemText
5041      * to avoid special character recognition by InsertMenuItem
5042      */
5043     if (!menu_inserted)
5044         InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5045     /* Set the menu item name. */
5046 #if defined(FEAT_MBYTE)
5047     SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5048 #else
5049     SetMenuItemText(parent->submenu_handle, idx+1, name);
5050 #endif
5051
5052 #if 0
5053     /* Called by Vim */
5054     DrawMenuBar();
5055 #endif
5056
5057 #if defined(FEAT_MBYTE)
5058     CFRelease(name);
5059 #else
5060     /* TODO: Can name be freed? */
5061     vim_free(name);
5062 #endif
5063 }
5064
5065     void
5066 gui_mch_toggle_tearoffs(int enable)
5067 {
5068     /* no tearoff menus */
5069 }
5070
5071 /*
5072  * Destroy the machine specific menu widget.
5073  */
5074     void
5075 gui_mch_destroy_menu(vimmenu_T *menu)
5076 {
5077     short       index = gui_mac_get_menu_item_index(menu);
5078
5079     if (index > 0)
5080     {
5081       if (menu->parent)
5082       {
5083         {
5084             /* For now just don't delete help menu items. (Huh? Dany) */
5085             DeleteMenuItem(menu->parent->submenu_handle, index);
5086
5087             /* Delete the Menu if it was a hierarchical Menu */
5088             if (menu->submenu_id != 0)
5089             {
5090                 DeleteMenu(menu->submenu_id);
5091                 DisposeMenu(menu->submenu_handle);
5092             }
5093         }
5094       }
5095 #ifdef DEBUG_MAC_MENU
5096       else
5097       {
5098         printf("gmdm 2\n");
5099       }
5100 #endif
5101     }
5102     else
5103     {
5104         {
5105             DeleteMenu(menu->submenu_id);
5106             DisposeMenu(menu->submenu_handle);
5107         }
5108     }
5109     /* Shouldn't this be already done by Vim. TODO: Check */
5110     DrawMenuBar();
5111 }
5112
5113 /*
5114  * Make a menu either grey or not grey.
5115  */
5116     void
5117 gui_mch_menu_grey(vimmenu_T *menu, int grey)
5118 {
5119     /* TODO: Check if menu really exists */
5120     short index = gui_mac_get_menu_item_index(menu);
5121 /*
5122     index = menu->index;
5123 */
5124     if (grey)
5125     {
5126         if (menu->children)
5127             DisableMenuItem(menu->submenu_handle, index);
5128         if (menu->parent)
5129           if (menu->parent->submenu_handle)
5130             DisableMenuItem(menu->parent->submenu_handle, index);
5131     }
5132     else
5133     {
5134         if (menu->children)
5135             EnableMenuItem(menu->submenu_handle, index);
5136         if (menu->parent)
5137           if (menu->parent->submenu_handle)
5138             EnableMenuItem(menu->parent->submenu_handle, index);
5139     }
5140 }
5141
5142 /*
5143  * Make menu item hidden or not hidden
5144  */
5145     void
5146 gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
5147 {
5148     /* There's no hidden mode on MacOS */
5149     gui_mch_menu_grey(menu, hidden);
5150 }
5151
5152
5153 /*
5154  * This is called after setting all the menus to grey/hidden or not.
5155  */
5156     void
5157 gui_mch_draw_menubar(void)
5158 {
5159     DrawMenuBar();
5160 }
5161
5162
5163 /*
5164  * Scrollbar stuff.
5165  */
5166
5167     void
5168 gui_mch_enable_scrollbar(
5169         scrollbar_T     *sb,
5170         int             flag)
5171 {
5172     if (flag)
5173         ShowControl(sb->id);
5174     else
5175         HideControl(sb->id);
5176
5177 #ifdef DEBUG_MAC_SB
5178     printf("enb_sb (%x) %x\n",sb->id, flag);
5179 #endif
5180 }
5181
5182     void
5183 gui_mch_set_scrollbar_thumb(
5184         scrollbar_T *sb,
5185         long val,
5186         long size,
5187         long max)
5188 {
5189     SetControl32BitMaximum (sb->id, max);
5190     SetControl32BitMinimum (sb->id, 0);
5191     SetControl32BitValue   (sb->id, val);
5192     SetControlViewSize     (sb->id, size);
5193 #ifdef DEBUG_MAC_SB
5194     printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
5195 #endif
5196 }
5197
5198     void
5199 gui_mch_set_scrollbar_pos(
5200         scrollbar_T *sb,
5201         int x,
5202         int y,
5203         int w,
5204         int h)
5205 {
5206     gui_mch_set_bg_color(gui.back_pixel);
5207 /*  if (gui.which_scrollbars[SBAR_LEFT])
5208     {
5209         MoveControl(sb->id, x-16, y);
5210         SizeControl(sb->id, w + 1, h);
5211     }
5212     else
5213     {
5214         MoveControl(sb->id, x, y);
5215         SizeControl(sb->id, w + 1, h);
5216     }*/
5217     if (sb == &gui.bottom_sbar)
5218         h += 1;
5219     else
5220         w += 1;
5221
5222     if (gui.which_scrollbars[SBAR_LEFT])
5223         x -= 15;
5224
5225     MoveControl(sb->id, x, y);
5226     SizeControl(sb->id, w, h);
5227 #ifdef DEBUG_MAC_SB
5228     printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
5229 #endif
5230 }
5231
5232     void
5233 gui_mch_create_scrollbar(
5234         scrollbar_T *sb,
5235         int orient)     /* SBAR_VERT or SBAR_HORIZ */
5236 {
5237     Rect bounds;
5238
5239     bounds.top = -16;
5240     bounds.bottom = -10;
5241     bounds.right = -10;
5242     bounds.left = -16;
5243
5244     sb->id = NewControl(gui.VimWindow,
5245                          &bounds,
5246                          "\pScrollBar",
5247                          TRUE,
5248                          0, /* current*/
5249                          0, /* top */
5250                          0, /* bottom */
5251                          kControlScrollBarLiveProc,
5252                          (long) sb->ident);
5253 #ifdef DEBUG_MAC_SB
5254     printf("create_sb (%x) %x\n",sb->id, orient);
5255 #endif
5256 }
5257
5258     void
5259 gui_mch_destroy_scrollbar(scrollbar_T *sb)
5260 {
5261     gui_mch_set_bg_color(gui.back_pixel);
5262     DisposeControl(sb->id);
5263 #ifdef DEBUG_MAC_SB
5264     printf("dest_sb (%x) \n",sb->id);
5265 #endif
5266 }
5267
5268
5269 /*
5270  * Cursor blink functions.
5271  *
5272  * This is a simple state machine:
5273  * BLINK_NONE   not blinking at all
5274  * BLINK_OFF    blinking, cursor is not shown
5275  * BLINK_ON blinking, cursor is shown
5276  */
5277     void
5278 gui_mch_set_blinking(long wait, long on, long off)
5279 {
5280     /* TODO: TODO: TODO: TODO: */
5281 /*    blink_waittime = wait;
5282     blink_ontime = on;
5283     blink_offtime = off;*/
5284 }
5285
5286 /*
5287  * Stop the cursor blinking.  Show the cursor if it wasn't shown.
5288  */
5289     void
5290 gui_mch_stop_blink(void)
5291 {
5292     gui_update_cursor(TRUE, FALSE);
5293     /* TODO: TODO: TODO: TODO: */
5294 /*    gui_w32_rm_blink_timer();
5295     if (blink_state == BLINK_OFF)
5296     gui_update_cursor(TRUE, FALSE);
5297     blink_state = BLINK_NONE;*/
5298 }
5299
5300 /*
5301  * Start the cursor blinking.  If it was already blinking, this restarts the
5302  * waiting time and shows the cursor.
5303  */
5304     void
5305 gui_mch_start_blink(void)
5306 {
5307     gui_update_cursor(TRUE, FALSE);
5308     /* TODO: TODO: TODO: TODO: */
5309 /*    gui_w32_rm_blink_timer(); */
5310
5311     /* Only switch blinking on if none of the times is zero */
5312 /*    if (blink_waittime && blink_ontime && blink_offtime)
5313     {
5314     blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5315                             (TIMERPROC)_OnBlinkTimer);
5316     blink_state = BLINK_ON;
5317     gui_update_cursor(TRUE, FALSE);
5318     }*/
5319 }
5320
5321 /*
5322  * Return the RGB value of a pixel as long.
5323  */
5324     long_u
5325 gui_mch_get_rgb(guicolor_T pixel)
5326 {
5327     return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5328 }
5329
5330
5331
5332 #ifdef FEAT_BROWSE
5333 /*
5334  * Pop open a file browser and return the file selected, in allocated memory,
5335  * or NULL if Cancel is hit.
5336  *  saving  - TRUE if the file will be saved to, FALSE if it will be opened.
5337  *  title   - Title message for the file browser dialog.
5338  *  dflt    - Default name of file.
5339  *  ext     - Default extension to be added to files without extensions.
5340  *  initdir - directory in which to open the browser (NULL = current dir)
5341  *  filter  - Filter for matched files to choose from.
5342  *  Has a format like this:
5343  *  "C Files (*.c)\0*.c\0"
5344  *  "All Files\0*.*\0\0"
5345  *  If these two strings were concatenated, then a choice of two file
5346  *  filters will be selectable to the user.  Then only matching files will
5347  *  be shown in the browser.  If NULL, the default allows all files.
5348  *
5349  *  *NOTE* - the filter string must be terminated with TWO nulls.
5350  */
5351     char_u *
5352 gui_mch_browse(
5353     int saving,
5354     char_u *title,
5355     char_u *dflt,
5356     char_u *ext,
5357     char_u *initdir,
5358     char_u *filter)
5359 {
5360     /* TODO: Add Ammon's safety checl (Dany) */
5361     NavReplyRecord      reply;
5362     char_u              *fname = NULL;
5363     char_u              **fnames = NULL;
5364     long                numFiles;
5365     NavDialogOptions    navOptions;
5366     OSErr               error;
5367
5368     /* Get Navigation Service Defaults value */
5369     NavGetDefaultDialogOptions(&navOptions);
5370
5371
5372     /* TODO: If we get a :browse args, set the Multiple bit. */
5373     navOptions.dialogOptionFlags =  kNavAllowInvisibleFiles
5374                                  |  kNavDontAutoTranslate
5375                                  |  kNavDontAddTranslateItems
5376                             /*   |  kNavAllowMultipleFiles */
5377                                  |  kNavAllowStationery;
5378
5379     (void) C2PascalString(title,   &navOptions.message);
5380     (void) C2PascalString(dflt,    &navOptions.savedFileName);
5381     /* Could set clientName?
5382      *           windowTitle? (there's no title bar?)
5383      */
5384
5385     if (saving)
5386     {
5387         /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5388         NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
5389         if (!reply.validRecord)
5390             return NULL;
5391     }
5392     else
5393     {
5394         /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5395         NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5396         if (!reply.validRecord)
5397             return NULL;
5398     }
5399
5400     fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5401
5402     NavDisposeReply(&reply);
5403
5404     if (fnames)
5405     {
5406         fname = fnames[0];
5407         vim_free(fnames);
5408     }
5409
5410     /* TODO: Shorten the file name if possible */
5411     return fname;
5412 }
5413 #endif /* FEAT_BROWSE */
5414
5415 #ifdef FEAT_GUI_DIALOG
5416 /*
5417  * Stuff for dialogues
5418  */
5419
5420 /*
5421  * Create a dialogue dynamically from the parameter strings.
5422  * type       = type of dialogue (question, alert, etc.)
5423  * title      = dialogue title. may be NULL for default title.
5424  * message    = text to display. Dialogue sizes to accommodate it.
5425  * buttons    = '\n' separated list of button captions, default first.
5426  * dfltbutton = number of default button.
5427  *
5428  * This routine returns 1 if the first button is pressed,
5429  *          2 for the second, etc.
5430  *
5431  *          0 indicates Esc was pressed.
5432  *          -1 for unexpected error
5433  *
5434  * If stubbing out this fn, return 1.
5435  */
5436
5437 typedef struct
5438 {
5439     short   idx;
5440     short   width;      /* Size of the text in pixel */
5441     Rect    box;
5442 } vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5443
5444 #define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5445
5446     static void
5447 macMoveDialogItem(
5448     DialogRef   theDialog,
5449     short       itemNumber,
5450     short       X,
5451     short       Y,
5452     Rect        *inBox)
5453 {
5454 #if 0 /* USE_CARBONIZED */
5455     /* Untested */
5456     MoveDialogItem(theDialog, itemNumber, X, Y);
5457     if (inBox != nil)
5458         GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
5459 #else
5460     short       itemType;
5461     Handle      itemHandle;
5462     Rect        localBox;
5463     Rect        *itemBox = &localBox;
5464
5465     if (inBox != nil)
5466         itemBox = inBox;
5467
5468     GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5469     OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5470     OffsetRect(itemBox, X, Y);
5471     /* To move a control (like a button) we need to call both
5472      * MoveControl and SetDialogItem. FAQ 6-18 */
5473     if (1) /*(itemType & kControlDialogItem) */
5474         MoveControl((ControlRef) itemHandle, X, Y);
5475     SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
5476 #endif
5477 }
5478
5479     static void
5480 macSizeDialogItem(
5481     DialogRef   theDialog,
5482     short       itemNumber,
5483     short       width,
5484     short       height)
5485 {
5486     short       itemType;
5487     Handle      itemHandle;
5488     Rect        itemBox;
5489
5490     GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
5491
5492     /* When width or height is zero do not change it */
5493     if (width  == 0)
5494         width  = itemBox.right  - itemBox.left;
5495     if (height == 0)
5496         height = itemBox.bottom - itemBox.top;
5497
5498 #if 0 /* USE_CARBONIZED */
5499     SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
5500 #else
5501     /* Resize the bounding box */
5502     itemBox.right  = itemBox.left + width;
5503     itemBox.bottom = itemBox.top  + height;
5504
5505     /* To resize a control (like a button) we need to call both
5506      * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5507     if (itemType & kControlDialogItem)
5508         SizeControl((ControlRef) itemHandle, width, height);
5509
5510     /* Configure back the item */
5511     SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
5512 #endif
5513 }
5514
5515     static void
5516 macSetDialogItemText(
5517     DialogRef   theDialog,
5518     short       itemNumber,
5519     Str255      itemName)
5520 {
5521     short       itemType;
5522     Handle      itemHandle;
5523     Rect        itemBox;
5524
5525     GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
5526
5527     if (itemType & kControlDialogItem)
5528         SetControlTitle((ControlRef) itemHandle, itemName);
5529     else
5530         SetDialogItemText(itemHandle, itemName);
5531 }
5532
5533
5534 /* ModalDialog() handler for message dialogs that have hotkey accelerators.
5535  * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5536  * setting gDialogHotKeys to NULL disables any hotkey handling.
5537  */
5538     static pascal Boolean
5539 DialogHotkeyFilterProc (
5540     DialogRef       theDialog,
5541     EventRecord     *event,
5542     DialogItemIndex *itemHit)
5543 {
5544     char_u keyHit;
5545
5546     if (event->what == keyDown || event->what == autoKey)
5547     {
5548         keyHit = (event->message & charCodeMask);
5549
5550         if (gDialogHotKeys && gDialogHotKeys[keyHit])
5551         {
5552 #ifdef DEBUG_MAC_DIALOG_HOTKEYS
5553             printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5554 #endif
5555             *itemHit = gDialogHotKeys[keyHit];
5556
5557             /* When handing off to StdFilterProc, pretend that the user
5558              * clicked the control manually. Note that this is also supposed
5559              * to cause the button to hilite briefly (to give some user
5560              * feedback), but this seems not to actually work (or it's too
5561              * fast to be seen).
5562              */
5563             event->what = kEventControlSimulateHit;
5564
5565             return true; /* we took care of it */
5566         }
5567
5568         /* Defer to the OS's standard behavior for this event.
5569          * This ensures that Enter will still activate the default button. */
5570         return StdFilterProc(theDialog, event, itemHit);
5571     }
5572     return false;      /* Let ModalDialog deal with it */
5573 }
5574
5575
5576 /* TODO: There have been some crashes with dialogs, check your inbox
5577  * (Jussi)
5578  */
5579     int
5580 gui_mch_dialog(
5581     int         type,
5582     char_u      *title,
5583     char_u      *message,
5584     char_u      *buttons,
5585     int         dfltbutton,
5586     char_u      *textfield)
5587 {
5588     Handle      buttonDITL;
5589     Handle      iconDITL;
5590     Handle      inputDITL;
5591     Handle      messageDITL;
5592     Handle      itemHandle;
5593     Handle      iconHandle;
5594     DialogPtr   theDialog;
5595     char_u      len;
5596     char_u      PascalTitle[256];       /* place holder for the title */
5597     char_u      name[256];
5598     GrafPtr     oldPort;
5599     short       itemHit;
5600     char_u      *buttonChar;
5601     short       hotKeys[256];           /* map of hotkey -> control ID */
5602     char_u      aHotKey;
5603     Rect        box;
5604     short       button;
5605     short       lastButton;
5606     short       itemType;
5607     short       useIcon;
5608     short       width;
5609     short       totalButtonWidth = 0;   /* the width of all buttons together
5610                                            including spacing */
5611     short       widestButton = 0;
5612     short       dfltButtonEdge     = 20;  /* gut feeling */
5613     short       dfltElementSpacing = 13;  /* from IM:V.2-29 */
5614     short       dfltIconSideSpace  = 23;  /* from IM:V.2-29 */
5615     short       maximumWidth       = 400; /* gut feeling */
5616     short       maxButtonWidth     = 175; /* gut feeling */
5617
5618     short       vertical;
5619     short       dialogHeight;
5620     short       messageLines = 3;
5621     FontInfo    textFontInfo;
5622
5623     vgmDlgItm   iconItm;
5624     vgmDlgItm   messageItm;
5625     vgmDlgItm   inputItm;
5626     vgmDlgItm   buttonItm;
5627
5628     WindowRef   theWindow;
5629
5630     ModalFilterUPP dialogUPP;
5631
5632     /* Check 'v' flag in 'guioptions': vertical button placement. */
5633     vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5634
5635     /* Create a new Dialog Box from template. */
5636     theDialog = GetNewDialog(129, nil, (WindowRef) -1);
5637
5638     /* Get the WindowRef */
5639     theWindow = GetDialogWindow(theDialog);
5640
5641     /* Hide the window.
5642      * 1. to avoid seeing slow drawing
5643      * 2. to prevent a problem seen while moving dialog item
5644      *    within a visible window. (non-Carbon MacOS 9)
5645      * Could be avoided by changing the resource.
5646      */
5647     HideWindow(theWindow);
5648
5649     /* Change the graphical port to the dialog,
5650      * so we can measure the text with the proper font */
5651     GetPort(&oldPort);
5652     SetPortDialogPort(theDialog);
5653
5654     /* Get the info about the default text,
5655      * used to calculate the height of the message
5656      * and of the  text field */
5657     GetFontInfo(&textFontInfo);
5658
5659     /*  Set the dialog title */
5660     if (title != NULL)
5661     {
5662         (void) C2PascalString(title, &PascalTitle);
5663         SetWTitle(theWindow, PascalTitle);
5664     }
5665
5666     /* Creates the buttons and add them to the Dialog Box. */
5667     buttonDITL = GetResource('DITL', 130);
5668     buttonChar = buttons;
5669     button = 0;
5670
5671     /* initialize the hotkey mapping */
5672     vim_memset(hotKeys, 0, sizeof(hotKeys));
5673
5674     for (;*buttonChar != 0;)
5675     {
5676         /* Get the name of the button */
5677         button++;
5678         len = 0;
5679         for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5680         {
5681             if (*buttonChar != DLG_HOTKEY_CHAR)
5682                 name[++len] = *buttonChar;
5683             else
5684             {
5685                 aHotKey = (char_u)*(buttonChar+1);
5686                 if (aHotKey >= 'A' && aHotKey <= 'Z')
5687                     aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5688                 hotKeys[aHotKey] = button;
5689 #ifdef DEBUG_MAC_DIALOG_HOTKEYS
5690                 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5691 #endif
5692             }
5693         }
5694
5695         if (*buttonChar != 0)
5696           buttonChar++;
5697         name[0] = len;
5698
5699         /* Add the button */
5700         AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
5701
5702         /* Change the button's name */
5703         macSetDialogItemText(theDialog, button, name);
5704
5705         /* Resize the button to fit its name */
5706         width = StringWidth(name) + 2 * dfltButtonEdge;
5707         /* Limite the size of any button to an acceptable value. */
5708         /* TODO: Should be based on the message width */
5709         if (width > maxButtonWidth)
5710             width = maxButtonWidth;
5711         macSizeDialogItem(theDialog, button, width, 0);
5712
5713         totalButtonWidth += width;
5714
5715         if (width > widestButton)
5716             widestButton = width;
5717     }
5718     ReleaseResource(buttonDITL);
5719     lastButton = button;
5720
5721     /* Add the icon to the Dialog Box. */
5722     iconItm.idx = lastButton + 1;
5723     iconDITL = GetResource('DITL', 131);
5724     switch (type)
5725     {
5726         case VIM_GENERIC:  useIcon = kNoteIcon;
5727         case VIM_ERROR:    useIcon = kStopIcon;
5728         case VIM_WARNING:  useIcon = kCautionIcon;
5729         case VIM_INFO:     useIcon = kNoteIcon;
5730         case VIM_QUESTION: useIcon = kNoteIcon;
5731         default:      useIcon = kStopIcon;
5732     };
5733     AppendDITL(theDialog, iconDITL, overlayDITL);
5734     ReleaseResource(iconDITL);
5735     GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
5736     /* TODO: Should the item be freed? */
5737     iconHandle = GetIcon(useIcon);
5738     SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
5739
5740     /* Add the message to the Dialog box. */
5741     messageItm.idx = lastButton + 2;
5742     messageDITL = GetResource('DITL', 132);
5743     AppendDITL(theDialog, messageDITL, overlayDITL);
5744     ReleaseResource(messageDITL);
5745     GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5746     (void) C2PascalString(message, &name);
5747     SetDialogItemText(itemHandle, name);
5748     messageItm.width = StringWidth(name);
5749
5750     /* Add the input box if needed */
5751     if (textfield != NULL)
5752     {
5753         /* Cheat for now reuse the message and convert to text edit */
5754         inputItm.idx = lastButton + 3;
5755         inputDITL = GetResource('DITL', 132);
5756         AppendDITL(theDialog, inputDITL, overlayDITL);
5757         ReleaseResource(inputDITL);
5758         GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5759 /*        SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5760         (void) C2PascalString(textfield, &name);
5761         SetDialogItemText(itemHandle, name);
5762         inputItm.width = StringWidth(name);
5763
5764         /* Hotkeys don't make sense if there's a text field */
5765         gDialogHotKeys = NULL;
5766     }
5767     else
5768         /* Install hotkey table */
5769         gDialogHotKeys = (short *)&hotKeys;
5770
5771     /* Set the <ENTER> and <ESC> button. */
5772     SetDialogDefaultItem(theDialog, dfltbutton);
5773     SetDialogCancelItem(theDialog, 0);
5774
5775     /* Reposition element */
5776
5777     /* Check if we need to force vertical */
5778     if (totalButtonWidth > maximumWidth)
5779         vertical = TRUE;
5780
5781     /* Place icon */
5782     macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
5783     iconItm.box.right = box.right;
5784     iconItm.box.bottom = box.bottom;
5785
5786     /* Place Message */
5787     messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
5788     macSizeDialogItem(theDialog, messageItm.idx, 0,  messageLines * (textFontInfo.ascent + textFontInfo.descent));
5789     macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
5790
5791     /* Place Input */
5792     if (textfield != NULL)
5793     {
5794         inputItm.box.left = messageItm.box.left;
5795         inputItm.box.top  = messageItm.box.bottom + dfltElementSpacing;
5796         macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5797         macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
5798         /* Convert the static text into a text edit.
5799          * For some reason this change need to be done last (Dany) */
5800         GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5801         SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
5802         SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5803     }
5804
5805     /* Place Button */
5806     if (textfield != NULL)
5807     {
5808         buttonItm.box.left = inputItm.box.left;
5809         buttonItm.box.top  = inputItm.box.bottom + dfltElementSpacing;
5810     }
5811     else
5812     {
5813         buttonItm.box.left = messageItm.box.left;
5814         buttonItm.box.top  = messageItm.box.bottom + dfltElementSpacing;
5815     }
5816
5817     for (button=1; button <= lastButton; button++)
5818     {
5819
5820         macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
5821         /* With vertical, it's better to have all buttons the same length */
5822         if (vertical)
5823         {
5824             macSizeDialogItem(theDialog, button, widestButton, 0);
5825             GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
5826         }
5827         /* Calculate position of next button */
5828         if (vertical)
5829             buttonItm.box.top  = box.bottom + dfltElementSpacing;
5830         else
5831             buttonItm.box.left  = box.right + dfltElementSpacing;
5832     }
5833
5834     /* Resize the dialog box */
5835     dialogHeight = box.bottom + dfltElementSpacing;
5836     SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5837
5838     /* Magic resize */
5839     AutoSizeDialog(theDialog);
5840     /* Need a horizontal resize anyway so not that useful */
5841
5842     /* Display it */
5843     ShowWindow(theWindow);
5844 /*  BringToFront(theWindow); */
5845     SelectWindow(theWindow);
5846
5847 /*  DrawDialog(theDialog); */
5848 #if 0
5849     GetPort(&oldPort);
5850     SetPortDialogPort(theDialog);
5851 #endif
5852
5853 #ifdef USE_CARBONKEYHANDLER
5854     /* Avoid that we use key events for the main window. */
5855     dialog_busy = TRUE;
5856 #endif
5857
5858     /* Prepare the shortcut-handling filterProc for handing to the dialog */
5859     dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5860
5861     /* Hang until one of the button is hit */
5862     do
5863     {
5864         ModalDialog(dialogUPP, &itemHit);
5865     } while ((itemHit < 1) || (itemHit > lastButton));
5866
5867 #ifdef USE_CARBONKEYHANDLER
5868     dialog_busy = FALSE;
5869 #endif
5870
5871     /* Copy back the text entered by the user into the param */
5872     if (textfield != NULL)
5873     {
5874         GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5875         GetDialogItemText(itemHandle, (char_u *) &name);
5876 #if IOSIZE < 256
5877         /* Truncate the name to IOSIZE if needed */
5878         if (name[0] > IOSIZE)
5879             name[0] = IOSIZE - 1;
5880 #endif
5881         vim_strncpy(textfield, &name[1], name[0]);
5882     }
5883
5884     /* Restore the original graphical port */
5885     SetPort(oldPort);
5886
5887     /* Free the modal filterProc */
5888     DisposeRoutineDescriptor(dialogUPP);
5889
5890     /* Get ride of th edialog (free memory) */
5891     DisposeDialog(theDialog);
5892
5893     return itemHit;
5894 /*
5895  * Usefull thing which could be used
5896  * SetDialogTimeout(): Auto click a button after timeout
5897  * SetDialogTracksCursor() : Get the I-beam cursor over input box
5898  * MoveDialogItem():        Probably better than SetDialogItem
5899  * SizeDialogItem():            (but is it Carbon Only?)
5900  * AutoSizeDialog():        Magic resize of dialog based on text length
5901  */
5902 }
5903 #endif /* FEAT_DIALOG_GUI */
5904
5905 /*
5906  * Display the saved error message(s).
5907  */
5908 #ifdef USE_MCH_ERRMSG
5909     void
5910 display_errors(void)
5911 {
5912     char        *p;
5913     char_u      pError[256];
5914
5915     if (error_ga.ga_data == NULL)
5916         return;
5917
5918     /* avoid putting up a message box with blanks only */
5919     for (p = (char *)error_ga.ga_data; *p; ++p)
5920         if (!isspace(*p))
5921         {
5922             if (STRLEN(p) > 255)
5923                 pError[0] = 255;
5924             else
5925                 pError[0] = STRLEN(p);
5926
5927             STRNCPY(&pError[1], p, pError[0]);
5928             ParamText(pError, nil, nil, nil);
5929             Alert(128, nil);
5930             break;
5931             /* TODO: handled message longer than 256 chars
5932              *   use auto-sizeable alert
5933              *   or dialog with scrollbars (TextEdit zone)
5934              */
5935         }
5936     ga_clear(&error_ga);
5937 }
5938 #endif
5939
5940 /*
5941  * Get current mouse coordinates in text window.
5942  */
5943     void
5944 gui_mch_getmouse(int *x, int *y)
5945 {
5946     Point where;
5947
5948     GetMouse(&where);
5949
5950     *x = where.h;
5951     *y = where.v;
5952 }
5953
5954     void
5955 gui_mch_setmouse(int x, int y)
5956 {
5957     /* TODO */
5958 #if 0
5959     /* From FAQ 3-11 */
5960
5961     CursorDevicePtr myMouse;
5962     Point           where;
5963
5964     if (   NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5965         != NGetTrapAddress(_Unimplemented,   ToolTrap))
5966     {
5967         /* New way */
5968
5969         /*
5970          * Get first devoice with one button.
5971          * This will probably be the standad mouse
5972          * startat head of cursor dev list
5973          *
5974          */
5975
5976         myMouse = nil;
5977
5978         do
5979         {
5980             /* Get the next cursor device */
5981             CursorDeviceNextDevice(&myMouse);
5982         }
5983         while ((myMouse != nil) && (myMouse->cntButtons != 1));
5984
5985         CursorDeviceMoveTo(myMouse, x, y);
5986     }
5987     else
5988     {
5989         /* Old way */
5990         where.h = x;
5991         where.v = y;
5992
5993         *(Point *)RawMouse = where;
5994         *(Point *)MTemp    = where;
5995         *(Ptr)    CrsrNew  = 0xFFFF;
5996     }
5997 #endif
5998 }
5999
6000     void
6001 gui_mch_show_popupmenu(vimmenu_T *menu)
6002 {
6003 /*
6004  *  Clone PopUp to use menu
6005  *  Create a object descriptor for the current selection
6006  *  Call the procedure
6007  */
6008
6009     MenuHandle  CntxMenu;
6010     Point       where;
6011     OSStatus    status;
6012     UInt32      CntxType;
6013     SInt16      CntxMenuID;
6014     UInt16      CntxMenuItem;
6015     Str255      HelpName = "";
6016     GrafPtr     savePort;
6017
6018     /* Save Current Port: On MacOS X we seem to lose the port */
6019     GetPort(&savePort); /*OSX*/
6020
6021     GetMouse(&where);
6022     LocalToGlobal(&where); /*OSX*/
6023     CntxMenu = menu->submenu_handle;
6024
6025     /* TODO: Get the text selection from Vim */
6026
6027     /* Call to Handle Popup */
6028     status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
6029                        HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
6030
6031     if (status == noErr)
6032     {
6033         if (CntxType == kCMMenuItemSelected)
6034         {
6035             /* Handle the menu CntxMenuID, CntxMenuItem */
6036             /* The submenu can be handle directly by gui_mac_handle_menu */
6037             /* But what about the current menu, is the menu changed by
6038              * ContextualMenuSelect */
6039             gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
6040         }
6041         else if (CntxMenuID == kCMShowHelpSelected)
6042         {
6043             /* Should come up with the help */
6044         }
6045     }
6046
6047     /* Restore original Port */
6048     SetPort(savePort); /*OSX*/
6049 }
6050
6051 #if defined(FEAT_CW_EDITOR) || defined(PROTO)
6052 /* TODO: Is it need for MACOS_X? (Dany) */
6053     void
6054 mch_post_buffer_write(buf_T *buf)
6055 {
6056     GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6057     Send_KAHL_MOD_AE(buf);
6058 }
6059 #endif
6060
6061 #ifdef FEAT_TITLE
6062 /*
6063  * Set the window title and icon.
6064  * (The icon is not taken care of).
6065  */
6066     void
6067 gui_mch_settitle(char_u *title, char_u *icon)
6068 {
6069     /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6070      *       that 256. Even better get it to fit nicely in the titlebar.
6071      */
6072 #ifdef MACOS_CONVERT
6073     CFStringRef windowTitle;
6074     size_t      windowTitleLen;
6075 #else
6076     char_u   *pascalTitle;
6077 #endif
6078
6079     if (title == NULL)          /* nothing to do */
6080         return;
6081
6082 #ifdef MACOS_CONVERT
6083     windowTitleLen = STRLEN(title);
6084     windowTitle  = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
6085
6086     if (windowTitle)
6087     {
6088         SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6089         CFRelease(windowTitle);
6090     }
6091 #else
6092     pascalTitle = C2Pascal_save(title);
6093     if (pascalTitle != NULL)
6094     {
6095         SetWTitle(gui.VimWindow, pascalTitle);
6096         vim_free(pascalTitle);
6097     }
6098 #endif
6099 }
6100 #endif
6101
6102 /*
6103  * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6104  */
6105
6106     int
6107 C2PascalString(char_u *CString, Str255 *PascalString)
6108 {
6109     char_u *PascalPtr = (char_u *) PascalString;
6110     int    len;
6111     int    i;
6112
6113     PascalPtr[0] = 0;
6114     if (CString == NULL)
6115         return 0;
6116
6117     len = STRLEN(CString);
6118     if (len > 255)
6119         len = 255;
6120
6121     for (i = 0; i < len; i++)
6122         PascalPtr[i+1] = CString[i];
6123
6124     PascalPtr[0] = len;
6125
6126     return 0;
6127 }
6128
6129     int
6130 GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
6131 {
6132     /* From FAQ 8-12 */
6133     Str255      filePascal;
6134     CInfoPBRec  myCPB;
6135     OSErr       err;
6136
6137     (void) C2PascalString(file, &filePascal);
6138
6139     myCPB.dirInfo.ioNamePtr   = filePascal;
6140     myCPB.dirInfo.ioVRefNum   = 0;
6141     myCPB.dirInfo.ioFDirIndex = 0;
6142     myCPB.dirInfo.ioDrDirID   = 0;
6143
6144     err= PBGetCatInfo(&myCPB, false);
6145
6146     /*    vRefNum, dirID, name */
6147     FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
6148
6149     /* TODO: Use an error code mechanism */
6150     return 0;
6151 }
6152
6153 /*
6154  * Convert a FSSpec to a fuill path
6155  */
6156
6157 char_u *FullPathFromFSSpec_save(FSSpec file)
6158 {
6159     /*
6160      * TODO: Add protection for 256 char max.
6161      */
6162
6163     CInfoPBRec  theCPB;
6164     char_u      fname[256];
6165     char_u      *filenamePtr = fname;
6166     OSErr       error;
6167     int         folder = 1;
6168 #ifdef USE_UNIXFILENAME
6169     SInt16      dfltVol_vRefNum;
6170     SInt32      dfltVol_dirID;
6171     FSRef       refFile;
6172     OSStatus    status;
6173     UInt32      pathSize = 256;
6174     char_u      pathname[256];
6175     char_u      *path = pathname;
6176 #else
6177     Str255      directoryName;
6178     char_u      temporary[255];
6179     char_u      *temporaryPtr = temporary;
6180 #endif
6181
6182 #ifdef USE_UNIXFILENAME
6183     /* Get the default volume */
6184     /* TODO: Remove as this only work if Vim is on the Boot Volume*/
6185     error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
6186
6187     if (error)
6188       return NULL;
6189 #endif
6190
6191     /* Start filling fname with file.name  */
6192     vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
6193
6194     /* Get the info about the file specified in FSSpec */
6195     theCPB.dirInfo.ioFDirIndex = 0;
6196     theCPB.dirInfo.ioNamePtr   = file.name;
6197     theCPB.dirInfo.ioVRefNum   = file.vRefNum;
6198     /*theCPB.hFileInfo.ioDirID   = 0;*/
6199     theCPB.dirInfo.ioDrDirID   = file.parID;
6200
6201     /* As ioFDirIndex = 0, get the info of ioNamePtr,
6202        which is relative to ioVrefNum, ioDirID */
6203     error = PBGetCatInfo(&theCPB, false);
6204
6205     /* If we are called for a new file we expect fnfErr */
6206     if ((error) && (error != fnfErr))
6207       return NULL;
6208
6209     /* Check if it's a file or folder       */
6210     /* default to file if file don't exist  */
6211     if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6212       folder = 0; /* It's not a folder */
6213     else
6214       folder = 1;
6215
6216 #ifdef USE_UNIXFILENAME
6217     /*
6218      * The function used here are available in Carbon, but
6219      * do nothing une MacOS 8 and 9
6220      */
6221     if (error == fnfErr)
6222     {
6223         /* If the file to be saved does not already exist, it isn't possible
6224            to convert its FSSpec into an FSRef.  But we can construct an
6225            FSSpec for the file's parent folder (since we have its volume and
6226            directory IDs), and since that folder does exist, we can convert
6227            that FSSpec into an FSRef, convert the FSRef in turn into a path,
6228            and, finally, append the filename. */
6229         FSSpec dirSpec;
6230         FSRef dirRef;
6231         Str255 emptyFilename = "\p";
6232         error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6233             theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6234         if (error)
6235             return NULL;
6236
6237         error = FSpMakeFSRef(&dirSpec, &dirRef);
6238         if (error)
6239             return NULL;
6240
6241         status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6242         if (status)
6243             return NULL;
6244
6245         STRCAT(path, "/");
6246         STRCAT(path, filenamePtr);
6247     }
6248     else
6249     {
6250         /* If the file to be saved already exists, we can get its full path
6251            by converting its FSSpec into an FSRef. */
6252         error=FSpMakeFSRef(&file, &refFile);
6253         if (error)
6254             return NULL;
6255
6256         status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
6257         if (status)
6258             return NULL;
6259     }
6260
6261     /* Add a slash at the end if needed */
6262     if (folder)
6263         STRCAT(path, "/");
6264
6265     return (vim_strsave(path));
6266 #else
6267     /* TODO: Get rid of all USE_UNIXFILENAME below */
6268     /* Set ioNamePtr, it's the same area which is always reused. */
6269     theCPB.dirInfo.ioNamePtr = directoryName;
6270
6271     /* Trick for first entry, set ioDrParID to the first value
6272      * we want for ioDrDirID*/
6273     theCPB.dirInfo.ioDrParID = file.parID;
6274     theCPB.dirInfo.ioDrDirID = file.parID;
6275
6276     if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
6277     do
6278     {
6279         theCPB.dirInfo.ioFDirIndex = -1;
6280      /* theCPB.dirInfo.ioNamePtr   = directoryName; Already done above. */
6281         theCPB.dirInfo.ioVRefNum   = file.vRefNum;
6282      /* theCPB.dirInfo.ioDirID     = irrelevant when ioFDirIndex = -1 */
6283         theCPB.dirInfo.ioDrDirID   = theCPB.dirInfo.ioDrParID;
6284
6285         /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6286         /*  *ioNamePtr[0 TO 31] will be updated            */
6287         error = PBGetCatInfo(&theCPB,false);
6288
6289         if (error)
6290           return NULL;
6291
6292         /* Put the new directoryName in front of the current fname */
6293         STRCPY(temporaryPtr, filenamePtr);
6294         vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
6295         STRCAT(filenamePtr, ":");
6296         STRCAT(filenamePtr, temporaryPtr);
6297     }
6298 #if 1 /* def USE_UNIXFILENAME */
6299     while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6300          /*  (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6301 #else
6302     while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6303 #endif
6304
6305     /* Get the information about the volume on which the file reside */
6306     theCPB.dirInfo.ioFDirIndex = -1;
6307  /* theCPB.dirInfo.ioNamePtr   = directoryName; Already done above. */
6308     theCPB.dirInfo.ioVRefNum   = file.vRefNum;
6309  /* theCPB.dirInfo.ioDirID     = irrelevant when ioFDirIndex = -1 */
6310     theCPB.dirInfo.ioDrDirID   = theCPB.dirInfo.ioDrParID;
6311
6312     /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6313     /*  *ioNamePtr[0 TO 31] will be updated            */
6314     error = PBGetCatInfo(&theCPB,false);
6315
6316     if (error)
6317       return NULL;
6318
6319     /* For MacOS Classic always add the volume name          */
6320     /* For MacOS X add the volume name preceded by "Volumes" */
6321     /*  when we are not referring to the boot volume         */
6322 #ifdef USE_UNIXFILENAME
6323     if (file.vRefNum != dfltVol_vRefNum)
6324 #endif
6325     {
6326         /* Add the volume name */
6327         STRCPY(temporaryPtr, filenamePtr);
6328         vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
6329         STRCAT(filenamePtr, ":");
6330         STRCAT(filenamePtr, temporaryPtr);
6331
6332 #ifdef USE_UNIXFILENAME
6333         STRCPY(temporaryPtr, filenamePtr);
6334         filenamePtr[0] = 0; /* NULL terminate the string */
6335         STRCAT(filenamePtr, "Volumes:");
6336         STRCAT(filenamePtr, temporaryPtr);
6337 #endif
6338     }
6339
6340     /* Append final path separator if it's a folder */
6341     if (folder)
6342         STRCAT(fname, ":");
6343
6344     /* As we use Unix File Name for MacOS X convert it */
6345 #ifdef USE_UNIXFILENAME
6346     /* Need to insert leading / */
6347     /* TODO: get the above code to use directly the / */
6348     STRCPY(&temporaryPtr[1], filenamePtr);
6349     temporaryPtr[0] = '/';
6350     STRCPY(filenamePtr, temporaryPtr);
6351     {
6352     char        *p;
6353     for (p = fname; *p; p++)
6354         if (*p == ':')
6355             *p = '/';
6356     }
6357 #endif
6358
6359     return (vim_strsave(fname));
6360 #endif
6361 }
6362
6363 #if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
6364 /*
6365  * Input Method Control functions.
6366  */
6367
6368 /*
6369  * Notify cursor position to IM.
6370  */
6371     void
6372 im_set_position(int row, int col)
6373 {
6374 #if 0
6375     /* TODO: Implement me! */
6376     im_start_row = row;
6377     im_start_col = col;
6378 #endif
6379 }
6380
6381 static ScriptLanguageRecord gTSLWindow;
6382 static ScriptLanguageRecord gTSLInsert;
6383 static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6384
6385 static Component             gTSCWindow;
6386 static Component             gTSCInsert;
6387 static Component             gTSCDefault;
6388
6389 static int                   im_initialized = 0;
6390
6391     static void
6392 im_on_window_switch(int active)
6393 {
6394     ScriptLanguageRecord *slptr = NULL;
6395     OSStatus err;
6396
6397     if (! gui.in_use)
6398         return;
6399
6400     if (im_initialized == 0)
6401     {
6402         im_initialized = 1;
6403
6404         /* save default TSM component (should be U.S.) to default */
6405         GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6406                                      kKeyboardInputMethodClass);
6407     }
6408
6409     if (active == TRUE)
6410     {
6411         im_is_active = TRUE;
6412         ActivateTSMDocument(gTSMDocument);
6413         slptr = &gTSLWindow;
6414
6415         if (slptr)
6416         {
6417             err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6418                                                kKeyboardInputMethodClass);
6419             if (err == noErr)
6420                 err = SetTextServiceLanguage(slptr);
6421
6422             if (err == noErr)
6423                 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6424         }
6425     }
6426     else
6427     {
6428         err = GetTextServiceLanguage(&gTSLWindow);
6429         if (err == noErr)
6430             slptr = &gTSLWindow;
6431
6432         if (slptr)
6433             GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6434                                          kKeyboardInputMethodClass);
6435
6436         im_is_active = FALSE;
6437         DeactivateTSMDocument(gTSMDocument);
6438     }
6439 }
6440
6441 /*
6442  * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6443  */
6444     void
6445 im_set_active(int active)
6446 {
6447     ScriptLanguageRecord *slptr = NULL;
6448     OSStatus err;
6449
6450     if (! gui.in_use)
6451         return;
6452
6453     if (im_initialized == 0)
6454     {
6455         im_initialized = 1;
6456
6457         /* save default TSM component (should be U.S.) to default */
6458         GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6459                                      kKeyboardInputMethodClass);
6460     }
6461
6462     if (active == TRUE)
6463     {
6464         im_is_active = TRUE;
6465         ActivateTSMDocument(gTSMDocument);
6466         slptr = &gTSLInsert;
6467
6468         if (slptr)
6469         {
6470             err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6471                                                kKeyboardInputMethodClass);
6472             if (err == noErr)
6473                 err = SetTextServiceLanguage(slptr);
6474
6475             if (err == noErr)
6476                 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6477         }
6478     }
6479     else
6480     {
6481         err = GetTextServiceLanguage(&gTSLInsert);
6482         if (err == noErr)
6483             slptr = &gTSLInsert;
6484
6485         if (slptr)
6486             GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6487                                          kKeyboardInputMethodClass);
6488
6489         /* restore to default when switch to normal mode, so than we could
6490          * enter commands easier */
6491         SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6492                                      kKeyboardInputMethodClass);
6493         SetTextServiceLanguage(&gTSLDefault);
6494
6495         im_is_active = FALSE;
6496         DeactivateTSMDocument(gTSMDocument);
6497     }
6498 }
6499
6500 /*
6501  * Get IM status.  When IM is on, return not 0.  Else return 0.
6502  */
6503     int
6504 im_get_status(void)
6505 {
6506     if (! gui.in_use)
6507         return 0;
6508
6509     return im_is_active;
6510 }
6511
6512 #endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
6513
6514
6515
6516
6517 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6518 // drawer implementation
6519 static MenuRef contextMenu = NULL;
6520 enum
6521 {
6522     kTabContextMenuId = 42,
6523 };
6524
6525 // the caller has to CFRelease() the returned string
6526     static CFStringRef
6527 getTabLabel(tabpage_T *page)
6528 {
6529     get_tabline_label(page, FALSE);
6530 #ifdef MACOS_CONVERT
6531     return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6532 #else
6533     // TODO: check internal encoding?
6534     return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6535                                                    kCFStringEncodingMacRoman);
6536 #endif
6537 }
6538
6539
6540 #define DRAWER_SIZE 150
6541 #define DRAWER_INSET 16
6542
6543 static ControlRef dataBrowser = NULL;
6544
6545 // when the tabline is hidden, vim doesn't call update_tabline(). When
6546 // the tabline is shown again, show_tabline() is called before upate_tabline(),
6547 // and because of this, the tab labels and vims internal tabs are out of sync
6548 // for a very short time. to prevent inconsistent state, we store the labels
6549 // of the tabs, not pointers to the tabs (which are invalid for a short time).
6550 static CFStringRef *tabLabels = NULL;
6551 static int tabLabelsSize = 0;
6552
6553 enum
6554 {
6555     kTabsColumn = 'Tabs'
6556 };
6557
6558     static int
6559 getTabCount(void)
6560 {
6561     tabpage_T   *tp;
6562     int         numTabs = 0;
6563
6564     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6565         ++numTabs;
6566     return numTabs;
6567 }
6568
6569 // data browser item display callback
6570     static OSStatus
6571 dbItemDataCallback(ControlRef browser,
6572         DataBrowserItemID itemID,
6573         DataBrowserPropertyID property /* column id */,
6574         DataBrowserItemDataRef itemData,
6575         Boolean changeValue)
6576 {
6577     OSStatus status = noErr;
6578
6579     // assert(property == kTabsColumn); // why is this violated??
6580
6581     // changeValue is true if we have a modifieable list and data was changed.
6582     // In our case, it's always false.
6583     // (that is: if (changeValue) updateInternalData(); else return
6584     // internalData();
6585     if (!changeValue)
6586     {
6587         CFStringRef str;
6588
6589         assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6590         str = tabLabels[itemID - 1];
6591         status = SetDataBrowserItemDataText(itemData, str);
6592     }
6593     else
6594         status = errDataBrowserPropertyNotSupported;
6595
6596     return status;
6597 }
6598
6599 // data browser action callback
6600     static void
6601 dbItemNotificationCallback(ControlRef browser,
6602         DataBrowserItemID item,
6603         DataBrowserItemNotification message)
6604 {
6605     switch (message)
6606     {
6607         case kDataBrowserItemSelected:
6608             send_tabline_event(item);
6609             break;
6610     }
6611 }
6612
6613 // callbacks needed for contextual menu:
6614     static void
6615 dbGetContextualMenuCallback(ControlRef browser,
6616         MenuRef *menu,
6617         UInt32 *helpType,
6618         CFStringRef *helpItemString,
6619         AEDesc *selection)
6620 {
6621     // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6622     *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6623     *helpItemString = NULL;
6624
6625     *menu = contextMenu;
6626 }
6627
6628     static void
6629 dbSelectContextualMenuCallback(ControlRef browser,
6630         MenuRef menu,
6631         UInt32 selectionType,
6632         SInt16 menuID,
6633         MenuItemIndex menuItem)
6634 {
6635     if (selectionType == kCMMenuItemSelected)
6636     {
6637         MenuCommand command;
6638         GetMenuItemCommandID(menu, menuItem, &command);
6639
6640         // get tab that was selected when the context menu appeared
6641         // (there is always one tab selected). TODO: check if the context menu
6642         // isn't opened on an item but on empty space (has to be possible some
6643         // way, the finder does it too ;-) )
6644         Handle items = NewHandle(0);
6645         if (items != NULL)
6646         {
6647             int numItems;
6648
6649             GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6650                                            kDataBrowserItemIsSelected, items);
6651             numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6652             if (numItems > 0)
6653             {
6654                 int idx;
6655                 DataBrowserItemID *itemsPtr;
6656
6657                 HLock(items);
6658                 itemsPtr = (DataBrowserItemID *)*items;
6659                 idx = itemsPtr[0];
6660                 HUnlock(items);
6661                 send_tabline_menu_event(idx, command);
6662             }
6663             DisposeHandle(items);
6664         }
6665     }
6666 }
6667
6668 // focus callback of the data browser to always leave focus in vim
6669     static OSStatus
6670 dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6671 {
6672     assert(GetEventClass(event) == kEventClassControl
6673             && GetEventKind(event) == kEventControlSetFocusPart);
6674
6675     return paramErr;
6676 }
6677
6678
6679 // drawer callback to resize data browser to drawer size
6680     static OSStatus
6681 drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6682 {
6683     switch (GetEventKind(event))
6684     {
6685         case kEventWindowBoundsChanged: // move or resize
6686             {
6687                 UInt32 attribs;
6688                 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6689                                        NULL, sizeof(attribs), NULL, &attribs);
6690                 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6691                 {
6692                     Rect r;
6693                     GetWindowBounds(drawer, kWindowContentRgn, &r);
6694                     SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6695                     SetControlBounds(dataBrowser, &r);
6696                     SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6697                                                         kTabsColumn, r.right);
6698                 }
6699             }
6700             break;
6701     }
6702
6703     return eventNotHandledErr;
6704 }
6705
6706 // Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6707 // This way the code works on 10.2 and 10.3 as well (it doesn't have the
6708 // blue highlights in the list view on these systems, though. Oh well.)
6709
6710
6711 #import <mach-o/dyld.h>
6712
6713 enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6714
6715     static OSStatus
6716 myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6717         OptionBits inAttributesToSet,
6718         OptionBits inAttributesToClear)
6719 {
6720     long osVersion;
6721     char *symbolName;
6722     NSSymbol symbol = NULL;
6723     OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6724               OptionBits   inAttributesToSet, OptionBits inAttributesToClear);
6725
6726     Gestalt(gestaltSystemVersion, &osVersion);
6727     if (osVersion < 0x1040) // only supported for 10.4 (and up)
6728         return noErr;
6729
6730     // C name mangling...
6731     symbolName = "_DataBrowserChangeAttributes";
6732     if (!NSIsSymbolNameDefined(symbolName)
6733             || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6734         return noErr;
6735
6736     dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6737     if (dataBrowserChangeAttributes == NULL)
6738         return noErr; // well...
6739     return dataBrowserChangeAttributes(inDataBrowser,
6740                                       inAttributesToSet, inAttributesToClear);
6741 }
6742
6743     static void
6744 initialise_tabline(void)
6745 {
6746     Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6747     DataBrowserCallbacks dbCallbacks;
6748     EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6749     EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6750     DataBrowserListViewColumnDesc colDesc;
6751
6752     // drawers have to have compositing enabled
6753     CreateNewWindow(kDrawerWindowClass,
6754             kWindowStandardHandlerAttribute
6755                     | kWindowCompositingAttribute
6756                     | kWindowResizableAttribute
6757                     | kWindowLiveResizeAttribute,
6758             &drawerRect, &drawer);
6759
6760     SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6761     SetDrawerParent(drawer, gui.VimWindow);
6762     SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6763
6764
6765     // create list view embedded in drawer
6766     CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6767                                                                 &dataBrowser);
6768
6769     dbCallbacks.version = kDataBrowserLatestCallbacks;
6770     InitDataBrowserCallbacks(&dbCallbacks);
6771     dbCallbacks.u.v1.itemDataCallback =
6772                                 NewDataBrowserItemDataUPP(dbItemDataCallback);
6773     dbCallbacks.u.v1.itemNotificationCallback =
6774                 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6775     dbCallbacks.u.v1.getContextualMenuCallback =
6776               NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6777     dbCallbacks.u.v1.selectContextualMenuCallback =
6778         NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6779
6780     SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6781
6782     SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6783     SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6784     SetDataBrowserSelectionFlags(dataBrowser,
6785               kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6786     SetDataBrowserTableViewHiliteStyle(dataBrowser,
6787                                              kDataBrowserTableViewFillHilite);
6788     Boolean b = false;
6789     SetControlData(dataBrowser, kControlEntireControl,
6790                   kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6791
6792     // enable blue background in data browser (this is only in 10.4 and vim
6793     // has to support older osx versions as well, so we have to load this
6794     // function dynamically)
6795     myDataBrowserChangeAttributes(dataBrowser,
6796                       kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6797
6798     // install callback that keeps focus in vim and away from the data browser
6799     InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6800                                                                   NULL, NULL);
6801
6802     // install callback that keeps data browser at the size of the drawer
6803     InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6804                                                                   NULL, NULL);
6805
6806     // add "tabs" column to data browser
6807     colDesc.propertyDesc.propertyID = kTabsColumn;
6808     colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6809
6810     // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6811     colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6812
6813     colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6814     colDesc.headerBtnDesc.minimumWidth = 100;
6815     colDesc.headerBtnDesc.maximumWidth = 150;
6816     colDesc.headerBtnDesc.titleOffset = 0;
6817     colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6818     colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6819     colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6820     colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6821
6822     AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6823
6824     // create tabline popup menu required by vim docs (see :he tabline-menu)
6825     CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6826     AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6827                                                     TABLINE_MENU_CLOSE, NULL);
6828     AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6829                                                       TABLINE_MENU_NEW, NULL);
6830     AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6831                                                      TABLINE_MENU_OPEN, NULL);
6832 }
6833
6834
6835 /*
6836  * Show or hide the tabline.
6837  */
6838     void
6839 gui_mch_show_tabline(int showit)
6840 {
6841     if (showit == 0)
6842         CloseDrawer(drawer, true);
6843     else
6844         OpenDrawer(drawer, kWindowEdgeRight, true);
6845 }
6846
6847 /*
6848  * Return TRUE when tabline is displayed.
6849  */
6850     int
6851 gui_mch_showing_tabline(void)
6852 {
6853     WindowDrawerState state = GetDrawerState(drawer);
6854
6855     return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6856 }
6857
6858 /*
6859  * Update the labels of the tabline.
6860  */
6861     void
6862 gui_mch_update_tabline(void)
6863 {
6864     tabpage_T   *tp;
6865     int         numTabs = getTabCount();
6866     int         nr = 1;
6867     int         curtabidx = 1;
6868
6869     // adjust data browser
6870     if (tabLabels != NULL)
6871     {
6872         int i;
6873
6874         for (i = 0; i < tabLabelsSize; ++i)
6875             CFRelease(tabLabels[i]);
6876         free(tabLabels);
6877     }
6878     tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6879     tabLabelsSize = numTabs;
6880
6881     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6882     {
6883         if (tp == curtab)
6884             curtabidx = nr;
6885         tabLabels[nr-1] = getTabLabel(tp);
6886     }
6887
6888     RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6889                                                   kDataBrowserItemNoProperty);
6890     // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6891     // can pass NULL for the id array
6892     AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6893                                                   kDataBrowserItemNoProperty);
6894
6895     DataBrowserItemID item = curtabidx;
6896     SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6897 }
6898
6899 /*
6900  * Set the current tab to "nr".  First tab is 1.
6901  */
6902     void
6903 gui_mch_set_curtab(nr)
6904     int         nr;
6905 {
6906     DataBrowserItemID item = nr;
6907     SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6908
6909     // TODO: call something like this?: (or restore scroll position, or...)
6910     RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6911                                                       kDataBrowserRevealOnly);
6912 }
6913
6914 #endif // FEAT_GUI_TABLINE