1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Macintosh port by Dany St-Amant
7 * Port to MPW by Bernhard Pruemmer
8 * Initial Carbon port by Ammon Skidmore
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.
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"
22 * TODO: Change still to merge from the macvim's iDisk
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.
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)
37 #include <Devices.h> /* included first to avoid CR problems */
40 #define USE_CARBONIZED
41 #define USE_AEVENT /* Enable AEVENT */
42 #undef USE_OFFSETED_WINDOW /* Debugging feature: start Vim window OFFSETed */
44 /* Compile as CodeWarior External Editor */
45 #if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46 # define USE_AEVENT /* Need Apple Event Support */
49 /* Vim's Scrap flavor. */
50 #define VIMSCRAPFLAVOR 'VIM!'
52 # define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
54 # define SCRAPTEXTFLAVOR kScrapFlavorTypeText
57 static EventHandlerUPP mouseWheelHandlerUPP = NULL;
58 SInt32 gMacSystemVersion;
61 # define USE_CARBONKEYHANDLER
63 static int im_is_active = FALSE;
65 /* TODO: Implement me! */
66 static int im_start_row = 0;
67 static int im_start_col = 0;
70 #define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
72 static TSMDocumentID gTSMDocument;
74 static void im_on_window_switch(int active);
75 static EventHandlerUPP keyEventHandlerUPP = NULL;
76 static EventHandlerUPP winEventHandlerUPP = NULL;
78 static pascal OSStatus gui_mac_handle_window_activate(
79 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
81 static pascal OSStatus gui_mac_handle_text_input(
82 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
84 static pascal OSStatus gui_mac_update_input_area(
85 EventHandlerCallRef nextHandler, EventRef theEvent);
87 static pascal OSStatus gui_mac_unicode_key_event(
88 EventHandlerCallRef nextHandler, EventRef theEvent);
93 /* Include some file. TODO: move into os_mac.h */
95 #include <Resources.h>
96 #include <Processes.h>
98 # include <AppleEvents.h>
99 # include <AERegistry.h>
101 # include <Gestalt.h>
102 #if UNIVERSAL_INTERFACES_VERSION >= 0x0330
103 # include <ControlDefinitions.h>
104 # include <Navigation.h> /* Navigation only part of ?? */
107 /* Help Manager (balloon.h, HM prefixed functions) are not supported
108 * under Carbon (Jussi) */
110 /* New Help Interface for Mac, not implemented yet.*/
111 # include <MacHelp.h>
115 * These seem to be rectangle options. Why are they not found in
119 #define kCreateEmpty 2 /*1*/
120 #define kCreateRect 2
124 * Dany: Don't like those...
126 #define topLeft(r) (((Point*)&(r))[0])
127 #define botRight(r) (((Point*)&(r))[1])
130 /* Time of last mouse click, to detect double-click */
131 static long lastMouseTick = 0;
134 static RgnHandle cursorRgn;
135 static RgnHandle dragRgn;
136 static Rect dragRect;
137 static short dragRectEnbl;
138 static short dragRectControl;
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).
145 static int allow_scrollbar = FALSE;
147 /* Last mouse click caused contextual menu, (to provide proper release) */
148 static short clickIsPopup;
150 /* Feedback Action for Scrollbar */
151 ControlActionUPP gScrollAction;
152 ControlActionUPP gScrollDrag;
154 /* Keeping track of which scrollbar is being dragged */
155 static ControlHandle dragged_sb = NULL;
157 /* Vector of char_u --> control index for hotkeys in dialogs */
158 static short *gDialogHotKeys;
165 Boolean isPanelVisible;
166 } gFontPanelInfo = { 0, 0, 0, false };
169 # define USE_ATSUI_DRAWING
171 ATSUStyle gFontStyle;
173 ATSUStyle gWideFontStyle;
175 Boolean gIsFontFallbackSet;
176 UInt32 useAntialias_cached = 0x0;
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)
187 #define vk_Esc 0x35 /* -> 1B */
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*/ /*?*/
205 #define vk_Clr 0x47 /* -> 1B (ESC) */
206 #define vk_Enter 0x4C /* -> 03 */
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 */
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 */
221 #define vk_Up 0x7E /* -> 1E */
222 #define vk_Down 0x7D /* -> 1F */
223 #define vk_Left 0x7B /* -> 1C */
224 #define vk_Right 0x7C /* -> 1D */
226 #define vk_Undo vk_F1
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
248 {vk_Right, 'k', 'r'},
267 /* {XK_Help, '%', '1'}, */
268 /* {XK_Undo, '&', '8'}, */
269 /* {XK_BackSpace, 'k', 'b'}, */
271 {vk_Delete, 'k', 'b'},
273 {vk_Insert, 'k', 'I'},
274 {vk_FwdDelete, 'k', 'D'},
277 /* {XK_Prior, 'k', 'P'}, */
278 /* {XK_Next, 'k', 'N'}, */
279 /* {XK_Print, '%', '9'}, */
281 {vk_PageUp, 'k', 'P'},
282 {vk_PageDown, 'k', 'N'},
284 /* End of list marker: */
289 * ------------------------------------------------------------
290 * Forward declaration (for those needed)
291 * ------------------------------------------------------------
295 OSErr HandleUnusedParms(const AppleEvent *theAEvent);
298 #ifdef FEAT_GUI_TABLINE
299 static void initialise_tabline(void);
300 static WindowRef drawer = NULL; // TODO: put into gui.h
303 #ifdef USE_ATSUI_DRAWING
304 static void gui_mac_set_font_attributes(GuiFont font);
305 static void gui_mac_dispose_atsui_style(void);
309 * ------------------------------------------------------------
311 * ------------------------------------------------------------
317 * Allocate memory and convert the C-String passed in
318 * into a pascal string
323 C2Pascal_save(char_u *Cstring)
325 char_u *PascalString;
331 len = STRLEN(Cstring);
333 if (len > 255) /* Truncate if necessary */
336 PascalString = alloc(len + 1);
337 if (PascalString != NULL)
339 mch_memmove(PascalString + 1, Cstring, len);
340 PascalString[0] = len;
347 * C2Pascal_save_and_remove_backslash
349 * Allocate memory and convert the C-String passed in
350 * into a pascal string. Also remove the backslash at the same time
355 C2Pascal_save_and_remove_backslash(char_u *Cstring)
357 char_u *PascalString;
361 len = STRLEN(Cstring);
363 if (len > 255) /* Truncate if necessary */
366 PascalString = alloc(len + 1);
367 if (PascalString != NULL)
369 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
371 if ((*c == '\\') && (c[1] != 0))
379 PascalString[0] = len;
386 * Convert the modifiers of an Event into vim's modifiers (mouse)
390 EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
392 int_u vimModifiers = 0x00;
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;
401 /* Not yet supported */
402 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
403 vimModifiers |= MOUSE_CMD;
405 return (vimModifiers);
409 * Convert the modifiers of an Event into vim's modifiers (keys)
413 EventModifiers2VimModifiers(EventModifiers macModifiers)
415 int_u vimModifiers = 0x00;
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;
424 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
425 vimModifiers |= MOD_MASK_CMD;
427 return (vimModifiers);
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.
439 points_to_pixels(char_u *str, char_u **end, int vertical)
447 if (*str == '.' && divisor == 0)
449 /* Start keeping a divisor, for later */
458 points += *str - '0';
467 pixels = points/divisor;
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.
479 menu_title_removing_mnemonic(vimmenu_T *menu)
484 CFRange mnemonicStart;
486 CFMutableStringRef cleanedName;
488 menuTitleLen = STRLEN(menu->dname);
489 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
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);
498 if (mnemonicStart.location != kCFNotFound
499 && (mnemonicStart.location + 2) < displayLen
500 && CFStringGetCharacterAtIndex(name,
501 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
503 if (CFStringFindWithOptions(name, CFSTR(")"),
504 CFRangeMake(mnemonicStart.location + 1,
505 displayLen - mnemonicStart.location - 1),
506 kCFCompareBackwards, &mnemonicEnd) &&
507 (mnemonicStart.location + 2) == mnemonicEnd.location)
509 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
512 CFStringDelete(cleanedName,
513 CFRangeMake(mnemonicStart.location,
514 mnemonicEnd.location + 1 -
515 mnemonicStart.location));
529 * Convert a list of FSSpec aliases into a list of fullpathname
534 new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
536 char_u **fnames = NULL;
541 AEKeyword dummyKeyword;
544 /* Get number of files in list */
545 *error = AECountItems(theList, numFiles);
549 /* Allocate the pointer list */
550 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
552 /* Empty out the list */
553 for (fileCount = 0; fileCount < *numFiles; fileCount++)
554 fnames[fileCount] = NULL;
556 /* Scan the list of FSSpec */
557 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
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);
565 /* Caller is able to clean up */
566 /* TODO: Should be clean up or not? For safety. */
570 /* Convert the FSSpec to a pathname */
571 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
578 * ------------------------------------------------------------
579 * CodeWarrior External Editor Support
580 * ------------------------------------------------------------
582 #ifdef FEAT_CW_EDITOR
585 * Handle the Window Search event from CodeWarrior
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.
596 * None. Put data in the location specified in the structure received.
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.
608 typedef struct WindowSearch WindowSearch;
609 struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
611 FSSpec theFile; // identifies the file
612 long *theDate; // where to put the modification date/time
617 const AppleEvent *theAEvent,
618 AppleEvent *theReply,
623 int foundFile = false;
625 WindowSearch SearchData;
628 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
632 error = HandleUnusedParms(theAEvent);
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)
646 if (foundFile == false)
647 *SearchData.theDate = fnfErr;
649 *SearchData.theDate = buf->b_mtime;
655 * Handle the Modified (from IDE to Editor) event from CodeWarrior
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.
668 * The reply for this event is:
670 * keyDirectObject typeAEList required
671 * each element in the list is a structure of typeChar
676 * When building the reply event, include one element in the list for
677 * each open file that has been modified.
681 typedef struct ModificationInfo ModificationInfo;
682 struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
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
691 const AppleEvent *theAEvent,
692 AppleEvent *theReply,
696 AEDescList replyList;
698 ModificationInfo theFile;
703 error = HandleUnusedParms(theAEvent);
708 /* replyObject.descriptorType = typeNull;
709 replyObject.dataHandle = nil;*/
711 /* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
712 error = AECreateList(nil, 0, false, &replyList);
717 error = AECountItems(&replyList, &numFiles);
719 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
720 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
728 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
729 if (buf->b_ml.ml_mfp != NULL)
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));
739 error = AECountItems(&replyList, &numFiles);
742 /* We can add data only if something to reply */
743 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
745 if (replyList.dataHandle)
746 AEDisposeDesc(&replyList);
752 * Handle the Get Text event from CodeWarrior
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.
765 * None. Put data in locations specified in the structure received.
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
777 typedef struct CW_GetText CW_GetText;
778 struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
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 */
788 const AppleEvent *theAEvent,
789 AppleEvent *theReply,
794 int foundFile = false;
796 CW_GetText GetTextData;
799 char_u *fullbuffer = NULL;
805 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
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)
820 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
821 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
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)
832 break; /* Simple handling for now */
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);
843 if (fullbuffer != NULL)
845 HLock(GetTextData.theText);
846 fullbuffer[BufferSize-1] = 0;
847 HUnlock(GetTextData.theText);
849 if (foundFile == false)
850 *GetTextData.theDate = fnfErr;
852 /* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
853 *GetTextData.theDate = buf->b_mtime;
856 error = HandleUnusedParms(theAEvent);
865 /* Taken from MoreAppleEvents:ProcessHelpers*/
867 FindProcessBySignature(
868 const OSType targetType,
869 const OSType targetCreator,
870 ProcessSerialNumberPtr psnPtr)
873 Boolean lookingForProcess = true;
875 ProcessInfoRec infoRec;
877 infoRec.processInfoLength = sizeof(ProcessInfoRec);
878 infoRec.processName = nil;
879 infoRec.processAppSpec = nil;
881 psnPtr->lowLongOfPSN = kNoProcess;
882 psnPtr->highLongOfPSN = kNoProcess;
884 while (lookingForProcess)
886 anErr = GetNextProcess(psnPtr);
888 lookingForProcess = false;
891 anErr = GetProcessInformation(psnPtr, &infoRec);
893 && (infoRec.processType == targetType)
894 && (infoRec.processSignature == targetCreator))
895 lookingForProcess = false;
900 }//end FindProcessBySignature
903 Send_KAHL_MOD_AE(buf_T *buf)
906 AEDesc targetAppDesc = { typeNull, nil };
907 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
908 AppleEvent theReply = { typeNull, nil };
910 AppleEvent theEvent = {typeNull, nil };
911 AEIdleUPP idleProcUPP = nil;
912 ModificationInfo ModData;
915 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
918 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
919 sizeof(ProcessSerialNumber), &targetAppDesc);
923 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
924 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
927 AEDisposeDesc(&targetAppDesc);
930 ModData.theFile = buf->b_FSSpec;
931 ModData.theDate = buf->b_mtime;
934 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
936 if (idleProcUPP == nil)
937 sendMode = kAENoReply;
939 sendMode = kAEWaitReply;
942 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
943 if (anErr == noErr && sendMode == kAEWaitReply)
945 /* anErr = AEHGetHandlerError(&theReply);*/
947 (void) AEDisposeDesc(&theReply);
950 #endif /* FEAT_CW_EDITOR */
953 * ------------------------------------------------------------
954 * Apple Event Handling procedure
955 * ------------------------------------------------------------
960 * Handle the Unused parms of an AppleEvent
964 HandleUnusedParms(const AppleEvent *theAEvent)
969 AEKeyword missedKeyword;
971 /* Get the "missed keyword" attribute from the AppleEvent. */
972 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
973 typeKeyword, &dummyType,
974 (Ptr)&missedKeyword, sizeof(missedKeyword),
977 /* If the descriptor isn't found, then we got the required parameters. */
978 if (error == errAEDescNotFound)
985 /* Why is this removed? */
986 error = errAEEventNotHandled;
995 * Handle the ODoc AppleEvent
997 * Deals with all files dragged to the application icon.
1001 typedef struct SelectionRange SelectionRange;
1002 struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
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
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.
1021 HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
1024 * TODO: Clean up the code with convert the AppleEvent into
1027 OSErr error = noErr;
1028 // OSErr firstError = noErr;
1029 // short numErrors = 0;
1035 // char_u fname[256];
1037 SelectionRange thePosition;
1038 short gotPosition = false;
1041 /* the direct object parameter is the list of aliases to files (one or more) */
1042 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1047 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1050 if (error == errAEDescNotFound)
1056 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1060 if (thePosition.lineNum >= 0)
1066 // Set the range char wise
1076 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1080 /* TODO: empty fnames[] first */
1091 /* these are the initial files dropped on the Vim icon */
1092 for (i = 0 ; i < numFiles; i++)
1094 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1095 || (p = vim_strsave(fnames[i])) == NULL)
1098 alist_add(&global_alist, p, 2);
1100 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1103 /* If the file name was already in the buffer list we need to switch
1105 if (curbuf->b_fnum != fnum)
1109 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1110 do_cmdline_cmd(cmd);
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);
1120 /* Handle the drop, :edit to get to the file */
1121 handle_drop(numFiles, fnames, FALSE);
1123 /* TODO: Handle the goto/select line more cleanly */
1124 if ((numFiles == 1) & (gotPosition))
1126 if (thePosition.lineNum >= 0)
1128 lnum = thePosition.lineNum + 1;
1129 /* oap->motion_type = MLINE;
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);*/
1140 goto_byte(thePosition.startRange + 1);
1143 /* Update the screen display */
1144 update_screen(NOT_VALID);
1146 /* Select the text if possible */
1149 VIsual_active = TRUE;
1150 VIsual_select = FALSE;
1151 VIsual = curwin->w_cursor;
1152 if (thePosition.lineNum < 0)
1155 goto_byte(thePosition.endRange);
1167 /* Fake mouse event to wake from stall */
1168 PostEvent(mouseUp, 0);
1171 AEDisposeDesc(&theList); /* dispose what we allocated */
1173 error = HandleUnusedParms(theAEvent);
1182 Handle_aevt_oapp_AE(
1183 const AppleEvent *theAEvent,
1184 AppleEvent *theReply,
1187 OSErr error = noErr;
1189 error = HandleUnusedParms(theAEvent);
1198 Handle_aevt_quit_AE(
1199 const AppleEvent *theAEvent,
1200 AppleEvent *theReply,
1203 OSErr error = noErr;
1205 error = HandleUnusedParms(theAEvent);
1209 /* Need to fake a :confirm qa */
1210 do_cmdline_cmd((char_u *)"confirm qa");
1220 Handle_aevt_pdoc_AE(
1221 const AppleEvent *theAEvent,
1222 AppleEvent *theReply,
1225 OSErr error = noErr;
1227 error = HandleUnusedParms(theAEvent);
1233 * Handling of unknown AppleEvent
1235 * (Just get rid of all the parms)
1239 const AppleEvent *theAEvent,
1240 AppleEvent *theReply,
1243 OSErr error = noErr;
1245 error = HandleUnusedParms(theAEvent);
1252 * Install the various AppleEvent Handlers
1255 InstallAEHandlers(void)
1259 /* install open application handler */
1260 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
1261 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
1267 /* install quit application handler */
1268 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
1269 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
1275 /* install open document handler */
1276 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
1277 NewAEEventHandlerUPP(HandleODocAE), 0, false);
1283 /* install print document handler */
1284 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
1285 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
1287 /* Install Core Suite */
1288 /* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
1289 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1291 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
1292 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1294 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
1295 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1297 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
1298 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1300 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
1301 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1303 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
1304 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1306 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
1307 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
1309 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
1310 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
1312 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
1313 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1315 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
1316 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1318 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
1319 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1321 error = AEInstallEventHandler(kAECoreSuite, kAESave,
1322 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1324 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
1325 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1328 #ifdef FEAT_CW_EDITOR
1330 * Bind codewarrior support handlers
1332 error = AEInstallEventHandler('KAHL', 'GTTX',
1333 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
1338 error = AEInstallEventHandler('KAHL', 'SRCH',
1339 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
1344 error = AEInstallEventHandler('KAHL', 'MOD ',
1345 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
1355 #endif /* USE_AEVENT */
1359 * Callback function, installed by InstallFontPanelHandler(), below,
1360 * to handle Font Panel events.
1364 EventHandlerCallRef inHandlerCallRef,
1368 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1370 gFontPanelInfo.isPanelVisible = false;
1374 if (GetEventKind(inEvent) == kEventFontSelection)
1377 FMFontFamily newFamily;
1379 FMFontStyle newStyle;
1381 /* Retrieve the font family ID number. */
1382 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1383 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1384 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1386 if (status == noErr)
1387 gFontPanelInfo.family = newFamily;
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;
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;
1406 InstallFontPanelHandler(void)
1408 EventTypeSpec eventTypes[2];
1409 EventHandlerUPP handlerUPP;
1410 /* EventHandlerRef handlerRef; */
1412 eventTypes[0].eventClass = kEventClassFont;
1413 eventTypes[0].eventKind = kEventFontSelection;
1414 eventTypes[1].eventClass = kEventClassFont;
1415 eventTypes[1].eventKind = kEventFontPanelClosed;
1417 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1419 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1420 /*userData=*/NULL, /*handlerRef=*/NULL);
1425 * Fill the buffer pointed to by outName with the name and size
1426 * of the font currently selected in the Font Panel.
1428 #define FONT_STYLE_BUFFER_SIZE 32
1430 GetFontPanelSelection(char_u *outName)
1433 ByteCount fontNameLen = 0;
1435 char_u styleString[FONT_STYLE_BUFFER_SIZE];
1440 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1442 /* Canonicalize localized font names */
1443 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1444 gFontPanelInfo.style, &fid, NULL) != noErr)
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)
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" : "")*/);
1462 if ((fontNameLen + STRLEN(styleString)) < 255)
1463 STRCPY(outName + fontNameLen, styleString);
1473 * ------------------------------------------------------------
1475 * ------------------------------------------------------------
1479 * gui_mac_get_menu_item_index
1481 * Returns the index inside the menu wher
1483 short /* Shoulde we return MenuItemIndex? */
1484 gui_mac_get_menu_item_index(vimmenu_T *pMenu)
1487 short itemIndex = -1;
1488 vimmenu_T *pBrother;
1490 /* Only menu without parent are the:
1491 * -menu in the menubar
1495 * Which are not items anyway.
1499 /* Start from the Oldest Brother */
1500 pBrother = pMenu->parent->children;
1502 while ((pBrother) && (itemIndex == -1))
1504 if (pBrother == pMenu)
1507 pBrother = pBrother->next;
1514 gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
1517 vimmenu_T *pChildMenu;
1518 vimmenu_T *pElder = pMenu->parent;
1521 /* Only menu without parent are the:
1522 * -menu in the menubar
1526 * Which are not items anyway.
1529 if ((pElder) && (pElder->submenu_id == menuID))
1531 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1532 pMenu = pMenu->next;
1536 for (; pMenu != NULL; pMenu = pMenu->next)
1538 if (pMenu->children != NULL)
1540 pChildMenu = gui_mac_get_vim_menu
1541 (menuID, itemIndex, pMenu->children);
1554 * ------------------------------------------------------------
1555 * MacOS Feedback procedures
1556 * ------------------------------------------------------------
1560 gui_mac_drag_thumb(ControlHandle theControl, short partCode)
1563 int value, dragging;
1564 ControlHandle theControlToUse;
1565 int dont_scroll_save = dont_scroll;
1567 theControlToUse = dragged_sb;
1569 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
1574 /* Need to find value by diff between Old Poss New Pos */
1575 value = GetControl32BitValue(theControlToUse);
1576 dragging = (partCode != 0);
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;
1587 gui_mac_scroll_action(ControlHandle theControl, short partCode)
1589 /* TODO: have live support */
1590 scrollbar_T *sb, *sb_info;
1594 int dragging = FALSE;
1595 int dont_scroll_save = dont_scroll;
1597 sb = gui_find_scrollbar((long)GetControlReference(theControl));
1602 if (sb->wp != NULL) /* Left or right scrollbar */
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().
1609 sb_info = &sb->wp->w_scrollbars[0];
1611 if (sb_info->size > 5)
1612 page = sb_info->size - 2; /* use two lines of context */
1614 page = sb_info->size;
1616 else /* Bottom scrollbar */
1619 page = W_WIDTH(curwin) - 5;
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;
1631 value = sb_info->value + data;
1632 /* if (value > sb_info->max)
1633 value = sb_info->max;
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;
1644 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1646 /* if (sb_info->wp != NULL)
1652 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1657 current_scrollbar = sb_num;
1658 scrollbar_value = value;
1660 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1666 * ------------------------------------------------------------
1667 * MacOS Click Handling procedures
1668 * ------------------------------------------------------------
1673 * Handle a click inside the window, it may happens in the
1674 * scrollbar or the contents.
1676 * TODO: Add support for potential TOOLBAR
1679 gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
1684 ControlHandle theControl;
1688 thePoint = theEvent->where;
1689 GlobalToLocal(&thePoint);
1690 SelectWindow(whichWindow);
1692 thePortion = FindControl(thePoint, whichWindow, &theControl);
1694 if (theControl != NUL)
1696 /* We hit a scollbar */
1698 if (thePortion != kControlIndicatorPart)
1700 dragged_sb = theControl;
1701 TrackControl(theControl, thePoint, gScrollAction);
1706 dragged_sb = theControl;
1708 TrackControl(theControl, thePoint, gScrollDrag);
1710 TrackControl(theControl, thePoint, NULL);
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) */
1720 /* We are inside the contents */
1722 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1723 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1725 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1726 vimMouseButton = MOUSE_LEFT;
1728 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
1730 clickIsPopup = FALSE;
1732 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1734 vimMouseButton = MOUSE_RIGHT;
1735 vimModifiers &= ~MOUSE_CTRL;
1736 clickIsPopup = TRUE;
1739 /* Is it a double click ? */
1740 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1742 /* Send the mouse click to Vim */
1743 gui_send_mouse_event(vimMouseButton, thePoint.h,
1744 thePoint.v, dblClick, vimModifiers);
1746 /* Create the rectangle around the cursor to detect
1747 * the mouse dragging
1750 /* TODO: Do we need to this even for the contextual menu?
1751 * It may be require for popup_setpos, but for popup?
1753 if (vimMouseButton == MOUSE_LEFT)
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));
1761 dragRectEnbl = TRUE;
1762 dragRectControl = kCreateRect;
1768 * Handle the click in the titlebar (to move the window)
1771 gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
1774 Rect *movingLimitsPtr = &movingLimits;
1776 /* TODO: may try to prevent move outside screen? */
1777 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
1778 DragWindow(whichWindow, where, movingLimitsPtr);
1782 * Handle the click in the grow box
1785 gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
1789 unsigned short newWidth;
1790 unsigned short newHeight;
1792 Rect *resizeLimitsPtr = &resizeLimits;
1793 Rect NewContentRect;
1795 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
1797 /* Set the minimum size */
1798 /* TODO: Should this come from Vim? */
1799 resizeLimits.top = 100;
1800 resizeLimits.left = 100;
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);
1811 * Handle the click in the zoom box
1814 gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
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 */
1829 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1830 ? inZoomIn : inZoomOut;
1832 if (!TrackBox(whichWindow, theEvent->where, thePart))
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;
1846 ZoomWindowIdeal(whichWindow, thePart, &p);
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);
1855 * ------------------------------------------------------------
1856 * MacOS Event Handling procedure
1857 * ------------------------------------------------------------
1861 * Handle the Update Event
1865 gui_mac_doUpdateEvent(EventRecord *event)
1867 WindowPtr whichWindow;
1869 RgnHandle updateRgn;
1871 Rect *updateRectPtr;
1877 updateRgn = NewRgn();
1878 if (updateRgn == NULL)
1881 /* This could be done by the caller as we
1882 * don't require anything else out of the event
1884 whichWindow = (WindowPtr) event->message;
1886 /* Save Current Port */
1889 /* Select the Window's Port */
1890 SetPortWindowPort(whichWindow);
1892 /* Let's update the window */
1893 BeginUpdate(whichWindow);
1894 /* Redraw the biggest rectangle covering the area
1897 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1899 /* Would be more appropriate to use the following but doesn't
1900 * seem to work under MacOS X (Dany)
1902 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1905 /* Use the HLock useless in Carbon? Is it harmful?*/
1906 HLock((Handle) updateRgn);
1908 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
1910 /* Code from original Carbon Port (using GetWindowRegion.
1911 * I believe the UpdateRgn is already in local (Dany)
1913 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1914 GlobalToLocal(&botRight(updateRect));
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))
1924 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1927 if (updateRectPtr->top < FILL_Y(0))
1929 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1932 if (updateRectPtr->right > FILL_X(Columns))
1934 SetRect(&rc, FILL_X(Columns), 0,
1935 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
1938 if (updateRectPtr->bottom > FILL_Y(Rows))
1940 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
1941 FILL_Y(Rows) + gui.border_offset);
1944 HUnlock((Handle) updateRgn);
1945 DisposeRgn(updateRgn);
1947 /* Update scrollbars */
1948 DrawControls(whichWindow);
1950 /* Update the GrowBox */
1951 /* Taken from FAQ 33-27 */
1953 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
1955 ClipRect(&growRect);
1956 DrawGrowIcon(whichWindow);
1958 DisposeRgn(saveRgn);
1959 EndUpdate(whichWindow);
1961 /* Restore original Port */
1966 * Handle the activate/deactivate event
1967 * (apply to a window)
1970 gui_mac_doActivateEvent(EventRecord *event)
1972 WindowPtr whichWindow;
1974 whichWindow = (WindowPtr) event->message;
1975 /* Dim scrollbars */
1976 if (whichWindow == gui.VimWindow)
1978 ControlRef rootControl;
1979 GetRootControl(gui.VimWindow, &rootControl);
1980 if ((event->modifiers) & activeFlag)
1981 ActivateControl(rootControl);
1983 DeactivateControl(rootControl);
1987 gui_focus_change((event->modifiers) & activeFlag);
1992 * Handle the suspend/resume event
1993 * (apply to the application)
1996 gui_mac_doSuspendEvent(EventRecord *event)
1998 /* The frontmost application just changed */
2000 /* NOTE: the suspend may happen before the deactivate
2004 /* May not need to change focus as the window will
2005 * get an activate/deactivate event
2007 if (event->message & 1)
2009 gui_focus_change(TRUE);
2012 gui_focus_change(FALSE);
2018 #ifdef USE_CARBONKEYHANDLER
2019 static pascal OSStatus
2020 gui_mac_handle_window_activate(
2021 EventHandlerCallRef nextHandler,
2025 UInt32 eventClass = GetEventClass(theEvent);
2026 UInt32 eventKind = GetEventKind(theEvent);
2028 if (eventClass == kEventClassWindow)
2032 case kEventWindowActivated:
2033 #if defined(USE_IM_CONTROL)
2034 im_on_window_switch(TRUE);
2038 case kEventWindowDeactivated:
2039 #if defined(USE_IM_CONTROL)
2040 im_on_window_switch(FALSE);
2046 return eventNotHandledErr;
2049 static pascal OSStatus
2050 gui_mac_handle_text_input(
2051 EventHandlerCallRef nextHandler,
2055 UInt32 eventClass = GetEventClass(theEvent);
2056 UInt32 eventKind = GetEventKind(theEvent);
2058 if (eventClass != kEventClassTextInput)
2059 return eventNotHandledErr;
2061 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2062 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2063 (kEventTextInputOffsetToPos != eventKind) &&
2064 (kEventTextInputPosToOffset != eventKind) &&
2065 (kEventTextInputGetSelectedText != eventKind))
2066 return eventNotHandledErr;
2070 case kEventTextInputUpdateActiveInputArea:
2071 return gui_mac_update_input_area(nextHandler, theEvent);
2072 case kEventTextInputUnicodeForKeyEvent:
2073 return gui_mac_unicode_key_event(nextHandler, theEvent);
2075 case kEventTextInputOffsetToPos:
2076 case kEventTextInputPosToOffset:
2077 case kEventTextInputGetSelectedText:
2081 return eventNotHandledErr;
2085 OSStatus gui_mac_update_input_area(
2086 EventHandlerCallRef nextHandler,
2089 return eventNotHandledErr;
2092 static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2095 # define INLINE_KEY_BUFFER_SIZE 80
2096 static pascal OSStatus
2097 gui_mac_unicode_key_event(
2098 EventHandlerCallRef nextHandler,
2101 /* Multibyte-friendly key event handler */
2105 char_u result[INLINE_KEY_BUFFER_SIZE];
2110 UInt32 modifiers, vimModifiers;
2113 Boolean isSpecial = FALSE;
2117 /* Mask the mouse (as per user setting) */
2121 /* Don't use the keys when the dialog wants them. */
2123 return eventNotHandledErr;
2125 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2126 typeUnicodeText, NULL, 0, &actualSize, NULL))
2127 return eventNotHandledErr;
2129 text = (UniChar *)alloc(actualSize);
2131 return eventNotHandledErr;
2133 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
2134 typeUnicodeText, NULL, actualSize, NULL, text);
2135 require_noerr(err, done);
2137 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
2138 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
2139 require_noerr(err, done);
2141 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
2142 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
2143 require_noerr(err, done);
2145 err = GetEventParameter(keyEvent, kEventParamKeyCode,
2146 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
2147 require_noerr(err, done);
2149 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
2150 typeChar, NULL, sizeof(char), NULL, &charcode);
2151 require_noerr(err, done);
2154 if (modifiers & cmdKey)
2155 goto done; /* Let system handle Cmd+... */
2158 key_char = charcode;
2159 vimModifiers = EventModifiers2VimModifiers(modifiers);
2161 /* Find the special key (eg., for cursor keys) */
2162 if (actualSize <= sizeof(UniChar) &&
2163 ((text[0] < 0x20) || (text[0] == 0x7f)))
2165 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2166 if (special_keys[i].key_sym == key_sym)
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);
2177 /* Intercept CMD-. and CTRL-c */
2178 if (((modifiers & controlKey) && key_char == 'c') ||
2179 ((modifiers & cmdKey) && key_char == '.'))
2184 /* remove SHIFT for keys that are already shifted, e.g.,
2186 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2187 vimModifiers &= ~MOD_MASK_SHIFT;
2189 /* remove CTRL from keys that already have it */
2190 if (key_char < 0x20)
2191 vimModifiers &= ~MOD_MASK_CTRL;
2193 /* don't process unicode characters here */
2194 if (!IS_SPECIAL(key_char))
2196 /* Following code to simplify and consolidate vimModifiers
2197 * taken liberally from gui_w48.c */
2198 key_char = simplify_key(key_char, (int *)&vimModifiers);
2200 /* Interpret META, include SHIFT, etc. */
2201 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2202 if (key_char == CSI)
2205 if (IS_SPECIAL(key_char))
2212 result[len++] = CSI;
2213 result[len++] = KS_MODIFIER;
2214 result[len++] = vimModifiers;
2217 if (isSpecial && IS_SPECIAL(key_char))
2219 result[len++] = CSI;
2220 result[len++] = K_SECOND(key_char);
2221 result[len++] = K_THIRD(key_char);
2225 encLen = actualSize;
2226 to = mac_utf16_to_enc(text, actualSize, &encLen);
2229 /* This is basically add_to_input_buf_csi() */
2230 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2232 result[len++] = to[i];
2235 result[len++] = KS_EXTRA;
2236 result[len++] = (int)KE_CSI;
2243 add_to_input_buf(result, len);
2250 /* Fake event to wake up WNE (required to get
2251 * key repeat working */
2252 PostEvent(keyUp, 0);
2256 return eventNotHandledErr;
2260 gui_mac_doKeyEvent(EventRecord *theEvent)
2262 /* TODO: add support for COMMAND KEY */
2264 unsigned char string[20];
2270 int simplify = FALSE;
2272 /* Mask the mouse (as per user setting) */
2276 /* Get the key code and it's ASCII representation */
2277 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2278 key_char = theEvent->message & charCodeMask;
2281 /* Intercept CTRL-C */
2282 if (theEvent->modifiers & controlKey)
2284 if (key_char == Ctrl_C && ctrl_c_interrupts)
2286 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2287 && (key_char == '2' || key_char == '6'))
2289 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2290 if (key_char == '2')
2293 key_char = Ctrl_HAT;
2294 theEvent->modifiers = 0;
2298 /* Intercept CMD-. */
2299 if (theEvent->modifiers & cmdKey)
2300 if (key_char == '.')
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)
2310 menu = MenuKey(key_char);
2313 gui_mac_handle_menu(menu);
2318 /* Convert the modifiers */
2319 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2322 /* Handle special keys. */
2324 /* Why has this been removed? */
2325 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
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)
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;
2339 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2340 special_keys[i].vim_code1);
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);
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)
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))
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;
2376 string[len++] = CSI;
2377 string[len++] = KS_MODIFIER;
2378 string[len++] = modifiers;
2381 if (IS_SPECIAL(key_char))
2383 string[len++] = CSI;
2384 string[len++] = K_SECOND(key_char);
2385 string[len++] = K_THIRD(key_char);
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)
2394 char_u from[2], *to;
2400 to = string_convert(&input_conv, from, &l);
2403 for (i = 0; i < l && len < 19; i++)
2407 string[len++] = KS_EXTRA;
2408 string[len++] = KE_CSI;
2411 string[len++] = to[i];
2416 string[len++] = key_char;
2420 string[len++] = key_char;
2423 if (len == 1 && string[0] == CSI)
2425 /* Turn CSI into K_CSI. */
2426 string[ len++ ] = KS_EXTRA;
2427 string[ len++ ] = KE_CSI;
2430 add_to_input_buf(string, len);
2438 gui_mac_doMouseDownEvent(EventRecord *theEvent)
2441 WindowPtr whichWindow;
2443 thePart = FindWindow(theEvent->where, &whichWindow);
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)
2455 /* TODO: what to do? */
2459 gui_mac_handle_menu(MenuSelect(theEvent->where));
2463 gui_mac_doInContentClick(theEvent, whichWindow);
2467 gui_mac_doInDragClick(theEvent->where, whichWindow);
2471 gui_mac_doInGrowClick(theEvent->where, whichWindow);
2475 if (TrackGoAway(whichWindow, theEvent->where))
2481 gui_mac_doInZoomClick(theEvent, whichWindow);
2488 * [this event is a moving in and out of a region]
2491 gui_mac_doMouseMovedEvent(EventRecord *event)
2496 thePoint = event->where;
2497 GlobalToLocal(&thePoint);
2498 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2501 gui_mouse_moved(thePoint.h, thePoint.v);
2504 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2505 thePoint.v, FALSE, vimModifiers);
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));
2514 dragRectControl = kCreateRect;
2519 * Handle the mouse release
2522 gui_mac_doMouseUpEvent(EventRecord *theEvent)
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);
2535 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
2538 vimModifiers &= ~MOUSE_CTRL;
2539 clickIsPopup = FALSE;
2541 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
2544 static pascal OSStatus
2545 gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2553 EventMouseWheelAxis axis;
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 */
2560 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2561 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2563 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2564 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2566 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2567 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2572 vim_mod |= MOUSE_SHIFT;
2573 if (mod & controlKey)
2574 vim_mod |= MOUSE_CTRL;
2575 if (mod & optionKey)
2576 vim_mod |= MOUSE_ALT;
2578 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2580 point.h -= bounds.left;
2581 point.v -= bounds.top;
2584 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2585 point.h, point.v, FALSE, vim_mod);
2587 /* post a bogus event to wake up WaitNextEvent */
2588 PostEvent(keyUp, 0);
2594 * when we fail give any additional callback handler a chance to perform
2597 return CallNextEventHandler(nextHandler, theEvent);
2601 gui_mch_mousehide(int hide)
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
2614 gui_mac_handle_contextual_menu(event)
2618 * Clone PopUp to use menu
2619 * Create a object descriptor for the current selection
2620 * Call the procedure
2623 // Call to Handle Popup
2624 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2626 if (status != noErr)
2629 if (CntxType == kCMMenuItemSelected)
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);
2636 else if (CntxMenuID == kCMShowHelpSelected)
2638 /* Should come up with the help */
2645 * Handle menubar selection
2648 gui_mac_handle_menu(long menuChoice)
2650 short menu = HiWord(menuChoice);
2651 short item = LoWord(menuChoice);
2652 vimmenu_T *theVimMenu = root_menu;
2654 if (menu == 256) /* TODO: use constant or gui.xyz */
2657 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
2661 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2664 gui_menu_cb(theVimMenu);
2670 * Dispatch the event to proper handler
2674 gui_mac_handle_event(EventRecord *event)
2678 /* Handle contextual menu right now (if needed) */
2679 if (IsShowContextualMenuClick(event))
2682 gui_mac_handle_contextual_menu(event);
2684 gui_mac_doMouseDownEvent(event);
2689 /* Handle normal event */
2690 switch (event->what)
2692 #ifndef USE_CARBONKEYHANDLER
2695 gui_mac_doKeyEvent(event);
2699 /* We don't care about when the key is released */
2703 gui_mac_doMouseDownEvent(event);
2707 gui_mac_doMouseUpEvent(event);
2711 gui_mac_doUpdateEvent(event);
2715 /* We don't need special handling for disk insertion */
2719 gui_mac_doActivateEvent(event);
2723 switch ((event->message >> 24) & 0xFF)
2725 case (0xFA): /* mouseMovedMessage */
2726 gui_mac_doMouseMovedEvent(event);
2728 case (0x01): /* suspendResumeMessage */
2729 gui_mac_doSuspendEvent(event);
2735 case (kHighLevelEvent):
2736 /* Someone's talking to us, through AppleEvents */
2737 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2744 * ------------------------------------------------------------
2746 * ------------------------------------------------------------
2751 gui_mac_find_font(char_u *font_name)
2755 char_u pFontName[256];
2756 Str255 systemFontname;
2761 char_u *fontNamePtr;
2764 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2771 STRCPY(&pFontName[1], font_name);
2772 pFontName[0] = STRLEN(font_name);
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);
2782 FMFontStyle fontStyle;
2785 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2786 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2789 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
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).
2800 int i, changed = FALSE;
2802 for (i = pFontName[0]; i > 0; --i)
2804 if (pFontName[i] == '_')
2811 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2812 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2813 kFontNoLanguageCode, &fontRef) == noErr)
2815 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2821 /* name = C2Pascal_save(menu->dname); */
2822 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2824 GetFNum(fontNamePtr, &font_id);
2830 /* Oups, the system font was it the one the user want */
2832 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2834 if (!EqualString(pFontName, systemFontname, false, false))
2840 /* Set the values found after ':' */
2846 size = points_to_pixels(p, &p, TRUE);
2849 * TODO: Maybe accept width and styles
2858 size = 1; /* Avoid having a size of 0 with system font */
2860 font = (size << 16) + ((long) font_id & 0xFFFF);
2866 * ------------------------------------------------------------
2867 * GUI_MCH functionality
2868 * ------------------------------------------------------------
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.
2877 gui_mch_prepare(int *argc, char **argv)
2879 /* TODO: Move most of this stuff toward gui_mch_init */
2882 # ifndef USE_FIND_BUNDLE_PATH
2887 ProcessSerialNumber psn;
2895 RegisterAppearanceClient();
2898 (void) InstallAEHandlers();
2901 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
2903 AppendMenu(pomme, "\pAbout VIM");
2905 InsertMenu(pomme, 0);
2910 #ifndef USE_OFFSETED_WINDOW
2911 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
2913 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
2917 CreateNewWindow(kDocumentWindowClass,
2918 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
2919 &windRect, &gui.VimWindow);
2920 SetPortWindowPort(gui.VimWindow);
2923 gui.char_height = 11;
2924 gui.char_ascent = 6;
2927 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2929 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2930 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
2932 dragRectEnbl = FALSE;
2934 dragRectControl = kCreateEmpty;
2935 cursorRgn = NewRgn();
2938 # ifndef USE_FIND_BUNDLE_PATH
2939 HGetVol(volName, &applVRefNum, &applDirID);
2940 /* TN2015: mention a possible bad VRefNum */
2941 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
2943 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2946 (void)GetCurrentProcess(&psn);
2947 /* if (err != noErr) return err; */
2949 (void)GetProcessBundleLocation(&psn, &applFSRef);
2950 /* if (err != noErr) return err; */
2952 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
2954 /* This technic return NIL when we disallow_gui */
2956 exe_name = FullPathFromFSSpec_save(applDir);
2960 #ifndef ALWAYS_USE_GUI
2962 * Check if the GUI can be started. Called before gvimrc is sourced.
2963 * Return OK or FAIL.
2966 gui_mch_init_check(void)
2968 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2969 * using the >console
2971 if (disallow_gui) /* see main.c for reason to disallow */
2978 receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
2982 char_u **fnames = NULL;
2986 /* Get drop position, modifiers and count of items */
2989 SInt16 mouseUpModifiers;
2992 GetDragMouse(theDrag, &point, NULL);
2993 GlobalToLocal(&point);
2996 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2997 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2998 CountDragItems(theDrag, &countItem);
3002 fnames = (char_u **)alloc(count * sizeof(char_u *));
3004 return dragNotAcceptedErr;
3006 /* Get file names dropped */
3007 for (i = j = 0; i < count; ++i)
3012 FlavorType type = flavorTypeHFS;
3013 HFSFlavor hfsFlavor;
3016 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3017 err = GetFlavorDataSize(theDrag, item, type, &size);
3018 if (err != noErr || size > sizeof(hfsFlavor))
3020 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3023 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3027 gui_handle_drop(x, y, modifiers, fnames, count);
3029 /* Fake mouse event to wake from stall */
3030 PostEvent(mouseUp, 0);
3036 * Initialise the GUI. Create all the windows, set up all the call-backs
3042 /* TODO: Move most of this stuff toward gui_mch_init */
3045 EventHandlerRef mouseWheelHandlerRef;
3046 EventTypeSpec eventTypeSpec;
3047 ControlRef rootControl;
3049 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
3050 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
3055 RegisterAppearanceClient();
3058 (void) InstallAEHandlers();
3061 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
3063 AppendMenu(pomme, "\pAbout VIM");
3065 InsertMenu(pomme, 0);
3070 #ifndef USE_OFFSETED_WINDOW
3071 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
3073 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
3076 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
3078 (WindowPtr)-1L, true, 0);
3079 CreateRootControl(gui.VimWindow, &rootControl);
3080 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3081 gui.VimWindow, NULL);
3082 SetPortWindowPort(gui.VimWindow);
3085 gui.char_height = 11;
3086 gui.char_ascent = 6;
3089 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3091 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3092 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
3094 /* Install Carbon event callbacks. */
3095 (void)InstallFontPanelHandler();
3097 dragRectEnbl = FALSE;
3099 dragRectControl = kCreateEmpty;
3100 cursorRgn = NewRgn();
3102 /* Display any pending error messages */
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;
3110 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3112 set_normal_colors();
3115 * Check that none of the colors are the same as the background color.
3116 * Then store the current values as the defaults.
3119 gui.def_norm_pixel = gui.norm_pixel;
3120 gui.def_back_pixel = gui.back_pixel;
3122 /* Get the colors for the highlight groups (gui_check_colors() might have
3124 highlight_gui_started();
3127 * Setting the gui constants
3130 gui.menu_height = 0;
3132 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3133 gui.border_offset = gui.border_width = 2;
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");
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))
3145 mouseWheelHandlerRef = NULL;
3146 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3147 mouseWheelHandlerUPP = NULL;
3150 #ifdef USE_CARBONKEYHANDLER
3151 InterfaceTypeList supportedServices = { kUnicodeDocument };
3152 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3154 /* We don't support inline input yet, use input window by default */
3155 UseInputWindow(gTSMDocument, TRUE);
3157 /* Should we activate the document by default? */
3158 // ActivateTSMDocument(gTSMDocument);
3160 EventTypeSpec textEventTypes[] = {
3161 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3162 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3163 { kEventClassTextInput, kEventTextInputPosToOffset },
3164 { kEventClassTextInput, kEventTextInputOffsetToPos },
3167 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3168 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3169 NR_ELEMS(textEventTypes),
3170 textEventTypes, NULL, NULL))
3172 DisposeEventHandlerUPP(keyEventHandlerUPP);
3173 keyEventHandlerUPP = NULL;
3176 EventTypeSpec windowEventTypes[] = {
3177 { kEventClassWindow, kEventWindowActivated },
3178 { kEventClassWindow, kEventWindowDeactivated },
3181 /* Install window event handler to support TSMDocument activate and
3183 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3184 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3186 NR_ELEMS(windowEventTypes),
3187 windowEventTypes, NULL, NULL))
3189 DisposeEventHandlerUPP(winEventHandlerUPP);
3190 winEventHandlerUPP = NULL;
3196 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3200 #ifdef FEAT_GUI_TABLINE
3202 * Create the tabline
3204 initialise_tabline();
3207 /* TODO: Load bitmap if using TOOLBAR */
3212 * Called when the foreground or background color has been changed.
3215 gui_mch_new_colors(void)
3218 * This proc is called when Normal is set to a value
3219 * so what msut be done? I don't know
3224 * Open the GUI window which was created by a call to gui_mch_init().
3229 ShowWindow(gui.VimWindow);
3231 if (gui_win_x != -1 && gui_win_y != -1)
3232 gui_mch_set_winpos(gui_win_x, gui_win_y);
3235 * Make the GUI the foreground process (in case it was launched
3236 * from the Terminal or via :gui).
3239 ProcessSerialNumber psn;
3240 if (GetCurrentProcess(&psn) == noErr)
3241 SetFrontProcess(&psn);
3247 #ifdef USE_ATSUI_DRAWING
3249 gui_mac_dispose_atsui_style(void)
3251 if (p_macatsui && gFontStyle)
3252 ATSUDisposeStyle(gFontStyle);
3254 if (p_macatsui && gWideFontStyle)
3255 ATSUDisposeStyle(gWideFontStyle);
3261 gui_mch_exit(int rc)
3263 /* TODO: find out all what is missing here? */
3264 DisposeRgn(cursorRgn);
3266 #ifdef USE_CARBONKEYHANDLER
3267 if (keyEventHandlerUPP)
3268 DisposeEventHandlerUPP(keyEventHandlerUPP);
3271 if (mouseWheelHandlerUPP != NULL)
3272 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3274 #ifdef USE_ATSUI_DRAWING
3275 gui_mac_dispose_atsui_style();
3278 #ifdef USE_CARBONKEYHANDLER
3279 FixTSMDocument(gTSMDocument);
3280 DeactivateTSMDocument(gTSMDocument);
3281 DeleteTSMDocument(gTSMDocument);
3284 /* Exit to shell? */
3289 * Get the position of the top left corner of the window.
3292 gui_mch_get_winpos(int *x, int *y)
3298 /* Carbon >= 1.0.2, MacOS >= 8.5 */
3299 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
3301 if (status != noErr)
3310 * Set the position of the top left corner of the window to the given
3314 gui_mch_set_winpos(int x, int y)
3316 /* TODO: Should make sure the window is move within range
3317 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3319 MoveWindowStructure(gui.VimWindow, x, y);
3323 gui_mch_set_shellsize(
3335 if (gui.which_scrollbars[SBAR_LEFT])
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); ??*/
3345 VimPort = GetWindowPort(gui.VimWindow);
3346 GetPortBounds(VimPort, &VimBound);
3348 SetPortBounds(VimPort, &VimBound);
3351 SizeWindow(gui.VimWindow, width, height, TRUE);
3353 gui_resize_shell(width, height);
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.
3363 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
3365 GDHandle dominantDevice = GetMainDevice();
3366 Rect screenRect = (**dominantDevice).gdRect;
3368 *screen_w = screenRect.right - 10;
3369 *screen_h = screenRect.bottom - 40;
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.
3380 gui_mac_select_font(char_u *font_name)
3382 GuiFont selected_font = NOFONT;
3384 FontSelectionQDStyle curr_font;
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);
3396 gFontPanelInfo.family = curr_font.instance.fontFamily;
3397 gFontPanelInfo.style = curr_font.instance.fontStyle;
3398 gFontPanelInfo.size = curr_font.size;
3400 /* Pop up the Font Panel. */
3401 status = FPShowHideFontPanel();
3402 if (status == noErr)
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.
3408 gFontPanelInfo.isPanelVisible = true;
3409 while (gFontPanelInfo.isPanelVisible)
3412 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3415 GetFontPanelSelection(font_name);
3416 selected_font = gui_mac_find_font(font_name);
3418 return selected_font;
3421 #ifdef USE_ATSUI_DRAWING
3423 gui_mac_create_atsui_style(void)
3425 if (p_macatsui && gFontStyle == NULL)
3427 if (ATSUCreateStyle(&gFontStyle) != noErr)
3431 if (p_macatsui && gWideFontStyle == NULL)
3433 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3434 gWideFontStyle = NULL;
3438 p_macatsui_last = p_macatsui;
3443 * Initialise vim to use the font with the given name. Return FAIL if the font
3444 * could not be loaded, OK otherwise.
3447 gui_mch_init_font(char_u *font_name, int fontset)
3449 /* TODO: Add support for bold italic underline proportional etc... */
3450 Str255 suggestedFont = "\pMonaco";
3451 int suggestedSize = 10;
3455 char_u used_font_name[512];
3457 #ifdef USE_ATSUI_DRAWING
3458 gui_mac_create_atsui_style();
3461 if (font_name == NULL)
3463 /* First try to get the suggested font */
3464 GetFNum(suggestedFont, &font_id);
3468 /* Then pickup the standard application font */
3469 font_id = GetAppFont();
3470 STRCPY(used_font_name, "default");
3473 STRCPY(used_font_name, "Monaco");
3474 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3476 else if (STRCMP(font_name, "*") == 0)
3478 char_u *new_p_guifont;
3480 font = gui_mac_select_font(used_font_name);
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)
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)
3494 if (*new_p_guifont == ' ')
3495 *new_p_guifont = '_';
3501 font = gui_mac_find_font(font_name);
3502 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
3508 gui.norm_font = font;
3510 hl_set_font_name(used_font_name);
3512 TextSize(font >> 16);
3513 TextFont(font & 0xFFFF);
3515 GetFontInfo(&font_info);
3517 gui.char_ascent = font_info.ascent;
3518 gui.char_width = CharWidth('_');
3519 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3521 #ifdef USE_ATSUI_DRAWING
3522 if (p_macatsui && gFontStyle)
3523 gui_mac_set_font_attributes(font);
3530 * Adjust gui.char_height (after 'linespace' was changed).
3533 gui_mch_adjust_charheight(void)
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;
3544 * Get a font structure for highlighting.
3547 gui_mch_get_font(char_u *name, int giveErrorIfMissing)
3551 font = gui_mac_find_font(name);
3555 if (giveErrorIfMissing)
3556 EMSG2(_(e_font), name);
3560 * TODO : Accept only monospace
3566 #if defined(FEAT_EVAL) || defined(PROTO)
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.
3572 gui_mch_get_fontname(GuiFont font, char_u *name)
3576 return vim_strsave(name);
3580 #ifdef USE_ATSUI_DRAWING
3582 gui_mac_set_font_attributes(GuiFont font)
3588 fontID = font & 0xFFFF;
3589 fontSize = Long2Fix(font >> 16);
3590 fontWidth = Long2Fix(gui.char_width);
3592 ATSUAttributeTag attribTags[] =
3594 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3595 kATSUMaxATSUITagValue + 1
3598 ByteCount attribSizes[] =
3600 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3604 ATSUAttributeValuePtr attribValues[] =
3606 &fontID, &fontSize, &fontWidth, &font
3609 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3611 if (ATSUSetAttributes(gFontStyle,
3612 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3613 attribTags, attribSizes, attribValues) != noErr)
3616 fprintf(stderr, "couldn't set font style\n");
3618 ATSUDisposeStyle(gFontStyle);
3625 /* FIXME: we should use a more mbyte sensitive way to support
3626 * wide font drawing */
3627 fontWidth = Long2Fix(gui.char_width * 2);
3629 if (ATSUSetAttributes(gWideFontStyle,
3630 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3631 attribTags, attribSizes, attribValues) != noErr)
3633 ATSUDisposeStyle(gWideFontStyle);
3634 gWideFontStyle = NULL;
3643 * Set the current text font.
3646 gui_mch_set_font(GuiFont font)
3648 #ifdef USE_ATSUI_DRAWING
3650 ByteCount actualFontByteCount;
3652 if (p_macatsui && gFontStyle)
3654 /* Avoid setting same font again */
3655 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3656 sizeof(font), &currFont, &actualFontByteCount) == noErr
3657 && actualFontByteCount == (sizeof font))
3659 if (currFont == font)
3663 gui_mac_set_font_attributes(font);
3666 if (p_macatsui && !gIsFontFallbackSet)
3668 /* Setup automatic font substitution. The user's guifontwide
3669 * is tried first, then the system tries other fonts. */
3671 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3672 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3673 ATSUCreateFontFallbacks(&gFontFallbacks);
3674 ATSUSetObjFontFallbacks(gFontFallbacks, );
3678 ATSUFontID fallbackFonts;
3679 gIsFontFallbackSet = TRUE;
3681 if (FMGetFontFromFontFamilyInstance(
3682 (gui.wide_font & 0xFFFF),
3687 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3689 kATSUSequentialFallbacksPreferred);
3692 ATSUAttributeValuePtr fallbackValues[] = { };
3697 TextSize(font >> 16);
3698 TextFont(font & 0xFFFF);
3702 * If a font is not going to be used, free its structure.
3705 gui_mch_free_font(font)
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.
3721 if (c >= 'a' && c <= 'f')
3722 return c - 'a' + 10;
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.
3733 gui_mch_get_color(char_u *name)
3735 /* TODO: Add support for the new named color of MacOS 8
3738 // guicolor_T color = 0;
3740 typedef struct guicolor_tTable
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
3750 static guicolor_tTable table[] =
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*/
3807 if (name[0] == '#' && strlen((char *) name) == 7)
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)
3815 return RGB(r, g, b);
3819 if (STRICMP(name, "hilite") == 0)
3821 LMGetHiliteRGB(&MacColor);
3822 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
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;
3831 * Last attempt. Look in the file "$VIM/rgb.txt".
3834 #define LINE_LEN 100
3836 char line[LINE_LEN];
3839 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
3843 fd = fopen((char *)fname, "rt");
3854 fgets(line, LINE_LEN, fd);
3857 if (len <= 1 || line[len-1] != '\n')
3862 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3868 if (STRICMP(color, name) == 0)
3871 return (guicolor_T) RGB(r, g, b);
3881 * Set the current text foreground color.
3884 gui_mch_set_fg_color(guicolor_T color)
3888 TheColor.red = Red(color) * 0x0101;
3889 TheColor.green = Green(color) * 0x0101;
3890 TheColor.blue = Blue(color) * 0x0101;
3892 RGBForeColor(&TheColor);
3896 * Set the current text background color.
3899 gui_mch_set_bg_color(guicolor_T color)
3903 TheColor.red = Red(color) * 0x0101;
3904 TheColor.green = Green(color) * 0x0101;
3905 TheColor.blue = Blue(color) * 0x0101;
3907 RGBBackColor(&TheColor);
3910 RGBColor specialColor;
3913 * Set the current text special color.
3916 gui_mch_set_sp_color(guicolor_T color)
3918 specialColor.red = Red(color) * 0x0101;
3919 specialColor.green = Green(color) * 0x0101;
3920 specialColor.blue = Blue(color) * 0x0101;
3924 * Draw undercurl at the bottom of the character cell.
3927 draw_undercurl(int flags, int row, int col, int cells)
3931 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3932 int y = FILL_Y(row + 1) - 1;
3934 RGBForeColor(&specialColor);
3936 offset = val[FILL_X(col) % 8];
3937 MoveTo(FILL_X(col), y - offset);
3939 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
3941 offset = val[x % 8];
3942 LineTo(x, y - offset);
3948 draw_string_QD(int row, int col, char_u *s, int len, int flags)
3951 char_u *tofree = NULL;
3953 if (output_conv.vc_type != CONV_NONE)
3955 tofree = string_convert(&output_conv, s, &len);
3962 * On OS X, try using Quartz-style text antialiasing.
3964 if (gMacSystemVersion >= 0x1020)
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);
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
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.
3981 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
3982 && !(flags & DRAW_TRANSP))
3986 rc.left = FILL_X(col);
3987 rc.top = FILL_Y(row);
3989 /* Multibyte computation taken from gui_w32.c */
3992 /* Compute the length in display cells. */
3993 rc.right = FILL_X(col + mb_string2cells(s, len));
3997 rc.right = FILL_X(col + len) + (col + len == Columns);
3998 rc.bottom = FILL_Y(row + 1);
4002 if (gMacSystemVersion >= 0x1020 && p_antialias)
4004 StyleParameter face;
4007 if (flags & DRAW_BOLD)
4009 if (flags & DRAW_UNDERL)
4013 /* Quartz antialiasing works only in srcOr transfer mode. */
4016 MoveTo(TEXT_X(col), TEXT_Y(row));
4017 DrawText((char*)s, 0, len);
4021 /* Use old-style, non-antialiased QuickDraw text rendering. */
4025 /* SelectFont(hdc, gui.currFont); */
4027 if (flags & DRAW_TRANSP)
4032 MoveTo(TEXT_X(col), TEXT_Y(row));
4033 DrawText((char *)s, 0, len);
4035 if (flags & DRAW_BOLD)
4038 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4039 DrawText((char *)s, 0, len);
4042 if (flags & DRAW_UNDERL)
4044 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4045 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4049 if (flags & DRAW_UNDERC)
4050 draw_undercurl(flags, row, col, len);
4057 #ifdef USE_ATSUI_DRAWING
4060 draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
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);
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] : ' ');
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
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.
4082 if ((flags & DRAW_TRANSP) == 0)
4086 rc.left = FILL_X(col);
4087 rc.top = FILL_Y(row);
4088 /* Multibyte computation taken from gui_w32.c */
4091 /* Compute the length in display cells. */
4092 rc.right = FILL_X(col + mb_string2cells(s, len));
4095 rc.right = FILL_X(col + len) + (col + len == Columns);
4097 rc.bottom = FILL_Y(row + 1);
4105 /* SelectFont(hdc, gui.currFont); */
4106 if (flags & DRAW_TRANSP)
4111 MoveTo(TEXT_X(col), TEXT_Y(row));
4113 if (gFontStyle && flags & DRAW_BOLD)
4115 Boolean attValue = true;
4116 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4117 ByteCount attribSizes[] = { sizeof(Boolean) };
4118 ATSUAttributeValuePtr attribValues[] = { &attValue };
4120 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4123 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
4124 : kATSStyleNoAntiAliasing;
4125 if (useAntialias != useAntialias_cached)
4127 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
4128 ByteCount attribSizes[] = { sizeof(UInt32) };
4129 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4132 ATSUSetAttributes(gFontStyle, 1, attribTags,
4133 attribSizes, attribValues);
4135 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4136 attribSizes, attribValues);
4138 useAntialias_cached = useAntialias;
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;
4150 last_width_in_cell = 1;
4151 ATSUCreateTextLayout(&textLayout);
4152 ATSUSetTextPointerLocation(textLayout, tofree,
4153 kATSUFromTextBeginning,
4154 kATSUToTextEnd, utf16_len);
4156 ATSUSetRunStyle(textLayout, gFontStyle,
4157 kATSUFromTextBeginning, kATSUToTextEnd); */
4159 /* Compute the length in display cells. */
4160 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4162 width_in_cell = (*mb_ptr2cells)(s + n);
4164 /* probably we are switching from single byte character
4165 * to multibyte characters (which requires more than one
4167 if (width_in_cell != last_width_in_cell)
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);
4173 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4176 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4177 offset += yet_to_draw;
4179 last_width_in_cell = width_in_cell;
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);
4191 /* finish the rest style */
4192 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4193 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4196 ATSUSetTransientFontMatching(textLayout, TRUE);
4197 ATSUDrawText(textLayout,
4198 kATSUFromTextBeginning, kATSUToTextEnd,
4199 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4200 ATSUDisposeTextLayout(textLayout);
4205 ATSUTextLayout textLayout;
4207 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4208 kATSUFromTextBeginning, kATSUToTextEnd,
4210 (gFontStyle ? 1 : 0), &utf16_len,
4211 (gFontStyle ? &gFontStyle : NULL),
4212 &textLayout) == noErr)
4214 ATSUSetTransientFontMatching(textLayout, TRUE);
4216 ATSUDrawText(textLayout,
4217 kATSUFromTextBeginning, kATSUToTextEnd,
4218 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4220 ATSUDisposeTextLayout(textLayout);
4224 /* drawing is done, now reset bold to normal */
4225 if (gFontStyle && flags & DRAW_BOLD)
4227 Boolean attValue = false;
4229 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4230 ByteCount attribSizes[] = { sizeof(Boolean) };
4231 ATSUAttributeValuePtr attribValues[] = { &attValue };
4233 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4238 if (flags & DRAW_UNDERC)
4239 draw_undercurl(flags, row, col, len);
4246 gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
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();
4257 draw_string_ATSUI(row, col, s, len, flags);
4260 draw_string_QD(row, col, s, len, flags);
4264 * Return OK if the key with the termcap name "name" is supported.
4267 gui_mch_haskey(char_u *name)
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)
4281 SysBeep(1); /* Should this be 0? (????) */
4285 gui_mch_flash(int msec)
4287 /* Do a visual beep by reversing the foreground and background colors */
4291 * Note: InvertRect() excludes right and bottom of rectangle.
4295 rc.right = gui.num_cols * gui.char_width;
4296 rc.bottom = gui.num_rows * gui.char_height;
4299 ui_delay((long)msec, TRUE); /* wait for some msec */
4305 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4308 gui_mch_invert_rectangle(int r, int c, int nr, int nc)
4313 * Note: InvertRect() excludes right and bottom of rectangle.
4315 rc.left = FILL_X(c);
4317 rc.right = rc.left + nc * gui.char_width;
4318 rc.bottom = rc.top + nr * gui.char_height;
4323 * Iconify the GUI window.
4326 gui_mch_iconify(void)
4328 /* TODO: find out what could replace iconify
4330 * -hide application?
4334 #if defined(FEAT_EVAL) || defined(PROTO)
4336 * Bring the Vim window to the foreground.
4339 gui_mch_set_foreground(void)
4346 * Draw a cursor without focus.
4349 gui_mch_draw_hollow_cursor(guicolor_T color)
4354 * Note: FrameRect() excludes right and bottom of rectangle.
4356 rc.left = FILL_X(gui.col);
4357 rc.top = FILL_Y(gui.row);
4358 rc.right = rc.left + gui.char_width;
4360 if (mb_lefthalve(gui.row, gui.col))
4361 rc.right += gui.char_width;
4363 rc.bottom = rc.top + gui.char_height;
4365 gui_mch_set_fg_color(color);
4371 * Draw part of a cursor, only w pixels wide, and h pixels high.
4374 gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
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;
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;
4389 gui_mch_set_fg_color(color);
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
4404 gui_mch_update(void)
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;
4412 * gui_mac_handle_event(&event);
4414 EventRecord theEvent;
4416 if (EventAvail(everyEvent, &theEvent))
4417 if (theEvent.what != nullEvent)
4418 gui_mch_wait_for_chars(0);
4422 * Simple wrapper to neglect more easily the time
4423 * spent inside WaitNextEvent while profiling.
4428 WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
4430 if (((long) sleep) < -1)
4432 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
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.
4445 gui_mch_wait_for_chars(int wtime)
4447 EventMask mask = (everyEvent);
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.
4457 if (dragged_sb != NULL)
4459 /* TODO: Check if FAIL is the proper return code */
4461 entryTick = TickCount();
4463 allow_scrollbar = TRUE;
4467 /* if (dragRectControl == kCreateEmpty)
4470 dragRectControl = kNothing;
4472 else*/ if (dragRectControl == kCreateRect)
4474 dragRgn = cursorRgn;
4475 RectRgn(dragRgn, &dragRect);
4476 dragRectControl = kNothing;
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.
4484 /* TODO: reduce wtime accordinly??? */
4486 sleeppyTick = 60 * wtime / 1000;
4488 sleeppyTick = 32767;
4490 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
4492 gui_mac_handle_event(&event);
4493 if (input_available())
4495 allow_scrollbar = FALSE;
4499 currentTick = TickCount();
4501 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4503 allow_scrollbar = FALSE;
4511 /* Flush any output to the screen */
4515 /* TODO: Is anything needed here? */
4519 * Clear a rectangular region of the screen from text pos (row1, col1) to
4520 * (row2, col2) inclusive.
4523 gui_mch_clear_block(int row1, int col1, int row2, int col2)
4528 * Clear one extra pixel at the far right, for when bold characters have
4529 * spilled over to the next column.
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);
4536 gui_mch_set_bg_color(gui.back_pixel);
4541 * Clear the whole text window.
4544 gui_mch_clear_all(void)
4550 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4551 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4553 gui_mch_set_bg_color(gui.back_pixel);
4555 /* gui_mch_set_fg_color(gui.norm_pixel);
4561 * Delete the given number of lines from the given row, scrolling up any
4562 * text further down within the scroll region.
4565 gui_mch_delete_lines(int row, int num_lines)
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);
4575 gui_mch_set_bg_color(gui.back_pixel);
4576 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
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);
4584 * Insert the given number of lines before the given row, scrolling down any
4585 * following text within the scroll region.
4588 gui_mch_insert_lines(int row, int num_lines)
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);
4597 gui_mch_set_bg_color(gui.back_pixel);
4599 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
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)
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;
4612 gui_clear_block(row, gui.scroll_region_left,
4613 row + num_lines - 1, gui.scroll_region_right);
4617 * TODO: add a vim format to the clipboard which remember
4618 * LINEWISE, CHARWISE, BLOCKWISE
4622 clip_mch_request_selection(VimClipboard *cbd)
4628 ScrapFlavorFlags scrapFlags;
4629 ScrapRef scrap = nil;
4636 error = GetCurrentScrap(&scrap);
4640 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4643 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4644 if (error == noErr && scrapSize > 1)
4650 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
4654 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
4659 ReserveMem(scrapSize);
4661 /* In CARBON we don't need a Handle, a pointer is good */
4662 textOfClip = NewHandle(scrapSize);
4664 /* tempclip = lalloc(scrapSize+1, TRUE); */
4666 error = GetScrapFlavorData(scrap,
4667 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4668 &scrapSize, *textOfClip);
4669 scrapSize -= flavor;
4672 type = **textOfClip;
4674 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4676 tempclip = lalloc(scrapSize + 1, TRUE);
4677 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4678 tempclip[scrapSize] = 0;
4680 #ifdef MACOS_CONVERT
4682 /* Convert from utf-16 (clipboard) */
4684 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
4695 searchCR = (char *)tempclip;
4696 while (searchCR != NULL)
4698 searchCR = strchr(searchCR, '\r');
4699 if (searchCR != NULL)
4703 clip_yank_selection(type, tempclip, scrapSize, cbd);
4706 HUnlock(textOfClip);
4708 DisposeHandle(textOfClip);
4712 clip_mch_lose_selection(VimClipboard *cbd)
4715 * TODO: Really nothing to do?
4720 clip_mch_own_selection(VimClipboard *cbd)
4726 * Send the current selection to the clipboard.
4729 clip_mch_set_selection(VimClipboard *cbd)
4741 clip_get_selection(cbd);
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.
4749 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
4751 #ifdef MACOS_CONVERT
4752 size_t utf16_len = 0;
4753 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4756 scrapSize = utf16_len;
4764 ClearCurrentScrap();
4766 textOfClip = NewHandle(scrapSize + 1);
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);
4784 gui_mch_set_text_area_pos(int x, int y, int w, int h)
4788 /* HideWindow(gui.VimWindow); */
4789 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
4791 if (gui.which_scrollbars[SBAR_LEFT])
4793 VimBound.left = -gui.scrollbar_width + 1;
4800 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
4802 ShowWindow(gui.VimWindow);
4810 gui_mch_enable_menu(int flag)
4813 * Menu is always active.
4818 gui_mch_set_menu_pos(int x, int y, int w, int h)
4821 * The menu is always at the top of the screen.
4826 * Add a sub menu to the menu bar.
4829 gui_mch_add_menu(vimmenu_T *menu, int idx)
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
4837 static long next_avail_id = 128;
4838 long menu_after_me = 0; /* Default to the end */
4839 #if defined(FEAT_MBYTE)
4845 vimmenu_T *parent = menu->parent;
4846 vimmenu_T *brother = menu->next;
4848 /* Cannot add a menu if ... */
4849 if ((parent != NULL && parent->submenu_id == 0))
4852 /* menu ID greater than 1024 are reserved for ??? */
4853 if (next_avail_id == 1024)
4856 /* My brother could be the PopUp, find my real brother */
4857 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4858 brother = brother->next;
4860 /* Find where to insert the menu (for MenuBar) */
4861 if ((parent == NULL) && (brother != NULL))
4862 menu_after_me = brother->submenu_id;
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;
4868 /* Convert the name */
4869 #ifdef MACOS_CONVERT
4870 name = menu_title_removing_mnemonic(menu);
4872 name = C2Pascal_save(menu->dname);
4877 /* Create the menu unless it's the help menu */
4879 /* Carbon suggest use of
4880 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4881 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
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);
4888 menu->submenu_handle = NewMenu(menu->submenu_id, name);
4895 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
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
4901 /* Insert the menu */
4902 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
4904 /* Vim should normally update it. TODO: verify */
4910 /* Adding as a submenu */
4912 index = gui_mac_get_menu_item_index(menu);
4914 /* Call InsertMenuItem followed by SetMenuItemText
4915 * to avoid special character recognition by InsertMenuItem
4917 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4918 #if defined(FEAT_MBYTE)
4919 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4921 SetMenuItemText(parent->submenu_handle, idx+1, name);
4923 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4924 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4925 InsertMenu(menu->submenu_handle, hierMenu);
4928 #if defined(FEAT_MBYTE)
4935 /* Done by Vim later on */
4941 * Add a menu item to a menu
4944 gui_mch_add_menu_item(vimmenu_T *menu, int idx)
4946 #if defined(FEAT_MBYTE)
4951 vimmenu_T *parent = menu->parent;
4954 /* Cannot add item, if the menu have not been created */
4955 if (parent->submenu_id == 0)
4958 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4959 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4961 /* Convert the name */
4962 #ifdef MACOS_CONVERT
4963 name = menu_title_removing_mnemonic(menu);
4965 name = C2Pascal_save(menu->dname);
4968 /* Where are just a menu item, so no handle, no id */
4969 menu->submenu_id = 0;
4970 menu->submenu_handle = NULL;
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.
4983 p_actext = menu->actext;
4984 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
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
4996 if (key > 0 && key < 32)
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.
5002 modifiers |= MOD_MASK_CTRL;
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.
5009 else if (key >= 'A' && key <= 'Z')
5010 modifiers |= MOD_MASK_SHIFT;
5011 else if (key >= 'a' && key <= 'z')
5013 /* Note: keycodes below 0x22 are reserved by Apple. */
5014 if (key >= 0x22 && vim_isprintc_strict(key))
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? */
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] = '/';
5033 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5034 /* Set the modifier keys. */
5035 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5040 /* Call InsertMenuItem followed by SetMenuItemText
5041 * to avoid special character recognition by InsertMenuItem
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);
5049 SetMenuItemText(parent->submenu_handle, idx+1, name);
5057 #if defined(FEAT_MBYTE)
5060 /* TODO: Can name be freed? */
5066 gui_mch_toggle_tearoffs(int enable)
5068 /* no tearoff menus */
5072 * Destroy the machine specific menu widget.
5075 gui_mch_destroy_menu(vimmenu_T *menu)
5077 short index = gui_mac_get_menu_item_index(menu);
5084 /* For now just don't delete help menu items. (Huh? Dany) */
5085 DeleteMenuItem(menu->parent->submenu_handle, index);
5087 /* Delete the Menu if it was a hierarchical Menu */
5088 if (menu->submenu_id != 0)
5090 DeleteMenu(menu->submenu_id);
5091 DisposeMenu(menu->submenu_handle);
5095 #ifdef DEBUG_MAC_MENU
5105 DeleteMenu(menu->submenu_id);
5106 DisposeMenu(menu->submenu_handle);
5109 /* Shouldn't this be already done by Vim. TODO: Check */
5114 * Make a menu either grey or not grey.
5117 gui_mch_menu_grey(vimmenu_T *menu, int grey)
5119 /* TODO: Check if menu really exists */
5120 short index = gui_mac_get_menu_item_index(menu);
5122 index = menu->index;
5127 DisableMenuItem(menu->submenu_handle, index);
5129 if (menu->parent->submenu_handle)
5130 DisableMenuItem(menu->parent->submenu_handle, index);
5135 EnableMenuItem(menu->submenu_handle, index);
5137 if (menu->parent->submenu_handle)
5138 EnableMenuItem(menu->parent->submenu_handle, index);
5143 * Make menu item hidden or not hidden
5146 gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
5148 /* There's no hidden mode on MacOS */
5149 gui_mch_menu_grey(menu, hidden);
5154 * This is called after setting all the menus to grey/hidden or not.
5157 gui_mch_draw_menubar(void)
5168 gui_mch_enable_scrollbar(
5173 ShowControl(sb->id);
5175 HideControl(sb->id);
5178 printf("enb_sb (%x) %x\n",sb->id, flag);
5183 gui_mch_set_scrollbar_thumb(
5189 SetControl32BitMaximum (sb->id, max);
5190 SetControl32BitMinimum (sb->id, 0);
5191 SetControl32BitValue (sb->id, val);
5192 SetControlViewSize (sb->id, size);
5194 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
5199 gui_mch_set_scrollbar_pos(
5206 gui_mch_set_bg_color(gui.back_pixel);
5207 /* if (gui.which_scrollbars[SBAR_LEFT])
5209 MoveControl(sb->id, x-16, y);
5210 SizeControl(sb->id, w + 1, h);
5214 MoveControl(sb->id, x, y);
5215 SizeControl(sb->id, w + 1, h);
5217 if (sb == &gui.bottom_sbar)
5222 if (gui.which_scrollbars[SBAR_LEFT])
5225 MoveControl(sb->id, x, y);
5226 SizeControl(sb->id, w, h);
5228 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
5233 gui_mch_create_scrollbar(
5235 int orient) /* SBAR_VERT or SBAR_HORIZ */
5240 bounds.bottom = -10;
5244 sb->id = NewControl(gui.VimWindow,
5251 kControlScrollBarLiveProc,
5254 printf("create_sb (%x) %x\n",sb->id, orient);
5259 gui_mch_destroy_scrollbar(scrollbar_T *sb)
5261 gui_mch_set_bg_color(gui.back_pixel);
5262 DisposeControl(sb->id);
5264 printf("dest_sb (%x) \n",sb->id);
5270 * Cursor blink functions.
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
5278 gui_mch_set_blinking(long wait, long on, long off)
5280 /* TODO: TODO: TODO: TODO: */
5281 /* blink_waittime = wait;
5283 blink_offtime = off;*/
5287 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5290 gui_mch_stop_blink(void)
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;*/
5301 * Start the cursor blinking. If it was already blinking, this restarts the
5302 * waiting time and shows the cursor.
5305 gui_mch_start_blink(void)
5307 gui_update_cursor(TRUE, FALSE);
5308 /* TODO: TODO: TODO: TODO: */
5309 /* gui_w32_rm_blink_timer(); */
5311 /* Only switch blinking on if none of the times is zero */
5312 /* if (blink_waittime && blink_ontime && blink_offtime)
5314 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5315 (TIMERPROC)_OnBlinkTimer);
5316 blink_state = BLINK_ON;
5317 gui_update_cursor(TRUE, FALSE);
5322 * Return the RGB value of a pixel as long.
5325 gui_mch_get_rgb(guicolor_T pixel)
5327 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
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.
5349 * *NOTE* - the filter string must be terminated with TWO nulls.
5360 /* TODO: Add Ammon's safety checl (Dany) */
5361 NavReplyRecord reply;
5362 char_u *fname = NULL;
5363 char_u **fnames = NULL;
5365 NavDialogOptions navOptions;
5368 /* Get Navigation Service Defaults value */
5369 NavGetDefaultDialogOptions(&navOptions);
5372 /* TODO: If we get a :browse args, set the Multiple bit. */
5373 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5374 | kNavDontAutoTranslate
5375 | kNavDontAddTranslateItems
5376 /* | kNavAllowMultipleFiles */
5377 | kNavAllowStationery;
5379 (void) C2PascalString(title, &navOptions.message);
5380 (void) C2PascalString(dflt, &navOptions.savedFileName);
5381 /* Could set clientName?
5382 * windowTitle? (there's no title bar?)
5387 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5388 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
5389 if (!reply.validRecord)
5394 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5395 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5396 if (!reply.validRecord)
5400 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5402 NavDisposeReply(&reply);
5410 /* TODO: Shorten the file name if possible */
5413 #endif /* FEAT_BROWSE */
5415 #ifdef FEAT_GUI_DIALOG
5417 * Stuff for dialogues
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.
5428 * This routine returns 1 if the first button is pressed,
5429 * 2 for the second, etc.
5431 * 0 indicates Esc was pressed.
5432 * -1 for unexpected error
5434 * If stubbing out this fn, return 1.
5440 short width; /* Size of the text in pixel */
5442 } vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5444 #define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5448 DialogRef theDialog,
5454 #if 0 /* USE_CARBONIZED */
5456 MoveDialogItem(theDialog, itemNumber, X, Y);
5458 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
5463 Rect *itemBox = &localBox;
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);
5481 DialogRef theDialog,
5490 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
5492 /* When width or height is zero do not change it */
5494 width = itemBox.right - itemBox.left;
5496 height = itemBox.bottom - itemBox.top;
5498 #if 0 /* USE_CARBONIZED */
5499 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
5501 /* Resize the bounding box */
5502 itemBox.right = itemBox.left + width;
5503 itemBox.bottom = itemBox.top + height;
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);
5510 /* Configure back the item */
5511 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
5516 macSetDialogItemText(
5517 DialogRef theDialog,
5525 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
5527 if (itemType & kControlDialogItem)
5528 SetControlTitle((ControlRef) itemHandle, itemName);
5530 SetDialogItemText(itemHandle, itemName);
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.
5538 static pascal Boolean
5539 DialogHotkeyFilterProc (
5540 DialogRef theDialog,
5542 DialogItemIndex *itemHit)
5546 if (event->what == keyDown || event->what == autoKey)
5548 keyHit = (event->message & charCodeMask);
5550 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5552 #ifdef DEBUG_MAC_DIALOG_HOTKEYS
5553 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5555 *itemHit = gDialogHotKeys[keyHit];
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
5563 event->what = kEventControlSimulateHit;
5565 return true; /* we took care of it */
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);
5572 return false; /* Let ModalDialog deal with it */
5576 /* TODO: There have been some crashes with dialogs, check your inbox
5594 DialogPtr theDialog;
5596 char_u PascalTitle[256]; /* place holder for the title */
5601 short hotKeys[256]; /* map of hotkey -> control ID */
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 */
5620 short messageLines = 3;
5621 FontInfo textFontInfo;
5624 vgmDlgItm messageItm;
5626 vgmDlgItm buttonItm;
5628 WindowRef theWindow;
5630 ModalFilterUPP dialogUPP;
5632 /* Check 'v' flag in 'guioptions': vertical button placement. */
5633 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5635 /* Create a new Dialog Box from template. */
5636 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
5638 /* Get the WindowRef */
5639 theWindow = GetDialogWindow(theDialog);
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.
5647 HideWindow(theWindow);
5649 /* Change the graphical port to the dialog,
5650 * so we can measure the text with the proper font */
5652 SetPortDialogPort(theDialog);
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);
5659 /* Set the dialog title */
5662 (void) C2PascalString(title, &PascalTitle);
5663 SetWTitle(theWindow, PascalTitle);
5666 /* Creates the buttons and add them to the Dialog Box. */
5667 buttonDITL = GetResource('DITL', 130);
5668 buttonChar = buttons;
5671 /* initialize the hotkey mapping */
5672 vim_memset(hotKeys, 0, sizeof(hotKeys));
5674 for (;*buttonChar != 0;)
5676 /* Get the name of the button */
5679 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5681 if (*buttonChar != DLG_HOTKEY_CHAR)
5682 name[++len] = *buttonChar;
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);
5695 if (*buttonChar != 0)
5699 /* Add the button */
5700 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
5702 /* Change the button's name */
5703 macSetDialogItemText(theDialog, button, name);
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);
5713 totalButtonWidth += width;
5715 if (width > widestButton)
5716 widestButton = width;
5718 ReleaseResource(buttonDITL);
5719 lastButton = button;
5721 /* Add the icon to the Dialog Box. */
5722 iconItm.idx = lastButton + 1;
5723 iconDITL = GetResource('DITL', 131);
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;
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);
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);
5750 /* Add the input box if needed */
5751 if (textfield != NULL)
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);
5764 /* Hotkeys don't make sense if there's a text field */
5765 gDialogHotKeys = NULL;
5768 /* Install hotkey table */
5769 gDialogHotKeys = (short *)&hotKeys;
5771 /* Set the <ENTER> and <ESC> button. */
5772 SetDialogDefaultItem(theDialog, dfltbutton);
5773 SetDialogCancelItem(theDialog, 0);
5775 /* Reposition element */
5777 /* Check if we need to force vertical */
5778 if (totalButtonWidth > maximumWidth)
5782 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
5783 iconItm.box.right = box.right;
5784 iconItm.box.bottom = box.bottom;
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);
5792 if (textfield != NULL)
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);
5806 if (textfield != NULL)
5808 buttonItm.box.left = inputItm.box.left;
5809 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5813 buttonItm.box.left = messageItm.box.left;
5814 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5817 for (button=1; button <= lastButton; button++)
5820 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
5821 /* With vertical, it's better to have all buttons the same length */
5824 macSizeDialogItem(theDialog, button, widestButton, 0);
5825 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
5827 /* Calculate position of next button */
5829 buttonItm.box.top = box.bottom + dfltElementSpacing;
5831 buttonItm.box.left = box.right + dfltElementSpacing;
5834 /* Resize the dialog box */
5835 dialogHeight = box.bottom + dfltElementSpacing;
5836 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5839 AutoSizeDialog(theDialog);
5840 /* Need a horizontal resize anyway so not that useful */
5843 ShowWindow(theWindow);
5844 /* BringToFront(theWindow); */
5845 SelectWindow(theWindow);
5847 /* DrawDialog(theDialog); */
5850 SetPortDialogPort(theDialog);
5853 #ifdef USE_CARBONKEYHANDLER
5854 /* Avoid that we use key events for the main window. */
5858 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5859 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5861 /* Hang until one of the button is hit */
5864 ModalDialog(dialogUPP, &itemHit);
5865 } while ((itemHit < 1) || (itemHit > lastButton));
5867 #ifdef USE_CARBONKEYHANDLER
5868 dialog_busy = FALSE;
5871 /* Copy back the text entered by the user into the param */
5872 if (textfield != NULL)
5874 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5875 GetDialogItemText(itemHandle, (char_u *) &name);
5877 /* Truncate the name to IOSIZE if needed */
5878 if (name[0] > IOSIZE)
5879 name[0] = IOSIZE - 1;
5881 vim_strncpy(textfield, &name[1], name[0]);
5884 /* Restore the original graphical port */
5887 /* Free the modal filterProc */
5888 DisposeRoutineDescriptor(dialogUPP);
5890 /* Get ride of th edialog (free memory) */
5891 DisposeDialog(theDialog);
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
5903 #endif /* FEAT_DIALOG_GUI */
5906 * Display the saved error message(s).
5908 #ifdef USE_MCH_ERRMSG
5910 display_errors(void)
5915 if (error_ga.ga_data == NULL)
5918 /* avoid putting up a message box with blanks only */
5919 for (p = (char *)error_ga.ga_data; *p; ++p)
5922 if (STRLEN(p) > 255)
5925 pError[0] = STRLEN(p);
5927 STRNCPY(&pError[1], p, pError[0]);
5928 ParamText(pError, nil, nil, nil);
5931 /* TODO: handled message longer than 256 chars
5932 * use auto-sizeable alert
5933 * or dialog with scrollbars (TextEdit zone)
5936 ga_clear(&error_ga);
5941 * Get current mouse coordinates in text window.
5944 gui_mch_getmouse(int *x, int *y)
5955 gui_mch_setmouse(int x, int y)
5961 CursorDevicePtr myMouse;
5964 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5965 != NGetTrapAddress(_Unimplemented, ToolTrap))
5970 * Get first devoice with one button.
5971 * This will probably be the standad mouse
5972 * startat head of cursor dev list
5980 /* Get the next cursor device */
5981 CursorDeviceNextDevice(&myMouse);
5983 while ((myMouse != nil) && (myMouse->cntButtons != 1));
5985 CursorDeviceMoveTo(myMouse, x, y);
5993 *(Point *)RawMouse = where;
5994 *(Point *)MTemp = where;
5995 *(Ptr) CrsrNew = 0xFFFF;
6001 gui_mch_show_popupmenu(vimmenu_T *menu)
6004 * Clone PopUp to use menu
6005 * Create a object descriptor for the current selection
6006 * Call the procedure
6009 MenuHandle CntxMenu;
6014 UInt16 CntxMenuItem;
6015 Str255 HelpName = "";
6018 /* Save Current Port: On MacOS X we seem to lose the port */
6019 GetPort(&savePort); /*OSX*/
6022 LocalToGlobal(&where); /*OSX*/
6023 CntxMenu = menu->submenu_handle;
6025 /* TODO: Get the text selection from Vim */
6027 /* Call to Handle Popup */
6028 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
6029 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
6031 if (status == noErr)
6033 if (CntxType == kCMMenuItemSelected)
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);
6041 else if (CntxMenuID == kCMShowHelpSelected)
6043 /* Should come up with the help */
6047 /* Restore original Port */
6048 SetPort(savePort); /*OSX*/
6051 #if defined(FEAT_CW_EDITOR) || defined(PROTO)
6052 /* TODO: Is it need for MACOS_X? (Dany) */
6054 mch_post_buffer_write(buf_T *buf)
6056 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6057 Send_KAHL_MOD_AE(buf);
6063 * Set the window title and icon.
6064 * (The icon is not taken care of).
6067 gui_mch_settitle(char_u *title, char_u *icon)
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.
6072 #ifdef MACOS_CONVERT
6073 CFStringRef windowTitle;
6074 size_t windowTitleLen;
6076 char_u *pascalTitle;
6079 if (title == NULL) /* nothing to do */
6082 #ifdef MACOS_CONVERT
6083 windowTitleLen = STRLEN(title);
6084 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
6088 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6089 CFRelease(windowTitle);
6092 pascalTitle = C2Pascal_save(title);
6093 if (pascalTitle != NULL)
6095 SetWTitle(gui.VimWindow, pascalTitle);
6096 vim_free(pascalTitle);
6103 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6107 C2PascalString(char_u *CString, Str255 *PascalString)
6109 char_u *PascalPtr = (char_u *) PascalString;
6114 if (CString == NULL)
6117 len = STRLEN(CString);
6121 for (i = 0; i < len; i++)
6122 PascalPtr[i+1] = CString[i];
6130 GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
6137 (void) C2PascalString(file, &filePascal);
6139 myCPB.dirInfo.ioNamePtr = filePascal;
6140 myCPB.dirInfo.ioVRefNum = 0;
6141 myCPB.dirInfo.ioFDirIndex = 0;
6142 myCPB.dirInfo.ioDrDirID = 0;
6144 err= PBGetCatInfo(&myCPB, false);
6146 /* vRefNum, dirID, name */
6147 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
6149 /* TODO: Use an error code mechanism */
6154 * Convert a FSSpec to a fuill path
6157 char_u *FullPathFromFSSpec_save(FSSpec file)
6160 * TODO: Add protection for 256 char max.
6165 char_u *filenamePtr = fname;
6168 #ifdef USE_UNIXFILENAME
6169 SInt16 dfltVol_vRefNum;
6170 SInt32 dfltVol_dirID;
6173 UInt32 pathSize = 256;
6174 char_u pathname[256];
6175 char_u *path = pathname;
6177 Str255 directoryName;
6178 char_u temporary[255];
6179 char_u *temporaryPtr = temporary;
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);
6191 /* Start filling fname with file.name */
6192 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
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;
6201 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6202 which is relative to ioVrefNum, ioDirID */
6203 error = PBGetCatInfo(&theCPB, false);
6205 /* If we are called for a new file we expect fnfErr */
6206 if ((error) && (error != fnfErr))
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 */
6216 #ifdef USE_UNIXFILENAME
6218 * The function used here are available in Carbon, but
6219 * do nothing une MacOS 8 and 9
6221 if (error == fnfErr)
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. */
6231 Str255 emptyFilename = "\p";
6232 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6233 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6237 error = FSpMakeFSRef(&dirSpec, &dirRef);
6241 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6246 STRCAT(path, filenamePtr);
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);
6256 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
6261 /* Add a slash at the end if needed */
6265 return (vim_strsave(path));
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;
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;
6276 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
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;
6285 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6286 /* *ioNamePtr[0 TO 31] will be updated */
6287 error = PBGetCatInfo(&theCPB,false);
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);
6298 #if 1 /* def USE_UNIXFILENAME */
6299 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6300 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6302 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
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;
6312 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6313 /* *ioNamePtr[0 TO 31] will be updated */
6314 error = PBGetCatInfo(&theCPB,false);
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)
6326 /* Add the volume name */
6327 STRCPY(temporaryPtr, filenamePtr);
6328 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
6329 STRCAT(filenamePtr, ":");
6330 STRCAT(filenamePtr, temporaryPtr);
6332 #ifdef USE_UNIXFILENAME
6333 STRCPY(temporaryPtr, filenamePtr);
6334 filenamePtr[0] = 0; /* NULL terminate the string */
6335 STRCAT(filenamePtr, "Volumes:");
6336 STRCAT(filenamePtr, temporaryPtr);
6340 /* Append final path separator if it's a folder */
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);
6353 for (p = fname; *p; p++)
6359 return (vim_strsave(fname));
6363 #if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
6365 * Input Method Control functions.
6369 * Notify cursor position to IM.
6372 im_set_position(int row, int col)
6375 /* TODO: Implement me! */
6381 static ScriptLanguageRecord gTSLWindow;
6382 static ScriptLanguageRecord gTSLInsert;
6383 static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6385 static Component gTSCWindow;
6386 static Component gTSCInsert;
6387 static Component gTSCDefault;
6389 static int im_initialized = 0;
6392 im_on_window_switch(int active)
6394 ScriptLanguageRecord *slptr = NULL;
6400 if (im_initialized == 0)
6404 /* save default TSM component (should be U.S.) to default */
6405 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6406 kKeyboardInputMethodClass);
6411 im_is_active = TRUE;
6412 ActivateTSMDocument(gTSMDocument);
6413 slptr = &gTSLWindow;
6417 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6418 kKeyboardInputMethodClass);
6420 err = SetTextServiceLanguage(slptr);
6423 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6428 err = GetTextServiceLanguage(&gTSLWindow);
6430 slptr = &gTSLWindow;
6433 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6434 kKeyboardInputMethodClass);
6436 im_is_active = FALSE;
6437 DeactivateTSMDocument(gTSMDocument);
6442 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6445 im_set_active(int active)
6447 ScriptLanguageRecord *slptr = NULL;
6453 if (im_initialized == 0)
6457 /* save default TSM component (should be U.S.) to default */
6458 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6459 kKeyboardInputMethodClass);
6464 im_is_active = TRUE;
6465 ActivateTSMDocument(gTSMDocument);
6466 slptr = &gTSLInsert;
6470 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6471 kKeyboardInputMethodClass);
6473 err = SetTextServiceLanguage(slptr);
6476 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6481 err = GetTextServiceLanguage(&gTSLInsert);
6483 slptr = &gTSLInsert;
6486 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6487 kKeyboardInputMethodClass);
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);
6495 im_is_active = FALSE;
6496 DeactivateTSMDocument(gTSMDocument);
6501 * Get IM status. When IM is on, return not 0. Else return 0.
6509 return im_is_active;
6512 #endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
6517 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6518 // drawer implementation
6519 static MenuRef contextMenu = NULL;
6522 kTabContextMenuId = 42,
6525 // the caller has to CFRelease() the returned string
6527 getTabLabel(tabpage_T *page)
6529 get_tabline_label(page, FALSE);
6530 #ifdef MACOS_CONVERT
6531 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6533 // TODO: check internal encoding?
6534 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6535 kCFStringEncodingMacRoman);
6540 #define DRAWER_SIZE 150
6541 #define DRAWER_INSET 16
6543 static ControlRef dataBrowser = NULL;
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;
6555 kTabsColumn = 'Tabs'
6564 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6569 // data browser item display callback
6571 dbItemDataCallback(ControlRef browser,
6572 DataBrowserItemID itemID,
6573 DataBrowserPropertyID property /* column id */,
6574 DataBrowserItemDataRef itemData,
6575 Boolean changeValue)
6577 OSStatus status = noErr;
6579 // assert(property == kTabsColumn); // why is this violated??
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
6589 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6590 str = tabLabels[itemID - 1];
6591 status = SetDataBrowserItemDataText(itemData, str);
6594 status = errDataBrowserPropertyNotSupported;
6599 // data browser action callback
6601 dbItemNotificationCallback(ControlRef browser,
6602 DataBrowserItemID item,
6603 DataBrowserItemNotification message)
6607 case kDataBrowserItemSelected:
6608 send_tabline_event(item);
6613 // callbacks needed for contextual menu:
6615 dbGetContextualMenuCallback(ControlRef browser,
6618 CFStringRef *helpItemString,
6621 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6622 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6623 *helpItemString = NULL;
6625 *menu = contextMenu;
6629 dbSelectContextualMenuCallback(ControlRef browser,
6631 UInt32 selectionType,
6633 MenuItemIndex menuItem)
6635 if (selectionType == kCMMenuItemSelected)
6637 MenuCommand command;
6638 GetMenuItemCommandID(menu, menuItem, &command);
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);
6649 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6650 kDataBrowserItemIsSelected, items);
6651 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6655 DataBrowserItemID *itemsPtr;
6658 itemsPtr = (DataBrowserItemID *)*items;
6661 send_tabline_menu_event(idx, command);
6663 DisposeHandle(items);
6668 // focus callback of the data browser to always leave focus in vim
6670 dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6672 assert(GetEventClass(event) == kEventClassControl
6673 && GetEventKind(event) == kEventControlSetFocusPart);
6679 // drawer callback to resize data browser to drawer size
6681 drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6683 switch (GetEventKind(event))
6685 case kEventWindowBoundsChanged: // move or resize
6688 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6689 NULL, sizeof(attribs), NULL, &attribs);
6690 if (attribs & kWindowBoundsChangeSizeChanged) // resize
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);
6703 return eventNotHandledErr;
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.)
6711 #import <mach-o/dyld.h>
6713 enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6716 myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6717 OptionBits inAttributesToSet,
6718 OptionBits inAttributesToClear)
6722 NSSymbol symbol = NULL;
6723 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6724 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6726 Gestalt(gestaltSystemVersion, &osVersion);
6727 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6730 // C name mangling...
6731 symbolName = "_DataBrowserChangeAttributes";
6732 if (!NSIsSymbolNameDefined(symbolName)
6733 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6736 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6737 if (dataBrowserChangeAttributes == NULL)
6738 return noErr; // well...
6739 return dataBrowserChangeAttributes(inDataBrowser,
6740 inAttributesToSet, inAttributesToClear);
6744 initialise_tabline(void)
6746 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6747 DataBrowserCallbacks dbCallbacks;
6748 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6749 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6750 DataBrowserListViewColumnDesc colDesc;
6752 // drawers have to have compositing enabled
6753 CreateNewWindow(kDrawerWindowClass,
6754 kWindowStandardHandlerAttribute
6755 | kWindowCompositingAttribute
6756 | kWindowResizableAttribute
6757 | kWindowLiveResizeAttribute,
6758 &drawerRect, &drawer);
6760 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6761 SetDrawerParent(drawer, gui.VimWindow);
6762 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6765 // create list view embedded in drawer
6766 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
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);
6780 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6782 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6783 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6784 SetDataBrowserSelectionFlags(dataBrowser,
6785 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6786 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6787 kDataBrowserTableViewFillHilite);
6789 SetControlData(dataBrowser, kControlEntireControl,
6790 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
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);
6798 // install callback that keeps focus in vim and away from the data browser
6799 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6802 // install callback that keeps data browser at the size of the drawer
6803 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6806 // add "tabs" column to data browser
6807 colDesc.propertyDesc.propertyID = kTabsColumn;
6808 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6810 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6811 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
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;
6822 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
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);
6836 * Show or hide the tabline.
6839 gui_mch_show_tabline(int showit)
6842 CloseDrawer(drawer, true);
6844 OpenDrawer(drawer, kWindowEdgeRight, true);
6848 * Return TRUE when tabline is displayed.
6851 gui_mch_showing_tabline(void)
6853 WindowDrawerState state = GetDrawerState(drawer);
6855 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6859 * Update the labels of the tabline.
6862 gui_mch_update_tabline(void)
6865 int numTabs = getTabCount();
6869 // adjust data browser
6870 if (tabLabels != NULL)
6874 for (i = 0; i < tabLabelsSize; ++i)
6875 CFRelease(tabLabels[i]);
6878 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6879 tabLabelsSize = numTabs;
6881 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6885 tabLabels[nr-1] = getTabLabel(tp);
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);
6895 DataBrowserItemID item = curtabidx;
6896 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6900 * Set the current tab to "nr". First tab is 1.
6903 gui_mch_set_curtab(nr)
6906 DataBrowserItemID item = nr;
6907 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6909 // TODO: call something like this?: (or restore scroll position, or...)
6910 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6911 kDataBrowserRevealOnly);
6914 #endif // FEAT_GUI_TABLINE