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