1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Macintosh port by Dany St-Amant
7 * Port to MPW by Bernhard Pruemmer
8 * Initial Carbon port by Ammon Skidmore
10 * Do ":help uganda" in Vim to read copying and usage conditions.
11 * Do ":help credits" in Vim to see a list of people who contributed.
12 * See README.txt for an overview of the Vim source code.
16 * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x
17 * - Comments mentioning FAQ refer to the book:
18 * "Macworld Mac Programming FAQs" from "IDG Books"
22 * TODO: Change still to merge from the macvim's iDisk
24 * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse
25 * uses of MenuItemIndex, changes in gui_mch_set_shellsize,
26 * ScrapManager error handling.
27 * Comments about function remaining to Carbonize.
32 * * Clipboard does not work (at least some cases)
33 * * ATSU font rendering has some problems
34 * * Investigate and remove dead code (there is still lots of that)
37 #include <Devices.h> /* included first to avoid CR problems */
40 #define USE_CARBONIZED
41 #define USE_AEVENT /* Enable AEVENT */
42 #undef USE_OFFSETED_WINDOW /* Debugging feature: start Vim window OFFSETed */
44 /* Compile as CodeWarior External Editor */
45 #if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46 # define USE_AEVENT /* Need Apple Event Support */
49 /* Vim's Scrap flavor. */
50 #define VIMSCRAPFLAVOR 'VIM!'
52 # define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
54 # define SCRAPTEXTFLAVOR kScrapFlavorTypeText
57 static EventHandlerUPP mouseWheelHandlerUPP
= NULL
;
58 SInt32 gMacSystemVersion
;
61 # define USE_CARBONKEYHANDLER
63 static int im_is_active
= FALSE
;
65 static int im_start_row
= 0;
66 static int im_start_col
= 0;
69 #define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
71 static TSMDocumentID gTSMDocument
;
73 static void im_on_window_switch(int active
);
74 static EventHandlerUPP keyEventHandlerUPP
= NULL
;
75 static EventHandlerUPP winEventHandlerUPP
= NULL
;
77 static pascal OSStatus
gui_mac_handle_window_activate(
78 EventHandlerCallRef nextHandler
, EventRef theEvent
, void *data
);
80 static pascal OSStatus
gui_mac_handle_text_input(
81 EventHandlerCallRef nextHandler
, EventRef theEvent
, void *data
);
83 static pascal OSStatus
gui_mac_update_input_area(
84 EventHandlerCallRef nextHandler
, EventRef theEvent
);
86 static pascal OSStatus
gui_mac_unicode_key_event(
87 EventHandlerCallRef nextHandler
, EventRef theEvent
);
92 /* Include some file. TODO: move into os_mac.h */
94 #include <Resources.h>
95 #include <Processes.h>
97 # include <AppleEvents.h>
98 # include <AERegistry.h>
100 # include <Gestalt.h>
101 #if UNIVERSAL_INTERFACES_VERSION >= 0x0330
102 # include <ControlDefinitions.h>
103 # include <Navigation.h> /* Navigation only part of ?? */
106 /* Help Manager (balloon.h, HM prefixed functions) are not supported
107 * under Carbon (Jussi) */
109 /* New Help Interface for Mac, not implemented yet.*/
110 # include <MacHelp.h>
114 * These seem to be rectangle options. Why are they not found in
118 #define kCreateEmpty 2 /*1*/
119 #define kCreateRect 2
123 * Dany: Don't like those...
125 #define topLeft(r) (((Point*)&(r))[0])
126 #define botRight(r) (((Point*)&(r))[1])
129 /* Time of last mouse click, to detect double-click */
130 static long lastMouseTick
= 0;
133 static RgnHandle cursorRgn
;
134 static RgnHandle dragRgn
;
135 static Rect dragRect
;
136 static short dragRectEnbl
;
137 static short dragRectControl
;
139 /* This variable is set when waiting for an event, which is the only moment
140 * scrollbar dragging can be done directly. It's not allowed while commands
141 * are executed, because it may move the cursor and that may cause unexpected
142 * problems (e.g., while ":s" is working).
144 static int allow_scrollbar
= FALSE
;
146 /* Last mouse click caused contextual menu, (to provide proper release) */
147 static short clickIsPopup
;
149 /* Feedback Action for Scrollbar */
150 ControlActionUPP gScrollAction
;
151 ControlActionUPP gScrollDrag
;
153 /* Keeping track of which scrollbar is being dragged */
154 static ControlHandle dragged_sb
= NULL
;
156 /* Vector of char_u --> control index for hotkeys in dialogs */
157 static short *gDialogHotKeys
;
164 Boolean isPanelVisible
;
165 } gFontPanelInfo
= { 0, 0, 0, false };
168 # define USE_ATSUI_DRAWING
170 ATSUStyle gFontStyle
;
172 ATSUStyle gWideFontStyle
;
174 Boolean gIsFontFallbackSet
;
178 #define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
179 #define Red(c) ((c & 0x00FF0000) >> 16)
180 #define Green(c) ((c & 0x0000FF00) >> 8)
181 #define Blue(c) ((c & 0x000000FF) >> 0)
185 #define vk_Esc 0x35 /* -> 1B */
187 #define vk_F1 0x7A /* -> 10 */
188 #define vk_F2 0x78 /*0x63*/
189 #define vk_F3 0x63 /*0x76*/
190 #define vk_F4 0x76 /*0x60*/
191 #define vk_F5 0x60 /*0x61*/
192 #define vk_F6 0x61 /*0x62*/
193 #define vk_F7 0x62 /*0x63*/ /*?*/
203 #define vk_Clr 0x47 /* -> 1B (ESC) */
204 #define vk_Enter 0x4C /* -> 03 */
206 #define vk_Space 0x31 /* -> 20 */
207 #define vk_Tab 0x30 /* -> 09 */
208 #define vk_Return 0x24 /* -> 0D */
209 /* This is wrong for OSX, what is it for? */
210 #define vk_Delete 0X08 /* -> 08 BackSpace */
212 #define vk_Help 0x72 /* -> 05 */
213 #define vk_Home 0x73 /* -> 01 */
214 #define vk_PageUp 0x74 /* -> 0D */
215 #define vk_FwdDelete 0x75 /* -> 7F */
216 #define vk_End 0x77 /* -> 04 */
217 #define vk_PageDown 0x79 /* -> 0C */
219 #define vk_Up 0x7E /* -> 1E */
220 #define vk_Down 0x7D /* -> 1F */
221 #define vk_Left 0x7B /* -> 1C */
222 #define vk_Right 0x7C /* -> 1D */
224 #define vk_Undo vk_F1
226 #define vk_Copy vk_F3
227 #define vk_Paste vk_F4
228 #define vk_PrintScreen vk_F13
229 #define vk_SCrollLock vk_F14
230 #define vk_Pause vk_F15
231 #define vk_NumLock vk_Clr
232 #define vk_Insert vk_Help
246 {vk_Right
, 'k', 'r'},
265 /* {XK_Help, '%', '1'}, */
266 /* {XK_Undo, '&', '8'}, */
267 /* {XK_BackSpace, 'k', 'b'}, */
269 {vk_Delete
, 'k', 'b'},
271 {vk_Insert
, 'k', 'I'},
272 {vk_FwdDelete
, 'k', 'D'},
275 /* {XK_Prior, 'k', 'P'}, */
276 /* {XK_Next, 'k', 'N'}, */
277 /* {XK_Print, '%', '9'}, */
279 {vk_PageUp
, 'k', 'P'},
280 {vk_PageDown
, 'k', 'N'},
282 /* End of list marker: */
287 * ------------------------------------------------------------
288 * Forward declaration (for those needed)
289 * ------------------------------------------------------------
293 OSErr
HandleUnusedParms(const AppleEvent
*theAEvent
);
296 #ifdef FEAT_GUI_TABLINE
297 static void initialise_tabline(void);
298 static WindowRef drawer
= NULL
; // TODO: put into gui.h
301 #ifdef USE_ATSUI_DRAWING
302 static void gui_mac_set_font_attributes(GuiFont font
);
303 static void gui_mac_dispose_atsui_style(void);
307 * ------------------------------------------------------------
309 * ------------------------------------------------------------
315 * Allocate memory and convert the C-String passed in
316 * into a pascal string
321 C2Pascal_save(char_u
*Cstring
)
323 char_u
*PascalString
;
329 len
= STRLEN(Cstring
);
331 if (len
> 255) /* Truncate if necessary */
334 PascalString
= alloc(len
+ 1);
335 if (PascalString
!= NULL
)
337 mch_memmove(PascalString
+ 1, Cstring
, len
);
338 PascalString
[0] = len
;
345 * C2Pascal_save_and_remove_backslash
347 * Allocate memory and convert the C-String passed in
348 * into a pascal string. Also remove the backslash at the same time
353 C2Pascal_save_and_remove_backslash(char_u
*Cstring
)
355 char_u
*PascalString
;
359 len
= STRLEN(Cstring
);
361 if (len
> 255) /* Truncate if necessary */
364 PascalString
= alloc(len
+ 1);
365 if (PascalString
!= NULL
)
367 for (c
= Cstring
, p
= PascalString
+1, len
= 0; (*c
!= 0) && (len
< 255); c
++)
369 if ((*c
== '\\') && (c
[1] != 0))
377 PascalString
[0] = len
;
384 * Convert the modifiers of an Event into vim's modifiers (mouse)
388 EventModifiers2VimMouseModifiers(EventModifiers macModifiers
)
390 int_u vimModifiers
= 0x00;
392 if (macModifiers
& (shiftKey
| rightShiftKey
))
393 vimModifiers
|= MOUSE_SHIFT
;
394 if (macModifiers
& (controlKey
| rightControlKey
))
395 vimModifiers
|= MOUSE_CTRL
;
396 if (macModifiers
& (optionKey
| rightOptionKey
))
397 vimModifiers
|= MOUSE_ALT
;
399 /* Not yet supported */
400 if (macModifiers
& (cmdKey
)) /* There's no rightCmdKey */
401 vimModifiers
|= MOUSE_CMD
;
403 return (vimModifiers
);
407 * Convert the modifiers of an Event into vim's modifiers (keys)
411 EventModifiers2VimModifiers(EventModifiers macModifiers
)
413 int_u vimModifiers
= 0x00;
415 if (macModifiers
& (shiftKey
| rightShiftKey
))
416 vimModifiers
|= MOD_MASK_SHIFT
;
417 if (macModifiers
& (controlKey
| rightControlKey
))
418 vimModifiers
|= MOD_MASK_CTRL
;
419 if (macModifiers
& (optionKey
| rightOptionKey
))
420 vimModifiers
|= MOD_MASK_ALT
;
422 if (macModifiers
& (cmdKey
)) /* There's no rightCmdKey */
423 vimModifiers
|= MOD_MASK_CMD
;
425 return (vimModifiers
);
428 /* Convert a string representing a point size into pixels. The string should
429 * be a positive decimal number, with an optional decimal point (eg, "12", or
430 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
431 * character is stored in *end. The flag "vertical" says whether this
432 * calculation is for a vertical (height) size or a horizontal (width) one.
437 points_to_pixels(char_u
*str
, char_u
**end
, int vertical
)
445 if (*str
== '.' && divisor
== 0)
447 /* Start keeping a divisor, for later */
456 points
+= *str
- '0';
465 pixels
= points
/divisor
;
472 * Deletes all traces of any Windows-style mnemonic text (including any
473 * parentheses) from a menu item and returns the cleaned menu item title.
474 * The caller is responsible for releasing the returned string.
477 menu_title_removing_mnemonic(vimmenu_T
*menu
)
482 CFRange mnemonicStart
;
484 CFMutableStringRef cleanedName
;
486 menuTitleLen
= STRLEN(menu
->dname
);
487 name
= (CFStringRef
) mac_enc_to_cfstring(menu
->dname
, menuTitleLen
);
491 /* Simple mnemonic-removal algorithm, assumes single parenthesized
492 * mnemonic character towards the end of the menu text */
493 mnemonicStart
= CFStringFind(name
, CFSTR("("), kCFCompareBackwards
);
494 displayLen
= CFStringGetLength(name
);
496 if (mnemonicStart
.location
!= kCFNotFound
497 && (mnemonicStart
.location
+ 2) < displayLen
498 && CFStringGetCharacterAtIndex(name
,
499 mnemonicStart
.location
+ 1) == (UniChar
)menu
->mnemonic
)
501 if (CFStringFindWithOptions(name
, CFSTR(")"),
502 CFRangeMake(mnemonicStart
.location
+ 1,
503 displayLen
- mnemonicStart
.location
- 1),
504 kCFCompareBackwards
, &mnemonicEnd
) &&
505 (mnemonicStart
.location
+ 2) == mnemonicEnd
.location
)
507 cleanedName
= CFStringCreateMutableCopy(NULL
, 0, name
);
510 CFStringDelete(cleanedName
,
511 CFRangeMake(mnemonicStart
.location
,
512 mnemonicEnd
.location
+ 1 -
513 mnemonicStart
.location
));
527 * Convert a list of FSSpec aliases into a list of fullpathname
532 new_fnames_from_AEDesc(AEDesc
*theList
, long *numFiles
, OSErr
*error
)
534 char_u
**fnames
= NULL
;
539 AEKeyword dummyKeyword
;
542 /* Get number of files in list */
543 *error
= AECountItems(theList
, numFiles
);
547 /* Allocate the pointer list */
548 fnames
= (char_u
**) alloc(*numFiles
* sizeof(char_u
*));
550 /* Empty out the list */
551 for (fileCount
= 0; fileCount
< *numFiles
; fileCount
++)
552 fnames
[fileCount
] = NULL
;
554 /* Scan the list of FSSpec */
555 for (fileCount
= 1; fileCount
<= *numFiles
; fileCount
++)
557 /* Get the alias for the nth file, convert to an FSSpec */
558 newError
= AEGetNthPtr(theList
, fileCount
, typeFSS
,
559 &dummyKeyword
, &dummyType
,
560 (Ptr
) &fileToOpen
, sizeof(FSSpec
), &actualSize
);
563 /* Caller is able to clean up */
564 /* TODO: Should be clean up or not? For safety. */
568 /* Convert the FSSpec to a pathname */
569 fnames
[fileCount
- 1] = FullPathFromFSSpec_save(fileToOpen
);
576 * ------------------------------------------------------------
577 * CodeWarrior External Editor Support
578 * ------------------------------------------------------------
580 #ifdef FEAT_CW_EDITOR
583 * Handle the Window Search event from CodeWarrior
588 * The IDE sends the Window Search AppleEvent to the editor when it
589 * needs to know whether a particular file is open in the editor.
594 * None. Put data in the location specified in the structure received.
599 * When the editor receives this event, determine whether the specified
600 * file is open. If it is, return the modification date/time for that file
601 * in the appropriate location specified in the structure. If the file is
602 * not opened, put the value fnfErr(file not found) in that location.
606 typedef struct WindowSearch WindowSearch
;
607 struct WindowSearch
/* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
609 FSSpec theFile
; // identifies the file
610 long *theDate
; // where to put the modification date/time
615 const AppleEvent
*theAEvent
,
616 AppleEvent
*theReply
,
621 int foundFile
= false;
623 WindowSearch SearchData
;
626 error
= AEGetParamPtr(theAEvent
, keyDirectObject
, typeChar
, &typeCode
, (Ptr
) &SearchData
, sizeof(WindowSearch
), &actualSize
);
630 error
= HandleUnusedParms(theAEvent
);
634 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
635 if (buf
->b_ml
.ml_mfp
!= NULL
636 && SearchData
.theFile
.parID
== buf
->b_FSSpec
.parID
637 && SearchData
.theFile
.name
[0] == buf
->b_FSSpec
.name
[0]
638 && STRNCMP(SearchData
.theFile
.name
, buf
->b_FSSpec
.name
, buf
->b_FSSpec
.name
[0] + 1) == 0)
644 if (foundFile
== false)
645 *SearchData
.theDate
= fnfErr
;
647 *SearchData
.theDate
= buf
->b_mtime
;
653 * Handle the Modified (from IDE to Editor) event from CodeWarrior
658 * The IDE sends this event to the external editor when it wants to
659 * know which files that are open in the editor have been modified.
666 * The reply for this event is:
668 * keyDirectObject typeAEList required
669 * each element in the list is a structure of typeChar
674 * When building the reply event, include one element in the list for
675 * each open file that has been modified.
679 typedef struct ModificationInfo ModificationInfo
;
680 struct ModificationInfo
/* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
682 FSSpec theFile
; // identifies the file
683 long theDate
; // the date/time the file was last modified
684 short saved
; // set this to zero when replying, unused
689 const AppleEvent
*theAEvent
,
690 AppleEvent
*theReply
,
694 AEDescList replyList
;
696 ModificationInfo theFile
;
701 error
= HandleUnusedParms(theAEvent
);
706 /* replyObject.descriptorType = typeNull;
707 replyObject.dataHandle = nil;*/
709 /* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
710 error
= AECreateList(nil
, 0, false, &replyList
);
715 error
= AECountItems(&replyList
, &numFiles
);
717 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
718 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
726 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
727 if (buf
->b_ml
.ml_mfp
!= NULL
)
729 /* Add this file to the list */
730 theFile
.theFile
= buf
->b_FSSpec
;
731 theFile
.theDate
= buf
->b_mtime
;
732 /* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
733 error
= AEPutPtr(&replyList
, numFiles
, typeChar
, (Ptr
) &theFile
, sizeof(theFile
));
737 error
= AECountItems(&replyList
, &numFiles
);
740 /* We can add data only if something to reply */
741 error
= AEPutParamDesc(theReply
, keyDirectObject
, &replyList
);
743 if (replyList
.dataHandle
)
744 AEDisposeDesc(&replyList
);
750 * Handle the Get Text event from CodeWarrior
755 * The IDE sends the Get Text AppleEvent to the editor when it needs
756 * the source code from a file. For example, when the user issues a
757 * Check Syntax or Compile command, the compiler needs access to
758 * the source code contained in the file.
763 * None. Put data in locations specified in the structure received.
768 * When the editor receives this event, it must set the size of the handle
769 * in theText to fit the data in the file. It must then copy the entire
770 * contents of the specified file into the memory location specified in
775 typedef struct CW_GetText CW_GetText
;
776 struct CW_GetText
/* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
778 FSSpec theFile
; /* identifies the file */
779 Handle theText
; /* the location where you return the text (must be resized properly) */
780 long *unused
; /* 0 (not used) */
781 long *theDate
; /* where to put the modification date/time */
786 const AppleEvent
*theAEvent
,
787 AppleEvent
*theReply
,
792 int foundFile
= false;
794 CW_GetText GetTextData
;
797 char_u
*fullbuffer
= NULL
;
803 error
= AEGetParamPtr(theAEvent
, keyDirectObject
, typeChar
, &typeCode
, (Ptr
) &GetTextData
, sizeof(GetTextData
), &actualSize
);
808 for (buf
= firstbuf
; buf
!= NULL
; buf
= buf
->b_next
)
809 if (buf
->b_ml
.ml_mfp
!= NULL
)
810 if (GetTextData
.theFile
.parID
== buf
->b_FSSpec
.parID
)
818 BufferSize
= 0; /* GetHandleSize(GetTextData.theText); */
819 for (lineno
= 0; lineno
<= buf
->b_ml
.ml_line_count
; lineno
++)
821 /* Must use the right buffer */
822 line
= ml_get_buf(buf
, (linenr_T
) lineno
, FALSE
);
823 linesize
= STRLEN(line
) + 1;
824 lineStart
= BufferSize
;
825 BufferSize
+= linesize
;
826 /* Resize handle to linesize+1 to include the linefeed */
827 SetHandleSize(GetTextData
.theText
, BufferSize
);
828 if (GetHandleSize(GetTextData
.theText
) != BufferSize
)
830 break; /* Simple handling for now */
834 HLock(GetTextData
.theText
);
835 fullbuffer
= (char_u
*) *GetTextData
.theText
;
836 STRCPY((char_u
*)(fullbuffer
+ lineStart
), line
);
837 fullbuffer
[BufferSize
-1] = '\r';
838 HUnlock(GetTextData
.theText
);
841 if (fullbuffer
!= NULL
)
843 HLock(GetTextData
.theText
);
844 fullbuffer
[BufferSize
-1] = 0;
845 HUnlock(GetTextData
.theText
);
847 if (foundFile
== false)
848 *GetTextData
.theDate
= fnfErr
;
850 /* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
851 *GetTextData
.theDate
= buf
->b_mtime
;
854 error
= HandleUnusedParms(theAEvent
);
863 /* Taken from MoreAppleEvents:ProcessHelpers*/
865 FindProcessBySignature(
866 const OSType targetType
,
867 const OSType targetCreator
,
868 ProcessSerialNumberPtr psnPtr
)
871 Boolean lookingForProcess
= true;
873 ProcessInfoRec infoRec
;
875 infoRec
.processInfoLength
= sizeof(ProcessInfoRec
);
876 infoRec
.processName
= nil
;
877 infoRec
.processAppSpec
= nil
;
879 psnPtr
->lowLongOfPSN
= kNoProcess
;
880 psnPtr
->highLongOfPSN
= kNoProcess
;
882 while (lookingForProcess
)
884 anErr
= GetNextProcess(psnPtr
);
886 lookingForProcess
= false;
889 anErr
= GetProcessInformation(psnPtr
, &infoRec
);
891 && (infoRec
.processType
== targetType
)
892 && (infoRec
.processSignature
== targetCreator
))
893 lookingForProcess
= false;
898 }//end FindProcessBySignature
901 Send_KAHL_MOD_AE(buf_T
*buf
)
904 AEDesc targetAppDesc
= { typeNull
, nil
};
905 ProcessSerialNumber psn
= { kNoProcess
, kNoProcess
};
906 AppleEvent theReply
= { typeNull
, nil
};
908 AppleEvent theEvent
= {typeNull
, nil
};
909 AEIdleUPP idleProcUPP
= nil
;
910 ModificationInfo ModData
;
913 anErr
= FindProcessBySignature('APPL', 'CWIE', &psn
);
916 anErr
= AECreateDesc(typeProcessSerialNumber
, &psn
,
917 sizeof(ProcessSerialNumber
), &targetAppDesc
);
921 anErr
= AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc
,
922 kAutoGenerateReturnID
, kAnyTransactionID
, &theEvent
);
925 AEDisposeDesc(&targetAppDesc
);
928 ModData
.theFile
= buf
->b_FSSpec
;
929 ModData
.theDate
= buf
->b_mtime
;
932 anErr
= AEPutParamPtr(&theEvent
, keyDirectObject
, typeChar
, &ModData
, sizeof(ModData
));
934 if (idleProcUPP
== nil
)
935 sendMode
= kAENoReply
;
937 sendMode
= kAEWaitReply
;
940 anErr
= AESend(&theEvent
, &theReply
, sendMode
, kAENormalPriority
, kNoTimeOut
, idleProcUPP
, nil
);
941 if (anErr
== noErr
&& sendMode
== kAEWaitReply
)
943 /* anErr = AEHGetHandlerError(&theReply);*/
945 (void) AEDisposeDesc(&theReply
);
948 #endif /* FEAT_CW_EDITOR */
951 * ------------------------------------------------------------
952 * Apple Event Handling procedure
953 * ------------------------------------------------------------
958 * Handle the Unused parms of an AppleEvent
962 HandleUnusedParms(const AppleEvent
*theAEvent
)
967 AEKeyword missedKeyword
;
969 /* Get the "missed keyword" attribute from the AppleEvent. */
970 error
= AEGetAttributePtr(theAEvent
, keyMissedKeywordAttr
,
971 typeKeyword
, &dummyType
,
972 (Ptr
)&missedKeyword
, sizeof(missedKeyword
),
975 /* If the descriptor isn't found, then we got the required parameters. */
976 if (error
== errAEDescNotFound
)
983 /* Why is this removed? */
984 error
= errAEEventNotHandled
;
993 * Handle the ODoc AppleEvent
995 * Deals with all files dragged to the application icon.
999 typedef struct SelectionRange SelectionRange
;
1000 struct SelectionRange
/* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1002 short unused1
; // 0 (not used)
1003 short lineNum
; // line to select (<0 to specify range)
1004 long startRange
; // start of selection range (if line < 0)
1005 long endRange
; // end of selection range (if line < 0)
1006 long unused2
; // 0 (not used)
1007 long theDate
; // modification date/time
1010 /* The IDE uses the optional keyAEPosition parameter to tell the ed-
1011 itor the selection range. If lineNum is zero or greater, scroll the text
1012 to the specified line. If lineNum is less than zero, use the values in
1013 startRange and endRange to select the specified characters. Scroll
1014 the text to display the selection. If lineNum, startRange, and
1015 endRange are all negative, there is no selection range specified.
1019 HandleODocAE(const AppleEvent
*theAEvent
, AppleEvent
*theReply
, long refCon
)
1022 * TODO: Clean up the code with convert the AppleEvent into
1025 OSErr error
= noErr
;
1026 // OSErr firstError = noErr;
1027 // short numErrors = 0;
1033 // char_u fname[256];
1035 SelectionRange thePosition
;
1036 short gotPosition
= false;
1039 /* the direct object parameter is the list of aliases to files (one or more) */
1040 error
= AEGetParamDesc(theAEvent
, keyDirectObject
, typeAEList
, &theList
);
1045 error
= AEGetParamPtr(theAEvent
, keyAEPosition
, typeChar
, &typeCode
, (Ptr
) &thePosition
, sizeof(SelectionRange
), &actualSize
);
1048 if (error
== errAEDescNotFound
)
1054 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1058 if (thePosition.lineNum >= 0)
1064 // Set the range char wise
1074 fnames
= new_fnames_from_AEDesc(&theList
, &numFiles
, &error
);
1078 /* TODO: empty fnames[] first */
1089 /* these are the initial files dropped on the Vim icon */
1090 for (i
= 0 ; i
< numFiles
; i
++)
1092 if (ga_grow(&global_alist
.al_ga
, 1) == FAIL
1093 || (p
= vim_strsave(fnames
[i
])) == NULL
)
1096 alist_add(&global_alist
, p
, 2);
1098 fnum
= GARGLIST
[GARGCOUNT
- 1].ae_fnum
;
1101 /* If the file name was already in the buffer list we need to switch
1103 if (curbuf
->b_fnum
!= fnum
)
1107 vim_snprintf((char *)cmd
, 30, "silent %dbuffer", fnum
);
1108 do_cmdline_cmd(cmd
);
1111 /* Change directory to the location of the first file. */
1112 if (GARGCOUNT
> 0 && vim_chdirfile(alist_name(&GARGLIST
[0])) == OK
)
1113 shorten_fnames(TRUE
);
1118 /* Handle the drop, :edit to get to the file */
1119 handle_drop(numFiles
, fnames
, FALSE
);
1121 /* TODO: Handle the goto/select line more cleanly */
1122 if ((numFiles
== 1) & (gotPosition
))
1124 if (thePosition
.lineNum
>= 0)
1126 lnum
= thePosition
.lineNum
+ 1;
1127 /* oap->motion_type = MLINE;
1131 else if (lnum
> curbuf
->b_ml
.ml_line_count
)
1132 lnum
= curbuf
->b_ml
.ml_line_count
;
1133 curwin
->w_cursor
.lnum
= lnum
;
1134 curwin
->w_cursor
.col
= 0;
1135 /* beginline(BL_SOL | BL_FIX);*/
1138 goto_byte(thePosition
.startRange
+ 1);
1141 /* Update the screen display */
1142 update_screen(NOT_VALID
);
1144 /* Select the text if possible */
1147 VIsual_active
= TRUE
;
1148 VIsual_select
= FALSE
;
1149 VIsual
= curwin
->w_cursor
;
1150 if (thePosition
.lineNum
< 0)
1153 goto_byte(thePosition
.endRange
);
1165 /* Fake mouse event to wake from stall */
1166 PostEvent(mouseUp
, 0);
1169 AEDisposeDesc(&theList
); /* dispose what we allocated */
1171 error
= HandleUnusedParms(theAEvent
);
1180 Handle_aevt_oapp_AE(
1181 const AppleEvent
*theAEvent
,
1182 AppleEvent
*theReply
,
1185 OSErr error
= noErr
;
1187 error
= HandleUnusedParms(theAEvent
);
1196 Handle_aevt_quit_AE(
1197 const AppleEvent
*theAEvent
,
1198 AppleEvent
*theReply
,
1201 OSErr error
= noErr
;
1203 error
= HandleUnusedParms(theAEvent
);
1207 /* Need to fake a :confirm qa */
1208 do_cmdline_cmd((char_u
*)"confirm qa");
1218 Handle_aevt_pdoc_AE(
1219 const AppleEvent
*theAEvent
,
1220 AppleEvent
*theReply
,
1223 OSErr error
= noErr
;
1225 error
= HandleUnusedParms(theAEvent
);
1231 * Handling of unknown AppleEvent
1233 * (Just get rid of all the parms)
1237 const AppleEvent
*theAEvent
,
1238 AppleEvent
*theReply
,
1241 OSErr error
= noErr
;
1243 error
= HandleUnusedParms(theAEvent
);
1250 * Install the various AppleEvent Handlers
1253 InstallAEHandlers(void)
1257 /* install open application handler */
1258 error
= AEInstallEventHandler(kCoreEventClass
, kAEOpenApplication
,
1259 NewAEEventHandlerUPP(Handle_aevt_oapp_AE
), 0, false);
1265 /* install quit application handler */
1266 error
= AEInstallEventHandler(kCoreEventClass
, kAEQuitApplication
,
1267 NewAEEventHandlerUPP(Handle_aevt_quit_AE
), 0, false);
1273 /* install open document handler */
1274 error
= AEInstallEventHandler(kCoreEventClass
, kAEOpenDocuments
,
1275 NewAEEventHandlerUPP(HandleODocAE
), 0, false);
1281 /* install print document handler */
1282 error
= AEInstallEventHandler(kCoreEventClass
, kAEPrintDocuments
,
1283 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE
), 0, false);
1285 /* Install Core Suite */
1286 /* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
1287 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1289 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
1290 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1292 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
1293 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1295 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
1296 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1298 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
1299 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1301 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
1302 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1304 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
1305 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
1307 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
1308 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
1310 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
1311 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1313 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
1314 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1316 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
1317 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1319 error = AEInstallEventHandler(kAECoreSuite, kAESave,
1320 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1322 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
1323 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
1326 #ifdef FEAT_CW_EDITOR
1328 * Bind codewarrior support handlers
1330 error
= AEInstallEventHandler('KAHL', 'GTTX',
1331 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE
), 0, false);
1336 error
= AEInstallEventHandler('KAHL', 'SRCH',
1337 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE
), 0, false);
1342 error
= AEInstallEventHandler('KAHL', 'MOD ',
1343 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE
), 0, false);
1353 #endif /* USE_AEVENT */
1357 * Callback function, installed by InstallFontPanelHandler(), below,
1358 * to handle Font Panel events.
1362 EventHandlerCallRef inHandlerCallRef
,
1366 if (GetEventKind(inEvent
) == kEventFontPanelClosed
)
1368 gFontPanelInfo
.isPanelVisible
= false;
1372 if (GetEventKind(inEvent
) == kEventFontSelection
)
1375 FMFontFamily newFamily
;
1377 FMFontStyle newStyle
;
1379 /* Retrieve the font family ID number. */
1380 status
= GetEventParameter(inEvent
, kEventParamFMFontFamily
,
1381 /*inDesiredType=*/typeFMFontFamily
, /*outActualType=*/NULL
,
1382 /*inBufferSize=*/sizeof(FMFontFamily
), /*outActualSize=*/NULL
,
1384 if (status
== noErr
)
1385 gFontPanelInfo
.family
= newFamily
;
1387 /* Retrieve the font size. */
1388 status
= GetEventParameter(inEvent
, kEventParamFMFontSize
,
1389 typeFMFontSize
, NULL
, sizeof(FMFontSize
), NULL
, &newSize
);
1390 if (status
== noErr
)
1391 gFontPanelInfo
.size
= newSize
;
1393 /* Retrieve the font style (bold, etc.). Currently unused. */
1394 status
= GetEventParameter(inEvent
, kEventParamFMFontStyle
,
1395 typeFMFontStyle
, NULL
, sizeof(FMFontStyle
), NULL
, &newStyle
);
1396 if (status
== noErr
)
1397 gFontPanelInfo
.style
= newStyle
;
1404 InstallFontPanelHandler(void)
1406 EventTypeSpec eventTypes
[2];
1407 EventHandlerUPP handlerUPP
;
1408 /* EventHandlerRef handlerRef; */
1410 eventTypes
[0].eventClass
= kEventClassFont
;
1411 eventTypes
[0].eventKind
= kEventFontSelection
;
1412 eventTypes
[1].eventClass
= kEventClassFont
;
1413 eventTypes
[1].eventKind
= kEventFontPanelClosed
;
1415 handlerUPP
= NewEventHandlerUPP(FontPanelHandler
);
1417 InstallApplicationEventHandler(handlerUPP
, /*numTypes=*/2, eventTypes
,
1418 /*userData=*/NULL
, /*handlerRef=*/NULL
);
1423 * Fill the buffer pointed to by outName with the name and size
1424 * of the font currently selected in the Font Panel.
1426 #define FONT_STYLE_BUFFER_SIZE 32
1428 GetFontPanelSelection(char_u
*outName
)
1431 ByteCount fontNameLen
= 0;
1433 char_u styleString
[FONT_STYLE_BUFFER_SIZE
];
1438 if (FMGetFontFamilyName(gFontPanelInfo
.family
, buf
) == noErr
)
1440 /* Canonicalize localized font names */
1441 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo
.family
,
1442 gFontPanelInfo
.style
, &fid
, NULL
) != noErr
)
1445 /* Request font name with Mac encoding (otherwise we could
1446 * get an unwanted utf-16 name) */
1447 if (ATSUFindFontName(fid
, kFontFullName
, kFontMacintoshPlatform
,
1448 kFontNoScriptCode
, kFontNoLanguageCode
,
1449 255, (char *)outName
, &fontNameLen
, NULL
) != noErr
)
1452 /* Only encode font size, because style (bold, italic, etc) is
1453 * already part of the font full name */
1454 vim_snprintf((char *)styleString
, FONT_STYLE_BUFFER_SIZE
, ":h%d",
1455 gFontPanelInfo
.size
/*,
1456 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1457 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1458 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1460 if ((fontNameLen
+ STRLEN(styleString
)) < 255)
1461 STRCPY(outName
+ fontNameLen
, styleString
);
1471 * ------------------------------------------------------------
1473 * ------------------------------------------------------------
1477 * gui_mac_get_menu_item_index
1479 * Returns the index inside the menu wher
1481 short /* Shoulde we return MenuItemIndex? */
1482 gui_mac_get_menu_item_index(vimmenu_T
*pMenu
)
1485 short itemIndex
= -1;
1486 vimmenu_T
*pBrother
;
1488 /* Only menu without parent are the:
1489 * -menu in the menubar
1493 * Which are not items anyway.
1497 /* Start from the Oldest Brother */
1498 pBrother
= pMenu
->parent
->children
;
1500 while ((pBrother
) && (itemIndex
== -1))
1502 if (pBrother
== pMenu
)
1505 pBrother
= pBrother
->next
;
1512 gui_mac_get_vim_menu(short menuID
, short itemIndex
, vimmenu_T
*pMenu
)
1515 vimmenu_T
*pChildMenu
;
1516 vimmenu_T
*pElder
= pMenu
->parent
;
1519 /* Only menu without parent are the:
1520 * -menu in the menubar
1524 * Which are not items anyway.
1527 if ((pElder
) && (pElder
->submenu_id
== menuID
))
1529 for (index
= 1; (index
!= itemIndex
) && (pMenu
!= NULL
); index
++)
1530 pMenu
= pMenu
->next
;
1534 for (; pMenu
!= NULL
; pMenu
= pMenu
->next
)
1536 if (pMenu
->children
!= NULL
)
1538 pChildMenu
= gui_mac_get_vim_menu
1539 (menuID
, itemIndex
, pMenu
->children
);
1552 * ------------------------------------------------------------
1553 * MacOS Feedback procedures
1554 * ------------------------------------------------------------
1558 gui_mac_drag_thumb(ControlHandle theControl
, short partCode
)
1561 int value
, dragging
;
1562 ControlHandle theControlToUse
;
1563 int dont_scroll_save
= dont_scroll
;
1565 theControlToUse
= dragged_sb
;
1567 sb
= gui_find_scrollbar((long) GetControlReference(theControlToUse
));
1572 /* Need to find value by diff between Old Poss New Pos */
1573 value
= GetControl32BitValue(theControlToUse
);
1574 dragging
= (partCode
!= 0);
1576 /* When "allow_scrollbar" is FALSE still need to remember the new
1577 * position, but don't actually scroll by setting "dont_scroll". */
1578 dont_scroll
= !allow_scrollbar
;
1579 gui_drag_scrollbar(sb
, value
, dragging
);
1580 dont_scroll
= dont_scroll_save
;
1585 gui_mac_scroll_action(ControlHandle theControl
, short partCode
)
1587 /* TODO: have live support */
1588 scrollbar_T
*sb
, *sb_info
;
1592 int dragging
= FALSE
;
1593 int dont_scroll_save
= dont_scroll
;
1595 sb
= gui_find_scrollbar((long)GetControlReference(theControl
));
1600 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
1603 * Careful: need to get scrollbar info out of first (left) scrollbar
1604 * for window, but keep real scrollbar too because we must pass it to
1605 * gui_drag_scrollbar().
1607 sb_info
= &sb
->wp
->w_scrollbars
[0];
1609 if (sb_info
->size
> 5)
1610 page
= sb_info
->size
- 2; /* use two lines of context */
1612 page
= sb_info
->size
;
1614 else /* Bottom scrollbar */
1617 page
= W_WIDTH(curwin
) - 5;
1622 case kControlUpButtonPart
: data
= -1; break;
1623 case kControlDownButtonPart
: data
= 1; break;
1624 case kControlPageDownPart
: data
= page
; break;
1625 case kControlPageUpPart
: data
= -page
; break;
1626 default: data
= 0; break;
1629 value
= sb_info
->value
+ data
;
1630 /* if (value > sb_info->max)
1631 value = sb_info->max;
1635 /* When "allow_scrollbar" is FALSE still need to remember the new
1636 * position, but don't actually scroll by setting "dont_scroll". */
1637 dont_scroll
= !allow_scrollbar
;
1638 gui_drag_scrollbar(sb
, value
, dragging
);
1639 dont_scroll
= dont_scroll_save
;
1642 gui_mch_set_scrollbar_thumb(sb
, value
, sb_info
->size
, sb_info
->max
);
1644 /* if (sb_info->wp != NULL)
1650 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1655 current_scrollbar = sb_num;
1656 scrollbar_value = value;
1658 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1664 * ------------------------------------------------------------
1665 * MacOS Click Handling procedures
1666 * ------------------------------------------------------------
1671 * Handle a click inside the window, it may happens in the
1672 * scrollbar or the contents.
1674 * TODO: Add support for potential TOOLBAR
1677 gui_mac_doInContentClick(EventRecord
*theEvent
, WindowPtr whichWindow
)
1682 ControlHandle theControl
;
1686 thePoint
= theEvent
->where
;
1687 GlobalToLocal(&thePoint
);
1688 SelectWindow(whichWindow
);
1690 thePortion
= FindControl(thePoint
, whichWindow
, &theControl
);
1692 if (theControl
!= NUL
)
1694 /* We hit a scollbar */
1696 if (thePortion
!= kControlIndicatorPart
)
1698 dragged_sb
= theControl
;
1699 TrackControl(theControl
, thePoint
, gScrollAction
);
1704 dragged_sb
= theControl
;
1706 TrackControl(theControl
, thePoint
, gScrollDrag
);
1708 TrackControl(theControl
, thePoint
, NULL
);
1710 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1711 * button has been released */
1712 gui_mac_drag_thumb(theControl
, 0); /* Should it be thePortion ? (Dany) */
1718 /* We are inside the contents */
1720 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1721 vimModifiers
= EventModifiers2VimMouseModifiers(theEvent
->modifiers
);
1723 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1724 vimMouseButton
= MOUSE_LEFT
;
1726 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
1728 clickIsPopup
= FALSE
;
1730 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent
))
1732 vimMouseButton
= MOUSE_RIGHT
;
1733 vimModifiers
&= ~MOUSE_CTRL
;
1734 clickIsPopup
= TRUE
;
1737 /* Is it a double click ? */
1738 dblClick
= ((theEvent
->when
- lastMouseTick
) < GetDblTime());
1740 /* Send the mouse click to Vim */
1741 gui_send_mouse_event(vimMouseButton
, thePoint
.h
,
1742 thePoint
.v
, dblClick
, vimModifiers
);
1744 /* Create the rectangle around the cursor to detect
1745 * the mouse dragging
1748 /* TODO: Do we need to this even for the contextual menu?
1749 * It may be require for popup_setpos, but for popup?
1751 if (vimMouseButton
== MOUSE_LEFT
)
1754 SetRect(&dragRect
, FILL_X(X_2_COL(thePoint
.h
)),
1755 FILL_Y(Y_2_ROW(thePoint
.v
)),
1756 FILL_X(X_2_COL(thePoint
.h
)+1),
1757 FILL_Y(Y_2_ROW(thePoint
.v
)+1));
1759 dragRectEnbl
= TRUE
;
1760 dragRectControl
= kCreateRect
;
1766 * Handle the click in the titlebar (to move the window)
1769 gui_mac_doInDragClick(Point where
, WindowPtr whichWindow
)
1772 Rect
*movingLimitsPtr
= &movingLimits
;
1774 /* TODO: may try to prevent move outside screen? */
1775 movingLimitsPtr
= GetRegionBounds(GetGrayRgn(), &movingLimits
);
1776 DragWindow(whichWindow
, where
, movingLimitsPtr
);
1780 * Handle the click in the grow box
1783 gui_mac_doInGrowClick(Point where
, WindowPtr whichWindow
)
1787 unsigned short newWidth
;
1788 unsigned short newHeight
;
1790 Rect
*resizeLimitsPtr
= &resizeLimits
;
1791 Rect NewContentRect
;
1793 resizeLimitsPtr
= GetRegionBounds(GetGrayRgn(), &resizeLimits
);
1795 /* Set the minimum size */
1796 /* TODO: Should this come from Vim? */
1797 resizeLimits
.top
= 100;
1798 resizeLimits
.left
= 100;
1800 newSize
= ResizeWindow(whichWindow
, where
, &resizeLimits
, &NewContentRect
);
1801 newWidth
= NewContentRect
.right
- NewContentRect
.left
;
1802 newHeight
= NewContentRect
.bottom
- NewContentRect
.top
;
1803 gui_resize_shell(newWidth
, newHeight
);
1804 gui_mch_set_bg_color(gui
.back_pixel
);
1805 gui_set_shellsize(TRUE
, FALSE
, RESIZE_BOTH
);
1809 * Handle the click in the zoom box
1812 gui_mac_doInZoomClick(EventRecord
*theEvent
, WindowPtr whichWindow
)
1818 /* ideal width is current */
1819 p
.h
= Columns
* gui
.char_width
+ 2 * gui
.border_offset
;
1820 if (gui
.which_scrollbars
[SBAR_LEFT
])
1821 p
.h
+= gui
.scrollbar_width
;
1822 if (gui
.which_scrollbars
[SBAR_RIGHT
])
1823 p
.h
+= gui
.scrollbar_width
;
1824 /* ideal height is as heigh as we can get */
1827 thePart
= IsWindowInStandardState(whichWindow
, &p
, &r
)
1828 ? inZoomIn
: inZoomOut
;
1830 if (!TrackBox(whichWindow
, theEvent
->where
, thePart
))
1833 /* use returned width */
1834 p
.h
= r
.right
- r
.left
;
1835 /* adjust returned height */
1836 p
.v
= r
.bottom
- r
.top
- 2 * gui
.border_offset
;
1837 if (gui
.which_scrollbars
[SBAR_BOTTOM
])
1838 p
.v
-= gui
.scrollbar_height
;
1839 p
.v
-= p
.v
% gui
.char_height
;
1840 p
.v
+= 2 * gui
.border_width
;
1841 if (gui
.which_scrollbars
[SBAR_BOTTOM
]);
1842 p
.v
+= gui
.scrollbar_height
;
1844 ZoomWindowIdeal(whichWindow
, thePart
, &p
);
1846 GetWindowBounds(whichWindow
, kWindowContentRgn
, &r
);
1847 gui_resize_shell(r
.right
- r
.left
, r
.bottom
- r
.top
);
1848 gui_mch_set_bg_color(gui
.back_pixel
);
1849 gui_set_shellsize(TRUE
, FALSE
, RESIZE_BOTH
);
1853 * ------------------------------------------------------------
1854 * MacOS Event Handling procedure
1855 * ------------------------------------------------------------
1859 * Handle the Update Event
1863 gui_mac_doUpdateEvent(EventRecord
*event
)
1865 WindowPtr whichWindow
;
1867 RgnHandle updateRgn
;
1869 Rect
*updateRectPtr
;
1875 updateRgn
= NewRgn();
1876 if (updateRgn
== NULL
)
1879 /* This could be done by the caller as we
1880 * don't require anything else out of the event
1882 whichWindow
= (WindowPtr
) event
->message
;
1884 /* Save Current Port */
1887 /* Select the Window's Port */
1888 SetPortWindowPort(whichWindow
);
1890 /* Let's update the window */
1891 BeginUpdate(whichWindow
);
1892 /* Redraw the biggest rectangle covering the area
1895 GetPortVisibleRegion(GetWindowPort(whichWindow
), updateRgn
);
1897 /* Would be more appropriate to use the following but doesn't
1898 * seem to work under MacOS X (Dany)
1900 GetWindowRegion(whichWindow
, kWindowUpdateRgn
, updateRgn
);
1903 /* Use the HLock useless in Carbon? Is it harmful?*/
1904 HLock((Handle
) updateRgn
);
1906 updateRectPtr
= GetRegionBounds(updateRgn
, &updateRect
);
1908 /* Code from original Carbon Port (using GetWindowRegion.
1909 * I believe the UpdateRgn is already in local (Dany)
1911 GlobalToLocal(&topLeft(updateRect
)); /* preCarbon? */
1912 GlobalToLocal(&botRight(updateRect
));
1914 /* Update the content (i.e. the text) */
1915 gui_redraw(updateRectPtr
->left
, updateRectPtr
->top
,
1916 updateRectPtr
->right
- updateRectPtr
->left
,
1917 updateRectPtr
->bottom
- updateRectPtr
->top
);
1918 /* Clear the border areas if needed */
1919 gui_mch_set_bg_color(gui
.back_pixel
);
1920 if (updateRectPtr
->left
< FILL_X(0))
1922 SetRect(&rc
, 0, 0, FILL_X(0), FILL_Y(Rows
));
1925 if (updateRectPtr
->top
< FILL_Y(0))
1927 SetRect(&rc
, 0, 0, FILL_X(Columns
), FILL_Y(0));
1930 if (updateRectPtr
->right
> FILL_X(Columns
))
1932 SetRect(&rc
, FILL_X(Columns
), 0,
1933 FILL_X(Columns
) + gui
.border_offset
, FILL_Y(Rows
));
1936 if (updateRectPtr
->bottom
> FILL_Y(Rows
))
1938 SetRect(&rc
, 0, FILL_Y(Rows
), FILL_X(Columns
) + gui
.border_offset
,
1939 FILL_Y(Rows
) + gui
.border_offset
);
1942 HUnlock((Handle
) updateRgn
);
1943 DisposeRgn(updateRgn
);
1945 /* Update scrollbars */
1946 DrawControls(whichWindow
);
1948 /* Update the GrowBox */
1949 /* Taken from FAQ 33-27 */
1951 GetWindowBounds(whichWindow
, kWindowGrowRgn
, &growRect
);
1953 ClipRect(&growRect
);
1954 DrawGrowIcon(whichWindow
);
1956 DisposeRgn(saveRgn
);
1957 EndUpdate(whichWindow
);
1959 /* Restore original Port */
1964 * Handle the activate/deactivate event
1965 * (apply to a window)
1968 gui_mac_doActivateEvent(EventRecord
*event
)
1970 WindowPtr whichWindow
;
1972 whichWindow
= (WindowPtr
) event
->message
;
1973 /* Dim scrollbars */
1974 if (whichWindow
== gui
.VimWindow
)
1976 ControlRef rootControl
;
1977 GetRootControl(gui
.VimWindow
, &rootControl
);
1978 if ((event
->modifiers
) & activeFlag
)
1979 ActivateControl(rootControl
);
1981 DeactivateControl(rootControl
);
1985 gui_focus_change((event
->modifiers
) & activeFlag
);
1990 * Handle the suspend/resume event
1991 * (apply to the application)
1994 gui_mac_doSuspendEvent(EventRecord
*event
)
1996 /* The frontmost application just changed */
1998 /* NOTE: the suspend may happen before the deactivate
2002 /* May not need to change focus as the window will
2003 * get an activate/deactivate event
2005 if (event
->message
& 1)
2007 gui_focus_change(TRUE
);
2010 gui_focus_change(FALSE
);
2016 #ifdef USE_CARBONKEYHANDLER
2017 static pascal OSStatus
2018 gui_mac_handle_window_activate(
2019 EventHandlerCallRef nextHandler
,
2023 UInt32 eventClass
= GetEventClass(theEvent
);
2024 UInt32 eventKind
= GetEventKind(theEvent
);
2026 if (eventClass
== kEventClassWindow
)
2030 case kEventWindowActivated
:
2031 #if defined(USE_IM_CONTROL)
2032 im_on_window_switch(TRUE
);
2036 case kEventWindowDeactivated
:
2037 #if defined(USE_IM_CONTROL)
2038 im_on_window_switch(FALSE
);
2044 return eventNotHandledErr
;
2047 static pascal OSStatus
2048 gui_mac_handle_text_input(
2049 EventHandlerCallRef nextHandler
,
2053 UInt32 eventClass
= GetEventClass(theEvent
);
2054 UInt32 eventKind
= GetEventKind(theEvent
);
2056 if (eventClass
!= kEventClassTextInput
)
2057 return eventNotHandledErr
;
2059 if ((kEventTextInputUpdateActiveInputArea
!= eventKind
) &&
2060 (kEventTextInputUnicodeForKeyEvent
!= eventKind
) &&
2061 (kEventTextInputOffsetToPos
!= eventKind
) &&
2062 (kEventTextInputPosToOffset
!= eventKind
) &&
2063 (kEventTextInputGetSelectedText
!= eventKind
))
2064 return eventNotHandledErr
;
2068 case kEventTextInputUpdateActiveInputArea
:
2069 return gui_mac_update_input_area(nextHandler
, theEvent
);
2070 case kEventTextInputUnicodeForKeyEvent
:
2071 return gui_mac_unicode_key_event(nextHandler
, theEvent
);
2073 case kEventTextInputOffsetToPos
:
2074 case kEventTextInputPosToOffset
:
2075 case kEventTextInputGetSelectedText
:
2079 return eventNotHandledErr
;
2083 OSStatus
gui_mac_update_input_area(
2084 EventHandlerCallRef nextHandler
,
2087 return eventNotHandledErr
;
2090 static int dialog_busy
= FALSE
; /* TRUE when gui_mch_dialog() wants the
2093 # define INLINE_KEY_BUFFER_SIZE 80
2094 static pascal OSStatus
2095 gui_mac_unicode_key_event(
2096 EventHandlerCallRef nextHandler
,
2099 /* Multibyte-friendly key event handler */
2103 char_u result
[INLINE_KEY_BUFFER_SIZE
];
2108 UInt32 modifiers
, vimModifiers
;
2111 Boolean isSpecial
= FALSE
;
2115 /* Mask the mouse (as per user setting) */
2119 /* Don't use the keys when the dialog wants them. */
2121 return eventNotHandledErr
;
2123 if (noErr
!= GetEventParameter(theEvent
, kEventParamTextInputSendText
,
2124 typeUnicodeText
, NULL
, 0, &actualSize
, NULL
))
2125 return eventNotHandledErr
;
2127 text
= (UniChar
*)alloc(actualSize
);
2129 return eventNotHandledErr
;
2131 err
= GetEventParameter(theEvent
, kEventParamTextInputSendText
,
2132 typeUnicodeText
, NULL
, actualSize
, NULL
, text
);
2133 require_noerr(err
, done
);
2135 err
= GetEventParameter(theEvent
, kEventParamTextInputSendKeyboardEvent
,
2136 typeEventRef
, NULL
, sizeof(EventRef
), NULL
, &keyEvent
);
2137 require_noerr(err
, done
);
2139 err
= GetEventParameter(keyEvent
, kEventParamKeyModifiers
,
2140 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &modifiers
);
2141 require_noerr(err
, done
);
2143 err
= GetEventParameter(keyEvent
, kEventParamKeyCode
,
2144 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &key_sym
);
2145 require_noerr(err
, done
);
2147 err
= GetEventParameter(keyEvent
, kEventParamKeyMacCharCodes
,
2148 typeChar
, NULL
, sizeof(char), NULL
, &charcode
);
2149 require_noerr(err
, done
);
2152 if (modifiers
& cmdKey
)
2153 goto done
; /* Let system handle Cmd+... */
2156 key_char
= charcode
;
2157 vimModifiers
= EventModifiers2VimModifiers(modifiers
);
2159 /* Find the special key (eg., for cursor keys) */
2160 if (actualSize
<= sizeof(UniChar
) &&
2161 ((text
[0] < 0x20) || (text
[0] == 0x7f)))
2163 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; ++i
)
2164 if (special_keys
[i
].key_sym
== key_sym
)
2166 key_char
= TO_SPECIAL(special_keys
[i
].vim_code0
,
2167 special_keys
[i
].vim_code1
);
2168 key_char
= simplify_key(key_char
,
2169 (int *)&vimModifiers
);
2175 /* Intercept CMD-. and CTRL-c */
2176 if (((modifiers
& controlKey
) && key_char
== 'c') ||
2177 ((modifiers
& cmdKey
) && key_char
== '.'))
2182 /* remove SHIFT for keys that are already shifted, e.g.,
2184 if (key_char
< 0x100 && !isalpha(key_char
) && isprint(key_char
))
2185 vimModifiers
&= ~MOD_MASK_SHIFT
;
2187 /* remove CTRL from keys that already have it */
2188 if (key_char
< 0x20)
2189 vimModifiers
&= ~MOD_MASK_CTRL
;
2191 /* don't process unicode characters here */
2192 if (!IS_SPECIAL(key_char
))
2194 /* Following code to simplify and consolidate vimModifiers
2195 * taken liberally from gui_w48.c */
2196 key_char
= simplify_key(key_char
, (int *)&vimModifiers
);
2198 /* Interpret META, include SHIFT, etc. */
2199 key_char
= extract_modifiers(key_char
, (int *)&vimModifiers
);
2200 if (key_char
== CSI
)
2203 if (IS_SPECIAL(key_char
))
2210 result
[len
++] = CSI
;
2211 result
[len
++] = KS_MODIFIER
;
2212 result
[len
++] = vimModifiers
;
2215 if (isSpecial
&& IS_SPECIAL(key_char
))
2217 result
[len
++] = CSI
;
2218 result
[len
++] = K_SECOND(key_char
);
2219 result
[len
++] = K_THIRD(key_char
);
2223 encLen
= actualSize
;
2224 to
= mac_utf16_to_enc(text
, actualSize
, &encLen
);
2227 /* This is basically add_to_input_buf_csi() */
2228 for (i
= 0; i
< encLen
&& len
< (INLINE_KEY_BUFFER_SIZE
-1); ++i
)
2230 result
[len
++] = to
[i
];
2233 result
[len
++] = KS_EXTRA
;
2234 result
[len
++] = (int)KE_CSI
;
2241 add_to_input_buf(result
, len
);
2248 /* Fake event to wake up WNE (required to get
2249 * key repeat working */
2250 PostEvent(keyUp
, 0);
2254 return eventNotHandledErr
;
2258 gui_mac_doKeyEvent(EventRecord
*theEvent
)
2260 /* TODO: add support for COMMAND KEY */
2262 unsigned char string
[20];
2268 int simplify
= FALSE
;
2270 /* Mask the mouse (as per user setting) */
2274 /* Get the key code and it's ASCII representation */
2275 key_sym
= ((theEvent
->message
& keyCodeMask
) >> 8);
2276 key_char
= theEvent
->message
& charCodeMask
;
2279 /* Intercept CTRL-C */
2280 if (theEvent
->modifiers
& controlKey
)
2282 if (key_char
== Ctrl_C
&& ctrl_c_interrupts
)
2284 else if ((theEvent
->modifiers
& ~(controlKey
|shiftKey
)) == 0
2285 && (key_char
== '2' || key_char
== '6'))
2287 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2288 if (key_char
== '2')
2291 key_char
= Ctrl_HAT
;
2292 theEvent
->modifiers
= 0;
2296 /* Intercept CMD-. */
2297 if (theEvent
->modifiers
& cmdKey
)
2298 if (key_char
== '.')
2301 /* Handle command key as per menu */
2302 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2303 if (theEvent
->modifiers
& cmdKey
)
2304 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2305 * Why the mouse button? */
2306 if ((theEvent
->modifiers
& (~(cmdKey
| btnState
| alphaLock
))) == 0)
2308 menu
= MenuKey(key_char
);
2311 gui_mac_handle_menu(menu
);
2316 /* Convert the modifiers */
2317 modifiers
= EventModifiers2VimModifiers(theEvent
->modifiers
);
2320 /* Handle special keys. */
2322 /* Why has this been removed? */
2323 if (!(theEvent
->modifiers
& (cmdKey
| controlKey
| rightControlKey
)))
2326 /* Find the special key (for non-printable keyt_char) */
2327 if ((key_char
< 0x20) || (key_char
== 0x7f))
2328 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; i
++)
2329 if (special_keys
[i
].key_sym
== key_sym
)
2332 /* We currently don't have not so special key */
2333 if (special_keys
[i
].vim_code1
== NUL
)
2334 key_char
= special_keys
[i
].vim_code0
;
2337 key_char
= TO_SPECIAL(special_keys
[i
].vim_code0
,
2338 special_keys
[i
].vim_code1
);
2344 /* For some keys the modifier is included in the char itself. */
2345 if (simplify
|| key_char
== TAB
|| key_char
== ' ')
2346 key_char
= simplify_key(key_char
, &modifiers
);
2348 /* Add the modifier to the input bu if needed */
2349 /* Do not want SHIFT-A or CTRL-A with modifier */
2350 if (!IS_SPECIAL(key_char
)
2351 && key_sym
!= vk_Space
2352 && key_sym
!= vk_Tab
2353 && key_sym
!= vk_Return
2354 && key_sym
!= vk_Enter
2355 && key_sym
!= vk_Esc
)
2358 /* Clear modifiers when only one modifier is set */
2359 if ((modifiers
== MOD_MASK_SHIFT
)
2360 || (modifiers
== MOD_MASK_CTRL
)
2361 || (modifiers
== MOD_MASK_ALT
))
2364 if (modifiers
& MOD_MASK_CTRL
)
2365 modifiers
= modifiers
& ~MOD_MASK_CTRL
;
2366 if (modifiers
& MOD_MASK_ALT
)
2367 modifiers
= modifiers
& ~MOD_MASK_ALT
;
2368 if (modifiers
& MOD_MASK_SHIFT
)
2369 modifiers
= modifiers
& ~MOD_MASK_SHIFT
;
2374 string
[len
++] = CSI
;
2375 string
[len
++] = KS_MODIFIER
;
2376 string
[len
++] = modifiers
;
2379 if (IS_SPECIAL(key_char
))
2381 string
[len
++] = CSI
;
2382 string
[len
++] = K_SECOND(key_char
);
2383 string
[len
++] = K_THIRD(key_char
);
2388 /* Convert characters when needed (e.g., from MacRoman to latin1).
2389 * This doesn't work for the NUL byte. */
2390 if (input_conv
.vc_type
!= CONV_NONE
&& key_char
> 0)
2392 char_u from
[2], *to
;
2398 to
= string_convert(&input_conv
, from
, &l
);
2401 for (i
= 0; i
< l
&& len
< 19; i
++)
2405 string
[len
++] = KS_EXTRA
;
2406 string
[len
++] = KE_CSI
;
2409 string
[len
++] = to
[i
];
2414 string
[len
++] = key_char
;
2418 string
[len
++] = key_char
;
2421 if (len
== 1 && string
[0] == CSI
)
2423 /* Turn CSI into K_CSI. */
2424 string
[ len
++ ] = KS_EXTRA
;
2425 string
[ len
++ ] = KE_CSI
;
2428 add_to_input_buf(string
, len
);
2436 gui_mac_doMouseDownEvent(EventRecord
*theEvent
)
2439 WindowPtr whichWindow
;
2441 thePart
= FindWindow(theEvent
->where
, &whichWindow
);
2443 #ifdef FEAT_GUI_TABLINE
2444 /* prevent that the vim window size changes if it's activated by a
2445 click into the tab pane */
2446 if (whichWindow
== drawer
)
2453 /* TODO: what to do? */
2457 gui_mac_handle_menu(MenuSelect(theEvent
->where
));
2461 gui_mac_doInContentClick(theEvent
, whichWindow
);
2465 gui_mac_doInDragClick(theEvent
->where
, whichWindow
);
2469 gui_mac_doInGrowClick(theEvent
->where
, whichWindow
);
2473 if (TrackGoAway(whichWindow
, theEvent
->where
))
2479 gui_mac_doInZoomClick(theEvent
, whichWindow
);
2486 * [this event is a moving in and out of a region]
2489 gui_mac_doMouseMovedEvent(EventRecord
*event
)
2494 thePoint
= event
->where
;
2495 GlobalToLocal(&thePoint
);
2496 vimModifiers
= EventModifiers2VimMouseModifiers(event
->modifiers
);
2499 gui_mouse_moved(thePoint
.h
, thePoint
.v
);
2502 gui_send_mouse_event(MOUSE_DRAG
, thePoint
.h
,
2503 thePoint
.v
, FALSE
, vimModifiers
);
2505 /* Reset the region from which we move in and out */
2506 SetRect(&dragRect
, FILL_X(X_2_COL(thePoint
.h
)),
2507 FILL_Y(Y_2_ROW(thePoint
.v
)),
2508 FILL_X(X_2_COL(thePoint
.h
)+1),
2509 FILL_Y(Y_2_ROW(thePoint
.v
)+1));
2512 dragRectControl
= kCreateRect
;
2517 * Handle the mouse release
2520 gui_mac_doMouseUpEvent(EventRecord
*theEvent
)
2525 /* TODO: Properly convert the Contextual menu mouse-up */
2526 /* Potential source of the double menu */
2527 lastMouseTick
= theEvent
->when
;
2528 dragRectEnbl
= FALSE
;
2529 dragRectControl
= kCreateEmpty
;
2530 thePoint
= theEvent
->where
;
2531 GlobalToLocal(&thePoint
);
2533 vimModifiers
= EventModifiers2VimMouseModifiers(theEvent
->modifiers
);
2536 vimModifiers
&= ~MOUSE_CTRL
;
2537 clickIsPopup
= FALSE
;
2539 gui_send_mouse_event(MOUSE_RELEASE
, thePoint
.h
, thePoint
.v
, FALSE
, vimModifiers
);
2542 static pascal OSStatus
2543 gui_mac_mouse_wheel(EventHandlerCallRef nextHandler
, EventRef theEvent
,
2551 EventMouseWheelAxis axis
;
2553 if (noErr
== GetEventParameter(theEvent
, kEventParamMouseWheelAxis
,
2554 typeMouseWheelAxis
, NULL
, sizeof(axis
), NULL
, &axis
)
2555 && axis
!= kEventMouseWheelAxisY
)
2556 goto bail
; /* Vim only does up-down scrolling */
2558 if (noErr
!= GetEventParameter(theEvent
, kEventParamMouseWheelDelta
,
2559 typeSInt32
, NULL
, sizeof(SInt32
), NULL
, &delta
))
2561 if (noErr
!= GetEventParameter(theEvent
, kEventParamMouseLocation
,
2562 typeQDPoint
, NULL
, sizeof(Point
), NULL
, &point
))
2564 if (noErr
!= GetEventParameter(theEvent
, kEventParamKeyModifiers
,
2565 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &mod
))
2570 vim_mod
|= MOUSE_SHIFT
;
2571 if (mod
& controlKey
)
2572 vim_mod
|= MOUSE_CTRL
;
2573 if (mod
& optionKey
)
2574 vim_mod
|= MOUSE_ALT
;
2576 if (noErr
== GetWindowBounds(gui
.VimWindow
, kWindowContentRgn
, &bounds
))
2578 point
.h
-= bounds
.left
;
2579 point
.v
-= bounds
.top
;
2582 gui_send_mouse_event((delta
> 0) ? MOUSE_4
: MOUSE_5
,
2583 point
.h
, point
.v
, FALSE
, vim_mod
);
2585 /* post a bogus event to wake up WaitNextEvent */
2586 PostEvent(keyUp
, 0);
2592 * when we fail give any additional callback handler a chance to perform
2595 return CallNextEventHandler(nextHandler
, theEvent
);
2601 * This would be the normal way of invoking the contextual menu
2602 * but the Vim API doesn't seem to a support a request to get
2603 * the menu that we should display
2606 gui_mac_handle_contextual_menu(event
)
2610 * Clone PopUp to use menu
2611 * Create a object descriptor for the current selection
2612 * Call the procedure
2615 // Call to Handle Popup
2616 OSStatus status
= ContextualMenuSelect(CntxMenu
, event
->where
, false, kCMHelpItemNoHelp
, "", NULL
, &CntxType
, &CntxMenuID
, &CntxMenuItem
);
2618 if (status
!= noErr
)
2621 if (CntxType
== kCMMenuItemSelected
)
2623 /* Handle the menu CntxMenuID, CntxMenuItem */
2624 /* The submenu can be handle directly by gui_mac_handle_menu */
2625 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
2626 gui_mac_handle_menu((CntxMenuID
<< 16) + CntxMenuItem
);
2628 else if (CntxMenuID
== kCMShowHelpSelected
)
2630 /* Should come up with the help */
2637 * Handle menubar selection
2640 gui_mac_handle_menu(long menuChoice
)
2642 short menu
= HiWord(menuChoice
);
2643 short item
= LoWord(menuChoice
);
2644 vimmenu_T
*theVimMenu
= root_menu
;
2646 if (menu
== 256) /* TODO: use constant or gui.xyz */
2649 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
2653 theVimMenu
= gui_mac_get_vim_menu(menu
, item
, root_menu
);
2656 gui_menu_cb(theVimMenu
);
2662 * Dispatch the event to proper handler
2666 gui_mac_handle_event(EventRecord
*event
)
2670 /* Handle contextual menu right now (if needed) */
2671 if (IsShowContextualMenuClick(event
))
2674 gui_mac_handle_contextual_menu(event
);
2676 gui_mac_doMouseDownEvent(event
);
2681 /* Handle normal event */
2682 switch (event
->what
)
2684 #ifndef USE_CARBONKEYHANDLER
2687 gui_mac_doKeyEvent(event
);
2691 /* We don't care about when the key is released */
2695 gui_mac_doMouseDownEvent(event
);
2699 gui_mac_doMouseUpEvent(event
);
2703 gui_mac_doUpdateEvent(event
);
2707 /* We don't need special handling for disk insertion */
2711 gui_mac_doActivateEvent(event
);
2715 switch ((event
->message
>> 24) & 0xFF)
2717 case (0xFA): /* mouseMovedMessage */
2718 gui_mac_doMouseMovedEvent(event
);
2720 case (0x01): /* suspendResumeMessage */
2721 gui_mac_doSuspendEvent(event
);
2727 case (kHighLevelEvent
):
2728 /* Someone's talking to us, through AppleEvents */
2729 error
= AEProcessAppleEvent(event
); /* TODO: Error Handling */
2736 * ------------------------------------------------------------
2738 * ------------------------------------------------------------
2743 gui_mac_find_font(char_u
*font_name
)
2747 char_u pFontName
[256];
2748 Str255 systemFontname
;
2753 char_u
*fontNamePtr
;
2756 for (p
= font_name
; ((*p
!= 0) && (*p
!= ':')); p
++)
2763 STRCPY(&pFontName
[1], font_name
);
2764 pFontName
[0] = STRLEN(font_name
);
2767 /* Get the font name, minus the style suffix (:h, etc) */
2768 char_u fontName
[256];
2769 char_u
*styleStart
= vim_strchr(font_name
, ':');
2770 size_t fontNameLen
= styleStart
? styleStart
- font_name
: STRLEN(fontName
);
2771 vim_strncpy(fontName
, font_name
, fontNameLen
);
2774 FMFontStyle fontStyle
;
2777 if (ATSUFindFontFromName(&pFontName
[1], pFontName
[0], kFontFullName
,
2778 kFontMacintoshPlatform
, kFontNoScriptCode
, kFontNoLanguageCode
,
2781 if (FMGetFontFamilyInstanceFromFont(fontRef
, &font_id
, &fontStyle
) != noErr
)
2788 * Try again, this time replacing underscores in the font name
2789 * with spaces (:set guifont allows the two to be used
2790 * interchangeably; the Font Manager doesn't).
2792 int i
, changed
= FALSE
;
2794 for (i
= pFontName
[0]; i
> 0; --i
)
2796 if (pFontName
[i
] == '_')
2803 if (ATSUFindFontFromName(&pFontName
[1], pFontName
[0],
2804 kFontFullName
, kFontNoPlatformCode
, kFontNoScriptCode
,
2805 kFontNoLanguageCode
, &fontRef
) == noErr
)
2807 if (FMGetFontFamilyInstanceFromFont(fontRef
, &font_id
, &fontStyle
) != noErr
)
2813 /* name = C2Pascal_save(menu->dname); */
2814 fontNamePtr
= C2Pascal_save_and_remove_backslash(font_name
);
2816 GetFNum(fontNamePtr
, &font_id
);
2822 /* Oups, the system font was it the one the user want */
2824 if (FMGetFontFamilyName(systemFont
, systemFontname
) != noErr
)
2826 if (!EqualString(pFontName
, systemFontname
, false, false))
2832 /* Set the values found after ':' */
2838 size
= points_to_pixels(p
, &p
, TRUE
);
2841 * TODO: Maybe accept width and styles
2850 size
= 1; /* Avoid having a size of 0 with system font */
2852 font
= (size
<< 16) + ((long) font_id
& 0xFFFF);
2858 * ------------------------------------------------------------
2859 * GUI_MCH functionality
2860 * ------------------------------------------------------------
2864 * Parse the GUI related command-line arguments. Any arguments used are
2865 * deleted from argv, and *argc is decremented accordingly. This is called
2866 * when vim is started, whether or not the GUI has been started.
2869 gui_mch_prepare(int *argc
, char **argv
)
2871 /* TODO: Move most of this stuff toward gui_mch_init */
2874 # ifndef USE_FIND_BUNDLE_PATH
2879 ProcessSerialNumber psn
;
2887 RegisterAppearanceClient();
2890 (void) InstallAEHandlers();
2893 pomme
= NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
2895 AppendMenu(pomme
, "\pAbout VIM");
2897 InsertMenu(pomme
, 0);
2902 #ifndef USE_OFFSETED_WINDOW
2903 SetRect(&windRect
, 10, 48, 10+80*7 + 16, 48+24*11);
2905 SetRect(&windRect
, 300, 40, 300+80*7 + 16, 40+24*11);
2909 CreateNewWindow(kDocumentWindowClass
,
2910 kWindowResizableAttribute
| kWindowCollapseBoxAttribute
,
2911 &windRect
, &gui
.VimWindow
);
2912 SetPortWindowPort(gui
.VimWindow
);
2915 gui
.char_height
= 11;
2916 gui
.char_ascent
= 6;
2919 gui
.in_focus
= TRUE
; /* For the moment -> syn. of front application */
2921 gScrollAction
= NewControlActionUPP(gui_mac_scroll_action
);
2922 gScrollDrag
= NewControlActionUPP(gui_mac_drag_thumb
);
2924 dragRectEnbl
= FALSE
;
2926 dragRectControl
= kCreateEmpty
;
2927 cursorRgn
= NewRgn();
2930 # ifndef USE_FIND_BUNDLE_PATH
2931 HGetVol(volName
, &applVRefNum
, &applDirID
);
2932 /* TN2015: mention a possible bad VRefNum */
2933 FSMakeFSSpec(applVRefNum
, applDirID
, "\p", &applDir
);
2935 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2938 (void)GetCurrentProcess(&psn
);
2939 /* if (err != noErr) return err; */
2941 (void)GetProcessBundleLocation(&psn
, &applFSRef
);
2942 /* if (err != noErr) return err; */
2944 (void)FSGetCatalogInfo(&applFSRef
, kFSCatInfoNone
, NULL
, NULL
, &applDir
, NULL
);
2946 /* This technic return NIL when we disallow_gui */
2948 exe_name
= FullPathFromFSSpec_save(applDir
);
2952 #ifndef ALWAYS_USE_GUI
2954 * Check if the GUI can be started. Called before gvimrc is sourced.
2955 * Return OK or FAIL.
2958 gui_mch_init_check(void)
2960 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2961 * using the >console
2963 if (disallow_gui
) /* see main.c for reason to disallow */
2970 receiveHandler(WindowRef theWindow
, void *handlerRefCon
, DragRef theDrag
)
2974 char_u
**fnames
= NULL
;
2978 /* Get drop position, modifiers and count of items */
2981 SInt16 mouseUpModifiers
;
2984 GetDragMouse(theDrag
, &point
, NULL
);
2985 GlobalToLocal(&point
);
2988 GetDragModifiers(theDrag
, NULL
, NULL
, &mouseUpModifiers
);
2989 modifiers
= EventModifiers2VimMouseModifiers(mouseUpModifiers
);
2990 CountDragItems(theDrag
, &countItem
);
2994 fnames
= (char_u
**)alloc(count
* sizeof(char_u
*));
2996 return dragNotAcceptedErr
;
2998 /* Get file names dropped */
2999 for (i
= j
= 0; i
< count
; ++i
)
3004 FlavorType type
= flavorTypeHFS
;
3005 HFSFlavor hfsFlavor
;
3008 GetDragItemReferenceNumber(theDrag
, i
+ 1, &item
);
3009 err
= GetFlavorDataSize(theDrag
, item
, type
, &size
);
3010 if (err
!= noErr
|| size
> sizeof(hfsFlavor
))
3012 err
= GetFlavorData(theDrag
, item
, type
, &hfsFlavor
, &size
, 0);
3015 fnames
[j
++] = FullPathFromFSSpec_save(hfsFlavor
.fileSpec
);
3019 gui_handle_drop(x
, y
, modifiers
, fnames
, count
);
3021 /* Fake mouse event to wake from stall */
3022 PostEvent(mouseUp
, 0);
3028 * Initialise the GUI. Create all the windows, set up all the call-backs
3034 /* TODO: Move most of this stuff toward gui_mch_init */
3037 EventHandlerRef mouseWheelHandlerRef
;
3038 EventTypeSpec eventTypeSpec
;
3039 ControlRef rootControl
;
3041 if (Gestalt(gestaltSystemVersion
, &gMacSystemVersion
) != noErr
)
3042 gMacSystemVersion
= 0x1000; /* TODO: Default to minimum sensible value */
3047 RegisterAppearanceClient();
3050 (void) InstallAEHandlers();
3053 pomme
= NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
3055 AppendMenu(pomme
, "\pAbout VIM");
3057 InsertMenu(pomme
, 0);
3062 #ifndef USE_OFFSETED_WINDOW
3063 SetRect(&windRect
, 10, 48, 10+80*7 + 16, 48+24*11);
3065 SetRect(&windRect
, 300, 40, 300+80*7 + 16, 40+24*11);
3068 gui
.VimWindow
= NewCWindow(nil
, &windRect
, "\pgVim on Macintosh", true,
3070 (WindowPtr
)-1L, true, 0);
3071 CreateRootControl(gui
.VimWindow
, &rootControl
);
3072 InstallReceiveHandler((DragReceiveHandlerUPP
)receiveHandler
,
3073 gui
.VimWindow
, NULL
);
3074 SetPortWindowPort(gui
.VimWindow
);
3077 gui
.char_height
= 11;
3078 gui
.char_ascent
= 6;
3081 gui
.in_focus
= TRUE
; /* For the moment -> syn. of front application */
3083 gScrollAction
= NewControlActionUPP(gui_mac_scroll_action
);
3084 gScrollDrag
= NewControlActionUPP(gui_mac_drag_thumb
);
3086 /* Install Carbon event callbacks. */
3087 (void)InstallFontPanelHandler();
3089 dragRectEnbl
= FALSE
;
3091 dragRectControl
= kCreateEmpty
;
3092 cursorRgn
= NewRgn();
3094 /* Display any pending error messages */
3097 /* Get background/foreground colors from system */
3098 /* TODO: do the appropriate call to get real defaults */
3099 gui
.norm_pixel
= 0x00000000;
3100 gui
.back_pixel
= 0x00FFFFFF;
3102 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3104 set_normal_colors();
3107 * Check that none of the colors are the same as the background color.
3108 * Then store the current values as the defaults.
3111 gui
.def_norm_pixel
= gui
.norm_pixel
;
3112 gui
.def_back_pixel
= gui
.back_pixel
;
3114 /* Get the colors for the highlight groups (gui_check_colors() might have
3116 highlight_gui_started();
3119 * Setting the gui constants
3122 gui
.menu_height
= 0;
3124 gui
.scrollbar_height
= gui
.scrollbar_width
= 15; /* cheat 1 overlap */
3125 gui
.border_offset
= gui
.border_width
= 2;
3127 /* If Quartz-style text anti aliasing is available (see
3128 gui_mch_draw_string() below), enable it for all font sizes. */
3129 vim_setenv((char_u
*)"QDTEXT_MINSIZE", (char_u
*)"1");
3131 eventTypeSpec
.eventClass
= kEventClassMouse
;
3132 eventTypeSpec
.eventKind
= kEventMouseWheelMoved
;
3133 mouseWheelHandlerUPP
= NewEventHandlerUPP(gui_mac_mouse_wheel
);
3134 if (noErr
!= InstallApplicationEventHandler(mouseWheelHandlerUPP
, 1,
3135 &eventTypeSpec
, NULL
, &mouseWheelHandlerRef
))
3137 mouseWheelHandlerRef
= NULL
;
3138 DisposeEventHandlerUPP(mouseWheelHandlerUPP
);
3139 mouseWheelHandlerUPP
= NULL
;
3142 #ifdef USE_CARBONKEYHANDLER
3143 InterfaceTypeList supportedServices
= { kUnicodeDocument
};
3144 NewTSMDocument(1, supportedServices
, &gTSMDocument
, 0);
3146 /* We don't support inline input yet, use input window by default */
3147 UseInputWindow(gTSMDocument
, TRUE
);
3149 /* Should we activate the document by default? */
3150 // ActivateTSMDocument(gTSMDocument);
3152 EventTypeSpec textEventTypes
[] = {
3153 { kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
3154 { kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
3155 { kEventClassTextInput
, kEventTextInputPosToOffset
},
3156 { kEventClassTextInput
, kEventTextInputOffsetToPos
},
3159 keyEventHandlerUPP
= NewEventHandlerUPP(gui_mac_handle_text_input
);
3160 if (noErr
!= InstallApplicationEventHandler(keyEventHandlerUPP
,
3161 NR_ELEMS(textEventTypes
),
3162 textEventTypes
, NULL
, NULL
))
3164 DisposeEventHandlerUPP(keyEventHandlerUPP
);
3165 keyEventHandlerUPP
= NULL
;
3168 EventTypeSpec windowEventTypes
[] = {
3169 { kEventClassWindow
, kEventWindowActivated
},
3170 { kEventClassWindow
, kEventWindowDeactivated
},
3173 /* Install window event handler to support TSMDocument activate and
3175 winEventHandlerUPP
= NewEventHandlerUPP(gui_mac_handle_window_activate
);
3176 if (noErr
!= InstallWindowEventHandler(gui
.VimWindow
,
3178 NR_ELEMS(windowEventTypes
),
3179 windowEventTypes
, NULL
, NULL
))
3181 DisposeEventHandlerUPP(winEventHandlerUPP
);
3182 winEventHandlerUPP
= NULL
;
3188 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3192 #ifdef FEAT_GUI_TABLINE
3194 * Create the tabline
3196 initialise_tabline();
3199 /* TODO: Load bitmap if using TOOLBAR */
3204 * Called when the foreground or background color has been changed.
3207 gui_mch_new_colors(void)
3210 * This proc is called when Normal is set to a value
3211 * so what msut be done? I don't know
3216 * Open the GUI window which was created by a call to gui_mch_init().
3221 ShowWindow(gui
.VimWindow
);
3223 if (gui_win_x
!= -1 && gui_win_y
!= -1)
3224 gui_mch_set_winpos(gui_win_x
, gui_win_y
);
3227 * Make the GUI the foreground process (in case it was launched
3228 * from the Terminal or via :gui).
3231 ProcessSerialNumber psn
;
3232 if (GetCurrentProcess(&psn
) == noErr
)
3233 SetFrontProcess(&psn
);
3239 #ifdef USE_ATSUI_DRAWING
3241 gui_mac_dispose_atsui_style(void)
3243 if (p_macatsui
&& gFontStyle
)
3244 ATSUDisposeStyle(gFontStyle
);
3246 if (p_macatsui
&& gWideFontStyle
)
3247 ATSUDisposeStyle(gWideFontStyle
);
3253 gui_mch_exit(int rc
)
3255 /* TODO: find out all what is missing here? */
3256 DisposeRgn(cursorRgn
);
3258 #ifdef USE_CARBONKEYHANDLER
3259 if (keyEventHandlerUPP
)
3260 DisposeEventHandlerUPP(keyEventHandlerUPP
);
3263 if (mouseWheelHandlerUPP
!= NULL
)
3264 DisposeEventHandlerUPP(mouseWheelHandlerUPP
);
3266 #ifdef USE_ATSUI_DRAWING
3267 gui_mac_dispose_atsui_style();
3270 #ifdef USE_CARBONKEYHANDLER
3271 FixTSMDocument(gTSMDocument
);
3272 DeactivateTSMDocument(gTSMDocument
);
3273 DeleteTSMDocument(gTSMDocument
);
3276 /* Exit to shell? */
3281 * Get the position of the top left corner of the window.
3284 gui_mch_get_winpos(int *x
, int *y
)
3290 /* Carbon >= 1.0.2, MacOS >= 8.5 */
3291 status
= GetWindowBounds(gui
.VimWindow
, kWindowStructureRgn
, &bounds
);
3293 if (status
!= noErr
)
3302 * Set the position of the top left corner of the window to the given
3306 gui_mch_set_winpos(int x
, int y
)
3308 /* TODO: Should make sure the window is move within range
3309 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3311 MoveWindowStructure(gui
.VimWindow
, x
, y
);
3315 gui_mch_set_shellsize(
3327 if (gui
.which_scrollbars
[SBAR_LEFT
])
3329 VimPort
= GetWindowPort(gui
.VimWindow
);
3330 GetPortBounds(VimPort
, &VimBound
);
3331 VimBound
.left
= -gui
.scrollbar_width
; /* + 1;*/
3332 SetPortBounds(VimPort
, &VimBound
);
3333 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
3337 VimPort
= GetWindowPort(gui
.VimWindow
);
3338 GetPortBounds(VimPort
, &VimBound
);
3340 SetPortBounds(VimPort
, &VimBound
);
3343 SizeWindow(gui
.VimWindow
, width
, height
, TRUE
);
3345 gui_resize_shell(width
, height
);
3349 * Get the screen dimensions.
3350 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3351 * Is there no way to find out how wide the borders really are?
3352 * TODO: Add live update of those value on suspend/resume.
3355 gui_mch_get_screen_dimensions(int *screen_w
, int *screen_h
)
3357 GDHandle dominantDevice
= GetMainDevice();
3358 Rect screenRect
= (**dominantDevice
).gdRect
;
3360 *screen_w
= screenRect
.right
- 10;
3361 *screen_h
= screenRect
.bottom
- 40;
3366 * Open the Font Panel and wait for the user to select a font and
3367 * close the panel. Then fill the buffer pointed to by font_name with
3368 * the name and size of the selected font and return the font's handle,
3369 * or NOFONT in case of an error.
3372 gui_mac_select_font(char_u
*font_name
)
3374 GuiFont selected_font
= NOFONT
;
3376 FontSelectionQDStyle curr_font
;
3378 /* Initialize the Font Panel with the current font. */
3379 curr_font
.instance
.fontFamily
= gui
.norm_font
& 0xFFFF;
3380 curr_font
.size
= (gui
.norm_font
>> 16);
3381 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3382 curr_font
.instance
.fontStyle
= 0;
3383 curr_font
.hasColor
= false;
3384 curr_font
.version
= 0; /* version number of the style structure */
3385 status
= SetFontInfoForSelection(kFontSelectionQDType
,
3386 /*numStyles=*/1, &curr_font
, /*eventTarget=*/NULL
);
3388 gFontPanelInfo
.family
= curr_font
.instance
.fontFamily
;
3389 gFontPanelInfo
.style
= curr_font
.instance
.fontStyle
;
3390 gFontPanelInfo
.size
= curr_font
.size
;
3392 /* Pop up the Font Panel. */
3393 status
= FPShowHideFontPanel();
3394 if (status
== noErr
)
3397 * The Font Panel is modeless. We really need it to be modal,
3398 * so we spin in an event loop until the panel is closed.
3400 gFontPanelInfo
.isPanelVisible
= true;
3401 while (gFontPanelInfo
.isPanelVisible
)
3404 WaitNextEvent(everyEvent
, &e
, /*sleep=*/20, /*mouseRgn=*/NULL
);
3407 GetFontPanelSelection(font_name
);
3408 selected_font
= gui_mac_find_font(font_name
);
3410 return selected_font
;
3413 #ifdef USE_ATSUI_DRAWING
3415 gui_mac_create_atsui_style(void)
3417 if (p_macatsui
&& gFontStyle
== NULL
)
3419 if (ATSUCreateStyle(&gFontStyle
) != noErr
)
3423 if (p_macatsui
&& gWideFontStyle
== NULL
)
3425 if (ATSUCreateStyle(&gWideFontStyle
) != noErr
)
3426 gWideFontStyle
= NULL
;
3430 p_macatsui_last
= p_macatsui
;
3435 * Initialise vim to use the font with the given name. Return FAIL if the font
3436 * could not be loaded, OK otherwise.
3439 gui_mch_init_font(char_u
*font_name
, int fontset
)
3441 /* TODO: Add support for bold italic underline proportional etc... */
3442 Str255 suggestedFont
= "\pMonaco";
3443 int suggestedSize
= 10;
3447 char_u used_font_name
[512];
3449 #ifdef USE_ATSUI_DRAWING
3450 gui_mac_create_atsui_style();
3453 if (font_name
== NULL
)
3455 /* First try to get the suggested font */
3456 GetFNum(suggestedFont
, &font_id
);
3460 /* Then pickup the standard application font */
3461 font_id
= GetAppFont();
3462 STRCPY(used_font_name
, "default");
3465 STRCPY(used_font_name
, "Monaco");
3466 font
= (suggestedSize
<< 16) + ((long) font_id
& 0xFFFF);
3468 else if (STRCMP(font_name
, "*") == 0)
3470 char_u
*new_p_guifont
;
3472 font
= gui_mac_select_font(used_font_name
);
3476 /* Set guifont to the name of the selected font. */
3477 new_p_guifont
= alloc(STRLEN(used_font_name
) + 1);
3478 if (new_p_guifont
!= NULL
)
3480 STRCPY(new_p_guifont
, used_font_name
);
3481 vim_free(p_guifont
);
3482 p_guifont
= new_p_guifont
;
3483 /* Replace spaces in the font name with underscores. */
3484 for ( ; *new_p_guifont
; ++new_p_guifont
)
3486 if (*new_p_guifont
== ' ')
3487 *new_p_guifont
= '_';
3493 font
= gui_mac_find_font(font_name
);
3494 vim_strncpy(used_font_name
, font_name
, sizeof(used_font_name
) - 1);
3500 gui
.norm_font
= font
;
3502 hl_set_font_name(used_font_name
);
3504 TextSize(font
>> 16);
3505 TextFont(font
& 0xFFFF);
3507 GetFontInfo(&font_info
);
3509 gui
.char_ascent
= font_info
.ascent
;
3510 gui
.char_width
= CharWidth('_');
3511 gui
.char_height
= font_info
.ascent
+ font_info
.descent
+ p_linespace
;
3513 #ifdef USE_ATSUI_DRAWING
3514 if (p_macatsui
&& gFontStyle
)
3515 gui_mac_set_font_attributes(font
);
3522 * Adjust gui.char_height (after 'linespace' was changed).
3525 gui_mch_adjust_charheight(void)
3529 GetFontInfo(&font_info
);
3530 gui
.char_height
= font_info
.ascent
+ font_info
.descent
+ p_linespace
;
3531 gui
.char_ascent
= font_info
.ascent
+ p_linespace
/ 2;
3536 * Get a font structure for highlighting.
3539 gui_mch_get_font(char_u
*name
, int giveErrorIfMissing
)
3543 font
= gui_mac_find_font(name
);
3547 if (giveErrorIfMissing
)
3548 EMSG2(_(e_font
), name
);
3552 * TODO : Accept only monospace
3558 #if defined(FEAT_EVAL) || defined(PROTO)
3560 * Return the name of font "font" in allocated memory.
3561 * Don't know how to get the actual name, thus use the provided name.
3564 gui_mch_get_fontname(GuiFont font
, char_u
*name
)
3568 return vim_strsave(name
);
3572 #ifdef USE_ATSUI_DRAWING
3574 gui_mac_set_font_attributes(GuiFont font
)
3580 fontID
= font
& 0xFFFF;
3581 fontSize
= Long2Fix(font
>> 16);
3582 fontWidth
= Long2Fix(gui
.char_width
);
3584 ATSUAttributeTag attribTags
[] =
3586 kATSUFontTag
, kATSUSizeTag
, kATSUImposeWidthTag
,
3587 kATSUMaxATSUITagValue
+ 1
3590 ByteCount attribSizes
[] =
3592 sizeof(ATSUFontID
), sizeof(Fixed
), sizeof(fontWidth
),
3596 ATSUAttributeValuePtr attribValues
[] =
3598 &fontID
, &fontSize
, &fontWidth
, &font
3601 if (FMGetFontFromFontFamilyInstance(fontID
, 0, &fontID
, NULL
) == noErr
)
3603 if (ATSUSetAttributes(gFontStyle
,
3604 (sizeof attribTags
) / sizeof(ATSUAttributeTag
),
3605 attribTags
, attribSizes
, attribValues
) != noErr
)
3608 fprintf(stderr
, "couldn't set font style\n");
3610 ATSUDisposeStyle(gFontStyle
);
3617 /* FIXME: we should use a more mbyte sensitive way to support
3618 * wide font drawing */
3619 fontWidth
= Long2Fix(gui
.char_width
* 2);
3621 if (ATSUSetAttributes(gWideFontStyle
,
3622 (sizeof attribTags
) / sizeof(ATSUAttributeTag
),
3623 attribTags
, attribSizes
, attribValues
) != noErr
)
3625 ATSUDisposeStyle(gWideFontStyle
);
3626 gWideFontStyle
= NULL
;
3635 * Set the current text font.
3638 gui_mch_set_font(GuiFont font
)
3640 #ifdef USE_ATSUI_DRAWING
3642 ByteCount actualFontByteCount
;
3644 if (p_macatsui
&& gFontStyle
)
3646 /* Avoid setting same font again */
3647 if (ATSUGetAttribute(gFontStyle
, kATSUMaxATSUITagValue
+ 1,
3648 sizeof(font
), &currFont
, &actualFontByteCount
) == noErr
3649 && actualFontByteCount
== (sizeof font
))
3651 if (currFont
== font
)
3655 gui_mac_set_font_attributes(font
);
3658 if (p_macatsui
&& !gIsFontFallbackSet
)
3660 /* Setup automatic font substitution. The user's guifontwide
3661 * is tried first, then the system tries other fonts. */
3663 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3664 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3665 ATSUCreateFontFallbacks(&gFontFallbacks);
3666 ATSUSetObjFontFallbacks(gFontFallbacks, );
3670 ATSUFontID fallbackFonts
;
3671 gIsFontFallbackSet
= TRUE
;
3673 if (FMGetFontFromFontFamilyInstance(
3674 (gui
.wide_font
& 0xFFFF),
3679 ATSUSetFontFallbacks((sizeof fallbackFonts
)/sizeof(ATSUFontID
),
3681 kATSUSequentialFallbacksPreferred
);
3684 ATSUAttributeValuePtr fallbackValues[] = { };
3689 TextSize(font
>> 16);
3690 TextFont(font
& 0xFFFF);
3694 * If a font is not going to be used, free its structure.
3697 gui_mch_free_font(font
)
3701 * Free font when "font" is not 0.
3702 * Nothing to do in the current implementation, since
3703 * nothing is allocated for each font used.
3713 if (c
>= 'a' && c
<= 'f')
3714 return c
- 'a' + 10;
3719 * Return the Pixel value (color) for the given color name. This routine was
3720 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3721 * Programmer's Guide.
3722 * Return INVALCOLOR when failed.
3725 gui_mch_get_color(char_u
*name
)
3727 /* TODO: Add support for the new named color of MacOS 8
3730 // guicolor_T color = 0;
3732 typedef struct guicolor_tTable
3739 * The comment at the end of each line is the source
3740 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3742 static guicolor_tTable table
[] =
3744 {"Black", RGB(0x00, 0x00, 0x00)},
3745 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3746 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3747 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3748 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3749 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3750 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3751 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3752 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3753 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3754 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3755 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3756 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3757 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3758 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3759 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3760 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3761 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3762 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3763 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3764 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3765 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3766 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3767 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3768 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3769 {"white", RGB(0xFF, 0xFF, 0xFF)},
3770 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3771 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3772 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3773 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3774 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3775 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3776 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3777 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3778 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3779 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3780 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3781 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3782 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3783 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3784 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3785 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3786 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3787 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
3788 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
3789 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3790 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3791 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3792 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3793 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3799 if (name
[0] == '#' && strlen((char *) name
) == 7)
3801 /* Name is in "#rrggbb" format */
3802 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
3803 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
3804 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
3805 if (r
< 0 || g
< 0 || b
< 0)
3807 return RGB(r
, g
, b
);
3811 if (STRICMP(name
, "hilite") == 0)
3813 LMGetHiliteRGB(&MacColor
);
3814 return (RGB(MacColor
.red
>> 8, MacColor
.green
>> 8, MacColor
.blue
>> 8));
3816 /* Check if the name is one of the colors we know */
3817 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
3818 if (STRICMP(name
, table
[i
].name
) == 0)
3819 return table
[i
].color
;
3823 * Last attempt. Look in the file "$VIM/rgb.txt".
3826 #define LINE_LEN 100
3828 char line
[LINE_LEN
];
3831 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
3835 fd
= fopen((char *)fname
, "rt");
3846 fgets(line
, LINE_LEN
, fd
);
3849 if (len
<= 1 || line
[len
-1] != '\n')
3854 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
3860 if (STRICMP(color
, name
) == 0)
3863 return (guicolor_T
) RGB(r
, g
, b
);
3873 * Set the current text foreground color.
3876 gui_mch_set_fg_color(guicolor_T color
)
3880 TheColor
.red
= Red(color
) * 0x0101;
3881 TheColor
.green
= Green(color
) * 0x0101;
3882 TheColor
.blue
= Blue(color
) * 0x0101;
3884 RGBForeColor(&TheColor
);
3888 * Set the current text background color.
3891 gui_mch_set_bg_color(guicolor_T color
)
3895 TheColor
.red
= Red(color
) * 0x0101;
3896 TheColor
.green
= Green(color
) * 0x0101;
3897 TheColor
.blue
= Blue(color
) * 0x0101;
3899 RGBBackColor(&TheColor
);
3902 RGBColor specialColor
;
3905 * Set the current text special color.
3908 gui_mch_set_sp_color(guicolor_T color
)
3910 specialColor
.red
= Red(color
) * 0x0101;
3911 specialColor
.green
= Green(color
) * 0x0101;
3912 specialColor
.blue
= Blue(color
) * 0x0101;
3916 * Draw undercurl at the bottom of the character cell.
3919 draw_undercurl(int flags
, int row
, int col
, int cells
)
3923 const static int val
[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3924 int y
= FILL_Y(row
+ 1) - 1;
3926 RGBForeColor(&specialColor
);
3928 offset
= val
[FILL_X(col
) % 8];
3929 MoveTo(FILL_X(col
), y
- offset
);
3931 for (x
= FILL_X(col
); x
< FILL_X(col
+ cells
); ++x
)
3933 offset
= val
[x
% 8];
3934 LineTo(x
, y
- offset
);
3940 draw_string_QD(int row
, int col
, char_u
*s
, int len
, int flags
)
3943 char_u
*tofree
= NULL
;
3945 if (output_conv
.vc_type
!= CONV_NONE
)
3947 tofree
= string_convert(&output_conv
, s
, &len
);
3954 * On OS X, try using Quartz-style text antialiasing.
3956 if (gMacSystemVersion
>= 0x1020)
3958 /* Quartz antialiasing is available only in OS 10.2 and later. */
3959 UInt32 qd_flags
= (p_antialias
?
3960 kQDUseCGTextRendering
| kQDUseCGTextMetrics
: 0);
3961 QDSwapTextFlags(qd_flags
);
3965 * When antialiasing we're using srcOr mode, we have to clear the block
3966 * before drawing the text.
3967 * Also needed when 'linespace' is non-zero to remove the cursor and
3969 * But not when drawing transparently.
3970 * The following is like calling gui_mch_clear_block(row, col, row, col +
3971 * len - 1), but without setting the bg color to gui.back_pixel.
3973 if (((gMacSystemVersion
>= 0x1020 && p_antialias
) || p_linespace
!= 0)
3974 && !(flags
& DRAW_TRANSP
))
3978 rc
.left
= FILL_X(col
);
3979 rc
.top
= FILL_Y(row
);
3981 /* Multibyte computation taken from gui_w32.c */
3987 /* Compute the length in display cells. */
3988 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(s
[n
]))
3989 cell_len
+= (*mb_ptr2cells
)(s
+ n
);
3990 rc
.right
= FILL_X(col
+ cell_len
);
3994 rc
.right
= FILL_X(col
+ len
) + (col
+ len
== Columns
);
3995 rc
.bottom
= FILL_Y(row
+ 1);
3999 if (gMacSystemVersion
>= 0x1020 && p_antialias
)
4001 StyleParameter face
;
4004 if (flags
& DRAW_BOLD
)
4006 if (flags
& DRAW_UNDERL
)
4010 /* Quartz antialiasing works only in srcOr transfer mode. */
4013 MoveTo(TEXT_X(col
), TEXT_Y(row
));
4014 DrawText((char*)s
, 0, len
);
4018 /* Use old-style, non-antialiased QuickDraw text rendering. */
4022 /* SelectFont(hdc, gui.currFont); */
4024 if (flags
& DRAW_TRANSP
)
4029 MoveTo(TEXT_X(col
), TEXT_Y(row
));
4030 DrawText((char *)s
, 0, len
);
4032 if (flags
& DRAW_BOLD
)
4035 MoveTo(TEXT_X(col
) + 1, TEXT_Y(row
));
4036 DrawText((char *)s
, 0, len
);
4039 if (flags
& DRAW_UNDERL
)
4041 MoveTo(FILL_X(col
), FILL_Y(row
+ 1) - 1);
4042 LineTo(FILL_X(col
+ len
) - 1, FILL_Y(row
+ 1) - 1);
4046 if (flags
& DRAW_UNDERC
)
4047 draw_undercurl(flags
, row
, col
, len
);
4054 #ifdef USE_ATSUI_DRAWING
4057 draw_string_ATSUI(int row
, int col
, char_u
*s
, int len
, int flags
)
4059 /* ATSUI requires utf-16 strings */
4060 UniCharCount utf16_len
;
4061 UniChar
*tofree
= mac_enc_to_utf16(s
, len
, (size_t *)&utf16_len
);
4062 utf16_len
/= sizeof(UniChar
);
4064 /* - ATSUI automatically antialiases text (Someone)
4065 * - for some reason it does not work... (Jussi) */
4066 #ifdef MAC_ATSUI_DEBUG
4067 fprintf(stderr
, "row = %d, col = %d, len = %d: '%c'\n",
4068 row
, col
, len
, len
== 1 ? s
[0] : ' ');
4071 * When antialiasing we're using srcOr mode, we have to clear the block
4072 * before drawing the text.
4073 * Also needed when 'linespace' is non-zero to remove the cursor and
4075 * But not when drawing transparently.
4076 * The following is like calling gui_mch_clear_block(row, col, row, col +
4077 * len - 1), but without setting the bg color to gui.back_pixel.
4079 if ((flags
& DRAW_TRANSP
) == 0)
4083 rc
.left
= FILL_X(col
);
4084 rc
.top
= FILL_Y(row
);
4085 /* Multibyte computation taken from gui_w32.c */
4091 /* Compute the length in display cells. */
4092 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(s
[n
]))
4093 cell_len
+= (*mb_ptr2cells
)(s
+ n
);
4094 rc
.right
= FILL_X(col
+ cell_len
);
4097 rc
.right
= FILL_X(col
+ len
) + (col
+ len
== Columns
);
4099 rc
.bottom
= FILL_Y(row
+ 1);
4107 /* SelectFont(hdc, gui.currFont); */
4108 if (flags
& DRAW_TRANSP
)
4113 MoveTo(TEXT_X(col
), TEXT_Y(row
));
4115 if (gFontStyle
&& flags
& DRAW_BOLD
)
4117 Boolean attValue
= true;
4118 ATSUAttributeTag attribTags
[] = { kATSUQDBoldfaceTag
};
4119 ByteCount attribSizes
[] = { sizeof(Boolean
) };
4120 ATSUAttributeValuePtr attribValues
[] = { &attValue
};
4122 ATSUSetAttributes(gFontStyle
, 1, attribTags
, attribSizes
, attribValues
);
4128 int n
, width_in_cell
, last_width_in_cell
;
4129 UniCharArrayOffset offset
= 0;
4130 UniCharCount yet_to_draw
= 0;
4131 ATSUTextLayout textLayout
;
4132 ATSUStyle textStyle
;
4134 last_width_in_cell
= 1;
4135 ATSUCreateTextLayout(&textLayout
);
4136 ATSUSetTextPointerLocation(textLayout
, tofree
,
4137 kATSUFromTextBeginning
,
4138 kATSUToTextEnd
, utf16_len
);
4140 ATSUSetRunStyle(textLayout, gFontStyle,
4141 kATSUFromTextBeginning, kATSUToTextEnd); */
4143 /* Compute the length in display cells. */
4144 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(s
[n
]))
4146 width_in_cell
= (*mb_ptr2cells
)(s
+ n
);
4148 /* probably we are switching from single byte character
4149 * to multibyte characters (which requires more than one
4151 if (width_in_cell
!= last_width_in_cell
)
4153 #ifdef MAC_ATSUI_DEBUG
4154 fprintf(stderr
, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4155 n
, last_width_in_cell
, width_in_cell
, offset
, yet_to_draw
);
4157 textStyle
= last_width_in_cell
> 1 ? gWideFontStyle
4160 ATSUSetRunStyle(textLayout
, textStyle
, offset
, yet_to_draw
);
4161 offset
+= yet_to_draw
;
4163 last_width_in_cell
= width_in_cell
;
4171 #ifdef MAC_ATSUI_DEBUG
4172 fprintf(stderr
, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4173 n
, last_width_in_cell
, width_in_cell
, offset
, yet_to_draw
);
4175 /* finish the rest style */
4176 textStyle
= width_in_cell
> 1 ? gWideFontStyle
: gFontStyle
;
4177 ATSUSetRunStyle(textLayout
, textStyle
, offset
, kATSUToTextEnd
);
4180 ATSUSetTransientFontMatching(textLayout
, TRUE
);
4181 ATSUDrawText(textLayout
,
4182 kATSUFromTextBeginning
, kATSUToTextEnd
,
4183 kATSUUseGrafPortPenLoc
, kATSUUseGrafPortPenLoc
);
4184 ATSUDisposeTextLayout(textLayout
);
4189 ATSUTextLayout textLayout
;
4191 if (ATSUCreateTextLayoutWithTextPtr(tofree
,
4192 kATSUFromTextBeginning
, kATSUToTextEnd
,
4194 (gFontStyle
? 1 : 0), &utf16_len
,
4195 (gFontStyle
? &gFontStyle
: NULL
),
4196 &textLayout
) == noErr
)
4198 ATSUSetTransientFontMatching(textLayout
, TRUE
);
4200 ATSUDrawText(textLayout
,
4201 kATSUFromTextBeginning
, kATSUToTextEnd
,
4202 kATSUUseGrafPortPenLoc
, kATSUUseGrafPortPenLoc
);
4204 ATSUDisposeTextLayout(textLayout
);
4208 /* drawing is done, now reset bold to normal */
4209 if (gFontStyle
&& flags
& DRAW_BOLD
)
4211 Boolean attValue
= false;
4213 ATSUAttributeTag attribTags
[] = { kATSUQDBoldfaceTag
};
4214 ByteCount attribSizes
[] = { sizeof(Boolean
) };
4215 ATSUAttributeValuePtr attribValues
[] = { &attValue
};
4217 ATSUSetAttributes(gFontStyle
, 1, attribTags
, attribSizes
,
4222 if (flags
& DRAW_UNDERC
)
4223 draw_undercurl(flags
, row
, col
, len
);
4230 gui_mch_draw_string(int row
, int col
, char_u
*s
, int len
, int flags
)
4232 #if defined(USE_ATSUI_DRAWING)
4233 if (p_macatsui
== 0 && p_macatsui_last
!= 0)
4234 /* switch from macatsui to nomacatsui */
4235 gui_mac_dispose_atsui_style();
4236 else if (p_macatsui
!= 0 && p_macatsui_last
== 0)
4237 /* switch from nomacatsui to macatsui */
4238 gui_mac_create_atsui_style();
4241 draw_string_ATSUI(row
, col
, s
, len
, flags
);
4244 draw_string_QD(row
, col
, s
, len
, flags
);
4248 * Return OK if the key with the termcap name "name" is supported.
4251 gui_mch_haskey(char_u
*name
)
4255 for (i
= 0; special_keys
[i
].key_sym
!= (KeySym
)0; i
++)
4256 if (name
[0] == special_keys
[i
].vim_code0
&&
4257 name
[1] == special_keys
[i
].vim_code1
)
4265 SysBeep(1); /* Should this be 0? (????) */
4269 gui_mch_flash(int msec
)
4271 /* Do a visual beep by reversing the foreground and background colors */
4275 * Note: InvertRect() excludes right and bottom of rectangle.
4279 rc
.right
= gui
.num_cols
* gui
.char_width
;
4280 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
4283 ui_delay((long)msec
, TRUE
); /* wait for some msec */
4289 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4292 gui_mch_invert_rectangle(int r
, int c
, int nr
, int nc
)
4297 * Note: InvertRect() excludes right and bottom of rectangle.
4299 rc
.left
= FILL_X(c
);
4301 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
4302 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
4307 * Iconify the GUI window.
4310 gui_mch_iconify(void)
4312 /* TODO: find out what could replace iconify
4314 * -hide application?
4318 #if defined(FEAT_EVAL) || defined(PROTO)
4320 * Bring the Vim window to the foreground.
4323 gui_mch_set_foreground(void)
4330 * Draw a cursor without focus.
4333 gui_mch_draw_hollow_cursor(guicolor_T color
)
4338 * Note: FrameRect() excludes right and bottom of rectangle.
4340 rc
.left
= FILL_X(gui
.col
);
4341 rc
.top
= FILL_Y(gui
.row
);
4342 rc
.right
= rc
.left
+ gui
.char_width
;
4344 if (mb_lefthalve(gui
.row
, gui
.col
))
4345 rc
.right
+= gui
.char_width
;
4347 rc
.bottom
= rc
.top
+ gui
.char_height
;
4349 gui_mch_set_fg_color(color
);
4355 * Draw part of a cursor, only w pixels wide, and h pixels high.
4358 gui_mch_draw_part_cursor(int w
, int h
, guicolor_T color
)
4362 #ifdef FEAT_RIGHTLEFT
4363 /* vertical line should be on the right of current point */
4364 if (CURSOR_BAR_RIGHT
)
4365 rc
.left
= FILL_X(gui
.col
+ 1) - w
;
4368 rc
.left
= FILL_X(gui
.col
);
4369 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
4370 rc
.right
= rc
.left
+ w
;
4371 rc
.bottom
= rc
.top
+ h
;
4373 gui_mch_set_fg_color(color
);
4382 * Catch up with any queued X events. This may put keyboard input into the
4383 * input buffer, call resize call-backs, trigger timers etc. If there is
4384 * nothing in the X event queue (& no timers pending), then we return
4388 gui_mch_update(void)
4390 /* TODO: find what to do
4391 * maybe call gui_mch_wait_for_chars (0)
4392 * more like look at EventQueue then
4393 * call heart of gui_mch_wait_for_chars;
4396 * gui_mac_handle_event(&event);
4398 EventRecord theEvent
;
4400 if (EventAvail(everyEvent
, &theEvent
))
4401 if (theEvent
.what
!= nullEvent
)
4402 gui_mch_wait_for_chars(0);
4406 * Simple wrapper to neglect more easily the time
4407 * spent inside WaitNextEvent while profiling.
4412 WaitNextEventWrp(EventMask eventMask
, EventRecord
*theEvent
, UInt32 sleep
, RgnHandle mouseRgn
)
4414 if (((long) sleep
) < -1)
4416 return WaitNextEvent(eventMask
, theEvent
, sleep
, mouseRgn
);
4420 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4421 * from the keyboard.
4422 * wtime == -1 Wait forever.
4423 * wtime == 0 This should never happen.
4424 * wtime > 0 Wait wtime milliseconds for a character.
4425 * Returns OK if a character was found to be available within the given time,
4426 * or FAIL otherwise.
4429 gui_mch_wait_for_chars(int wtime
)
4431 EventMask mask
= (everyEvent
);
4437 /* If we are providing life feedback with the scrollbar,
4438 * we don't want to try to wait for an event, or else
4439 * there won't be any life feedback.
4441 if (dragged_sb
!= NULL
)
4443 /* TODO: Check if FAIL is the proper return code */
4445 entryTick
= TickCount();
4447 allow_scrollbar
= TRUE
;
4451 /* if (dragRectControl == kCreateEmpty)
4454 dragRectControl = kNothing;
4456 else*/ if (dragRectControl
== kCreateRect
)
4458 dragRgn
= cursorRgn
;
4459 RectRgn(dragRgn
, &dragRect
);
4460 dragRectControl
= kNothing
;
4463 * Don't use gui_mch_update() because then we will spin-lock until a
4464 * char arrives, instead we use WaitNextEventWrp() to hang until an
4465 * event arrives. No need to check for input_buf_full because we are
4466 * returning as soon as it contains a single char.
4468 /* TODO: reduce wtime accordinly??? */
4470 sleeppyTick
= 60 * wtime
/ 1000;
4472 sleeppyTick
= 32767;
4474 if (WaitNextEventWrp(mask
, &event
, sleeppyTick
, dragRgn
))
4476 gui_mac_handle_event(&event
);
4477 if (input_available())
4479 allow_scrollbar
= FALSE
;
4483 currentTick
= TickCount();
4485 while ((wtime
== -1) || ((currentTick
- entryTick
) < 60*wtime
/1000));
4487 allow_scrollbar
= FALSE
;
4495 /* Flush any output to the screen */
4499 /* TODO: Is anything needed here? */
4503 * Clear a rectangular region of the screen from text pos (row1, col1) to
4504 * (row2, col2) inclusive.
4507 gui_mch_clear_block(int row1
, int col1
, int row2
, int col2
)
4512 * Clear one extra pixel at the far right, for when bold characters have
4513 * spilled over to the next column.
4515 rc
.left
= FILL_X(col1
);
4516 rc
.top
= FILL_Y(row1
);
4517 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
4518 rc
.bottom
= FILL_Y(row2
+ 1);
4520 gui_mch_set_bg_color(gui
.back_pixel
);
4525 * Clear the whole text window.
4528 gui_mch_clear_all(void)
4534 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
4535 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
4537 gui_mch_set_bg_color(gui
.back_pixel
);
4539 /* gui_mch_set_fg_color(gui.norm_pixel);
4545 * Delete the given number of lines from the given row, scrolling up any
4546 * text further down within the scroll region.
4549 gui_mch_delete_lines(int row
, int num_lines
)
4553 /* changed without checking! */
4554 rc
.left
= FILL_X(gui
.scroll_region_left
);
4555 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
4556 rc
.top
= FILL_Y(row
);
4557 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
4559 gui_mch_set_bg_color(gui
.back_pixel
);
4560 ScrollRect(&rc
, 0, -num_lines
* gui
.char_height
, (RgnHandle
) nil
);
4562 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
4563 gui
.scroll_region_left
,
4564 gui
.scroll_region_bot
, gui
.scroll_region_right
);
4568 * Insert the given number of lines before the given row, scrolling down any
4569 * following text within the scroll region.
4572 gui_mch_insert_lines(int row
, int num_lines
)
4576 rc
.left
= FILL_X(gui
.scroll_region_left
);
4577 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
4578 rc
.top
= FILL_Y(row
);
4579 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
4581 gui_mch_set_bg_color(gui
.back_pixel
);
4583 ScrollRect(&rc
, 0, gui
.char_height
* num_lines
, (RgnHandle
) nil
);
4585 /* Update gui.cursor_row if the cursor scrolled or copied over */
4586 if (gui
.cursor_row
>= gui
.row
4587 && gui
.cursor_col
>= gui
.scroll_region_left
4588 && gui
.cursor_col
<= gui
.scroll_region_right
)
4590 if (gui
.cursor_row
<= gui
.scroll_region_bot
- num_lines
)
4591 gui
.cursor_row
+= num_lines
;
4592 else if (gui
.cursor_row
<= gui
.scroll_region_bot
)
4593 gui
.cursor_is_valid
= FALSE
;
4596 gui_clear_block(row
, gui
.scroll_region_left
,
4597 row
+ num_lines
- 1, gui
.scroll_region_right
);
4601 * TODO: add a vim format to the clipboard which remember
4602 * LINEWISE, CHARWISE, BLOCKWISE
4606 clip_mch_request_selection(VimClipboard
*cbd
)
4612 ScrapFlavorFlags scrapFlags
;
4613 ScrapRef scrap
= nil
;
4620 error
= GetCurrentScrap(&scrap
);
4624 error
= GetScrapFlavorFlags(scrap
, VIMSCRAPFLAVOR
, &scrapFlags
);
4627 error
= GetScrapFlavorSize(scrap
, VIMSCRAPFLAVOR
, &scrapSize
);
4628 if (error
== noErr
&& scrapSize
> 1)
4634 error
= GetScrapFlavorFlags(scrap
, SCRAPTEXTFLAVOR
, &scrapFlags
);
4638 error
= GetScrapFlavorSize(scrap
, SCRAPTEXTFLAVOR
, &scrapSize
);
4643 ReserveMem(scrapSize
);
4645 /* In CARBON we don't need a Handle, a pointer is good */
4646 textOfClip
= NewHandle(scrapSize
);
4648 /* tempclip = lalloc(scrapSize+1, TRUE); */
4650 error
= GetScrapFlavorData(scrap
,
4651 flavor
? VIMSCRAPFLAVOR
: SCRAPTEXTFLAVOR
,
4652 &scrapSize
, *textOfClip
);
4653 scrapSize
-= flavor
;
4656 type
= **textOfClip
;
4658 type
= (strchr(*textOfClip
, '\r') != NULL
) ? MLINE
: MCHAR
;
4660 tempclip
= lalloc(scrapSize
+ 1, TRUE
);
4661 mch_memmove(tempclip
, *textOfClip
+ flavor
, scrapSize
);
4662 tempclip
[scrapSize
] = 0;
4664 #ifdef MACOS_CONVERT
4666 /* Convert from utf-16 (clipboard) */
4668 char_u
*to
= mac_utf16_to_enc((UniChar
*)tempclip
, scrapSize
, &encLen
);
4679 searchCR
= (char *)tempclip
;
4680 while (searchCR
!= NULL
)
4682 searchCR
= strchr(searchCR
, '\r');
4683 if (searchCR
!= NULL
)
4687 clip_yank_selection(type
, tempclip
, scrapSize
, cbd
);
4690 HUnlock(textOfClip
);
4692 DisposeHandle(textOfClip
);
4696 clip_mch_lose_selection(VimClipboard
*cbd
)
4699 * TODO: Really nothing to do?
4704 clip_mch_own_selection(VimClipboard
*cbd
)
4710 * Send the current selection to the clipboard.
4713 clip_mch_set_selection(VimClipboard
*cbd
)
4725 clip_get_selection(cbd
);
4728 * Once we set the clipboard, lose ownership. If another application sets
4729 * the clipboard, we don't want to think that we still own it.
4733 type
= clip_convert_selection(&str
, (long_u
*)&scrapSize
, cbd
);
4735 #ifdef MACOS_CONVERT
4736 size_t utf16_len
= 0;
4737 UniChar
*to
= mac_enc_to_utf16(str
, scrapSize
, &utf16_len
);
4740 scrapSize
= utf16_len
;
4748 ClearCurrentScrap();
4750 textOfClip
= NewHandle(scrapSize
+ 1);
4753 **textOfClip
= type
;
4754 mch_memmove(*textOfClip
+ 1, str
, scrapSize
);
4755 GetCurrentScrap(&scrap
);
4756 PutScrapFlavor(scrap
, SCRAPTEXTFLAVOR
, kScrapFlavorMaskNone
,
4757 scrapSize
, *textOfClip
+ 1);
4758 PutScrapFlavor(scrap
, VIMSCRAPFLAVOR
, kScrapFlavorMaskNone
,
4759 scrapSize
+ 1, *textOfClip
);
4760 HUnlock(textOfClip
);
4761 DisposeHandle(textOfClip
);
4768 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
4772 /* HideWindow(gui.VimWindow); */
4773 GetWindowBounds(gui
.VimWindow
, kWindowGlobalPortRgn
, &VimBound
);
4775 if (gui
.which_scrollbars
[SBAR_LEFT
])
4777 VimBound
.left
= -gui
.scrollbar_width
+ 1;
4784 SetWindowBounds(gui
.VimWindow
, kWindowGlobalPortRgn
, &VimBound
);
4786 ShowWindow(gui
.VimWindow
);
4794 gui_mch_enable_menu(int flag
)
4797 * Menu is always active.
4802 gui_mch_set_menu_pos(int x
, int y
, int w
, int h
)
4805 * The menu is always at the top of the screen.
4810 * Add a sub menu to the menu bar.
4813 gui_mch_add_menu(vimmenu_T
*menu
, int idx
)
4816 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4817 * TODO: use menu->mnemonic and menu->actext
4818 * TODO: Try to reuse menu id
4819 * Carbon Help suggest to use only id between 1 and 235
4821 static long next_avail_id
= 128;
4822 long menu_after_me
= 0; /* Default to the end */
4823 #if defined(FEAT_MBYTE)
4829 vimmenu_T
*parent
= menu
->parent
;
4830 vimmenu_T
*brother
= menu
->next
;
4832 /* Cannot add a menu if ... */
4833 if ((parent
!= NULL
&& parent
->submenu_id
== 0))
4836 /* menu ID greater than 1024 are reserved for ??? */
4837 if (next_avail_id
== 1024)
4840 /* My brother could be the PopUp, find my real brother */
4841 while ((brother
!= NULL
) && (!menu_is_menubar(brother
->name
)))
4842 brother
= brother
->next
;
4844 /* Find where to insert the menu (for MenuBar) */
4845 if ((parent
== NULL
) && (brother
!= NULL
))
4846 menu_after_me
= brother
->submenu_id
;
4848 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4849 if (!menu_is_menubar(menu
->name
))
4850 menu_after_me
= hierMenu
;
4852 /* Convert the name */
4853 #ifdef MACOS_CONVERT
4854 name
= menu_title_removing_mnemonic(menu
);
4856 name
= C2Pascal_save(menu
->dname
);
4861 /* Create the menu unless it's the help menu */
4863 /* Carbon suggest use of
4864 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4865 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
4867 menu
->submenu_id
= next_avail_id
;
4868 #if defined(FEAT_MBYTE)
4869 if (CreateNewMenu(menu
->submenu_id
, 0, (MenuRef
*)&menu
->submenu_handle
) == noErr
)
4870 SetMenuTitleWithCFString((MenuRef
)menu
->submenu_handle
, name
);
4872 menu
->submenu_handle
= NewMenu(menu
->submenu_id
, name
);
4879 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4881 /* TODO: Verify if we could only Insert Menu if really part of the
4882 * menubar The Inserted menu are scanned or the Command-key combos
4885 /* Insert the menu */
4886 InsertMenu(menu
->submenu_handle
, menu_after_me
); /* insert before */
4888 /* Vim should normally update it. TODO: verify */
4894 /* Adding as a submenu */
4896 index
= gui_mac_get_menu_item_index(menu
);
4898 /* Call InsertMenuItem followed by SetMenuItemText
4899 * to avoid special character recognition by InsertMenuItem
4901 InsertMenuItem(parent
->submenu_handle
, "\p ", idx
); /* afterItem */
4902 #if defined(FEAT_MBYTE)
4903 SetMenuItemTextWithCFString(parent
->submenu_handle
, idx
+1, name
);
4905 SetMenuItemText(parent
->submenu_handle
, idx
+1, name
);
4907 SetItemCmd(parent
->submenu_handle
, idx
+1, 0x1B);
4908 SetItemMark(parent
->submenu_handle
, idx
+1, menu
->submenu_id
);
4909 InsertMenu(menu
->submenu_handle
, hierMenu
);
4912 #if defined(FEAT_MBYTE)
4919 /* Done by Vim later on */
4925 * Add a menu item to a menu
4928 gui_mch_add_menu_item(vimmenu_T
*menu
, int idx
)
4930 #if defined(FEAT_MBYTE)
4935 vimmenu_T
*parent
= menu
->parent
;
4938 /* Cannot add item, if the menu have not been created */
4939 if (parent
->submenu_id
== 0)
4942 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4943 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4945 /* Convert the name */
4946 #ifdef MACOS_CONVERT
4947 name
= menu_title_removing_mnemonic(menu
);
4949 name
= C2Pascal_save(menu
->dname
);
4952 /* Where are just a menu item, so no handle, no id */
4953 menu
->submenu_id
= 0;
4954 menu
->submenu_handle
= NULL
;
4959 /* If the accelerator text for the menu item looks like it describes
4960 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4961 * item's command equivalent.
4967 p_actext
= menu
->actext
;
4968 key
= find_special_key(&p_actext
, &modifiers
, /*keycode=*/0);
4970 key
= 0; /* error: trailing text */
4971 /* find_special_key() returns a keycode with as many of the
4972 * specified modifiers as appropriate already applied (e.g., for
4973 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4974 * as the only modifier). Since we want to display all of the
4975 * modifiers, we need to convert the keycode back to a printable
4976 * character plus modifiers.
4977 * TODO: Write an alternative find_special_key() that doesn't
4980 if (key
> 0 && key
< 32)
4982 /* Convert a control key to an uppercase letter. Note that
4983 * by this point it is no longer possible to distinguish
4984 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4986 modifiers
|= MOD_MASK_CTRL
;
4989 /* If the keycode is an uppercase letter, set the Shift modifier.
4990 * If it is a lowercase letter, don't set the modifier, but convert
4991 * the letter to uppercase for display in the menu.
4993 else if (key
>= 'A' && key
<= 'Z')
4994 modifiers
|= MOD_MASK_SHIFT
;
4995 else if (key
>= 'a' && key
<= 'z')
4997 /* Note: keycodes below 0x22 are reserved by Apple. */
4998 if (key
>= 0x22 && vim_isprintc_strict(key
))
5001 char_u mac_mods
= kMenuNoModifiers
;
5002 /* Convert Vim modifier codes to Menu Manager equivalents. */
5003 if (modifiers
& MOD_MASK_SHIFT
)
5004 mac_mods
|= kMenuShiftModifier
;
5005 if (modifiers
& MOD_MASK_CTRL
)
5006 mac_mods
|= kMenuControlModifier
;
5007 if (!(modifiers
& MOD_MASK_CMD
))
5008 mac_mods
|= kMenuNoCommandModifier
;
5009 if (modifiers
& MOD_MASK_ALT
|| modifiers
& MOD_MASK_MULTI_CLICK
)
5010 valid
= 0; /* TODO: will Alt someday map to Option? */
5013 char_u item_txt
[10];
5014 /* Insert the menu item after idx, with its command key. */
5015 item_txt
[0] = 3; item_txt
[1] = ' '; item_txt
[2] = '/';
5017 InsertMenuItem(parent
->submenu_handle
, item_txt
, idx
);
5018 /* Set the modifier keys. */
5019 SetMenuItemModifiers(parent
->submenu_handle
, idx
+1, mac_mods
);
5024 /* Call InsertMenuItem followed by SetMenuItemText
5025 * to avoid special character recognition by InsertMenuItem
5028 InsertMenuItem(parent
->submenu_handle
, "\p ", idx
); /* afterItem */
5029 /* Set the menu item name. */
5030 #if defined(FEAT_MBYTE)
5031 SetMenuItemTextWithCFString(parent
->submenu_handle
, idx
+1, name
);
5033 SetMenuItemText(parent
->submenu_handle
, idx
+1, name
);
5041 #if defined(FEAT_MBYTE)
5044 /* TODO: Can name be freed? */
5050 gui_mch_toggle_tearoffs(int enable
)
5052 /* no tearoff menus */
5056 * Destroy the machine specific menu widget.
5059 gui_mch_destroy_menu(vimmenu_T
*menu
)
5061 short index
= gui_mac_get_menu_item_index(menu
);
5068 /* For now just don't delete help menu items. (Huh? Dany) */
5069 DeleteMenuItem(menu
->parent
->submenu_handle
, index
);
5071 /* Delete the Menu if it was a hierarchical Menu */
5072 if (menu
->submenu_id
!= 0)
5074 DeleteMenu(menu
->submenu_id
);
5075 DisposeMenu(menu
->submenu_handle
);
5079 #ifdef DEBUG_MAC_MENU
5089 DeleteMenu(menu
->submenu_id
);
5090 DisposeMenu(menu
->submenu_handle
);
5093 /* Shouldn't this be already done by Vim. TODO: Check */
5098 * Make a menu either grey or not grey.
5101 gui_mch_menu_grey(vimmenu_T
*menu
, int grey
)
5103 /* TODO: Check if menu really exists */
5104 short index
= gui_mac_get_menu_item_index(menu
);
5106 index = menu->index;
5111 DisableMenuItem(menu
->submenu_handle
, index
);
5113 if (menu
->parent
->submenu_handle
)
5114 DisableMenuItem(menu
->parent
->submenu_handle
, index
);
5119 EnableMenuItem(menu
->submenu_handle
, index
);
5121 if (menu
->parent
->submenu_handle
)
5122 EnableMenuItem(menu
->parent
->submenu_handle
, index
);
5127 * Make menu item hidden or not hidden
5130 gui_mch_menu_hidden(vimmenu_T
*menu
, int hidden
)
5132 /* There's no hidden mode on MacOS */
5133 gui_mch_menu_grey(menu
, hidden
);
5138 * This is called after setting all the menus to grey/hidden or not.
5141 gui_mch_draw_menubar(void)
5152 gui_mch_enable_scrollbar(
5157 ShowControl(sb
->id
);
5159 HideControl(sb
->id
);
5162 printf("enb_sb (%x) %x\n",sb
->id
, flag
);
5167 gui_mch_set_scrollbar_thumb(
5173 SetControl32BitMaximum (sb
->id
, max
);
5174 SetControl32BitMinimum (sb
->id
, 0);
5175 SetControl32BitValue (sb
->id
, val
);
5176 SetControlViewSize (sb
->id
, size
);
5178 printf("thumb_sb (%x) %x, %x,%x\n",sb
->id
, val
, size
, max
);
5183 gui_mch_set_scrollbar_pos(
5190 gui_mch_set_bg_color(gui
.back_pixel
);
5191 /* if (gui.which_scrollbars[SBAR_LEFT])
5193 MoveControl(sb->id, x-16, y);
5194 SizeControl(sb->id, w + 1, h);
5198 MoveControl(sb->id, x, y);
5199 SizeControl(sb->id, w + 1, h);
5201 if (sb
== &gui
.bottom_sbar
)
5206 if (gui
.which_scrollbars
[SBAR_LEFT
])
5209 MoveControl(sb
->id
, x
, y
);
5210 SizeControl(sb
->id
, w
, h
);
5212 printf("size_sb (%x) %x, %x, %x, %x\n",sb
->id
, x
, y
, w
, h
);
5217 gui_mch_create_scrollbar(
5219 int orient
) /* SBAR_VERT or SBAR_HORIZ */
5224 bounds
.bottom
= -10;
5228 sb
->id
= NewControl(gui
.VimWindow
,
5235 kControlScrollBarLiveProc
,
5238 printf("create_sb (%x) %x\n",sb
->id
, orient
);
5243 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
5245 gui_mch_set_bg_color(gui
.back_pixel
);
5246 DisposeControl(sb
->id
);
5248 printf("dest_sb (%x) \n",sb
->id
);
5254 * Cursor blink functions.
5256 * This is a simple state machine:
5257 * BLINK_NONE not blinking at all
5258 * BLINK_OFF blinking, cursor is not shown
5259 * BLINK_ON blinking, cursor is shown
5262 gui_mch_set_blinking(long wait
, long on
, long off
)
5264 /* TODO: TODO: TODO: TODO: */
5265 /* blink_waittime = wait;
5267 blink_offtime = off;*/
5271 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5274 gui_mch_stop_blink(void)
5276 gui_update_cursor(TRUE
, FALSE
);
5277 /* TODO: TODO: TODO: TODO: */
5278 /* gui_w32_rm_blink_timer();
5279 if (blink_state == BLINK_OFF)
5280 gui_update_cursor(TRUE, FALSE);
5281 blink_state = BLINK_NONE;*/
5285 * Start the cursor blinking. If it was already blinking, this restarts the
5286 * waiting time and shows the cursor.
5289 gui_mch_start_blink(void)
5291 gui_update_cursor(TRUE
, FALSE
);
5292 /* TODO: TODO: TODO: TODO: */
5293 /* gui_w32_rm_blink_timer(); */
5295 /* Only switch blinking on if none of the times is zero */
5296 /* if (blink_waittime && blink_ontime && blink_offtime)
5298 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5299 (TIMERPROC)_OnBlinkTimer);
5300 blink_state = BLINK_ON;
5301 gui_update_cursor(TRUE, FALSE);
5306 * Return the RGB value of a pixel as long.
5309 gui_mch_get_rgb(guicolor_T pixel
)
5311 return (Red(pixel
) << 16) + (Green(pixel
) << 8) + Blue(pixel
);
5318 * Pop open a file browser and return the file selected, in allocated memory,
5319 * or NULL if Cancel is hit.
5320 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5321 * title - Title message for the file browser dialog.
5322 * dflt - Default name of file.
5323 * ext - Default extension to be added to files without extensions.
5324 * initdir - directory in which to open the browser (NULL = current dir)
5325 * filter - Filter for matched files to choose from.
5326 * Has a format like this:
5327 * "C Files (*.c)\0*.c\0"
5328 * "All Files\0*.*\0\0"
5329 * If these two strings were concatenated, then a choice of two file
5330 * filters will be selectable to the user. Then only matching files will
5331 * be shown in the browser. If NULL, the default allows all files.
5333 * *NOTE* - the filter string must be terminated with TWO nulls.
5344 /* TODO: Add Ammon's safety checl (Dany) */
5345 NavReplyRecord reply
;
5346 char_u
*fname
= NULL
;
5347 char_u
**fnames
= NULL
;
5349 NavDialogOptions navOptions
;
5352 /* Get Navigation Service Defaults value */
5353 NavGetDefaultDialogOptions(&navOptions
);
5356 /* TODO: If we get a :browse args, set the Multiple bit. */
5357 navOptions
.dialogOptionFlags
= kNavAllowInvisibleFiles
5358 | kNavDontAutoTranslate
5359 | kNavDontAddTranslateItems
5360 /* | kNavAllowMultipleFiles */
5361 | kNavAllowStationery
;
5363 (void) C2PascalString(title
, &navOptions
.message
);
5364 (void) C2PascalString(dflt
, &navOptions
.savedFileName
);
5365 /* Could set clientName?
5366 * windowTitle? (there's no title bar?)
5371 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5372 NavPutFile(NULL
, &reply
, &navOptions
, NULL
, 'TEXT', 'VIM!', NULL
);
5373 if (!reply
.validRecord
)
5378 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5379 NavGetFile(NULL
, &reply
, &navOptions
, NULL
, NULL
, NULL
, NULL
, NULL
);
5380 if (!reply
.validRecord
)
5384 fnames
= new_fnames_from_AEDesc(&reply
.selection
, &numFiles
, &error
);
5386 NavDisposeReply(&reply
);
5394 /* TODO: Shorten the file name if possible */
5397 #endif /* FEAT_BROWSE */
5399 #ifdef FEAT_GUI_DIALOG
5401 * Stuff for dialogues
5405 * Create a dialogue dynamically from the parameter strings.
5406 * type = type of dialogue (question, alert, etc.)
5407 * title = dialogue title. may be NULL for default title.
5408 * message = text to display. Dialogue sizes to accommodate it.
5409 * buttons = '\n' separated list of button captions, default first.
5410 * dfltbutton = number of default button.
5412 * This routine returns 1 if the first button is pressed,
5413 * 2 for the second, etc.
5415 * 0 indicates Esc was pressed.
5416 * -1 for unexpected error
5418 * If stubbing out this fn, return 1.
5424 short width
; /* Size of the text in pixel */
5426 } vgmDlgItm
; /* Vim Gui_Mac.c Dialog Item */
5428 #define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5432 DialogRef theDialog
,
5438 #if 0 /* USE_CARBONIZED */
5440 MoveDialogItem(theDialog
, itemNumber
, X
, Y
);
5442 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, inBox
);
5447 Rect
*itemBox
= &localBox
;
5452 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, itemBox
);
5453 OffsetRect(itemBox
, -itemBox
->left
, -itemBox
->top
);
5454 OffsetRect(itemBox
, X
, Y
);
5455 /* To move a control (like a button) we need to call both
5456 * MoveControl and SetDialogItem. FAQ 6-18 */
5457 if (1) /*(itemType & kControlDialogItem) */
5458 MoveControl((ControlRef
) itemHandle
, X
, Y
);
5459 SetDialogItem(theDialog
, itemNumber
, itemType
, itemHandle
, itemBox
);
5465 DialogRef theDialog
,
5474 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, &itemBox
);
5476 /* When width or height is zero do not change it */
5478 width
= itemBox
.right
- itemBox
.left
;
5480 height
= itemBox
.bottom
- itemBox
.top
;
5482 #if 0 /* USE_CARBONIZED */
5483 SizeDialogItem(theDialog
, itemNumber
, width
, height
); /* Untested */
5485 /* Resize the bounding box */
5486 itemBox
.right
= itemBox
.left
+ width
;
5487 itemBox
.bottom
= itemBox
.top
+ height
;
5489 /* To resize a control (like a button) we need to call both
5490 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5491 if (itemType
& kControlDialogItem
)
5492 SizeControl((ControlRef
) itemHandle
, width
, height
);
5494 /* Configure back the item */
5495 SetDialogItem(theDialog
, itemNumber
, itemType
, itemHandle
, &itemBox
);
5500 macSetDialogItemText(
5501 DialogRef theDialog
,
5509 GetDialogItem(theDialog
, itemNumber
, &itemType
, &itemHandle
, &itemBox
);
5511 if (itemType
& kControlDialogItem
)
5512 SetControlTitle((ControlRef
) itemHandle
, itemName
);
5514 SetDialogItemText(itemHandle
, itemName
);
5518 /* ModalDialog() handler for message dialogs that have hotkey accelerators.
5519 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5520 * setting gDialogHotKeys to NULL disables any hotkey handling.
5522 static pascal Boolean
5523 DialogHotkeyFilterProc (
5524 DialogRef theDialog
,
5526 DialogItemIndex
*itemHit
)
5530 if (event
->what
== keyDown
|| event
->what
== autoKey
)
5532 keyHit
= (event
->message
& charCodeMask
);
5534 if (gDialogHotKeys
&& gDialogHotKeys
[keyHit
])
5536 #ifdef DEBUG_MAC_DIALOG_HOTKEYS
5537 printf("user pressed hotkey '%c' --> item %d\n", keyHit
, gDialogHotKeys
[keyHit
]);
5539 *itemHit
= gDialogHotKeys
[keyHit
];
5541 /* When handing off to StdFilterProc, pretend that the user
5542 * clicked the control manually. Note that this is also supposed
5543 * to cause the button to hilite briefly (to give some user
5544 * feedback), but this seems not to actually work (or it's too
5547 event
->what
= kEventControlSimulateHit
;
5549 return true; /* we took care of it */
5552 /* Defer to the OS's standard behavior for this event.
5553 * This ensures that Enter will still activate the default button. */
5554 return StdFilterProc(theDialog
, event
, itemHit
);
5556 return false; /* Let ModalDialog deal with it */
5560 /* TODO: There have been some crashes with dialogs, check your inbox
5578 DialogPtr theDialog
;
5580 char_u PascalTitle
[256]; /* place holder for the title */
5585 short hotKeys
[256]; /* map of hotkey -> control ID */
5593 short totalButtonWidth
= 0; /* the width of all buttons together
5594 including spacing */
5595 short widestButton
= 0;
5596 short dfltButtonEdge
= 20; /* gut feeling */
5597 short dfltElementSpacing
= 13; /* from IM:V.2-29 */
5598 short dfltIconSideSpace
= 23; /* from IM:V.2-29 */
5599 short maximumWidth
= 400; /* gut feeling */
5600 short maxButtonWidth
= 175; /* gut feeling */
5604 short messageLines
= 3;
5605 FontInfo textFontInfo
;
5608 vgmDlgItm messageItm
;
5610 vgmDlgItm buttonItm
;
5612 WindowRef theWindow
;
5614 ModalFilterUPP dialogUPP
;
5616 /* Check 'v' flag in 'guioptions': vertical button placement. */
5617 vertical
= (vim_strchr(p_go
, GO_VERTICAL
) != NULL
);
5619 /* Create a new Dialog Box from template. */
5620 theDialog
= GetNewDialog(129, nil
, (WindowRef
) -1);
5622 /* Get the WindowRef */
5623 theWindow
= GetDialogWindow(theDialog
);
5626 * 1. to avoid seeing slow drawing
5627 * 2. to prevent a problem seen while moving dialog item
5628 * within a visible window. (non-Carbon MacOS 9)
5629 * Could be avoided by changing the resource.
5631 HideWindow(theWindow
);
5633 /* Change the graphical port to the dialog,
5634 * so we can measure the text with the proper font */
5636 SetPortDialogPort(theDialog
);
5638 /* Get the info about the default text,
5639 * used to calculate the height of the message
5640 * and of the text field */
5641 GetFontInfo(&textFontInfo
);
5643 /* Set the dialog title */
5646 (void) C2PascalString(title
, &PascalTitle
);
5647 SetWTitle(theWindow
, PascalTitle
);
5650 /* Creates the buttons and add them to the Dialog Box. */
5651 buttonDITL
= GetResource('DITL', 130);
5652 buttonChar
= buttons
;
5655 /* initialize the hotkey mapping */
5656 memset(hotKeys
, 0, sizeof(hotKeys
));
5658 for (;*buttonChar
!= 0;)
5660 /* Get the name of the button */
5663 for (;((*buttonChar
!= DLG_BUTTON_SEP
) && (*buttonChar
!= 0) && (len
< 255)); buttonChar
++)
5665 if (*buttonChar
!= DLG_HOTKEY_CHAR
)
5666 name
[++len
] = *buttonChar
;
5669 aHotKey
= (char_u
)*(buttonChar
+1);
5670 if (aHotKey
>= 'A' && aHotKey
<= 'Z')
5671 aHotKey
= (char_u
)((int)aHotKey
+ (int)'a' - (int)'A');
5672 hotKeys
[aHotKey
] = button
;
5673 #ifdef DEBUG_MAC_DIALOG_HOTKEYS
5674 printf("### hotKey for button %d is '%c'\n", button
, aHotKey
);
5679 if (*buttonChar
!= 0)
5683 /* Add the button */
5684 AppendDITL(theDialog
, buttonDITL
, overlayDITL
); /* appendDITLRight); */
5686 /* Change the button's name */
5687 macSetDialogItemText(theDialog
, button
, name
);
5689 /* Resize the button to fit its name */
5690 width
= StringWidth(name
) + 2 * dfltButtonEdge
;
5691 /* Limite the size of any button to an acceptable value. */
5692 /* TODO: Should be based on the message width */
5693 if (width
> maxButtonWidth
)
5694 width
= maxButtonWidth
;
5695 macSizeDialogItem(theDialog
, button
, width
, 0);
5697 totalButtonWidth
+= width
;
5699 if (width
> widestButton
)
5700 widestButton
= width
;
5702 ReleaseResource(buttonDITL
);
5703 lastButton
= button
;
5705 /* Add the icon to the Dialog Box. */
5706 iconItm
.idx
= lastButton
+ 1;
5707 iconDITL
= GetResource('DITL', 131);
5710 case VIM_GENERIC
: useIcon
= kNoteIcon
;
5711 case VIM_ERROR
: useIcon
= kStopIcon
;
5712 case VIM_WARNING
: useIcon
= kCautionIcon
;
5713 case VIM_INFO
: useIcon
= kNoteIcon
;
5714 case VIM_QUESTION
: useIcon
= kNoteIcon
;
5715 default: useIcon
= kStopIcon
;
5717 AppendDITL(theDialog
, iconDITL
, overlayDITL
);
5718 ReleaseResource(iconDITL
);
5719 GetDialogItem(theDialog
, iconItm
.idx
, &itemType
, &itemHandle
, &box
);
5720 /* TODO: Should the item be freed? */
5721 iconHandle
= GetIcon(useIcon
);
5722 SetDialogItem(theDialog
, iconItm
.idx
, itemType
, iconHandle
, &box
);
5724 /* Add the message to the Dialog box. */
5725 messageItm
.idx
= lastButton
+ 2;
5726 messageDITL
= GetResource('DITL', 132);
5727 AppendDITL(theDialog
, messageDITL
, overlayDITL
);
5728 ReleaseResource(messageDITL
);
5729 GetDialogItem(theDialog
, messageItm
.idx
, &itemType
, &itemHandle
, &box
);
5730 (void) C2PascalString(message
, &name
);
5731 SetDialogItemText(itemHandle
, name
);
5732 messageItm
.width
= StringWidth(name
);
5734 /* Add the input box if needed */
5735 if (textfield
!= NULL
)
5737 /* Cheat for now reuse the message and convert to text edit */
5738 inputItm
.idx
= lastButton
+ 3;
5739 inputDITL
= GetResource('DITL', 132);
5740 AppendDITL(theDialog
, inputDITL
, overlayDITL
);
5741 ReleaseResource(inputDITL
);
5742 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &box
);
5743 /* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5744 (void) C2PascalString(textfield
, &name
);
5745 SetDialogItemText(itemHandle
, name
);
5746 inputItm
.width
= StringWidth(name
);
5748 /* Hotkeys don't make sense if there's a text field */
5749 gDialogHotKeys
= NULL
;
5752 /* Install hotkey table */
5753 gDialogHotKeys
= (short *)&hotKeys
;
5755 /* Set the <ENTER> and <ESC> button. */
5756 SetDialogDefaultItem(theDialog
, dfltbutton
);
5757 SetDialogCancelItem(theDialog
, 0);
5759 /* Reposition element */
5761 /* Check if we need to force vertical */
5762 if (totalButtonWidth
> maximumWidth
)
5766 macMoveDialogItem(theDialog
, iconItm
.idx
, dfltIconSideSpace
, dfltElementSpacing
, &box
);
5767 iconItm
.box
.right
= box
.right
;
5768 iconItm
.box
.bottom
= box
.bottom
;
5771 messageItm
.box
.left
= iconItm
.box
.right
+ dfltIconSideSpace
;
5772 macSizeDialogItem(theDialog
, messageItm
.idx
, 0, messageLines
* (textFontInfo
.ascent
+ textFontInfo
.descent
));
5773 macMoveDialogItem(theDialog
, messageItm
.idx
, messageItm
.box
.left
, dfltElementSpacing
, &messageItm
.box
);
5776 if (textfield
!= NULL
)
5778 inputItm
.box
.left
= messageItm
.box
.left
;
5779 inputItm
.box
.top
= messageItm
.box
.bottom
+ dfltElementSpacing
;
5780 macSizeDialogItem(theDialog
, inputItm
.idx
, 0, textFontInfo
.ascent
+ textFontInfo
.descent
);
5781 macMoveDialogItem(theDialog
, inputItm
.idx
, inputItm
.box
.left
, inputItm
.box
.top
, &inputItm
.box
);
5782 /* Convert the static text into a text edit.
5783 * For some reason this change need to be done last (Dany) */
5784 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &inputItm
.box
);
5785 SetDialogItem(theDialog
, inputItm
.idx
, kEditTextDialogItem
, itemHandle
, &inputItm
.box
);
5786 SelectDialogItemText(theDialog
, inputItm
.idx
, 0, 32767);
5790 if (textfield
!= NULL
)
5792 buttonItm
.box
.left
= inputItm
.box
.left
;
5793 buttonItm
.box
.top
= inputItm
.box
.bottom
+ dfltElementSpacing
;
5797 buttonItm
.box
.left
= messageItm
.box
.left
;
5798 buttonItm
.box
.top
= messageItm
.box
.bottom
+ dfltElementSpacing
;
5801 for (button
=1; button
<= lastButton
; button
++)
5804 macMoveDialogItem(theDialog
, button
, buttonItm
.box
.left
, buttonItm
.box
.top
, &box
);
5805 /* With vertical, it's better to have all buttons the same length */
5808 macSizeDialogItem(theDialog
, button
, widestButton
, 0);
5809 GetDialogItem(theDialog
, button
, &itemType
, &itemHandle
, &box
);
5811 /* Calculate position of next button */
5813 buttonItm
.box
.top
= box
.bottom
+ dfltElementSpacing
;
5815 buttonItm
.box
.left
= box
.right
+ dfltElementSpacing
;
5818 /* Resize the dialog box */
5819 dialogHeight
= box
.bottom
+ dfltElementSpacing
;
5820 SizeWindow(theWindow
, maximumWidth
, dialogHeight
, TRUE
);
5823 AutoSizeDialog(theDialog
);
5824 /* Need a horizontal resize anyway so not that useful */
5827 ShowWindow(theWindow
);
5828 /* BringToFront(theWindow); */
5829 SelectWindow(theWindow
);
5831 /* DrawDialog(theDialog); */
5834 SetPortDialogPort(theDialog
);
5837 #ifdef USE_CARBONKEYHANDLER
5838 /* Avoid that we use key events for the main window. */
5842 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5843 dialogUPP
= NewModalFilterUPP(DialogHotkeyFilterProc
);
5845 /* Hang until one of the button is hit */
5848 ModalDialog(dialogUPP
, &itemHit
);
5849 } while ((itemHit
< 1) || (itemHit
> lastButton
));
5851 #ifdef USE_CARBONKEYHANDLER
5852 dialog_busy
= FALSE
;
5855 /* Copy back the text entered by the user into the param */
5856 if (textfield
!= NULL
)
5858 GetDialogItem(theDialog
, inputItm
.idx
, &itemType
, &itemHandle
, &box
);
5859 GetDialogItemText(itemHandle
, (char_u
*) &name
);
5861 /* Truncate the name to IOSIZE if needed */
5862 if (name
[0] > IOSIZE
)
5863 name
[0] = IOSIZE
- 1;
5865 vim_strncpy(textfield
, &name
[1], name
[0]);
5868 /* Restore the original graphical port */
5871 /* Free the modal filterProc */
5872 DisposeRoutineDescriptor(dialogUPP
);
5874 /* Get ride of th edialog (free memory) */
5875 DisposeDialog(theDialog
);
5879 * Usefull thing which could be used
5880 * SetDialogTimeout(): Auto click a button after timeout
5881 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5882 * MoveDialogItem(): Probably better than SetDialogItem
5883 * SizeDialogItem(): (but is it Carbon Only?)
5884 * AutoSizeDialog(): Magic resize of dialog based on text length
5887 #endif /* FEAT_DIALOG_GUI */
5890 * Display the saved error message(s).
5892 #ifdef USE_MCH_ERRMSG
5894 display_errors(void)
5899 if (error_ga
.ga_data
== NULL
)
5902 /* avoid putting up a message box with blanks only */
5903 for (p
= (char *)error_ga
.ga_data
; *p
; ++p
)
5906 if (STRLEN(p
) > 255)
5909 pError
[0] = STRLEN(p
);
5911 STRNCPY(&pError
[1], p
, pError
[0]);
5912 ParamText(pError
, nil
, nil
, nil
);
5915 /* TODO: handled message longer than 256 chars
5916 * use auto-sizeable alert
5917 * or dialog with scrollbars (TextEdit zone)
5920 ga_clear(&error_ga
);
5925 * Get current mouse coordinates in text window.
5928 gui_mch_getmouse(int *x
, int *y
)
5939 gui_mch_setmouse(int x
, int y
)
5945 CursorDevicePtr myMouse
;
5948 if ( NGetTrapAddress(_CursorDeviceDispatch
, ToolTrap
)
5949 != NGetTrapAddress(_Unimplemented
, ToolTrap
))
5954 * Get first devoice with one button.
5955 * This will probably be the standad mouse
5956 * startat head of cursor dev list
5964 /* Get the next cursor device */
5965 CursorDeviceNextDevice(&myMouse
);
5967 while ((myMouse
!= nil
) && (myMouse
->cntButtons
!= 1));
5969 CursorDeviceMoveTo(myMouse
, x
, y
);
5977 *(Point
*)RawMouse
= where
;
5978 *(Point
*)MTemp
= where
;
5979 *(Ptr
) CrsrNew
= 0xFFFF;
5985 gui_mch_show_popupmenu(vimmenu_T
*menu
)
5988 * Clone PopUp to use menu
5989 * Create a object descriptor for the current selection
5990 * Call the procedure
5993 MenuHandle CntxMenu
;
5998 UInt16 CntxMenuItem
;
5999 Str255 HelpName
= "";
6002 /* Save Current Port: On MacOS X we seem to lose the port */
6003 GetPort(&savePort
); /*OSX*/
6006 LocalToGlobal(&where
); /*OSX*/
6007 CntxMenu
= menu
->submenu_handle
;
6009 /* TODO: Get the text selection from Vim */
6011 /* Call to Handle Popup */
6012 status
= ContextualMenuSelect(CntxMenu
, where
, false, kCMHelpItemRemoveHelp
,
6013 HelpName
, NULL
, &CntxType
, &CntxMenuID
, &CntxMenuItem
);
6015 if (status
== noErr
)
6017 if (CntxType
== kCMMenuItemSelected
)
6019 /* Handle the menu CntxMenuID, CntxMenuItem */
6020 /* The submenu can be handle directly by gui_mac_handle_menu */
6021 /* But what about the current menu, is the menu changed by
6022 * ContextualMenuSelect */
6023 gui_mac_handle_menu((CntxMenuID
<< 16) + CntxMenuItem
);
6025 else if (CntxMenuID
== kCMShowHelpSelected
)
6027 /* Should come up with the help */
6031 /* Restore original Port */
6032 SetPort(savePort
); /*OSX*/
6035 #if defined(FEAT_CW_EDITOR) || defined(PROTO)
6036 /* TODO: Is it need for MACOS_X? (Dany) */
6038 mch_post_buffer_write(buf_T
*buf
)
6040 GetFSSpecFromPath(buf
->b_ffname
, &buf
->b_FSSpec
);
6041 Send_KAHL_MOD_AE(buf
);
6047 * Set the window title and icon.
6048 * (The icon is not taken care of).
6051 gui_mch_settitle(char_u
*title
, char_u
*icon
)
6053 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6054 * that 256. Even better get it to fit nicely in the titlebar.
6056 #ifdef MACOS_CONVERT
6057 CFStringRef windowTitle
;
6058 size_t windowTitleLen
;
6060 char_u
*pascalTitle
;
6063 if (title
== NULL
) /* nothing to do */
6066 #ifdef MACOS_CONVERT
6067 windowTitleLen
= STRLEN(title
);
6068 windowTitle
= (CFStringRef
)mac_enc_to_cfstring(title
, windowTitleLen
);
6072 SetWindowTitleWithCFString(gui
.VimWindow
, windowTitle
);
6073 CFRelease(windowTitle
);
6076 pascalTitle
= C2Pascal_save(title
);
6077 if (pascalTitle
!= NULL
)
6079 SetWTitle(gui
.VimWindow
, pascalTitle
);
6080 vim_free(pascalTitle
);
6087 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6091 C2PascalString(char_u
*CString
, Str255
*PascalString
)
6093 char_u
*PascalPtr
= (char_u
*) PascalString
;
6098 if (CString
== NULL
)
6101 len
= STRLEN(CString
);
6105 for (i
= 0; i
< len
; i
++)
6106 PascalPtr
[i
+1] = CString
[i
];
6114 GetFSSpecFromPath(char_u
*file
, FSSpec
*fileFSSpec
)
6121 (void) C2PascalString(file
, &filePascal
);
6123 myCPB
.dirInfo
.ioNamePtr
= filePascal
;
6124 myCPB
.dirInfo
.ioVRefNum
= 0;
6125 myCPB
.dirInfo
.ioFDirIndex
= 0;
6126 myCPB
.dirInfo
.ioDrDirID
= 0;
6128 err
= PBGetCatInfo(&myCPB
, false);
6130 /* vRefNum, dirID, name */
6131 FSMakeFSSpec(0, 0, filePascal
, fileFSSpec
);
6133 /* TODO: Use an error code mechanism */
6138 * Convert a FSSpec to a fuill path
6141 char_u
*FullPathFromFSSpec_save(FSSpec file
)
6144 * TODO: Add protection for 256 char max.
6149 char_u
*filenamePtr
= fname
;
6152 #ifdef USE_UNIXFILENAME
6153 SInt16 dfltVol_vRefNum
;
6154 SInt32 dfltVol_dirID
;
6157 UInt32 pathSize
= 256;
6158 char_u pathname
[256];
6159 char_u
*path
= pathname
;
6161 Str255 directoryName
;
6162 char_u temporary
[255];
6163 char_u
*temporaryPtr
= temporary
;
6166 #ifdef USE_UNIXFILENAME
6167 /* Get the default volume */
6168 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
6169 error
=HGetVol(NULL
, &dfltVol_vRefNum
, &dfltVol_dirID
);
6175 /* Start filling fname with file.name */
6176 vim_strncpy(filenamePtr
, &file
.name
[1], file
.name
[0]);
6178 /* Get the info about the file specified in FSSpec */
6179 theCPB
.dirInfo
.ioFDirIndex
= 0;
6180 theCPB
.dirInfo
.ioNamePtr
= file
.name
;
6181 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
6182 /*theCPB.hFileInfo.ioDirID = 0;*/
6183 theCPB
.dirInfo
.ioDrDirID
= file
.parID
;
6185 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6186 which is relative to ioVrefNum, ioDirID */
6187 error
= PBGetCatInfo(&theCPB
, false);
6189 /* If we are called for a new file we expect fnfErr */
6190 if ((error
) && (error
!= fnfErr
))
6193 /* Check if it's a file or folder */
6194 /* default to file if file don't exist */
6195 if (((theCPB
.hFileInfo
.ioFlAttrib
& ioDirMask
) == 0) || (error
))
6196 folder
= 0; /* It's not a folder */
6200 #ifdef USE_UNIXFILENAME
6202 * The function used here are available in Carbon, but
6203 * do nothing une MacOS 8 and 9
6205 if (error
== fnfErr
)
6207 /* If the file to be saved does not already exist, it isn't possible
6208 to convert its FSSpec into an FSRef. But we can construct an
6209 FSSpec for the file's parent folder (since we have its volume and
6210 directory IDs), and since that folder does exist, we can convert
6211 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6212 and, finally, append the filename. */
6215 Str255 emptyFilename
= "\p";
6216 error
= FSMakeFSSpec(theCPB
.dirInfo
.ioVRefNum
,
6217 theCPB
.dirInfo
.ioDrDirID
, emptyFilename
, &dirSpec
);
6221 error
= FSpMakeFSRef(&dirSpec
, &dirRef
);
6225 status
= FSRefMakePath(&dirRef
, (UInt8
*)path
, pathSize
);
6230 STRCAT(path
, filenamePtr
);
6234 /* If the file to be saved already exists, we can get its full path
6235 by converting its FSSpec into an FSRef. */
6236 error
=FSpMakeFSRef(&file
, &refFile
);
6240 status
=FSRefMakePath(&refFile
, (UInt8
*) path
, pathSize
);
6245 /* Add a slash at the end if needed */
6249 return (vim_strsave(path
));
6251 /* TODO: Get rid of all USE_UNIXFILENAME below */
6252 /* Set ioNamePtr, it's the same area which is always reused. */
6253 theCPB
.dirInfo
.ioNamePtr
= directoryName
;
6255 /* Trick for first entry, set ioDrParID to the first value
6256 * we want for ioDrDirID*/
6257 theCPB
.dirInfo
.ioDrParID
= file
.parID
;
6258 theCPB
.dirInfo
.ioDrDirID
= file
.parID
;
6260 if ((TRUE
) && (file
.parID
!= fsRtDirID
/*fsRtParID*/))
6263 theCPB
.dirInfo
.ioFDirIndex
= -1;
6264 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6265 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
6266 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
6267 theCPB
.dirInfo
.ioDrDirID
= theCPB
.dirInfo
.ioDrParID
;
6269 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6270 /* *ioNamePtr[0 TO 31] will be updated */
6271 error
= PBGetCatInfo(&theCPB
,false);
6276 /* Put the new directoryName in front of the current fname */
6277 STRCPY(temporaryPtr
, filenamePtr
);
6278 vim_strncpy(filenamePtr
, &directoryName
[1], directoryName
[0]);
6279 STRCAT(filenamePtr
, ":");
6280 STRCAT(filenamePtr
, temporaryPtr
);
6282 #if 1 /* def USE_UNIXFILENAME */
6283 while ((theCPB
.dirInfo
.ioDrParID
!= fsRtDirID
) /* && */
6284 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6286 while (theCPB
.dirInfo
.ioDrDirID
!= fsRtDirID
);
6289 /* Get the information about the volume on which the file reside */
6290 theCPB
.dirInfo
.ioFDirIndex
= -1;
6291 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6292 theCPB
.dirInfo
.ioVRefNum
= file
.vRefNum
;
6293 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
6294 theCPB
.dirInfo
.ioDrDirID
= theCPB
.dirInfo
.ioDrParID
;
6296 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6297 /* *ioNamePtr[0 TO 31] will be updated */
6298 error
= PBGetCatInfo(&theCPB
,false);
6303 /* For MacOS Classic always add the volume name */
6304 /* For MacOS X add the volume name preceded by "Volumes" */
6305 /* when we are not referring to the boot volume */
6306 #ifdef USE_UNIXFILENAME
6307 if (file
.vRefNum
!= dfltVol_vRefNum
)
6310 /* Add the volume name */
6311 STRCPY(temporaryPtr
, filenamePtr
);
6312 vim_strncpy(filenamePtr
, &directoryName
[1], directoryName
[0]);
6313 STRCAT(filenamePtr
, ":");
6314 STRCAT(filenamePtr
, temporaryPtr
);
6316 #ifdef USE_UNIXFILENAME
6317 STRCPY(temporaryPtr
, filenamePtr
);
6318 filenamePtr
[0] = 0; /* NULL terminate the string */
6319 STRCAT(filenamePtr
, "Volumes:");
6320 STRCAT(filenamePtr
, temporaryPtr
);
6324 /* Append final path separator if it's a folder */
6328 /* As we use Unix File Name for MacOS X convert it */
6329 #ifdef USE_UNIXFILENAME
6330 /* Need to insert leading / */
6331 /* TODO: get the above code to use directly the / */
6332 STRCPY(&temporaryPtr
[1], filenamePtr
);
6333 temporaryPtr
[0] = '/';
6334 STRCPY(filenamePtr
, temporaryPtr
);
6337 for (p
= fname
; *p
; p
++)
6343 return (vim_strsave(fname
));
6347 #if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
6349 * Input Method Control functions.
6353 * Notify cursor position to IM.
6356 im_set_position(int row
, int col
)
6359 /* TODO: Implement me! */
6365 static ScriptLanguageRecord gTSLWindow
;
6366 static ScriptLanguageRecord gTSLInsert
;
6367 static ScriptLanguageRecord gTSLDefault
= { 0, 0 };
6369 static Component gTSCWindow
;
6370 static Component gTSCInsert
;
6371 static Component gTSCDefault
;
6373 static int im_initialized
= 0;
6376 im_on_window_switch(int active
)
6378 ScriptLanguageRecord
*slptr
= NULL
;
6384 if (im_initialized
== 0)
6388 /* save default TSM component (should be U.S.) to default */
6389 GetDefaultInputMethodOfClass(&gTSCDefault
, &gTSLDefault
,
6390 kKeyboardInputMethodClass
);
6395 im_is_active
= TRUE
;
6396 ActivateTSMDocument(gTSMDocument
);
6397 slptr
= &gTSLWindow
;
6401 err
= SetDefaultInputMethodOfClass(gTSCWindow
, slptr
,
6402 kKeyboardInputMethodClass
);
6404 err
= SetTextServiceLanguage(slptr
);
6407 KeyScript(slptr
->fScript
| smKeyForceKeyScriptMask
);
6412 err
= GetTextServiceLanguage(&gTSLWindow
);
6414 slptr
= &gTSLWindow
;
6417 GetDefaultInputMethodOfClass(&gTSCWindow
, slptr
,
6418 kKeyboardInputMethodClass
);
6420 im_is_active
= FALSE
;
6421 DeactivateTSMDocument(gTSMDocument
);
6426 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6429 im_set_active(int active
)
6431 ScriptLanguageRecord
*slptr
= NULL
;
6437 if (im_initialized
== 0)
6441 /* save default TSM component (should be U.S.) to default */
6442 GetDefaultInputMethodOfClass(&gTSCDefault
, &gTSLDefault
,
6443 kKeyboardInputMethodClass
);
6448 im_is_active
= TRUE
;
6449 ActivateTSMDocument(gTSMDocument
);
6450 slptr
= &gTSLInsert
;
6454 err
= SetDefaultInputMethodOfClass(gTSCInsert
, slptr
,
6455 kKeyboardInputMethodClass
);
6457 err
= SetTextServiceLanguage(slptr
);
6460 KeyScript(slptr
->fScript
| smKeyForceKeyScriptMask
);
6465 err
= GetTextServiceLanguage(&gTSLInsert
);
6467 slptr
= &gTSLInsert
;
6470 GetDefaultInputMethodOfClass(&gTSCInsert
, slptr
,
6471 kKeyboardInputMethodClass
);
6473 /* restore to default when switch to normal mode, so than we could
6474 * enter commands easier */
6475 SetDefaultInputMethodOfClass(gTSCDefault
, &gTSLDefault
,
6476 kKeyboardInputMethodClass
);
6477 SetTextServiceLanguage(&gTSLDefault
);
6479 im_is_active
= FALSE
;
6480 DeactivateTSMDocument(gTSMDocument
);
6485 * Get IM status. When IM is on, return not 0. Else return 0.
6493 return im_is_active
;
6496 #endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
6501 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6502 // drawer implementation
6503 static MenuRef contextMenu
= NULL
;
6506 kTabContextMenuId
= 42,
6509 // the caller has to CFRelease() the returned string
6511 getTabLabel(tabpage_T
*page
)
6513 get_tabline_label(page
, FALSE
);
6514 #ifdef MACOS_CONVERT
6515 return (CFStringRef
)mac_enc_to_cfstring(NameBuff
, STRLEN(NameBuff
));
6517 // TODO: check internal encoding?
6518 return CFStringCreateWithCString(kCFAllocatorDefault
, (char *)NameBuff
,
6519 kCFStringEncodingMacRoman
);
6524 #define DRAWER_SIZE 150
6525 #define DRAWER_INSET 16
6527 static ControlRef dataBrowser
= NULL
;
6529 // when the tabline is hidden, vim doesn't call update_tabline(). When
6530 // the tabline is shown again, show_tabline() is called before upate_tabline(),
6531 // and because of this, the tab labels and vims internal tabs are out of sync
6532 // for a very short time. to prevent inconsistent state, we store the labels
6533 // of the tabs, not pointers to the tabs (which are invalid for a short time).
6534 static CFStringRef
*tabLabels
= NULL
;
6535 static int tabLabelsSize
= 0;
6539 kTabsColumn
= 'Tabs'
6548 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
)
6553 // data browser item display callback
6555 dbItemDataCallback(ControlRef browser
,
6556 DataBrowserItemID itemID
,
6557 DataBrowserPropertyID property
/* column id */,
6558 DataBrowserItemDataRef itemData
,
6559 Boolean changeValue
)
6561 OSStatus status
= noErr
;
6563 // assert(property == kTabsColumn); // why is this violated??
6565 // changeValue is true if we have a modifieable list and data was changed.
6566 // In our case, it's always false.
6567 // (that is: if (changeValue) updateInternalData(); else return
6573 assert(itemID
- 1 >= 0 && itemID
- 1 < tabLabelsSize
);
6574 str
= tabLabels
[itemID
- 1];
6575 status
= SetDataBrowserItemDataText(itemData
, str
);
6578 status
= errDataBrowserPropertyNotSupported
;
6583 // data browser action callback
6585 dbItemNotificationCallback(ControlRef browser
,
6586 DataBrowserItemID item
,
6587 DataBrowserItemNotification message
)
6591 case kDataBrowserItemSelected
:
6592 send_tabline_event(item
);
6597 // callbacks needed for contextual menu:
6599 dbGetContextualMenuCallback(ControlRef browser
,
6602 CFStringRef
*helpItemString
,
6605 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6606 *helpType
= kCMHelpItemRemoveHelp
; // OS X only ;-)
6607 *helpItemString
= NULL
;
6609 *menu
= contextMenu
;
6613 dbSelectContextualMenuCallback(ControlRef browser
,
6615 UInt32 selectionType
,
6617 MenuItemIndex menuItem
)
6619 if (selectionType
== kCMMenuItemSelected
)
6621 MenuCommand command
;
6622 GetMenuItemCommandID(menu
, menuItem
, &command
);
6624 // get tab that was selected when the context menu appeared
6625 // (there is always one tab selected). TODO: check if the context menu
6626 // isn't opened on an item but on empty space (has to be possible some
6627 // way, the finder does it too ;-) )
6628 Handle items
= NewHandle(0);
6633 GetDataBrowserItems(browser
, kDataBrowserNoItem
, false,
6634 kDataBrowserItemIsSelected
, items
);
6635 numItems
= GetHandleSize(items
) / sizeof(DataBrowserItemID
);
6639 DataBrowserItemID
*itemsPtr
;
6642 itemsPtr
= (DataBrowserItemID
*)*items
;
6645 send_tabline_menu_event(idx
, command
);
6647 DisposeHandle(items
);
6652 // focus callback of the data browser to always leave focus in vim
6654 dbFocusCallback(EventHandlerCallRef handler
, EventRef event
, void *data
)
6656 assert(GetEventClass(event
) == kEventClassControl
6657 && GetEventKind(event
) == kEventControlSetFocusPart
);
6663 // drawer callback to resize data browser to drawer size
6665 drawerCallback(EventHandlerCallRef handler
, EventRef event
, void *data
)
6667 switch (GetEventKind(event
))
6669 case kEventWindowBoundsChanged
: // move or resize
6672 GetEventParameter(event
, kEventParamAttributes
, typeUInt32
,
6673 NULL
, sizeof(attribs
), NULL
, &attribs
);
6674 if (attribs
& kWindowBoundsChangeSizeChanged
) // resize
6677 GetWindowBounds(drawer
, kWindowContentRgn
, &r
);
6678 SetRect(&r
, 0, 0, r
.right
- r
.left
, r
.bottom
- r
.top
);
6679 SetControlBounds(dataBrowser
, &r
);
6680 SetDataBrowserTableViewNamedColumnWidth(dataBrowser
,
6681 kTabsColumn
, r
.right
);
6687 return eventNotHandledErr
;
6690 // Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6691 // This way the code works on 10.2 and 10.3 as well (it doesn't have the
6692 // blue highlights in the list view on these systems, though. Oh well.)
6695 #import <mach-o/dyld.h>
6697 enum { kMyDataBrowserAttributeListViewAlternatingRowColors
= (1 << 1) };
6700 myDataBrowserChangeAttributes(ControlRef inDataBrowser
,
6701 OptionBits inAttributesToSet
,
6702 OptionBits inAttributesToClear
)
6706 NSSymbol symbol
= NULL
;
6707 OSStatus (*dataBrowserChangeAttributes
)(ControlRef inDataBrowser
,
6708 OptionBits inAttributesToSet
, OptionBits inAttributesToClear
);
6710 Gestalt(gestaltSystemVersion
, &osVersion
);
6711 if (osVersion
< 0x1040) // only supported for 10.4 (and up)
6714 // C name mangling...
6715 symbolName
= "_DataBrowserChangeAttributes";
6716 if (!NSIsSymbolNameDefined(symbolName
)
6717 || (symbol
= NSLookupAndBindSymbol(symbolName
)) == NULL
)
6720 dataBrowserChangeAttributes
= NSAddressOfSymbol(symbol
);
6721 if (dataBrowserChangeAttributes
== NULL
)
6722 return noErr
; // well...
6723 return dataBrowserChangeAttributes(inDataBrowser
,
6724 inAttributesToSet
, inAttributesToClear
);
6728 initialise_tabline(void)
6730 Rect drawerRect
= { 0, 0, 0, DRAWER_SIZE
};
6731 DataBrowserCallbacks dbCallbacks
;
6732 EventTypeSpec focusEvent
= {kEventClassControl
, kEventControlSetFocusPart
};
6733 EventTypeSpec resizeEvent
= {kEventClassWindow
, kEventWindowBoundsChanged
};
6734 DataBrowserListViewColumnDesc colDesc
;
6736 // drawers have to have compositing enabled
6737 CreateNewWindow(kDrawerWindowClass
,
6738 kWindowStandardHandlerAttribute
6739 | kWindowCompositingAttribute
6740 | kWindowResizableAttribute
6741 | kWindowLiveResizeAttribute
,
6742 &drawerRect
, &drawer
);
6744 SetThemeWindowBackground(drawer
, kThemeBrushDrawerBackground
, true);
6745 SetDrawerParent(drawer
, gui
.VimWindow
);
6746 SetDrawerOffsets(drawer
, kWindowOffsetUnchanged
, DRAWER_INSET
);
6749 // create list view embedded in drawer
6750 CreateDataBrowserControl(drawer
, &drawerRect
, kDataBrowserListView
,
6753 dbCallbacks
.version
= kDataBrowserLatestCallbacks
;
6754 InitDataBrowserCallbacks(&dbCallbacks
);
6755 dbCallbacks
.u
.v1
.itemDataCallback
=
6756 NewDataBrowserItemDataUPP(dbItemDataCallback
);
6757 dbCallbacks
.u
.v1
.itemNotificationCallback
=
6758 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback
);
6759 dbCallbacks
.u
.v1
.getContextualMenuCallback
=
6760 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback
);
6761 dbCallbacks
.u
.v1
.selectContextualMenuCallback
=
6762 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback
);
6764 SetDataBrowserCallbacks(dataBrowser
, &dbCallbacks
);
6766 SetDataBrowserListViewHeaderBtnHeight(dataBrowser
, 0); // no header
6767 SetDataBrowserHasScrollBars(dataBrowser
, false, true); // only vertical
6768 SetDataBrowserSelectionFlags(dataBrowser
,
6769 kDataBrowserSelectOnlyOne
| kDataBrowserNeverEmptySelectionSet
);
6770 SetDataBrowserTableViewHiliteStyle(dataBrowser
,
6771 kDataBrowserTableViewFillHilite
);
6773 SetControlData(dataBrowser
, kControlEntireControl
,
6774 kControlDataBrowserIncludesFrameAndFocusTag
, sizeof(b
), &b
);
6776 // enable blue background in data browser (this is only in 10.4 and vim
6777 // has to support older osx versions as well, so we have to load this
6778 // function dynamically)
6779 myDataBrowserChangeAttributes(dataBrowser
,
6780 kMyDataBrowserAttributeListViewAlternatingRowColors
, 0);
6782 // install callback that keeps focus in vim and away from the data browser
6783 InstallControlEventHandler(dataBrowser
, dbFocusCallback
, 1, &focusEvent
,
6786 // install callback that keeps data browser at the size of the drawer
6787 InstallWindowEventHandler(drawer
, drawerCallback
, 1, &resizeEvent
,
6790 // add "tabs" column to data browser
6791 colDesc
.propertyDesc
.propertyID
= kTabsColumn
;
6792 colDesc
.propertyDesc
.propertyType
= kDataBrowserTextType
;
6794 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6795 colDesc
.propertyDesc
.propertyFlags
= kDataBrowserDefaultPropertyFlags
;
6797 colDesc
.headerBtnDesc
.version
= kDataBrowserListViewLatestHeaderDesc
;
6798 colDesc
.headerBtnDesc
.minimumWidth
= 100;
6799 colDesc
.headerBtnDesc
.maximumWidth
= 150;
6800 colDesc
.headerBtnDesc
.titleOffset
= 0;
6801 colDesc
.headerBtnDesc
.titleString
= CFSTR("Tabs");
6802 colDesc
.headerBtnDesc
.initialOrder
= kDataBrowserOrderIncreasing
;
6803 colDesc
.headerBtnDesc
.btnFontStyle
.flags
= 0; // use default font
6804 colDesc
.headerBtnDesc
.btnContentInfo
.contentType
= kControlContentTextOnly
;
6806 AddDataBrowserListViewColumn(dataBrowser
, &colDesc
, 0);
6808 // create tabline popup menu required by vim docs (see :he tabline-menu)
6809 CreateNewMenu(kTabContextMenuId
, 0, &contextMenu
);
6810 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("Close"), 0,
6811 TABLINE_MENU_CLOSE
, NULL
);
6812 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("New Tab"), 0,
6813 TABLINE_MENU_NEW
, NULL
);
6814 AppendMenuItemTextWithCFString(contextMenu
, CFSTR("Open Tab..."), 0,
6815 TABLINE_MENU_OPEN
, NULL
);
6820 * Show or hide the tabline.
6823 gui_mch_show_tabline(int showit
)
6826 CloseDrawer(drawer
, true);
6828 OpenDrawer(drawer
, kWindowEdgeRight
, true);
6832 * Return TRUE when tabline is displayed.
6835 gui_mch_showing_tabline(void)
6837 WindowDrawerState state
= GetDrawerState(drawer
);
6839 return state
== kWindowDrawerOpen
|| state
== kWindowDrawerOpening
;
6843 * Update the labels of the tabline.
6846 gui_mch_update_tabline(void)
6849 int numTabs
= getTabCount();
6853 // adjust data browser
6854 if (tabLabels
!= NULL
)
6858 for (i
= 0; i
< tabLabelsSize
; ++i
)
6859 CFRelease(tabLabels
[i
]);
6862 tabLabels
= (CFStringRef
*)malloc(numTabs
* sizeof(CFStringRef
));
6863 tabLabelsSize
= numTabs
;
6865 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
6869 tabLabels
[nr
-1] = getTabLabel(tp
);
6872 RemoveDataBrowserItems(dataBrowser
, kDataBrowserNoItem
, 0, NULL
,
6873 kDataBrowserItemNoProperty
);
6874 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6875 // can pass NULL for the id array
6876 AddDataBrowserItems(dataBrowser
, kDataBrowserNoItem
, numTabs
, NULL
,
6877 kDataBrowserItemNoProperty
);
6879 DataBrowserItemID item
= curtabidx
;
6880 SetDataBrowserSelectedItems(dataBrowser
, 1, &item
, kDataBrowserItemsAssign
);
6884 * Set the current tab to "nr". First tab is 1.
6887 gui_mch_set_curtab(nr
)
6890 DataBrowserItemID item
= nr
;
6891 SetDataBrowserSelectedItems(dataBrowser
, 1, &item
, kDataBrowserItemsAssign
);
6893 // TODO: call something like this?: (or restore scroll position, or...)
6894 RevealDataBrowserItem(dataBrowser
, item
, kTabsColumn
,
6895 kDataBrowserRevealOnly
);
6898 #endif // FEAT_GUI_TABLINE