comparison src/gui_mac.c @ 7:3fc0f57ecb91 v7.0001

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