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
62 static EventHandlerUPP keyEventHandlerUPP
= NULL
;
66 /* Include some file. TODO: move into os_mac.h */
68 #include <Resources.h>
69 #include <Processes.h>
71 # include <AppleEvents.h>
72 # include <AERegistry.h>
75 #if UNIVERSAL_INTERFACES_VERSION >= 0x0330
76 # include <ControlDefinitions.h>
77 # include <Navigation.h> /* Navigation only part of ?? */
80 /* Help Manager (balloon.h, HM prefixed functions) are not supported
81 * under Carbon (Jussi) */
83 /* New Help Interface for Mac, not implemented yet.*/
88 * These seem to be rectangle options. Why are they not found in
92 #define kCreateEmpty 2 /*1*/
97 * Dany: Don't like those...
99 #define topLeft(r) (((Point*)&(r))[0])
100 #define botRight(r) (((Point*)&(r))[1])
103 /* Time of last mouse click, to detect double-click */
104 static long lastMouseTick
= 0;
107 static RgnHandle cursorRgn
;
108 static RgnHandle dragRgn
;
109 static Rect dragRect
;
110 static short dragRectEnbl
;
111 static short dragRectControl
;
113 /* This variable is set when waiting for an event, which is the only moment
114 * scrollbar dragging can be done directly. It's not allowed while commands
115 * are executed, because it may move the cursor and that may cause unexpected
116 * problems (e.g., while ":s" is working).
118 static int allow_scrollbar
= FALSE
;
120 /* Last mouse click caused contextual menu, (to provide proper release) */
121 static short clickIsPopup
;
123 /* Feedback Action for Scrollbar */
124 ControlActionUPP gScrollAction
;
125 ControlActionUPP gScrollDrag
;
127 /* Keeping track of which scrollbar is being dragged */
128 static ControlHandle dragged_sb
= NULL
;
135 Boolean isPanelVisible
;
136 } gFontPanelInfo
= { 0, 0, 0, false };
139 # define USE_ATSUI_DRAWING
140 ATSUStyle gFontStyle
;
141 Boolean gIsFontFallbackSet
;
145 #define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
146 #define Red(c) ((c & 0x00FF0000) >> 16)
147 #define Green(c) ((c & 0x0000FF00) >> 8)
148 #define Blue(c) ((c & 0x000000FF) >> 0)
152 #define vk_Esc 0x35 /* -> 1B */
154 #define vk_F1 0x7A /* -> 10 */
155 #define vk_F2 0x78 /*0x63*/
156 #define vk_F3 0x63 /*0x76*/
157 #define vk_F4 0x76 /*0x60*/
158 #define vk_F5 0x60 /*0x61*/
159 #define vk_F6 0x61 /*0x62*/
160 #define vk_F7 0x62 /*0x63*/ /*?*/
170 #define vk_Clr 0x47 /* -> 1B (ESC) */
171 #define vk_Enter 0x4C /* -> 03 */
173 #define vk_Space 0x31 /* -> 20 */
174 #define vk_Tab 0x30 /* -> 09 */
175 #define vk_Return 0x24 /* -> 0D */
176 /* This is wrong for OSX, what is it for? */
177 #define vk_Delete 0X08 /* -> 08 BackSpace */
179 #define vk_Help 0x72 /* -> 05 */
180 #define vk_Home 0x73 /* -> 01 */
181 #define vk_PageUp 0x74 /* -> 0D */
182 #define vk_FwdDelete 0x75 /* -> 7F */
183 #define vk_End 0x77 /* -> 04 */
184 #define vk_PageDown 0x79 /* -> 0C */
186 #define vk_Up 0x7E /* -> 1E */
187 #define vk_Down 0x7D /* -> 1F */
188 #define vk_Left 0x7B /* -> 1C */
189 #define vk_Right 0x7C /* -> 1D */
191 #define vk_Undo vk_F1
193 #define vk_Copy vk_F3
194 #define vk_Paste vk_F4
195 #define vk_PrintScreen vk_F13
196 #define vk_SCrollLock vk_F14
197 #define vk_Pause vk_F15
198 #define vk_NumLock vk_Clr
199 #define vk_Insert vk_Help
213 {vk_Right
, 'k', 'r'},
232 /* {XK_Help, '%', '1'}, */
233 /* {XK_Undo, '&', '8'}, */
234 /* {XK_BackSpace, 'k', 'b'}, */
236 {vk_Delete
, 'k', 'b'},
238 {vk_Insert
, 'k', 'I'},
239 {vk_FwdDelete
, 'k', 'D'},
242 /* {XK_Prior, 'k', 'P'}, */
243 /* {XK_Next, 'k', 'N'}, */
244 /* {XK_Print, '%', '9'}, */
246 {vk_PageUp
, 'k', 'P'},
247 {vk_PageDown
, 'k', 'N'},
249 /* End of list marker: */
254 * ------------------------------------------------------------
255 * Forward declaration (for those needed)
256 * ------------------------------------------------------------
260 OSErr
HandleUnusedParms(const AppleEvent
*theAEvent
);
263 #ifdef FEAT_GUI_TABLINE
264 static void initialise_tabline(void);
265 static WindowRef drawer
= NULL
; // TODO: put into gui.h
269 * ------------------------------------------------------------
271 * ------------------------------------------------------------
277 * Allocate memory and convert the C-String passed in
278 * into a pascal string
283 C2Pascal_save(char_u
*Cstring
)
285 char_u
*PascalString
;
291 len
= STRLEN(Cstring
);
293 if (len
> 255) /* Truncate if necessary */
296 PascalString
= alloc(len
+ 1);
297 if (PascalString
!= NULL
)
299 mch_memmove(PascalString
+ 1, Cstring
, len
);
300 PascalString
[0] = len
;
307 * C2Pascal_save_and_remove_backslash
309 * Allocate memory and convert the C-String passed in
310 * into a pascal string. Also remove the backslash at the same time
315 C2Pascal_save_and_remove_backslash(char_u
*Cstring
)
317 char_u
*PascalString
;
321 len
= STRLEN(Cstring
);
323 if (len
> 255) /* Truncate if necessary */
326 PascalString
= alloc(len
+ 1);
327 if (PascalString
!= NULL
)
329 for (c
= Cstring
, p
= PascalString
+1, len
= 0; (*c
!= 0) && (len
< 255); c
++)
331 if ((*c
== '\\') && (c
[1] != 0))
339 PascalString
[0] = len
;
346 * Convert the modifiers of an Event into vim's modifiers (mouse)
350 EventModifiers2VimMouseModifiers(EventModifiers macModifiers
)
352 int_u vimModifiers
= 0x00;
354 if (macModifiers
& (shiftKey
| rightShiftKey
))
355 vimModifiers
|= MOUSE_SHIFT
;
356 if (macModifiers
& (controlKey
| rightControlKey
))
357 vimModifiers
|= MOUSE_CTRL
;
358 if (macModifiers
& (optionKey
| rightOptionKey
))
359 vimModifiers
|= MOUSE_ALT
;
361 /* Not yet supported */
362 if (macModifiers
& (cmdKey
)) /* There's no rightCmdKey */
363 vimModifiers
|= MOUSE_CMD
;
365 return (vimModifiers
);
369 * Convert the modifiers of an Event into vim's modifiers (keys)
373 EventModifiers2VimModifiers(EventModifiers macModifiers
)
375 int_u vimModifiers
= 0x00;
377 if (macModifiers
& (shiftKey
| rightShiftKey
))
378 vimModifiers
|= MOD_MASK_SHIFT
;
379 if (macModifiers
& (controlKey
| rightControlKey
))
380 vimModifiers
|= MOD_MASK_CTRL
;
381 if (macModifiers
& (optionKey
| rightOptionKey
))
382 vimModifiers
|= MOD_MASK_ALT
;
384 if (macModifiers
& (cmdKey
)) /* There's no rightCmdKey */
385 vimModifiers
|= MOD_MASK_CMD
;
387 return (vimModifiers
);
390 /* Convert a string representing a point size into pixels. The string should
391 * be a positive decimal number, with an optional decimal point (eg, "12", or
392 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
393 * character is stored in *end. The flag "vertical" says whether this
394 * calculation is for a vertical (height) size or a horizontal (width) one.
399 points_to_pixels(char_u
*str
, char_u
**end
, int vertical
)
407 if (*str
== '.' && divisor
== 0)
409 /* Start keeping a divisor, for later */
418 points
+= *str
- '0';
427 pixels
= points
/divisor
;
434 * Deletes all traces of any Windows-style mnemonic text (including any
435 * parentheses) from a menu item and returns the cleaned menu item title.
436 * The caller is responsible for releasing the returned string.
439 menu_title_removing_mnemonic(vimmenu_T
*menu
)
444 CFRange mnemonicStart
;
446 CFMutableStringRef cleanedName
;
448 menuTitleLen
= STRLEN(menu
->dname
);
449 name
= mac_enc_to_cfstring(menu
->dname
, menuTitleLen
);
453 /* Simple mnemonic-removal algorithm, assumes single parenthesized
454 * mnemonic character towards the end of the menu text */
455 mnemonicStart
= CFStringFind(name
, CFSTR("("), kCFCompareBackwards
);
456 displayLen
= CFStringGetLength(name
);
458 if (mnemonicStart
.location
!= kCFNotFound
459 && (mnemonicStart
.location
+ 2) < displayLen
460 && CFStringGetCharacterAtIndex(name
,
461 mnemonicStart
.location
+ 1) == (UniChar
)menu
->mnemonic
)
463 if (CFStringFindWithOptions(name
, CFSTR(")"),
464 CFRangeMake(mnemonicStart
.location
+ 1,
465 displayLen
- mnemonicStart
.location
- 1),
466 kCFCompareBackwards
, &mnemonicEnd
) &&
467 (mnemonicStart
.location
+ 2) == mnemonicEnd
.location
)
469 cleanedName
= CFStringCreateMutableCopy(NULL
, 0, name
);
472 CFStringDelete(cleanedName
,
473 CFRangeMake(mnemonicStart
.location
,
474 mnemonicEnd
.location
+ 1 -
475 mnemonicStart
.location
));
489 * Convert a list of FSSpec aliases into a list of fullpathname
494 new_fnames_from_AEDesc(AEDesc
*theList
, long *numFiles
, OSErr
*error
)
496 char_u
**fnames
= NULL
;
501 AEKeyword dummyKeyword
;
504 /* Get number of files in list */
505 *error
= AECountItems(theList
, numFiles
);
509 /* Allocate the pointer list */
510 fnames
= (char_u
**) alloc(*numFiles
* sizeof(char_u
*));
512 /* Empty out the list */
513 for (fileCount
= 0; fileCount
< *numFiles
; fileCount
++)
514 fnames
[fileCount
] = NULL
;
516 /* Scan the list of FSSpec */
517 for (fileCount
= 1; fileCount
<= *numFiles
; fileCount
++)
519 /* Get the alias for the nth file, convert to an FSSpec */
520 newError
= AEGetNthPtr(theList
, fileCount
, typeFSS
,
521 &dummyKeyword
, &dummyType
,
522 (Ptr
) &fileToOpen
, sizeof(FSSpec
), &actualSize
);
525 /* Caller is able to clean up */
526 /* TODO: Should be clean up or not? For safety. */
530 /* Convert the FSSpec to a pathname */
531 fnames
[fileCount
- 1] = FullPathFromFSSpec_save(fileToOpen
);
538 * ------------------------------------------------------------
539 * CodeWarrior External Editor Support
540 * ------------------------------------------------------------
542 #ifdef FEAT_CW_EDITOR
545 * Handle the Window Search event from CodeWarrior
550 * The IDE sends the Window Search AppleEvent to the editor when it
551 * needs to know whether a particular file is open in the editor.
556 * None. Put data in the location specified in the structure received.
561 * When the editor receives this event, determine whether the specified
562 * file is open. If it is, return the modification date/time for that file
563 * in the appropriate location specified in the structure. If the file is
564 * not opened, put the value fnfErr(file not found) in that location.
568 typedef struct WindowSearch WindowSearch
;
569 struct WindowSearch
/* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
571 FSSpec theFile
; // identifies the file
572 long *theDate
; // where to put the modification date/time
577 const AppleEvent
*theAEvent
,
578 AppleEvent
*theReply
,
583 int foundFile
= false;
585 WindowSearch SearchData
;
588 error
= AEGetParamPtr(theAEvent
, keyDirectObject
, typeChar
, &typeCode
, (Ptr
) &SearchData
, sizeof(WindowSearch
), &actualSize
);
592 error
= HandleUnusedParms(theAEvent
);
596 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
597 if (buf
->b_ml
.ml_mfp
!= NULL
598 && SearchData
.theFile
.parID
== buf
->b_FSSpec
.parID
599 && SearchData
.theFile
.name
[0] == buf
->b_FSSpec
.name
[0]
600 && STRNCMP(SearchData
.theFile
.name
, buf
->b_FSSpec
.name
, buf
->b_FSSpec
.name
[0] + 1) == 0)
606 if (foundFile
== false)
607 *SearchData
.theDate
= fnfErr
;
609 *SearchData
.theDate
= buf
->b_mtime
;
615 * Handle the Modified (from IDE to Editor) event from CodeWarrior
620 * The IDE sends this event to the external editor when it wants to
621 * know which files that are open in the editor have been modified.
628 * The reply for this event is:
630 * keyDirectObject typeAEList required
631 * each element in the list is a structure of typeChar
636 * When building the reply event, include one element in the list for
637 * each open file that has been modified.
641 typedef struct ModificationInfo ModificationInfo
;
642 struct ModificationInfo
/* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
644 FSSpec theFile
; // identifies the file
645 long theDate
; // the date/time the file was last modified
646 short saved
; // set this to zero when replying, unused
651 const AppleEvent
*theAEvent
,
652 AppleEvent
*theReply
,
656 AEDescList replyList
;
658 ModificationInfo theFile
;
663 error
= HandleUnusedParms(theAEvent
);
668 /* replyObject.descriptorType = typeNull;
669 replyObject.dataHandle = nil;*/
671 /* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
672 error
= AECreateList(nil
, 0, false, &replyList
);
677 error
= AECountItems(&replyList
, &numFiles
);
679 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
680 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
688 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
689 if (buf
->b_ml
.ml_mfp
!= NULL
)
691 /* Add this file to the list */
692 theFile
.theFile
= buf
->b_FSSpec
;
693 theFile
.theDate
= buf
->b_mtime
;
694 /* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
695 error
= AEPutPtr(&replyList
, numFiles
, typeChar
, (Ptr
) &theFile
, sizeof(theFile
));
699 error
= AECountItems(&replyList
, &numFiles
);
702 /* We can add data only if something to reply */
703 error
= AEPutParamDesc(theReply
, keyDirectObject
, &replyList
);
705 if (replyList
.dataHandle
)
706 AEDisposeDesc(&replyList
);
712 * Handle the Get Text event from CodeWarrior
717 * The IDE sends the Get Text AppleEvent to the editor when it needs
718 * the source code from a file. For example, when the user issues a
719 * Check Syntax or Compile command, the compiler needs access to
720 * the source code contained in the file.
725 * None. Put data in locations specified in the structure received.
730 * When the editor receives this event, it must set the size of the handle
731 * in theText to fit the data in the file. It must then copy the entire
732 * contents of the specified file into the memory location specified in
737 typedef struct CW_GetText CW_GetText
;
738 struct CW_GetText
/* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
740 FSSpec theFile
; /* identifies the file */
741 Handle theText
; /* the location where you return the text (must be resized properly) */
742 long *unused
; /* 0 (not used) */
743 long *theDate
; /* where to put the modification date/time */
748 const AppleEvent
*theAEvent
,
749 AppleEvent
*theReply
,
754 int foundFile
= false;
756 CW_GetText GetTextData
;
759 char_u
*fullbuffer
= NULL
;
765 error
= AEGetParamPtr(theAEvent
, keyDirectObject
, typeChar
, &typeCode
, (Ptr
) &GetTextData
, sizeof(GetTextData
), &actualSize
);
770 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
771 if (buf
->b_ml
.ml_mfp
!= NULL
)
772 if (GetTextData
.theFile
.parID
== buf
->b_FSSpec
.parID
)
780 BufferSize
= 0; /* GetHandleSize(GetTextData.theText); */
781 for (lineno
= 0; lineno
<= buf
->b_ml
.ml_line_count
; lineno
++)
783 /* Must use the right buffer */
784 line
= ml_get_buf(buf
, (linenr_T
) lineno
, FALSE
);
785 linesize
= STRLEN(line
) + 1;
786 lineStart
= BufferSize
;
787 BufferSize
+= linesize
;
788 /* Resize handle to linesize+1 to include the linefeed */
789 SetHandleSize(GetTextData
.theText
, BufferSize
);
790 if (GetHandleSize(GetTextData
.theText
) != BufferSize
)
792 break; /* Simple handling for now */
796 HLock(GetTextData
.theText
);
797 fullbuffer
= (char_u
*) *GetTextData
.theText
;
798 STRCPY((char_u
*)(fullbuffer
+ lineStart
), line
);
799 fullbuffer
[BufferSize
-1] = '\r';
800 HUnlock(GetTextData
.theText
);
803 if (fullbuffer
!= NULL
)
805 HLock(GetTextData
.theText
);
806 fullbuffer
[BufferSize
-1] = 0;
807 HUnlock(GetTextData
.theText
);
809 if (foundFile
== false)
810 *GetTextData
.theDate
= fnfErr
;
812 /* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
813 *GetTextData
.theDate
= buf
->b_mtime
;
816 error
= HandleUnusedParms(theAEvent
);
825 /* Taken from MoreAppleEvents:ProcessHelpers*/
827 FindProcessBySignature(
828 const OSType targetType
,
829 const OSType targetCreator
,
830 ProcessSerialNumberPtr psnPtr
)
833 Boolean lookingForProcess
= true;
835 ProcessInfoRec infoRec
;
837 infoRec
.processInfoLength
= sizeof(ProcessInfoRec
);
838 infoRec
.processName
= nil
;
839 infoRec
.processAppSpec
= nil
;
841 psnPtr
->lowLongOfPSN
= kNoProcess
;
842 psnPtr
->highLongOfPSN
= kNoProcess
;
844 while (lookingForProcess
)
846 anErr
= GetNextProcess(psnPtr
);
848 lookingForProcess
= false;
851 anErr
= GetProcessInformation(psnPtr
, &infoRec
);
853 && (infoRec
.processType
== targetType
)
854 && (infoRec
.processSignature
== targetCreator
))
855 lookingForProcess
= false;
860 }//end FindProcessBySignature
863 Send_KAHL_MOD_AE(buf_T
*buf
)
866 AEDesc targetAppDesc
= { typeNull
, nil
};
867 ProcessSerialNumber psn
= { kNoProcess
, kNoProcess
};
868 AppleEvent theReply
= { typeNull
, nil
};
870 AppleEvent theEvent
= {typeNull
, nil
};
871 AEIdleUPP idleProcUPP
= nil
;
872 ModificationInfo ModData
;
875 anErr
= FindProcessBySignature('APPL', 'CWIE', &psn
);
878 anErr
= AECreateDesc(typeProcessSerialNumber
, &psn
,
879 sizeof(ProcessSerialNumber
), &targetAppDesc
);
883 anErr
= AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc
,
884 kAutoGenerateReturnID
, kAnyTransactionID
, &theEvent
);
887 AEDisposeDesc(&targetAppDesc
);
890 ModData
.theFile
= buf
->b_FSSpec
;
891 ModData
.theDate
= buf
->b_mtime
;
894 anErr
= AEPutParamPtr(&theEvent
, keyDirectObject
, typeChar
, &ModData
, sizeof(ModData
));
896 if (idleProcUPP
== nil
)
897 sendMode
= kAENoReply
;
899 sendMode
= kAEWaitReply
;
902 anErr
= AESend(&theEvent
, &theReply
, sendMode
, kAENormalPriority
, kNoTimeOut
, idleProcUPP
, nil
);
903 if (anErr
== noErr
&& sendMode
== kAEWaitReply
)
905 /* anErr = AEHGetHandlerError(&theReply);*/
907 (void) AEDisposeDesc(&theReply
);
910 #endif /* FEAT_CW_EDITOR */
913 * ------------------------------------------------------------
914 * Apple Event Handling procedure
915 * ------------------------------------------------------------
920 * Handle the Unused parms of an AppleEvent
924 HandleUnusedParms(const AppleEvent
*theAEvent
)
929 AEKeyword missedKeyword
;
931 /* Get the "missed keyword" attribute from the AppleEvent. */
932 error
= AEGetAttributePtr(theAEvent
, keyMissedKeywordAttr
,
933 typeKeyword
, &dummyType
,
934 (Ptr
)&missedKeyword
, sizeof(missedKeyword
),
937 /* If the descriptor isn't found, then we got the required parameters. */
938 if (error
== errAEDescNotFound
)
945 /* Why is this removed? */
946 error
= errAEEventNotHandled
;
955 * Handle the ODoc AppleEvent
957 * Deals with all files dragged to the application icon.
961 typedef struct SelectionRange SelectionRange
;
962 struct SelectionRange
/* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
964 short unused1
; // 0 (not used)
965 short lineNum
; // line to select (<0 to specify range)
966 long startRange
; // start of selection range (if line < 0)
967 long endRange
; // end of selection range (if line < 0)
968 long unused2
; // 0 (not used)
969 long theDate
; // modification date/time
972 /* The IDE uses the optional keyAEPosition parameter to tell the ed-
973 itor the selection range. If lineNum is zero or greater, scroll the text
974 to the specified line. If lineNum is less than zero, use the values in
975 startRange and endRange to select the specified characters. Scroll
976 the text to display the selection. If lineNum, startRange, and
977 endRange are all negative, there is no selection range specified.
981 HandleODocAE(const AppleEvent
*theAEvent
, AppleEvent
*theReply
, long refCon
)
984 * TODO: Clean up the code with convert the AppleEvent into
988 // OSErr firstError = noErr;
989 // short numErrors = 0;
995 // char_u fname[256];
997 SelectionRange thePosition
;
998 short gotPosition
= false;
1001 /* the direct object parameter is the list of aliases to files (one or more) */
1002 error
= AEGetParamDesc(theAEvent
, keyDirectObject
, typeAEList
, &theList
);
1007 error
= AEGetParamPtr(theAEvent
, keyAEPosition
, typeChar
, &typeCode
, (Ptr
) &thePosition
, sizeof(SelectionRange
), &actualSize
);
1010 if (error
== errAEDescNotFound
)
1016 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1020 if (thePosition.lineNum >= 0)
1026 // Set the range char wise
1036 fnames
= new_fnames_from_AEDesc(&theList
, &numFiles
, &error
);
1040 /* TODO: empty fnames[] first */
1051 /* these are the initial files dropped on the Vim icon */
1052 for (i
= 0 ; i
< numFiles
; i
++)
1054 if (ga_grow(&global_alist
.al_ga
, 1) == FAIL
1055 || (p
= vim_strsave(fnames
[i
])) == NULL
)
1058 alist_add(&global_alist
, p
, 2);
1060 fnum
= GARGLIST
[GARGCOUNT
- 1].ae_fnum
;
1063 /* If the file name was already in the buffer list we need to switch
1065 if (curbuf
->b_fnum
!= fnum
)
1069 vim_snprintf((char *)cmd
, 30, "silent %dbuffer", fnum
);
1070 do_cmdline_cmd(cmd
);
1073 /* Change directory to the location of the first file. */
1074 if (GARGCOUNT
> 0 && vim_chdirfile(alist_name(&GARGLIST
[0])) == OK
)
1075 shorten_fnames(TRUE
);
1080 /* Handle the drop, :edit to get to the file */
1081 handle_drop(numFiles
, fnames
, FALSE
);
1083 /* TODO: Handle the goto/select line more cleanly */
1084 if ((numFiles
== 1) & (gotPosition
))
1086 if (thePosition
.lineNum
>= 0)
1088 lnum
= thePosition
.lineNum
+ 1;
1089 /* oap->motion_type = MLINE;
1093 else if (lnum
> curbuf
->b_ml
.ml_line_count
)
1094 lnum
= curbuf
->b_ml
.ml_line_count
;
1095 curwin
->w_cursor
.lnum
= lnum
;
1096 curwin
->w_cursor
.col
= 0;
1097 /* beginline(BL_SOL | BL_FIX);*/
1100 goto_byte(thePosition
.startRange
+ 1);
1103 /* Update the screen display */
1104 update_screen(NOT_VALID
);
1106 /* Select the text if possible */
1109 VIsual_active
= TRUE
;
1110 VIsual_select
= FALSE
;
1111 VIsual
= curwin
->w_cursor
;
1112 if (thePosition
.lineNum
< 0)
1115 goto_byte(thePosition
.endRange
);
1127 /* Fake mouse event to wake from stall */
1128 PostEvent(mouseUp
, 0);
1131 AEDisposeDesc(&theList
); /* dispose what we allocated */
1133 error
= HandleUnusedParms(theAEvent
);
1142 Handle_aevt_oapp_AE(
1143 const AppleEvent
*theAEvent
,
1144 AppleEvent
*theReply
,
1147 OSErr error
= noErr
;
1149 error
= HandleUnusedParms(theAEvent
);
1158 Handle_aevt_quit_AE(
1159 const AppleEvent
*theAEvent
,
1160 AppleEvent
*theReply
,
1163 OSErr error
= noErr
;
1165 error
= HandleUnusedParms(theAEvent
);
1169 /* Need to fake a :confirm qa */
1170 do_cmdline_cmd((char_u
*)"confirm qa");
1180 Handle_aevt_pdoc_AE(
1181 const AppleEvent
*theAEvent
,
1182 AppleEvent
*theReply
,
1185 OSErr error
= noErr
;
1187 error
= HandleUnusedParms(theAEvent
);
1193 * Handling of unknown AppleEvent
1195 * (Just get rid of all the parms)
1199 const AppleEvent
*theAEvent
,
1200 AppleEvent
*theReply
,
1203 OSErr error
= noErr
;
1205 error
= HandleUnusedParms(theAEvent
);
1212 * Install the various AppleEvent Handlers
1215 InstallAEHandlers(void)
1219 /* install open application handler */
1220 error
= AEInstallEventHandler(kCoreEventClass
, kAEOpenApplication
,
1221 NewAEEventHandlerUPP(Handle_aevt_oapp_AE
), 0, false);
1227 /* install quit application handler */
1228 error
= AEInstallEventHandler(kCoreEventClass
, kAEQuitApplication
,
1229 NewAEEventHandlerUPP(Handle_aevt_quit_AE
), 0, false);
1235 /* install open document handler */
1236 error
= AEInstallEventHandler(kCoreEventClass
, kAEOpenDocuments
,
1237 NewAEEventHandlerUPP(HandleODocAE
), 0, false);
1243 /* install print document handler */
1244 error
= AEInstallEventHandler(kCoreEventClass
, kAEPrintDocuments
,
1245 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE
), 0, false);
1247 /* Install Core Suite */
1248 /* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
1249 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1251 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
1252 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1254 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
1255 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1257 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
1258 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1260 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
1261 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1263 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
1264 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1266 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
1267 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
1269 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
1270 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
1272 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
1273 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1275 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
1276 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1278 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
1279 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1281 error = AEInstallEventHandler(kAECoreSuite, kAESave,
1282 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1284 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
1285 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1288 #ifdef FEAT_CW_EDITOR
1290 * Bind codewarrior support handlers
1292 error
= AEInstallEventHandler('KAHL', 'GTTX',
1293 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE
), 0, false);
1298 error
= AEInstallEventHandler('KAHL', 'SRCH',
1299 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE
), 0, false);
1304 error
= AEInstallEventHandler('KAHL', 'MOD ',
1305 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE
), 0, false);
1315 #endif /* USE_AEVENT */
1319 * Callback function, installed by InstallFontPanelHandler(), below,
1320 * to handle Font Panel events.
1324 EventHandlerCallRef inHandlerCallRef
,
1328 if (GetEventKind(inEvent
) == kEventFontPanelClosed
)
1330 gFontPanelInfo
.isPanelVisible
= false;
1334 if (GetEventKind(inEvent
) == kEventFontSelection
)
1337 FMFontFamily newFamily
;
1339 FMFontStyle newStyle
;
1341 /* Retrieve the font family ID number. */
1342 status
= GetEventParameter(inEvent
, kEventParamFMFontFamily
,
1343 /*inDesiredType=*/typeFMFontFamily
, /*outActualType=*/NULL
,
1344 /*inBufferSize=*/sizeof(FMFontFamily
), /*outActualSize=*/NULL
,
1346 if (status
== noErr
)
1347 gFontPanelInfo
.family
= newFamily
;
1349 /* Retrieve the font size. */
1350 status
= GetEventParameter(inEvent
, kEventParamFMFontSize
,
1351 typeFMFontSize
, NULL
, sizeof(FMFontSize
), NULL
, &newSize
);
1352 if (status
== noErr
)
1353 gFontPanelInfo
.size
= newSize
;
1355 /* Retrieve the font style (bold, etc.). Currently unused. */
1356 status
= GetEventParameter(inEvent
, kEventParamFMFontStyle
,
1357 typeFMFontStyle
, NULL
, sizeof(FMFontStyle
), NULL
, &newStyle
);
1358 if (status
== noErr
)
1359 gFontPanelInfo
.style
= newStyle
;
1366 InstallFontPanelHandler(void)
1368 EventTypeSpec eventTypes
[2];
1369 EventHandlerUPP handlerUPP
;
1370 /* EventHandlerRef handlerRef; */
1372 eventTypes
[0].eventClass
= kEventClassFont
;
1373 eventTypes
[0].eventKind
= kEventFontSelection
;
1374 eventTypes
[1].eventClass
= kEventClassFont
;
1375 eventTypes
[1].eventKind
= kEventFontPanelClosed
;
1377 handlerUPP
= NewEventHandlerUPP(FontPanelHandler
);
1379 InstallApplicationEventHandler(handlerUPP
, /*numTypes=*/2, eventTypes
,
1380 /*userData=*/NULL
, /*handlerRef=*/NULL
);
1385 * Fill the buffer pointed to by outName with the name and size
1386 * of the font currently selected in the Font Panel.
1388 #define FONT_STYLE_BUFFER_SIZE 32
1390 GetFontPanelSelection(char_u
*outName
)
1393 ByteCount fontNameLen
= 0;
1395 char_u styleString
[FONT_STYLE_BUFFER_SIZE
];
1400 if (FMGetFontFamilyName(gFontPanelInfo
.family
, buf
) == noErr
)
1402 /* Canonicalize localized font names */
1403 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo
.family
,
1404 gFontPanelInfo
.style
, &fid
, NULL
) != noErr
)
1407 /* Request font name with Mac encoding (otherwise we could
1408 * get an unwanted utf-16 name) */
1409 if (ATSUFindFontName(fid
, kFontFullName
, kFontMacintoshPlatform
,
1410 kFontNoScriptCode
, kFontNoLanguageCode
,
1411 255, (char *)outName
, &fontNameLen
, NULL
) != noErr
)
1414 /* Only encode font size, because style (bold, italic, etc) is
1415 * already part of the font full name */
1416 vim_snprintf((char *)styleString
, FONT_STYLE_BUFFER_SIZE
, ":h%d",
1417 gFontPanelInfo
.size
/*,
1418 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1419 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1420 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1422 if ((fontNameLen
+ STRLEN(styleString
)) < 255)
1423 STRCPY(outName
+ fontNameLen
, styleString
);
1433 * ------------------------------------------------------------
1435 * ------------------------------------------------------------
1439 * gui_mac_get_menu_item_index
1441 * Returns the index inside the menu wher
1443 short /* Shoulde we return MenuItemIndex? */
1444 gui_mac_get_menu_item_index(vimmenu_T
*pMenu
)
1447 short itemIndex
= -1;
1448 vimmenu_T
*pBrother
;
1450 /* Only menu without parent are the:
1451 * -menu in the menubar
1455 * Which are not items anyway.
1459 /* Start from the Oldest Brother */
1460 pBrother
= pMenu
->parent
->children
;
1462 while ((pBrother
) && (itemIndex
== -1))
1464 if (pBrother
== pMenu
)
1467 pBrother
= pBrother
->next
;
1474 gui_mac_get_vim_menu(short menuID
, short itemIndex
, vimmenu_T
*pMenu
)
1477 vimmenu_T
*pChildMenu
;
1478 vimmenu_T
*pElder
= pMenu
->parent
;
1481 /* Only menu without parent are the:
1482 * -menu in the menubar
1486 * Which are not items anyway.
1489 if ((pElder
) && (pElder
->submenu_id
== menuID
))
1491 for (index
= 1; (index
!= itemIndex
) && (pMenu
!= NULL
); index
++)
1492 pMenu
= pMenu
->next
;
1496 for (; pMenu
!= NULL
; pMenu
= pMenu
->next
)
1498 if (pMenu
->children
!= NULL
)
1500 pChildMenu
= gui_mac_get_vim_menu
1501 (menuID
, itemIndex
, pMenu
->children
);
1514 * ------------------------------------------------------------
1515 * MacOS Feedback procedures
1516 * ------------------------------------------------------------
1520 gui_mac_drag_thumb(ControlHandle theControl
, short partCode
)
1523 int value
, dragging
;
1524 ControlHandle theControlToUse
;
1525 int dont_scroll_save
= dont_scroll
;
1527 theControlToUse
= dragged_sb
;
1529 sb
= gui_find_scrollbar((long) GetControlReference(theControlToUse
));
1534 /* Need to find value by diff between Old Poss New Pos */
1535 value
= GetControl32BitValue(theControlToUse
);
1536 dragging
= (partCode
!= 0);
1538 /* When "allow_scrollbar" is FALSE still need to remember the new
1539 * position, but don't actually scroll by setting "dont_scroll". */
1540 dont_scroll
= !allow_scrollbar
;
1541 gui_drag_scrollbar(sb
, value
, dragging
);
1542 dont_scroll
= dont_scroll_save
;
1547 gui_mac_scroll_action(ControlHandle theControl
, short partCode
)
1549 /* TODO: have live support */
1550 scrollbar_T
*sb
, *sb_info
;
1554 int dragging
= FALSE
;
1555 int dont_scroll_save
= dont_scroll
;
1557 sb
= gui_find_scrollbar((long)GetControlReference(theControl
));
1562 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
1565 * Careful: need to get scrollbar info out of first (left) scrollbar
1566 * for window, but keep real scrollbar too because we must pass it to
1567 * gui_drag_scrollbar().
1569 sb_info
= &sb
->wp
->w_scrollbars
[0];
1571 if (sb_info
->size
> 5)
1572 page
= sb_info
->size
- 2; /* use two lines of context */
1574 page
= sb_info
->size
;
1576 else /* Bottom scrollbar */
1579 page
= W_WIDTH(curwin
) - 5;
1584 case kControlUpButtonPart
: data
= -1; break;
1585 case kControlDownButtonPart
: data
= 1; break;
1586 case kControlPageDownPart
: data
= page
; break;
1587 case kControlPageUpPart
: data
= -page
; break;
1588 default: data
= 0; break;
1591 value
= sb_info
->value
+ data
;
1592 /* if (value > sb_info->max)
1593 value = sb_info->max;
1597 /* When "allow_scrollbar" is FALSE still need to remember the new
1598 * position, but don't actually scroll by setting "dont_scroll". */
1599 dont_scroll
= !allow_scrollbar
;
1600 gui_drag_scrollbar(sb
, value
, dragging
);
1601 dont_scroll
= dont_scroll_save
;
1604 gui_mch_set_scrollbar_thumb(sb
, value
, sb_info
->size
, sb_info
->max
);
1606 /* if (sb_info->wp != NULL)
1612 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1617 current_scrollbar = sb_num;
1618 scrollbar_value = value;
1620 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1626 * ------------------------------------------------------------
1627 * MacOS Click Handling procedures
1628 * ------------------------------------------------------------
1633 * Handle a click inside the window, it may happens in the
1634 * scrollbar or the contents.
1636 * TODO: Add support for potential TOOLBAR
1639 gui_mac_doInContentClick(EventRecord
*theEvent
, WindowPtr whichWindow
)
1644 ControlHandle theControl
;
1648 thePoint
= theEvent
->where
;
1649 GlobalToLocal(&thePoint
);
1650 SelectWindow(whichWindow
);
1652 thePortion
= FindControl(thePoint
, whichWindow
, &theControl
);
1654 if (theControl
!= NUL
)
1656 /* We hit a scollbar */
1658 if (thePortion
!= kControlIndicatorPart
)
1660 dragged_sb
= theControl
;
1661 TrackControl(theControl
, thePoint
, gScrollAction
);
1666 dragged_sb
= theControl
;
1668 TrackControl(theControl
, thePoint
, gScrollDrag
);
1670 TrackControl(theControl
, thePoint
, NULL
);
1672 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1673 * button has been released */
1674 gui_mac_drag_thumb(theControl
, 0); /* Should it be thePortion ? (Dany) */
1680 /* We are inside the contents */
1682 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1683 vimModifiers
= EventModifiers2VimMouseModifiers(theEvent
->modifiers
);
1685 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1686 vimMouseButton
= MOUSE_LEFT
;
1688 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
1690 clickIsPopup
= FALSE
;
1692 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent
))
1694 vimMouseButton
= MOUSE_RIGHT
;
1695 vimModifiers
&= ~MOUSE_CTRL
;
1696 clickIsPopup
= TRUE
;
1699 /* Is it a double click ? */
1700 dblClick
= ((theEvent
->when
- lastMouseTick
) < GetDblTime());
1702 /* Send the mouse click to Vim */
1703 gui_send_mouse_event(vimMouseButton
, thePoint
.h
,
1704 thePoint
.v
, dblClick
, vimModifiers
);
1706 /* Create the rectangle around the cursor to detect
1707 * the mouse dragging
1710 /* TODO: Do we need to this even for the contextual menu?
1711 * It may be require for popup_setpos, but for popup?
1713 if (vimMouseButton
== MOUSE_LEFT
)
1716 SetRect(&dragRect
, FILL_X(X_2_COL(thePoint
.h
)),
1717 FILL_Y(Y_2_ROW(thePoint
.v
)),
1718 FILL_X(X_2_COL(thePoint
.h
)+1),
1719 FILL_Y(Y_2_ROW(thePoint
.v
)+1));
1721 dragRectEnbl
= TRUE
;
1722 dragRectControl
= kCreateRect
;
1728 * Handle the click in the titlebar (to move the window)
1731 gui_mac_doInDragClick(Point where
, WindowPtr whichWindow
)
1734 Rect
*movingLimitsPtr
= &movingLimits
;
1736 /* TODO: may try to prevent move outside screen? */
1737 movingLimitsPtr
= GetRegionBounds(GetGrayRgn(), &movingLimits
);
1738 DragWindow(whichWindow
, where
, movingLimitsPtr
);
1742 * Handle the click in the grow box
1745 gui_mac_doInGrowClick(Point where
, WindowPtr whichWindow
)
1749 unsigned short newWidth
;
1750 unsigned short newHeight
;
1752 Rect
*resizeLimitsPtr
= &resizeLimits
;
1753 Rect NewContentRect
;
1755 resizeLimitsPtr
= GetRegionBounds(GetGrayRgn(), &resizeLimits
);
1757 /* Set the minimum size */
1758 /* TODO: Should this come from Vim? */
1759 resizeLimits
.top
= 100;
1760 resizeLimits
.left
= 100;
1762 newSize
= ResizeWindow(whichWindow
, where
, &resizeLimits
, &NewContentRect
);
1763 newWidth
= NewContentRect
.right
- NewContentRect
.left
;
1764 newHeight
= NewContentRect
.bottom
- NewContentRect
.top
;
1765 gui_resize_shell(newWidth
, newHeight
);
1766 gui_mch_set_bg_color(gui
.back_pixel
);
1767 gui_set_shellsize(TRUE
, FALSE
, RESIZE_BOTH
);
1771 * Handle the click in the zoom box
1774 gui_mac_doInZoomClick(EventRecord
*theEvent
, WindowPtr whichWindow
)
1780 /* ideal width is current */
1781 p
.h
= Columns
* gui
.char_width
+ 2 * gui
.border_offset
;
1782 if (gui
.which_scrollbars
[SBAR_LEFT
])
1783 p
.h
+= gui
.scrollbar_width
;
1784 if (gui
.which_scrollbars
[SBAR_RIGHT
])
1785 p
.h
+= gui
.scrollbar_width
;
1786 /* ideal height is as heigh as we can get */
1789 thePart
= IsWindowInStandardState(whichWindow
, &p
, &r
)
1790 ? inZoomIn
: inZoomOut
;
1792 if (!TrackBox(whichWindow
, theEvent
->where
, thePart
))
1795 /* use returned width */
1796 p
.h
= r
.right
- r
.left
;
1797 /* adjust returned height */
1798 p
.v
= r
.bottom
- r
.top
- 2 * gui
.border_offset
;
1799 if (gui
.which_scrollbars
[SBAR_BOTTOM
])
1800 p
.v
-= gui
.scrollbar_height
;
1801 p
.v
-= p
.v
% gui
.char_height
;
1802 p
.v
+= 2 * gui
.border_width
;
1803 if (gui
.which_scrollbars
[SBAR_BOTTOM
]);
1804 p
.v
+= gui
.scrollbar_height
;
1806 ZoomWindowIdeal(whichWindow
, thePart
, &p
);
1808 GetWindowBounds(whichWindow
, kWindowContentRgn
, &r
);
1809 gui_resize_shell(r
.right
- r
.left
, r
.bottom
- r
.top
);
1810 gui_mch_set_bg_color(gui
.back_pixel
);
1811 gui_set_shellsize(TRUE
, FALSE
, RESIZE_BOTH
);
1815 * ------------------------------------------------------------
1816 * MacOS Event Handling procedure
1817 * ------------------------------------------------------------
1821 * Handle the Update Event
1825 gui_mac_doUpdateEvent(EventRecord
*event
)
1827 WindowPtr whichWindow
;
1829 RgnHandle updateRgn
;
1831 Rect
*updateRectPtr
;
1837 updateRgn
= NewRgn();
1838 if (updateRgn
== NULL
)
1841 /* This could be done by the caller as we
1842 * don't require anything else out of the event
1844 whichWindow
= (WindowPtr
) event
->message
;
1846 /* Save Current Port */
1849 /* Select the Window's Port */
1850 SetPortWindowPort(whichWindow
);
1852 /* Let's update the window */
1853 BeginUpdate(whichWindow
);
1854 /* Redraw the biggest rectangle covering the area
1857 GetPortVisibleRegion(GetWindowPort(whichWindow
), updateRgn
);
1859 /* Would be more appropriate to use the following but doesn't
1860 * seem to work under MacOS X (Dany)
1862 GetWindowRegion(whichWindow
, kWindowUpdateRgn
, updateRgn
);
1865 /* Use the HLock useless in Carbon? Is it harmful?*/
1866 HLock((Handle
) updateRgn
);
1868 updateRectPtr
= GetRegionBounds(updateRgn
, &updateRect
);
1870 /* Code from original Carbon Port (using GetWindowRegion.
1871 * I believe the UpdateRgn is already in local (Dany)
1873 GlobalToLocal(&topLeft(updateRect
)); /* preCarbon? */
1874 GlobalToLocal(&botRight(updateRect
));
1876 /* Update the content (i.e. the text) */
1877 gui_redraw(updateRectPtr
->left
, updateRectPtr
->top
,
1878 updateRectPtr
->right
- updateRectPtr
->left
,
1879 updateRectPtr
->bottom
- updateRectPtr
->top
);
1880 /* Clear the border areas if needed */
1881 gui_mch_set_bg_color(gui
.back_pixel
);
1882 if (updateRectPtr
->left
< FILL_X(0))
1884 SetRect(&rc
, 0, 0, FILL_X(0), FILL_Y(Rows
));
1887 if (updateRectPtr
->top
< FILL_Y(0))
1889 SetRect(&rc
, 0, 0, FILL_X(Columns
), FILL_Y(0));
1892 if (updateRectPtr
->right
> FILL_X(Columns
))
1894 SetRect(&rc
, FILL_X(Columns
), 0,
1895 FILL_X(Columns
) + gui
.border_offset
, FILL_Y(Rows
));
1898 if (updateRectPtr
->bottom
> FILL_Y(Rows
))
1900 SetRect(&rc
, 0, FILL_Y(Rows
), FILL_X(Columns
) + gui
.border_offset
,
1901 FILL_Y(Rows
) + gui
.border_offset
);
1904 HUnlock((Handle
) updateRgn
);
1905 DisposeRgn(updateRgn
);
1907 /* Update scrollbars */
1908 DrawControls(whichWindow
);
1910 /* Update the GrowBox */
1911 /* Taken from FAQ 33-27 */
1913 GetWindowBounds(whichWindow
, kWindowGrowRgn
, &growRect
);
1915 ClipRect(&growRect
);
1916 DrawGrowIcon(whichWindow
);
1918 DisposeRgn(saveRgn
);
1919 EndUpdate(whichWindow
);
1921 /* Restore original Port */
1926 * Handle the activate/deactivate event
1927 * (apply to a window)
1930 gui_mac_doActivateEvent(EventRecord
*event
)
1932 WindowPtr whichWindow
;
1934 whichWindow
= (WindowPtr
) event
->message
;
1935 /* Dim scrollbars */
1936 if (whichWindow
== gui
.VimWindow
)
1938 ControlRef rootControl
;
1939 GetRootControl(gui
.VimWindow
, &rootControl
);
1940 if ((event
->modifiers
) & activeFlag
)
1941 ActivateControl(rootControl
);
1943 DeactivateControl(rootControl
);
1947 gui_focus_change((event
->modifiers
) & activeFlag
);
1952 * Handle the suspend/resume event
1953 * (apply to the application)
1956 gui_mac_doSuspendEvent(EventRecord
*event
)
1958 /* The frontmost application just changed */
1960 /* NOTE: the suspend may happen before the deactivate
1964 /* May not need to change focus as the window will
1965 * get an activate/deactivate event
1967 if (event
->message
& 1)
1969 gui_focus_change(TRUE
);
1972 gui_focus_change(FALSE
);
1978 #ifdef USE_CARBONKEYHANDLER
1980 static int dialog_busy
= FALSE
; /* TRUE when gui_mch_dialog() wants the keys */
1982 # define INLINE_KEY_BUFFER_SIZE 80
1983 static pascal OSStatus
1984 gui_mac_doKeyEventCarbon(
1985 EventHandlerCallRef nextHandler
,
1989 /* Multibyte-friendly key event handler */
1993 char_u result
[INLINE_KEY_BUFFER_SIZE
];
1998 UInt32 modifiers
, vimModifiers
;
2001 Boolean isSpecial
= FALSE
;
2005 /* Mask the mouse (as per user setting) */
2009 /* Don't use the keys when the dialog wants them. */
2011 return eventNotHandledErr
;
2013 if (noErr
!= GetEventParameter(theEvent
, kEventParamTextInputSendText
,
2014 typeUnicodeText
, NULL
, 0, &actualSize
, NULL
))
2015 return eventNotHandledErr
;
2017 text
= (UniChar
*)alloc(actualSize
);
2019 return eventNotHandledErr
;
2021 err
= GetEventParameter(theEvent
, kEventParamTextInputSendText
,
2022 typeUnicodeText
, NULL
, actualSize
, NULL
, text
);
2023 require_noerr(err
, done
);
2025 err
= GetEventParameter(theEvent
, kEventParamTextInputSendKeyboardEvent
,
2026 typeEventRef
, NULL
, sizeof(EventRef
), NULL
, &keyEvent
);
2027 require_noerr(err
, done
);
2029 err
= GetEventParameter(keyEvent
, kEventParamKeyModifiers
,
2030 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &modifiers
);
2031 require_noerr(err
, done
);
2033 err
= GetEventParameter(keyEvent
, kEventParamKeyCode
,
2034 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &key_sym
);
2035 require_noerr(err
, done
);
2037 err
= GetEventParameter(keyEvent
, kEventParamKeyMacCharCodes
,
2038 typeChar
, NULL
, sizeof(char), NULL
, &charcode
);
2039 require_noerr(err
, done
);
2042 if (modifiers
& cmdKey
)
2043 goto done
; /* Let system handle Cmd+... */
2046 key_char
= charcode
;
2047 vimModifiers
= EventModifiers2VimModifiers(modifiers
);
2049 /* Find the special key (eg., for cursor keys) */
2050 if (actualSize
<= sizeof(UniChar
) &&
2051 ((text
[0] < 0x20) || (text
[0] == 0x7f)))
2053 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; ++i
)
2054 if (special_keys
[i
].key_sym
== key_sym
)
2056 key_char
= TO_SPECIAL(special_keys
[i
].vim_code0
,
2057 special_keys
[i
].vim_code1
);
2058 key_char
= simplify_key(key_char
,
2059 (int *)&vimModifiers
);
2065 /* Intercept CMD-. and CTRL-c */
2066 if (((modifiers
& controlKey
) && key_char
== 'c') ||
2067 ((modifiers
& cmdKey
) && key_char
== '.'))
2072 /* remove SHIFT for keys that are already shifted, e.g.,
2074 if (key_char
< 0x100 && !isalpha(key_char
) && isprint(key_char
))
2075 vimModifiers
&= ~MOD_MASK_SHIFT
;
2077 /* remove CTRL from keys that already have it */
2078 if (key_char
< 0x20)
2079 vimModifiers
&= ~MOD_MASK_CTRL
;
2081 /* don't process unicode characters here */
2082 if (!IS_SPECIAL(key_char
))
2084 /* Following code to simplify and consolidate vimModifiers
2085 * taken liberally from gui_w48.c */
2086 key_char
= simplify_key(key_char
, (int *)&vimModifiers
);
2088 /* Interpret META, include SHIFT, etc. */
2089 key_char
= extract_modifiers(key_char
, (int *)&vimModifiers
);
2090 if (key_char
== CSI
)
2093 if (IS_SPECIAL(key_char
))
2100 result
[len
++] = CSI
;
2101 result
[len
++] = KS_MODIFIER
;
2102 result
[len
++] = vimModifiers
;
2105 if (isSpecial
&& IS_SPECIAL(key_char
))
2107 result
[len
++] = CSI
;
2108 result
[len
++] = K_SECOND(key_char
);
2109 result
[len
++] = K_THIRD(key_char
);
2113 encLen
= actualSize
;
2114 to
= mac_utf16_to_enc(text
, actualSize
, &encLen
);
2117 /* This is basically add_to_input_buf_csi() */
2118 for (i
= 0; i
< encLen
&& len
< (INLINE_KEY_BUFFER_SIZE
-1); ++i
)
2120 result
[len
++] = to
[i
];
2123 result
[len
++] = KS_EXTRA
;
2124 result
[len
++] = (int)KE_CSI
;
2131 add_to_input_buf(result
, len
);
2138 /* Fake event to wake up WNE (required to get
2139 * key repeat working */
2140 PostEvent(keyUp
, 0);
2144 return eventNotHandledErr
;
2148 gui_mac_doKeyEvent(EventRecord
*theEvent
)
2150 /* TODO: add support for COMMAND KEY */
2152 unsigned char string
[20];
2158 int simplify
= FALSE
;
2160 /* Mask the mouse (as per user setting) */
2164 /* Get the key code and it's ASCII representation */
2165 key_sym
= ((theEvent
->message
& keyCodeMask
) >> 8);
2166 key_char
= theEvent
->message
& charCodeMask
;
2169 /* Intercept CTRL-C */
2170 if (theEvent
->modifiers
& controlKey
)
2172 if (key_char
== Ctrl_C
&& ctrl_c_interrupts
)
2174 else if ((theEvent
->modifiers
& ~(controlKey
|shiftKey
)) == 0
2175 && (key_char
== '2' || key_char
== '6'))
2177 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2178 if (key_char
== '2')
2181 key_char
= Ctrl_HAT
;
2182 theEvent
->modifiers
= 0;
2186 /* Intercept CMD-. */
2187 if (theEvent
->modifiers
& cmdKey
)
2188 if (key_char
== '.')
2191 /* Handle command key as per menu */
2192 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2193 if (theEvent
->modifiers
& cmdKey
)
2194 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2195 * Why the mouse button? */
2196 if ((theEvent
->modifiers
& (~(cmdKey
| btnState
| alphaLock
))) == 0)
2198 menu
= MenuKey(key_char
);
2201 gui_mac_handle_menu(menu
);
2206 /* Convert the modifiers */
2207 modifiers
= EventModifiers2VimModifiers(theEvent
->modifiers
);
2210 /* Handle special keys. */
2212 /* Why has this been removed? */
2213 if (!(theEvent
->modifiers
& (cmdKey
| controlKey
| rightControlKey
)))
2216 /* Find the special key (for non-printable keyt_char) */
2217 if ((key_char
< 0x20) || (key_char
== 0x7f))
2218 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; i
++)
2219 if (special_keys
[i
].key_sym
== key_sym
)
2222 /* We currently don't have not so special key */
2223 if (special_keys
[i
].vim_code1
== NUL
)
2224 key_char
= special_keys
[i
].vim_code0
;
2227 key_char
= TO_SPECIAL(special_keys
[i
].vim_code0
,
2228 special_keys
[i
].vim_code1
);
2234 /* For some keys the modifier is included in the char itself. */
2235 if (simplify
|| key_char
== TAB
|| key_char
== ' ')
2236 key_char
= simplify_key(key_char
, &modifiers
);
2238 /* Add the modifier to the input bu if needed */
2239 /* Do not want SHIFT-A or CTRL-A with modifier */
2240 if (!IS_SPECIAL(key_char
)
2241 && key_sym
!= vk_Space
2242 && key_sym
!= vk_Tab
2243 && key_sym
!= vk_Return
2244 && key_sym
!= vk_Enter
2245 && key_sym
!= vk_Esc
)
2248 /* Clear modifiers when only one modifier is set */
2249 if ((modifiers
== MOD_MASK_SHIFT
)
2250 || (modifiers
== MOD_MASK_CTRL
)
2251 || (modifiers
== MOD_MASK_ALT
))
2254 if (modifiers
& MOD_MASK_CTRL
)
2255 modifiers
= modifiers
& ~MOD_MASK_CTRL
;
2256 if (modifiers
& MOD_MASK_ALT
)
2257 modifiers
= modifiers
& ~MOD_MASK_ALT
;
2258 if (modifiers
& MOD_MASK_SHIFT
)
2259 modifiers
= modifiers
& ~MOD_MASK_SHIFT
;
2264 string
[len
++] = CSI
;
2265 string
[len
++] = KS_MODIFIER
;
2266 string
[len
++] = modifiers
;
2269 if (IS_SPECIAL(key_char
))
2271 string
[len
++] = CSI
;
2272 string
[len
++] = K_SECOND(key_char
);
2273 string
[len
++] = K_THIRD(key_char
);
2278 /* Convert characters when needed (e.g., from MacRoman to latin1).
2279 * This doesn't work for the NUL byte. */
2280 if (input_conv
.vc_type
!= CONV_NONE
&& key_char
> 0)
2282 char_u from
[2], *to
;
2288 to
= string_convert(&input_conv
, from
, &l
);
2291 for (i
= 0; i
< l
&& len
< 19; i
++)
2295 string
[len
++] = KS_EXTRA
;
2296 string
[len
++] = KE_CSI
;
2299 string
[len
++] = to
[i
];
2304 string
[len
++] = key_char
;
2308 string
[len
++] = key_char
;
2311 if (len
== 1 && string
[0] == CSI
)
2313 /* Turn CSI into K_CSI. */
2314 string
[ len
++ ] = KS_EXTRA
;
2315 string
[ len
++ ] = KE_CSI
;
2318 add_to_input_buf(string
, len
);
2326 gui_mac_doMouseDownEvent(EventRecord
*theEvent
)
2329 WindowPtr whichWindow
;
2331 thePart
= FindWindow(theEvent
->where
, &whichWindow
);
2333 #ifdef FEAT_GUI_TABLINE
2334 /* prevent that the vim window size changes if it's activated by a
2335 click into the tab pane */
2336 if (whichWindow
== drawer
)
2343 /* TODO: what to do? */
2347 gui_mac_handle_menu(MenuSelect(theEvent
->where
));
2351 gui_mac_doInContentClick(theEvent
, whichWindow
);
2355 gui_mac_doInDragClick(theEvent
->where
, whichWindow
);
2359 gui_mac_doInGrowClick(theEvent
->where
, whichWindow
);
2363 if (TrackGoAway(whichWindow
, theEvent
->where
))
2369 gui_mac_doInZoomClick(theEvent
, whichWindow
);
2376 * [this event is a moving in and out of a region]
2379 gui_mac_doMouseMovedEvent(EventRecord
*event
)
2384 thePoint
= event
->where
;
2385 GlobalToLocal(&thePoint
);
2386 vimModifiers
= EventModifiers2VimMouseModifiers(event
->modifiers
);
2389 gui_mouse_moved(thePoint
.h
, thePoint
.v
);
2392 gui_send_mouse_event(MOUSE_DRAG
, thePoint
.h
,
2393 thePoint
.v
, FALSE
, vimModifiers
);
2395 /* Reset the region from which we move in and out */
2396 SetRect(&dragRect
, FILL_X(X_2_COL(thePoint
.h
)),
2397 FILL_Y(Y_2_ROW(thePoint
.v
)),
2398 FILL_X(X_2_COL(thePoint
.h
)+1),
2399 FILL_Y(Y_2_ROW(thePoint
.v
)+1));
2402 dragRectControl
= kCreateRect
;
2407 * Handle the mouse release
2410 gui_mac_doMouseUpEvent(EventRecord
*theEvent
)
2415 /* TODO: Properly convert the Contextual menu mouse-up */
2416 /* Potential source of the double menu */
2417 lastMouseTick
= theEvent
->when
;
2418 dragRectEnbl
= FALSE
;
2419 dragRectControl
= kCreateEmpty
;
2420 thePoint
= theEvent
->where
;
2421 GlobalToLocal(&thePoint
);
2423 vimModifiers
= EventModifiers2VimMouseModifiers(theEvent
->modifiers
);
2426 vimModifiers
&= ~MOUSE_CTRL
;
2427 clickIsPopup
= FALSE
;
2429 gui_send_mouse_event(MOUSE_RELEASE
, thePoint
.h
, thePoint
.v
, FALSE
, vimModifiers
);
2432 static pascal OSStatus
2433 gui_mac_mouse_wheel(EventHandlerCallRef nextHandler
, EventRef theEvent
,
2436 EventRef bogusEvent
;
2442 EventMouseWheelAxis axis
;
2444 if (noErr
== GetEventParameter(theEvent
, kEventParamMouseWheelAxis
,
2445 typeMouseWheelAxis
, NULL
, sizeof(axis
), NULL
, &axis
)
2446 && axis
!= kEventMouseWheelAxisY
)
2447 goto bail
; /* Vim only does up-down scrolling */
2449 if (noErr
!= GetEventParameter(theEvent
, kEventParamMouseWheelDelta
,
2450 typeSInt32
, NULL
, sizeof(SInt32
), NULL
, &delta
))
2452 if (noErr
!= GetEventParameter(theEvent
, kEventParamMouseLocation
,
2453 typeQDPoint
, NULL
, sizeof(Point
), NULL
, &point
))
2455 if (noErr
!= GetEventParameter(theEvent
, kEventParamKeyModifiers
,
2456 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &mod
))
2461 vim_mod
|= MOUSE_SHIFT
;
2462 if (mod
& controlKey
)
2463 vim_mod
|= MOUSE_CTRL
;
2464 if (mod
& optionKey
)
2465 vim_mod
|= MOUSE_ALT
;
2467 /* post a bogus event to wake up WaitNextEvent */
2468 if (noErr
!= CreateEvent(NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
2469 kEventAttributeNone
, &bogusEvent
))
2471 if (noErr
!= PostEventToQueue(GetMainEventQueue(), bogusEvent
,
2475 ReleaseEvent(bogusEvent
);
2477 if (noErr
== GetWindowBounds(gui
.VimWindow
, kWindowContentRgn
, &bounds
))
2479 point
.h
-= bounds
.left
;
2480 point
.v
-= bounds
.top
;
2483 gui_send_mouse_event((delta
> 0) ? MOUSE_4
: MOUSE_5
,
2484 point
.h
, point
.v
, FALSE
, vim_mod
);
2490 * when we fail give any additional callback handler a chance to perform
2493 return CallNextEventHandler(nextHandler
, theEvent
);
2499 * This would be the normal way of invoking the contextual menu
2500 * but the Vim API doesn't seem to a support a request to get
2501 * the menu that we should display
2504 gui_mac_handle_contextual_menu(event
)
2508 * Clone PopUp to use menu
2509 * Create a object descriptor for the current selection
2510 * Call the procedure
2513 // Call to Handle Popup
2514 OSStatus status
= ContextualMenuSelect(CntxMenu
, event
->where
, false, kCMHelpItemNoHelp
, "", NULL
, &CntxType
, &CntxMenuID
, &CntxMenuItem
);
2516 if (status
!= noErr
)
2519 if (CntxType
== kCMMenuItemSelected
)
2521 /* Handle the menu CntxMenuID, CntxMenuItem */
2522 /* The submenu can be handle directly by gui_mac_handle_menu */
2523 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
2524 gui_mac_handle_menu((CntxMenuID
<< 16) + CntxMenuItem
);
2526 else if (CntxMenuID
== kCMShowHelpSelected
)
2528 /* Should come up with the help */
2535 * Handle menubar selection
2538 gui_mac_handle_menu(long menuChoice
)
2540 short menu
= HiWord(menuChoice
);
2541 short item
= LoWord(menuChoice
);
2542 vimmenu_T
*theVimMenu
= root_menu
;
2544 if (menu
== 256) /* TODO: use constant or gui.xyz */
2547 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
2551 theVimMenu
= gui_mac_get_vim_menu(menu
, item
, root_menu
);
2554 gui_menu_cb(theVimMenu
);
2560 * Dispatch the event to proper handler
2564 gui_mac_handle_event(EventRecord
*event
)
2568 /* Handle contextual menu right now (if needed) */
2569 if (IsShowContextualMenuClick(event
))
2572 gui_mac_handle_contextual_menu(event
);
2574 gui_mac_doMouseDownEvent(event
);
2579 /* Handle normal event */
2580 switch (event
->what
)
2582 #ifndef USE_CARBONKEYHANDLER
2585 gui_mac_doKeyEvent(event
);
2589 /* We don't care about when the key is released */
2593 gui_mac_doMouseDownEvent(event
);
2597 gui_mac_doMouseUpEvent(event
);
2601 gui_mac_doUpdateEvent(event
);
2605 /* We don't need special handling for disk insertion */
2609 gui_mac_doActivateEvent(event
);
2613 switch ((event
->message
>> 24) & 0xFF)
2615 case (0xFA): /* mouseMovedMessage */
2616 gui_mac_doMouseMovedEvent(event
);
2618 case (0x01): /* suspendResumeMessage */
2619 gui_mac_doSuspendEvent(event
);
2625 case (kHighLevelEvent
):
2626 /* Someone's talking to us, through AppleEvents */
2627 error
= AEProcessAppleEvent(event
); /* TODO: Error Handling */
2634 * ------------------------------------------------------------
2636 * ------------------------------------------------------------
2641 gui_mac_find_font(char_u
*font_name
)
2645 char_u pFontName
[256];
2646 Str255 systemFontname
;
2651 char_u
*fontNamePtr
;
2654 for (p
= font_name
; ((*p
!= 0) && (*p
!= ':')); p
++)
2661 STRCPY(&pFontName
[1], font_name
);
2662 pFontName
[0] = STRLEN(font_name
);
2665 /* Get the font name, minus the style suffix (:h, etc) */
2666 char_u fontName
[256];
2667 char_u
*styleStart
= vim_strchr(font_name
, ':');
2668 size_t fontNameLen
= styleStart
? styleStart
- font_name
: STRLEN(fontName
);
2669 vim_strncpy(fontName
, font_name
, fontNameLen
);
2672 FMFontStyle fontStyle
;
2675 if (ATSUFindFontFromName(&pFontName
[1], pFontName
[0], kFontFullName
,
2676 kFontMacintoshPlatform
, kFontNoScriptCode
, kFontNoLanguageCode
,
2679 if (FMGetFontFamilyInstanceFromFont(fontRef
, &font_id
, &fontStyle
) != noErr
)
2686 * Try again, this time replacing underscores in the font name
2687 * with spaces (:set guifont allows the two to be used
2688 * interchangeably; the Font Manager doesn't).
2690 int i
, changed
= FALSE
;
2692 for (i
= pFontName
[0]; i
> 0; --i
)
2694 if (pFontName
[i
] == '_')
2701 if (ATSUFindFontFromName(&pFontName
[1], pFontName
[0],
2702 kFontFullName
, kFontNoPlatformCode
, kFontNoScriptCode
,
2703 kFontNoLanguageCode
, &fontRef
) == noErr
)
2705 if (FMGetFontFamilyInstanceFromFont(fontRef
, &font_id
, &fontStyle
) != noErr
)
2711 /* name = C2Pascal_save(menu->dname); */
2712 fontNamePtr
= C2Pascal_save_and_remove_backslash(font_name
);
2714 GetFNum(fontNamePtr
, &font_id
);
2720 /* Oups, the system font was it the one the user want */
2722 if (FMGetFontFamilyName(systemFont
, systemFontname
) != noErr
)
2724 if (!EqualString(pFontName
, systemFontname
, false, false))
2730 /* Set the values found after ':' */
2736 size
= points_to_pixels(p
, &p
, TRUE
);
2739 * TODO: Maybe accept width and styles
2748 size
= 1; /* Avoid having a size of 0 with system font */
2750 font
= (size
<< 16) + ((long) font_id
& 0xFFFF);
2756 * ------------------------------------------------------------
2757 * GUI_MCH functionality
2758 * ------------------------------------------------------------
2762 * Parse the GUI related command-line arguments. Any arguments used are
2763 * deleted from argv, and *argc is decremented accordingly. This is called
2764 * when vim is started, whether or not the GUI has been started.
2767 gui_mch_prepare(int *argc
, char **argv
)
2769 /* TODO: Move most of this stuff toward gui_mch_init */
2772 # ifndef USE_FIND_BUNDLE_PATH
2777 ProcessSerialNumber psn
;
2785 RegisterAppearanceClient();
2788 (void) InstallAEHandlers();
2791 pomme
= NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
2793 AppendMenu(pomme
, "\pAbout VIM");
2795 InsertMenu(pomme
, 0);
2800 #ifndef USE_OFFSETED_WINDOW
2801 SetRect(&windRect
, 10, 48, 10+80*7 + 16, 48+24*11);
2803 SetRect(&windRect
, 300, 40, 300+80*7 + 16, 40+24*11);
2807 CreateNewWindow(kDocumentWindowClass
,
2808 kWindowResizableAttribute
| kWindowCollapseBoxAttribute
,
2809 &windRect
, &gui
.VimWindow
);
2810 SetPortWindowPort(gui
.VimWindow
);
2813 gui
.char_height
= 11;
2814 gui
.char_ascent
= 6;
2817 gui
.in_focus
= TRUE
; /* For the moment -> syn. of front application */
2819 gScrollAction
= NewControlActionUPP(gui_mac_scroll_action
);
2820 gScrollDrag
= NewControlActionUPP(gui_mac_drag_thumb
);
2822 dragRectEnbl
= FALSE
;
2824 dragRectControl
= kCreateEmpty
;
2825 cursorRgn
= NewRgn();
2828 # ifndef USE_FIND_BUNDLE_PATH
2829 HGetVol(volName
, &applVRefNum
, &applDirID
);
2830 /* TN2015: mention a possible bad VRefNum */
2831 FSMakeFSSpec(applVRefNum
, applDirID
, "\p", &applDir
);
2833 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2835 * This technic remove the ../Contents/MacOS/etc part
2837 (void)GetCurrentProcess(&psn
);
2838 /* if (err != noErr) return err; */
2840 (void)GetProcessBundleLocation(&psn
, &applFSRef
);
2841 /* if (err != noErr) return err; */
2843 (void)FSGetCatalogInfo(&applFSRef
, kFSCatInfoNone
, NULL
, NULL
, &applDir
, NULL
);
2845 /* This technic return NIL when we disallow_gui */
2847 exe_name
= FullPathFromFSSpec_save(applDir
);
2851 #ifndef ALWAYS_USE_GUI
2853 * Check if the GUI can be started. Called before gvimrc is sourced.
2854 * Return OK or FAIL.
2857 gui_mch_init_check(void)
2859 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2860 * using the >console
2862 if (disallow_gui
) /* see main.c for reason to disallow */
2869 receiveHandler(WindowRef theWindow
, void *handlerRefCon
, DragRef theDrag
)
2873 char_u
**fnames
= NULL
;
2877 /* Get drop position, modifiers and count of items */
2880 SInt16 mouseUpModifiers
;
2883 GetDragMouse(theDrag
, &point
, NULL
);
2884 GlobalToLocal(&point
);
2887 GetDragModifiers(theDrag
, NULL
, NULL
, &mouseUpModifiers
);
2888 modifiers
= EventModifiers2VimMouseModifiers(mouseUpModifiers
);
2889 CountDragItems(theDrag
, &countItem
);
2893 fnames
= (char_u
**)alloc(count
* sizeof(char_u
*));
2895 return dragNotAcceptedErr
;
2897 /* Get file names dropped */
2898 for (i
= j
= 0; i
< count
; ++i
)
2903 FlavorType type
= flavorTypeHFS
;
2904 HFSFlavor hfsFlavor
;
2907 GetDragItemReferenceNumber(theDrag
, i
+ 1, &item
);
2908 err
= GetFlavorDataSize(theDrag
, item
, type
, &size
);
2909 if (err
!= noErr
|| size
> sizeof(hfsFlavor
))
2911 err
= GetFlavorData(theDrag
, item
, type
, &hfsFlavor
, &size
, 0);
2914 fnames
[j
++] = FullPathFromFSSpec_save(hfsFlavor
.fileSpec
);
2918 gui_handle_drop(x
, y
, modifiers
, fnames
, count
);
2920 /* Fake mouse event to wake from stall */
2921 PostEvent(mouseUp
, 0);
2927 * Initialise the GUI. Create all the windows, set up all the call-backs
2933 /* TODO: Move most of this stuff toward gui_mch_init */
2936 EventTypeSpec eventTypeSpec
;
2937 EventHandlerRef mouseWheelHandlerRef
;
2938 #ifdef USE_CARBONKEYHANDLER
2939 EventHandlerRef keyEventHandlerRef
;
2941 ControlRef rootControl
;
2943 if (Gestalt(gestaltSystemVersion
, &gMacSystemVersion
) != noErr
)
2944 gMacSystemVersion
= 0x1000; /* TODO: Default to minimum sensible value */
2949 RegisterAppearanceClient();
2952 (void) InstallAEHandlers();
2955 pomme
= NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
2957 AppendMenu(pomme
, "\pAbout VIM");
2959 InsertMenu(pomme
, 0);
2964 #ifndef USE_OFFSETED_WINDOW
2965 SetRect(&windRect
, 10, 48, 10+80*7 + 16, 48+24*11);
2967 SetRect(&windRect
, 300, 40, 300+80*7 + 16, 40+24*11);
2970 gui
.VimWindow
= NewCWindow(nil
, &windRect
, "\pgVim on Macintosh", true,
2972 (WindowPtr
)-1L, true, 0);
2973 CreateRootControl(gui
.VimWindow
, &rootControl
);
2974 InstallReceiveHandler((DragReceiveHandlerUPP
)receiveHandler
,
2975 gui
.VimWindow
, NULL
);
2976 SetPortWindowPort(gui
.VimWindow
);
2979 gui
.char_height
= 11;
2980 gui
.char_ascent
= 6;
2983 gui
.in_focus
= TRUE
; /* For the moment -> syn. of front application */
2985 gScrollAction
= NewControlActionUPP(gui_mac_scroll_action
);
2986 gScrollDrag
= NewControlActionUPP(gui_mac_drag_thumb
);
2988 /* Install Carbon event callbacks. */
2989 (void)InstallFontPanelHandler();
2991 dragRectEnbl
= FALSE
;
2993 dragRectControl
= kCreateEmpty
;
2994 cursorRgn
= NewRgn();
2996 /* Display any pending error messages */
2999 /* Get background/foreground colors from system */
3000 /* TODO: do the appropriate call to get real defaults */
3001 gui
.norm_pixel
= 0x00000000;
3002 gui
.back_pixel
= 0x00FFFFFF;
3004 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3006 set_normal_colors();
3009 * Check that none of the colors are the same as the background color.
3010 * Then store the current values as the defaults.
3013 gui
.def_norm_pixel
= gui
.norm_pixel
;
3014 gui
.def_back_pixel
= gui
.back_pixel
;
3016 /* Get the colors for the highlight groups (gui_check_colors() might have
3018 highlight_gui_started();
3021 * Setting the gui constants
3024 gui
.menu_height
= 0;
3026 gui
.scrollbar_height
= gui
.scrollbar_width
= 15; /* cheat 1 overlap */
3027 gui
.border_offset
= gui
.border_width
= 2;
3029 /* If Quartz-style text anti aliasing is available (see
3030 gui_mch_draw_string() below), enable it for all font sizes. */
3031 vim_setenv((char_u
*)"QDTEXT_MINSIZE", (char_u
*)"1");
3033 eventTypeSpec
.eventClass
= kEventClassMouse
;
3034 eventTypeSpec
.eventKind
= kEventMouseWheelMoved
;
3035 mouseWheelHandlerUPP
= NewEventHandlerUPP(gui_mac_mouse_wheel
);
3036 if (noErr
!= InstallApplicationEventHandler(mouseWheelHandlerUPP
, 1,
3037 &eventTypeSpec
, NULL
, &mouseWheelHandlerRef
))
3039 mouseWheelHandlerRef
= NULL
;
3040 DisposeEventHandlerUPP(mouseWheelHandlerUPP
);
3041 mouseWheelHandlerUPP
= NULL
;
3044 #ifdef USE_CARBONKEYHANDLER
3045 eventTypeSpec
.eventClass
= kEventClassTextInput
;
3046 eventTypeSpec
.eventKind
= kEventUnicodeForKeyEvent
;
3047 keyEventHandlerUPP
= NewEventHandlerUPP(gui_mac_doKeyEventCarbon
);
3048 if (noErr
!= InstallApplicationEventHandler(keyEventHandlerUPP
, 1,
3049 &eventTypeSpec
, NULL
, &keyEventHandlerRef
))
3051 keyEventHandlerRef
= NULL
;
3052 DisposeEventHandlerUPP(keyEventHandlerUPP
);
3053 keyEventHandlerUPP
= NULL
;
3059 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3063 #ifdef FEAT_GUI_TABLINE
3065 * Create the tabline
3067 initialise_tabline();
3070 /* TODO: Load bitmap if using TOOLBAR */
3075 * Called when the foreground or background color has been changed.
3078 gui_mch_new_colors(void)
3081 * This proc is called when Normal is set to a value
3082 * so what msut be done? I don't know
3087 * Open the GUI window which was created by a call to gui_mch_init().
3092 ShowWindow(gui
.VimWindow
);
3094 if (gui_win_x
!= -1 && gui_win_y
!= -1)
3095 gui_mch_set_winpos(gui_win_x
, gui_win_y
);
3098 * Make the GUI the foreground process (in case it was launched
3099 * from the Terminal or via :gui).
3102 ProcessSerialNumber psn
;
3103 if (GetCurrentProcess(&psn
) == noErr
)
3104 SetFrontProcess(&psn
);
3111 gui_mch_exit(int rc
)
3113 /* TODO: find out all what is missing here? */
3114 DisposeRgn(cursorRgn
);
3116 #ifdef USE_CARBONKEYHANDLER
3117 if (keyEventHandlerUPP
)
3118 DisposeEventHandlerUPP(keyEventHandlerUPP
);
3121 if (mouseWheelHandlerUPP
!= NULL
)
3122 DisposeEventHandlerUPP(mouseWheelHandlerUPP
);
3124 #ifdef USE_ATSUI_DRAWING
3125 if (p_macatsui
&& gFontStyle
)
3126 ATSUDisposeStyle(gFontStyle
);
3129 /* Exit to shell? */
3134 * Get the position of the top left corner of the window.
3137 gui_mch_get_winpos(int *x
, int *y
)
3143 /* Carbon >= 1.0.2, MacOS >= 8.5 */
3144 status
= GetWindowBounds(gui
.VimWindow
, kWindowStructureRgn
, &bounds
);
3146 if (status
!= noErr
)
3155 * Set the position of the top left corner of the window to the given
3159 gui_mch_set_winpos(int x
, int y
)
3161 /* TODO: Should make sure the window is move within range
3162 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3164 MoveWindowStructure(gui
.VimWindow
, x
, y
);
3168 gui_mch_set_shellsize(
3180 if (gui
.which_scrollbars
[SBAR_LEFT
])
3182 VimPort
= GetWindowPort(gui
.VimWindow
);
3183 GetPortBounds(VimPort
, &VimBound
);
3184 VimBound
.left
= -gui
.scrollbar_width
; /* + 1;*/
3185 SetPortBounds(VimPort
, &VimBound
);
3186 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
3190 VimPort
= GetWindowPort(gui
.VimWindow
);
3191 GetPortBounds(VimPort
, &VimBound
);
3193 SetPortBounds(VimPort
, &VimBound
);
3196 SizeWindow(gui
.VimWindow
, width
, height
, TRUE
);
3198 gui_resize_shell(width
, height
);
3202 * Get the screen dimensions.
3203 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3204 * Is there no way to find out how wide the borders really are?
3205 * TODO: Add live update of those value on suspend/resume.
3208 gui_mch_get_screen_dimensions(int *screen_w
, int *screen_h
)
3210 GDHandle dominantDevice
= GetMainDevice();
3211 Rect screenRect
= (**dominantDevice
).gdRect
;
3213 *screen_w
= screenRect
.right
- 10;
3214 *screen_h
= screenRect
.bottom
- 40;
3219 * Open the Font Panel and wait for the user to select a font and
3220 * close the panel. Then fill the buffer pointed to by font_name with
3221 * the name and size of the selected font and return the font's handle,
3222 * or NOFONT in case of an error.
3225 gui_mac_select_font(char_u
*font_name
)
3227 GuiFont selected_font
= NOFONT
;
3229 FontSelectionQDStyle curr_font
;
3231 /* Initialize the Font Panel with the current font. */
3232 curr_font
.instance
.fontFamily
= gui
.norm_font
& 0xFFFF;
3233 curr_font
.size
= (gui
.norm_font
>> 16);
3234 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3235 curr_font
.instance
.fontStyle
= 0;
3236 curr_font
.hasColor
= false;
3237 curr_font
.version
= 0; /* version number of the style structure */
3238 status
= SetFontInfoForSelection(kFontSelectionQDType
,
3239 /*numStyles=*/1, &curr_font
, /*eventTarget=*/NULL
);
3241 gFontPanelInfo
.family
= curr_font
.instance
.fontFamily
;
3242 gFontPanelInfo
.style
= curr_font
.instance
.fontStyle
;
3243 gFontPanelInfo
.size
= curr_font
.size
;
3245 /* Pop up the Font Panel. */
3246 status
= FPShowHideFontPanel();
3247 if (status
== noErr
)
3250 * The Font Panel is modeless. We really need it to be modal,
3251 * so we spin in an event loop until the panel is closed.
3253 gFontPanelInfo
.isPanelVisible
= true;
3254 while (gFontPanelInfo
.isPanelVisible
)
3257 WaitNextEvent(everyEvent
, &e
, /*sleep=*/20, /*mouseRgn=*/NULL
);
3260 GetFontPanelSelection(font_name
);
3261 selected_font
= gui_mac_find_font(font_name
);
3263 return selected_font
;
3268 * Initialise vim to use the font with the given name. Return FAIL if the font
3269 * could not be loaded, OK otherwise.
3272 gui_mch_init_font(char_u
*font_name
, int fontset
)
3274 /* TODO: Add support for bold italic underline proportional etc... */
3275 Str255 suggestedFont
= "\pMonaco";
3276 int suggestedSize
= 10;
3280 char_u used_font_name
[512];
3282 #ifdef USE_ATSUI_DRAWING
3283 if (p_macatsui
&& gFontStyle
== NULL
)
3285 if (ATSUCreateStyle(&gFontStyle
) != noErr
)
3290 if (font_name
== NULL
)
3292 /* First try to get the suggested font */
3293 GetFNum(suggestedFont
, &font_id
);
3297 /* Then pickup the standard application font */
3298 font_id
= GetAppFont();
3299 STRCPY(used_font_name
, "default");
3302 STRCPY(used_font_name
, "Monaco");
3303 font
= (suggestedSize
<< 16) + ((long) font_id
& 0xFFFF);
3305 else if (STRCMP(font_name
, "*") == 0)
3307 char_u
*new_p_guifont
;
3309 font
= gui_mac_select_font(used_font_name
);
3313 /* Set guifont to the name of the selected font. */
3314 new_p_guifont
= alloc(STRLEN(used_font_name
) + 1);
3315 if (new_p_guifont
!= NULL
)
3317 STRCPY(new_p_guifont
, used_font_name
);
3318 vim_free(p_guifont
);
3319 p_guifont
= new_p_guifont
;
3320 /* Replace spaces in the font name with underscores. */
3321 for ( ; *new_p_guifont
; ++new_p_guifont
)
3323 if (*new_p_guifont
== ' ')
3324 *new_p_guifont
= '_';
3330 font
= gui_mac_find_font(font_name
);
3331 vim_strncpy(used_font_name
, font_name
, sizeof(used_font_name
) - 1);
3337 gui
.norm_font
= font
;
3339 hl_set_font_name(used_font_name
);
3341 TextSize(font
>> 16);
3342 TextFont(font
& 0xFFFF);
3344 GetFontInfo(&font_info
);
3346 gui
.char_ascent
= font_info
.ascent
;
3347 gui
.char_width
= CharWidth('_');
3348 gui
.char_height
= font_info
.ascent
+ font_info
.descent
+ p_linespace
;
3350 #ifdef USE_ATSUI_DRAWING
3353 ATSStyleRenderingOptions fontOptions
;
3355 if (p_macatsui
&& gFontStyle
)
3357 fontID
= font
& 0xFFFF;
3358 fontSize
= Long2Fix(font
>> 16);
3360 /* No antialiasing by default (do not attempt to touch antialising
3361 * options on pre-Jaguar) */
3363 (gMacSystemVersion
>= 0x1020) ?
3364 kATSStyleNoAntiAliasing
:
3367 ATSUAttributeTag attribTags
[] =
3369 kATSUFontTag
, kATSUSizeTag
, kATSUStyleRenderingOptionsTag
,
3370 kATSUMaxATSUITagValue
+1
3372 ByteCount attribSizes
[] =
3374 sizeof(ATSUFontID
), sizeof(Fixed
),
3375 sizeof(ATSStyleRenderingOptions
), sizeof font
3377 ATSUAttributeValuePtr attribValues
[] =
3379 &fontID
, &fontSize
, &fontOptions
, &font
3382 /* Convert font id to ATSUFontID */
3383 if (FMGetFontFromFontFamilyInstance(fontID
, 0, &fontID
, NULL
) == noErr
)
3385 if (ATSUSetAttributes(gFontStyle
,
3386 (sizeof attribTags
)/sizeof(ATSUAttributeTag
),
3387 attribTags
, attribSizes
, attribValues
) != noErr
)
3389 ATSUDisposeStyle(gFontStyle
);
3400 * Adjust gui.char_height (after 'linespace' was changed).
3403 gui_mch_adjust_charheight(void)
3407 GetFontInfo(&font_info
);
3408 gui
.char_height
= font_info
.ascent
+ font_info
.descent
+ p_linespace
;
3409 gui
.char_ascent
= font_info
.ascent
+ p_linespace
/ 2;
3414 * Get a font structure for highlighting.
3417 gui_mch_get_font(char_u
*name
, int giveErrorIfMissing
)
3421 font
= gui_mac_find_font(name
);
3425 if (giveErrorIfMissing
)
3426 EMSG2(_(e_font
), name
);
3430 * TODO : Accept only monospace
3436 #if defined(FEAT_EVAL) || defined(PROTO)
3438 * Return the name of font "font" in allocated memory.
3439 * Don't know how to get the actual name, thus use the provided name.
3442 gui_mch_get_fontname(GuiFont font
, char_u
*name
)
3446 return vim_strsave(name
);
3451 * Set the current text font.
3454 gui_mch_set_font(GuiFont font
)
3456 #ifdef USE_ATSUI_DRAWING
3458 ByteCount actualFontByteCount
;
3461 ATSStyleRenderingOptions fontOptions
;
3463 if (p_macatsui
&& gFontStyle
)
3465 /* Avoid setting same font again */
3466 if (ATSUGetAttribute(gFontStyle
, kATSUMaxATSUITagValue
+1, sizeof font
,
3467 &currFont
, &actualFontByteCount
) == noErr
&&
3468 actualFontByteCount
== (sizeof font
))
3470 if (currFont
== font
)
3474 fontID
= font
& 0xFFFF;
3475 fontSize
= Long2Fix(font
>> 16);
3476 /* Respect p_antialias setting only for wide font.
3477 * The reason for doing this at the moment is a bit complicated,
3478 * but it's mainly because a) latin (non-wide) aliased fonts
3479 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3480 * b) wide multibyte input does not suffer from that problem. */
3482 (p_antialias && (font == gui.wide_font)) ?
3483 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
3485 /*fontOptions = kATSStyleAntiAliasing;*/
3487 ATSUAttributeTag attribTags
[] =
3489 kATSUFontTag
, kATSUSizeTag
, kATSUStyleRenderingOptionsTag
,
3490 kATSUMaxATSUITagValue
+1
3492 ByteCount attribSizes
[] =
3494 sizeof(ATSUFontID
), sizeof(Fixed
),
3495 sizeof(ATSStyleRenderingOptions
), sizeof font
3497 ATSUAttributeValuePtr attribValues
[] =
3499 &fontID
, &fontSize
, &fontOptions
, &font
3502 if (FMGetFontFromFontFamilyInstance(fontID
, 0, &fontID
, NULL
) == noErr
)
3504 if (ATSUSetAttributes(gFontStyle
,
3505 (sizeof attribTags
)/sizeof(ATSUAttributeTag
),
3506 attribTags
, attribSizes
, attribValues
) != noErr
)
3509 fprintf(stderr
, "couldn't set font style\n");
3511 ATSUDisposeStyle(gFontStyle
);
3518 if (p_macatsui
&& !gIsFontFallbackSet
)
3520 /* Setup automatic font substitution. The user's guifontwide
3521 * is tried first, then the system tries other fonts. */
3523 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3524 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3525 ATSUCreateFontFallbacks(&gFontFallbacks);
3526 ATSUSetObjFontFallbacks(gFontFallbacks, );
3530 ATSUFontID fallbackFonts
;
3531 gIsFontFallbackSet
= TRUE
;
3533 if (FMGetFontFromFontFamilyInstance(
3534 (gui
.wide_font
& 0xFFFF),
3539 ATSUSetFontFallbacks((sizeof fallbackFonts
)/sizeof(ATSUFontID
), &fallbackFonts
, kATSUSequentialFallbacksPreferred
);
3542 ATSUAttributeValuePtr fallbackValues[] = { };
3547 TextSize(font
>> 16);
3548 TextFont(font
& 0xFFFF);
3552 * If a font is not going to be used, free its structure.
3555 gui_mch_free_font(font
)
3559 * Free font when "font" is not 0.
3560 * Nothing to do in the current implementation, since
3561 * nothing is allocated for each font used.
3571 if (c
>= 'a' && c
<= 'f')
3572 return c
- 'a' + 10;
3577 * Return the Pixel value (color) for the given color name. This routine was
3578 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3579 * Programmer's Guide.
3580 * Return INVALCOLOR when failed.
3583 gui_mch_get_color(char_u
*name
)
3585 /* TODO: Add support for the new named color of MacOS 8
3588 // guicolor_T color = 0;
3590 typedef struct guicolor_tTable
3597 * The comment at the end of each line is the source
3598 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3600 static guicolor_tTable table
[] =
3602 {"Black", RGB(0x00, 0x00, 0x00)},
3603 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3604 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3605 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3606 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3607 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3608 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3609 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3610 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3611 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3612 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3613 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3614 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3615 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3616 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3617 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3618 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3619 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3620 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3621 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3622 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3623 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3624 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3625 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3626 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3627 {"white", RGB(0xFF, 0xFF, 0xFF)},
3628 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3629 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3630 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3631 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3632 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3633 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3634 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3635 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3636 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3637 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3638 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3639 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3640 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3641 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3642 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3643 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3644 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3645 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
3646 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
3647 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3648 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3649 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3650 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3651 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3657 if (name
[0] == '#' && strlen((char *) name
) == 7)
3659 /* Name is in "#rrggbb" format */
3660 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
3661 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
3662 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
3663 if (r
< 0 || g
< 0 || b
< 0)
3665 return RGB(r
, g
, b
);
3669 if (STRICMP(name
, "hilite") == 0)
3671 LMGetHiliteRGB(&MacColor
);
3672 return (RGB(MacColor
.red
>> 8, MacColor
.green
>> 8, MacColor
.blue
>> 8));
3674 /* Check if the name is one of the colors we know */
3675 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
3676 if (STRICMP(name
, table
[i
].name
) == 0)
3677 return table
[i
].color
;
3681 * Last attempt. Look in the file "$VIM/rgb.txt".
3684 #define LINE_LEN 100
3686 char line
[LINE_LEN
];
3689 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
3693 fd
= fopen((char *)fname
, "rt");
3704 fgets(line
, LINE_LEN
, fd
);
3707 if (len
<= 1 || line
[len
-1] != '\n')
3712 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
3718 if (STRICMP(color
, name
) == 0)
3721 return (guicolor_T
) RGB(r
, g
, b
);
3731 * Set the current text foreground color.
3734 gui_mch_set_fg_color(guicolor_T color
)
3738 TheColor
.red
= Red(color
) * 0x0101;
3739 TheColor
.green
= Green(color
) * 0x0101;
3740 TheColor
.blue
= Blue(color
) * 0x0101;
3742 RGBForeColor(&TheColor
);
3746 * Set the current text background color.
3749 gui_mch_set_bg_color(guicolor_T color
)
3753 TheColor
.red
= Red(color
) * 0x0101;
3754 TheColor
.green
= Green(color
) * 0x0101;
3755 TheColor
.blue
= Blue(color
) * 0x0101;
3757 RGBBackColor(&TheColor
);
3760 RGBColor specialColor
;
3763 * Set the current text special color.
3766 gui_mch_set_sp_color(guicolor_T color
)
3768 specialColor
.red
= Red(color
) * 0x0101;
3769 specialColor
.green
= Green(color
) * 0x0101;
3770 specialColor
.blue
= Blue(color
) * 0x0101;
3774 * Draw undercurl at the bottom of the character cell.
3777 draw_undercurl(int flags
, int row
, int col
, int cells
)
3781 const static int val
[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3782 int y
= FILL_Y(row
+ 1) - 1;
3784 RGBForeColor(&specialColor
);
3786 offset
= val
[FILL_X(col
) % 8];
3787 MoveTo(FILL_X(col
), y
- offset
);
3789 for (x
= FILL_X(col
); x
< FILL_X(col
+ cells
); ++x
)
3791 offset
= val
[x
% 8];
3792 LineTo(x
, y
- offset
);
3798 draw_string_QD(int row
, int col
, char_u
*s
, int len
, int flags
)
3801 char_u
*tofree
= NULL
;
3803 if (output_conv
.vc_type
!= CONV_NONE
)
3805 tofree
= string_convert(&output_conv
, s
, &len
);
3812 * On OS X, try using Quartz-style text antialiasing.
3814 if (gMacSystemVersion
>= 0x1020)
3816 /* Quartz antialiasing is available only in OS 10.2 and later. */
3817 UInt32 qd_flags
= (p_antialias
?
3818 kQDUseCGTextRendering
| kQDUseCGTextMetrics
: 0);
3819 QDSwapTextFlags(qd_flags
);
3823 * When antialiasing we're using srcOr mode, we have to clear the block
3824 * before drawing the text.
3825 * Also needed when 'linespace' is non-zero to remove the cursor and
3827 * But not when drawing transparently.
3828 * The following is like calling gui_mch_clear_block(row, col, row, col +
3829 * len - 1), but without setting the bg color to gui.back_pixel.
3831 if (((gMacSystemVersion
>= 0x1020 && p_antialias
) || p_linespace
!= 0)
3832 && !(flags
& DRAW_TRANSP
))
3836 rc
.left
= FILL_X(col
);
3837 rc
.top
= FILL_Y(row
);
3839 /* Multibyte computation taken from gui_w32.c */
3845 /* Compute the length in display cells. */
3846 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(s
[n
]))
3847 cell_len
+= (*mb_ptr2cells
)(s
+ n
);
3848 rc
.right
= FILL_X(col
+ cell_len
);
3852 rc
.right
= FILL_X(col
+ len
) + (col
+ len
== Columns
);
3853 rc
.bottom
= FILL_Y(row
+ 1);
3857 if (gMacSystemVersion
>= 0x1020 && p_antialias
)
3859 StyleParameter face
;
3862 if (flags
& DRAW_BOLD
)
3864 if (flags
& DRAW_UNDERL
)
3868 /* Quartz antialiasing works only in srcOr transfer mode. */
3871 MoveTo(TEXT_X(col
), TEXT_Y(row
));
3872 DrawText((char*)s
, 0, len
);
3876 /* Use old-style, non-antialiased QuickDraw text rendering. */
3880 /* SelectFont(hdc, gui.currFont); */
3882 if (flags
& DRAW_TRANSP
)
3887 MoveTo(TEXT_X(col
), TEXT_Y(row
));
3888 DrawText((char *)s
, 0, len
);
3890 if (flags
& DRAW_BOLD
)
3893 MoveTo(TEXT_X(col
) + 1, TEXT_Y(row
));
3894 DrawText((char *)s
, 0, len
);
3897 if (flags
& DRAW_UNDERL
)
3899 MoveTo(FILL_X(col
), FILL_Y(row
+ 1) - 1);
3900 LineTo(FILL_X(col
+ len
) - 1, FILL_Y(row
+ 1) - 1);
3904 if (flags
& DRAW_UNDERC
)
3905 draw_undercurl(flags
, row
, col
, len
);
3912 #ifdef USE_ATSUI_DRAWING
3915 draw_string_ATSUI(int row
, int col
, char_u
*s
, int len
, int flags
)
3917 /* ATSUI requires utf-16 strings */
3918 UniCharCount utf16_len
;
3919 UniChar
*tofree
= mac_enc_to_utf16(s
, len
, (size_t *)&utf16_len
);
3920 utf16_len
/= sizeof(UniChar
);
3922 /* - ATSUI automatically antialiases text (Someone)
3923 * - for some reason it does not work... (Jussi) */
3926 * When antialiasing we're using srcOr mode, we have to clear the block
3927 * before drawing the text.
3928 * Also needed when 'linespace' is non-zero to remove the cursor and
3930 * But not when drawing transparently.
3931 * The following is like calling gui_mch_clear_block(row, col, row, col +
3932 * len - 1), but without setting the bg color to gui.back_pixel.
3934 if ((flags
& DRAW_TRANSP
) == 0)
3938 rc
.left
= FILL_X(col
);
3939 rc
.top
= FILL_Y(row
);
3940 /* Multibyte computation taken from gui_w32.c */
3946 /* Compute the length in display cells. */
3947 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(s
[n
]))
3948 cell_len
+= (*mb_ptr2cells
)(s
+ n
);
3949 rc
.right
= FILL_X(col
+ cell_len
);
3952 rc
.right
= FILL_X(col
+ len
) + (col
+ len
== Columns
);
3954 rc
.bottom
= FILL_Y(row
+ 1);
3959 /* Use old-style, non-antialiased QuickDraw text rendering. */
3963 /* SelectFont(hdc, gui.currFont); */
3965 if (flags
& DRAW_TRANSP
)
3970 MoveTo(TEXT_X(col
), TEXT_Y(row
));
3971 ATSUTextLayout textLayout
;
3973 if (ATSUCreateTextLayoutWithTextPtr(tofree
,
3974 kATSUFromTextBeginning
, kATSUToTextEnd
,
3976 (gFontStyle
? 1 : 0), &utf16_len
,
3977 (gFontStyle
? &gFontStyle
: NULL
),
3978 &textLayout
) == noErr
)
3980 ATSUSetTransientFontMatching(textLayout
, TRUE
);
3982 ATSUDrawText(textLayout
,
3983 kATSUFromTextBeginning
, kATSUToTextEnd
,
3984 kATSUUseGrafPortPenLoc
, kATSUUseGrafPortPenLoc
);
3986 ATSUDisposeTextLayout(textLayout
);
3990 if (flags
& DRAW_UNDERC
)
3991 draw_undercurl(flags
, row
, col
, len
);
3998 gui_mch_draw_string(int row
, int col
, char_u
*s
, int len
, int flags
)
4000 #if defined(USE_ATSUI_DRAWING)
4002 draw_string_ATSUI(row
, col
, s
, len
, flags
);
4005 draw_string_QD(row
, col
, s
, len
, flags
);
4009 * Return OK if the key with the termcap name "name" is supported.
4012 gui_mch_haskey(char_u
*name
)
4016 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; i
++)
4017 if (name
[0] == special_keys
[i
].vim_code0
&&
4018 name
[1] == special_keys
[i
].vim_code1
)
4026 SysBeep(1); /* Should this be 0? (????) */
4030 gui_mch_flash(int msec
)
4032 /* Do a visual beep by reversing the foreground and background colors */
4036 * Note: InvertRect() excludes right and bottom of rectangle.
4040 rc
.right
= gui
.num_cols
* gui
.char_width
;
4041 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
4044 ui_delay((long)msec
, TRUE
); /* wait for some msec */
4050 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4053 gui_mch_invert_rectangle(int r
, int c
, int nr
, int nc
)
4058 * Note: InvertRect() excludes right and bottom of rectangle.
4060 rc
.left
= FILL_X(c
);
4062 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
4063 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
4068 * Iconify the GUI window.
4071 gui_mch_iconify(void)
4073 /* TODO: find out what could replace iconify
4075 * -hide application?
4079 #if defined(FEAT_EVAL) || defined(PROTO)
4081 * Bring the Vim window to the foreground.
4084 gui_mch_set_foreground(void)
4091 * Draw a cursor without focus.
4094 gui_mch_draw_hollow_cursor(guicolor_T color
)
4099 * Note: FrameRect() excludes right and bottom of rectangle.
4101 rc
.left
= FILL_X(gui
.col
);
4102 rc
.top
= FILL_Y(gui
.row
);
4103 rc
.right
= rc
.left
+ gui
.char_width
;
4105 if (mb_lefthalve(gui
.row
, gui
.col
))
4106 rc
.right
+= gui
.char_width
;
4108 rc
.bottom
= rc
.top
+ gui
.char_height
;
4110 gui_mch_set_fg_color(color
);
4116 * Draw part of a cursor, only w pixels wide, and h pixels high.
4119 gui_mch_draw_part_cursor(int w
, int h
, guicolor_T color
)
4123 #ifdef FEAT_RIGHTLEFT
4124 /* vertical line should be on the right of current point */
4125 if (CURSOR_BAR_RIGHT
)
4126 rc
.left
= FILL_X(gui
.col
+ 1) - w
;
4129 rc
.left
= FILL_X(gui
.col
);
4130 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
4131 rc
.right
= rc
.left
+ w
;
4132 rc
.bottom
= rc
.top
+ h
;
4134 gui_mch_set_fg_color(color
);
4143 * Catch up with any queued X events. This may put keyboard input into the
4144 * input buffer, call resize call-backs, trigger timers etc. If there is
4145 * nothing in the X event queue (& no timers pending), then we return
4149 gui_mch_update(void)
4151 /* TODO: find what to do
4152 * maybe call gui_mch_wait_for_chars (0)
4153 * more like look at EventQueue then
4154 * call heart of gui_mch_wait_for_chars;
4157 * gui_mac_handle_event(&event);
4159 EventRecord theEvent
;
4161 if (EventAvail(everyEvent
, &theEvent
))
4162 if (theEvent
.what
!= nullEvent
)
4163 gui_mch_wait_for_chars(0);
4167 * Simple wrapper to neglect more easily the time
4168 * spent inside WaitNextEvent while profiling.
4173 WaitNextEventWrp(EventMask eventMask
, EventRecord
*theEvent
, UInt32 sleep
, RgnHandle mouseRgn
)
4175 if (((long) sleep
) < -1)
4177 return WaitNextEvent(eventMask
, theEvent
, sleep
, mouseRgn
);
4181 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4182 * from the keyboard.
4183 * wtime == -1 Wait forever.
4184 * wtime == 0 This should never happen.
4185 * wtime > 0 Wait wtime milliseconds for a character.
4186 * Returns OK if a character was found to be available within the given time,
4187 * or FAIL otherwise.
4190 gui_mch_wait_for_chars(int wtime
)
4192 EventMask mask
= (everyEvent
);
4198 /* If we are providing life feedback with the scrollbar,
4199 * we don't want to try to wait for an event, or else
4200 * there won't be any life feedback.
4202 if (dragged_sb
!= NULL
)
4204 /* TODO: Check if FAIL is the proper return code */
4206 entryTick
= TickCount();
4208 allow_scrollbar
= TRUE
;
4212 /* if (dragRectControl == kCreateEmpty)
4215 dragRectControl = kNothing;
4217 else*/ if (dragRectControl
== kCreateRect
)
4219 dragRgn
= cursorRgn
;
4220 RectRgn(dragRgn
, &dragRect
);
4221 dragRectControl
= kNothing
;
4224 * Don't use gui_mch_update() because then we will spin-lock until a
4225 * char arrives, instead we use WaitNextEventWrp() to hang until an
4226 * event arrives. No need to check for input_buf_full because we are
4227 * returning as soon as it contains a single char.
4229 /* TODO: reduce wtime accordinly??? */
4231 sleeppyTick
= 60*wtime
/1000;
4233 sleeppyTick
= 32767;
4234 if (WaitNextEventWrp(mask
, &event
, sleeppyTick
, dragRgn
))
4236 gui_mac_handle_event(&event
);
4237 if (input_available())
4239 allow_scrollbar
= FALSE
;
4243 currentTick
= TickCount();
4245 while ((wtime
== -1) || ((currentTick
- entryTick
) < 60*wtime
/1000));
4247 allow_scrollbar
= FALSE
;
4255 /* Flush any output to the screen */
4259 /* TODO: Is anything needed here? */
4263 * Clear a rectangular region of the screen from text pos (row1, col1) to
4264 * (row2, col2) inclusive.
4267 gui_mch_clear_block(int row1
, int col1
, int row2
, int col2
)
4272 * Clear one extra pixel at the far right, for when bold characters have
4273 * spilled over to the next column.
4275 rc
.left
= FILL_X(col1
);
4276 rc
.top
= FILL_Y(row1
);
4277 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
4278 rc
.bottom
= FILL_Y(row2
+ 1);
4280 gui_mch_set_bg_color(gui
.back_pixel
);
4285 * Clear the whole text window.
4288 gui_mch_clear_all(void)
4294 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
4295 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
4297 gui_mch_set_bg_color(gui
.back_pixel
);
4299 /* gui_mch_set_fg_color(gui.norm_pixel);
4305 * Delete the given number of lines from the given row, scrolling up any
4306 * text further down within the scroll region.
4309 gui_mch_delete_lines(int row
, int num_lines
)
4313 /* changed without checking! */
4314 rc
.left
= FILL_X(gui
.scroll_region_left
);
4315 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
4316 rc
.top
= FILL_Y(row
);
4317 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
4319 gui_mch_set_bg_color(gui
.back_pixel
);
4320 ScrollRect(&rc
, 0, -num_lines
* gui
.char_height
, (RgnHandle
) nil
);
4322 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
4323 gui
.scroll_region_left
,
4324 gui
.scroll_region_bot
, gui
.scroll_region_right
);
4328 * Insert the given number of lines before the given row, scrolling down any
4329 * following text within the scroll region.
4332 gui_mch_insert_lines(int row
, int num_lines
)
4336 rc
.left
= FILL_X(gui
.scroll_region_left
);
4337 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
4338 rc
.top
= FILL_Y(row
);
4339 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
4341 gui_mch_set_bg_color(gui
.back_pixel
);
4343 ScrollRect(&rc
, 0, gui
.char_height
* num_lines
, (RgnHandle
) nil
);
4345 /* Update gui.cursor_row if the cursor scrolled or copied over */
4346 if (gui
.cursor_row
>= gui
.row
4347 && gui
.cursor_col
>= gui
.scroll_region_left
4348 && gui
.cursor_col
<= gui
.scroll_region_right
)
4350 if (gui
.cursor_row
<= gui
.scroll_region_bot
- num_lines
)
4351 gui
.cursor_row
+= num_lines
;
4352 else if (gui
.cursor_row
<= gui
.scroll_region_bot
)
4353 gui
.cursor_is_valid
= FALSE
;
4356 gui_clear_block(row
, gui
.scroll_region_left
,
4357 row
+ num_lines
- 1, gui
.scroll_region_right
);
4361 * TODO: add a vim format to the clipboard which remember
4362 * LINEWISE, CHARWISE, BLOCKWISE
4366 clip_mch_request_selection(VimClipboard
*cbd
)
4372 ScrapFlavorFlags scrapFlags
;
4373 ScrapRef scrap
= nil
;
4380 error
= GetCurrentScrap(&scrap
);
4384 error
= GetScrapFlavorFlags(scrap
, VIMSCRAPFLAVOR
, &scrapFlags
);
4387 error
= GetScrapFlavorSize(scrap
, VIMSCRAPFLAVOR
, &scrapSize
);
4388 if (error
== noErr
&& scrapSize
> 1)
4394 error
= GetScrapFlavorFlags(scrap
, SCRAPTEXTFLAVOR
, &scrapFlags
);
4398 error
= GetScrapFlavorSize(scrap
, SCRAPTEXTFLAVOR
, &scrapSize
);
4403 ReserveMem(scrapSize
);
4405 /* In CARBON we don't need a Handle, a pointer is good */
4406 textOfClip
= NewHandle(scrapSize
);
4408 /* tempclip = lalloc(scrapSize+1, TRUE); */
4410 error
= GetScrapFlavorData(scrap
,
4411 flavor
? VIMSCRAPFLAVOR
: SCRAPTEXTFLAVOR
,
4412 &scrapSize
, *textOfClip
);
4413 scrapSize
-= flavor
;
4416 type
= **textOfClip
;
4418 type
= (strchr(*textOfClip
, '\r') != NULL
) ? MLINE
: MCHAR
;
4420 tempclip
= lalloc(scrapSize
+ 1, TRUE
);
4421 mch_memmove(tempclip
, *textOfClip
+ flavor
, scrapSize
);
4422 tempclip
[scrapSize
] = 0;
4424 #ifdef MACOS_CONVERT
4426 /* Convert from utf-16 (clipboard) */
4428 char_u
*to
= mac_utf16_to_enc((UniChar
*)tempclip
, scrapSize
, &encLen
);
4439 searchCR
= (char *)tempclip
;
4440 while (searchCR
!= NULL
)
4442 searchCR
= strchr(searchCR
, '\r');
4443 if (searchCR
!= NULL
)
4447 clip_yank_selection(type
, tempclip
, scrapSize
, cbd
);
4450 HUnlock(textOfClip
);
4452 DisposeHandle(textOfClip
);
4456 clip_mch_lose_selection(VimClipboard
*cbd
)
4459 * TODO: Really nothing to do?
4464 clip_mch_own_selection(VimClipboard
*cbd
)
4470 * Send the current selection to the clipboard.
4473 clip_mch_set_selection(VimClipboard
*cbd
)
4485 clip_get_selection(cbd
);
4488 * Once we set the clipboard, lose ownership. If another application sets
4489 * the clipboard, we don't want to think that we still own it.
4493 type
= clip_convert_selection(&str
, (long_u
*)&scrapSize
, cbd
);
4495 #ifdef MACOS_CONVERT
4496 size_t utf16_len
= 0;
4497 UniChar
*to
= mac_enc_to_utf16(str
, scrapSize
, &utf16_len
);
4500 scrapSize
= utf16_len
;
4508 ClearCurrentScrap();
4510 textOfClip
= NewHandle(scrapSize
+ 1);
4513 **textOfClip
= type
;
4514 mch_memmove(*textOfClip
+ 1, str
, scrapSize
);
4515 GetCurrentScrap(&scrap
);
4516 PutScrapFlavor(scrap
, SCRAPTEXTFLAVOR
, kScrapFlavorMaskNone
,
4517 scrapSize
, *textOfClip
+ 1);
4518 PutScrapFlavor(scrap
, VIMSCRAPFLAVOR
, kScrapFlavorMaskNone
,
4519 scrapSize
+ 1, *textOfClip
);
4520 HUnlock(textOfClip
);
4521 DisposeHandle(textOfClip
);
4528 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
4532 /* HideWindow(gui.VimWindow); */
4533 GetWindowBounds(gui
.VimWindow
, kWindowGlobalPortRgn
, &VimBound
);
4535 if (gui
.which_scrollbars
[SBAR_LEFT
])
4537 VimBound
.left
= -gui
.scrollbar_width
+ 1;
4544 SetWindowBounds(gui
.VimWindow
, kWindowGlobalPortRgn
, &VimBound
);
4546 ShowWindow(gui
.VimWindow
);
4554 gui_mch_enable_menu(int flag
)
4557 * Menu is always active.
4562 gui_mch_set_menu_pos(int x
, int y
, int w
, int h
)
4565 * The menu is always at the top of the screen.
4570 * Add a sub menu to the menu bar.
4573 gui_mch_add_menu(vimmenu_T
*menu
, int idx
)
4576 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4577 * TODO: use menu->mnemonic and menu->actext
4578 * TODO: Try to reuse menu id
4579 * Carbon Help suggest to use only id between 1 and 235
4581 static long next_avail_id
= 128;
4582 long menu_after_me
= 0; /* Default to the end */
4583 #if defined(FEAT_MBYTE)
4589 vimmenu_T
*parent
= menu
->parent
;
4590 vimmenu_T
*brother
= menu
->next
;
4592 /* Cannot add a menu if ... */
4593 if ((parent
!= NULL
&& parent
->submenu_id
== 0))
4596 /* menu ID greater than 1024 are reserved for ??? */
4597 if (next_avail_id
== 1024)
4600 /* My brother could be the PopUp, find my real brother */
4601 while ((brother
!= NULL
) && (!menu_is_menubar(brother
->name
)))
4602 brother
= brother
->next
;
4604 /* Find where to insert the menu (for MenuBar) */
4605 if ((parent
== NULL
) && (brother
!= NULL
))
4606 menu_after_me
= brother
->submenu_id
;
4608 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4609 if (!menu_is_menubar(menu
->name
))
4610 menu_after_me
= hierMenu
;
4612 /* Convert the name */
4613 #ifdef MACOS_CONVERT
4614 name
= menu_title_removing_mnemonic(menu
);
4616 name
= C2Pascal_save(menu
->dname
);
4621 /* Create the menu unless it's the help menu */
4623 /* Carbon suggest use of
4624 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4625 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
4627 menu
->submenu_id
= next_avail_id
;
4628 #if defined(FEAT_MBYTE)
4629 if (CreateNewMenu(menu
->submenu_id
, 0, (MenuRef
*)&menu
->submenu_handle
) == noErr
)
4630 SetMenuTitleWithCFString((MenuRef
)menu
->submenu_handle
, name
);
4632 menu
->submenu_handle
= NewMenu(menu
->submenu_id
, name
);
4639 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4641 /* TODO: Verify if we could only Insert Menu if really part of the
4642 * menubar The Inserted menu are scanned or the Command-key combos
4645 /* Insert the menu */
4646 InsertMenu(menu
->submenu_handle
, menu_after_me
); /* insert before */
4648 /* Vim should normally update it. TODO: verify */
4654 /* Adding as a submenu */
4656 index
= gui_mac_get_menu_item_index(menu
);
4658 /* Call InsertMenuItem followed by SetMenuItemText
4659 * to avoid special character recognition by InsertMenuItem
4661 InsertMenuItem(parent
->submenu_handle
, "\p ", idx
); /* afterItem */
4662 #if defined(FEAT_MBYTE)
4663 SetMenuItemTextWithCFString(parent
->submenu_handle
, idx
+1, name
);
4665 SetMenuItemText(parent
->submenu_handle
, idx
+1, name
);
4667 SetItemCmd(parent
->submenu_handle
, idx
+1, 0x1B);
4668 SetItemMark(parent
->submenu_handle
, idx
+1, menu
->submenu_id
);
4669 InsertMenu(menu
->submenu_handle
, hierMenu
);
4672 #if defined(FEAT_MBYTE)
4679 /* Done by Vim later on */
4685 * Add a menu item to a menu
4688 gui_mch_add_menu_item(vimmenu_T
*menu
, int idx
)
4690 #if defined(FEAT_MBYTE)
4695 vimmenu_T
*parent
= menu
->parent
;
4698 /* Cannot add item, if the menu have not been created */
4699 if (parent
->submenu_id
== 0)
4702 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4703 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4705 /* Convert the name */
4706 #ifdef MACOS_CONVERT
4707 name
= menu_title_removing_mnemonic(menu
);
4709 name
= C2Pascal_save(menu
->dname
);
4712 /* Where are just a menu item, so no handle, no id */
4713 menu
->submenu_id
= 0;
4714 menu
->submenu_handle
= NULL
;
4719 /* If the accelerator text for the menu item looks like it describes
4720 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4721 * item's command equivalent.
4727 p_actext
= menu
->actext
;
4728 key
= find_special_key(&p_actext
, &modifiers
, /*keycode=*/0);
4730 key
= 0; /* error: trailing text */
4731 /* find_special_key() returns a keycode with as many of the
4732 * specified modifiers as appropriate already applied (e.g., for
4733 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4734 * as the only modifier). Since we want to display all of the
4735 * modifiers, we need to convert the keycode back to a printable
4736 * character plus modifiers.
4737 * TODO: Write an alternative find_special_key() that doesn't
4740 if (key
> 0 && key
< 32)
4742 /* Convert a control key to an uppercase letter. Note that
4743 * by this point it is no longer possible to distinguish
4744 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4746 modifiers
|= MOD_MASK_CTRL
;
4749 /* If the keycode is an uppercase letter, set the Shift modifier.
4750 * If it is a lowercase letter, don't set the modifier, but convert
4751 * the letter to uppercase for display in the menu.
4753 else if (key
>= 'A' && key
<= 'Z')
4754 modifiers
|= MOD_MASK_SHIFT
;
4755 else if (key
>= 'a' && key
<= 'z')
4757 /* Note: keycodes below 0x22 are reserved by Apple. */
4758 if (key
>= 0x22 && vim_isprintc_strict(key
))
4761 char_u mac_mods
= kMenuNoModifiers
;
4762 /* Convert Vim modifier codes to Menu Manager equivalents. */
4763 if (modifiers
& MOD_MASK_SHIFT
)
4764 mac_mods
|= kMenuShiftModifier
;
4765 if (modifiers
& MOD_MASK_CTRL
)
4766 mac_mods
|= kMenuControlModifier
;
4767 if (!(modifiers
& MOD_MASK_CMD
))
4768 mac_mods
|= kMenuNoCommandModifier
;
4769 if (modifiers
& MOD_MASK_ALT
|| modifiers
& MOD_MASK_MULTI_CLICK
)
4770 valid
= 0; /* TODO: will Alt someday map to Option? */
4773 char_u item_txt
[10];
4774 /* Insert the menu item after idx, with its command key. */
4775 item_txt
[0] = 3; item_txt
[1] = ' '; item_txt
[2] = '/';
4777 InsertMenuItem(parent
->submenu_handle
, item_txt
, idx
);
4778 /* Set the modifier keys. */
4779 SetMenuItemModifiers(parent
->submenu_handle
, idx
+1, mac_mods
);
4784 /* Call InsertMenuItem followed by SetMenuItemText
4785 * to avoid special character recognition by InsertMenuItem
4788 InsertMenuItem(parent
->submenu_handle
, "\p ", idx
); /* afterItem */
4789 /* Set the menu item name. */
4790 #if defined(FEAT_MBYTE)
4791 SetMenuItemTextWithCFString(parent
->submenu_handle
, idx
+1, name
);
4793 SetMenuItemText(parent
->submenu_handle
, idx
+1, name
);
4801 #if defined(FEAT_MBYTE)
4804 /* TODO: Can name be freed? */
4810 gui_mch_toggle_tearoffs(int enable
)
4812 /* no tearoff menus */
4816 * Destroy the machine specific menu widget.
4819 gui_mch_destroy_menu(vimmenu_T
*menu
)
4821 short index
= gui_mac_get_menu_item_index(menu
);
4828 /* For now just don't delete help menu items. (Huh? Dany) */
4829 DeleteMenuItem(menu
->parent
->submenu_handle
, index
);
4831 /* Delete the Menu if it was a hierarchical Menu */
4832 if (menu
->submenu_id
!= 0)
4834 DeleteMenu(menu
->submenu_id
);
4835 DisposeMenu(menu
->submenu_handle
);
4839 #ifdef DEBUG_MAC_MENU
4849 DeleteMenu(menu
->submenu_id
);
4850 DisposeMenu(menu
->submenu_handle
);
4853 /* Shouldn't this be already done by Vim. TODO: Check */
4858 * Make a menu either grey or not grey.
4861 gui_mch_menu_grey(vimmenu_T
*menu
, int grey
)
4863 /* TODO: Check if menu really exists */
4864 short index
= gui_mac_get_menu_item_index(menu
);
4866 index = menu->index;
4871 DisableMenuItem(menu
->submenu_handle
, index
);
4873 if (menu
->parent
->submenu_handle
)
4874 DisableMenuItem(menu
->parent
->submenu_handle
, index
);
4879 EnableMenuItem(menu
->submenu_handle
, index
);
4881 if (menu
->parent
->submenu_handle
)
4882 EnableMenuItem(menu
->parent
->submenu_handle
, index
);
4887 * Make menu item hidden or not hidden
4890 gui_mch_menu_hidden(vimmenu_T
*menu
, int hidden
)
4892 /* There's no hidden mode on MacOS */
4893 gui_mch_menu_grey(menu
, hidden
);
4898 * This is called after setting all the menus to grey/hidden or not.
4901 gui_mch_draw_menubar(void)
4912 gui_mch_enable_scrollbar(
4917 ShowControl(sb
->id
);
4919 HideControl(sb
->id
);
4922 printf("enb_sb (%x) %x\n",sb
->id
, flag
);
4927 gui_mch_set_scrollbar_thumb(
4933 SetControl32BitMaximum (sb
->id
, max
);
4934 SetControl32BitMinimum (sb
->id
, 0);
4935 SetControl32BitValue (sb
->id
, val
);
4936 SetControlViewSize (sb
->id
, size
);
4938 printf("thumb_sb (%x) %x, %x,%x\n",sb
->id
, val
, size
, max
);
4943 gui_mch_set_scrollbar_pos(
4950 gui_mch_set_bg_color(gui
.back_pixel
);
4951 /* if (gui.which_scrollbars[SBAR_LEFT])
4953 MoveControl(sb->id, x-16, y);
4954 SizeControl(sb->id, w + 1, h);
4958 MoveControl(sb->id, x, y);
4959 SizeControl(sb->id, w + 1, h);
4961 if (sb
== &gui
.bottom_sbar
)
4966 if (gui
.which_scrollbars
[SBAR_LEFT
])
4969 MoveControl(sb
->id
, x
, y
);
4970 SizeControl(sb
->id
, w
, h
);
4972 printf("size_sb (%x) %x, %x, %x, %x\n",sb
->id
, x
, y
, w
, h
);
4977 gui_mch_create_scrollbar(
4979 int orient
) /* SBAR_VERT or SBAR_HORIZ */
4984 bounds
.bottom
= -10;
4988 sb
->id
= NewControl(gui
.VimWindow
,
4995 kControlScrollBarLiveProc
,
4998 printf("create_sb (%x) %x\n",sb
->id
, orient
);
5003 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
5005 gui_mch_set_bg_color(gui
.back_pixel
);
5006 DisposeControl(sb
->id
);
5008 printf("dest_sb (%x) \n",sb
->id
);
5014 * Cursor blink functions.
5016 * This is a simple state machine:
5017 * BLINK_NONE not blinking at all
5018 * BLINK_OFF blinking, cursor is not shown
5019 * BLINK_ON blinking, cursor is shown
5022 gui_mch_set_blinking(long wait
, long on
, long off
)
5024 /* TODO: TODO: TODO: TODO: */
5025 /* blink_waittime = wait;
5027 blink_offtime = off;*/
5031 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5034 gui_mch_stop_blink(void)
5036 gui_update_cursor(TRUE
, FALSE
);
5037 /* TODO: TODO: TODO: TODO: */
5038 /* gui_w32_rm_blink_timer();
5039 if (blink_state == BLINK_OFF)
5040 gui_update_cursor(TRUE, FALSE);
5041 blink_state = BLINK_NONE;*/
5045 * Start the cursor blinking. If it was already blinking, this restarts the
5046 * waiting time and shows the cursor.
5049 gui_mch_start_blink(void)
5051 gui_update_cursor(TRUE
, FALSE
);
5052 /* TODO: TODO: TODO: TODO: */
5053 /* gui_w32_rm_blink_timer(); */
5055 /* Only switch blinking on if none of the times is zero */
5056 /* if (blink_waittime && blink_ontime && blink_offtime)
5058 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5059 (TIMERPROC)_OnBlinkTimer);
5060 blink_state = BLINK_ON;
5061 gui_update_cursor(TRUE, FALSE);
5066 * Return the RGB value of a pixel as long.
5069 gui_mch_get_rgb(guicolor_T pixel
)
5071 return (Red(pixel
) << 16) + (Green(pixel
) << 8) + Blue(pixel
);
5078 * Pop open a file browser and return the file selected, in allocated memory,
5079 * or NULL if Cancel is hit.
5080 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5081 * title - Title message for the file browser dialog.
5082 * dflt - Default name of file.
5083 * ext - Default extension to be added to files without extensions.
5084 * initdir - directory in which to open the browser (NULL = current dir)
5085 * filter - Filter for matched files to choose from.
5086 * Has a format like this:
5087 * "C Files (*.c)\0*.c\0"
5088 * "All Files\0*.*\0\0"
5089 * If these two strings were concatenated, then a choice of two file
5090 * filters will be selectable to the user. Then only matching files will
5091 * be shown in the browser. If NULL, the default allows all files.
5093 * *NOTE* - the filter string must be terminated with TWO nulls.
5104 /* TODO: Add Ammon's safety checl (Dany) */
5105 NavReplyRecord reply
;
5106 char_u
*fname
= NULL
;
5107 char_u
**fnames
= NULL
;
5109 NavDialogOptions navOptions
;
5112 /* Get Navigation Service Defaults value */
5113 NavGetDefaultDialogOptions(&navOptions
);
5116 /* TODO: If we get a :browse args, set the Multiple bit. */
5117 navOptions
.dialogOptionFlags
= kNavAllowInvisibleFiles
5118 | kNavDontAutoTranslate
5119 | kNavDontAddTranslateItems
5120 /* | kNavAllowMultipleFiles */
5121 | kNavAllowStationery
;
5123 (void) C2PascalString(title
, &navOptions
.message
);
5124 (void) C2PascalString(dflt
, &navOptions
.savedFileName
);
5125 /* Could set clientName?
5126 * windowTitle? (there's no title bar?)
5131 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5132 NavPutFile(NULL
, &reply
, &navOptions
, NULL
, 'TEXT', 'VIM!', NULL
);
5133 if (!reply
.validRecord
)
5138 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5139 NavGetFile(NULL
, &reply
, &navOptions
, NULL
, NULL
, NULL
, NULL
, NULL
);
5140 if (!reply
.validRecord
)
5144 fnames
= new_fnames_from_AEDesc(&reply
.selection
, &numFiles
, &error
);
5146 NavDisposeReply(&reply
);
5154 /* TODO: Shorten the file name if possible */
5157 #endif /* FEAT_BROWSE */
5159 #ifdef FEAT_GUI_DIALOG
5161 * Stuff for dialogues
5165 * Create a dialogue dynamically from the parameter strings.
5166 * type = type of dialogue (question, alert, etc.)
5167 * title = dialogue title. may be NULL for default title.
5168 * message = text to display. Dialogue sizes to accommodate it.
5169 * buttons = '\n' separated list of button captions, default first.
5170 * dfltbutton = number of default button.
5172 * This routine returns 1 if the first button is pressed,
5173 * 2 for the second, etc.
5175 * 0 indicates Esc was pressed.
5176 * -1 for unexpected error
5178 * If stubbing out this fn, return 1.
5184 short width
; /* Size of the text in pixel */
5186 } vgmDlgItm
; /* Vim Gui_Mac.c Dialog Item */
5188 #define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5192 DialogRef theDialog
,
5198 #if 0 /* USE_CARBONIZED */
5200 MoveDialogItem(theDialog
, itemNumber
, X
, Y
);
5202 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, inBox
);
5207 Rect
*itemBox
= &localBox
;
5212 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, itemBox
);
5213 OffsetRect(itemBox
, -itemBox
->left
, -itemBox
->top
);
5214 OffsetRect(itemBox
, X
, Y
);
5215 /* To move a control (like a button) we need to call both
5216 * MoveControl and SetDialogItem. FAQ 6-18 */
5217 if (1) /*(itemType & kControlDialogItem) */
5218 MoveControl((ControlRef
) itemHandle
, X
, Y
);
5219 SetDialogItem(theDialog
, itemNumber
, itemType
, itemHandle
, itemBox
);
5225 DialogRef theDialog
,
5234 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, &itemBox
);
5236 /* When width or height is zero do not change it */
5238 width
= itemBox
.right
- itemBox
.left
;
5240 height
= itemBox
.bottom
- itemBox
.top
;
5242 #if 0 /* USE_CARBONIZED */
5243 SizeDialogItem(theDialog
, itemNumber
, width
, height
); /* Untested */
5245 /* Resize the bounding box */
5246 itemBox
.right
= itemBox
.left
+ width
;
5247 itemBox
.bottom
= itemBox
.top
+ height
;
5249 /* To resize a control (like a button) we need to call both
5250 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5251 if (itemType
& kControlDialogItem
)
5252 SizeControl((ControlRef
) itemHandle
, width
, height
);
5254 /* Configure back the item */
5255 SetDialogItem(theDialog
, itemNumber
, itemType
, itemHandle
, &itemBox
);
5260 macSetDialogItemText(
5261 DialogRef theDialog
,
5269 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, &itemBox
);
5271 if (itemType
& kControlDialogItem
)
5272 SetControlTitle((ControlRef
) itemHandle
, itemName
);
5274 SetDialogItemText(itemHandle
, itemName
);
5277 /* TODO: There have been some crashes with dialogs, check your inbox
5295 DialogPtr theDialog
;
5297 char_u PascalTitle
[256]; /* place holder for the title */
5308 short totalButtonWidth
= 0; /* the width of all buttons together
5309 including spacing */
5310 short widestButton
= 0;
5311 short dfltButtonEdge
= 20; /* gut feeling */
5312 short dfltElementSpacing
= 13; /* from IM:V.2-29 */
5313 short dfltIconSideSpace
= 23; /* from IM:V.2-29 */
5314 short maximumWidth
= 400; /* gut feeling */
5315 short maxButtonWidth
= 175; /* gut feeling */
5319 short messageLines
= 3;
5320 FontInfo textFontInfo
;
5323 vgmDlgItm messageItm
;
5325 vgmDlgItm buttonItm
;
5327 WindowRef theWindow
;
5329 /* Check 'v' flag in 'guioptions': vertical button placement. */
5330 vertical
= (vim_strchr(p_go
, GO_VERTICAL
) != NULL
);
5332 /* Create a new Dialog Box from template. */
5333 theDialog
= GetNewDialog(129, nil
, (WindowRef
) -1);
5335 /* Get the WindowRef */
5336 theWindow
= GetDialogWindow(theDialog
);
5339 * 1. to avoid seeing slow drawing
5340 * 2. to prevent a problem seen while moving dialog item
5341 * within a visible window. (non-Carbon MacOS 9)
5342 * Could be avoided by changing the resource.
5344 HideWindow(theWindow
);
5346 /* Change the graphical port to the dialog,
5347 * so we can measure the text with the proper font */
5349 SetPortDialogPort(theDialog
);
5351 /* Get the info about the default text,
5352 * used to calculate the height of the message
5353 * and of the text field */
5354 GetFontInfo(&textFontInfo
);
5356 /* Set the dialog title */
5359 (void) C2PascalString(title
, &PascalTitle
);
5360 SetWTitle(theWindow
, PascalTitle
);
5363 /* Creates the buttons and add them to the Dialog Box. */
5364 buttonDITL
= GetResource('DITL', 130);
5365 buttonChar
= buttons
;
5368 for (;*buttonChar
!= 0;)
5370 /* Get the name of the button */
5373 for (;((*buttonChar
!= DLG_BUTTON_SEP
) && (*buttonChar
!= 0) && (len
< 255)); buttonChar
++)
5375 if (*buttonChar
!= DLG_HOTKEY_CHAR
)
5376 name
[++len
] = *buttonChar
;
5378 if (*buttonChar
!= 0)
5382 /* Add the button */
5383 AppendDITL(theDialog
, buttonDITL
, overlayDITL
); /* appendDITLRight); */
5385 /* Change the button's name */
5386 macSetDialogItemText(theDialog
, button
, name
);
5388 /* Resize the button to fit its name */
5389 width
= StringWidth(name
) + 2 * dfltButtonEdge
;
5390 /* Limite the size of any button to an acceptable value. */
5391 /* TODO: Should be based on the message width */
5392 if (width
> maxButtonWidth
)
5393 width
= maxButtonWidth
;
5394 macSizeDialogItem(theDialog
, button
, width
, 0);
5396 totalButtonWidth
+= width
;
5398 if (width
> widestButton
)
5399 widestButton
= width
;
5401 ReleaseResource(buttonDITL
);
5402 lastButton
= button
;
5404 /* Add the icon to the Dialog Box. */
5405 iconItm
.idx
= lastButton
+ 1;
5406 iconDITL
= GetResource('DITL', 131);
5409 case VIM_GENERIC
: useIcon
= kNoteIcon
;
5410 case VIM_ERROR
: useIcon
= kStopIcon
;
5411 case VIM_WARNING
: useIcon
= kCautionIcon
;
5412 case VIM_INFO
: useIcon
= kNoteIcon
;
5413 case VIM_QUESTION
: useIcon
= kNoteIcon
;
5414 default: useIcon
= kStopIcon
;
5416 AppendDITL(theDialog
, iconDITL
, overlayDITL
);
5417 ReleaseResource(iconDITL
);
5418 GetDialogItem(theDialog
, iconItm
.idx
, &itemType
, &itemHandle
, &box
);
5419 /* TODO: Should the item be freed? */
5420 iconHandle
= GetIcon(useIcon
);
5421 SetDialogItem(theDialog
, iconItm
.idx
, itemType
, iconHandle
, &box
);
5423 /* Add the message to the Dialog box. */
5424 messageItm
.idx
= lastButton
+ 2;
5425 messageDITL
= GetResource('DITL', 132);
5426 AppendDITL(theDialog
, messageDITL
, overlayDITL
);
5427 ReleaseResource(messageDITL
);
5428 GetDialogItem(theDialog
, messageItm
.idx
, &itemType
, &itemHandle
, &box
);
5429 (void) C2PascalString(message
, &name
);
5430 SetDialogItemText(itemHandle
, name
);
5431 messageItm
.width
= StringWidth(name
);
5433 /* Add the input box if needed */
5434 if (textfield
!= NULL
)
5436 /* Cheat for now reuse the message and convert to text edit */
5437 inputItm
.idx
= lastButton
+ 3;
5438 inputDITL
= GetResource('DITL', 132);
5439 AppendDITL(theDialog
, inputDITL
, overlayDITL
);
5440 ReleaseResource(inputDITL
);
5441 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &box
);
5442 /* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5443 (void) C2PascalString(textfield
, &name
);
5444 SetDialogItemText(itemHandle
, name
);
5445 inputItm
.width
= StringWidth(name
);
5448 /* Set the <ENTER> and <ESC> button. */
5449 SetDialogDefaultItem(theDialog
, dfltbutton
);
5450 SetDialogCancelItem(theDialog
, 0);
5452 /* Reposition element */
5454 /* Check if we need to force vertical */
5455 if (totalButtonWidth
> maximumWidth
)
5459 macMoveDialogItem(theDialog
, iconItm
.idx
, dfltIconSideSpace
, dfltElementSpacing
, &box
);
5460 iconItm
.box
.right
= box
.right
;
5461 iconItm
.box
.bottom
= box
.bottom
;
5464 messageItm
.box
.left
= iconItm
.box
.right
+ dfltIconSideSpace
;
5465 macSizeDialogItem(theDialog
, messageItm
.idx
, 0, messageLines
* (textFontInfo
.ascent
+ textFontInfo
.descent
));
5466 macMoveDialogItem(theDialog
, messageItm
.idx
, messageItm
.box
.left
, dfltElementSpacing
, &messageItm
.box
);
5469 if (textfield
!= NULL
)
5471 inputItm
.box
.left
= messageItm
.box
.left
;
5472 inputItm
.box
.top
= messageItm
.box
.bottom
+ dfltElementSpacing
;
5473 macSizeDialogItem(theDialog
, inputItm
.idx
, 0, textFontInfo
.ascent
+ textFontInfo
.descent
);
5474 macMoveDialogItem(theDialog
, inputItm
.idx
, inputItm
.box
.left
, inputItm
.box
.top
, &inputItm
.box
);
5475 /* Convert the static text into a text edit.
5476 * For some reason this change need to be done last (Dany) */
5477 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &inputItm
.box
);
5478 SetDialogItem(theDialog
, inputItm
.idx
, kEditTextDialogItem
, itemHandle
, &inputItm
.box
);
5479 SelectDialogItemText(theDialog
, inputItm
.idx
, 0, 32767);
5483 if (textfield
!= NULL
)
5485 buttonItm
.box
.left
= inputItm
.box
.left
;
5486 buttonItm
.box
.top
= inputItm
.box
.bottom
+ dfltElementSpacing
;
5490 buttonItm
.box
.left
= messageItm
.box
.left
;
5491 buttonItm
.box
.top
= messageItm
.box
.bottom
+ dfltElementSpacing
;
5494 for (button
=1; button
<= lastButton
; button
++)
5497 macMoveDialogItem(theDialog
, button
, buttonItm
.box
.left
, buttonItm
.box
.top
, &box
);
5498 /* With vertical, it's better to have all buttons the same length */
5501 macSizeDialogItem(theDialog
, button
, widestButton
, 0);
5502 GetDialogItem(theDialog
, button
, &itemType
, &itemHandle
, &box
);
5504 /* Calculate position of next button */
5506 buttonItm
.box
.top
= box
.bottom
+ dfltElementSpacing
;
5508 buttonItm
.box
.left
= box
.right
+ dfltElementSpacing
;
5511 /* Resize the dialog box */
5512 dialogHeight
= box
.bottom
+ dfltElementSpacing
;
5513 SizeWindow(theWindow
, maximumWidth
, dialogHeight
, TRUE
);
5516 AutoSizeDialog(theDialog
);
5517 /* Need a horizontal resize anyway so not that useful */
5520 ShowWindow(theWindow
);
5521 /* BringToFront(theWindow); */
5522 SelectWindow(theWindow
);
5524 /* DrawDialog(theDialog); */
5527 SetPortDialogPort(theDialog
);
5530 #ifdef USE_CARBONKEYHANDLER
5531 /* Avoid that we use key events for the main window. */
5535 /* Hang until one of the button is hit */
5538 ModalDialog(nil
, &itemHit
);
5539 } while ((itemHit
< 1) || (itemHit
> lastButton
));
5541 #ifdef USE_CARBONKEYHANDLER
5542 dialog_busy
= FALSE
;
5545 /* Copy back the text entered by the user into the param */
5546 if (textfield
!= NULL
)
5548 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &box
);
5549 GetDialogItemText(itemHandle
, (char_u
*) &name
);
5551 /* Truncate the name to IOSIZE if needed */
5552 if (name
[0] > IOSIZE
)
5553 name
[0] = IOSIZE
- 1;
5555 vim_strncpy(textfield
, &name
[1], name
[0]);
5558 /* Restore the original graphical port */
5561 /* Get ride of th edialog (free memory) */
5562 DisposeDialog(theDialog
);
5566 * Usefull thing which could be used
5567 * SetDialogTimeout(): Auto click a button after timeout
5568 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5569 * MoveDialogItem(): Probably better than SetDialogItem
5570 * SizeDialogItem(): (but is it Carbon Only?)
5571 * AutoSizeDialog(): Magic resize of dialog based on text length
5574 #endif /* FEAT_DIALOG_GUI */
5577 * Display the saved error message(s).
5579 #ifdef USE_MCH_ERRMSG
5581 display_errors(void)
5586 if (error_ga
.ga_data
== NULL
)
5589 /* avoid putting up a message box with blanks only */
5590 for (p
= (char *)error_ga
.ga_data
; *p
; ++p
)
5593 if (STRLEN(p
) > 255)
5596 pError
[0] = STRLEN(p
);
5598 STRNCPY(&pError
[1], p
, pError
[0]);
5599 ParamText(pError
, nil
, nil
, nil
);
5602 /* TODO: handled message longer than 256 chars
5603 * use auto-sizeable alert
5604 * or dialog with scrollbars (TextEdit zone)
5607 ga_clear(&error_ga
);
5612 * Get current mouse coordinates in text window.
5615 gui_mch_getmouse(int *x
, int *y
)
5626 gui_mch_setmouse(int x
, int y
)
5632 CursorDevicePtr myMouse
;
5635 if ( NGetTrapAddress(_CursorDeviceDispatch
, ToolTrap
)
5636 != NGetTrapAddress(_Unimplemented
, ToolTrap
))
5641 * Get first devoice with one button.
5642 * This will probably be the standad mouse
5643 * startat head of cursor dev list
5651 /* Get the next cursor device */
5652 CursorDeviceNextDevice(&myMouse
);
5654 while ((myMouse
!= nil
) && (myMouse
->cntButtons
!= 1));
5656 CursorDeviceMoveTo(myMouse
, x
, y
);
5664 *(Point
*)RawMouse
= where
;
5665 *(Point
*)MTemp
= where
;
5666 *(Ptr
) CrsrNew
= 0xFFFF;
5672 gui_mch_show_popupmenu(vimmenu_T
*menu
)
5675 * Clone PopUp to use menu
5676 * Create a object descriptor for the current selection
5677 * Call the procedure
5680 MenuHandle CntxMenu
;
5685 UInt16 CntxMenuItem
;
5686 Str255 HelpName
= "";
5689 /* Save Current Port: On MacOS X we seem to lose the port */
5690 GetPort(&savePort
); /*OSX*/
5693 LocalToGlobal(&where
); /*OSX*/
5694 CntxMenu
= menu
->submenu_handle
;
5696 /* TODO: Get the text selection from Vim */
5698 /* Call to Handle Popup */
5699 status
= ContextualMenuSelect(CntxMenu
, where
, false, kCMHelpItemRemoveHelp
,
5700 HelpName
, NULL
, &CntxType
, &CntxMenuID
, &CntxMenuItem
);
5702 if (status
== noErr
)
5704 if (CntxType
== kCMMenuItemSelected
)
5706 /* Handle the menu CntxMenuID, CntxMenuItem */
5707 /* The submenu can be handle directly by gui_mac_handle_menu */
5708 /* But what about the current menu, is the menu changed by
5709 * ContextualMenuSelect */
5710 gui_mac_handle_menu((CntxMenuID
<< 16) + CntxMenuItem
);
5712 else if (CntxMenuID
== kCMShowHelpSelected
)
5714 /* Should come up with the help */
5718 /* Restore original Port */
5719 SetPort(savePort
); /*OSX*/
5722 #if defined(FEAT_CW_EDITOR) || defined(PROTO)
5723 /* TODO: Is it need for MACOS_X? (Dany) */
5725 mch_post_buffer_write(buf_T
*buf
)
5727 GetFSSpecFromPath(buf
->b_ffname
, &buf
->b_FSSpec
);
5728 Send_KAHL_MOD_AE(buf
);
5734 * Set the window title and icon.
5735 * (The icon is not taken care of).
5738 gui_mch_settitle(char_u
*title
, char_u
*icon
)
5740 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5741 * that 256. Even better get it to fit nicely in the titlebar.
5743 #ifdef MACOS_CONVERT
5744 CFStringRef windowTitle
;
5745 size_t windowTitleLen
;
5747 char_u
*pascalTitle
;
5750 if (title
== NULL
) /* nothing to do */
5753 #ifdef MACOS_CONVERT
5754 windowTitleLen
= STRLEN(title
);
5755 windowTitle
= mac_enc_to_cfstring(title
, windowTitleLen
);
5759 SetWindowTitleWithCFString(gui
.VimWindow
, windowTitle
);
5760 CFRelease(windowTitle
);
5763 pascalTitle
= C2Pascal_save(title
);
5764 if (pascalTitle
!= NULL
)
5766 SetWTitle(gui
.VimWindow
, pascalTitle
);
5767 vim_free(pascalTitle
);
5774 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5778 C2PascalString(char_u
*CString
, Str255
*PascalString
)
5780 char_u
*PascalPtr
= (char_u
*) PascalString
;
5785 if (CString
== NULL
)
5788 len
= STRLEN(CString
);
5792 for (i
= 0; i
< len
; i
++)
5793 PascalPtr
[i
+1] = CString
[i
];
5801 GetFSSpecFromPath(char_u
*file
, FSSpec
*fileFSSpec
)
5808 (void) C2PascalString(file
, &filePascal
);
5810 myCPB
.dirInfo
.ioNamePtr
= filePascal
;
5811 myCPB
.dirInfo
.ioVRefNum
= 0;
5812 myCPB
.dirInfo
.ioFDirIndex
= 0;
5813 myCPB
.dirInfo
.ioDrDirID
= 0;
5815 err
= PBGetCatInfo(&myCPB
, false);
5817 /* vRefNum, dirID, name */
5818 FSMakeFSSpec(0, 0, filePascal
, fileFSSpec
);
5820 /* TODO: Use an error code mechanism */
5825 * Convert a FSSpec to a fuill path
5828 char_u
*FullPathFromFSSpec_save(FSSpec file
)
5831 * TODO: Add protection for 256 char max.
5836 char_u
*filenamePtr
= fname
;
5839 #ifdef USE_UNIXFILENAME
5840 SInt16 dfltVol_vRefNum
;
5841 SInt32 dfltVol_dirID
;
5844 UInt32 pathSize
= 256;
5845 char_u pathname
[256];
5846 char_u
*path
= pathname
;
5848 Str255 directoryName
;
5849 char_u temporary
[255];
5850 char_u
*temporaryPtr
= temporary
;
5853 #ifdef USE_UNIXFILENAME
5854 /* Get the default volume */
5855 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
5856 error
=HGetVol(NULL
, &dfltVol_vRefNum
, &dfltVol_dirID
);
5862 /* Start filling fname with file.name */
5863 vim_strncpy(filenamePtr
, &file
.name
[1], file
.name
[0]);
5865 /* Get the info about the file specified in FSSpec */
5866 theCPB
.dirInfo
.ioFDirIndex
= 0;
5867 theCPB
.dirInfo
.ioNamePtr
= file
.name
;
5868 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
5869 /*theCPB.hFileInfo.ioDirID = 0;*/
5870 theCPB
.dirInfo
.ioDrDirID
= file
.parID
;
5872 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5873 which is relative to ioVrefNum, ioDirID */
5874 error
= PBGetCatInfo(&theCPB
, false);
5876 /* If we are called for a new file we expect fnfErr */
5877 if ((error
) && (error
!= fnfErr
))
5880 /* Check if it's a file or folder */
5881 /* default to file if file don't exist */
5882 if (((theCPB
.hFileInfo
.ioFlAttrib
& ioDirMask
) == 0) || (error
))
5883 folder
= 0; /* It's not a folder */
5887 #ifdef USE_UNIXFILENAME
5889 * The function used here are available in Carbon, but
5890 * do nothing une MacOS 8 and 9
5892 if (error
== fnfErr
)
5894 /* If the file to be saved does not already exist, it isn't possible
5895 to convert its FSSpec into an FSRef. But we can construct an
5896 FSSpec for the file's parent folder (since we have its volume and
5897 directory IDs), and since that folder does exist, we can convert
5898 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5899 and, finally, append the filename. */
5902 Str255 emptyFilename
= "\p";
5903 error
= FSMakeFSSpec(theCPB
.dirInfo
.ioVRefNum
,
5904 theCPB
.dirInfo
.ioDrDirID
, emptyFilename
, &dirSpec
);
5908 error
= FSpMakeFSRef(&dirSpec
, &dirRef
);
5912 status
= FSRefMakePath(&dirRef
, (UInt8
*)path
, pathSize
);
5917 STRCAT(path
, filenamePtr
);
5921 /* If the file to be saved already exists, we can get its full path
5922 by converting its FSSpec into an FSRef. */
5923 error
=FSpMakeFSRef(&file
, &refFile
);
5927 status
=FSRefMakePath(&refFile
, (UInt8
*) path
, pathSize
);
5932 /* Add a slash at the end if needed */
5936 return (vim_strsave(path
));
5938 /* TODO: Get rid of all USE_UNIXFILENAME below */
5939 /* Set ioNamePtr, it's the same area which is always reused. */
5940 theCPB
.dirInfo
.ioNamePtr
= directoryName
;
5942 /* Trick for first entry, set ioDrParID to the first value
5943 * we want for ioDrDirID*/
5944 theCPB
.dirInfo
.ioDrParID
= file
.parID
;
5945 theCPB
.dirInfo
.ioDrDirID
= file
.parID
;
5947 if ((TRUE
) && (file
.parID
!= fsRtDirID
/*fsRtParID*/))
5950 theCPB
.dirInfo
.ioFDirIndex
= -1;
5951 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5952 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
5953 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
5954 theCPB
.dirInfo
.ioDrDirID
= theCPB
.dirInfo
.ioDrParID
;
5956 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5957 /* *ioNamePtr[0 TO 31] will be updated */
5958 error
= PBGetCatInfo(&theCPB
,false);
5963 /* Put the new directoryName in front of the current fname */
5964 STRCPY(temporaryPtr
, filenamePtr
);
5965 vim_strncpy(filenamePtr
, &directoryName
[1], directoryName
[0]);
5966 STRCAT(filenamePtr
, ":");
5967 STRCAT(filenamePtr
, temporaryPtr
);
5969 #if 1 /* def USE_UNIXFILENAME */
5970 while ((theCPB
.dirInfo
.ioDrParID
!= fsRtDirID
) /* && */
5971 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5973 while (theCPB
.dirInfo
.ioDrDirID
!= fsRtDirID
);
5976 /* Get the information about the volume on which the file reside */
5977 theCPB
.dirInfo
.ioFDirIndex
= -1;
5978 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5979 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
5980 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
5981 theCPB
.dirInfo
.ioDrDirID
= theCPB
.dirInfo
.ioDrParID
;
5983 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5984 /* *ioNamePtr[0 TO 31] will be updated */
5985 error
= PBGetCatInfo(&theCPB
,false);
5990 /* For MacOS Classic always add the volume name */
5991 /* For MacOS X add the volume name preceded by "Volumes" */
5992 /* when we are not referring to the boot volume */
5993 #ifdef USE_UNIXFILENAME
5994 if (file
.vRefNum
!= dfltVol_vRefNum
)
5997 /* Add the volume name */
5998 STRCPY(temporaryPtr
, filenamePtr
);
5999 vim_strncpy(filenamePtr
, &directoryName
[1], directoryName
[0]);
6000 STRCAT(filenamePtr
, ":");
6001 STRCAT(filenamePtr
, temporaryPtr
);
6003 #ifdef USE_UNIXFILENAME
6004 STRCPY(temporaryPtr
, filenamePtr
);
6005 filenamePtr
[0] = 0; /* NULL terminate the string */
6006 STRCAT(filenamePtr
, "Volumes:");
6007 STRCAT(filenamePtr
, temporaryPtr
);
6011 /* Append final path separator if it's a folder */
6015 /* As we use Unix File Name for MacOS X convert it */
6016 #ifdef USE_UNIXFILENAME
6017 /* Need to insert leading / */
6018 /* TODO: get the above code to use directly the / */
6019 STRCPY(&temporaryPtr
[1], filenamePtr
);
6020 temporaryPtr
[0] = '/';
6021 STRCPY(filenamePtr
, temporaryPtr
);
6024 for (p
= fname
; *p
; p
++)
6030 return (vim_strsave(fname
));
6034 #if defined(USE_IM_CONTROL) || defined(PROTO)
6036 * Input Method Control functions.
6040 * Notify cursor position to IM.
6043 im_set_position(int row
, int col
)
6045 /* TODO: Implement me! */
6049 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6052 im_set_active(int active
)
6054 KeyScript(active
? smKeySysScript
: smKeyRoman
);
6058 * Get IM status. When IM is on, return not 0. Else return 0.
6063 SInt32 script
= GetScriptManagerVariable(smKeyScript
);
6064 return (script
!= smRoman
6065 && script
== GetScriptManagerVariable(smSysScript
)) ? 1 : 0;
6068 #endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
6073 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6074 // drawer implementation
6075 static MenuRef contextMenu
= NULL
;
6078 kTabContextMenuId
= 42,
6081 // the caller has to CFRelease() the returned string
6083 getTabLabel(tabpage_T
*page
)
6085 get_tabline_label(page
, FALSE
);
6086 #ifdef MACOS_CONVERT
6087 return mac_enc_to_cfstring(NameBuff
, STRLEN(NameBuff
));
6089 // TODO: check internal encoding?
6090 return CFStringCreateWithCString(kCFAllocatorDefault
, (char *)NameBuff
,
6091 kCFStringEncodingMacRoman
);
6096 #define DRAWER_SIZE 150
6097 #define DRAWER_INSET 16
6099 static ControlRef dataBrowser
= NULL
;
6101 // when the tabline is hidden, vim doesn't call update_tabline(). When
6102 // the tabline is shown again, show_tabline() is called before upate_tabline(),
6103 // and because of this, the tab labels and vims internal tabs are out of sync
6104 // for a very short time. to prevent inconsistent state, we store the labels
6105 // of the tabs, not pointers to the tabs (which are invalid for a short time).
6106 static CFStringRef
*tabLabels
= NULL
;
6107 static int tabLabelsSize
= 0;
6111 kTabsColumn
= 'Tabs'
6120 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
)
6125 // data browser item display callback
6127 dbItemDataCallback(ControlRef browser
,
6128 DataBrowserItemID itemID
,
6129 DataBrowserPropertyID property
/* column id */,
6130 DataBrowserItemDataRef itemData
,
6131 Boolean changeValue
)
6133 OSStatus status
= noErr
;
6135 // assert(property == kTabsColumn); // why is this violated??
6137 // changeValue is true if we have a modifieable list and data was changed.
6138 // In our case, it's always false.
6139 // (that is: if (changeValue) updateInternalData(); else return
6145 assert(itemID
- 1 >= 0 && itemID
- 1 < tabLabelsSize
);
6146 str
= tabLabels
[itemID
- 1];
6147 status
= SetDataBrowserItemDataText(itemData
, str
);
6150 status
= errDataBrowserPropertyNotSupported
;
6155 // data browser action callback
6157 dbItemNotificationCallback(ControlRef browser
,
6158 DataBrowserItemID item
,
6159 DataBrowserItemNotification message
)
6163 case kDataBrowserItemSelected
:
6164 send_tabline_event(item
);
6169 // callbacks needed for contextual menu:
6171 dbGetContextualMenuCallback(ControlRef browser
,
6174 CFStringRef
*helpItemString
,
6177 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6178 *helpType
= kCMHelpItemRemoveHelp
; // OS X only ;-)
6179 *helpItemString
= NULL
;
6181 *menu
= contextMenu
;
6185 dbSelectContextualMenuCallback(ControlRef browser
,
6187 UInt32 selectionType
,
6189 MenuItemIndex menuItem
)
6191 if (selectionType
== kCMMenuItemSelected
)
6193 MenuCommand command
;
6194 GetMenuItemCommandID(menu
, menuItem
, &command
);
6196 // get tab that was selected when the context menu appeared
6197 // (there is always one tab selected). TODO: check if the context menu
6198 // isn't opened on an item but on empty space (has to be possible some
6199 // way, the finder does it too ;-) )
6200 Handle items
= NewHandle(0);
6205 GetDataBrowserItems(browser
, kDataBrowserNoItem
, false,
6206 kDataBrowserItemIsSelected
, items
);
6207 numItems
= GetHandleSize(items
) / sizeof(DataBrowserItemID
);
6211 DataBrowserItemID
*itemsPtr
;
6214 itemsPtr
= (DataBrowserItemID
*)*items
;
6217 send_tabline_menu_event(idx
, command
);
6219 DisposeHandle(items
);
6224 // focus callback of the data browser to always leave focus in vim
6226 dbFocusCallback(EventHandlerCallRef handler
, EventRef event
, void *data
)
6228 assert(GetEventClass(event
) == kEventClassControl
6229 && GetEventKind(event
) == kEventControlSetFocusPart
);
6235 // drawer callback to resize data browser to drawer size
6237 drawerCallback(EventHandlerCallRef handler
, EventRef event
, void *data
)
6239 switch (GetEventKind(event
))
6241 case kEventWindowBoundsChanged
: // move or resize
6244 GetEventParameter(event
, kEventParamAttributes
, typeUInt32
,
6245 NULL
, sizeof(attribs
), NULL
, &attribs
);
6246 if (attribs
& kWindowBoundsChangeSizeChanged
) // resize
6249 GetWindowBounds(drawer
, kWindowContentRgn
, &r
);
6250 SetRect(&r
, 0, 0, r
.right
- r
.left
, r
.bottom
- r
.top
);
6251 SetControlBounds(dataBrowser
, &r
);
6252 SetDataBrowserTableViewNamedColumnWidth(dataBrowser
,
6253 kTabsColumn
, r
.right
);
6259 return eventNotHandledErr
;
6262 // Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6263 // This way the code works on 10.2 and 10.3 as well (it doesn't have the
6264 // blue highlights in the list view on these systems, though. Oh well.)
6267 #import <mach-o/dyld.h>
6269 enum { kMyDataBrowserAttributeListViewAlternatingRowColors
= (1 << 1) };
6272 myDataBrowserChangeAttributes(ControlRef inDataBrowser
,
6273 OptionBits inAttributesToSet
,
6274 OptionBits inAttributesToClear
)
6278 NSSymbol symbol
= NULL
;
6279 OSStatus (*dataBrowserChangeAttributes
)(ControlRef inDataBrowser
,
6280 OptionBits inAttributesToSet
, OptionBits inAttributesToClear
);
6282 Gestalt(gestaltSystemVersion
, &osVersion
);
6283 if (osVersion
< 0x1040) // only supported for 10.4 (and up)
6286 // C name mangling...
6287 symbolName
= "_DataBrowserChangeAttributes";
6288 if (!NSIsSymbolNameDefined(symbolName
)
6289 || (symbol
= NSLookupAndBindSymbol(symbolName
)) == NULL
)
6292 dataBrowserChangeAttributes
= NSAddressOfSymbol(symbol
);
6293 if (dataBrowserChangeAttributes
== NULL
)
6294 return noErr
; // well...
6295 return dataBrowserChangeAttributes(inDataBrowser
,
6296 inAttributesToSet
, inAttributesToClear
);
6300 initialise_tabline(void)
6302 Rect drawerRect
= { 0, 0, 0, DRAWER_SIZE
};
6303 DataBrowserCallbacks dbCallbacks
;
6304 EventTypeSpec focusEvent
= {kEventClassControl
, kEventControlSetFocusPart
};
6305 EventTypeSpec resizeEvent
= {kEventClassWindow
, kEventWindowBoundsChanged
};
6306 DataBrowserListViewColumnDesc colDesc
;
6308 // drawers have to have compositing enabled
6309 CreateNewWindow(kDrawerWindowClass
,
6310 kWindowStandardHandlerAttribute
6311 | kWindowCompositingAttribute
6312 | kWindowResizableAttribute
6313 | kWindowLiveResizeAttribute
,
6314 &drawerRect
, &drawer
);
6316 SetThemeWindowBackground(drawer
, kThemeBrushDrawerBackground
, true);
6317 SetDrawerParent(drawer
, gui
.VimWindow
);
6318 SetDrawerOffsets(drawer
, kWindowOffsetUnchanged
, DRAWER_INSET
);
6321 // create list view embedded in drawer
6322 CreateDataBrowserControl(drawer
, &drawerRect
, kDataBrowserListView
,
6325 dbCallbacks
.version
= kDataBrowserLatestCallbacks
;
6326 InitDataBrowserCallbacks(&dbCallbacks
);
6327 dbCallbacks
.u
.v1
.itemDataCallback
=
6328 NewDataBrowserItemDataUPP(dbItemDataCallback
);
6329 dbCallbacks
.u
.v1
.itemNotificationCallback
=
6330 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback
);
6331 dbCallbacks
.u
.v1
.getContextualMenuCallback
=
6332 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback
);
6333 dbCallbacks
.u
.v1
.selectContextualMenuCallback
=
6334 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback
);
6336 SetDataBrowserCallbacks(dataBrowser
, &dbCallbacks
);
6338 SetDataBrowserListViewHeaderBtnHeight(dataBrowser
, 0); // no header
6339 SetDataBrowserHasScrollBars(dataBrowser
, false, true); // only vertical
6340 SetDataBrowserSelectionFlags(dataBrowser
,
6341 kDataBrowserSelectOnlyOne
| kDataBrowserNeverEmptySelectionSet
);
6342 SetDataBrowserTableViewHiliteStyle(dataBrowser
,
6343 kDataBrowserTableViewFillHilite
);
6345 SetControlData(dataBrowser
, kControlEntireControl
,
6346 kControlDataBrowserIncludesFrameAndFocusTag
, sizeof(b
), &b
);
6348 // enable blue background in data browser (this is only in 10.4 and vim
6349 // has to support older osx versions as well, so we have to load this
6350 // function dynamically)
6351 myDataBrowserChangeAttributes(dataBrowser
,
6352 kMyDataBrowserAttributeListViewAlternatingRowColors
, 0);
6354 // install callback that keeps focus in vim and away from the data browser
6355 InstallControlEventHandler(dataBrowser
, dbFocusCallback
, 1, &focusEvent
,
6358 // install callback that keeps data browser at the size of the drawer
6359 InstallWindowEventHandler(drawer
, drawerCallback
, 1, &resizeEvent
,
6362 // add "tabs" column to data browser
6363 colDesc
.propertyDesc
.propertyID
= kTabsColumn
;
6364 colDesc
.propertyDesc
.propertyType
= kDataBrowserTextType
;
6366 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6367 colDesc
.propertyDesc
.propertyFlags
= kDataBrowserDefaultPropertyFlags
;
6369 colDesc
.headerBtnDesc
.version
= kDataBrowserListViewLatestHeaderDesc
;
6370 colDesc
.headerBtnDesc
.minimumWidth
= 100;
6371 colDesc
.headerBtnDesc
.maximumWidth
= 150;
6372 colDesc
.headerBtnDesc
.titleOffset
= 0;
6373 colDesc
.headerBtnDesc
.titleString
= CFSTR("Tabs");
6374 colDesc
.headerBtnDesc
.initialOrder
= kDataBrowserOrderIncreasing
;
6375 colDesc
.headerBtnDesc
.btnFontStyle
.flags
= 0; // use default font
6376 colDesc
.headerBtnDesc
.btnContentInfo
.contentType
= kControlContentTextOnly
;
6378 AddDataBrowserListViewColumn(dataBrowser
, &colDesc
, 0);
6380 // create tabline popup menu required by vim docs (see :he tabline-menu)
6381 CreateNewMenu(kTabContextMenuId
, 0, &contextMenu
);
6382 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("Close"), 0,
6383 TABLINE_MENU_CLOSE
, NULL
);
6384 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("New Tab"), 0,
6385 TABLINE_MENU_NEW
, NULL
);
6386 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("Open Tab..."), 0,
6387 TABLINE_MENU_OPEN
, NULL
);
6392 * Show or hide the tabline.
6395 gui_mch_show_tabline(int showit
)
6398 CloseDrawer(drawer
, true);
6400 OpenDrawer(drawer
, kWindowEdgeRight
, true);
6404 * Return TRUE when tabline is displayed.
6407 gui_mch_showing_tabline(void)
6409 WindowDrawerState state
= GetDrawerState(drawer
);
6411 return state
== kWindowDrawerOpen
|| state
== kWindowDrawerOpening
;
6415 * Update the labels of the tabline.
6418 gui_mch_update_tabline(void)
6421 int numTabs
= getTabCount();
6425 // adjust data browser
6426 if (tabLabels
!= NULL
)
6430 for (i
= 0; i
< tabLabelsSize
; ++i
)
6431 CFRelease(tabLabels
[i
]);
6434 tabLabels
= (CFStringRef
*)malloc(numTabs
* sizeof(CFStringRef
));
6435 tabLabelsSize
= numTabs
;
6437 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
6441 tabLabels
[nr
-1] = getTabLabel(tp
);
6444 RemoveDataBrowserItems(dataBrowser
, kDataBrowserNoItem
, 0, NULL
,
6445 kDataBrowserItemNoProperty
);
6446 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6447 // can pass NULL for the id array
6448 AddDataBrowserItems(dataBrowser
, kDataBrowserNoItem
, numTabs
, NULL
,
6449 kDataBrowserItemNoProperty
);
6451 DataBrowserItemID item
= curtabidx
;
6452 SetDataBrowserSelectedItems(dataBrowser
, 1, &item
, kDataBrowserItemsAssign
);
6456 * Set the current tab to "nr". First tab is 1.
6459 gui_mch_set_curtab(nr
)
6462 DataBrowserItemID item
= nr
;
6463 SetDataBrowserSelectedItems(dataBrowser
, 1, &item
, kDataBrowserItemsAssign
);
6465 // TODO: call something like this?: (or restore scroll position, or...)
6466 RevealDataBrowserItem(dataBrowser
, item
, kTabsColumn
,
6467 kDataBrowserRevealOnly
);
6470 #endif // FEAT_GUI_TABLINE