blob: 03dc326f68481736537cceb42135ebc45108b0f5 [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
Bram Moolenaar26a60b42005-02-22 08:49:11 +000094#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
95# define USE_CARBONKEYHANDLER
96static EventHandlerUPP keyEventHandlerUPP = NULL;
97/* Defined in os_mac_conv.c */
98extern char_u *mac_utf16_to_enc __ARGS((UniChar *from, size_t fromLen, size_t *actualLen));
99extern UniChar *mac_enc_to_utf16 __ARGS((char_u *from, size_t fromLen, size_t *actualLen));
100extern CFStringRef mac_enc_to_cfstring __ARGS((char_u *from, size_t fromLen));
101#endif
102
103#ifdef MACOS_X
104SInt32 gMacSystemVersion;
105#endif
106
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107/* Debugging feature: start Vim window OFFSETed */
108#undef USE_OFFSETED_WINDOW
109
110/* Debugging feature: use CodeWarior SIOUX */
111#undef USE_SIOUX
112
113
114/* Include some file. TODO: move into os_mac.h */
115#include <Menus.h>
116#include <Resources.h>
117#if !TARGET_API_MAC_CARBON
118#include <StandardFile.h>
119#include <Traps.h>
120#endif
121#include <Balloons.h>
122#include <Processes.h>
123#ifdef USE_AEVENT
124# include <AppleEvents.h>
125# include <AERegistry.h>
126#endif
127#ifdef USE_CTRLCLICKMENU
128# include <Gestalt.h>
129#endif
130#ifdef USE_SIOUX
131# include <stdio.h>
132# include <sioux.h>
133# include <console.h>
134#endif
135#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
136# include <ControlDefinitions.h>
137# include <Navigation.h> /* Navigation only part of ?? */
138#endif
139
140#if TARGET_API_MAC_CARBON && 0
141/* New Help Interface for Mac, not implemented yet.*/
142# include <MacHelp.h>
143#endif
144
145/*
146 * Translate new name to old ones
147 * New function only available in MacOS 8.5,
148 * So use old one to be compatible back to System 7
149 */
150#ifndef USE_CARBONIZED
151# undef EnableMenuItem
152# define EnableMenuItem EnableItem
153# undef DisableMenuItem
154# define DisableMenuItem DisableItem
155#endif
156
157/* Carbon does not support the Get/SetControll functions,
158 * use Get/SetControl32Bit instead and rename for non-carbon
159 * systems.
160 */
161
162#ifndef USE_CARBONIZED
163# undef SetControl32BitMaximum
164# define SetControl32BitMaximum SetControlMaximum
165# undef SetControl32BitMinimum
166# define SetControl32BitMinimum SetControlMinimum
167# undef SetControl32BitValue
168# define SetControl32BitValue SetControlValue
169# undef GetControl32BitValue
170# define GetControl32BitValue GetControlValue
171#endif
172
173/*
174 * ???
175 */
176
177#define kNothing 0
178#define kCreateEmpty 2 /*1*/
179#define kCreateRect 2
180#define kDestroy 3
181
182/*
183 * Dany: Don't like those...
184 */
185
186#define topLeft(r) (((Point*)&(r))[0])
187#define botRight(r) (((Point*)&(r))[1])
188
189
190/* Time of last mouse click, to detect double-click */
191static long lastMouseTick = 0;
192
193/* ??? */
194static RgnHandle cursorRgn;
195static RgnHandle dragRgn;
196static Rect dragRect;
197static short dragRectEnbl;
198static short dragRectControl;
199
200/* This variable is set when waiting for an event, which is the only moment
201 * scrollbar dragging can be done directly. It's not allowed while commands
202 * are executed, because it may move the cursor and that may cause unexpected
203 * problems (e.g., while ":s" is working).
204 */
205static int allow_scrollbar = FALSE;
206
207/* Last mouse click caused contextual menu, (to provide proper release) */
208#ifdef USE_CTRLCLICKMENU
209static short clickIsPopup;
210#endif
211
212/* Feedback Action for Scrollbar */
213ControlActionUPP gScrollAction;
214ControlActionUPP gScrollDrag;
215
216/* Keeping track of which scrollbar is being dragged */
217static ControlHandle dragged_sb = NULL;
218
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000219#if defined(USE_CARBONIZED) && defined(MACOS_X)
220static struct
221{
222 FMFontFamily family;
223 FMFontSize size;
224 FMFontStyle style;
225 Boolean isPanelVisible;
226} gFontPanelInfo = { 0, 0, 0, false };
227#endif
228
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000229#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
230# define USE_ATSUI_DRAWING
231ATSUStyle gFontStyle;
232Boolean gIsFontFallbackSet;
233#endif
234
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235/*
236 * The Quickdraw global is predefined in CodeWarior
237 * but is not in Apple MPW
238 */
239#if (defined(__MRC__) || defined(__SC__))
240# if !(defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON)
241QDGlobals qd;
242# endif
243#endif
244
245/* Colors Macros */
246#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
247#define Red(c) ((c & 0x00FF0000) >> 16)
248#define Green(c) ((c & 0x0000FF00) >> 8)
249#define Blue(c) ((c & 0x000000FF) >> 0)
250
251/* Key mapping */
252
253#define vk_Esc 0x35 /* -> 1B */
254
255#define vk_F1 0x7A /* -> 10 */
256#define vk_F2 0x78 /*0x63*/
257#define vk_F3 0x63 /*0x76*/
258#define vk_F4 0x76 /*0x60*/
259#define vk_F5 0x60 /*0x61*/
260#define vk_F6 0x61 /*0x62*/
261#define vk_F7 0x62 /*0x63*/ /*?*/
262#define vk_F8 0x64
263#define vk_F9 0x65
264#define vk_F10 0x6D
265#define vk_F11 0x67
266#define vk_F12 0x6F
267#define vk_F13 0x69
268#define vk_F14 0x6B
269#define vk_F15 0x71
270
271#define vk_Clr 0x47 /* -> 1B (ESC) */
272#define vk_Enter 0x4C /* -> 03 */
273
274#define vk_Space 0x31 /* -> 20 */
275#define vk_Tab 0x30 /* -> 09 */
276#define vk_Return 0x24 /* -> 0D */
277/* This is wrong for OSX, what is it for? */
278#define vk_Delete 0X08 /* -> 08 BackSpace */
279
280#define vk_Help 0x72 /* -> 05 */
281#define vk_Home 0x73 /* -> 01 */
282#define vk_PageUp 0x74 /* -> 0D */
283#define vk_FwdDelete 0x75 /* -> 7F */
284#define vk_End 0x77 /* -> 04 */
285#define vk_PageDown 0x79 /* -> 0C */
286
287#define vk_Up 0x7E /* -> 1E */
288#define vk_Down 0x7D /* -> 1F */
289#define vk_Left 0x7B /* -> 1C */
290#define vk_Right 0x7C /* -> 1D */
291
292#define vk_Undo vk_F1
293#define vk_Cut vk_F2
294#define vk_Copy vk_F3
295#define vk_Paste vk_F4
296#define vk_PrintScreen vk_F13
297#define vk_SCrollLock vk_F14
298#define vk_Pause vk_F15
299#define vk_NumLock vk_Clr
300#define vk_Insert vk_Help
301
302#define KeySym char
303
304static struct
305{
306 KeySym key_sym;
307 char_u vim_code0;
308 char_u vim_code1;
309} special_keys[] =
310{
311 {vk_Up, 'k', 'u'},
312 {vk_Down, 'k', 'd'},
313 {vk_Left, 'k', 'l'},
314 {vk_Right, 'k', 'r'},
315
316 {vk_F1, 'k', '1'},
317 {vk_F2, 'k', '2'},
318 {vk_F3, 'k', '3'},
319 {vk_F4, 'k', '4'},
320 {vk_F5, 'k', '5'},
321 {vk_F6, 'k', '6'},
322 {vk_F7, 'k', '7'},
323 {vk_F8, 'k', '8'},
324 {vk_F9, 'k', '9'},
325 {vk_F10, 'k', ';'},
326
327 {vk_F11, 'F', '1'},
328 {vk_F12, 'F', '2'},
329 {vk_F13, 'F', '3'},
330 {vk_F14, 'F', '4'},
331 {vk_F15, 'F', '5'},
332
333/* {XK_Help, '%', '1'}, */
334/* {XK_Undo, '&', '8'}, */
335/* {XK_BackSpace, 'k', 'b'}, */
336#ifndef MACOS_X
337 {vk_Delete, 'k', 'b'},
338#endif
339 {vk_Insert, 'k', 'I'},
340 {vk_FwdDelete, 'k', 'D'},
341 {vk_Home, 'k', 'h'},
342 {vk_End, '@', '7'},
343/* {XK_Prior, 'k', 'P'}, */
344/* {XK_Next, 'k', 'N'}, */
345/* {XK_Print, '%', '9'}, */
346
347 {vk_PageUp, 'k', 'P'},
348 {vk_PageDown, 'k', 'N'},
349
350 /* End of list marker: */
351 {(KeySym)0, 0, 0}
352};
353
354/*
355 * ------------------------------------------------------------
356 * Forward declaration (for those needed)
357 * ------------------------------------------------------------
358 */
359
360#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000361OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362#endif
363
364/*
365 * ------------------------------------------------------------
366 * Conversion Utility
367 * ------------------------------------------------------------
368 */
369
370/*
371 * C2Pascal_save
372 *
373 * Allocate memory and convert the C-String passed in
374 * into a pascal string
375 *
376 */
377
378char_u *C2Pascal_save(char_u *Cstring)
379{
380 char_u *PascalString;
381 int len;
382
383 if (Cstring == NULL)
384 return NULL;
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 mch_memmove(PascalString + 1, Cstring, len);
395 PascalString[0] = len;
396 }
397
398 return PascalString;
399}
400
401/*
402 * C2Pascal_save_and_remove_backslash
403 *
404 * Allocate memory and convert the C-String passed in
405 * into a pascal string. Also remove the backslash at the same time
406 *
407 */
408
409char_u *C2Pascal_save_and_remove_backslash(char_u *Cstring)
410{
411 char_u *PascalString;
412 int len;
413 char_u *p, *c;
414
415 len = STRLEN(Cstring);
416
417 if (len > 255) /* Truncate if necessary */
418 len = 255;
419
420 PascalString = alloc(len + 1);
421 if (PascalString != NULL)
422 {
423 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
424 {
425 if ((*c == '\\') && (c[1] != 0))
426 {
427 c++;
428 }
429 *p = *c;
430 p++;
431 len++;
432 }
433 PascalString[0] = len;
434 }
435
436 return PascalString;
437}
438
439/*
440 * Convert the modifiers of an Event into vim's modifiers (mouse)
441 */
442
443 int_u
444EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
445{
446 int_u vimModifiers = 0x00;
447
448 if (macModifiers & (shiftKey | rightShiftKey))
449 vimModifiers |= MOUSE_SHIFT;
450 if (macModifiers & (controlKey | rightControlKey))
451 vimModifiers |= MOUSE_CTRL;
452 if (macModifiers & (optionKey | rightOptionKey))
453 vimModifiers |= MOUSE_ALT;
454#if 0
455 /* Not yet supported */
456 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
457 vimModifiers |= MOUSE_CMD;
458#endif
459 return (vimModifiers);
460}
461
462/*
463 * Convert the modifiers of an Event into vim's modifiers (keys)
464 */
465
466 static int_u
467EventModifiers2VimModifiers(EventModifiers macModifiers)
468{
469 int_u vimModifiers = 0x00;
470
471 if (macModifiers & (shiftKey | rightShiftKey))
472 vimModifiers |= MOD_MASK_SHIFT;
473 if (macModifiers & (controlKey | rightControlKey))
474 vimModifiers |= MOD_MASK_CTRL;
475 if (macModifiers & (optionKey | rightOptionKey))
476 vimModifiers |= MOD_MASK_ALT;
477#ifdef USE_CMD_KEY
478 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
479 vimModifiers |= MOD_MASK_CMD;
480#endif
481 return (vimModifiers);
482}
483
484/* Convert a string representing a point size into pixels. The string should
485 * be a positive decimal number, with an optional decimal point (eg, "12", or
486 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
487 * character is stored in *end. The flag "vertical" says whether this
488 * calculation is for a vertical (height) size or a horizontal (width) one.
489 *
490 * From gui_w48.c
491 */
492 static int
493points_to_pixels(char_u *str, char_u **end, int vertical)
494{
495 int pixels;
496 int points = 0;
497 int divisor = 0;
498
499 while (*str)
500 {
501 if (*str == '.' && divisor == 0)
502 {
503 /* Start keeping a divisor, for later */
504 divisor = 1;
505 continue;
506 }
507
508 if (!isdigit(*str))
509 break;
510
511 points *= 10;
512 points += *str - '0';
513 divisor *= 10;
514
515 ++str;
516 }
517
518 if (divisor == 0)
519 divisor = 1;
520
521 pixels = points/divisor;
522 *end = str;
523 return pixels;
524}
525
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000526#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
527/*
528 * Deletes all traces of any Windows-style mnemonic text (including any
529 * parentheses) from a menu item and returns the cleaned menu item title.
530 * The caller is responsible for releasing the returned string.
531 */
532 static CFStringRef
533menu_title_removing_mnemonic(menu)
534 vimmenu_T *menu;
535{
536 CFStringRef name;
537 size_t menuTitleLen;
538 CFIndex displayLen;
539 CFRange mnemonicStart;
540 CFRange mnemonicEnd;
541 CFMutableStringRef cleanedName;
542
543 menuTitleLen = STRLEN(menu->dname);
544 name = mac_enc_to_cfstring(menu->dname, menuTitleLen);
545
546 if (name)
547 {
548 /* Simple mnemonic-removal algorithm, assumes single parenthesized
549 * mnemonic character towards the end of the menu text */
550 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
551 displayLen = CFStringGetLength(name);
552
553 if (mnemonicStart.location != kCFNotFound
554 && (mnemonicStart.location + 2) < displayLen
555 && CFStringGetCharacterAtIndex(name,
556 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
557 {
558 if (CFStringFindWithOptions(name, CFSTR(")"),
559 CFRangeMake(mnemonicStart.location + 1,
560 displayLen - mnemonicStart.location - 1),
561 kCFCompareBackwards, &mnemonicEnd) &&
562 (mnemonicStart.location + 2) == mnemonicEnd.location)
563 {
564 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
565 if (cleanedName)
566 {
567 CFStringDelete(cleanedName,
568 CFRangeMake(mnemonicStart.location,
569 mnemonicEnd.location + 1 -
570 mnemonicStart.location));
571
572 CFRelease(name);
573 name = cleanedName;
574 }
575 }
576 }
577 }
578
579 return name;
580}
581#endif
582
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583/*
584 * Convert a list of FSSpec aliases into a list of fullpathname
585 * character strings.
586 */
587
588char_u **new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
589{
590 char_u **fnames = NULL;
591 OSErr newError;
592 long fileCount;
593 FSSpec fileToOpen;
594 long actualSize;
595 AEKeyword dummyKeyword;
596 DescType dummyType;
597
598 /* Get number of files in list */
599 *error = AECountItems(theList, numFiles);
600 if (*error)
601 {
602#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000603 printf("fname_from_AEDesc: AECountItems error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604#endif
605 return(fnames);
606 }
607
608 /* Allocate the pointer list */
609 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
610
611 /* Empty out the list */
612 for (fileCount = 0; fileCount < *numFiles; fileCount++)
613 fnames[fileCount] = NULL;
614
615 /* Scan the list of FSSpec */
616 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
617 {
618 /* Get the alias for the nth file, convert to an FSSpec */
619 newError = AEGetNthPtr(theList, fileCount, typeFSS,
620 &dummyKeyword, &dummyType,
621 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
622 if (newError)
623 {
624 /* Caller is able to clean up */
625 /* TODO: Should be clean up or not? For safety. */
626#ifdef USE_SIOUX
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000627 printf("aevt_odoc: AEGetNthPtr error: %ld\n", (long)newError);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628#endif
629 return(fnames);
630 }
631
632 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000633 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 }
635
636 return (fnames);
637}
638
639/*
640 * ------------------------------------------------------------
641 * CodeWarrior External Editor Support
642 * ------------------------------------------------------------
643 */
644#ifdef FEAT_CW_EDITOR
645
646/*
647 * Handle the Window Search event from CodeWarrior
648 *
649 * Description
650 * -----------
651 *
652 * The IDE sends the Window Search AppleEvent to the editor when it
653 * needs to know whether a particular file is open in the editor.
654 *
655 * Event Reply
656 * -----------
657 *
658 * None. Put data in the location specified in the structure received.
659 *
660 * Remarks
661 * -------
662 *
663 * When the editor receives this event, determine whether the specified
664 * file is open. If it is, return the modification date/time for that file
665 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000666 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667 *
668 */
669
670#if defined(__MWERKS__) /* only in Codewarrior */
671# pragma options align=mac68k
672#endif
673typedef struct WindowSearch WindowSearch;
674struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
675{
676 FSSpec theFile; // identifies the file
677 long *theDate; // where to put the modification date/time
678};
679#if defined(__MWERKS__) /* only in Codewarrior */
680# pragma options align=reset
681#endif
682
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000683 pascal OSErr
684Handle_KAHL_SRCH_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685{
686 OSErr error = noErr;
687 buf_T *buf;
688 int foundFile = false;
689 DescType typeCode;
690 WindowSearch SearchData;
691 Size actualSize;
692
693 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
694 if (error)
695 {
696#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000697 printf("KAHL_SRCH: AEGetParamPtr error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698#endif
699 return(error);
700 }
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_SRCH: HandleUnusedParms error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707#endif
708 return(error);
709 }
710
711 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
712 if (buf->b_ml.ml_mfp != NULL
713 && SearchData.theFile.parID == buf->b_FSSpec.parID
714 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
715 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
716 {
717 foundFile = true;
718 break;
719 }
720
721 if (foundFile == false)
722 *SearchData.theDate = fnfErr;
723 else
724 *SearchData.theDate = buf->b_mtime;
725
726#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000727 printf("KAHL_SRCH: file \"%#s\" {%d}", SearchData.theFile.name,SearchData.theFile.parID);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728 if (foundFile == false)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000729 printf(" NOT");
730 printf(" found. [date %lx, %lx]\n", *SearchData.theDate, buf->b_mtime_read);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731#endif
732
733 return error;
734};
735
736/*
737 * Handle the Modified (from IDE to Editor) event from CodeWarrior
738 *
739 * Description
740 * -----------
741 *
742 * The IDE sends this event to the external editor when it wants to
743 * know which files that are open in the editor have been modified.
744 *
745 * Parameters None.
746 * ----------
747 *
748 * Event Reply
749 * -----------
750 * The reply for this event is:
751 *
752 * keyDirectObject typeAEList required
753 * each element in the list is a structure of typeChar
754 *
755 * Remarks
756 * -------
757 *
758 * When building the reply event, include one element in the list for
759 * each open file that has been modified.
760 *
761 */
762
763#if defined(__MWERKS__) /* only in Codewarrior */
764# pragma options align=mac68k
765#endif
766typedef struct ModificationInfo ModificationInfo;
767struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
768{
769 FSSpec theFile; // identifies the file
770 long theDate; // the date/time the file was last modified
771 short saved; // set this to zero when replying, unused
772};
773#if defined(__MWERKS__) /* only in Codewarrior */
774# pragma options align=reset
775#endif
776
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000777 pascal OSErr
778Handle_KAHL_MOD_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779{
780 OSErr error = noErr;
781 AEDescList replyList;
782 long numFiles;
783 ModificationInfo theFile;
784 buf_T *buf;
785
786 theFile.saved = 0;
787
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000788 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 if (error)
790 {
791#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000792 printf("KAHL_MOD: HandleUnusedParms error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793#endif
794 return(error);
795 }
796
797 /* Send the reply */
798/* replyObject.descriptorType = typeNull;
799 replyObject.dataHandle = nil;*/
800
801/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
802 error = AECreateList(nil, 0, false, &replyList);
803 if (error)
804 {
805#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000806 printf("KAHL_MOD: AECreateList error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807#endif
808 return(error);
809 }
810
811#if 0
812 error = AECountItems(&replyList, &numFiles);
813#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000814 printf("KAHL_MOD ReplyList: %x %x\n", replyList.descriptorType, replyList.dataHandle);
815 printf("KAHL_MOD ItemInList: %d\n", numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816#endif
817
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
819 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 * sizeof(DescType))
821 */
822
823 /* AEPutDesc */
824#endif
825
826 numFiles = 0;
827 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
828 if (buf->b_ml.ml_mfp != NULL)
829 {
830 /* Add this file to the list */
831 theFile.theFile = buf->b_FSSpec;
832 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000833/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
834 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835#ifdef USE_SIOUX
836 if (numFiles == 0)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000837 printf("KAHL_MOD: ");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000839 printf(", ");
840 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 +0000841 if (error)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000842 printf(" (%d)", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 numFiles++;
844#endif
845 };
846
847#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000848 printf("\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849#endif
850
851#if 0
852 error = AECountItems(&replyList, &numFiles);
853#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000854 printf("KAHL_MOD ItemInList: %d\n", numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855#endif
856#endif
857
858 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000859 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860
861#ifdef USE_SIOUX
862 if (error)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000863 printf("KAHL_MOD: AEPutParamDesc error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864#endif
865
866 if (replyList.dataHandle)
867 AEDisposeDesc(&replyList);
868
869 return error;
870};
871
872/*
873 * Handle the Get Text event from CodeWarrior
874 *
875 * Description
876 * -----------
877 *
878 * The IDE sends the Get Text AppleEvent to the editor when it needs
879 * the source code from a file. For example, when the user issues a
880 * Check Syntax or Compile command, the compiler needs access to
881 * the source code contained in the file.
882 *
883 * Event Reply
884 * -----------
885 *
886 * None. Put data in locations specified in the structure received.
887 *
888 * Remarks
889 * -------
890 *
891 * When the editor receives this event, it must set the size of the handle
892 * in theText to fit the data in the file. It must then copy the entire
893 * contents of the specified file into the memory location specified in
894 * theText.
895 *
896 */
897
898#if defined(__MWERKS__) /* only in Codewarrior */
899# pragma options align=mac68k
900#endif
901typedef struct CW_GetText CW_GetText;
902struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
903{
904 FSSpec theFile; /* identifies the file */
905 Handle theText; /* the location where you return the text (must be resized properly) */
906 long *unused; /* 0 (not used) */
907 long *theDate; /* where to put the modification date/time */
908};
909#if defined(__MWERKS__) /* only in Codewarrior */
910# pragma options align=reset
911#endif
912
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 pascal OSErr
914Handle_KAHL_GTTX_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915{
916 OSErr error = noErr;
917 buf_T *buf;
918 int foundFile = false;
919 DescType typeCode;
920 CW_GetText GetTextData;
921 Size actualSize;
922 char_u *line;
923 char_u *fullbuffer = NULL;
924 long linesize;
925 long lineStart;
926 long BufferSize;
927 long lineno;
928
929 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
930
931 if (error)
932 {
933#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 printf("KAHL_GTTX: AEGetParamPtr error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935#endif
936 return(error);
937 }
938
939 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
940 if (buf->b_ml.ml_mfp != NULL)
941 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
942 {
943 foundFile = true;
944 break;
945 }
946
947 if (foundFile)
948 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000949 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000950 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
951 {
952 /* Must use the right buffer */
953 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
954 linesize = STRLEN(line) + 1;
955 lineStart = BufferSize;
956 BufferSize += linesize;
957 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000958 SetHandleSize(GetTextData.theText, BufferSize);
959 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 {
961 #ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000962 printf("KAHL_GTTX: SetHandleSize increase: %d, size %d\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963 linesize, BufferSize);
964 #endif
965 break; /* Simple handling for now */
966 }
967 else
968 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000969 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000971 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000973 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 }
975 }
976 if (fullbuffer != NULL)
977 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000978 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000980 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981 }
982 if (foundFile == false)
983 *GetTextData.theDate = fnfErr;
984 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000985/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000986 *GetTextData.theDate = buf->b_mtime;
987 }
988#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000989 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 +0000990 if (foundFile == false)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000991 printf(" NOT");
992 printf(" found. (BufferSize = %d)\n", BufferSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993#endif
994
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000995 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 if (error)
997 {
998#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000999 printf("KAHL_GTTX: HandleUnusedParms error: %d\n", error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000#endif
1001 return(error);
1002 }
1003
1004 return(error);
1005}
1006
1007/*
1008 *
1009 */
1010
1011/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001012pascal OSErr FindProcessBySignature(const OSType targetType,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001013 const OSType targetCreator,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001014 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001015{
1016 OSErr anErr = noErr;
1017 Boolean lookingForProcess = true;
1018
1019 ProcessInfoRec infoRec;
1020
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001021 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022 infoRec.processName = nil;
1023 infoRec.processAppSpec = nil;
1024
1025 psnPtr->lowLongOfPSN = kNoProcess;
1026 psnPtr->highLongOfPSN = kNoProcess;
1027
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001028 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001030 anErr = GetNextProcess(psnPtr);
1031 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 else
1034 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001035 anErr = GetProcessInformation(psnPtr, &infoRec);
1036 if ((anErr == noErr)
1037 && (infoRec.processType == targetType)
1038 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 }
1041 }
1042
1043 return anErr;
1044}//end FindProcessBySignature
1045
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001046 void
1047Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001048{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001049 OSErr anErr = noErr;
1050 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
1052 AppleEvent theReply = { typeNull, nil };
1053 AESendMode sendMode;
1054 AppleEvent theEvent = {typeNull, nil };
1055 AEIdleUPP idleProcUPP = nil;
1056 ModificationInfo ModData;
1057
1058
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001059 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001061 printf("CodeWarrior is");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 if (anErr != noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001063 printf(" NOT");
1064 printf(" running\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001066 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001068 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
1069 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001071 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 {
1073 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
1074 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
1075 }
1076
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001077 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078
1079 /* Add the parms */
1080 ModData.theFile = buf->b_FSSpec;
1081 ModData.theDate = buf->b_mtime;
1082
1083 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001084 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001086 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 sendMode = kAENoReply;
1088 else
1089 sendMode = kAEWaitReply;
1090
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001091 if (anErr == noErr)
1092 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
1093 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 {
1095#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001096 printf("KAHL_MOD: Send error: %d\n", anErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001098/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001100 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 }
1102}
1103#endif /* FEAT_CW_EDITOR */
1104
1105/*
1106 * ------------------------------------------------------------
1107 * Apple Event Handling procedure
1108 * ------------------------------------------------------------
1109 */
1110#ifdef USE_AEVENT
1111
1112/*
1113 * Handle the Unused parms of an AppleEvent
1114 */
1115
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001116 OSErr
1117HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118{
1119 OSErr error;
1120 long actualSize;
1121 DescType dummyType;
1122 AEKeyword missedKeyword;
1123
1124 /* Get the "missed keyword" attribute from the AppleEvent. */
1125 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
1126 typeKeyword, &dummyType,
1127 (Ptr)&missedKeyword, sizeof(missedKeyword),
1128 &actualSize);
1129
1130 /* If the descriptor isn't found, then we got the required parameters. */
1131 if (error == errAEDescNotFound)
1132 {
1133 error = noErr;
1134 }
1135 else
1136 {
1137#if 0
1138 /* Why is this removed? */
1139 error = errAEEventNotHandled;
1140#endif
1141 }
1142
1143 return error;
1144}
1145
1146
1147/*
1148 * Handle the ODoc AppleEvent
1149 *
1150 * Deals with all files dragged to the application icon.
1151 *
1152 */
1153
1154#if defined(__MWERKS__) /* only in Codewarrior */
1155# pragma options align=mac68k
1156#endif
1157typedef struct SelectionRange SelectionRange;
1158struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1159{
1160 short unused1; // 0 (not used)
1161 short lineNum; // line to select (<0 to specify range)
1162 long startRange; // start of selection range (if line < 0)
1163 long endRange; // end of selection range (if line < 0)
1164 long unused2; // 0 (not used)
1165 long theDate; // modification date/time
1166};
1167#if defined(__MWERKS__) /* only in Codewarrior */
1168# pragma options align=reset
1169#endif
1170
1171/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1172 itor the selection range. If lineNum is zero or greater, scroll the text
1173 to the specified line. If lineNum is less than zero, use the values in
1174 startRange and endRange to select the specified characters. Scroll
1175 the text to display the selection. If lineNum, startRange, and
1176 endRange are all negative, there is no selection range specified.
1177 */
1178
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001179 pascal OSErr
1180HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181{
1182 /*
1183 * TODO: Clean up the code with convert the AppleEvent into
1184 * a ":args"
1185 */
1186 OSErr error = noErr;
1187// OSErr firstError = noErr;
1188// short numErrors = 0;
1189 AEDesc theList;
1190 DescType typeCode;
1191 long numFiles;
1192 // long fileCount;
1193 char_u **fnames;
1194// char_u fname[256];
1195 Size actualSize;
1196 SelectionRange thePosition;
1197 short gotPosition = false;
1198 long lnum;
1199
1200#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001201 printf("aevt_odoc:\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202#endif
1203
1204 /* the direct object parameter is the list of aliases to files (one or more) */
1205 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1206 if (error)
1207 {
1208#ifdef USE_SIOUX
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001209 printf("aevt_odoc: AEGetParamDesc error: %ld\n", (long)error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210#endif
1211 return(error);
1212 }
1213
1214
1215 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1216 if (error == noErr)
1217 gotPosition = true;
1218 if (error == errAEDescNotFound)
1219 error = noErr;
1220 if (error)
1221 {
1222#ifdef USE_SIOUX
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001223 printf("aevt_odoc: AEGetParamPtr error: %ld\n", (long)error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224#endif
1225 return(error);
1226 }
1227
1228#ifdef USE_SIOUX
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001229 printf("aevt_odoc: lineNum: %d, startRange %ld, endRange %ld, [date %lx]\n",
1230 (int)thePosition.lineNum,
1231 (long)thePosition.startRange, (long)thePosition.endRange,
1232 (long)thePosition.theDate);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233#endif
1234/*
1235 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1236
1237 if (^error) then
1238 {
1239 if (thePosition.lineNum >= 0)
1240 {
1241 // Goto this line
1242 }
1243 else
1244 {
1245 // Set the range char wise
1246 }
1247 }
1248 */
1249
1250
1251#ifdef FEAT_VISUAL
1252 reset_VIsual();
1253#endif
1254
1255 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1256
1257 if (error)
1258 {
1259 /* TODO: empty fnames[] first */
1260 vim_free(fnames);
1261 return (error);
1262 }
1263
1264 if (starting > 0)
1265 {
1266 int i;
1267 char_u *p;
1268
1269 /* these are the initial files dropped on the Vim icon */
1270 for (i = 0 ; i < numFiles; i++)
1271 {
1272 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1273 || (p = vim_strsave(fnames[i])) == NULL)
1274 mch_exit(2);
1275 else
1276 alist_add(&global_alist, p, 2);
1277 }
1278 goto finished;
1279 }
1280
1281 /* Handle the drop, :edit to get to the file */
1282 handle_drop(numFiles, fnames, FALSE);
1283
1284 /* TODO: Handle the goto/select line more cleanly */
1285 if ((numFiles == 1) & (gotPosition))
1286 {
1287 if (thePosition.lineNum >= 0)
1288 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001289 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290 /* oap->motion_type = MLINE;
1291 setpcmark();*/
1292 if (lnum < 1L)
1293 lnum = 1L;
1294 else if (lnum > curbuf->b_ml.ml_line_count)
1295 lnum = curbuf->b_ml.ml_line_count;
1296 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001297 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298 /* beginline(BL_SOL | BL_FIX);*/
1299 }
1300 else
1301 goto_byte(thePosition.startRange + 1);
1302 }
1303
1304 /* Update the screen display */
1305 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001306#ifdef FEAT_VISUAL
1307 /* Select the text if possible */
1308 if (gotPosition)
1309 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001310 VIsual_active = TRUE;
1311 VIsual_select = FALSE;
1312 VIsual = curwin->w_cursor;
1313 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001314 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001315 VIsual_mode = 'v';
1316 goto_byte(thePosition.endRange);
1317 }
1318 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001319 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001320 VIsual_mode = 'V';
1321 VIsual.col = 0;
1322 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001323 }
1324#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325 setcursor();
1326 out_flush();
1327
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001328 /* Fake mouse event to wake from stall */
1329 PostEvent(mouseUp, 0);
1330
Bram Moolenaar071d4272004-06-13 20:20:40 +00001331 finished:
1332 AEDisposeDesc(&theList); /* dispose what we allocated */
1333
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001334 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001335 if (error)
1336 {
1337#ifdef USE_SIOUX
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001338 printf("aevt_odoc: HandleUnusedParms error: %ld\n", (long)error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339#endif
1340 return(error);
1341 }
1342 return(error);
1343}
1344
1345/*
1346 *
1347 */
1348
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001349 pascal OSErr
1350Handle_aevt_oapp_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351{
1352 OSErr error = noErr;
1353
1354#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001355 printf("aevt_oapp:\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356#endif
1357
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001358 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 if (error)
1360 {
1361 return(error);
1362 }
1363
1364 return(error);
1365}
1366
1367/*
1368 *
1369 */
1370
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001371 pascal OSErr
1372Handle_aevt_quit_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373{
1374 OSErr error = noErr;
1375
1376#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001377 printf("aevt_quit\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378#endif
1379
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001380 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 if (error)
1382 {
1383 return(error);
1384 }
1385
1386 /* Need to fake a :confirm qa */
1387 do_cmdline_cmd((char_u *)"confirm qa");
1388
1389 return(error);
1390}
1391
1392/*
1393 *
1394 */
1395
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001396 pascal OSErr
1397Handle_aevt_pdoc_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398{
1399 OSErr error = noErr;
1400
1401#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001402 printf("aevt_pdoc:\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403#endif
1404
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001405 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001406 if (error)
1407 {
1408 return(error);
1409 }
1410
1411 return(error);
1412}
1413
1414/*
1415 * Handling of unknown AppleEvent
1416 *
1417 * (Just get rid of all the parms)
1418 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001419 pascal OSErr
1420Handle_unknown_AE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421{
1422 OSErr error = noErr;
1423
1424#ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001425 printf("Unknown Event: %x\n", theAEvent->descriptorType);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426#endif
1427
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001428 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429 if (error)
1430 {
1431 return(error);
1432 }
1433
1434 return(error);
1435}
1436
1437
1438
1439#if TARGET_API_MAC_CARBON
1440# define NewAEEventHandlerProc(x) NewAEEventHandlerUPP(x)
1441#endif
1442
1443/*
1444 * Install the various AppleEvent Handlers
1445 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001446 OSErr
1447InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448{
1449 OSErr error;
1450
1451 /* install open application handler */
1452 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
1453 NewAEEventHandlerProc(Handle_aevt_oapp_AE), 0, false);
1454 if (error)
1455 {
1456 return error;
1457 }
1458
1459 /* install quit application handler */
1460 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
1461 NewAEEventHandlerProc(Handle_aevt_quit_AE), 0, false);
1462 if (error)
1463 {
1464 return error;
1465 }
1466
1467 /* install open document handler */
1468 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
1469 NewAEEventHandlerProc(HandleODocAE), 0, false);
1470 if (error)
1471 {
1472 return error;
1473 }
1474
1475 /* install print document handler */
1476 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
1477 NewAEEventHandlerProc(Handle_aevt_pdoc_AE), 0, false);
1478
1479/* Install Core Suite */
1480/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
1481 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1482
1483 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
1484 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1485
1486 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
1487 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1488
1489 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
1490 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1491
1492 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
1493 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1494
1495 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
1496 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1497
1498 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
1499 NewAEEventHandlerProc(Handle_unknown_AE), kAEGetData, false);
1500
1501 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
1502 NewAEEventHandlerProc(Handle_unknown_AE), kAEGetDataSize, false);
1503
1504 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
1505 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1506
1507 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
1508 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1509
1510 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
1511 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1512
1513 error = AEInstallEventHandler(kAECoreSuite, kAESave,
1514 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1515
1516 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
1517 NewAEEventHandlerProc(Handle_unknown_AE), nil, false);
1518*/
1519
1520#ifdef FEAT_CW_EDITOR
1521 /*
1522 * Bind codewarrior support handlers
1523 */
1524 error = AEInstallEventHandler('KAHL', 'GTTX',
1525 NewAEEventHandlerProc(Handle_KAHL_GTTX_AE), 0, false);
1526 if (error)
1527 {
1528 return error;
1529 }
1530 error = AEInstallEventHandler('KAHL', 'SRCH',
1531 NewAEEventHandlerProc(Handle_KAHL_SRCH_AE), 0, false);
1532 if (error)
1533 {
1534 return error;
1535 }
1536 error = AEInstallEventHandler('KAHL', 'MOD ',
1537 NewAEEventHandlerProc(Handle_KAHL_MOD_AE), 0, false);
1538 if (error)
1539 {
1540 return error;
1541 }
1542#endif
1543
1544 return error;
1545
1546}
1547#endif /* USE_AEVENT */
1548
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001549
1550#if defined(USE_CARBONIZED) && defined(MACOS_X)
1551/*
1552 * Callback function, installed by InstallFontPanelHandler(), below,
1553 * to handle Font Panel events.
1554 */
1555 static OSStatus
1556FontPanelHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent,
1557 void *inUserData)
1558{
1559 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1560 {
1561 gFontPanelInfo.isPanelVisible = false;
1562 return noErr;
1563 }
1564
1565 if (GetEventKind(inEvent) == kEventFontSelection)
1566 {
1567 OSStatus status;
1568 FMFontFamily newFamily;
1569 FMFontSize newSize;
1570 FMFontStyle newStyle;
1571
1572 /* Retrieve the font family ID number. */
1573 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1574 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1575 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1576 &newFamily);
1577 if (status == noErr)
1578 gFontPanelInfo.family = newFamily;
1579
1580 /* Retrieve the font size. */
1581 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1582 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1583 if (status == noErr)
1584 gFontPanelInfo.size = newSize;
1585
1586 /* Retrieve the font style (bold, etc.). Currently unused. */
1587 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1588 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1589 if (status == noErr)
1590 gFontPanelInfo.style = newStyle;
1591 }
1592 return noErr;
1593}
1594
1595
1596 static void
1597InstallFontPanelHandler()
1598{
1599 EventTypeSpec eventTypes[2];
1600 EventHandlerUPP handlerUPP;
1601 /* EventHandlerRef handlerRef; */
1602
1603 eventTypes[0].eventClass = kEventClassFont;
1604 eventTypes[0].eventKind = kEventFontSelection;
1605 eventTypes[1].eventClass = kEventClassFont;
1606 eventTypes[1].eventKind = kEventFontPanelClosed;
1607
1608 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1609
1610 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1611 /*userData=*/NULL, /*handlerRef=*/NULL);
1612}
1613
1614
1615/*
1616 * Fill the buffer pointed to by outName with the name and size
1617 * of the font currently selected in the Font Panel.
1618 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001619#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001620 static void
1621GetFontPanelSelection(char_u* outName)
1622{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001623 Str255 buf;
1624 ByteCount fontNameLen = 0;
1625 ATSUFontID fid;
1626 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001627
1628 if (!outName)
1629 return;
1630
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001631 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1632 {
1633 /* Canonicalize localized font names */
1634 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1635 gFontPanelInfo.style, &fid, NULL) != noErr)
1636 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001637
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001638 /* Request font name with Mac encoding (otherwise we could
1639 * get an unwanted utf-16 name) */
1640 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1641 kFontNoScriptCode, kFontNoLanguageCode,
1642 255, outName, &fontNameLen, NULL) != noErr)
1643 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001644
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001645 /* Only encode font size, because style (bold, italic, etc) is
1646 * already part of the font full name */
1647 snprintf(styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
1648 gFontPanelInfo.size/*,
1649 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1650 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1651 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1652
1653 if ((fontNameLen + STRLEN(styleString)) < 255)
1654 STRCPY(outName + fontNameLen, styleString);
1655 }
1656 else
1657 {
1658 *outName = NULL;
1659 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001660}
1661#endif
1662
1663
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664/*
1665 * ------------------------------------------------------------
1666 * Unfiled yet
1667 * ------------------------------------------------------------
1668 */
1669
1670/*
1671 * gui_mac_get_menu_item_index
1672 *
1673 * Returns the index inside the menu wher
1674 */
1675 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001676gui_mac_get_menu_item_index(pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 vimmenu_T *pMenu;
1678{
1679 short index;
1680 short itemIndex = -1;
1681 vimmenu_T *pBrother;
1682
1683 /* Only menu without parent are the:
1684 * -menu in the menubar
1685 * -popup menu
1686 * -toolbar (guess)
1687 *
1688 * Which are not items anyway.
1689 */
1690 if (pMenu->parent)
1691 {
1692 /* Start from the Oldest Brother */
1693 pBrother = pMenu->parent->children;
1694 index = 1;
1695 while ((pBrother) && (itemIndex == -1))
1696 {
1697 if (pBrother == pMenu)
1698 itemIndex = index;
1699 index++;
1700 pBrother = pBrother->next;
1701 }
1702#ifdef USE_HELPMENU
1703 /* Adjust index in help menu (for predefined ones) */
1704 if (itemIndex != -1)
1705 if (pMenu->parent->submenu_id == kHMHelpMenuID)
1706 itemIndex += gui.MacOSHelpItems;
1707#endif
1708 }
1709 return itemIndex;
1710}
1711
1712 static vimmenu_T *
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001713gui_mac_get_vim_menu(menuID, itemIndex, pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 short menuID;
1715 short itemIndex;
1716 vimmenu_T *pMenu;
1717{
1718 short index;
1719 vimmenu_T *pChildMenu;
1720 vimmenu_T *pElder = pMenu->parent;
1721
1722
1723 /* Only menu without parent are the:
1724 * -menu in the menubar
1725 * -popup menu
1726 * -toolbar (guess)
1727 *
1728 * Which are not items anyway.
1729 */
1730
1731 if ((pElder) && (pElder->submenu_id == menuID))
1732 {
1733#ifdef USE_HELPMENU
1734 if (menuID == kHMHelpMenuID)
1735 itemIndex -= gui.MacOSHelpItems;
1736#endif
1737
1738 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1739 pMenu = pMenu->next;
1740 }
1741 else
1742 {
1743 for (; pMenu != NULL; pMenu = pMenu->next)
1744 {
1745 if (pMenu->children != NULL)
1746 {
1747 pChildMenu = gui_mac_get_vim_menu
1748 (menuID, itemIndex, pMenu->children);
1749 if (pChildMenu)
1750 {
1751 pMenu = pChildMenu;
1752 break;
1753 }
1754 }
1755 }
1756 }
1757 return pMenu;
1758}
1759
1760/*
1761 * ------------------------------------------------------------
1762 * MacOS Feedback procedures
1763 * ------------------------------------------------------------
1764 */
1765 pascal
1766 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001767gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768{
1769 scrollbar_T *sb;
1770 int value, dragging;
1771 ControlHandle theControlToUse;
1772 int dont_scroll_save = dont_scroll;
1773
1774 theControlToUse = dragged_sb;
1775
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001776 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777
1778 if (sb == NULL)
1779 return;
1780
1781 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001782 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 dragging = (partCode != 0);
1784
1785 /* When "allow_scrollbar" is FALSE still need to remember the new
1786 * position, but don't actually scroll by setting "dont_scroll". */
1787 dont_scroll = !allow_scrollbar;
1788 gui_drag_scrollbar(sb, value, dragging);
1789 dont_scroll = dont_scroll_save;
1790}
1791
1792 pascal
1793 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001794gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795{
1796 /* TODO: have live support */
1797 scrollbar_T *sb, *sb_info;
1798 long data;
1799 long value;
1800 int page;
1801 int dragging = FALSE;
1802 int dont_scroll_save = dont_scroll;
1803
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001804 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805
1806 if (sb == NULL)
1807 return;
1808
1809 if (sb->wp != NULL) /* Left or right scrollbar */
1810 {
1811 /*
1812 * Careful: need to get scrollbar info out of first (left) scrollbar
1813 * for window, but keep real scrollbar too because we must pass it to
1814 * gui_drag_scrollbar().
1815 */
1816 sb_info = &sb->wp->w_scrollbars[0];
1817
1818 if (sb_info->size > 5)
1819 page = sb_info->size - 2; /* use two lines of context */
1820 else
1821 page = sb_info->size;
1822 }
1823 else /* Bottom scrollbar */
1824 {
1825 sb_info = sb;
1826 page = W_WIDTH(curwin) - 5;
1827 }
1828
1829 switch (partCode)
1830 {
1831 case kControlUpButtonPart: data = -1; break;
1832 case kControlDownButtonPart: data = 1; break;
1833 case kControlPageDownPart: data = page; break;
1834 case kControlPageUpPart: data = -page; break;
1835 default: data = 0; break;
1836 }
1837
1838 value = sb_info->value + data;
1839/* if (value > sb_info->max)
1840 value = sb_info->max;
1841 else if (value < 0)
1842 value = 0;*/
1843
1844 /* When "allow_scrollbar" is FALSE still need to remember the new
1845 * position, but don't actually scroll by setting "dont_scroll". */
1846 dont_scroll = !allow_scrollbar;
1847 gui_drag_scrollbar(sb, value, dragging);
1848 dont_scroll = dont_scroll_save;
1849
1850 out_flush();
1851 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1852
1853/* if (sb_info->wp != NULL)
1854 {
1855 win_T *wp;
1856 int sb_num;
1857
1858 sb_num = 0;
1859 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1860 sb_num++;
1861
1862 if (wp != NULL)
1863 {
1864 current_scrollbar = sb_num;
1865 scrollbar_value = value;
1866 gui_do_scroll();
1867 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1868 }
1869 }*/
1870}
1871
1872/*
1873 * ------------------------------------------------------------
1874 * MacOS Click Handling procedures
1875 * ------------------------------------------------------------
1876 */
1877
1878
1879/*
1880 * Handle a click inside the window, it may happens in the
1881 * scrollbar or the contents.
1882 *
1883 * TODO: Add support for potential TOOLBAR
1884 */
1885 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001886gui_mac_doInContentClick(theEvent, whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 EventRecord *theEvent;
1888 WindowPtr whichWindow;
1889{
1890 Point thePoint;
1891 int_u vimModifiers;
1892 short thePortion;
1893 ControlHandle theControl;
1894 int vimMouseButton;
1895 short dblClick;
1896
1897 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001898 GlobalToLocal(&thePoint);
1899 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902
1903 if (theControl != NUL)
1904 {
1905 /* We hit a scollbar */
1906
1907 if (thePortion != kControlIndicatorPart)
1908 {
1909 dragged_sb = theControl;
1910 TrackControl(theControl, thePoint, gScrollAction);
1911 dragged_sb = NULL;
1912 }
1913 else
1914 {
1915 dragged_sb = theControl;
1916#if 1
1917 TrackControl(theControl, thePoint, gScrollDrag);
1918#else
1919 TrackControl(theControl, thePoint, NULL);
1920#endif
1921 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1922 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001923 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 dragged_sb = NULL;
1925 }
1926 }
1927 else
1928 {
1929 /* We are inside the contents */
1930
1931 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1932 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1933
1934 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1935 vimMouseButton = MOUSE_LEFT;
1936
1937#ifdef USE_CTRLCLICKMENU
1938 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
1939 clickIsPopup = FALSE;
1940
1941 if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup()))
1942 if (IsShowContextualMenuClick(theEvent))
1943 {
1944 vimMouseButton = MOUSE_RIGHT;
1945 vimModifiers &= ~MOUSE_CTRL;
1946 clickIsPopup = TRUE;
1947 }
1948#endif
1949
1950 /* Is it a double click ? */
1951 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1952
1953 /* Send the mouse clicj to Vim */
1954 gui_send_mouse_event(vimMouseButton, thePoint.h,
1955 thePoint.v, dblClick, vimModifiers);
1956
1957 /* Create the rectangle around the cursor to detect
1958 * the mouse dragging
1959 */
1960#ifdef USE_CTRLCLICKMENU
1961#if 0
1962 /* TODO: Do we need to this even for the contextual menu?
1963 * It may be require for popup_setpos, but for popup?
1964 */
1965 if (vimMouseButton == MOUSE_LEFT)
1966#endif
1967#endif
1968 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001969 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 FILL_Y(Y_2_ROW(thePoint.v)),
1971 FILL_X(X_2_COL(thePoint.h)+1),
1972 FILL_Y(Y_2_ROW(thePoint.v)+1));
1973
1974 dragRectEnbl = TRUE;
1975 dragRectControl = kCreateRect;
1976 }
1977 }
1978}
1979
1980/*
1981 * Handle the click in the titlebar (to move the window)
1982 */
1983 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001984gui_mac_doInDragClick(where, whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 Point where;
1986 WindowPtr whichWindow;
1987{
1988 Rect movingLimits;
1989 Rect *movingLimitsPtr = &movingLimits;
1990
1991 /* TODO: may try to prevent move outside screen? */
1992#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001993 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994#else
1995 movingLimitsPtr = &(*GetGrayRgn())->rgnBBox;
1996#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001997 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001998}
1999
2000/*
2001 * Handle the click in the grow box
2002 */
2003 void
2004gui_mac_doInGrowClick(where, whichWindow)
2005 Point where;
2006 WindowPtr whichWindow;
2007{
2008
2009 long newSize;
2010 unsigned short newWidth;
2011 unsigned short newHeight;
2012 Rect resizeLimits;
2013 Rect *resizeLimitsPtr = &resizeLimits;
2014#ifdef USE_CARBONIZED
2015 Rect NewContentRect;
2016
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002017 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018#else
2019 resizeLimits = qd.screenBits.bounds;
2020#endif
2021
2022 /* Set the minimun size */
2023 /* TODO: Should this come from Vim? */
2024 resizeLimits.top = 100;
2025 resizeLimits.left = 100;
2026
2027#ifdef USE_CARBONIZED
2028 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
2029 newWidth = NewContentRect.right - NewContentRect.left;
2030 newHeight = NewContentRect.bottom - NewContentRect.top;
2031 gui_resize_shell(newWidth, newHeight);
2032 gui_mch_set_bg_color(gui.back_pixel);
2033 gui_set_shellsize(TRUE, FALSE);
2034#else
2035 newSize = GrowWindow(whichWindow, where, &resizeLimits);
2036 if (newSize != 0)
2037 {
2038 newWidth = newSize & 0x0000FFFF;
2039 newHeight = (newSize >> 16) & 0x0000FFFF;
2040
2041 gui_mch_set_bg_color(gui.back_pixel);
2042
2043 gui_resize_shell(newWidth, newHeight);
2044
2045 /*
2046 * We need to call gui_set_shellsize as the size
2047 * used by Vim may be smaller than the size selected
2048 * by the user. This cause some overhead
2049 * TODO: add a check inside gui_resize_shell?
2050 */
2051 gui_set_shellsize(TRUE, FALSE);
2052
2053 /*
2054 * Origin of the code below is unknown.
2055 * Functionality is unknown.
2056 * Time of commented out is unknown.
2057 */
2058/* SetPort(wp);
2059 InvalRect(&wp->portRect);
2060 if (isUserWindow(wp)) {
2061 DrawingWindowPeek aWindow = (DrawingWindowPeek)wp;
2062
2063 if (aWindow->toolRoutines.toolWindowResizedProc)
2064 CallToolWindowResizedProc(aWindow->toolRoutines.toolWindowResizedProc, wp);
2065 }*/
2066 };
2067#endif
2068
2069}
2070
2071/*
2072 * Handle the click in the zoom box
2073 */
2074#ifdef USE_CARBONIZED
2075 static void
2076gui_mac_doInZoomClick(theEvent, whichWindow)
2077 EventRecord *theEvent;
2078 WindowPtr whichWindow;
2079{
2080 Rect r;
2081 Point p;
2082 short thePart;
2083
2084 /* ideal width is current */
2085 p.h = Columns * gui.char_width + 2 * gui.border_offset;
2086 if (gui.which_scrollbars[SBAR_LEFT])
2087 p.h += gui.scrollbar_width;
2088 if (gui.which_scrollbars[SBAR_RIGHT])
2089 p.h += gui.scrollbar_width;
2090 /* ideal height is as heigh as we can get */
2091 p.v = 15 * 1024;
2092
2093 thePart = IsWindowInStandardState(whichWindow, &p, &r)
2094 ? inZoomIn : inZoomOut;
2095
2096 if (!TrackBox(whichWindow, theEvent->where, thePart))
2097 return;
2098
2099 /* use returned width */
2100 p.h = r.right - r.left;
2101 /* adjust returned height */
2102 p.v = r.bottom - r.top - 2 * gui.border_offset;
2103 if (gui.which_scrollbars[SBAR_BOTTOM])
2104 p.v -= gui.scrollbar_height;
2105 p.v -= p.v % gui.char_height;
2106 p.v += 2 * gui.border_width;
2107 if (gui.which_scrollbars[SBAR_BOTTOM]);
2108 p.v += gui.scrollbar_height;
2109
2110 ZoomWindowIdeal(whichWindow, thePart, &p);
2111
2112 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
2113 gui_resize_shell(r.right - r.left, r.bottom - r.top);
2114 gui_mch_set_bg_color(gui.back_pixel);
2115 gui_set_shellsize(TRUE, FALSE);
2116}
2117#endif /* defined(USE_CARBONIZED) */
2118
2119/*
2120 * ------------------------------------------------------------
2121 * MacOS Event Handling procedure
2122 * ------------------------------------------------------------
2123 */
2124
2125/*
2126 * Handle the Update Event
2127 */
2128
2129 void
2130gui_mac_doUpdateEvent(event)
2131 EventRecord *event;
2132{
2133 WindowPtr whichWindow;
2134 GrafPtr savePort;
2135 RgnHandle updateRgn;
2136#ifdef USE_CARBONIZED
2137 Rect updateRect;
2138#endif
2139 Rect *updateRectPtr;
2140 Rect rc;
2141 Rect growRect;
2142 RgnHandle saveRgn;
2143
2144
2145#ifdef USE_CARBONIZED
2146 updateRgn = NewRgn();
2147 if (updateRgn == NULL)
2148 return;
2149#endif
2150
2151 /* This could be done by the caller as we
2152 * don't require anything else out of the event
2153 */
2154 whichWindow = (WindowPtr) event->message;
2155
2156 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002157 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158
2159 /* Select the Window's Port */
2160#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002161 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002163 SetPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164#endif
2165
2166 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002167 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 /* Redraw the biggest rectangle covering the area
2169 * to be updated.
2170 */
2171#ifdef USE_CARBONIZED
2172 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
2173# if 0
2174 /* Would be more appropriate to use the follwing but doesn't
2175 * seem to work under MacOS X (Dany)
2176 */
2177 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
2178# endif
2179#else
2180 updateRgn = whichWindow->visRgn;
2181#endif
2182 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002183 HLock((Handle) updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002185 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002186# if 0
2187 /* Code from original Carbon Port (using GetWindowRegion.
2188 * I believe the UpdateRgn is already in local (Dany)
2189 */
2190 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
2191 GlobalToLocal(&botRight(updateRect));
2192# endif
2193#else
2194 updateRectPtr = &(*updateRgn)->rgnBBox;
2195#endif
2196 /* Update the content (i.e. the text) */
2197 gui_redraw(updateRectPtr->left, updateRectPtr->top,
2198 updateRectPtr->right - updateRectPtr->left,
2199 updateRectPtr->bottom - updateRectPtr->top);
2200 /* Clear the border areas if needed */
2201 gui_mch_set_bg_color(gui.back_pixel);
2202 if (updateRectPtr->left < FILL_X(0))
2203 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002204 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
2205 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 }
2207 if (updateRectPtr->top < FILL_Y(0))
2208 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002209 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
2210 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 }
2212 if (updateRectPtr->right > FILL_X(Columns))
2213 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002214 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002216 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 }
2218 if (updateRectPtr->bottom > FILL_Y(Rows))
2219 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002220 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002222 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002224 HUnlock((Handle) updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002226 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227#endif
2228
2229 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002230 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231
2232 /* Update the GrowBox */
2233 /* Taken from FAQ 33-27 */
2234 saveRgn = NewRgn();
2235#ifdef USE_CARBONIZED
2236 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
2237#else
2238 growRect = whichWindow->portRect;
2239 growRect.top = growRect.bottom - 15;
2240 growRect.left = growRect.right - 15;
2241#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002242 GetClip(saveRgn);
2243 ClipRect(&growRect);
2244 DrawGrowIcon(whichWindow);
2245 SetClip(saveRgn);
2246 DisposeRgn(saveRgn);
2247 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248
2249 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002250 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251}
2252
2253/*
2254 * Handle the activate/deactivate event
2255 * (apply to a window)
2256 */
2257 void
2258gui_mac_doActivateEvent(event)
2259 EventRecord *event;
2260{
2261 WindowPtr whichWindow;
2262
2263 whichWindow = (WindowPtr) event->message;
2264 if ((event->modifiers) & activeFlag)
2265 /* Activate */
2266 gui_focus_change(TRUE);
2267 else
2268 {
2269 /* Deactivate */
2270 gui_focus_change(FALSE);
2271/* DON'T KNOW what the code below was doing
2272 found in the deactivate clause, but the
2273 clause writting TRUE into in_focus (BUG)
2274 */
2275
2276#if 0 /* Removed by Dany as per above June 2001 */
2277 a_bool = false;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002278 SetPreserveGlyph(a_bool);
2279 SetOutlinePreferred(a_bool);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280#endif
2281 }
2282}
2283
2284
2285/*
2286 * Handle the suspend/resume event
2287 * (apply to the application)
2288 */
2289 void
2290gui_mac_doSuspendEvent(event)
2291 EventRecord *event;
2292{
2293 /* The frontmost application just changed */
2294
2295 /* NOTE: the suspend may happen before the deactivate
2296 * seen on MacOS X
2297 */
2298
2299 /* May not need to change focus as the window will
2300 * get an activate/desactivate event
2301 */
2302 if (event->message & 1)
2303 /* Resume */
2304 gui_focus_change(TRUE);
2305 else
2306 /* Suspend */
2307 gui_focus_change(FALSE);
2308}
2309
2310/*
2311 * Handle the key
2312 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002313#ifdef USE_CARBONKEYHANDLER
2314# define INLINE_KEY_BUFFER_SIZE 80
2315 static pascal OSStatus
2316gui_mac_doKeyEventCarbon(EventHandlerCallRef nextHandler, EventRef theEvent,
2317 void *data)
2318{
2319 /* Multibyte-friendly key event handler */
2320 OSStatus e = -1;
2321 UInt32 actualSize;
2322 UniChar *text;
2323 char_u result[INLINE_KEY_BUFFER_SIZE];
2324 short len = 0;
2325 UInt32 key_sym;
2326 char charcode;
2327 int key_char;
2328 UInt32 modifiers;
2329 size_t encLen;
2330 char_u *to = NULL;
2331 Boolean isSpecial = FALSE;
2332 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002334 /* Mask the mouse (as per user setting) */
2335 if (p_mh)
2336 ObscureCursor();
2337
2338 do
2339 {
2340 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2341 typeUnicodeText, NULL, 0, &actualSize, NULL))
2342 break;
2343
2344 text = (UniChar *)alloc(actualSize);
2345
2346 if (text)
2347 {
2348 do
2349 {
2350 if (noErr != GetEventParameter(theEvent,
2351 kEventParamTextInputSendText,
2352 typeUnicodeText, NULL, actualSize, NULL, text))
2353 break;
2354 EventRef keyEvent;
2355 if (noErr != GetEventParameter(theEvent,
2356 kEventParamTextInputSendKeyboardEvent,
2357 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent))
2358 break;
2359 if (noErr != GetEventParameter(keyEvent,
2360 kEventParamKeyModifiers,
2361 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers))
2362 break;
2363 if (noErr != GetEventParameter(keyEvent,
2364 kEventParamKeyCode,
2365 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym))
2366 break;
2367 if (noErr != GetEventParameter(keyEvent,
2368 kEventParamKeyMacCharCodes,
2369 typeChar, NULL, sizeof(char), NULL, &charcode))
2370 break;
2371
2372 key_char = charcode;
2373
2374 if (modifiers & controlKey)
2375 {
2376 if ((modifiers & ~(controlKey|shiftKey)) == 0
2377 && (key_char == '2' || key_char == '6'))
2378 {
2379 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2380 if (key_char == '2')
2381 key_char = Ctrl_AT;
2382 else
2383 key_char = Ctrl_HAT;
2384
2385 text[0] = (UniChar)key_char;
2386 modifiers = 0;
2387 }
2388 }
2389
2390 if (modifiers & cmdKey)
2391#ifndef USE_CMD_KEY
2392 break; /* Let system handle Cmd+... */
2393#else
2394 {
2395 /* Intercept CMD-. */
2396 if (key_char == '.')
2397 got_int = TRUE;
2398
2399 /* Convert the modifiers */
2400 modifiers = EventModifiers2VimModifiers(modifiers);
2401
2402 /* Following code to simplify and consolidate modifiers
2403 * taken liberally from gui_w48.c */
2404
2405 key_char = simplify_key(key_char, (int *)&modifiers);
2406
2407 /* remove SHIFT for keys that are already shifted, e.g.,
2408 * '(' and '*' */
2409 if (key_char < 0x100 &&
2410 !isalpha(key_char) && isprint(key_char))
2411 modifiers &= ~MOD_MASK_SHIFT;
2412
2413 /* Interpret META, include SHIFT, etc. */
2414 key_char = extract_modifiers(key_char, (int *)&modifiers);
2415 if (key_char == CSI)
2416 key_char = K_CSI;
2417
2418 if (modifiers)
2419 {
2420 result[len++] = CSI;
2421 result[len++] = KS_MODIFIER;
2422 result[len++] = modifiers;
2423 }
2424
2425 isSpecial = TRUE;
2426 }
2427#endif
2428 else
2429 {
2430 /* Find the special key (eg., for cursor keys) */
2431 if (!(actualSize > sizeof(UniChar)) &&
2432 ((text[0] < 0x20) || (text[0] == 0x7f)))
2433 {
2434 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2435 if (special_keys[i].key_sym == key_sym)
2436 {
2437 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2438 special_keys[i].vim_code1);
2439 key_char = simplify_key(key_char,
2440 (int *)&modifiers);
2441 isSpecial = TRUE;
2442 break;
2443 }
2444 }
2445 }
2446
2447 if (isSpecial && IS_SPECIAL(key_char))
2448 {
2449 result[len++] = CSI;
2450 result[len++] = K_SECOND(key_char);
2451 result[len++] = K_THIRD(key_char);
2452 }
2453 else
2454 {
2455 encLen = actualSize;
2456 to = mac_utf16_to_enc(text, actualSize, &encLen);
2457 }
2458
2459 if (to)
2460 {
2461 /* This is basically add_to_input_buf_csi() */
2462 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2463 {
2464 result[len++] = to[i];
2465 if (to[i] == CSI)
2466 {
2467 result[len++] = KS_EXTRA;
2468 result[len++] = (int)KE_CSI;
2469 }
2470 }
2471 vim_free(to);
2472 }
2473
2474 add_to_input_buf(result, len);
2475 e = noErr;
2476 }
2477 while (0);
2478
2479 vim_free(text);
2480 if (e == noErr)
2481 {
2482 /* Fake event to wake up WNE (required to get
2483 * key repeat working */
2484 PostEvent(keyUp, 0);
2485 return noErr;
2486 }
2487 }
2488 }
2489 while (0);
2490
2491 return CallNextEventHandler(nextHandler, theEvent);
2492}
2493#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 void
2495gui_mac_doKeyEvent(EventRecord *theEvent)
2496{
2497 /* TODO: add support for COMMAND KEY */
2498 long menu;
2499 unsigned char string[20];
2500 short num, i;
2501 short len = 0;
2502 KeySym key_sym;
2503 int key_char;
2504 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002505 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506
2507 /* Mask the mouse (as per user setting) */
2508 if (p_mh)
2509 ObscureCursor();
2510
2511 /* Get the key code and it's ASCII representation */
2512 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2513 key_char = theEvent->message & charCodeMask;
2514 num = 1;
2515
2516 /* Intercept CTRL-C */
2517 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002518 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 if (key_char == Ctrl_C && ctrl_c_interrupts)
2520 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002521 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2522 && (key_char == '2' || key_char == '6'))
2523 {
2524 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2525 if (key_char == '2')
2526 key_char = Ctrl_AT;
2527 else
2528 key_char = Ctrl_HAT;
2529 theEvent->modifiers = 0;
2530 }
2531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532
2533 /* Intercept CMD-. */
2534 if (theEvent->modifiers & cmdKey)
2535 if (key_char == '.')
2536 got_int = TRUE;
2537
2538 /* Handle command key as per menu */
2539 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2540 if (theEvent->modifiers & cmdKey)
2541 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2542 * Why the mouse button? */
2543 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2544 {
2545 menu = MenuKey(key_char);
2546 if (HiWord(menu))
2547 {
2548 gui_mac_handle_menu(menu);
2549 return;
2550 }
2551 }
2552
2553 /* Convert the modifiers */
2554 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2555
2556
2557 /* Handle special keys. */
2558#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002559 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2561#endif
2562 {
2563 /* Find the special key (for non-printable keyt_char) */
2564 if ((key_char < 0x20) || (key_char == 0x7f))
2565 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2566 if (special_keys[i].key_sym == key_sym)
2567 {
2568# if 0
2569 /* We currently don't have not so special key */
2570 if (special_keys[i].vim_code1 == NUL)
2571 key_char = special_keys[i].vim_code0;
2572 else
2573# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002574 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2575 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002576 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 break;
2578 }
2579 }
2580
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002581 /* For some keys the modifier is included in the char itself. */
2582 if (simplify || key_char == TAB || key_char == ' ')
2583 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584
2585 /* Add the modifier to the input bu if needed */
2586 /* Do not want SHIFT-A or CTRL-A with modifier */
2587 if (!IS_SPECIAL(key_char)
2588 && key_sym != vk_Space
2589 && key_sym != vk_Tab
2590 && key_sym != vk_Return
2591 && key_sym != vk_Enter
2592 && key_sym != vk_Esc)
2593 {
2594#if 1
2595 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002596 if ((modifiers == MOD_MASK_SHIFT)
2597 || (modifiers == MOD_MASK_CTRL)
2598 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 modifiers = 0;
2600#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002601 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002603 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002605 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 modifiers = modifiers & ~MOD_MASK_SHIFT;
2607#endif
2608 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002609 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002611 string[len++] = CSI;
2612 string[len++] = KS_MODIFIER;
2613 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 }
2615
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002616 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002618 string[len++] = CSI;
2619 string[len++] = K_SECOND(key_char);
2620 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 }
2622 else
2623 {
2624#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002625 /* Convert characters when needed (e.g., from MacRoman to latin1).
2626 * This doesn't work for the NUL byte. */
2627 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 {
2629 char_u from[2], *to;
2630 int l;
2631
2632 from[0] = key_char;
2633 from[1] = NUL;
2634 l = 1;
2635 to = string_convert(&input_conv, from, &l);
2636 if (to != NULL)
2637 {
2638 for (i = 0; i < l && len < 19; i++)
2639 {
2640 if (to[i] == CSI)
2641 {
2642 string[len++] = KS_EXTRA;
2643 string[len++] = KE_CSI;
2644 }
2645 else
2646 string[len++] = to[i];
2647 }
2648 vim_free(to);
2649 }
2650 else
2651 string[len++] = key_char;
2652 }
2653 else
2654#endif
2655 string[len++] = key_char;
2656 }
2657
2658 if (len == 1 && string[0] == CSI)
2659 {
2660 /* Turn CSI into K_CSI. */
2661 string[ len++ ] = KS_EXTRA;
2662 string[ len++ ] = KE_CSI;
2663 }
2664
2665 add_to_input_buf(string, len);
2666}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002667#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668
2669/*
2670 * Handle MouseClick
2671 */
2672 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002673gui_mac_doMouseDownEvent(theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 EventRecord *theEvent;
2675{
2676 short thePart;
2677 WindowPtr whichWindow;
2678
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002679 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680
2681 switch (thePart)
2682 {
2683 case (inDesk):
2684 /* TODO: what to do? */
2685 break;
2686
2687 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002688 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 break;
2690
2691 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002692 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 break;
2694
2695 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002696 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697 break;
2698
2699 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002700 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 break;
2702
2703 case (inGoAway):
2704 if (TrackGoAway(whichWindow, theEvent->where))
2705 gui_shell_closed();
2706 break;
2707
2708 case (inZoomIn):
2709 case (inZoomOut):
2710#ifdef USE_CARBONIZED
2711 gui_mac_doInZoomClick(theEvent, whichWindow);
2712#endif
2713 break;
2714 }
2715}
2716
2717/*
2718 * Handle MouseMoved
2719 * [this event is a moving in and out of a region]
2720 */
2721 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002722gui_mac_doMouseMovedEvent(event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 EventRecord *event;
2724{
2725 Point thePoint;
2726 int_u vimModifiers;
2727
2728 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002729 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2731
2732 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002733 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 else
2735#ifdef USE_CTRLCLICKMENU
2736 if (!clickIsPopup)
2737#endif
2738 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2739 thePoint.v, FALSE, vimModifiers);
2740
2741 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002742 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 FILL_Y(Y_2_ROW(thePoint.v)),
2744 FILL_X(X_2_COL(thePoint.h)+1),
2745 FILL_Y(Y_2_ROW(thePoint.v)+1));
2746
2747 if (dragRectEnbl)
2748 dragRectControl = kCreateRect;
2749
2750}
2751
2752/*
2753 * Handle the mouse release
2754 */
2755 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002756gui_mac_doMouseUpEvent(theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 EventRecord *theEvent;
2758{
2759 Point thePoint;
2760 int_u vimModifiers;
2761
2762 /* TODO: Properly convert the Contextual menu mouse-up */
2763 /* Potential source of the double menu */
2764 lastMouseTick = theEvent->when;
2765 dragRectEnbl = FALSE;
2766 dragRectControl = kCreateEmpty;
2767 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002768 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769
2770 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
2771#ifdef USE_CTRLCLICKMENU
2772 if (clickIsPopup)
2773 {
2774 vimModifiers &= ~MOUSE_CTRL;
2775 clickIsPopup = FALSE;
2776 }
2777#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002778 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779}
2780
2781#ifdef USE_MOUSEWHEEL
2782 static pascal OSStatus
2783gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2784 void *data)
2785{
2786 EventRef bogusEvent;
2787 Point point;
2788 Rect bounds;
2789 UInt32 mod;
2790 SInt32 delta;
2791 int_u vim_mod;
2792
2793 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2794 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2795 goto bail;
2796 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2797 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2798 goto bail;
2799 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2800 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2801 goto bail;
2802
2803 vim_mod = 0;
2804 if (mod & shiftKey)
2805 vim_mod |= MOUSE_SHIFT;
2806 if (mod & controlKey)
2807 vim_mod |= MOUSE_CTRL;
2808 if (mod & optionKey)
2809 vim_mod |= MOUSE_ALT;
2810
2811 /* post a bogus event to wake up WaitNextEvent */
2812 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2813 kEventAttributeNone, &bogusEvent))
2814 goto bail;
2815 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2816 kEventPriorityLow))
2817 goto bail;
2818
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002819 ReleaseEvent(bogusEvent);
2820
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2822 {
2823 point.h -= bounds.left;
2824 point.v -= bounds.top;
2825 }
2826
2827 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2828 point.h, point.v, FALSE, vim_mod);
2829
2830 return noErr;
2831
2832 bail:
2833 /*
2834 * when we fail give any additional callback handler a chance to perform
2835 * it's actions
2836 */
2837 return CallNextEventHandler(nextHandler, theEvent);
2838}
2839#endif /* defined(USE_MOUSEWHEEL) */
2840
2841#if 0
2842
2843/*
2844 * This would be the normal way of invoking the contextual menu
2845 * but the Vim API doesn't seem to a support a request to get
2846 * the menu that we should display
2847 */
2848 void
2849gui_mac_handle_contextual_menu(event)
2850 EventRecord *event;
2851{
2852/*
2853 * Clone PopUp to use menu
2854 * Create a object descriptor for the current selection
2855 * Call the procedure
2856 */
2857
2858// Call to Handle Popup
2859 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2860
2861 if (status != noErr)
2862 return;
2863
2864 if (CntxType == kCMMenuItemSelected)
2865 {
2866 /* Handle the menu CntxMenuID, CntxMenuItem */
2867 /* The submenu can be handle directly by gui_mac_handle_menu */
2868 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002869 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870 }
2871 else if (CntxMenuID == kCMShowHelpSelected)
2872 {
2873 /* Should come up with the help */
2874 }
2875
2876}
2877#endif
2878
2879/*
2880 * Handle menubar selection
2881 */
2882 void
2883gui_mac_handle_menu(menuChoice)
2884 long menuChoice;
2885{
2886 short menu = HiWord(menuChoice);
2887 short item = LoWord(menuChoice);
2888 vimmenu_T *theVimMenu = root_menu;
2889#ifndef USE_CARBONIZED
2890 MenuHandle appleMenu;
2891 Str255 itemName;
2892#endif
2893
2894 if (menu == 256) /* TODO: use constant or gui.xyz */
2895 {
2896 if (item == 1)
2897 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
2898 else
2899 {
2900#ifndef USE_CARBONIZED
2901 /* Desk Accessory doesn't exist in Carbon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002902 appleMenu = GetMenuHandle(menu);
2903 GetMenuItemText(appleMenu, item, itemName);
2904 (void) OpenDeskAcc(itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#endif
2906 }
2907 }
2908 else if (item != 0)
2909 {
2910 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2911
2912 if (theVimMenu)
2913 gui_menu_cb(theVimMenu);
2914 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002915 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916}
2917
2918/*
2919 * Dispatch the event to proper handler
2920 */
2921
2922 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002923gui_mac_handle_event(event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 EventRecord *event;
2925{
2926 OSErr error;
2927
2928 /* Handle contextual menu right now (if needed) */
2929#ifdef USE_CTRLCLICKMENU
2930 if (gui.MacOSHaveCntxMenu)
2931 if (IsShowContextualMenuClick(event))
2932 {
2933# if 0
2934 gui_mac_handle_contextual_menu(event);
2935# else
2936 gui_mac_doMouseDownEvent(event);
2937# endif
2938 return;
2939 }
2940#endif
2941
2942 /* Handle normal event */
2943 switch (event->what)
2944 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002945#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 case (keyDown):
2947 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002948 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 case (keyUp):
2952 /* We don't care about when the key get release */
2953 break;
2954
2955 case (mouseDown):
2956 gui_mac_doMouseDownEvent(event);
2957 break;
2958
2959 case (mouseUp):
2960 gui_mac_doMouseUpEvent(event);
2961 break;
2962
2963 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002964 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965 break;
2966
2967 case (diskEvt):
2968 /* We don't need special handling for disk insertion */
2969 break;
2970
2971 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002972 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 break;
2974
2975 case (osEvt):
2976 switch ((event->message >> 24) & 0xFF)
2977 {
2978 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002979 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 break;
2981 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002982 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 break;
2984 }
2985 break;
2986
2987#ifdef USE_AEVENT
2988 case (kHighLevelEvent):
2989 /* Someone's talking to us, through AppleEvents */
2990 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2991 break;
2992#endif
2993 }
2994}
2995
2996/*
2997 * ------------------------------------------------------------
2998 * Unknown Stuff
2999 * ------------------------------------------------------------
3000 */
3001
3002
3003 GuiFont
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003004gui_mac_find_font(font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005 char_u *font_name;
3006{
3007 char_u c;
3008 char_u *p;
3009 char_u pFontName[256];
3010 Str255 systemFontname;
3011 short font_id;
3012 short size=9;
3013 GuiFont font;
3014#if 0
3015 char_u *fontNamePtr;
3016#endif
3017
3018 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
3019 ;
3020
3021 c = *p;
3022 *p = 0;
3023
3024#if 1
3025 STRCPY(&pFontName[1], font_name);
3026 pFontName[0] = STRLEN(font_name);
3027 *p = c;
3028
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003029 /* Get the font name, minus the style suffix (:h, etc) */
3030#if defined(MACOS_X) && defined(USE_CARBONIZED)
3031 char_u fontName[256];
3032 char_u *styleStart = vim_strchr(font_name, ':');
3033 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
3034 vim_strncpy(fontName, font_name, fontNameLen);
3035
3036 ATSUFontID fontRef;
3037 FMFontStyle fontStyle;
3038 font_id = 0;
3039
3040 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
3041 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
3042 &fontRef) == noErr)
3043 {
3044 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
3045 font_id = 0;
3046 }
3047#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003048 GetFNum(pFontName, &font_id);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003049#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003050
3051 if (font_id == 0)
3052 {
3053 /*
3054 * Try again, this time replacing underscores in the font name
3055 * with spaces (:set guifont allows the two to be used
3056 * interchangeably; the Font Manager doesn't).
3057 */
3058 int i, changed = FALSE;
3059
3060 for (i = pFontName[0]; i > 0; --i)
3061 {
3062 if (pFontName[i] == '_')
3063 {
3064 pFontName[i] = ' ';
3065 changed = TRUE;
3066 }
3067 }
3068 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003069#if defined(MACOS_X) && defined(USE_CARBONIZED)
3070 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
3071 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
3072 kFontNoLanguageCode, &fontRef) == noErr)
3073 {
3074 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
3075 font_id = 0;
3076 }
3077#else
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003078 GetFNum(pFontName, &font_id);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003079#endif
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003080 }
3081
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082#else
3083 /* name = C2Pascal_save(menu->dname); */
3084 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
3085
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003086 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087#endif
3088
3089
3090 if (font_id == 0)
3091 {
3092 /* Oups, the system font was it the one the user want */
3093
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003094#if defined(MACOS_X) && defined(USE_CARBONIZED)
3095 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
3096 return NOFONT;
3097#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003098 GetFontName(0, systemFontname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003099#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 if (!EqualString(pFontName, systemFontname, false, false))
3101 return NOFONT;
3102 }
3103 if (*p == ':')
3104 {
3105 p++;
3106 /* Set the values found after ':' */
3107 while (*p)
3108 {
3109 switch (*p++)
3110 {
3111 case 'h':
3112 size = points_to_pixels(p, &p, TRUE);
3113 break;
3114 /*
3115 * TODO: Maybe accept width and styles
3116 */
3117 }
3118 while (*p == ':')
3119 p++;
3120 }
3121 }
3122
3123 if (size < 1)
3124 size = 1; /* Avoid having a size of 0 with system font */
3125
3126 font = (size << 16) + ((long) font_id & 0xFFFF);
3127
3128 return font;
3129}
3130
3131/*
3132 * ------------------------------------------------------------
3133 * GUI_MCH functionnality
3134 * ------------------------------------------------------------
3135 */
3136
3137/*
3138 * Parse the GUI related command-line arguments. Any arguments used are
3139 * deleted from argv, and *argc is decremented accordingly. This is called
3140 * when vim is started, whether or not the GUI has been started.
3141 */
3142 void
3143gui_mch_prepare(argc, argv)
3144 int *argc;
3145 char **argv;
3146{
3147 /* TODO: Move most of this stuff toward gui_mch_init */
3148#ifdef USE_EXE_NAME
3149 FSSpec applDir;
3150# ifndef USE_FIND_BUNDLE_PATH
3151 short applVRefNum;
3152 long applDirID;
3153 Str255 volName;
3154# else
3155 ProcessSerialNumber psn;
3156 FSRef applFSRef;
3157# endif
3158#endif
3159
3160#ifndef USE_CARBONIZED
3161 MaxApplZone(); /* What could replace thos */
3162 /* In Carbon, all shared library are automatically load in
3163 * there's no need to init them
3164 */
3165 InitGraf(&qd.thePort);
3166 InitFonts();
3167 InitWindows();
3168 InitMenus();
3169 TEInit();
3170 InitDialogs(nil);
3171#else
3172 /* Why did I put that in? (Dany) */
3173 MoreMasterPointers (0x40 * 3); /* we love handles */
3174#endif
3175
3176#if 0
3177 InitCursor();
3178
3179#ifdef USE_CARBONIZED
3180 RegisterAppearanceClient();
3181#endif
3182
3183#ifdef USE_AEVENT
3184 (void) InstallAEHandlers();
3185#endif
3186
3187#ifdef USE_CTRLCLICKMENU
3188 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
3189 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
3190 else
3191 gui.MacOSHaveCntxMenu = false;
3192
3193 if (gui.MacOSHaveCntxMenu)
3194 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
3195#endif
3196
3197#ifdef USE_SIOUX
3198 SIOUXSettings.standalone = false;
3199 SIOUXSettings.initializeTB = false;
3200 SIOUXSettings.setupmenus = false;
3201 SIOUXSettings.asktosaveonclose = false;
3202 SIOUXSettings.showstatusline = true;
3203 SIOUXSettings.toppixel = 300;
3204 SIOUXSettings.leftpixel = 10;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003205 InstallConsole(1); /* fileno(stdout) = 1, on page 430 of MSL C */
3206 printf("Debugging console enabled\n");
3207 /* SIOUXSetTitle((char_u *) "Vim Stdout"); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208#endif
3209
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003210 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003212 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213#ifndef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003214 AppendMenu(pomme, "\p-");
3215 AppendResMenu(pomme, 'DRVR');
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216#endif
3217
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003218 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219
3220 DrawMenuBar();
3221
3222
3223#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003224 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003226 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227#endif
3228
3229
3230#ifdef USE_CARBONIZED
3231 CreateNewWindow(kDocumentWindowClass,
3232 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003233 &windRect, &gui.VimWindow);
3234 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235#else
3236 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, documentProc,
3237 (WindowPtr) -1L, false, 0);
3238 SetPort(gui.VimWindow);
3239#endif
3240
3241 gui.char_width = 7;
3242 gui.char_height = 11;
3243 gui.char_ascent = 6;
3244 gui.num_rows = 24;
3245 gui.num_cols = 80;
3246 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3247
3248#if TARGET_API_MAC_CARBON
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003249 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3250 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003252 gScrollAction = NewControlActionProc(gui_mac_scroll_action);
3253 gScrollDrag = NewControlActionProc(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254#endif
3255
3256 /* Getting a handle to the Help menu */
3257#ifdef USE_HELPMENU
3258# ifdef USE_CARBONIZED
3259 HMGetHelpMenu(&gui.MacOSHelpMenu, NULL);
3260# else
3261 (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu);
3262# endif
3263
3264 if (gui.MacOSHelpMenu != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003265 gui.MacOSHelpItems = CountMenuItems(gui.MacOSHelpMenu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 else
3267 gui.MacOSHelpItems = 0;
3268#endif
3269
3270 dragRectEnbl = FALSE;
3271 dragRgn = NULL;
3272 dragRectControl = kCreateEmpty;
3273 cursorRgn = NewRgn();
3274#endif
3275#ifdef USE_EXE_NAME
3276# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003277 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003279 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280# else
3281 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
3282 * of TN2015
3283 * This technic remove the ../Contents/MacOS/etc part
3284 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003285 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286 /* if (err != noErr) return err; */
3287
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003288 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 /* if (err != noErr) return err; */
3290
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003291 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292
3293 /* This technic return NIL when we disallow_gui */
3294# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003295 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296#endif
3297
3298#ifdef USE_VIM_CREATOR_ID
3299 _fcreator = 'VIM!';
3300 _ftype = 'TEXT';
3301#endif
3302}
3303
3304#ifndef ALWAYS_USE_GUI
3305/*
3306 * Check if the GUI can be started. Called before gvimrc is sourced.
3307 * Return OK or FAIL.
3308 */
3309 int
3310gui_mch_init_check(void)
3311{
3312 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
3313 * using the >console
3314 */
3315 if (disallow_gui) /* see main.c for reason to disallow */
3316 return FAIL;
3317 return OK;
3318}
3319#endif
3320
3321 static OSErr
3322receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag)
3323{
3324 int x, y;
3325 int_u modifiers;
3326 char_u **fnames = NULL;
3327 int count;
3328 int i, j;
3329
3330 /* Get drop position, modifiers and count of items */
3331 {
3332 Point point;
3333 SInt16 mouseUpModifiers;
3334 UInt16 countItem;
3335
3336 GetDragMouse(theDrag, &point, NULL);
3337 GlobalToLocal(&point);
3338 x = point.h;
3339 y = point.v;
3340 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
3341 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
3342 CountDragItems(theDrag, &countItem);
3343 count = countItem;
3344 }
3345
3346 fnames = (char_u **)alloc(count * sizeof(char_u *));
3347 if (fnames == NULL)
3348 return dragNotAcceptedErr;
3349
3350 /* Get file names dropped */
3351 for (i = j = 0; i < count; ++i)
3352 {
3353 DragItemRef item;
3354 OSErr err;
3355 Size size;
3356 FlavorType type = flavorTypeHFS;
3357 HFSFlavor hfsFlavor;
3358
3359 fnames[i] = NULL;
3360 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3361 err = GetFlavorDataSize(theDrag, item, type, &size);
3362 if (err != noErr || size > sizeof(hfsFlavor))
3363 continue;
3364 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3365 if (err != noErr)
3366 continue;
3367 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3368 }
3369 count = j;
3370
3371 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003372
3373 /* Fake mouse event to wake from stall */
3374 PostEvent(mouseUp, 0);
3375
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 return noErr;
3377}
3378
3379/*
3380 * Initialise the GUI. Create all the windows, set up all the call-backs
3381 * etc.
3382 */
3383 int
3384gui_mch_init()
3385{
3386 /* TODO: Move most of this stuff toward gui_mch_init */
3387 Rect windRect;
3388 MenuHandle pomme;
3389#ifdef USE_CTRLCLICKMENU
3390 long gestalt_rc;
3391#endif
3392#ifdef USE_MOUSEWHEEL
3393 EventTypeSpec eventTypeSpec;
3394 EventHandlerRef mouseWheelHandlerRef;
3395#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003396#ifdef USE_CARBONKEYHANDLER
3397 EventHandlerRef keyEventHandlerRef;
3398#endif
3399
3400#ifdef MACOS_X
3401 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
3402 gMacSystemVersion = 0x1000; /* Default to minimum sensible value */
3403#endif
3404
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405#if 1
3406 InitCursor();
3407
3408#ifdef USE_CARBONIZED
3409 RegisterAppearanceClient();
3410#endif
3411
3412#ifdef USE_AEVENT
3413 (void) InstallAEHandlers();
3414#endif
3415
3416#ifdef USE_CTRLCLICKMENU
3417 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
3418 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
3419 else
3420 gui.MacOSHaveCntxMenu = false;
3421
3422 if (gui.MacOSHaveCntxMenu)
3423 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
3424#endif
3425
3426#ifdef USE_SIOUX
3427 SIOUXSettings.standalone = false;
3428 SIOUXSettings.initializeTB = false;
3429 SIOUXSettings.setupmenus = false;
3430 SIOUXSettings.asktosaveonclose = false;
3431 SIOUXSettings.showstatusline = true;
3432 SIOUXSettings.toppixel = 300;
3433 SIOUXSettings.leftpixel = 10;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003434 InstallConsole(1); /* fileno(stdout) = 1, on page 430 of MSL C */
3435 printf("Debugging console enabled\n");
3436 /* SIOUXSetTitle((char_u *) "Vim Stdout"); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437#endif
3438
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003439 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003441 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442#ifndef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003443 AppendMenu(pomme, "\p-");
3444 AppendResMenu(pomme, 'DRVR');
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445#endif
3446
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003447 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448
3449 DrawMenuBar();
3450
3451
3452#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003453 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003455 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456#endif
3457
3458 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
3459#ifdef USE_CARBONIZED
3460 zoomDocProc,
3461#else
3462 documentProc,
3463#endif
3464 (WindowPtr)-1L, true, 0);
3465 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3466 gui.VimWindow, NULL);
3467#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003468 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469#else
3470 SetPort(gui.VimWindow);
3471#endif
3472
3473 gui.char_width = 7;
3474 gui.char_height = 11;
3475 gui.char_ascent = 6;
3476 gui.num_rows = 24;
3477 gui.num_cols = 80;
3478 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3479
3480#if TARGET_API_MAC_CARBON
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003481 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3482 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003484 gScrollAction = NewControlActionProc(gui_mac_scroll_action);
3485 gScrollDrag = NewControlActionProc(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486#endif
3487
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003488#if defined(USE_CARBONIZED) && defined(MACOS_X)
3489 /* Install Carbon event callbacks. */
3490 (void)InstallFontPanelHandler();
3491#endif
3492
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 /* Getting a handle to the Help menu */
3494#ifdef USE_HELPMENU
3495# ifdef USE_CARBONIZED
3496 HMGetHelpMenu(&gui.MacOSHelpMenu, NULL);
3497# else
3498 (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu);
3499# endif
3500
3501 if (gui.MacOSHelpMenu != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003502 gui.MacOSHelpItems = CountMenuItems(gui.MacOSHelpMenu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 else
3504 gui.MacOSHelpItems = 0;
3505#endif
3506
3507 dragRectEnbl = FALSE;
3508 dragRgn = NULL;
3509 dragRectControl = kCreateEmpty;
3510 cursorRgn = NewRgn();
3511#endif
3512 /* Display any pending error messages */
3513 display_errors();
3514
3515 /* Get background/foreground colors from system */
3516 /* TODO: do the approriate call to get real defaults */
3517 gui.norm_pixel = 0x00000000;
3518 gui.back_pixel = 0x00FFFFFF;
3519
3520 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3521 * file). */
3522 set_normal_colors();
3523
3524 /*
3525 * Check that none of the colors are the same as the background color.
3526 * Then store the current values as the defaults.
3527 */
3528 gui_check_colors();
3529 gui.def_norm_pixel = gui.norm_pixel;
3530 gui.def_back_pixel = gui.back_pixel;
3531
3532 /* Get the colors for the highlight groups (gui_check_colors() might have
3533 * changed them) */
3534 highlight_gui_started();
3535
3536 /*
3537 * Setting the gui constants
3538 */
3539#ifdef FEAT_MENU
3540 gui.menu_height = 0;
3541#endif
3542 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3543 gui.border_offset = gui.border_width = 2;
3544
3545#if defined(FEAT_GUI) && defined(MACOS_X)
3546 /* If Quartz-style text antialiasing is available (see
3547 gui_mch_draw_string() below), enable it for all font sizes. */
3548 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
3549#endif
3550
3551#ifdef USE_MOUSEWHEEL
3552 eventTypeSpec.eventClass = kEventClassMouse;
3553 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3554 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3555 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3556 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3557 {
3558 mouseWheelHandlerRef = NULL;
3559 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3560 mouseWheelHandlerUPP = NULL;
3561 }
3562#endif
3563
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003564#ifdef USE_CARBONKEYHANDLER
3565 eventTypeSpec.eventClass = kEventClassTextInput;
3566 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3567 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3568 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3569 &eventTypeSpec, NULL, &keyEventHandlerRef))
3570 {
3571 keyEventHandlerRef = NULL;
3572 DisposeEventHandlerUPP(keyEventHandlerUPP);
3573 keyEventHandlerUPP = NULL;
3574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575#endif
3576
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003577/*
3578#ifdef FEAT_MBYTE
3579 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3580#endif
3581*/
3582
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 /* TODO: Load bitmap if using TOOLBAR */
3584 return OK;
3585}
3586
3587/*
3588 * Called when the foreground or background color has been changed.
3589 */
3590 void
3591gui_mch_new_colors()
3592{
3593 /* TODO:
3594 * This proc is called when Normal is set to a value
3595 * so what msut be done? I don't know
3596 */
3597}
3598
3599/*
3600 * Open the GUI window which was created by a call to gui_mch_init().
3601 */
3602 int
3603gui_mch_open()
3604{
3605 ShowWindow(gui.VimWindow);
3606
3607 if (gui_win_x != -1 && gui_win_y != -1)
3608 gui_mch_set_winpos(gui_win_x, gui_win_y);
3609
3610#ifdef USE_CARBONIZED
3611 /*
3612 * Make the GUI the foreground process (in case it was launched
3613 * from the Terminal or via :gui).
3614 */
3615 {
3616 ProcessSerialNumber psn;
3617 if (GetCurrentProcess(&psn) == noErr)
3618 SetFrontProcess(&psn);
3619 }
3620#endif
3621
3622 return OK;
3623}
3624
3625 void
3626gui_mch_exit(int rc)
3627{
3628 /* TODO: find out all what is missing here? */
3629 DisposeRgn(cursorRgn);
3630
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003631#ifdef USE_CARBONKEYHANDLER
3632 if (keyEventHandlerUPP)
3633 DisposeEventHandlerUPP(keyEventHandlerUPP);
3634#endif
3635
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636#ifdef USE_MOUSEWHEEL
3637 if (mouseWheelHandlerUPP != NULL)
3638 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3639#endif
3640
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003641#ifdef USE_ATSUI_DRAWING
3642 if (gFontStyle)
3643 ATSUDisposeStyle(gFontStyle);
3644#endif
3645
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 /* Exit to shell? */
3647 exit(rc);
3648}
3649
3650/*
3651 * Get the position of the top left corner of the window.
3652 */
3653 int
3654gui_mch_get_winpos(int *x, int *y)
3655{
3656 /* TODO */
3657#ifdef USE_CARBONIZED
3658 Rect bounds;
3659 OSStatus status;
3660
3661 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003662 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663
3664 if (status != noErr)
3665 return FAIL;
3666 *x = bounds.left;
3667 *y = bounds.top;
3668 return OK;
3669#endif
3670 return FAIL;
3671}
3672
3673/*
3674 * Set the position of the top left corner of the window to the given
3675 * coordinates.
3676 */
3677 void
3678gui_mch_set_winpos(int x, int y)
3679{
3680 /* TODO: Should make sure the window is move within range
3681 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3682 */
3683 MoveWindow(gui.VimWindow, x, y, TRUE);
3684}
3685
3686 void
3687gui_mch_set_shellsize(
3688 int width,
3689 int height,
3690 int min_width,
3691 int min_height,
3692 int base_width,
3693 int base_height)
3694{
3695#ifdef USE_CARBONIZED
3696 CGrafPtr VimPort;
3697 Rect VimBound;
3698#endif
3699
3700 if (gui.which_scrollbars[SBAR_LEFT])
3701 {
3702#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003703 VimPort = GetWindowPort(gui.VimWindow);
3704 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003706 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
3708#else
3709 gui.VimWindow->portRect.left = -gui.scrollbar_width; /* + 1;*/
3710 /* SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
3711#endif
3712 }
3713 else
3714 {
3715#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003716 VimPort = GetWindowPort(gui.VimWindow);
3717 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003719 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720#else
3721 gui.VimWindow->portRect.left = 0;
3722#endif;
3723 }
3724
3725 SizeWindow(gui.VimWindow, width, height, TRUE);
3726
3727 gui_resize_shell(width, height);
3728}
3729
3730/*
3731 * Get the screen dimensions.
3732 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3733 * Is there no way to find out how wide the borders really are?
3734 * TODO: Add live udate of those value on suspend/resume.
3735 */
3736 void
3737gui_mch_get_screen_dimensions(screen_w, screen_h)
3738 int *screen_w;
3739 int *screen_h;
3740{
3741 GDHandle dominantDevice = GetMainDevice();
3742 Rect screenRect = (**dominantDevice).gdRect;
3743
3744 *screen_w = screenRect.right - 10;
3745 *screen_h = screenRect.bottom - 40;
3746}
3747
3748
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003749#if defined(USE_CARBONIZED) && defined(MACOS_X)
3750/*
3751 * Open the Font Panel and wait for the user to select a font and
3752 * close the panel. Then fill the buffer pointed to by font_name with
3753 * the name and size of the selected font and return the font's handle,
3754 * or NOFONT in case of an error.
3755 */
3756 static GuiFont
3757gui_mac_select_font(char_u *font_name)
3758{
3759 GuiFont selected_font = NOFONT;
3760 OSStatus status;
3761 FontSelectionQDStyle curr_font;
3762
3763 /* Initialize the Font Panel with the current font. */
3764 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3765 curr_font.size = (gui.norm_font >> 16);
3766 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3767 curr_font.instance.fontStyle = 0;
3768 curr_font.hasColor = false;
3769 curr_font.version = 0; /* version number of the style structure */
3770 status = SetFontInfoForSelection(kFontSelectionQDType,
3771 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3772
3773 gFontPanelInfo.family = curr_font.instance.fontFamily;
3774 gFontPanelInfo.style = curr_font.instance.fontStyle;
3775 gFontPanelInfo.size = curr_font.size;
3776
3777 /* Pop up the Font Panel. */
3778 status = FPShowHideFontPanel();
3779 if (status == noErr)
3780 {
3781 /*
3782 * The Font Panel is modeless. We really need it to be modal,
3783 * so we spin in an event loop until the panel is closed.
3784 */
3785 gFontPanelInfo.isPanelVisible = true;
3786 while (gFontPanelInfo.isPanelVisible)
3787 {
3788 EventRecord e;
3789 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3790 }
3791
3792 GetFontPanelSelection(font_name);
3793 selected_font = gui_mac_find_font(font_name);
3794 }
3795 return selected_font;
3796}
3797#endif
3798
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799
3800/*
3801 * Initialise vim to use the font with the given name. Return FAIL if the font
3802 * could not be loaded, OK otherwise.
3803 */
3804 int
3805gui_mch_init_font(font_name, fontset)
3806 char_u *font_name;
3807 int fontset; /* not used */
3808{
3809 /* TODO: Add support for bold italic underline proportional etc... */
3810 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003811 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 FontInfo font_info;
3813 short font_id;
3814 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003815 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003817#ifdef USE_ATSUI_DRAWING
3818 if (gFontStyle == NULL)
3819 {
3820 if (ATSUCreateStyle(&gFontStyle) != noErr)
3821 gFontStyle = NULL;
3822 }
3823#endif
3824
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 if (font_name == NULL)
3826 {
3827 /* First try to get the suggested font */
3828 GetFNum(suggestedFont, &font_id);
3829
3830 if (font_id == 0)
3831 {
3832 /* Then pickup the standard application font */
3833 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003834 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003836 else
3837 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003838 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3839 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003840#if defined(USE_CARBONIZED) && defined(MACOS_X)
3841 else if (STRCMP(font_name, "*") == 0)
3842 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003843 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003844
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003845 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003846 if (font == NOFONT)
3847 return FAIL;
3848
3849 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003850 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003851 if (new_p_guifont != NULL)
3852 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003853 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003854 vim_free(p_guifont);
3855 p_guifont = new_p_guifont;
3856 /* Replace spaces in the font name with underscores. */
3857 for ( ; *new_p_guifont; ++new_p_guifont)
3858 {
3859 if (*new_p_guifont == ' ')
3860 *new_p_guifont = '_';
3861 }
3862 }
3863 }
3864#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003865 else
3866 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003867 font = gui_mac_find_font(font_name);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003868 STRNCPY(used_font_name, font_name, sizeof(used_font_name));
3869 used_font_name[sizeof(used_font_name) - 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870
3871 if (font == NOFONT)
3872 return FAIL;
3873 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003874
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 gui.norm_font = font;
3876
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003877 hl_set_font_name(used_font_name);
3878
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003879 TextSize(font >> 16);
3880 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003882 GetFontInfo(&font_info);
3883
3884 gui.char_ascent = font_info.ascent;
3885 gui.char_width = CharWidth('_');
3886 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3887
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003888#ifdef USE_ATSUI_DRAWING
3889 ATSUFontID fontID;
3890 Fixed fontSize;
3891 ATSStyleRenderingOptions fontOptions;
3892
3893 if (gFontStyle)
3894 {
3895 fontID = font & 0xFFFF;
3896 fontSize = Long2Fix(font >> 16);
3897
3898 /* No antialiasing by default (do not attempt to touch antialising
3899 * options on pre-Jaguar) */
3900 fontOptions =
3901#ifdef MACOS_X
3902 (gMacSystemVersion >= 0x1020) ?
3903 kATSStyleNoAntiAliasing :
3904#endif
3905 kATSStyleNoOptions;
3906
3907 ATSUAttributeTag attribTags[] =
3908 {
3909 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3910 kATSUMaxATSUITagValue+1
3911 };
3912 ByteCount attribSizes[] =
3913 {
3914 sizeof(ATSUFontID), sizeof(Fixed),
3915 sizeof(ATSStyleRenderingOptions), sizeof font
3916 };
3917 ATSUAttributeValuePtr attribValues[] =
3918 {
3919 &fontID, &fontSize, &fontOptions, &font
3920 };
3921
3922 /* Convert font id to ATSUFontID */
3923 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3924 {
3925 if (ATSUSetAttributes(gFontStyle,
3926 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3927 attribTags, attribSizes, attribValues) != noErr)
3928 {
3929 ATSUDisposeStyle(gFontStyle);
3930 gFontStyle = NULL;
3931 }
3932 }
3933 }
3934#endif
3935
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 return OK;
3937
3938}
3939
3940 int
3941gui_mch_adjust_charsize()
3942{
3943 FontInfo font_info;
3944
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003945 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3947 gui.char_ascent = font_info.ascent + p_linespace / 2;
3948 return OK;
3949}
3950
3951/*
3952 * Get a font structure for highlighting.
3953 */
3954 GuiFont
3955gui_mch_get_font(name, giveErrorIfMissing)
3956 char_u *name;
3957 int giveErrorIfMissing;
3958{
3959 GuiFont font;
3960
3961 font = gui_mac_find_font(name);
3962
3963 if (font == NOFONT)
3964 {
3965 if (giveErrorIfMissing)
3966 EMSG2(_(e_font), name);
3967 return NOFONT;
3968 }
3969 /*
3970 * TODO : Accept only monospace
3971 */
3972
3973 return font;
3974}
3975
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003976#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003978 * Return the name of font "font" in allocated memory.
3979 * Don't know how to get the actual name, thus use the provided name.
3980 */
3981 char_u *
3982gui_mch_get_fontname(font, name)
3983 GuiFont font;
3984 char_u *name;
3985{
3986 if (name == NULL)
3987 return NULL;
3988 return vim_strsave(name);
3989}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003990#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003991
3992/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 * Set the current text font.
3994 */
3995 void
3996gui_mch_set_font(font)
3997 GuiFont font;
3998{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003999#ifdef USE_ATSUI_DRAWING
4000 GuiFont currFont;
4001 ByteCount actualFontByteCount;
4002 ATSUFontID fontID;
4003 Fixed fontSize;
4004 ATSStyleRenderingOptions fontOptions;
4005
4006 if (gFontStyle)
4007 {
4008 /* Avoid setting same font again */
4009 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
4010 &currFont, &actualFontByteCount) == noErr &&
4011 actualFontByteCount == (sizeof font))
4012 {
4013 if (currFont == font)
4014 return;
4015 }
4016
4017 fontID = font & 0xFFFF;
4018 fontSize = Long2Fix(font >> 16);
4019 /* Respect p_antialias setting only for wide font.
4020 * The reason for doing this at the moment is a bit complicated,
4021 * but it's mainly because a) latin (non-wide) aliased fonts
4022 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
4023 * b) wide multibyte input does not suffer from that problem. */
4024 fontOptions =
4025#ifdef MACOS_X
4026 (p_antialias && (font == gui.wide_font)) ?
4027 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
4028#else
4029 kATSStyleNoOptions;
4030#endif
4031
4032 ATSUAttributeTag attribTags[] =
4033 {
4034 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
4035 kATSUMaxATSUITagValue+1
4036 };
4037 ByteCount attribSizes[] =
4038 {
4039 sizeof(ATSUFontID), sizeof(Fixed),
4040 sizeof(ATSStyleRenderingOptions), sizeof font
4041 };
4042 ATSUAttributeValuePtr attribValues[] =
4043 {
4044 &fontID, &fontSize, &fontOptions, &font
4045 };
4046
4047 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
4048 {
4049 if (ATSUSetAttributes(gFontStyle,
4050 (sizeof attribTags)/sizeof(ATSUAttributeTag),
4051 attribTags, attribSizes, attribValues) != noErr)
4052 {
4053#ifndef NDEBUG
4054 fprintf(stderr, "couldn't set font style\n");
4055#endif
4056 ATSUDisposeStyle(gFontStyle);
4057 gFontStyle = NULL;
4058 }
4059 }
4060
4061 }
4062
4063 if (!gIsFontFallbackSet)
4064 {
4065 /* Setup automatic font substitution. The user's guifontwide
4066 * is tried first, then the system tries other fonts. */
4067/*
4068 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
4069 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
4070 ATSUCreateFontFallbacks(&gFontFallbacks);
4071 ATSUSetObjFontFallbacks(gFontFallbacks, );
4072*/
4073 if (gui.wide_font)
4074 {
4075 ATSUFontID fallbackFonts;
4076 gIsFontFallbackSet = TRUE;
4077
4078 if (FMGetFontFromFontFamilyInstance(
4079 (gui.wide_font & 0xFFFF),
4080 0,
4081 &fallbackFonts,
4082 NULL) == noErr)
4083 {
4084 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
4085 }
4086/*
4087 ATSUAttributeValuePtr fallbackValues[] = { };
4088*/
4089 }
4090 }
4091#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 TextSize(font >> 16);
4093 TextFont(font & 0xFFFF);
4094}
4095
4096#if 0 /* not used */
4097/*
4098 * Return TRUE if the two fonts given are equivalent.
4099 */
4100 int
4101gui_mch_same_font(f1, f2)
4102 GuiFont f1;
4103 GuiFont f2;
4104{
4105 return f1 == f2;
4106}
4107#endif
4108
4109/*
4110 * If a font is not going to be used, free its structure.
4111 */
4112 void
4113gui_mch_free_font(font)
4114 GuiFont font;
4115{
4116 /*
4117 * Free font when "font" is not 0.
4118 * Nothing to do in the current implementation, since
4119 * nothing is allocated for each font used.
4120 */
4121}
4122
4123 static int
4124hex_digit(c)
4125 int c;
4126{
4127 if (isdigit(c))
4128 return c - '0';
4129 c = TOLOWER_ASC(c);
4130 if (c >= 'a' && c <= 'f')
4131 return c - 'a' + 10;
4132 return -1000;
4133}
4134
4135/*
4136 * Return the Pixel value (color) for the given color name. This routine was
4137 * pretty much taken from example code in the Silicon Graphics OSF/Motif
4138 * Programmer's Guide.
4139 * Return INVALCOLOR when failed.
4140 */
4141 guicolor_T
4142gui_mch_get_color(name)
4143 char_u *name;
4144{
4145 /* TODO: Add support for the new named color of MacOS 8
4146 */
4147 RGBColor MacColor;
4148// guicolor_T color = 0;
4149
4150 typedef struct guicolor_tTable
4151 {
4152 char *name;
4153 guicolor_T color;
4154 } guicolor_tTable;
4155
4156 /*
4157 * The comment at the end of each line is the source
4158 * (Mac, Window, Unix) and the number is the unix rgb.txt value
4159 */
4160 static guicolor_tTable table[] =
4161 {
4162 {"Black", RGB(0x00, 0x00, 0x00)},
4163 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
4164 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
4165 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
4166 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
4167 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
4168 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
4169 {"white", RGB(0xFF, 0xFF, 0xFF)},
4170 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
4171 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
4172 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
4173 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
4174 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
4175 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
4176 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
4177 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
4178 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
4179 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
4180 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
4181 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
4182 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
4183 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
4184 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
4185 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
4186 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
4187 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
4188 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
4189 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
4190 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
4191 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
4192 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
4193 };
4194
4195 int r, g, b;
4196 int i;
4197
4198 if (name[0] == '#' && strlen((char *) name) == 7)
4199 {
4200 /* Name is in "#rrggbb" format */
4201 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
4202 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
4203 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
4204 if (r < 0 || g < 0 || b < 0)
4205 return INVALCOLOR;
4206 return RGB(r, g, b);
4207 }
4208 else
4209 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004210 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004212 LMGetHiliteRGB(&MacColor);
4213 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 }
4215 /* Check if the name is one of the colors we know */
4216 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
4217 if (STRICMP(name, table[i].name) == 0)
4218 return table[i].color;
4219 }
4220
4221
4222 /*
4223 * Last attempt. Look in the file "$VIM/rgb.txt".
4224 */
4225 {
4226#define LINE_LEN 100
4227 FILE *fd;
4228 char line[LINE_LEN];
4229 char_u *fname;
4230
4231#ifdef COLON_AS_PATHSEP
4232 fname = expand_env_save((char_u *)"$VIMRUNTIME:rgb.txt");
4233#else
4234 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
4235#endif
4236 if (fname == NULL)
4237 return INVALCOLOR;
4238
4239 fd = fopen((char *)fname, "rt");
4240 vim_free(fname);
4241 if (fd == NULL)
4242 return INVALCOLOR;
4243
4244 while (!feof(fd))
4245 {
4246 int len;
4247 int pos;
4248 char *color;
4249
4250 fgets(line, LINE_LEN, fd);
4251 len = strlen(line);
4252
4253 if (len <= 1 || line[len-1] != '\n')
4254 continue;
4255
4256 line[len-1] = '\0';
4257
4258 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
4259 if (i != 3)
4260 continue;
4261
4262 color = line + pos;
4263
4264 if (STRICMP(color, name) == 0)
4265 {
4266 fclose(fd);
4267 return (guicolor_T) RGB(r, g, b);
4268 }
4269 }
4270 fclose(fd);
4271 }
4272
4273 return INVALCOLOR;
4274}
4275
4276/*
4277 * Set the current text foreground color.
4278 */
4279 void
4280gui_mch_set_fg_color(color)
4281 guicolor_T color;
4282{
4283 RGBColor TheColor;
4284
4285 TheColor.red = Red(color) * 0x0101;
4286 TheColor.green = Green(color) * 0x0101;
4287 TheColor.blue = Blue(color) * 0x0101;
4288
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004289 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290}
4291
4292/*
4293 * Set the current text background color.
4294 */
4295 void
4296gui_mch_set_bg_color(color)
4297 guicolor_T color;
4298{
4299 RGBColor TheColor;
4300
4301 TheColor.red = Red(color) * 0x0101;
4302 TheColor.green = Green(color) * 0x0101;
4303 TheColor.blue = Blue(color) * 0x0101;
4304
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004305 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306}
4307
4308 void
4309gui_mch_draw_string(row, col, s, len, flags)
4310 int row;
4311 int col;
4312 char_u *s;
4313 int len;
4314 int flags;
4315{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316#ifdef FEAT_MBYTE
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004317#ifdef USE_ATSUI_DRAWING
4318 /* ATSUI requires utf-16 strings */
4319 UniCharCount utf16_len;
4320 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4321 utf16_len /= sizeof(UniChar);
4322#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 char_u *tofree = NULL;
4324
4325 if (output_conv.vc_type != CONV_NONE)
4326 {
4327 tofree = string_convert(&output_conv, s, &len);
4328 if (tofree != NULL)
4329 s = tofree;
4330 }
4331#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004332#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333
4334#if defined(FEAT_GUI) && defined(MACOS_X)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004335 /* ATSUI automatically antialiases text */
4336#ifndef USE_ATSUI_DRAWING
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337 /*
4338 * On OS X, try using Quartz-style text antialiasing.
4339 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004340 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 {
4342 /* Quartz antialiasing is available only in OS 10.2 and later. */
4343 UInt32 qd_flags = (p_antialias ?
4344 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004345 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004347#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004349 /*
4350 * When antialiasing we're using srcOr mode, we have to clear the block
4351 * before drawing the text.
4352 * Also needed when 'linespace' is non-zero to remove the cursor and
4353 * underlining.
4354 * But not when drawing transparently.
4355 * The following is like calling gui_mch_clear_block(row, col, row, col +
4356 * len - 1), but without setting the bg color to gui.back_pixel.
4357 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004358#ifdef USE_ATSUI_DRAWING
4359 if ((flags & DRAW_TRANSP) == 0)
4360#else
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004361 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004362 && !(flags & DRAW_TRANSP))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004363#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004364 {
4365 Rect rc;
4366
4367 rc.left = FILL_X(col);
4368 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004369#ifdef FEAT_MBYTE
4370 /* Multibyte computation taken from gui_w32.c */
4371 if (has_mbyte)
4372 {
4373 int cell_len = 0;
4374 int n;
4375
4376 /* Compute the length in display cells. */
4377 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4378 cell_len += (*mb_ptr2cells)(s + n);
4379 rc.right = FILL_X(col + cell_len);
4380 }
4381 else
4382#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004383 rc.right = FILL_X(col + len) + (col + len == Columns);
4384 rc.bottom = FILL_Y(row + 1);
4385 EraseRect(&rc);
4386 }
4387
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004388#ifndef USE_ATSUI_DRAWING
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004389 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 {
4391 StyleParameter face;
4392
4393 face = normal;
4394 if (flags & DRAW_BOLD)
4395 face |= bold;
4396 if (flags & DRAW_UNDERL)
4397 face |= underline;
4398 TextFace(face);
4399
4400 /* Quartz antialiasing works only in srcOr transfer mode. */
4401 TextMode(srcOr);
4402
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 MoveTo(TEXT_X(col), TEXT_Y(row));
4404 DrawText((char*)s, 0, len);
4405 }
4406 else
4407#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004408#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409 {
4410 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004411 TextMode(srcCopy);
4412 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413
4414 /* SelectFont(hdc, gui.currFont); */
4415
4416 if (flags & DRAW_TRANSP)
4417 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004418 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419 }
4420
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004421 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004422#ifdef USE_ATSUI_DRAWING
4423 ATSUTextLayout textLayout;
4424
4425 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4426 kATSUFromTextBeginning, kATSUToTextEnd,
4427 utf16_len,
4428 (gFontStyle ? 1 : 0), &utf16_len,
4429 (gFontStyle ? &gFontStyle : NULL),
4430 &textLayout) == noErr)
4431 {
4432 ATSUSetTransientFontMatching(textLayout, TRUE);
4433
4434 ATSUDrawText(textLayout,
4435 kATSUFromTextBeginning, kATSUToTextEnd,
4436 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4437
4438 ATSUDisposeTextLayout(textLayout);
4439 }
4440#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004441 DrawText((char *)s, 0, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442
4443
4444 if (flags & DRAW_BOLD)
4445 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004446 TextMode(srcOr);
4447 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4448 DrawText((char *)s, 0, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 }
4450
4451 if (flags & DRAW_UNDERL)
4452 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004453 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4454 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004456#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 }
4458
4459#ifdef FEAT_MBYTE
4460 vim_free(tofree);
4461#endif
4462}
4463
4464/*
4465 * Return OK if the key with the termcap name "name" is supported.
4466 */
4467 int
4468gui_mch_haskey(name)
4469 char_u *name;
4470{
4471 int i;
4472
4473 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4474 if (name[0] == special_keys[i].vim_code0 &&
4475 name[1] == special_keys[i].vim_code1)
4476 return OK;
4477 return FAIL;
4478}
4479
4480 void
4481gui_mch_beep()
4482{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004483 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484}
4485
4486 void
4487gui_mch_flash(msec)
4488 int msec;
4489{
4490 /* Do a visual beep by reversing the foreground and background colors */
4491 Rect rc;
4492
4493 /*
4494 * Note: InvertRect() excludes right and bottom of rectangle.
4495 */
4496 rc.left = 0;
4497 rc.top = 0;
4498 rc.right = gui.num_cols * gui.char_width;
4499 rc.bottom = gui.num_rows * gui.char_height;
4500 InvertRect(&rc);
4501
4502 ui_delay((long)msec, TRUE); /* wait for some msec */
4503
4504 InvertRect(&rc);
4505}
4506
4507/*
4508 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4509 */
4510 void
4511gui_mch_invert_rectangle(r, c, nr, nc)
4512 int r;
4513 int c;
4514 int nr;
4515 int nc;
4516{
4517 Rect rc;
4518
4519 /*
4520 * Note: InvertRect() excludes right and bottom of rectangle.
4521 */
4522 rc.left = FILL_X(c);
4523 rc.top = FILL_Y(r);
4524 rc.right = rc.left + nc * gui.char_width;
4525 rc.bottom = rc.top + nr * gui.char_height;
4526 InvertRect(&rc);
4527
4528}
4529
4530/*
4531 * Iconify the GUI window.
4532 */
4533 void
4534gui_mch_iconify()
4535{
4536 /* TODO: find out what could replace iconify
4537 * -window shade?
4538 * -hide application?
4539 */
4540}
4541
4542#if defined(FEAT_EVAL) || defined(PROTO)
4543/*
4544 * Bring the Vim window to the foreground.
4545 */
4546 void
4547gui_mch_set_foreground()
4548{
4549 /* TODO */
4550}
4551#endif
4552
4553/*
4554 * Draw a cursor without focus.
4555 */
4556 void
4557gui_mch_draw_hollow_cursor(color)
4558 guicolor_T color;
4559{
4560 Rect rc;
4561
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 /*
4563 * Note: FrameRect() excludes right and bottom of rectangle.
4564 */
4565 rc.left = FILL_X(gui.col);
4566 rc.top = FILL_Y(gui.row);
4567 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004568#ifdef FEAT_MBYTE
4569 if (mb_lefthalve(gui.row, gui.col))
4570 rc.right += gui.char_width;
4571#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 rc.bottom = rc.top + gui.char_height;
4573
4574 gui_mch_set_fg_color(color);
4575
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004576 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577}
4578
4579/*
4580 * Draw part of a cursor, only w pixels wide, and h pixels high.
4581 */
4582 void
4583gui_mch_draw_part_cursor(w, h, color)
4584 int w;
4585 int h;
4586 guicolor_T color;
4587{
4588 Rect rc;
4589
4590#ifdef FEAT_RIGHTLEFT
4591 /* vertical line should be on the right of current point */
4592 if (CURSOR_BAR_RIGHT)
4593 rc.left = FILL_X(gui.col + 1) - w;
4594 else
4595#endif
4596 rc.left = FILL_X(gui.col);
4597 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4598 rc.right = rc.left + w;
4599 rc.bottom = rc.top + h;
4600
4601 gui_mch_set_fg_color(color);
4602
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004603 FrameRect(&rc);
4604// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605}
4606
4607
4608
4609/*
4610 * Catch up with any queued X events. This may put keyboard input into the
4611 * input buffer, call resize call-backs, trigger timers etc. If there is
4612 * nothing in the X event queue (& no timers pending), then we return
4613 * immediately.
4614 */
4615 void
4616gui_mch_update()
4617{
4618 /* TODO: find what to do
4619 * maybe call gui_mch_wait_for_chars (0)
4620 * more like look at EventQueue then
4621 * call heart of gui_mch_wait_for_chars;
4622 *
4623 * if (eventther)
4624 * gui_mac_handle_event(&event);
4625 */
4626 EventRecord theEvent;
4627
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004628 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 if (theEvent.what != nullEvent)
4630 gui_mch_wait_for_chars(0);
4631}
4632
4633/*
4634 * Simple wrapper to neglect more easily the time
4635 * spent inside WaitNextEvent while profiling.
4636 */
4637
4638#if defined(__MWERKS__) /* only in Codewarrior */
4639# pragma profile reset
4640#endif
4641 pascal
4642 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004643WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644{
4645 if (((long) sleep) < -1)
4646 sleep = 32767;
4647 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4648}
4649
4650/*
4651 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4652 * from the keyboard.
4653 * wtime == -1 Wait forever.
4654 * wtime == 0 This should never happen.
4655 * wtime > 0 Wait wtime milliseconds for a character.
4656 * Returns OK if a character was found to be available within the given time,
4657 * or FAIL otherwise.
4658 */
4659#if defined(__MWERKS__) /* only in Codewarrior */
4660# pragma profile reset
4661#endif
4662 int
4663gui_mch_wait_for_chars(wtime)
4664 int wtime;
4665{
4666 EventMask mask = (everyEvent);
4667 EventRecord event;
4668 long entryTick;
4669 long currentTick;
4670 long sleeppyTick;
4671
4672 /* If we are providing life feedback with the scrollbar,
4673 * we don't want to try to wait for an event, or else
4674 * there won't be any life feedback.
4675 */
4676 if (dragged_sb != NULL)
4677 return FAIL;
4678 /* TODO: Check if FAIL is the proper return code */
4679
4680 entryTick = TickCount();
4681
4682 allow_scrollbar = TRUE;
4683
4684 do
4685 {
4686/* if (dragRectControl == kCreateEmpty)
4687 {
4688 dragRgn = NULL;
4689 dragRectControl = kNothing;
4690 }
4691 else*/ if (dragRectControl == kCreateRect)
4692 {
4693 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004694 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 dragRectControl = kNothing;
4696 }
4697 /*
4698 * Don't use gui_mch_update() because then we will spin-lock until a
4699 * char arrives, instead we use WaitNextEventWrp() to hang until an
4700 * event arrives. No need to check for input_buf_full because we are
4701 * returning as soon as it contains a single char.
4702 */
4703 /* TODO: reduce wtime accordinly??? */
4704 if (wtime > -1)
4705 sleeppyTick = 60*wtime/1000;
4706 else
4707 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004708 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709 {
4710#ifdef USE_SIOUX
4711 if (!SIOUXHandleOneEvent(&event))
4712#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004713 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 if (input_available())
4715 {
4716 allow_scrollbar = FALSE;
4717 return OK;
4718 }
4719 }
4720 currentTick = TickCount();
4721 }
4722 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4723
4724 allow_scrollbar = FALSE;
4725 return FAIL;
4726}
4727
4728#if defined(__MWERKS__) /* only in Codewarrior */
4729# pragma profile reset
4730#endif
4731
4732/*
4733 * Output routines.
4734 */
4735
4736/* Flush any output to the screen */
4737 void
4738gui_mch_flush()
4739{
4740 /* TODO: Is anything needed here? */
4741}
4742
4743/*
4744 * Clear a rectangular region of the screen from text pos (row1, col1) to
4745 * (row2, col2) inclusive.
4746 */
4747 void
4748gui_mch_clear_block(row1, col1, row2, col2)
4749 int row1;
4750 int col1;
4751 int row2;
4752 int col2;
4753{
4754 Rect rc;
4755
4756 /*
4757 * Clear one extra pixel at the far right, for when bold characters have
4758 * spilled over to the next column.
4759 */
4760 rc.left = FILL_X(col1);
4761 rc.top = FILL_Y(row1);
4762 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4763 rc.bottom = FILL_Y(row2 + 1);
4764
4765 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004766 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767}
4768
4769/*
4770 * Clear the whole text window.
4771 */
4772 void
4773gui_mch_clear_all()
4774{
4775 Rect rc;
4776
4777 rc.left = 0;
4778 rc.top = 0;
4779 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4780 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4781
4782 gui_mch_set_bg_color(gui.back_pixel);
4783 EraseRect(&rc);
4784/* gui_mch_set_fg_color(gui.norm_pixel);
4785 FrameRect(&rc);
4786*/
4787}
4788
4789/*
4790 * Delete the given number of lines from the given row, scrolling up any
4791 * text further down within the scroll region.
4792 */
4793 void
4794gui_mch_delete_lines(row, num_lines)
4795 int row;
4796 int num_lines;
4797{
4798 Rect rc;
4799
4800 /* changed without checking! */
4801 rc.left = FILL_X(gui.scroll_region_left);
4802 rc.right = FILL_X(gui.scroll_region_right + 1);
4803 rc.top = FILL_Y(row);
4804 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4805
4806 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004807 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808
4809 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4810 gui.scroll_region_left,
4811 gui.scroll_region_bot, gui.scroll_region_right);
4812}
4813
4814/*
4815 * Insert the given number of lines before the given row, scrolling down any
4816 * following text within the scroll region.
4817 */
4818 void
4819gui_mch_insert_lines(row, num_lines)
4820 int row;
4821 int num_lines;
4822{
4823 Rect rc;
4824
4825 rc.left = FILL_X(gui.scroll_region_left);
4826 rc.right = FILL_X(gui.scroll_region_right + 1);
4827 rc.top = FILL_Y(row);
4828 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4829
4830 gui_mch_set_bg_color(gui.back_pixel);
4831
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004832 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833
4834 /* Update gui.cursor_row if the cursor scrolled or copied over */
4835 if (gui.cursor_row >= gui.row
4836 && gui.cursor_col >= gui.scroll_region_left
4837 && gui.cursor_col <= gui.scroll_region_right)
4838 {
4839 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4840 gui.cursor_row += num_lines;
4841 else if (gui.cursor_row <= gui.scroll_region_bot)
4842 gui.cursor_is_valid = FALSE;
4843 }
4844
4845 gui_clear_block(row, gui.scroll_region_left,
4846 row + num_lines - 1, gui.scroll_region_right);
4847}
4848
4849 /*
4850 * TODO: add a vim format to the clipboard which remember
4851 * LINEWISE, CHARWISE, BLOCKWISE
4852 */
4853
4854 void
4855clip_mch_request_selection(cbd)
4856 VimClipboard *cbd;
4857{
4858
4859 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004860 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861#ifdef USE_CARBONIZED
4862 Size scrapSize;
4863 ScrapFlavorFlags scrapFlags;
4864 ScrapRef scrap = nil;
4865 OSStatus error;
4866#else
4867 long scrapOffset;
4868 long scrapSize;
4869#endif
4870 int type;
4871 char *searchCR;
4872 char_u *tempclip;
4873
4874
4875#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004876 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 if (error != noErr)
4878 return;
4879
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004880 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4881 if (error == noErr)
4882 {
4883 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4884 if (error == noErr && scrapSize > 1)
4885 flavor = 1;
4886 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004888 if (flavor == 0)
4889 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004890 error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004891 if (error != noErr)
4892 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004893
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004894 error = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004895 if (error != noErr)
4896 return;
4897 }
4898
4899 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900#else
4901 /* Call to LoadScrap seem to avoid problem with crash on first paste */
4902 scrapSize = LoadScrap();
4903 scrapSize = GetScrap(nil, 'TEXT', &scrapOffset);
4904
4905 if (scrapSize > 0)
4906#endif
4907 {
4908#ifdef USE_CARBONIZED
4909 /* In CARBON we don't need a Handle, a pointer is good */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004910 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911 /* tempclip = lalloc(scrapSize+1, TRUE); */
4912#else
4913 textOfClip = NewHandle(0);
4914#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004915 HLock(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004916#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004917 error = GetScrapFlavorData(scrap,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004918 flavor ? VIMSCRAPFLAVOR : kScrapFlavorTypeUnicode,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004919 &scrapSize, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920#else
4921 scrapSize = GetScrap(textOfClip, 'TEXT', &scrapOffset);
4922#endif
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004923 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004925 if (flavor)
4926 type = **textOfClip;
4927 else
4928 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004929
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004930 tempclip = lalloc(scrapSize + 1, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004931#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED)
4932 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4933#else
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004934 STRNCPY(tempclip, *textOfClip + flavor, scrapSize);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004935#endif
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004936 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937
4938 searchCR = (char *)tempclip;
4939 while (searchCR != NULL)
4940 {
4941 searchCR = strchr(searchCR, '\r');
4942
4943 if (searchCR != NULL)
4944 searchCR[0] = '\n';
4945
4946 }
4947
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004948#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED)
4949 /* Convert from utf-16 (clipboard) */
4950 size_t encLen = 0;
4951 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
4952 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004954 scrapSize = encLen;
4955 vim_free(tempclip);
4956 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 }
4958#endif
4959 clip_yank_selection(type, tempclip, scrapSize, cbd);
4960
4961 vim_free(tempclip);
4962 HUnlock(textOfClip);
4963
4964 DisposeHandle(textOfClip);
4965 }
4966}
4967
4968 void
4969clip_mch_lose_selection(cbd)
4970 VimClipboard *cbd;
4971{
4972 /*
4973 * TODO: Really nothing to do?
4974 */
4975}
4976
4977 int
4978clip_mch_own_selection(cbd)
4979 VimClipboard *cbd;
4980{
4981 return OK;
4982}
4983
4984/*
4985 * Send the current selection to the clipboard.
4986 */
4987 void
4988clip_mch_set_selection(cbd)
4989 VimClipboard *cbd;
4990{
4991 Handle textOfClip;
4992 long scrapSize;
4993 int type;
4994#ifdef USE_CARBONIZED
4995 ScrapRef scrap;
4996#endif
4997
4998 char_u *str = NULL;
4999
5000 if (!cbd->owned)
5001 return;
5002
5003 clip_get_selection(cbd);
5004
5005 /*
5006 * Once we set the clipboard, lose ownership. If another application sets
5007 * the clipboard, we don't want to think that we still own it.
5008 *
5009 */
5010
5011 cbd->owned = FALSE;
5012
5013 type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd);
5014
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005015#if defined(FEAT_MBYTE) && defined(USE_CARBONIZED)
5016 size_t utf16_len = 0;
5017 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
5018 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005019 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005020 scrapSize = utf16_len;
5021 vim_free(str);
5022 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023 }
5024#endif
5025
5026 if (type >= 0)
5027 {
5028#ifdef USE_CARBONIZED
5029 ClearCurrentScrap();
5030#else
5031 ZeroScrap();
5032#endif
5033
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005034#ifdef USE_CARBONIZED
5035 textOfClip = NewHandle(scrapSize + 1);
5036#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037 textOfClip = NewHandle(scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005038#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039 HLock(textOfClip);
5040
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005042 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005043 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005044 GetCurrentScrap(&scrap);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005045 PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005046 scrapSize, *textOfClip + 1);
5047 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
5048 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005050 STRNCPY(*textOfClip, str, scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 PutScrap(scrapSize, 'TEXT', *textOfClip);
5052#endif
5053 HUnlock(textOfClip);
5054 DisposeHandle(textOfClip);
5055 }
5056
5057 vim_free(str);
5058}
5059
5060 void
5061gui_mch_set_text_area_pos(x, y, w, h)
5062 int x;
5063 int y;
5064 int w;
5065 int h;
5066{
5067 Rect VimBound;
5068
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005069/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005070#ifdef USE_CARBONIZED
5071 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
5072#else
5073 VimBound = gui.VimWindow->portRect;
5074#endif
5075
5076 if (gui.which_scrollbars[SBAR_LEFT])
5077 {
5078 VimBound.left = -gui.scrollbar_width + 1;
5079 }
5080 else
5081 {
5082 VimBound.left = 0;
5083 }
5084
5085#ifdef USE_CARBONIZED
5086 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
5087#endif
5088
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005089 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090}
5091
5092/*
5093 * Menu stuff.
5094 */
5095
5096 void
5097gui_mch_enable_menu(flag)
5098 int flag;
5099{
5100 /*
5101 * Menu is always active in itself
5102 * (maybe we should only disable a vim menu
5103 * and keep standard menu)
5104 *
5105 */
5106}
5107
5108 void
5109gui_mch_set_menu_pos(x, y, w, h)
5110 int x;
5111 int y;
5112 int w;
5113 int h;
5114{
5115 /*
5116 * The menu is always at the top of the screen
5117 * Maybe a futur version will permit a menu in the window
5118 *
5119 */
5120}
5121
5122/*
5123 * Add a sub menu to the menu bar.
5124 */
5125 void
5126gui_mch_add_menu(menu, idx)
5127 vimmenu_T *menu;
5128 int idx;
5129{
5130 /*
5131 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
5132 * TODO: use menu->mnemonic and menu->actext
5133 * TODO: Try to reuse menu id
5134 * Carbon Help suggest to use only id between 1 and 235
5135 */
5136 static long next_avail_id = 128;
5137 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005138#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5139 CFStringRef name;
5140#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005142#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 short index;
5144 vimmenu_T *parent = menu->parent;
5145 vimmenu_T *brother = menu->next;
5146
5147 /* Cannot add a menu if ... */
5148 if ((parent != NULL && parent->submenu_id == 0))
5149 return;
5150
5151 /* menu ID greater than 1024 are reserved for ??? */
5152 if (next_avail_id == 1024)
5153 return;
5154
5155 /* My brother could be the PopUp, find my real brother */
5156 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
5157 brother = brother->next;
5158
5159 /* Find where to insert the menu (for MenuBar) */
5160 if ((parent == NULL) && (brother != NULL))
5161 menu_after_me = brother->submenu_id;
5162
5163 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
5164 if (!menu_is_menubar(menu->name))
5165 menu_after_me = hierMenu;
5166
5167 /* Convert the name */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005168#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5169 name = menu_title_removing_mnemonic(menu);
5170#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005172#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173 if (name == NULL)
5174 return;
5175
5176 /* Create the menu unless it's the help menu */
5177#ifdef USE_HELPMENU
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005178#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5179 if (menu->priority == 9999)
5180#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181 if (STRNCMP(name, "\4Help", 5) == 0)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005182#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183 {
5184 menu->submenu_id = kHMHelpMenuID;
5185 menu->submenu_handle = gui.MacOSHelpMenu;
5186 }
5187 else
5188#endif
5189 {
5190 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005191 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
5192 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193 */
5194 menu->submenu_id = next_avail_id;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005195#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5196 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
5197 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
5198#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005199 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005200#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 next_avail_id++;
5202 }
5203
5204 if (parent == NULL)
5205 {
5206 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
5207
5208 /* TODO: Verify if we could only Insert Menu if really part of the
5209 * menubar The Inserted menu are scanned or the Command-key combos
5210 */
5211
5212 /* Insert the menu unless it's the Help menu */
5213#ifdef USE_HELPMENU
5214 if (menu->submenu_id != kHMHelpMenuID)
5215#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005216 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217#if 1
5218 /* Vim should normally update it. TODO: verify */
5219 DrawMenuBar();
5220#endif
5221 }
5222 else
5223 {
5224 /* Adding as a submenu */
5225
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005226 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227
5228 /* Call InsertMenuItem followed by SetMenuItemText
5229 * to avoid special character recognition by InsertMenuItem
5230 */
5231 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005232#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5233 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5234#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005236#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
5238 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
5239 InsertMenu(menu->submenu_handle, hierMenu);
5240 }
5241
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005242#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5243 CFRelease(name);
5244#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005245 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005246#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247
5248#if 0
5249 /* Done by Vim later on */
5250 DrawMenuBar();
5251#endif
5252}
5253
5254/*
5255 * Add a menu item to a menu
5256 */
5257 void
5258gui_mch_add_menu_item(menu, idx)
5259 vimmenu_T *menu;
5260 int idx;
5261{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005262#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5263 CFStringRef name;
5264#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005265 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005266#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267 vimmenu_T *parent = menu->parent;
5268 int menu_inserted;
5269
5270 /* Cannot add item, if the menu have not been created */
5271 if (parent->submenu_id == 0)
5272 return;
5273
5274 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
5275 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
5276
5277 /* Convert the name */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005278#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5279 name = menu_title_removing_mnemonic(menu);
5280#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005281 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005282#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283
5284 /* Where are just a menu item, so no handle, no id */
5285 menu->submenu_id = 0;
5286 menu->submenu_handle = NULL;
5287
5288#ifdef USE_HELPMENU
5289 /* The index in the help menu are offseted */
5290 if (parent->submenu_id == kHMHelpMenuID)
5291 idx += gui.MacOSHelpItems;
5292#endif
5293
5294 menu_inserted = 0;
5295 if (menu->actext)
5296 {
5297 /* If the accelerator text for the menu item looks like it describes
5298 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
5299 * item's command equivalent.
5300 */
5301 int key = 0;
5302 int modifiers = 0;
5303 char_u *p_actext;
5304
5305 p_actext = menu->actext;
5306 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
5307 if (*p_actext != 0)
5308 key = 0; /* error: trailing text */
5309 /* find_special_key() returns a keycode with as many of the
5310 * specified modifiers as appropriate already applied (e.g., for
5311 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
5312 * as the only modifier). Since we want to display all of the
5313 * modifiers, we need to convert the keycode back to a printable
5314 * character plus modifiers.
5315 * TODO: Write an alternative find_special_key() that doesn't
5316 * apply modifiers.
5317 */
5318 if (key > 0 && key < 32)
5319 {
5320 /* Convert a control key to an uppercase letter. Note that
5321 * by this point it is no longer possible to distinguish
5322 * between, e.g., Ctrl-S and Ctrl-Shift-S.
5323 */
5324 modifiers |= MOD_MASK_CTRL;
5325 key += '@';
5326 }
5327 /* If the keycode is an uppercase letter, set the Shift modifier.
5328 * If it is a lowercase letter, don't set the modifier, but convert
5329 * the letter to uppercase for display in the menu.
5330 */
5331 else if (key >= 'A' && key <= 'Z')
5332 modifiers |= MOD_MASK_SHIFT;
5333 else if (key >= 'a' && key <= 'z')
5334 key += 'A' - 'a';
5335 /* Note: keycodes below 0x22 are reserved by Apple. */
5336 if (key >= 0x22 && vim_isprintc_strict(key))
5337 {
5338 int valid = 1;
5339 char_u mac_mods = kMenuNoModifiers;
5340 /* Convert Vim modifier codes to Menu Manager equivalents. */
5341 if (modifiers & MOD_MASK_SHIFT)
5342 mac_mods |= kMenuShiftModifier;
5343 if (modifiers & MOD_MASK_CTRL)
5344 mac_mods |= kMenuControlModifier;
5345 if (!(modifiers & MOD_MASK_CMD))
5346 mac_mods |= kMenuNoCommandModifier;
5347 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5348 valid = 0; /* TODO: will Alt someday map to Option? */
5349 if (valid)
5350 {
5351 char_u item_txt[10];
5352 /* Insert the menu item after idx, with its command key. */
5353 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5354 item_txt[3] = key;
5355 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5356 /* Set the modifier keys. */
5357 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5358 menu_inserted = 1;
5359 }
5360 }
5361 }
5362 /* Call InsertMenuItem followed by SetMenuItemText
5363 * to avoid special character recognition by InsertMenuItem
5364 */
5365 if (!menu_inserted)
5366 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5367 /* Set the menu item name. */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005368#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5369 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5370#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005372#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373
5374#if 0
5375 /* Called by Vim */
5376 DrawMenuBar();
5377#endif
5378
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005379#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
5380 CFRelease(name);
5381#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382 /* TODO: Can name be freed? */
5383 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005384#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005385}
5386
5387 void
5388gui_mch_toggle_tearoffs(enable)
5389 int enable;
5390{
5391 /* no tearoff menus */
5392}
5393
5394/*
5395 * Destroy the machine specific menu widget.
5396 */
5397 void
5398gui_mch_destroy_menu(menu)
5399 vimmenu_T *menu;
5400{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005401 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005402
5403 if (index > 0)
5404 {
5405 if (menu->parent)
5406 {
5407#ifdef USE_HELPMENU
5408 if (menu->parent->submenu_handle != nil) /*gui.MacOSHelpMenu)*/
5409#endif
5410 {
5411 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005412 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005413
5414 /* Delete the Menu if it was a hierarchical Menu */
5415 if (menu->submenu_id != 0)
5416 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005417 DeleteMenu(menu->submenu_id);
5418 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419 }
5420 }
5421#ifdef USE_HELPMENU
5422# ifdef DEBUG_MAC_MENU
5423 else
5424 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005425 printf("gmdm 1\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005426 }
5427# endif
5428#endif
5429 }
5430#ifdef DEBUG_MAC_MENU
5431 else
5432 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005433 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005434 }
5435#endif
5436 }
5437 else
5438 {
5439 /* Do not delete the Help Menu */
5440#ifdef USE_HELPMENU
5441 if (menu->submenu_id != kHMHelpMenuID)
5442#endif
5443 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005444 DeleteMenu(menu->submenu_id);
5445 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 }
5447 }
5448 /* Shouldn't this be already done by Vim. TODO: Check */
5449 DrawMenuBar();
5450}
5451
5452/*
5453 * Make a menu either grey or not grey.
5454 */
5455 void
5456gui_mch_menu_grey(menu, grey)
5457 vimmenu_T *menu;
5458 int grey;
5459{
5460 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005461 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005462/*
5463 index = menu->index;
5464*/
5465 if (grey)
5466 {
5467 if (menu->children)
5468 DisableMenuItem(menu->submenu_handle, index);
5469 if (menu->parent)
5470 if (menu->parent->submenu_handle)
5471 DisableMenuItem(menu->parent->submenu_handle, index);
5472 }
5473 else
5474 {
5475 if (menu->children)
5476 EnableMenuItem(menu->submenu_handle, index);
5477 if (menu->parent)
5478 if (menu->parent->submenu_handle)
5479 EnableMenuItem(menu->parent->submenu_handle, index);
5480 }
5481}
5482
5483/*
5484 * Make menu item hidden or not hidden
5485 */
5486 void
5487gui_mch_menu_hidden(menu, hidden)
5488 vimmenu_T *menu;
5489 int hidden;
5490{
5491 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005492 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005493}
5494
5495
5496/*
5497 * This is called after setting all the menus to grey/hidden or not.
5498 */
5499 void
5500gui_mch_draw_menubar()
5501{
5502 DrawMenuBar();
5503}
5504
5505
5506/*
5507 * Scrollbar stuff.
5508 */
5509
5510 void
5511gui_mch_enable_scrollbar(sb, flag)
5512 scrollbar_T *sb;
5513 int flag;
5514{
5515 if (flag)
5516 ShowControl(sb->id);
5517 else
5518 HideControl(sb->id);
5519
5520#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005521 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005522#endif
5523}
5524
5525 void
5526gui_mch_set_scrollbar_thumb(sb, val, size, max)
5527 scrollbar_T *sb;
5528 long val;
5529 long size;
5530 long max;
5531{
5532 SetControl32BitMaximum (sb->id, max);
5533 SetControl32BitMinimum (sb->id, 0);
5534 SetControl32BitValue (sb->id, val);
5535#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005536 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005537#endif
5538}
5539
5540 void
5541gui_mch_set_scrollbar_pos(sb, x, y, w, h)
5542 scrollbar_T *sb;
5543 int x;
5544 int y;
5545 int w;
5546 int h;
5547{
5548 gui_mch_set_bg_color(gui.back_pixel);
5549/* if (gui.which_scrollbars[SBAR_LEFT])
5550 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005551 MoveControl(sb->id, x-16, y);
5552 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005553 }
5554 else
5555 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005556 MoveControl(sb->id, x, y);
5557 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005558 }*/
5559 if (sb == &gui.bottom_sbar)
5560 h += 1;
5561 else
5562 w += 1;
5563
5564 if (gui.which_scrollbars[SBAR_LEFT])
5565 x -= 15;
5566
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005567 MoveControl(sb->id, x, y);
5568 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005569#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005570 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571#endif
5572}
5573
5574 void
5575gui_mch_create_scrollbar(sb, orient)
5576 scrollbar_T *sb;
5577 int orient; /* SBAR_VERT or SBAR_HORIZ */
5578{
5579 Rect bounds;
5580
5581 bounds.top = -16;
5582 bounds.bottom = -10;
5583 bounds.right = -10;
5584 bounds.left = -16;
5585
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005586 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587 &bounds,
5588 "\pScrollBar",
5589 TRUE,
5590 0, /* current*/
5591 0, /* top */
5592 0, /* bottom */
5593#ifdef USE_CARBONIZED
5594 kControlScrollBarLiveProc,
5595#else
5596 scrollBarProc,
5597#endif
5598 (long) sb->ident);
5599#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005600 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005601#endif
5602}
5603
5604 void
5605gui_mch_destroy_scrollbar(sb)
5606 scrollbar_T *sb;
5607{
5608 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005609 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005610#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005611 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612#endif
5613}
5614
5615
5616/*
5617 * Cursor blink functions.
5618 *
5619 * This is a simple state machine:
5620 * BLINK_NONE not blinking at all
5621 * BLINK_OFF blinking, cursor is not shown
5622 * BLINK_ON blinking, cursor is shown
5623 */
5624 void
5625gui_mch_set_blinking(long wait, long on, long off)
5626{
5627 /* TODO: TODO: TODO: TODO: */
5628/* blink_waittime = wait;
5629 blink_ontime = on;
5630 blink_offtime = off;*/
5631}
5632
5633/*
5634 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5635 */
5636 void
5637gui_mch_stop_blink()
5638{
5639 gui_update_cursor(TRUE, FALSE);
5640 /* TODO: TODO: TODO: TODO: */
5641/* gui_w32_rm_blink_timer();
5642 if (blink_state == BLINK_OFF)
5643 gui_update_cursor(TRUE, FALSE);
5644 blink_state = BLINK_NONE;*/
5645}
5646
5647/*
5648 * Start the cursor blinking. If it was already blinking, this restarts the
5649 * waiting time and shows the cursor.
5650 */
5651 void
5652gui_mch_start_blink()
5653{
5654 gui_update_cursor(TRUE, FALSE);
5655 /* TODO: TODO: TODO: TODO: */
5656/* gui_w32_rm_blink_timer(); */
5657
5658 /* Only switch blinking on if none of the times is zero */
5659/* if (blink_waittime && blink_ontime && blink_offtime)
5660 {
5661 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5662 (TIMERPROC)_OnBlinkTimer);
5663 blink_state = BLINK_ON;
5664 gui_update_cursor(TRUE, FALSE);
5665 }*/
5666}
5667
5668/*
5669 * Return the RGB value of a pixel as long.
5670 */
5671 long_u
5672gui_mch_get_rgb(guicolor_T pixel)
5673{
5674 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5675}
5676
5677
5678
5679#ifdef FEAT_BROWSE
5680/*
5681 * Pop open a file browser and return the file selected, in allocated memory,
5682 * or NULL if Cancel is hit.
5683 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5684 * title - Title message for the file browser dialog.
5685 * dflt - Default name of file.
5686 * ext - Default extension to be added to files without extensions.
5687 * initdir - directory in which to open the browser (NULL = current dir)
5688 * filter - Filter for matched files to choose from.
5689 * Has a format like this:
5690 * "C Files (*.c)\0*.c\0"
5691 * "All Files\0*.*\0\0"
5692 * If these two strings were concatenated, then a choice of two file
5693 * filters will be selectable to the user. Then only matching files will
5694 * be shown in the browser. If NULL, the default allows all files.
5695 *
5696 * *NOTE* - the filter string must be terminated with TWO nulls.
5697 */
5698 char_u *
5699gui_mch_browse(
5700 int saving,
5701 char_u *title,
5702 char_u *dflt,
5703 char_u *ext,
5704 char_u *initdir,
5705 char_u *filter)
5706{
5707#if defined (USE_NAVIGATION_SERVICE) || defined (USE_CARBONIZED)
5708 /* TODO: Add Ammon's safety checl (Dany) */
5709 NavReplyRecord reply;
5710 char_u *fname = NULL;
5711 char_u **fnames = NULL;
5712 long numFiles;
5713 NavDialogOptions navOptions;
5714 OSErr error;
5715
5716 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005717 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005718
5719
5720 /* TODO: If we get a :browse args, set the Multiple bit. */
5721 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5722 | kNavDontAutoTranslate
5723 | kNavDontAddTranslateItems
5724 /* | kNavAllowMultipleFiles */
5725 | kNavAllowStationery;
5726
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005727 (void) C2PascalString(title, &navOptions.message);
5728 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729 /* Could set clientName?
5730 * windowTitle? (there's no title bar?)
5731 */
5732
5733 if (saving)
5734 {
5735 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005736 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737 if (!reply.validRecord)
5738 return NULL;
5739 }
5740 else
5741 {
5742 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5743 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5744 if (!reply.validRecord)
5745 return NULL;
5746 }
5747
5748 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5749
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005750 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751
5752 if (fnames)
5753 {
5754 fname = fnames[0];
5755 vim_free(fnames);
5756 }
5757
5758 /* TODO: Shorten the file name if possible */
5759 return fname;
5760#else
5761 SFTypeList fileTypes;
5762 StandardFileReply reply;
5763 Str255 Prompt;
5764 Str255 DefaultName;
5765 Str255 Directory;
5766
5767 /* TODO: split dflt in path and filename */
5768
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005769 (void) C2PascalString(title, &Prompt);
5770 (void) C2PascalString(dflt, &DefaultName);
5771 (void) C2PascalString(initdir, &Directory);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005772
5773 if (saving)
5774 {
5775 /* Use a custon filter instead of nil FAQ 9-4 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005776 StandardPutFile(Prompt, DefaultName, &reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005777 if (!reply.sfGood)
5778 return NULL;
5779 }
5780 else
5781 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005782 StandardGetFile(nil, -1, fileTypes, &reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783 if (!reply.sfGood)
5784 return NULL;
5785 }
5786
5787 /* Work fine but append a : for new file */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005788 return (FullPathFromFSSpec_save(reply.sfFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005789
5790 /* Shorten the file name if possible */
5791/* mch_dirname(IObuff, IOSIZE);
5792 p = shorten_fname(fileBuf, IObuff);
5793 if (p == NULL)
5794 p = fileBuf;
5795 return vim_strsave(p);
5796*/
5797#endif
5798}
5799#endif /* FEAT_BROWSE */
5800
5801#ifdef FEAT_GUI_DIALOG
5802/*
5803 * Stuff for dialogues
5804 */
5805
5806/*
5807 * Create a dialogue dynamically from the parameter strings.
5808 * type = type of dialogue (question, alert, etc.)
5809 * title = dialogue title. may be NULL for default title.
5810 * message = text to display. Dialogue sizes to accommodate it.
5811 * buttons = '\n' separated list of button captions, default first.
5812 * dfltbutton = number of default button.
5813 *
5814 * This routine returns 1 if the first button is pressed,
5815 * 2 for the second, etc.
5816 *
5817 * 0 indicates Esc was pressed.
5818 * -1 for unexpected error
5819 *
5820 * If stubbing out this fn, return 1.
5821 */
5822
5823typedef struct
5824{
5825 short idx;
5826 short width; /* Size of the text in pixel */
5827 Rect box;
5828} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5829
5830#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5831
5832 static void
5833macMoveDialogItem(
5834 DialogRef theDialog,
5835 short itemNumber,
5836 short X,
5837 short Y,
5838 Rect *inBox)
5839{
5840#if 0 /* USE_CARBONIZED */
5841 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005842 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005844 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845#else
5846 short itemType;
5847 Handle itemHandle;
5848 Rect localBox;
5849 Rect *itemBox = &localBox;
5850
5851 if (inBox != nil)
5852 itemBox = inBox;
5853
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005854 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5855 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5856 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857 /* To move a control (like a button) we need to call both
5858 * MoveControl and SetDialogItem. FAQ 6-18 */
5859 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005860 MoveControl((ControlRef) itemHandle, X, Y);
5861 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005862#endif
5863}
5864
5865 static void
5866macSizeDialogItem(
5867 DialogRef theDialog,
5868 short itemNumber,
5869 short width,
5870 short height)
5871{
5872 short itemType;
5873 Handle itemHandle;
5874 Rect itemBox;
5875
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005876 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877
5878 /* When width or height is zero do not change it */
5879 if (width == 0)
5880 width = itemBox.right - itemBox.left;
5881 if (height == 0)
5882 height = itemBox.bottom - itemBox.top;
5883
5884#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005885 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886#else
5887 /* Resize the bounding box */
5888 itemBox.right = itemBox.left + width;
5889 itemBox.bottom = itemBox.top + height;
5890
5891 /* To resize a control (like a button) we need to call both
5892 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5893 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005894 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895
5896 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005897 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005898#endif
5899}
5900
5901 static void
5902macSetDialogItemText(
5903 DialogRef theDialog,
5904 short itemNumber,
5905 Str255 itemName)
5906{
5907 short itemType;
5908 Handle itemHandle;
5909 Rect itemBox;
5910
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005911 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912
5913 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005914 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005916 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005917}
5918
5919 int
5920gui_mch_dialog(
5921 int type,
5922 char_u *title,
5923 char_u *message,
5924 char_u *buttons,
5925 int dfltbutton,
5926 char_u *textfield)
5927{
5928 Handle buttonDITL;
5929 Handle iconDITL;
5930 Handle inputDITL;
5931 Handle messageDITL;
5932 Handle itemHandle;
5933 Handle iconHandle;
5934 DialogPtr theDialog;
5935 char_u len;
5936 char_u PascalTitle[256]; /* place holder for the title */
5937 char_u name[256];
5938 GrafPtr oldPort;
5939 short itemHit;
5940 char_u *buttonChar;
5941 Rect box;
5942 short button;
5943 short lastButton;
5944 short itemType;
5945 short useIcon;
5946 short width;
5947 short totalButtonWidth = 0; /* the width of all button together incuding spacing */
5948 short widestButton = 0;
5949 short dfltButtonEdge = 20; /* gut feeling */
5950 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5951 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5952 short maximumWidth = 400; /* gut feeling */
5953 short maxButtonWidth = 175; /* gut feeling */
5954
5955 short vertical;
5956 short dialogHeight;
5957 short messageLines = 3;
5958 FontInfo textFontInfo;
5959
5960 vgmDlgItm iconItm;
5961 vgmDlgItm messageItm;
5962 vgmDlgItm inputItm;
5963 vgmDlgItm buttonItm;
5964
5965 WindowRef theWindow;
5966
5967 /* Check 'v' flag in 'guioptions': vertical button placement. */
5968 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5969
5970 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005971 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005972
5973 /* Get the WindowRef */
5974 theWindow = GetDialogWindow(theDialog);
5975
5976 /* Hide the window.
5977 * 1. to avoid seeing slow drawing
5978 * 2. to prevent a problem seen while moving dialog item
5979 * within a visible window. (non-Carbon MacOS 9)
5980 * Could be avoided by changing the resource.
5981 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005982 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005983
5984 /* Change the graphical port to the dialog,
5985 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005986 GetPort(&oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005988 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005989#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005990 SetPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991#endif
5992
5993 /* Get the info about the default text,
5994 * used to calculate the height of the message
5995 * and of the text field */
5996 GetFontInfo(&textFontInfo);
5997
5998 /* Set the dialog title */
5999 if (title != NULL)
6000 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006001 (void) C2PascalString(title, &PascalTitle);
6002 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003 }
6004
6005 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006006 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006007 buttonChar = buttons;
6008 button = 0;
6009
6010 for (;*buttonChar != 0;)
6011 {
6012 /* Get the name of the button */
6013 button++;
6014 len = 0;
6015 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
6016 {
6017 if (*buttonChar != DLG_HOTKEY_CHAR)
6018 name[++len] = *buttonChar;
6019 }
6020 if (*buttonChar != 0)
6021 buttonChar++;
6022 name[0] = len;
6023
6024 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006025 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006026
6027 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006028 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006029
6030 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006031 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 /* Limite the size of any button to an acceptable value. */
6033 /* TODO: Should be based on the message width */
6034 if (width > maxButtonWidth)
6035 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006036 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006037
6038 totalButtonWidth += width;
6039
6040 if (width > widestButton)
6041 widestButton = width;
6042 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006043 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 lastButton = button;
6045
6046 /* Add the icon to the Dialog Box. */
6047 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006048 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006049 switch (type)
6050 {
6051 case VIM_GENERIC: useIcon = kNoteIcon;
6052 case VIM_ERROR: useIcon = kStopIcon;
6053 case VIM_WARNING: useIcon = kCautionIcon;
6054 case VIM_INFO: useIcon = kNoteIcon;
6055 case VIM_QUESTION: useIcon = kNoteIcon;
6056 default: useIcon = kStopIcon;
6057 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006058 AppendDITL(theDialog, iconDITL, overlayDITL);
6059 ReleaseResource(iconDITL);
6060 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006062 iconHandle = GetIcon(useIcon);
6063 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064
6065 /* Add the message to the Dialog box. */
6066 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006067 messageDITL = GetResource('DITL', 132);
6068 AppendDITL(theDialog, messageDITL, overlayDITL);
6069 ReleaseResource(messageDITL);
6070 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
6071 (void) C2PascalString(message, &name);
6072 SetDialogItemText(itemHandle, name);
6073 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074
6075 /* Add the input box if needed */
6076 if (textfield != NULL)
6077 {
6078 /* Cheat for now reuse the message and convet to text edit */
6079 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006080 inputDITL = GetResource('DITL', 132);
6081 AppendDITL(theDialog, inputDITL, overlayDITL);
6082 ReleaseResource(inputDITL);
6083 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
6084/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
6085 (void) C2PascalString(textfield, &name);
6086 SetDialogItemText(itemHandle, name);
6087 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006088 }
6089
6090 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006091 SetDialogDefaultItem(theDialog, dfltbutton);
6092 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006093
6094 /* Reposition element */
6095
6096 /* Check if we need to force vertical */
6097 if (totalButtonWidth > maximumWidth)
6098 vertical = TRUE;
6099
6100 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006101 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102 iconItm.box.right = box.right;
6103 iconItm.box.bottom = box.bottom;
6104
6105 /* Place Message */
6106 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006107 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
6108 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006109
6110 /* Place Input */
6111 if (textfield != NULL)
6112 {
6113 inputItm.box.left = messageItm.box.left;
6114 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006115 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
6116 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006117 /* Convert the static text into a text edit.
6118 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006119 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
6120 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
6122 }
6123
6124 /* Place Button */
6125 if (textfield != NULL)
6126 {
6127 buttonItm.box.left = inputItm.box.left;
6128 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
6129 }
6130 else
6131 {
6132 buttonItm.box.left = messageItm.box.left;
6133 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
6134 }
6135
6136 for (button=1; button <= lastButton; button++)
6137 {
6138
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006139 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 /* With vertical, it's better to have all button the same lenght */
6141 if (vertical)
6142 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006143 macSizeDialogItem(theDialog, button, widestButton, 0);
6144 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006145 }
6146 /* Calculate position of next button */
6147 if (vertical)
6148 buttonItm.box.top = box.bottom + dfltElementSpacing;
6149 else
6150 buttonItm.box.left = box.right + dfltElementSpacing;
6151 }
6152
6153 /* Resize the dialog box */
6154 dialogHeight = box.bottom + dfltElementSpacing;
6155 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
6156
6157#ifdef USE_CARBONIZED
6158 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006159 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160 /* Need a horizontal resize anyway so not that useful */
6161#endif
6162
6163 /* Display it */
6164 ShowWindow(theWindow);
6165/* BringToFront(theWindow); */
6166 SelectWindow(theWindow);
6167
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006168/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006169#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006170 GetPort(&oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171#ifdef USE_CARBONIZED
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006172 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006174 SetPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006175#endif
6176#endif
6177
6178 /* Hang until one of the button is hit */
6179 do
6180 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006181 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006182 } while ((itemHit < 1) || (itemHit > lastButton));
6183
6184 /* Copy back the text entered by the user into the param */
6185 if (textfield != NULL)
6186 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006187 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
6188 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006189#if IOSIZE < 256
6190 /* Truncate the name to IOSIZE if needed */
6191 if (name[0] > IOSIZE)
6192 name[0] = IOSIZE - 1;
6193#endif
6194 STRNCPY(textfield, &name[1], name[0]);
6195 textfield[name[0]] = NUL;
6196 }
6197
6198 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006199 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200
6201 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006202 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203
6204 return itemHit;
6205/*
6206 * Usefull thing which could be used
6207 * SetDialogTimeout(): Auto click a button after timeout
6208 * SetDialogTracksCursor() : Get the I-beam cursor over input box
6209 * MoveDialogItem(): Probably better than SetDialogItem
6210 * SizeDialogItem(): (but is it Carbon Only?)
6211 * AutoSizeDialog(): Magic resize of dialog based on text lenght
6212 */
6213}
6214#endif /* FEAT_DIALOG_GUI */
6215
6216/*
6217 * Display the saved error message(s).
6218 */
6219#ifdef USE_MCH_ERRMSG
6220 void
6221display_errors()
6222{
6223 char *p;
6224 char_u pError[256];
6225
6226 if (error_ga.ga_data != NULL)
6227 {
6228 /* avoid putting up a message box with blanks only */
6229 for (p = (char *)error_ga.ga_data; *p; ++p)
6230 if (!isspace(*p))
6231 {
6232 if (STRLEN(p) > 255)
6233 pError[0] = 255;
6234 else
6235 pError[0] = STRLEN(p);
6236
6237 STRNCPY(&pError[1], p, pError[0]);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006238 ParamText(pError, nil, nil, nil);
6239 Alert(128, nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006240 break;
6241 /* TODO: handled message longer than 256 chars
6242 * use auto-sizeable alert
6243 * or dialog with scrollbars (TextEdit zone)
6244 */
6245 }
6246 ga_clear(&error_ga);
6247 }
6248}
6249#endif
6250
6251/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00006252 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00006254 void
6255gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256{
6257 Point where;
6258
6259 GetMouse(&where);
6260
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00006261 *x = where.h;
6262 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006263}
6264
6265 void
6266gui_mch_setmouse(x, y)
6267 int x;
6268 int y;
6269{
6270 /* TODO */
6271#if 0
6272 /* From FAQ 3-11 */
6273
6274 CursorDevicePtr myMouse;
6275 Point where;
6276
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006277 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
6278 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006279 {
6280 /* New way */
6281
6282 /*
6283 * Get first devoice with one button.
6284 * This will probably be the standad mouse
6285 * startat head of cursor dev list
6286 *
6287 */
6288
6289 myMouse = nil;
6290
6291 do
6292 {
6293 /* Get the next cursor device */
6294 CursorDeviceNextDevice(&myMouse);
6295 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006296 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006297
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006298 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 }
6300 else
6301 {
6302 /* Old way */
6303 where.h = x;
6304 where.v = y;
6305
6306 *(Point *)RawMouse = where;
6307 *(Point *)MTemp = where;
6308 *(Ptr) CrsrNew = 0xFFFF;
6309 }
6310#endif
6311}
6312
6313 void
6314gui_mch_show_popupmenu(menu)
6315 vimmenu_T *menu;
6316{
6317#ifdef USE_CTRLCLICKMENU
6318/*
6319 * Clone PopUp to use menu
6320 * Create a object descriptor for the current selection
6321 * Call the procedure
6322 */
6323
6324 MenuHandle CntxMenu;
6325 Point where;
6326 OSStatus status;
6327 UInt32 CntxType;
6328 SInt16 CntxMenuID;
6329 UInt16 CntxMenuItem;
6330 Str255 HelpName = "";
6331 GrafPtr savePort;
6332
6333 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006334 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006336 GetMouse(&where);
6337 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006338 CntxMenu = menu->submenu_handle;
6339
6340 /* TODO: Get the text selection from Vim */
6341
6342 /* Call to Handle Popup */
6343 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemNoHelp, HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
6344
6345 if (status == noErr)
6346 {
6347 if (CntxType == kCMMenuItemSelected)
6348 {
6349 /* Handle the menu CntxMenuID, CntxMenuItem */
6350 /* The submenu can be handle directly by gui_mac_handle_menu */
6351 /* But what about the current menu, is the menu changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006352 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353 }
6354 else if (CntxMenuID == kCMShowHelpSelected)
6355 {
6356 /* Should come up with the help */
6357 }
6358 }
6359
6360 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006361 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006362#endif
6363}
6364
6365#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6366/* TODO: Is it need for MACOS_X? (Dany) */
6367 void
6368mch_post_buffer_write(buf_T *buf)
6369{
6370# ifdef USE_SIOUX
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006371 printf("Writing Buf...\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006372# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006373 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6374 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006375}
6376#endif
6377
6378#ifdef FEAT_TITLE
6379/*
6380 * Set the window title and icon.
6381 * (The icon is not taken care of).
6382 */
6383 void
6384gui_mch_settitle(title, icon)
6385 char_u *title;
6386 char_u *icon;
6387{
6388 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6389 * that 256. Even better get it to fit nicely in the titlebar.
6390 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006391#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
6392 CFStringRef windowTitle;
6393 size_t windowTitleLen;
6394#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006395 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006396#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006397
6398 if (title == NULL) /* nothing to do */
6399 return;
6400
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006401#if defined(USE_CARBONIZED) && defined(FEAT_MBYTE)
6402 windowTitleLen = STRLEN(title);
6403 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
6404
6405 if (windowTitle)
6406 {
6407 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6408 CFRelease(windowTitle);
6409 }
6410#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006411 pascalTitle = C2Pascal_save(title);
6412 if (pascalTitle != NULL)
6413 {
6414 SetWTitle(gui.VimWindow, pascalTitle);
6415 vim_free(pascalTitle);
6416 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006418}
6419#endif
6420
6421/*
6422 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6423 */
6424
6425 int
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006426C2PascalString(CString, PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006427 char_u *CString;
6428 Str255 *PascalString;
6429{
6430 char_u *PascalPtr = (char_u *) PascalString;
6431 int len;
6432 int i;
6433
6434 PascalPtr[0] = 0;
6435 if (CString == NULL)
6436 return 0;
6437
6438 len = STRLEN(CString);
6439 if (len > 255)
6440 len = 255;
6441
6442 for (i = 0; i < len; i++)
6443 PascalPtr[i+1] = CString[i];
6444
6445 PascalPtr[0] = len;
6446
6447 return 0;
6448}
6449
6450 int
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006451GetFSSpecFromPath(file, fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006452 char_u *file;
6453 FSSpec *fileFSSpec;
6454{
6455 /* From FAQ 8-12 */
6456 Str255 filePascal;
6457 CInfoPBRec myCPB;
6458 OSErr err;
6459
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006460 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006461
6462 myCPB.dirInfo.ioNamePtr = filePascal;
6463 myCPB.dirInfo.ioVRefNum = 0;
6464 myCPB.dirInfo.ioFDirIndex = 0;
6465 myCPB.dirInfo.ioDrDirID = 0;
6466
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006467 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006468
6469 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006470 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006471
6472 /* TODO: Use an error code mechanism */
6473 return 0;
6474}
6475
6476/*
6477 * Convert a FSSpec to a fuill path
6478 */
6479
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006480char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006481{
6482 /*
6483 * TODO: Add protection for 256 char max.
6484 */
6485
6486 CInfoPBRec theCPB;
6487 char_u fname[256];
6488 char_u *filenamePtr = fname;
6489 OSErr error;
6490 int folder = 1;
6491#ifdef USE_UNIXFILENAME
6492 SInt16 dfltVol_vRefNum;
6493 SInt32 dfltVol_dirID;
6494 FSRef refFile;
6495 OSStatus status;
6496 UInt32 pathSize = 256;
6497 char_u pathname[256];
6498 char_u *path = pathname;
6499#else
6500 Str255 directoryName;
6501 char_u temporary[255];
6502 char_u *temporaryPtr = temporary;
6503#endif
6504
6505#ifdef USE_UNIXFILENAME
6506 /* Get the default volume */
6507 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006508 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006509
6510 if (error)
6511 return NULL;
6512#endif
6513
6514 /* Start filling fname with file.name */
6515 STRNCPY(filenamePtr, &file.name[1], file.name[0]);
6516 filenamePtr[file.name[0]] = 0; /* NULL terminate the string */
6517
6518 /* Get the info about the file specified in FSSpec */
6519 theCPB.dirInfo.ioFDirIndex = 0;
6520 theCPB.dirInfo.ioNamePtr = file.name;
6521 theCPB.dirInfo.ioVRefNum = file.vRefNum;
6522 /*theCPB.hFileInfo.ioDirID = 0;*/
6523 theCPB.dirInfo.ioDrDirID = file.parID;
6524
6525 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6526 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006527 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006528
6529 /* If we are called for a new file we expect fnfErr */
6530 if ((error) && (error != fnfErr))
6531 return NULL;
6532
6533 /* Check if it's a file or folder */
6534 /* default to file if file don't exist */
6535 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6536 folder = 0; /* It's not a folder */
6537 else
6538 folder = 1;
6539
6540#ifdef USE_UNIXFILENAME
6541 /*
6542 * The function used here are available in Carbon, but
6543 * do nothing une MacOS 8 and 9
6544 */
6545 if (error == fnfErr)
6546 {
6547 /* If the file to be saved does not already exist, it isn't possible
6548 to convert its FSSpec into an FSRef. But we can construct an
6549 FSSpec for the file's parent folder (since we have its volume and
6550 directory IDs), and since that folder does exist, we can convert
6551 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6552 and, finally, append the filename. */
6553 FSSpec dirSpec;
6554 FSRef dirRef;
6555 Str255 emptyFilename = "\p";
6556 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6557 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6558 if (error)
6559 return NULL;
6560
6561 error = FSpMakeFSRef(&dirSpec, &dirRef);
6562 if (error)
6563 return NULL;
6564
6565 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6566 if (status)
6567 return NULL;
6568
6569 STRCAT(path, "/");
6570 STRCAT(path, filenamePtr);
6571 }
6572 else
6573 {
6574 /* If the file to be saved already exists, we can get its full path
6575 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006576 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577 if (error)
6578 return NULL;
6579
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006580 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006581 if (status)
6582 return NULL;
6583 }
6584
6585 /* Add a slash at the end if needed */
6586 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006587 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006588
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006589 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006590#else
6591 /* TODO: Get rid of all USE_UNIXFILENAME below */
6592 /* Set ioNamePtr, it's the same area which is always reused. */
6593 theCPB.dirInfo.ioNamePtr = directoryName;
6594
6595 /* Trick for first entry, set ioDrParID to the first value
6596 * we want for ioDrDirID*/
6597 theCPB.dirInfo.ioDrParID = file.parID;
6598 theCPB.dirInfo.ioDrDirID = file.parID;
6599
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006600 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006601 do
6602 {
6603 theCPB.dirInfo.ioFDirIndex = -1;
6604 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6605 theCPB.dirInfo.ioVRefNum = file.vRefNum;
6606 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
6607 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6608
6609 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6610 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006611 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006612
6613 if (error)
6614 return NULL;
6615
6616 /* Put the new directoryName in front of the current fname */
6617 STRCPY(temporaryPtr, filenamePtr);
6618 STRNCPY(filenamePtr, &directoryName[1], directoryName[0]);
6619 filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */
6620 STRCAT(filenamePtr, ":");
6621 STRCAT(filenamePtr, temporaryPtr);
6622 }
6623#if 1 /* def USE_UNIXFILENAME */
6624 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6625 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6626#else
6627 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6628#endif
6629
6630 /* Get the information about the volume on which the file reside */
6631 theCPB.dirInfo.ioFDirIndex = -1;
6632 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6633 theCPB.dirInfo.ioVRefNum = file.vRefNum;
6634 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
6635 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6636
6637 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6638 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006639 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006640
6641 if (error)
6642 return NULL;
6643
6644 /* For MacOS Classic always add the volume name */
6645 /* For MacOS X add the volume name preceded by "Volumes" */
6646 /* when we are not refering to the boot volume */
6647#ifdef USE_UNIXFILENAME
6648 if (file.vRefNum != dfltVol_vRefNum)
6649#endif
6650 {
6651 /* Add the volume name */
6652 STRCPY(temporaryPtr, filenamePtr);
6653 STRNCPY(filenamePtr, &directoryName[1], directoryName[0]);
6654 filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */
6655 STRCAT(filenamePtr, ":");
6656 STRCAT(filenamePtr, temporaryPtr);
6657
6658#ifdef USE_UNIXFILENAME
6659 STRCPY(temporaryPtr, filenamePtr);
6660 filenamePtr[0] = 0; /* NULL terminate the string */
6661 STRCAT(filenamePtr, "Volumes:");
6662 STRCAT(filenamePtr, temporaryPtr);
6663#endif
6664 }
6665
6666 /* Append final path separator if it's a folder */
6667 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006668 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006669
6670 /* As we use Unix File Name for MacOS X convert it */
6671#ifdef USE_UNIXFILENAME
6672 /* Need to insert leading / */
6673 /* TODO: get the above code to use directly the / */
6674 STRCPY(&temporaryPtr[1], filenamePtr);
6675 temporaryPtr[0] = '/';
6676 STRCPY(filenamePtr, temporaryPtr);
6677 {
6678 char *p;
6679 for (p = fname; *p; p++)
6680 if (*p == ':')
6681 *p = '/';
6682 }
6683#endif
6684
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006685 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006686#endif
6687}
6688
6689#if defined(USE_IM_CONTROL) || defined(PROTO)
6690/*
6691 * Input Method Control functions.
6692 */
6693
6694/*
6695 * Notify cursor position to IM.
6696 */
6697 void
6698im_set_position(int row, int col)
6699{
6700 /* TODO: Implement me! */
6701}
6702
6703/*
6704 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6705 */
6706 void
6707im_set_active(int active)
6708{
6709 KeyScript(active ? smKeySysScript : smKeyRoman);
6710}
6711
6712/*
6713 * Get IM status. When IM is on, return not 0. Else return 0.
6714 */
6715 int
6716im_get_status()
6717{
6718 SInt32 script = GetScriptManagerVariable(smKeyScript);
6719 return (script != smRoman
6720 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6721}
6722#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */