blob: 0acc3dbce4ff70b70cb15408965cd2cff47c10ce [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/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000016 * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x
17 * - Comments mentioning FAQ refer to the book:
18 * "Macworld Mac Programming FAQs" from "IDG Books"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019 */
20
21/*
22 * TODO: Change still to merge from the macvim's iDisk
23 *
24 * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse
25 * uses of MenuItemIndex, changes in gui_mch_set_shellsize,
26 * ScrapManager error handling.
27 * Comments about function remaining to Carbonize.
28 *
29 */
30
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000031 /* TODO (Jussi)
32 * * Clipboard does not work (at least some cases)
33 * * ATSU font rendering has some problems
34 * * Investigate and remove dead code (there is still lots of that)
35 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000036
37#include <Devices.h> /* included first to avoid CR problems */
38#include "vim.h"
39
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000040#define USE_CARBONIZED
41#define USE_AEVENT /* Enable AEVENT */
42#undef USE_OFFSETED_WINDOW /* Debugging feature: start Vim window OFFSETed */
Bram Moolenaar071d4272004-06-13 20:20:40 +000043
44/* Compile as CodeWarior External Editor */
45#if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46# define USE_AEVENT /* Need Apple Event Support */
47#endif
48
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000049/* Vim's Scrap flavor. */
50#define VIMSCRAPFLAVOR 'VIM!'
51
Bram Moolenaar071d4272004-06-13 20:20:40 +000052static EventHandlerUPP mouseWheelHandlerUPP = NULL;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000053SInt32 gMacSystemVersion;
Bram Moolenaar071d4272004-06-13 20:20:40 +000054
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000055#ifdef MACOS_CONVERT
56# define USE_CARBONKEYHANDLER
Bram Moolenaar26a60b42005-02-22 08:49:11 +000057static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +000058#endif
59
Bram Moolenaar071d4272004-06-13 20:20:40 +000060
61/* Include some file. TODO: move into os_mac.h */
62#include <Menus.h>
63#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000064#include <Processes.h>
65#ifdef USE_AEVENT
66# include <AppleEvents.h>
67# include <AERegistry.h>
68#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000069# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000070#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
71# include <ControlDefinitions.h>
72# include <Navigation.h> /* Navigation only part of ?? */
73#endif
74
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000075/* Help Manager (balloon.h, HM prefixed functions) are not supported
76 * under Carbon (Jussi) */
77# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +000078/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000079# include <MacHelp.h>
80# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000081
82/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000083 * These seem to be rectangle options. Why are they not found in
84 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000086#define kNothing 0
87#define kCreateEmpty 2 /*1*/
88#define kCreateRect 2
89#define kDestroy 3
90
91/*
92 * Dany: Don't like those...
93 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000094#define topLeft(r) (((Point*)&(r))[0])
95#define botRight(r) (((Point*)&(r))[1])
96
97
98/* Time of last mouse click, to detect double-click */
99static long lastMouseTick = 0;
100
101/* ??? */
102static RgnHandle cursorRgn;
103static RgnHandle dragRgn;
104static Rect dragRect;
105static short dragRectEnbl;
106static short dragRectControl;
107
108/* This variable is set when waiting for an event, which is the only moment
109 * scrollbar dragging can be done directly. It's not allowed while commands
110 * are executed, because it may move the cursor and that may cause unexpected
111 * problems (e.g., while ":s" is working).
112 */
113static int allow_scrollbar = FALSE;
114
115/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117
118/* Feedback Action for Scrollbar */
119ControlActionUPP gScrollAction;
120ControlActionUPP gScrollDrag;
121
122/* Keeping track of which scrollbar is being dragged */
123static ControlHandle dragged_sb = NULL;
124
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000125static struct
126{
127 FMFontFamily family;
128 FMFontSize size;
129 FMFontStyle style;
130 Boolean isPanelVisible;
131} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000132
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000133#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000134# define USE_ATSUI_DRAWING
135ATSUStyle gFontStyle;
136Boolean gIsFontFallbackSet;
137#endif
138
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139/* Colors Macros */
140#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
141#define Red(c) ((c & 0x00FF0000) >> 16)
142#define Green(c) ((c & 0x0000FF00) >> 8)
143#define Blue(c) ((c & 0x000000FF) >> 0)
144
145/* Key mapping */
146
147#define vk_Esc 0x35 /* -> 1B */
148
149#define vk_F1 0x7A /* -> 10 */
150#define vk_F2 0x78 /*0x63*/
151#define vk_F3 0x63 /*0x76*/
152#define vk_F4 0x76 /*0x60*/
153#define vk_F5 0x60 /*0x61*/
154#define vk_F6 0x61 /*0x62*/
155#define vk_F7 0x62 /*0x63*/ /*?*/
156#define vk_F8 0x64
157#define vk_F9 0x65
158#define vk_F10 0x6D
159#define vk_F11 0x67
160#define vk_F12 0x6F
161#define vk_F13 0x69
162#define vk_F14 0x6B
163#define vk_F15 0x71
164
165#define vk_Clr 0x47 /* -> 1B (ESC) */
166#define vk_Enter 0x4C /* -> 03 */
167
168#define vk_Space 0x31 /* -> 20 */
169#define vk_Tab 0x30 /* -> 09 */
170#define vk_Return 0x24 /* -> 0D */
171/* This is wrong for OSX, what is it for? */
172#define vk_Delete 0X08 /* -> 08 BackSpace */
173
174#define vk_Help 0x72 /* -> 05 */
175#define vk_Home 0x73 /* -> 01 */
176#define vk_PageUp 0x74 /* -> 0D */
177#define vk_FwdDelete 0x75 /* -> 7F */
178#define vk_End 0x77 /* -> 04 */
179#define vk_PageDown 0x79 /* -> 0C */
180
181#define vk_Up 0x7E /* -> 1E */
182#define vk_Down 0x7D /* -> 1F */
183#define vk_Left 0x7B /* -> 1C */
184#define vk_Right 0x7C /* -> 1D */
185
186#define vk_Undo vk_F1
187#define vk_Cut vk_F2
188#define vk_Copy vk_F3
189#define vk_Paste vk_F4
190#define vk_PrintScreen vk_F13
191#define vk_SCrollLock vk_F14
192#define vk_Pause vk_F15
193#define vk_NumLock vk_Clr
194#define vk_Insert vk_Help
195
196#define KeySym char
197
198static struct
199{
200 KeySym key_sym;
201 char_u vim_code0;
202 char_u vim_code1;
203} special_keys[] =
204{
205 {vk_Up, 'k', 'u'},
206 {vk_Down, 'k', 'd'},
207 {vk_Left, 'k', 'l'},
208 {vk_Right, 'k', 'r'},
209
210 {vk_F1, 'k', '1'},
211 {vk_F2, 'k', '2'},
212 {vk_F3, 'k', '3'},
213 {vk_F4, 'k', '4'},
214 {vk_F5, 'k', '5'},
215 {vk_F6, 'k', '6'},
216 {vk_F7, 'k', '7'},
217 {vk_F8, 'k', '8'},
218 {vk_F9, 'k', '9'},
219 {vk_F10, 'k', ';'},
220
221 {vk_F11, 'F', '1'},
222 {vk_F12, 'F', '2'},
223 {vk_F13, 'F', '3'},
224 {vk_F14, 'F', '4'},
225 {vk_F15, 'F', '5'},
226
227/* {XK_Help, '%', '1'}, */
228/* {XK_Undo, '&', '8'}, */
229/* {XK_BackSpace, 'k', 'b'}, */
230#ifndef MACOS_X
231 {vk_Delete, 'k', 'b'},
232#endif
233 {vk_Insert, 'k', 'I'},
234 {vk_FwdDelete, 'k', 'D'},
235 {vk_Home, 'k', 'h'},
236 {vk_End, '@', '7'},
237/* {XK_Prior, 'k', 'P'}, */
238/* {XK_Next, 'k', 'N'}, */
239/* {XK_Print, '%', '9'}, */
240
241 {vk_PageUp, 'k', 'P'},
242 {vk_PageDown, 'k', 'N'},
243
244 /* End of list marker: */
245 {(KeySym)0, 0, 0}
246};
247
248/*
249 * ------------------------------------------------------------
250 * Forward declaration (for those needed)
251 * ------------------------------------------------------------
252 */
253
254#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000255OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000256#endif
257
258/*
259 * ------------------------------------------------------------
260 * Conversion Utility
261 * ------------------------------------------------------------
262 */
263
264/*
265 * C2Pascal_save
266 *
267 * Allocate memory and convert the C-String passed in
268 * into a pascal string
269 *
270 */
271
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000272 char_u *
273C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274{
275 char_u *PascalString;
276 int len;
277
278 if (Cstring == NULL)
279 return NULL;
280
281 len = STRLEN(Cstring);
282
283 if (len > 255) /* Truncate if necessary */
284 len = 255;
285
286 PascalString = alloc(len + 1);
287 if (PascalString != NULL)
288 {
289 mch_memmove(PascalString + 1, Cstring, len);
290 PascalString[0] = len;
291 }
292
293 return PascalString;
294}
295
296/*
297 * C2Pascal_save_and_remove_backslash
298 *
299 * Allocate memory and convert the C-String passed in
300 * into a pascal string. Also remove the backslash at the same time
301 *
302 */
303
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000304 char_u *
305C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306{
307 char_u *PascalString;
308 int len;
309 char_u *p, *c;
310
311 len = STRLEN(Cstring);
312
313 if (len > 255) /* Truncate if necessary */
314 len = 255;
315
316 PascalString = alloc(len + 1);
317 if (PascalString != NULL)
318 {
319 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
320 {
321 if ((*c == '\\') && (c[1] != 0))
322 {
323 c++;
324 }
325 *p = *c;
326 p++;
327 len++;
328 }
329 PascalString[0] = len;
330 }
331
332 return PascalString;
333}
334
335/*
336 * Convert the modifiers of an Event into vim's modifiers (mouse)
337 */
338
339 int_u
340EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
341{
342 int_u vimModifiers = 0x00;
343
344 if (macModifiers & (shiftKey | rightShiftKey))
345 vimModifiers |= MOUSE_SHIFT;
346 if (macModifiers & (controlKey | rightControlKey))
347 vimModifiers |= MOUSE_CTRL;
348 if (macModifiers & (optionKey | rightOptionKey))
349 vimModifiers |= MOUSE_ALT;
350#if 0
351 /* Not yet supported */
352 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
353 vimModifiers |= MOUSE_CMD;
354#endif
355 return (vimModifiers);
356}
357
358/*
359 * Convert the modifiers of an Event into vim's modifiers (keys)
360 */
361
362 static int_u
363EventModifiers2VimModifiers(EventModifiers macModifiers)
364{
365 int_u vimModifiers = 0x00;
366
367 if (macModifiers & (shiftKey | rightShiftKey))
368 vimModifiers |= MOD_MASK_SHIFT;
369 if (macModifiers & (controlKey | rightControlKey))
370 vimModifiers |= MOD_MASK_CTRL;
371 if (macModifiers & (optionKey | rightOptionKey))
372 vimModifiers |= MOD_MASK_ALT;
373#ifdef USE_CMD_KEY
374 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
375 vimModifiers |= MOD_MASK_CMD;
376#endif
377 return (vimModifiers);
378}
379
380/* Convert a string representing a point size into pixels. The string should
381 * be a positive decimal number, with an optional decimal point (eg, "12", or
382 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
383 * character is stored in *end. The flag "vertical" says whether this
384 * calculation is for a vertical (height) size or a horizontal (width) one.
385 *
386 * From gui_w48.c
387 */
388 static int
389points_to_pixels(char_u *str, char_u **end, int vertical)
390{
391 int pixels;
392 int points = 0;
393 int divisor = 0;
394
395 while (*str)
396 {
397 if (*str == '.' && divisor == 0)
398 {
399 /* Start keeping a divisor, for later */
400 divisor = 1;
401 continue;
402 }
403
404 if (!isdigit(*str))
405 break;
406
407 points *= 10;
408 points += *str - '0';
409 divisor *= 10;
410
411 ++str;
412 }
413
414 if (divisor == 0)
415 divisor = 1;
416
417 pixels = points/divisor;
418 *end = str;
419 return pixels;
420}
421
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000422#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000423/*
424 * Deletes all traces of any Windows-style mnemonic text (including any
425 * parentheses) from a menu item and returns the cleaned menu item title.
426 * The caller is responsible for releasing the returned string.
427 */
428 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000429menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000430{
431 CFStringRef name;
432 size_t menuTitleLen;
433 CFIndex displayLen;
434 CFRange mnemonicStart;
435 CFRange mnemonicEnd;
436 CFMutableStringRef cleanedName;
437
438 menuTitleLen = STRLEN(menu->dname);
439 name = mac_enc_to_cfstring(menu->dname, menuTitleLen);
440
441 if (name)
442 {
443 /* Simple mnemonic-removal algorithm, assumes single parenthesized
444 * mnemonic character towards the end of the menu text */
445 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
446 displayLen = CFStringGetLength(name);
447
448 if (mnemonicStart.location != kCFNotFound
449 && (mnemonicStart.location + 2) < displayLen
450 && CFStringGetCharacterAtIndex(name,
451 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
452 {
453 if (CFStringFindWithOptions(name, CFSTR(")"),
454 CFRangeMake(mnemonicStart.location + 1,
455 displayLen - mnemonicStart.location - 1),
456 kCFCompareBackwards, &mnemonicEnd) &&
457 (mnemonicStart.location + 2) == mnemonicEnd.location)
458 {
459 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
460 if (cleanedName)
461 {
462 CFStringDelete(cleanedName,
463 CFRangeMake(mnemonicStart.location,
464 mnemonicEnd.location + 1 -
465 mnemonicStart.location));
466
467 CFRelease(name);
468 name = cleanedName;
469 }
470 }
471 }
472 }
473
474 return name;
475}
476#endif
477
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478/*
479 * Convert a list of FSSpec aliases into a list of fullpathname
480 * character strings.
481 */
482
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000483 char_u **
484new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485{
486 char_u **fnames = NULL;
487 OSErr newError;
488 long fileCount;
489 FSSpec fileToOpen;
490 long actualSize;
491 AEKeyword dummyKeyword;
492 DescType dummyType;
493
494 /* Get number of files in list */
495 *error = AECountItems(theList, numFiles);
496 if (*error)
497 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 return(fnames);
499 }
500
501 /* Allocate the pointer list */
502 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
503
504 /* Empty out the list */
505 for (fileCount = 0; fileCount < *numFiles; fileCount++)
506 fnames[fileCount] = NULL;
507
508 /* Scan the list of FSSpec */
509 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
510 {
511 /* Get the alias for the nth file, convert to an FSSpec */
512 newError = AEGetNthPtr(theList, fileCount, typeFSS,
513 &dummyKeyword, &dummyType,
514 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
515 if (newError)
516 {
517 /* Caller is able to clean up */
518 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 return(fnames);
520 }
521
522 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000523 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524 }
525
526 return (fnames);
527}
528
529/*
530 * ------------------------------------------------------------
531 * CodeWarrior External Editor Support
532 * ------------------------------------------------------------
533 */
534#ifdef FEAT_CW_EDITOR
535
536/*
537 * Handle the Window Search event from CodeWarrior
538 *
539 * Description
540 * -----------
541 *
542 * The IDE sends the Window Search AppleEvent to the editor when it
543 * needs to know whether a particular file is open in the editor.
544 *
545 * Event Reply
546 * -----------
547 *
548 * None. Put data in the location specified in the structure received.
549 *
550 * Remarks
551 * -------
552 *
553 * When the editor receives this event, determine whether the specified
554 * file is open. If it is, return the modification date/time for that file
555 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000556 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 *
558 */
559
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560typedef struct WindowSearch WindowSearch;
561struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
562{
563 FSSpec theFile; // identifies the file
564 long *theDate; // where to put the modification date/time
565};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000567 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000568Handle_KAHL_SRCH_AE(
569 const AppleEvent *theAEvent,
570 AppleEvent *theReply,
571 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572{
573 OSErr error = noErr;
574 buf_T *buf;
575 int foundFile = false;
576 DescType typeCode;
577 WindowSearch SearchData;
578 Size actualSize;
579
580 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
581 if (error)
582 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583 return(error);
584 }
585
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000586 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587 if (error)
588 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589 return(error);
590 }
591
592 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
593 if (buf->b_ml.ml_mfp != NULL
594 && SearchData.theFile.parID == buf->b_FSSpec.parID
595 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
596 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
597 {
598 foundFile = true;
599 break;
600 }
601
602 if (foundFile == false)
603 *SearchData.theDate = fnfErr;
604 else
605 *SearchData.theDate = buf->b_mtime;
606
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 return error;
608};
609
610/*
611 * Handle the Modified (from IDE to Editor) event from CodeWarrior
612 *
613 * Description
614 * -----------
615 *
616 * The IDE sends this event to the external editor when it wants to
617 * know which files that are open in the editor have been modified.
618 *
619 * Parameters None.
620 * ----------
621 *
622 * Event Reply
623 * -----------
624 * The reply for this event is:
625 *
626 * keyDirectObject typeAEList required
627 * each element in the list is a structure of typeChar
628 *
629 * Remarks
630 * -------
631 *
632 * When building the reply event, include one element in the list for
633 * each open file that has been modified.
634 *
635 */
636
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637typedef struct ModificationInfo ModificationInfo;
638struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
639{
640 FSSpec theFile; // identifies the file
641 long theDate; // the date/time the file was last modified
642 short saved; // set this to zero when replying, unused
643};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000645 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000646Handle_KAHL_MOD_AE(
647 const AppleEvent *theAEvent,
648 AppleEvent *theReply,
649 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650{
651 OSErr error = noErr;
652 AEDescList replyList;
653 long numFiles;
654 ModificationInfo theFile;
655 buf_T *buf;
656
657 theFile.saved = 0;
658
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000659 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660 if (error)
661 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662 return(error);
663 }
664
665 /* Send the reply */
666/* replyObject.descriptorType = typeNull;
667 replyObject.dataHandle = nil;*/
668
669/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
670 error = AECreateList(nil, 0, false, &replyList);
671 if (error)
672 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673 return(error);
674 }
675
676#if 0
677 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000679 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
680 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 * sizeof(DescType))
682 */
683
684 /* AEPutDesc */
685#endif
686
687 numFiles = 0;
688 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
689 if (buf->b_ml.ml_mfp != NULL)
690 {
691 /* Add this file to the list */
692 theFile.theFile = buf->b_FSSpec;
693 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000694/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
695 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 };
697
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698#if 0
699 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700#endif
701
702 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000703 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 if (replyList.dataHandle)
706 AEDisposeDesc(&replyList);
707
708 return error;
709};
710
711/*
712 * Handle the Get Text event from CodeWarrior
713 *
714 * Description
715 * -----------
716 *
717 * The IDE sends the Get Text AppleEvent to the editor when it needs
718 * the source code from a file. For example, when the user issues a
719 * Check Syntax or Compile command, the compiler needs access to
720 * the source code contained in the file.
721 *
722 * Event Reply
723 * -----------
724 *
725 * None. Put data in locations specified in the structure received.
726 *
727 * Remarks
728 * -------
729 *
730 * When the editor receives this event, it must set the size of the handle
731 * in theText to fit the data in the file. It must then copy the entire
732 * contents of the specified file into the memory location specified in
733 * theText.
734 *
735 */
736
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737typedef struct CW_GetText CW_GetText;
738struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
739{
740 FSSpec theFile; /* identifies the file */
741 Handle theText; /* the location where you return the text (must be resized properly) */
742 long *unused; /* 0 (not used) */
743 long *theDate; /* where to put the modification date/time */
744};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000746 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000747Handle_KAHL_GTTX_AE(
748 const AppleEvent *theAEvent,
749 AppleEvent *theReply,
750 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751{
752 OSErr error = noErr;
753 buf_T *buf;
754 int foundFile = false;
755 DescType typeCode;
756 CW_GetText GetTextData;
757 Size actualSize;
758 char_u *line;
759 char_u *fullbuffer = NULL;
760 long linesize;
761 long lineStart;
762 long BufferSize;
763 long lineno;
764
765 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
766
767 if (error)
768 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 return(error);
770 }
771
772 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
773 if (buf->b_ml.ml_mfp != NULL)
774 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
775 {
776 foundFile = true;
777 break;
778 }
779
780 if (foundFile)
781 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000782 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
784 {
785 /* Must use the right buffer */
786 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
787 linesize = STRLEN(line) + 1;
788 lineStart = BufferSize;
789 BufferSize += linesize;
790 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000791 SetHandleSize(GetTextData.theText, BufferSize);
792 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 break; /* Simple handling for now */
795 }
796 else
797 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000798 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000800 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000802 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 }
804 }
805 if (fullbuffer != NULL)
806 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000807 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000809 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 }
811 if (foundFile == false)
812 *GetTextData.theDate = fnfErr;
813 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000814/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 *GetTextData.theDate = buf->b_mtime;
816 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (error)
820 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 return(error);
822 }
823
824 return(error);
825}
826
827/*
828 *
829 */
830
831/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000832 pascal OSErr
833FindProcessBySignature(
834 const OSType targetType,
835 const OSType targetCreator,
836 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837{
838 OSErr anErr = noErr;
839 Boolean lookingForProcess = true;
840
841 ProcessInfoRec infoRec;
842
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000843 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 infoRec.processName = nil;
845 infoRec.processAppSpec = nil;
846
847 psnPtr->lowLongOfPSN = kNoProcess;
848 psnPtr->highLongOfPSN = kNoProcess;
849
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000850 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000852 anErr = GetNextProcess(psnPtr);
853 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 else
856 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000857 anErr = GetProcessInformation(psnPtr, &infoRec);
858 if ((anErr == noErr)
859 && (infoRec.processType == targetType)
860 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 }
863 }
864
865 return anErr;
866}//end FindProcessBySignature
867
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000868 void
869Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000871 OSErr anErr = noErr;
872 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
874 AppleEvent theReply = { typeNull, nil };
875 AESendMode sendMode;
876 AppleEvent theEvent = {typeNull, nil };
877 AEIdleUPP idleProcUPP = nil;
878 ModificationInfo ModData;
879
880
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000881 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000882 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
885 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000887 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 {
889 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
890 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
891 }
892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000893 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894
895 /* Add the parms */
896 ModData.theFile = buf->b_FSSpec;
897 ModData.theDate = buf->b_mtime;
898
899 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000900 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000902 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 sendMode = kAENoReply;
904 else
905 sendMode = kAEWaitReply;
906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000907 if (anErr == noErr)
908 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
909 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000911/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000914 }
915}
916#endif /* FEAT_CW_EDITOR */
917
918/*
919 * ------------------------------------------------------------
920 * Apple Event Handling procedure
921 * ------------------------------------------------------------
922 */
923#ifdef USE_AEVENT
924
925/*
926 * Handle the Unused parms of an AppleEvent
927 */
928
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000929 OSErr
930HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931{
932 OSErr error;
933 long actualSize;
934 DescType dummyType;
935 AEKeyword missedKeyword;
936
937 /* Get the "missed keyword" attribute from the AppleEvent. */
938 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
939 typeKeyword, &dummyType,
940 (Ptr)&missedKeyword, sizeof(missedKeyword),
941 &actualSize);
942
943 /* If the descriptor isn't found, then we got the required parameters. */
944 if (error == errAEDescNotFound)
945 {
946 error = noErr;
947 }
948 else
949 {
950#if 0
951 /* Why is this removed? */
952 error = errAEEventNotHandled;
953#endif
954 }
955
956 return error;
957}
958
959
960/*
961 * Handle the ODoc AppleEvent
962 *
963 * Deals with all files dragged to the application icon.
964 *
965 */
966
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967typedef struct SelectionRange SelectionRange;
968struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
969{
970 short unused1; // 0 (not used)
971 short lineNum; // line to select (<0 to specify range)
972 long startRange; // start of selection range (if line < 0)
973 long endRange; // end of selection range (if line < 0)
974 long unused2; // 0 (not used)
975 long theDate; // modification date/time
976};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000977
978/* The IDE uses the optional keyAEPosition parameter to tell the ed-
979 itor the selection range. If lineNum is zero or greater, scroll the text
980 to the specified line. If lineNum is less than zero, use the values in
981 startRange and endRange to select the specified characters. Scroll
982 the text to display the selection. If lineNum, startRange, and
983 endRange are all negative, there is no selection range specified.
984 */
985
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000986 pascal OSErr
987HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988{
989 /*
990 * TODO: Clean up the code with convert the AppleEvent into
991 * a ":args"
992 */
993 OSErr error = noErr;
994// OSErr firstError = noErr;
995// short numErrors = 0;
996 AEDesc theList;
997 DescType typeCode;
998 long numFiles;
999 // long fileCount;
1000 char_u **fnames;
1001// char_u fname[256];
1002 Size actualSize;
1003 SelectionRange thePosition;
1004 short gotPosition = false;
1005 long lnum;
1006
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007 /* the direct object parameter is the list of aliases to files (one or more) */
1008 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1009 if (error)
1010 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 return(error);
1012 }
1013
1014
1015 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1016 if (error == noErr)
1017 gotPosition = true;
1018 if (error == errAEDescNotFound)
1019 error = noErr;
1020 if (error)
1021 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022 return(error);
1023 }
1024
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025/*
1026 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1027
1028 if (^error) then
1029 {
1030 if (thePosition.lineNum >= 0)
1031 {
1032 // Goto this line
1033 }
1034 else
1035 {
1036 // Set the range char wise
1037 }
1038 }
1039 */
1040
1041
1042#ifdef FEAT_VISUAL
1043 reset_VIsual();
1044#endif
1045
1046 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1047
1048 if (error)
1049 {
1050 /* TODO: empty fnames[] first */
1051 vim_free(fnames);
1052 return (error);
1053 }
1054
1055 if (starting > 0)
1056 {
1057 int i;
1058 char_u *p;
1059
1060 /* these are the initial files dropped on the Vim icon */
1061 for (i = 0 ; i < numFiles; i++)
1062 {
1063 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1064 || (p = vim_strsave(fnames[i])) == NULL)
1065 mch_exit(2);
1066 else
1067 alist_add(&global_alist, p, 2);
1068 }
1069 goto finished;
1070 }
1071
1072 /* Handle the drop, :edit to get to the file */
1073 handle_drop(numFiles, fnames, FALSE);
1074
1075 /* TODO: Handle the goto/select line more cleanly */
1076 if ((numFiles == 1) & (gotPosition))
1077 {
1078 if (thePosition.lineNum >= 0)
1079 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001080 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 /* oap->motion_type = MLINE;
1082 setpcmark();*/
1083 if (lnum < 1L)
1084 lnum = 1L;
1085 else if (lnum > curbuf->b_ml.ml_line_count)
1086 lnum = curbuf->b_ml.ml_line_count;
1087 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001088 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 /* beginline(BL_SOL | BL_FIX);*/
1090 }
1091 else
1092 goto_byte(thePosition.startRange + 1);
1093 }
1094
1095 /* Update the screen display */
1096 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001097#ifdef FEAT_VISUAL
1098 /* Select the text if possible */
1099 if (gotPosition)
1100 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001101 VIsual_active = TRUE;
1102 VIsual_select = FALSE;
1103 VIsual = curwin->w_cursor;
1104 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001105 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001106 VIsual_mode = 'v';
1107 goto_byte(thePosition.endRange);
1108 }
1109 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001110 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001111 VIsual_mode = 'V';
1112 VIsual.col = 0;
1113 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001114 }
1115#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116 setcursor();
1117 out_flush();
1118
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001119 /* Fake mouse event to wake from stall */
1120 PostEvent(mouseUp, 0);
1121
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122 finished:
1123 AEDisposeDesc(&theList); /* dispose what we allocated */
1124
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001125 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 if (error)
1127 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 return(error);
1129 }
1130 return(error);
1131}
1132
1133/*
1134 *
1135 */
1136
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001137 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001138Handle_aevt_oapp_AE(
1139 const AppleEvent *theAEvent,
1140 AppleEvent *theReply,
1141 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001142{
1143 OSErr error = noErr;
1144
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001145 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 if (error)
1147 {
1148 return(error);
1149 }
1150
1151 return(error);
1152}
1153
1154/*
1155 *
1156 */
1157
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001158 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001159Handle_aevt_quit_AE(
1160 const AppleEvent *theAEvent,
1161 AppleEvent *theReply,
1162 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163{
1164 OSErr error = noErr;
1165
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001166 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 if (error)
1168 {
1169 return(error);
1170 }
1171
1172 /* Need to fake a :confirm qa */
1173 do_cmdline_cmd((char_u *)"confirm qa");
1174
1175 return(error);
1176}
1177
1178/*
1179 *
1180 */
1181
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001182 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001183Handle_aevt_pdoc_AE(
1184 const AppleEvent *theAEvent,
1185 AppleEvent *theReply,
1186 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187{
1188 OSErr error = noErr;
1189
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001190 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191 if (error)
1192 {
1193 return(error);
1194 }
1195
1196 return(error);
1197}
1198
1199/*
1200 * Handling of unknown AppleEvent
1201 *
1202 * (Just get rid of all the parms)
1203 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001204 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001205Handle_unknown_AE(
1206 const AppleEvent *theAEvent,
1207 AppleEvent *theReply,
1208 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209{
1210 OSErr error = noErr;
1211
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001212 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213 if (error)
1214 {
1215 return(error);
1216 }
1217
1218 return(error);
1219}
1220
1221
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222/*
1223 * Install the various AppleEvent Handlers
1224 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001225 OSErr
1226InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227{
1228 OSErr error;
1229
1230 /* install open application handler */
1231 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001232 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 if (error)
1234 {
1235 return error;
1236 }
1237
1238 /* install quit application handler */
1239 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001240 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 if (error)
1242 {
1243 return error;
1244 }
1245
1246 /* install open document handler */
1247 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001248 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 if (error)
1250 {
1251 return error;
1252 }
1253
1254 /* install print document handler */
1255 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001256 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257
1258/* Install Core Suite */
1259/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001260 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261
1262 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001263 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264
1265 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001266 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267
1268 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001269 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001270
1271 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001272 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273
1274 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001275 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276
1277 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001278 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279
1280 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001281 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282
1283 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001284 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285
1286 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001287 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288
1289 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001290 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291
1292 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001293 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294
1295 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001296 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297*/
1298
1299#ifdef FEAT_CW_EDITOR
1300 /*
1301 * Bind codewarrior support handlers
1302 */
1303 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001304 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 if (error)
1306 {
1307 return error;
1308 }
1309 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001310 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 if (error)
1312 {
1313 return error;
1314 }
1315 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001316 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317 if (error)
1318 {
1319 return error;
1320 }
1321#endif
1322
1323 return error;
1324
1325}
1326#endif /* USE_AEVENT */
1327
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001328
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001329/*
1330 * Callback function, installed by InstallFontPanelHandler(), below,
1331 * to handle Font Panel events.
1332 */
1333 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001334FontPanelHandler(
1335 EventHandlerCallRef inHandlerCallRef,
1336 EventRef inEvent,
1337 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001338{
1339 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1340 {
1341 gFontPanelInfo.isPanelVisible = false;
1342 return noErr;
1343 }
1344
1345 if (GetEventKind(inEvent) == kEventFontSelection)
1346 {
1347 OSStatus status;
1348 FMFontFamily newFamily;
1349 FMFontSize newSize;
1350 FMFontStyle newStyle;
1351
1352 /* Retrieve the font family ID number. */
1353 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1354 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1355 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1356 &newFamily);
1357 if (status == noErr)
1358 gFontPanelInfo.family = newFamily;
1359
1360 /* Retrieve the font size. */
1361 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1362 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1363 if (status == noErr)
1364 gFontPanelInfo.size = newSize;
1365
1366 /* Retrieve the font style (bold, etc.). Currently unused. */
1367 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1368 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1369 if (status == noErr)
1370 gFontPanelInfo.style = newStyle;
1371 }
1372 return noErr;
1373}
1374
1375
1376 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001377InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001378{
1379 EventTypeSpec eventTypes[2];
1380 EventHandlerUPP handlerUPP;
1381 /* EventHandlerRef handlerRef; */
1382
1383 eventTypes[0].eventClass = kEventClassFont;
1384 eventTypes[0].eventKind = kEventFontSelection;
1385 eventTypes[1].eventClass = kEventClassFont;
1386 eventTypes[1].eventKind = kEventFontPanelClosed;
1387
1388 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1389
1390 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1391 /*userData=*/NULL, /*handlerRef=*/NULL);
1392}
1393
1394
1395/*
1396 * Fill the buffer pointed to by outName with the name and size
1397 * of the font currently selected in the Font Panel.
1398 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001399#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001400 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001401GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001402{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001403 Str255 buf;
1404 ByteCount fontNameLen = 0;
1405 ATSUFontID fid;
1406 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001407
1408 if (!outName)
1409 return;
1410
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001411 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1412 {
1413 /* Canonicalize localized font names */
1414 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1415 gFontPanelInfo.style, &fid, NULL) != noErr)
1416 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001417
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001418 /* Request font name with Mac encoding (otherwise we could
1419 * get an unwanted utf-16 name) */
1420 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1421 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001422 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001424
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001425 /* Only encode font size, because style (bold, italic, etc) is
1426 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001427 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428 gFontPanelInfo.size/*,
1429 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1430 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1431 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1432
1433 if ((fontNameLen + STRLEN(styleString)) < 255)
1434 STRCPY(outName + fontNameLen, styleString);
1435 }
1436 else
1437 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001438 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001439 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001440}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001441
1442
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443/*
1444 * ------------------------------------------------------------
1445 * Unfiled yet
1446 * ------------------------------------------------------------
1447 */
1448
1449/*
1450 * gui_mac_get_menu_item_index
1451 *
1452 * Returns the index inside the menu wher
1453 */
1454 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001455gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456{
1457 short index;
1458 short itemIndex = -1;
1459 vimmenu_T *pBrother;
1460
1461 /* Only menu without parent are the:
1462 * -menu in the menubar
1463 * -popup menu
1464 * -toolbar (guess)
1465 *
1466 * Which are not items anyway.
1467 */
1468 if (pMenu->parent)
1469 {
1470 /* Start from the Oldest Brother */
1471 pBrother = pMenu->parent->children;
1472 index = 1;
1473 while ((pBrother) && (itemIndex == -1))
1474 {
1475 if (pBrother == pMenu)
1476 itemIndex = index;
1477 index++;
1478 pBrother = pBrother->next;
1479 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480 }
1481 return itemIndex;
1482}
1483
1484 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001485gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486{
1487 short index;
1488 vimmenu_T *pChildMenu;
1489 vimmenu_T *pElder = pMenu->parent;
1490
1491
1492 /* Only menu without parent are the:
1493 * -menu in the menubar
1494 * -popup menu
1495 * -toolbar (guess)
1496 *
1497 * Which are not items anyway.
1498 */
1499
1500 if ((pElder) && (pElder->submenu_id == menuID))
1501 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001502 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1503 pMenu = pMenu->next;
1504 }
1505 else
1506 {
1507 for (; pMenu != NULL; pMenu = pMenu->next)
1508 {
1509 if (pMenu->children != NULL)
1510 {
1511 pChildMenu = gui_mac_get_vim_menu
1512 (menuID, itemIndex, pMenu->children);
1513 if (pChildMenu)
1514 {
1515 pMenu = pChildMenu;
1516 break;
1517 }
1518 }
1519 }
1520 }
1521 return pMenu;
1522}
1523
1524/*
1525 * ------------------------------------------------------------
1526 * MacOS Feedback procedures
1527 * ------------------------------------------------------------
1528 */
1529 pascal
1530 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001531gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001532{
1533 scrollbar_T *sb;
1534 int value, dragging;
1535 ControlHandle theControlToUse;
1536 int dont_scroll_save = dont_scroll;
1537
1538 theControlToUse = dragged_sb;
1539
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001540 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541
1542 if (sb == NULL)
1543 return;
1544
1545 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001546 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 dragging = (partCode != 0);
1548
1549 /* When "allow_scrollbar" is FALSE still need to remember the new
1550 * position, but don't actually scroll by setting "dont_scroll". */
1551 dont_scroll = !allow_scrollbar;
1552 gui_drag_scrollbar(sb, value, dragging);
1553 dont_scroll = dont_scroll_save;
1554}
1555
1556 pascal
1557 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001558gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559{
1560 /* TODO: have live support */
1561 scrollbar_T *sb, *sb_info;
1562 long data;
1563 long value;
1564 int page;
1565 int dragging = FALSE;
1566 int dont_scroll_save = dont_scroll;
1567
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001568 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569
1570 if (sb == NULL)
1571 return;
1572
1573 if (sb->wp != NULL) /* Left or right scrollbar */
1574 {
1575 /*
1576 * Careful: need to get scrollbar info out of first (left) scrollbar
1577 * for window, but keep real scrollbar too because we must pass it to
1578 * gui_drag_scrollbar().
1579 */
1580 sb_info = &sb->wp->w_scrollbars[0];
1581
1582 if (sb_info->size > 5)
1583 page = sb_info->size - 2; /* use two lines of context */
1584 else
1585 page = sb_info->size;
1586 }
1587 else /* Bottom scrollbar */
1588 {
1589 sb_info = sb;
1590 page = W_WIDTH(curwin) - 5;
1591 }
1592
1593 switch (partCode)
1594 {
1595 case kControlUpButtonPart: data = -1; break;
1596 case kControlDownButtonPart: data = 1; break;
1597 case kControlPageDownPart: data = page; break;
1598 case kControlPageUpPart: data = -page; break;
1599 default: data = 0; break;
1600 }
1601
1602 value = sb_info->value + data;
1603/* if (value > sb_info->max)
1604 value = sb_info->max;
1605 else if (value < 0)
1606 value = 0;*/
1607
1608 /* When "allow_scrollbar" is FALSE still need to remember the new
1609 * position, but don't actually scroll by setting "dont_scroll". */
1610 dont_scroll = !allow_scrollbar;
1611 gui_drag_scrollbar(sb, value, dragging);
1612 dont_scroll = dont_scroll_save;
1613
1614 out_flush();
1615 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1616
1617/* if (sb_info->wp != NULL)
1618 {
1619 win_T *wp;
1620 int sb_num;
1621
1622 sb_num = 0;
1623 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1624 sb_num++;
1625
1626 if (wp != NULL)
1627 {
1628 current_scrollbar = sb_num;
1629 scrollbar_value = value;
1630 gui_do_scroll();
1631 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1632 }
1633 }*/
1634}
1635
1636/*
1637 * ------------------------------------------------------------
1638 * MacOS Click Handling procedures
1639 * ------------------------------------------------------------
1640 */
1641
1642
1643/*
1644 * Handle a click inside the window, it may happens in the
1645 * scrollbar or the contents.
1646 *
1647 * TODO: Add support for potential TOOLBAR
1648 */
1649 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001650gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651{
1652 Point thePoint;
1653 int_u vimModifiers;
1654 short thePortion;
1655 ControlHandle theControl;
1656 int vimMouseButton;
1657 short dblClick;
1658
1659 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001660 GlobalToLocal(&thePoint);
1661 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001663 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664
1665 if (theControl != NUL)
1666 {
1667 /* We hit a scollbar */
1668
1669 if (thePortion != kControlIndicatorPart)
1670 {
1671 dragged_sb = theControl;
1672 TrackControl(theControl, thePoint, gScrollAction);
1673 dragged_sb = NULL;
1674 }
1675 else
1676 {
1677 dragged_sb = theControl;
1678#if 1
1679 TrackControl(theControl, thePoint, gScrollDrag);
1680#else
1681 TrackControl(theControl, thePoint, NULL);
1682#endif
1683 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1684 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001685 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 dragged_sb = NULL;
1687 }
1688 }
1689 else
1690 {
1691 /* We are inside the contents */
1692
1693 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1694 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1695
1696 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1697 vimMouseButton = MOUSE_LEFT;
1698
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001700 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 clickIsPopup = FALSE;
1702
1703 if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup()))
1704 if (IsShowContextualMenuClick(theEvent))
1705 {
1706 vimMouseButton = MOUSE_RIGHT;
1707 vimModifiers &= ~MOUSE_CTRL;
1708 clickIsPopup = TRUE;
1709 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710
1711 /* Is it a double click ? */
1712 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1713
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001714 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 gui_send_mouse_event(vimMouseButton, thePoint.h,
1716 thePoint.v, dblClick, vimModifiers);
1717
1718 /* Create the rectangle around the cursor to detect
1719 * the mouse dragging
1720 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721#if 0
1722 /* TODO: Do we need to this even for the contextual menu?
1723 * It may be require for popup_setpos, but for popup?
1724 */
1725 if (vimMouseButton == MOUSE_LEFT)
1726#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001728 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 FILL_Y(Y_2_ROW(thePoint.v)),
1730 FILL_X(X_2_COL(thePoint.h)+1),
1731 FILL_Y(Y_2_ROW(thePoint.v)+1));
1732
1733 dragRectEnbl = TRUE;
1734 dragRectControl = kCreateRect;
1735 }
1736 }
1737}
1738
1739/*
1740 * Handle the click in the titlebar (to move the window)
1741 */
1742 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001743gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744{
1745 Rect movingLimits;
1746 Rect *movingLimitsPtr = &movingLimits;
1747
1748 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001749 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001750 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751}
1752
1753/*
1754 * Handle the click in the grow box
1755 */
1756 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001757gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758{
1759
1760 long newSize;
1761 unsigned short newWidth;
1762 unsigned short newHeight;
1763 Rect resizeLimits;
1764 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 Rect NewContentRect;
1766
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001767 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768
1769 /* Set the minimun size */
1770 /* TODO: Should this come from Vim? */
1771 resizeLimits.top = 100;
1772 resizeLimits.left = 100;
1773
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1775 newWidth = NewContentRect.right - NewContentRect.left;
1776 newHeight = NewContentRect.bottom - NewContentRect.top;
1777 gui_resize_shell(newWidth, newHeight);
1778 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001779 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780}
1781
1782/*
1783 * Handle the click in the zoom box
1784 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001786gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787{
1788 Rect r;
1789 Point p;
1790 short thePart;
1791
1792 /* ideal width is current */
1793 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1794 if (gui.which_scrollbars[SBAR_LEFT])
1795 p.h += gui.scrollbar_width;
1796 if (gui.which_scrollbars[SBAR_RIGHT])
1797 p.h += gui.scrollbar_width;
1798 /* ideal height is as heigh as we can get */
1799 p.v = 15 * 1024;
1800
1801 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1802 ? inZoomIn : inZoomOut;
1803
1804 if (!TrackBox(whichWindow, theEvent->where, thePart))
1805 return;
1806
1807 /* use returned width */
1808 p.h = r.right - r.left;
1809 /* adjust returned height */
1810 p.v = r.bottom - r.top - 2 * gui.border_offset;
1811 if (gui.which_scrollbars[SBAR_BOTTOM])
1812 p.v -= gui.scrollbar_height;
1813 p.v -= p.v % gui.char_height;
1814 p.v += 2 * gui.border_width;
1815 if (gui.which_scrollbars[SBAR_BOTTOM]);
1816 p.v += gui.scrollbar_height;
1817
1818 ZoomWindowIdeal(whichWindow, thePart, &p);
1819
1820 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1821 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1822 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001823 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825
1826/*
1827 * ------------------------------------------------------------
1828 * MacOS Event Handling procedure
1829 * ------------------------------------------------------------
1830 */
1831
1832/*
1833 * Handle the Update Event
1834 */
1835
1836 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001837gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 WindowPtr whichWindow;
1840 GrafPtr savePort;
1841 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 Rect *updateRectPtr;
1844 Rect rc;
1845 Rect growRect;
1846 RgnHandle saveRgn;
1847
1848
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 updateRgn = NewRgn();
1850 if (updateRgn == NULL)
1851 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852
1853 /* This could be done by the caller as we
1854 * don't require anything else out of the event
1855 */
1856 whichWindow = (WindowPtr) event->message;
1857
1858 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001859 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860
1861 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001862 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863
1864 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001865 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 /* Redraw the biggest rectangle covering the area
1867 * to be updated.
1868 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1870# if 0
1871 /* Would be more appropriate to use the follwing but doesn't
1872 * seem to work under MacOS X (Dany)
1873 */
1874 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1875# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001876
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001878 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001879
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001880 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881# if 0
1882 /* Code from original Carbon Port (using GetWindowRegion.
1883 * I believe the UpdateRgn is already in local (Dany)
1884 */
1885 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1886 GlobalToLocal(&botRight(updateRect));
1887# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 /* Update the content (i.e. the text) */
1889 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1890 updateRectPtr->right - updateRectPtr->left,
1891 updateRectPtr->bottom - updateRectPtr->top);
1892 /* Clear the border areas if needed */
1893 gui_mch_set_bg_color(gui.back_pixel);
1894 if (updateRectPtr->left < FILL_X(0))
1895 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001896 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1897 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 }
1899 if (updateRectPtr->top < FILL_Y(0))
1900 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1902 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 }
1904 if (updateRectPtr->right > FILL_X(Columns))
1905 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001906 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001908 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 }
1910 if (updateRectPtr->bottom > FILL_Y(Rows))
1911 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001912 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001914 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001916 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001917 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918
1919 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001920 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921
1922 /* Update the GrowBox */
1923 /* Taken from FAQ 33-27 */
1924 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001926 GetClip(saveRgn);
1927 ClipRect(&growRect);
1928 DrawGrowIcon(whichWindow);
1929 SetClip(saveRgn);
1930 DisposeRgn(saveRgn);
1931 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932
1933 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001934 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935}
1936
1937/*
1938 * Handle the activate/deactivate event
1939 * (apply to a window)
1940 */
1941 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001942gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943{
1944 WindowPtr whichWindow;
1945
1946 whichWindow = (WindowPtr) event->message;
1947 if ((event->modifiers) & activeFlag)
1948 /* Activate */
1949 gui_focus_change(TRUE);
1950 else
1951 {
1952 /* Deactivate */
1953 gui_focus_change(FALSE);
1954/* DON'T KNOW what the code below was doing
1955 found in the deactivate clause, but the
1956 clause writting TRUE into in_focus (BUG)
1957 */
1958
1959#if 0 /* Removed by Dany as per above June 2001 */
1960 a_bool = false;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001961 SetPreserveGlyph(a_bool);
1962 SetOutlinePreferred(a_bool);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963#endif
1964 }
1965}
1966
1967
1968/*
1969 * Handle the suspend/resume event
1970 * (apply to the application)
1971 */
1972 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001973gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001974{
1975 /* The frontmost application just changed */
1976
1977 /* NOTE: the suspend may happen before the deactivate
1978 * seen on MacOS X
1979 */
1980
1981 /* May not need to change focus as the window will
1982 * get an activate/desactivate event
1983 */
1984 if (event->message & 1)
1985 /* Resume */
1986 gui_focus_change(TRUE);
1987 else
1988 /* Suspend */
1989 gui_focus_change(FALSE);
1990}
1991
1992/*
1993 * Handle the key
1994 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001995#ifdef USE_CARBONKEYHANDLER
1996# define INLINE_KEY_BUFFER_SIZE 80
1997 static pascal OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001998gui_mac_doKeyEventCarbon(
1999 EventHandlerCallRef nextHandler,
2000 EventRef theEvent,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002001 void *data)
2002{
2003 /* Multibyte-friendly key event handler */
2004 OSStatus e = -1;
2005 UInt32 actualSize;
2006 UniChar *text;
2007 char_u result[INLINE_KEY_BUFFER_SIZE];
2008 short len = 0;
2009 UInt32 key_sym;
2010 char charcode;
2011 int key_char;
2012 UInt32 modifiers;
2013 size_t encLen;
2014 char_u *to = NULL;
2015 Boolean isSpecial = FALSE;
2016 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002018 /* Mask the mouse (as per user setting) */
2019 if (p_mh)
2020 ObscureCursor();
2021
2022 do
2023 {
2024 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2025 typeUnicodeText, NULL, 0, &actualSize, NULL))
2026 break;
2027
2028 text = (UniChar *)alloc(actualSize);
2029
2030 if (text)
2031 {
2032 do
2033 {
2034 if (noErr != GetEventParameter(theEvent,
2035 kEventParamTextInputSendText,
2036 typeUnicodeText, NULL, actualSize, NULL, text))
2037 break;
2038 EventRef keyEvent;
2039 if (noErr != GetEventParameter(theEvent,
2040 kEventParamTextInputSendKeyboardEvent,
2041 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent))
2042 break;
2043 if (noErr != GetEventParameter(keyEvent,
2044 kEventParamKeyModifiers,
2045 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers))
2046 break;
2047 if (noErr != GetEventParameter(keyEvent,
2048 kEventParamKeyCode,
2049 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym))
2050 break;
2051 if (noErr != GetEventParameter(keyEvent,
2052 kEventParamKeyMacCharCodes,
2053 typeChar, NULL, sizeof(char), NULL, &charcode))
2054 break;
2055
2056 key_char = charcode;
2057
2058 if (modifiers & controlKey)
2059 {
2060 if ((modifiers & ~(controlKey|shiftKey)) == 0
2061 && (key_char == '2' || key_char == '6'))
2062 {
2063 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2064 if (key_char == '2')
2065 key_char = Ctrl_AT;
2066 else
2067 key_char = Ctrl_HAT;
2068
2069 text[0] = (UniChar)key_char;
2070 modifiers = 0;
2071 }
2072 }
2073
2074 if (modifiers & cmdKey)
2075#ifndef USE_CMD_KEY
2076 break; /* Let system handle Cmd+... */
2077#else
2078 {
2079 /* Intercept CMD-. */
2080 if (key_char == '.')
2081 got_int = TRUE;
2082
2083 /* Convert the modifiers */
2084 modifiers = EventModifiers2VimModifiers(modifiers);
2085
2086 /* Following code to simplify and consolidate modifiers
2087 * taken liberally from gui_w48.c */
2088
2089 key_char = simplify_key(key_char, (int *)&modifiers);
2090
2091 /* remove SHIFT for keys that are already shifted, e.g.,
2092 * '(' and '*' */
2093 if (key_char < 0x100 &&
2094 !isalpha(key_char) && isprint(key_char))
2095 modifiers &= ~MOD_MASK_SHIFT;
2096
2097 /* Interpret META, include SHIFT, etc. */
2098 key_char = extract_modifiers(key_char, (int *)&modifiers);
2099 if (key_char == CSI)
2100 key_char = K_CSI;
2101
2102 if (modifiers)
2103 {
2104 result[len++] = CSI;
2105 result[len++] = KS_MODIFIER;
2106 result[len++] = modifiers;
2107 }
2108
2109 isSpecial = TRUE;
2110 }
2111#endif
2112 else
2113 {
2114 /* Find the special key (eg., for cursor keys) */
2115 if (!(actualSize > sizeof(UniChar)) &&
2116 ((text[0] < 0x20) || (text[0] == 0x7f)))
2117 {
2118 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2119 if (special_keys[i].key_sym == key_sym)
2120 {
2121 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2122 special_keys[i].vim_code1);
2123 key_char = simplify_key(key_char,
2124 (int *)&modifiers);
2125 isSpecial = TRUE;
2126 break;
2127 }
2128 }
2129 }
2130
2131 if (isSpecial && IS_SPECIAL(key_char))
2132 {
2133 result[len++] = CSI;
2134 result[len++] = K_SECOND(key_char);
2135 result[len++] = K_THIRD(key_char);
2136 }
2137 else
2138 {
2139 encLen = actualSize;
2140 to = mac_utf16_to_enc(text, actualSize, &encLen);
2141 }
2142
2143 if (to)
2144 {
2145 /* This is basically add_to_input_buf_csi() */
2146 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2147 {
2148 result[len++] = to[i];
2149 if (to[i] == CSI)
2150 {
2151 result[len++] = KS_EXTRA;
2152 result[len++] = (int)KE_CSI;
2153 }
2154 }
2155 vim_free(to);
2156 }
2157
2158 add_to_input_buf(result, len);
2159 e = noErr;
2160 }
2161 while (0);
2162
2163 vim_free(text);
2164 if (e == noErr)
2165 {
2166 /* Fake event to wake up WNE (required to get
2167 * key repeat working */
2168 PostEvent(keyUp, 0);
2169 return noErr;
2170 }
2171 }
2172 }
2173 while (0);
2174
2175 return CallNextEventHandler(nextHandler, theEvent);
2176}
2177#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 void
2179gui_mac_doKeyEvent(EventRecord *theEvent)
2180{
2181 /* TODO: add support for COMMAND KEY */
2182 long menu;
2183 unsigned char string[20];
2184 short num, i;
2185 short len = 0;
2186 KeySym key_sym;
2187 int key_char;
2188 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002189 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190
2191 /* Mask the mouse (as per user setting) */
2192 if (p_mh)
2193 ObscureCursor();
2194
2195 /* Get the key code and it's ASCII representation */
2196 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2197 key_char = theEvent->message & charCodeMask;
2198 num = 1;
2199
2200 /* Intercept CTRL-C */
2201 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002202 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203 if (key_char == Ctrl_C && ctrl_c_interrupts)
2204 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002205 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2206 && (key_char == '2' || key_char == '6'))
2207 {
2208 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2209 if (key_char == '2')
2210 key_char = Ctrl_AT;
2211 else
2212 key_char = Ctrl_HAT;
2213 theEvent->modifiers = 0;
2214 }
2215 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216
2217 /* Intercept CMD-. */
2218 if (theEvent->modifiers & cmdKey)
2219 if (key_char == '.')
2220 got_int = TRUE;
2221
2222 /* Handle command key as per menu */
2223 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2224 if (theEvent->modifiers & cmdKey)
2225 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2226 * Why the mouse button? */
2227 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2228 {
2229 menu = MenuKey(key_char);
2230 if (HiWord(menu))
2231 {
2232 gui_mac_handle_menu(menu);
2233 return;
2234 }
2235 }
2236
2237 /* Convert the modifiers */
2238 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2239
2240
2241 /* Handle special keys. */
2242#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002243 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2245#endif
2246 {
2247 /* Find the special key (for non-printable keyt_char) */
2248 if ((key_char < 0x20) || (key_char == 0x7f))
2249 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2250 if (special_keys[i].key_sym == key_sym)
2251 {
2252# if 0
2253 /* We currently don't have not so special key */
2254 if (special_keys[i].vim_code1 == NUL)
2255 key_char = special_keys[i].vim_code0;
2256 else
2257# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002258 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2259 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002260 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 break;
2262 }
2263 }
2264
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002265 /* For some keys the modifier is included in the char itself. */
2266 if (simplify || key_char == TAB || key_char == ' ')
2267 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268
2269 /* Add the modifier to the input bu if needed */
2270 /* Do not want SHIFT-A or CTRL-A with modifier */
2271 if (!IS_SPECIAL(key_char)
2272 && key_sym != vk_Space
2273 && key_sym != vk_Tab
2274 && key_sym != vk_Return
2275 && key_sym != vk_Enter
2276 && key_sym != vk_Esc)
2277 {
2278#if 1
2279 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002280 if ((modifiers == MOD_MASK_SHIFT)
2281 || (modifiers == MOD_MASK_CTRL)
2282 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 modifiers = 0;
2284#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002285 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002287 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002289 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 modifiers = modifiers & ~MOD_MASK_SHIFT;
2291#endif
2292 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002293 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002295 string[len++] = CSI;
2296 string[len++] = KS_MODIFIER;
2297 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 }
2299
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002300 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002302 string[len++] = CSI;
2303 string[len++] = K_SECOND(key_char);
2304 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 }
2306 else
2307 {
2308#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002309 /* Convert characters when needed (e.g., from MacRoman to latin1).
2310 * This doesn't work for the NUL byte. */
2311 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 {
2313 char_u from[2], *to;
2314 int l;
2315
2316 from[0] = key_char;
2317 from[1] = NUL;
2318 l = 1;
2319 to = string_convert(&input_conv, from, &l);
2320 if (to != NULL)
2321 {
2322 for (i = 0; i < l && len < 19; i++)
2323 {
2324 if (to[i] == CSI)
2325 {
2326 string[len++] = KS_EXTRA;
2327 string[len++] = KE_CSI;
2328 }
2329 else
2330 string[len++] = to[i];
2331 }
2332 vim_free(to);
2333 }
2334 else
2335 string[len++] = key_char;
2336 }
2337 else
2338#endif
2339 string[len++] = key_char;
2340 }
2341
2342 if (len == 1 && string[0] == CSI)
2343 {
2344 /* Turn CSI into K_CSI. */
2345 string[ len++ ] = KS_EXTRA;
2346 string[ len++ ] = KE_CSI;
2347 }
2348
2349 add_to_input_buf(string, len);
2350}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002351#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352
2353/*
2354 * Handle MouseClick
2355 */
2356 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002357gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358{
2359 short thePart;
2360 WindowPtr whichWindow;
2361
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002362 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363
2364 switch (thePart)
2365 {
2366 case (inDesk):
2367 /* TODO: what to do? */
2368 break;
2369
2370 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002371 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 break;
2373
2374 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002375 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 break;
2377
2378 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002379 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 break;
2381
2382 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002383 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 break;
2385
2386 case (inGoAway):
2387 if (TrackGoAway(whichWindow, theEvent->where))
2388 gui_shell_closed();
2389 break;
2390
2391 case (inZoomIn):
2392 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 break;
2395 }
2396}
2397
2398/*
2399 * Handle MouseMoved
2400 * [this event is a moving in and out of a region]
2401 */
2402 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002403gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404{
2405 Point thePoint;
2406 int_u vimModifiers;
2407
2408 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002409 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002410 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2411
2412 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002413 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2417 thePoint.v, FALSE, vimModifiers);
2418
2419 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002420 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421 FILL_Y(Y_2_ROW(thePoint.v)),
2422 FILL_X(X_2_COL(thePoint.h)+1),
2423 FILL_Y(Y_2_ROW(thePoint.v)+1));
2424
2425 if (dragRectEnbl)
2426 dragRectControl = kCreateRect;
2427
2428}
2429
2430/*
2431 * Handle the mouse release
2432 */
2433 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002434gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435{
2436 Point thePoint;
2437 int_u vimModifiers;
2438
2439 /* TODO: Properly convert the Contextual menu mouse-up */
2440 /* Potential source of the double menu */
2441 lastMouseTick = theEvent->when;
2442 dragRectEnbl = FALSE;
2443 dragRectControl = kCreateEmpty;
2444 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002445 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446
2447 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 if (clickIsPopup)
2449 {
2450 vimModifiers &= ~MOUSE_CTRL;
2451 clickIsPopup = FALSE;
2452 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002453 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454}
2455
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 static pascal OSStatus
2457gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2458 void *data)
2459{
2460 EventRef bogusEvent;
2461 Point point;
2462 Rect bounds;
2463 UInt32 mod;
2464 SInt32 delta;
2465 int_u vim_mod;
2466
2467 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2468 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2469 goto bail;
2470 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2471 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2472 goto bail;
2473 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2474 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2475 goto bail;
2476
2477 vim_mod = 0;
2478 if (mod & shiftKey)
2479 vim_mod |= MOUSE_SHIFT;
2480 if (mod & controlKey)
2481 vim_mod |= MOUSE_CTRL;
2482 if (mod & optionKey)
2483 vim_mod |= MOUSE_ALT;
2484
2485 /* post a bogus event to wake up WaitNextEvent */
2486 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2487 kEventAttributeNone, &bogusEvent))
2488 goto bail;
2489 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2490 kEventPriorityLow))
2491 goto bail;
2492
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002493 ReleaseEvent(bogusEvent);
2494
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2496 {
2497 point.h -= bounds.left;
2498 point.v -= bounds.top;
2499 }
2500
2501 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2502 point.h, point.v, FALSE, vim_mod);
2503
2504 return noErr;
2505
2506 bail:
2507 /*
2508 * when we fail give any additional callback handler a chance to perform
2509 * it's actions
2510 */
2511 return CallNextEventHandler(nextHandler, theEvent);
2512}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513
2514#if 0
2515
2516/*
2517 * This would be the normal way of invoking the contextual menu
2518 * but the Vim API doesn't seem to a support a request to get
2519 * the menu that we should display
2520 */
2521 void
2522gui_mac_handle_contextual_menu(event)
2523 EventRecord *event;
2524{
2525/*
2526 * Clone PopUp to use menu
2527 * Create a object descriptor for the current selection
2528 * Call the procedure
2529 */
2530
2531// Call to Handle Popup
2532 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2533
2534 if (status != noErr)
2535 return;
2536
2537 if (CntxType == kCMMenuItemSelected)
2538 {
2539 /* Handle the menu CntxMenuID, CntxMenuItem */
2540 /* The submenu can be handle directly by gui_mac_handle_menu */
2541 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002542 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 }
2544 else if (CntxMenuID == kCMShowHelpSelected)
2545 {
2546 /* Should come up with the help */
2547 }
2548
2549}
2550#endif
2551
2552/*
2553 * Handle menubar selection
2554 */
2555 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002556gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557{
2558 short menu = HiWord(menuChoice);
2559 short item = LoWord(menuChoice);
2560 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561
2562 if (menu == 256) /* TODO: use constant or gui.xyz */
2563 {
2564 if (item == 1)
2565 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 }
2567 else if (item != 0)
2568 {
2569 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2570
2571 if (theVimMenu)
2572 gui_menu_cb(theVimMenu);
2573 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002574 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575}
2576
2577/*
2578 * Dispatch the event to proper handler
2579 */
2580
2581 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002582gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583{
2584 OSErr error;
2585
2586 /* Handle contextual menu right now (if needed) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 if (gui.MacOSHaveCntxMenu)
2588 if (IsShowContextualMenuClick(event))
2589 {
2590# if 0
2591 gui_mac_handle_contextual_menu(event);
2592# else
2593 gui_mac_doMouseDownEvent(event);
2594# endif
2595 return;
2596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597
2598 /* Handle normal event */
2599 switch (event->what)
2600 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002601#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 case (keyDown):
2603 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002604 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 case (keyUp):
2608 /* We don't care about when the key get release */
2609 break;
2610
2611 case (mouseDown):
2612 gui_mac_doMouseDownEvent(event);
2613 break;
2614
2615 case (mouseUp):
2616 gui_mac_doMouseUpEvent(event);
2617 break;
2618
2619 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002620 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 break;
2622
2623 case (diskEvt):
2624 /* We don't need special handling for disk insertion */
2625 break;
2626
2627 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002628 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629 break;
2630
2631 case (osEvt):
2632 switch ((event->message >> 24) & 0xFF)
2633 {
2634 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002635 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 break;
2637 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002638 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639 break;
2640 }
2641 break;
2642
2643#ifdef USE_AEVENT
2644 case (kHighLevelEvent):
2645 /* Someone's talking to us, through AppleEvents */
2646 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2647 break;
2648#endif
2649 }
2650}
2651
2652/*
2653 * ------------------------------------------------------------
2654 * Unknown Stuff
2655 * ------------------------------------------------------------
2656 */
2657
2658
2659 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002660gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661{
2662 char_u c;
2663 char_u *p;
2664 char_u pFontName[256];
2665 Str255 systemFontname;
2666 short font_id;
2667 short size=9;
2668 GuiFont font;
2669#if 0
2670 char_u *fontNamePtr;
2671#endif
2672
2673 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2674 ;
2675
2676 c = *p;
2677 *p = 0;
2678
2679#if 1
2680 STRCPY(&pFontName[1], font_name);
2681 pFontName[0] = STRLEN(font_name);
2682 *p = c;
2683
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002684 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002685 char_u fontName[256];
2686 char_u *styleStart = vim_strchr(font_name, ':');
2687 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2688 vim_strncpy(fontName, font_name, fontNameLen);
2689
2690 ATSUFontID fontRef;
2691 FMFontStyle fontStyle;
2692 font_id = 0;
2693
2694 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2695 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2696 &fontRef) == noErr)
2697 {
2698 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2699 font_id = 0;
2700 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002701
2702 if (font_id == 0)
2703 {
2704 /*
2705 * Try again, this time replacing underscores in the font name
2706 * with spaces (:set guifont allows the two to be used
2707 * interchangeably; the Font Manager doesn't).
2708 */
2709 int i, changed = FALSE;
2710
2711 for (i = pFontName[0]; i > 0; --i)
2712 {
2713 if (pFontName[i] == '_')
2714 {
2715 pFontName[i] = ' ';
2716 changed = TRUE;
2717 }
2718 }
2719 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002720 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2721 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2722 kFontNoLanguageCode, &fontRef) == noErr)
2723 {
2724 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2725 font_id = 0;
2726 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002727 }
2728
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729#else
2730 /* name = C2Pascal_save(menu->dname); */
2731 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2732
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002733 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734#endif
2735
2736
2737 if (font_id == 0)
2738 {
2739 /* Oups, the system font was it the one the user want */
2740
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002741 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2742 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 if (!EqualString(pFontName, systemFontname, false, false))
2744 return NOFONT;
2745 }
2746 if (*p == ':')
2747 {
2748 p++;
2749 /* Set the values found after ':' */
2750 while (*p)
2751 {
2752 switch (*p++)
2753 {
2754 case 'h':
2755 size = points_to_pixels(p, &p, TRUE);
2756 break;
2757 /*
2758 * TODO: Maybe accept width and styles
2759 */
2760 }
2761 while (*p == ':')
2762 p++;
2763 }
2764 }
2765
2766 if (size < 1)
2767 size = 1; /* Avoid having a size of 0 with system font */
2768
2769 font = (size << 16) + ((long) font_id & 0xFFFF);
2770
2771 return font;
2772}
2773
2774/*
2775 * ------------------------------------------------------------
2776 * GUI_MCH functionnality
2777 * ------------------------------------------------------------
2778 */
2779
2780/*
2781 * Parse the GUI related command-line arguments. Any arguments used are
2782 * deleted from argv, and *argc is decremented accordingly. This is called
2783 * when vim is started, whether or not the GUI has been started.
2784 */
2785 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002786gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787{
2788 /* TODO: Move most of this stuff toward gui_mch_init */
2789#ifdef USE_EXE_NAME
2790 FSSpec applDir;
2791# ifndef USE_FIND_BUNDLE_PATH
2792 short applVRefNum;
2793 long applDirID;
2794 Str255 volName;
2795# else
2796 ProcessSerialNumber psn;
2797 FSRef applFSRef;
2798# endif
2799#endif
2800
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801 /* Why did I put that in? (Dany) */
2802 MoreMasterPointers (0x40 * 3); /* we love handles */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803
2804#if 0
2805 InitCursor();
2806
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808
2809#ifdef USE_AEVENT
2810 (void) InstallAEHandlers();
2811#endif
2812
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2814 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2815 else
2816 gui.MacOSHaveCntxMenu = false;
2817
2818 if (gui.MacOSHaveCntxMenu)
2819 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002821 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002823 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002825 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826
2827 DrawMenuBar();
2828
2829
2830#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002831 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002833 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834#endif
2835
2836
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 CreateNewWindow(kDocumentWindowClass,
2838 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002839 &windRect, &gui.VimWindow);
2840 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841
2842 gui.char_width = 7;
2843 gui.char_height = 11;
2844 gui.char_ascent = 6;
2845 gui.num_rows = 24;
2846 gui.num_cols = 80;
2847 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2848
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002849 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2850 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851
2852 dragRectEnbl = FALSE;
2853 dragRgn = NULL;
2854 dragRectControl = kCreateEmpty;
2855 cursorRgn = NewRgn();
2856#endif
2857#ifdef USE_EXE_NAME
2858# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002859 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002861 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862# else
2863 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2864 * of TN2015
2865 * This technic remove the ../Contents/MacOS/etc part
2866 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002867 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 /* if (err != noErr) return err; */
2869
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002870 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 /* if (err != noErr) return err; */
2872
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002873 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874
2875 /* This technic return NIL when we disallow_gui */
2876# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002877 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879}
2880
2881#ifndef ALWAYS_USE_GUI
2882/*
2883 * Check if the GUI can be started. Called before gvimrc is sourced.
2884 * Return OK or FAIL.
2885 */
2886 int
2887gui_mch_init_check(void)
2888{
2889 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2890 * using the >console
2891 */
2892 if (disallow_gui) /* see main.c for reason to disallow */
2893 return FAIL;
2894 return OK;
2895}
2896#endif
2897
2898 static OSErr
2899receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag)
2900{
2901 int x, y;
2902 int_u modifiers;
2903 char_u **fnames = NULL;
2904 int count;
2905 int i, j;
2906
2907 /* Get drop position, modifiers and count of items */
2908 {
2909 Point point;
2910 SInt16 mouseUpModifiers;
2911 UInt16 countItem;
2912
2913 GetDragMouse(theDrag, &point, NULL);
2914 GlobalToLocal(&point);
2915 x = point.h;
2916 y = point.v;
2917 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2918 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2919 CountDragItems(theDrag, &countItem);
2920 count = countItem;
2921 }
2922
2923 fnames = (char_u **)alloc(count * sizeof(char_u *));
2924 if (fnames == NULL)
2925 return dragNotAcceptedErr;
2926
2927 /* Get file names dropped */
2928 for (i = j = 0; i < count; ++i)
2929 {
2930 DragItemRef item;
2931 OSErr err;
2932 Size size;
2933 FlavorType type = flavorTypeHFS;
2934 HFSFlavor hfsFlavor;
2935
2936 fnames[i] = NULL;
2937 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2938 err = GetFlavorDataSize(theDrag, item, type, &size);
2939 if (err != noErr || size > sizeof(hfsFlavor))
2940 continue;
2941 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2942 if (err != noErr)
2943 continue;
2944 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
2945 }
2946 count = j;
2947
2948 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002949
2950 /* Fake mouse event to wake from stall */
2951 PostEvent(mouseUp, 0);
2952
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953 return noErr;
2954}
2955
2956/*
2957 * Initialise the GUI. Create all the windows, set up all the call-backs
2958 * etc.
2959 */
2960 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002961gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962{
2963 /* TODO: Move most of this stuff toward gui_mch_init */
2964 Rect windRect;
2965 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966 long gestalt_rc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 EventTypeSpec eventTypeSpec;
2968 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002969#ifdef USE_CARBONKEYHANDLER
2970 EventHandlerRef keyEventHandlerRef;
2971#endif
2972
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002973 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002974 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002975
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976#if 1
2977 InitCursor();
2978
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980
2981#ifdef USE_AEVENT
2982 (void) InstallAEHandlers();
2983#endif
2984
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002985 /* Ctrl click */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2987 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2988 else
2989 gui.MacOSHaveCntxMenu = false;
2990
2991 if (gui.MacOSHaveCntxMenu)
2992 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002994 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002996 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002998 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002999
3000 DrawMenuBar();
3001
3002
3003#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003004 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003006 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007#endif
3008
3009 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 (WindowPtr)-1L, true, 0);
3012 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3013 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003014 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015
3016 gui.char_width = 7;
3017 gui.char_height = 11;
3018 gui.char_ascent = 6;
3019 gui.num_rows = 24;
3020 gui.num_cols = 80;
3021 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3022
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003023 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3024 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003026 /* Install Carbon event callbacks. */
3027 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028
3029 dragRectEnbl = FALSE;
3030 dragRgn = NULL;
3031 dragRectControl = kCreateEmpty;
3032 cursorRgn = NewRgn();
3033#endif
3034 /* Display any pending error messages */
3035 display_errors();
3036
3037 /* Get background/foreground colors from system */
3038 /* TODO: do the approriate call to get real defaults */
3039 gui.norm_pixel = 0x00000000;
3040 gui.back_pixel = 0x00FFFFFF;
3041
3042 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3043 * file). */
3044 set_normal_colors();
3045
3046 /*
3047 * Check that none of the colors are the same as the background color.
3048 * Then store the current values as the defaults.
3049 */
3050 gui_check_colors();
3051 gui.def_norm_pixel = gui.norm_pixel;
3052 gui.def_back_pixel = gui.back_pixel;
3053
3054 /* Get the colors for the highlight groups (gui_check_colors() might have
3055 * changed them) */
3056 highlight_gui_started();
3057
3058 /*
3059 * Setting the gui constants
3060 */
3061#ifdef FEAT_MENU
3062 gui.menu_height = 0;
3063#endif
3064 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3065 gui.border_offset = gui.border_width = 2;
3066
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 /* If Quartz-style text antialiasing is available (see
3068 gui_mch_draw_string() below), enable it for all font sizes. */
3069 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 eventTypeSpec.eventClass = kEventClassMouse;
3072 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3073 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3074 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3075 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3076 {
3077 mouseWheelHandlerRef = NULL;
3078 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3079 mouseWheelHandlerUPP = NULL;
3080 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003082#ifdef USE_CARBONKEYHANDLER
3083 eventTypeSpec.eventClass = kEventClassTextInput;
3084 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3085 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3086 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3087 &eventTypeSpec, NULL, &keyEventHandlerRef))
3088 {
3089 keyEventHandlerRef = NULL;
3090 DisposeEventHandlerUPP(keyEventHandlerUPP);
3091 keyEventHandlerUPP = NULL;
3092 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093#endif
3094
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003095/*
3096#ifdef FEAT_MBYTE
3097 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3098#endif
3099*/
3100
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 /* TODO: Load bitmap if using TOOLBAR */
3102 return OK;
3103}
3104
3105/*
3106 * Called when the foreground or background color has been changed.
3107 */
3108 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003109gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110{
3111 /* TODO:
3112 * This proc is called when Normal is set to a value
3113 * so what msut be done? I don't know
3114 */
3115}
3116
3117/*
3118 * Open the GUI window which was created by a call to gui_mch_init().
3119 */
3120 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003121gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122{
3123 ShowWindow(gui.VimWindow);
3124
3125 if (gui_win_x != -1 && gui_win_y != -1)
3126 gui_mch_set_winpos(gui_win_x, gui_win_y);
3127
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 /*
3129 * Make the GUI the foreground process (in case it was launched
3130 * from the Terminal or via :gui).
3131 */
3132 {
3133 ProcessSerialNumber psn;
3134 if (GetCurrentProcess(&psn) == noErr)
3135 SetFrontProcess(&psn);
3136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137
3138 return OK;
3139}
3140
3141 void
3142gui_mch_exit(int rc)
3143{
3144 /* TODO: find out all what is missing here? */
3145 DisposeRgn(cursorRgn);
3146
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003147#ifdef USE_CARBONKEYHANDLER
3148 if (keyEventHandlerUPP)
3149 DisposeEventHandlerUPP(keyEventHandlerUPP);
3150#endif
3151
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 if (mouseWheelHandlerUPP != NULL)
3153 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003155#ifdef USE_ATSUI_DRAWING
3156 if (gFontStyle)
3157 ATSUDisposeStyle(gFontStyle);
3158#endif
3159
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 /* Exit to shell? */
3161 exit(rc);
3162}
3163
3164/*
3165 * Get the position of the top left corner of the window.
3166 */
3167 int
3168gui_mch_get_winpos(int *x, int *y)
3169{
3170 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171 Rect bounds;
3172 OSStatus status;
3173
3174 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003175 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176
3177 if (status != noErr)
3178 return FAIL;
3179 *x = bounds.left;
3180 *y = bounds.top;
3181 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 return FAIL;
3183}
3184
3185/*
3186 * Set the position of the top left corner of the window to the given
3187 * coordinates.
3188 */
3189 void
3190gui_mch_set_winpos(int x, int y)
3191{
3192 /* TODO: Should make sure the window is move within range
3193 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3194 */
3195 MoveWindow(gui.VimWindow, x, y, TRUE);
3196}
3197
3198 void
3199gui_mch_set_shellsize(
3200 int width,
3201 int height,
3202 int min_width,
3203 int min_height,
3204 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003205 int base_height,
3206 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 CGrafPtr VimPort;
3209 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210
3211 if (gui.which_scrollbars[SBAR_LEFT])
3212 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003213 VimPort = GetWindowPort(gui.VimWindow);
3214 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003216 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003218 }
3219 else
3220 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003221 VimPort = GetWindowPort(gui.VimWindow);
3222 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003224 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 }
3226
3227 SizeWindow(gui.VimWindow, width, height, TRUE);
3228
3229 gui_resize_shell(width, height);
3230}
3231
3232/*
3233 * Get the screen dimensions.
3234 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3235 * Is there no way to find out how wide the borders really are?
3236 * TODO: Add live udate of those value on suspend/resume.
3237 */
3238 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003239gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240{
3241 GDHandle dominantDevice = GetMainDevice();
3242 Rect screenRect = (**dominantDevice).gdRect;
3243
3244 *screen_w = screenRect.right - 10;
3245 *screen_h = screenRect.bottom - 40;
3246}
3247
3248
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003249/*
3250 * Open the Font Panel and wait for the user to select a font and
3251 * close the panel. Then fill the buffer pointed to by font_name with
3252 * the name and size of the selected font and return the font's handle,
3253 * or NOFONT in case of an error.
3254 */
3255 static GuiFont
3256gui_mac_select_font(char_u *font_name)
3257{
3258 GuiFont selected_font = NOFONT;
3259 OSStatus status;
3260 FontSelectionQDStyle curr_font;
3261
3262 /* Initialize the Font Panel with the current font. */
3263 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3264 curr_font.size = (gui.norm_font >> 16);
3265 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3266 curr_font.instance.fontStyle = 0;
3267 curr_font.hasColor = false;
3268 curr_font.version = 0; /* version number of the style structure */
3269 status = SetFontInfoForSelection(kFontSelectionQDType,
3270 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3271
3272 gFontPanelInfo.family = curr_font.instance.fontFamily;
3273 gFontPanelInfo.style = curr_font.instance.fontStyle;
3274 gFontPanelInfo.size = curr_font.size;
3275
3276 /* Pop up the Font Panel. */
3277 status = FPShowHideFontPanel();
3278 if (status == noErr)
3279 {
3280 /*
3281 * The Font Panel is modeless. We really need it to be modal,
3282 * so we spin in an event loop until the panel is closed.
3283 */
3284 gFontPanelInfo.isPanelVisible = true;
3285 while (gFontPanelInfo.isPanelVisible)
3286 {
3287 EventRecord e;
3288 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3289 }
3290
3291 GetFontPanelSelection(font_name);
3292 selected_font = gui_mac_find_font(font_name);
3293 }
3294 return selected_font;
3295}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003296
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297
3298/*
3299 * Initialise vim to use the font with the given name. Return FAIL if the font
3300 * could not be loaded, OK otherwise.
3301 */
3302 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003303gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304{
3305 /* TODO: Add support for bold italic underline proportional etc... */
3306 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003307 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003308 FontInfo font_info;
3309 short font_id;
3310 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003311 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003313#ifdef USE_ATSUI_DRAWING
3314 if (gFontStyle == NULL)
3315 {
3316 if (ATSUCreateStyle(&gFontStyle) != noErr)
3317 gFontStyle = NULL;
3318 }
3319#endif
3320
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 if (font_name == NULL)
3322 {
3323 /* First try to get the suggested font */
3324 GetFNum(suggestedFont, &font_id);
3325
3326 if (font_id == 0)
3327 {
3328 /* Then pickup the standard application font */
3329 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003330 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003332 else
3333 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3335 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003336 else if (STRCMP(font_name, "*") == 0)
3337 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003338 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003339
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003340 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003341 if (font == NOFONT)
3342 return FAIL;
3343
3344 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003345 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003346 if (new_p_guifont != NULL)
3347 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003348 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003349 vim_free(p_guifont);
3350 p_guifont = new_p_guifont;
3351 /* Replace spaces in the font name with underscores. */
3352 for ( ; *new_p_guifont; ++new_p_guifont)
3353 {
3354 if (*new_p_guifont == ' ')
3355 *new_p_guifont = '_';
3356 }
3357 }
3358 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359 else
3360 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003361 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003362 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363
3364 if (font == NOFONT)
3365 return FAIL;
3366 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003367
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 gui.norm_font = font;
3369
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003370 hl_set_font_name(used_font_name);
3371
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003372 TextSize(font >> 16);
3373 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003375 GetFontInfo(&font_info);
3376
3377 gui.char_ascent = font_info.ascent;
3378 gui.char_width = CharWidth('_');
3379 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3380
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003381#ifdef USE_ATSUI_DRAWING
3382 ATSUFontID fontID;
3383 Fixed fontSize;
3384 ATSStyleRenderingOptions fontOptions;
3385
3386 if (gFontStyle)
3387 {
3388 fontID = font & 0xFFFF;
3389 fontSize = Long2Fix(font >> 16);
3390
3391 /* No antialiasing by default (do not attempt to touch antialising
3392 * options on pre-Jaguar) */
3393 fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003394 (gMacSystemVersion >= 0x1020) ?
3395 kATSStyleNoAntiAliasing :
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003396 kATSStyleNoOptions;
3397
3398 ATSUAttributeTag attribTags[] =
3399 {
3400 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3401 kATSUMaxATSUITagValue+1
3402 };
3403 ByteCount attribSizes[] =
3404 {
3405 sizeof(ATSUFontID), sizeof(Fixed),
3406 sizeof(ATSStyleRenderingOptions), sizeof font
3407 };
3408 ATSUAttributeValuePtr attribValues[] =
3409 {
3410 &fontID, &fontSize, &fontOptions, &font
3411 };
3412
3413 /* Convert font id to ATSUFontID */
3414 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3415 {
3416 if (ATSUSetAttributes(gFontStyle,
3417 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3418 attribTags, attribSizes, attribValues) != noErr)
3419 {
3420 ATSUDisposeStyle(gFontStyle);
3421 gFontStyle = NULL;
3422 }
3423 }
3424 }
3425#endif
3426
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428}
3429
Bram Moolenaar02743632005-07-25 20:42:36 +00003430/*
3431 * Adjust gui.char_height (after 'linespace' was changed).
3432 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003434gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435{
3436 FontInfo font_info;
3437
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003438 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003439 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3440 gui.char_ascent = font_info.ascent + p_linespace / 2;
3441 return OK;
3442}
3443
3444/*
3445 * Get a font structure for highlighting.
3446 */
3447 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003448gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449{
3450 GuiFont font;
3451
3452 font = gui_mac_find_font(name);
3453
3454 if (font == NOFONT)
3455 {
3456 if (giveErrorIfMissing)
3457 EMSG2(_(e_font), name);
3458 return NOFONT;
3459 }
3460 /*
3461 * TODO : Accept only monospace
3462 */
3463
3464 return font;
3465}
3466
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003467#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003469 * Return the name of font "font" in allocated memory.
3470 * Don't know how to get the actual name, thus use the provided name.
3471 */
3472 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003473gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003474{
3475 if (name == NULL)
3476 return NULL;
3477 return vim_strsave(name);
3478}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003479#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480
3481/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 * Set the current text font.
3483 */
3484 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003485gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003487#ifdef USE_ATSUI_DRAWING
3488 GuiFont currFont;
3489 ByteCount actualFontByteCount;
3490 ATSUFontID fontID;
3491 Fixed fontSize;
3492 ATSStyleRenderingOptions fontOptions;
3493
3494 if (gFontStyle)
3495 {
3496 /* Avoid setting same font again */
3497 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
3498 &currFont, &actualFontByteCount) == noErr &&
3499 actualFontByteCount == (sizeof font))
3500 {
3501 if (currFont == font)
3502 return;
3503 }
3504
3505 fontID = font & 0xFFFF;
3506 fontSize = Long2Fix(font >> 16);
3507 /* Respect p_antialias setting only for wide font.
3508 * The reason for doing this at the moment is a bit complicated,
3509 * but it's mainly because a) latin (non-wide) aliased fonts
3510 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3511 * b) wide multibyte input does not suffer from that problem. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003512 /*fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003513 (p_antialias && (font == gui.wide_font)) ?
3514 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003515 */
3516 /*fontOptions = kATSStyleAntiAliasing;*/
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003517
3518 ATSUAttributeTag attribTags[] =
3519 {
3520 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3521 kATSUMaxATSUITagValue+1
3522 };
3523 ByteCount attribSizes[] =
3524 {
3525 sizeof(ATSUFontID), sizeof(Fixed),
3526 sizeof(ATSStyleRenderingOptions), sizeof font
3527 };
3528 ATSUAttributeValuePtr attribValues[] =
3529 {
3530 &fontID, &fontSize, &fontOptions, &font
3531 };
3532
3533 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3534 {
3535 if (ATSUSetAttributes(gFontStyle,
3536 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3537 attribTags, attribSizes, attribValues) != noErr)
3538 {
3539#ifndef NDEBUG
3540 fprintf(stderr, "couldn't set font style\n");
3541#endif
3542 ATSUDisposeStyle(gFontStyle);
3543 gFontStyle = NULL;
3544 }
3545 }
3546
3547 }
3548
3549 if (!gIsFontFallbackSet)
3550 {
3551 /* Setup automatic font substitution. The user's guifontwide
3552 * is tried first, then the system tries other fonts. */
3553/*
3554 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3555 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3556 ATSUCreateFontFallbacks(&gFontFallbacks);
3557 ATSUSetObjFontFallbacks(gFontFallbacks, );
3558*/
3559 if (gui.wide_font)
3560 {
3561 ATSUFontID fallbackFonts;
3562 gIsFontFallbackSet = TRUE;
3563
3564 if (FMGetFontFromFontFamilyInstance(
3565 (gui.wide_font & 0xFFFF),
3566 0,
3567 &fallbackFonts,
3568 NULL) == noErr)
3569 {
3570 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
3571 }
3572/*
3573 ATSUAttributeValuePtr fallbackValues[] = { };
3574*/
3575 }
3576 }
3577#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578 TextSize(font >> 16);
3579 TextFont(font & 0xFFFF);
3580}
3581
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582/*
3583 * If a font is not going to be used, free its structure.
3584 */
3585 void
3586gui_mch_free_font(font)
3587 GuiFont font;
3588{
3589 /*
3590 * Free font when "font" is not 0.
3591 * Nothing to do in the current implementation, since
3592 * nothing is allocated for each font used.
3593 */
3594}
3595
3596 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003597hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598{
3599 if (isdigit(c))
3600 return c - '0';
3601 c = TOLOWER_ASC(c);
3602 if (c >= 'a' && c <= 'f')
3603 return c - 'a' + 10;
3604 return -1000;
3605}
3606
3607/*
3608 * Return the Pixel value (color) for the given color name. This routine was
3609 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3610 * Programmer's Guide.
3611 * Return INVALCOLOR when failed.
3612 */
3613 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003614gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615{
3616 /* TODO: Add support for the new named color of MacOS 8
3617 */
3618 RGBColor MacColor;
3619// guicolor_T color = 0;
3620
3621 typedef struct guicolor_tTable
3622 {
3623 char *name;
3624 guicolor_T color;
3625 } guicolor_tTable;
3626
3627 /*
3628 * The comment at the end of each line is the source
3629 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3630 */
3631 static guicolor_tTable table[] =
3632 {
3633 {"Black", RGB(0x00, 0x00, 0x00)},
3634 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3635 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3636 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3637 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3638 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3639 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3640 {"white", RGB(0xFF, 0xFF, 0xFF)},
3641 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3642 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3643 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3644 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3645 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3646 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3647 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3648 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3649 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3650 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3651 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3652 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3653 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3654 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3655 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3656 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3657 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3658 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003659 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3661 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3662 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3663 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3664 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3665 };
3666
3667 int r, g, b;
3668 int i;
3669
3670 if (name[0] == '#' && strlen((char *) name) == 7)
3671 {
3672 /* Name is in "#rrggbb" format */
3673 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3674 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3675 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3676 if (r < 0 || g < 0 || b < 0)
3677 return INVALCOLOR;
3678 return RGB(r, g, b);
3679 }
3680 else
3681 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003682 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003684 LMGetHiliteRGB(&MacColor);
3685 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686 }
3687 /* Check if the name is one of the colors we know */
3688 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3689 if (STRICMP(name, table[i].name) == 0)
3690 return table[i].color;
3691 }
3692
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 /*
3694 * Last attempt. Look in the file "$VIM/rgb.txt".
3695 */
3696 {
3697#define LINE_LEN 100
3698 FILE *fd;
3699 char line[LINE_LEN];
3700 char_u *fname;
3701
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703 if (fname == NULL)
3704 return INVALCOLOR;
3705
3706 fd = fopen((char *)fname, "rt");
3707 vim_free(fname);
3708 if (fd == NULL)
3709 return INVALCOLOR;
3710
3711 while (!feof(fd))
3712 {
3713 int len;
3714 int pos;
3715 char *color;
3716
3717 fgets(line, LINE_LEN, fd);
3718 len = strlen(line);
3719
3720 if (len <= 1 || line[len-1] != '\n')
3721 continue;
3722
3723 line[len-1] = '\0';
3724
3725 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3726 if (i != 3)
3727 continue;
3728
3729 color = line + pos;
3730
3731 if (STRICMP(color, name) == 0)
3732 {
3733 fclose(fd);
3734 return (guicolor_T) RGB(r, g, b);
3735 }
3736 }
3737 fclose(fd);
3738 }
3739
3740 return INVALCOLOR;
3741}
3742
3743/*
3744 * Set the current text foreground color.
3745 */
3746 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003747gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748{
3749 RGBColor TheColor;
3750
3751 TheColor.red = Red(color) * 0x0101;
3752 TheColor.green = Green(color) * 0x0101;
3753 TheColor.blue = Blue(color) * 0x0101;
3754
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003755 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756}
3757
3758/*
3759 * Set the current text background color.
3760 */
3761 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003762gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763{
3764 RGBColor TheColor;
3765
3766 TheColor.red = Red(color) * 0x0101;
3767 TheColor.green = Green(color) * 0x0101;
3768 TheColor.blue = Blue(color) * 0x0101;
3769
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003770 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771}
3772
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003773RGBColor specialColor;
3774
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003775/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003776 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003777 */
3778 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003779gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003780{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003781 specialColor.red = Red(color) * 0x0101;
3782 specialColor.green = Green(color) * 0x0101;
3783 specialColor.blue = Blue(color) * 0x0101;
3784}
3785
3786/*
3787 * Draw undercurl at the bottom of the character cell.
3788 */
3789 static void
3790draw_undercurl(int flags, int row, int col, int cells)
3791{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003792 int x;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003793 int offset;
3794 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3795 int y = FILL_Y(row + 1) - 1;
3796
3797 RGBForeColor(&specialColor);
3798
3799 offset = val[FILL_X(col) % 8];
3800 MoveTo(FILL_X(col), y - offset);
3801
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003802 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003803 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003804 offset = val[x % 8];
3805 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003806 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003807}
3808
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003809#ifndef USE_ATSUI_DRAWING
3810
3811 static void
3812draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814#ifdef FEAT_MBYTE
3815 char_u *tofree = NULL;
3816
3817 if (output_conv.vc_type != CONV_NONE)
3818 {
3819 tofree = string_convert(&output_conv, s, &len);
3820 if (tofree != NULL)
3821 s = tofree;
3822 }
3823#endif
3824
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 /*
3826 * On OS X, try using Quartz-style text antialiasing.
3827 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003828 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 {
3830 /* Quartz antialiasing is available only in OS 10.2 and later. */
3831 UInt32 qd_flags = (p_antialias ?
3832 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003833 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 }
3835
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003836 /*
3837 * When antialiasing we're using srcOr mode, we have to clear the block
3838 * before drawing the text.
3839 * Also needed when 'linespace' is non-zero to remove the cursor and
3840 * underlining.
3841 * But not when drawing transparently.
3842 * The following is like calling gui_mch_clear_block(row, col, row, col +
3843 * len - 1), but without setting the bg color to gui.back_pixel.
3844 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003845 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003846 && !(flags & DRAW_TRANSP))
3847 {
3848 Rect rc;
3849
3850 rc.left = FILL_X(col);
3851 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003852#ifdef FEAT_MBYTE
3853 /* Multibyte computation taken from gui_w32.c */
3854 if (has_mbyte)
3855 {
3856 int cell_len = 0;
3857 int n;
3858
3859 /* Compute the length in display cells. */
3860 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3861 cell_len += (*mb_ptr2cells)(s + n);
3862 rc.right = FILL_X(col + cell_len);
3863 }
3864 else
3865#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003866 rc.right = FILL_X(col + len) + (col + len == Columns);
3867 rc.bottom = FILL_Y(row + 1);
3868 EraseRect(&rc);
3869 }
3870
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003871 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 {
3873 StyleParameter face;
3874
3875 face = normal;
3876 if (flags & DRAW_BOLD)
3877 face |= bold;
3878 if (flags & DRAW_UNDERL)
3879 face |= underline;
3880 TextFace(face);
3881
3882 /* Quartz antialiasing works only in srcOr transfer mode. */
3883 TextMode(srcOr);
3884
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 MoveTo(TEXT_X(col), TEXT_Y(row));
3886 DrawText((char*)s, 0, len);
3887 }
3888 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889 {
3890 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003891 TextMode(srcCopy);
3892 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893
3894 /* SelectFont(hdc, gui.currFont); */
3895
3896 if (flags & DRAW_TRANSP)
3897 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003898 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 }
3900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003901 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003902 DrawText((char *)s, 0, len);
3903
3904 if (flags & DRAW_BOLD)
3905 {
3906 TextMode(srcOr);
3907 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3908 DrawText((char *)s, 0, len);
3909 }
3910
3911 if (flags & DRAW_UNDERL)
3912 {
3913 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3914 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3915 }
3916 }
3917
3918 if (flags & DRAW_UNDERC)
3919 draw_undercurl(flags, row, col, len);
3920
3921#ifdef FEAT_MBYTE
3922 vim_free(tofree);
3923#endif
3924}
3925
3926#else /* USE_ATSUI_DRAWING */
3927
3928 static void
3929draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3930{
3931 /* ATSUI requires utf-16 strings */
3932 UniCharCount utf16_len;
3933 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3934 utf16_len /= sizeof(UniChar);
3935
3936 /* - ATSUI automatically antialiases text (Someone)
3937 * - for some reason it does not work... (Jussi) */
3938
3939 /*
3940 * When antialiasing we're using srcOr mode, we have to clear the block
3941 * before drawing the text.
3942 * Also needed when 'linespace' is non-zero to remove the cursor and
3943 * underlining.
3944 * But not when drawing transparently.
3945 * The following is like calling gui_mch_clear_block(row, col, row, col +
3946 * len - 1), but without setting the bg color to gui.back_pixel.
3947 */
3948 if ((flags & DRAW_TRANSP) == 0)
3949 {
3950 Rect rc;
3951
3952 rc.left = FILL_X(col);
3953 rc.top = FILL_Y(row);
3954 /* Multibyte computation taken from gui_w32.c */
3955 if (has_mbyte)
3956 {
3957 int cell_len = 0;
3958 int n;
3959
3960 /* Compute the length in display cells. */
3961 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3962 cell_len += (*mb_ptr2cells)(s + n);
3963 rc.right = FILL_X(col + cell_len);
3964 }
3965 else
3966 rc.right = FILL_X(col + len) + (col + len == Columns);
3967
3968 rc.bottom = FILL_Y(row + 1);
3969 EraseRect(&rc);
3970 }
3971
3972 {
3973 /* Use old-style, non-antialiased QuickDraw text rendering. */
3974 TextMode(srcCopy);
3975 TextFace(normal);
3976
3977 /* SelectFont(hdc, gui.currFont); */
3978
3979 if (flags & DRAW_TRANSP)
3980 {
3981 TextMode(srcOr);
3982 }
3983
3984 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003985 ATSUTextLayout textLayout;
3986
3987 if (ATSUCreateTextLayoutWithTextPtr(tofree,
3988 kATSUFromTextBeginning, kATSUToTextEnd,
3989 utf16_len,
3990 (gFontStyle ? 1 : 0), &utf16_len,
3991 (gFontStyle ? &gFontStyle : NULL),
3992 &textLayout) == noErr)
3993 {
3994 ATSUSetTransientFontMatching(textLayout, TRUE);
3995
3996 ATSUDrawText(textLayout,
3997 kATSUFromTextBeginning, kATSUToTextEnd,
3998 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
3999
4000 ATSUDisposeTextLayout(textLayout);
4001 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 }
4003
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004004 if (flags & DRAW_UNDERC)
4005 draw_undercurl(flags, row, col, len);
4006
Bram Moolenaar071d4272004-06-13 20:20:40 +00004007 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004008}
4009#endif
4010
4011 void
4012gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4013{
4014#if defined(USE_ATSUI_DRAWING)
4015 draw_string_ATSUI(row, col, s, len, flags);
4016#else
4017 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018#endif
4019}
4020
4021/*
4022 * Return OK if the key with the termcap name "name" is supported.
4023 */
4024 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004025gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026{
4027 int i;
4028
4029 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4030 if (name[0] == special_keys[i].vim_code0 &&
4031 name[1] == special_keys[i].vim_code1)
4032 return OK;
4033 return FAIL;
4034}
4035
4036 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004037gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004039 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040}
4041
4042 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004043gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004044{
4045 /* Do a visual beep by reversing the foreground and background colors */
4046 Rect rc;
4047
4048 /*
4049 * Note: InvertRect() excludes right and bottom of rectangle.
4050 */
4051 rc.left = 0;
4052 rc.top = 0;
4053 rc.right = gui.num_cols * gui.char_width;
4054 rc.bottom = gui.num_rows * gui.char_height;
4055 InvertRect(&rc);
4056
4057 ui_delay((long)msec, TRUE); /* wait for some msec */
4058
4059 InvertRect(&rc);
4060}
4061
4062/*
4063 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4064 */
4065 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004066gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067{
4068 Rect rc;
4069
4070 /*
4071 * Note: InvertRect() excludes right and bottom of rectangle.
4072 */
4073 rc.left = FILL_X(c);
4074 rc.top = FILL_Y(r);
4075 rc.right = rc.left + nc * gui.char_width;
4076 rc.bottom = rc.top + nr * gui.char_height;
4077 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078}
4079
4080/*
4081 * Iconify the GUI window.
4082 */
4083 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004084gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085{
4086 /* TODO: find out what could replace iconify
4087 * -window shade?
4088 * -hide application?
4089 */
4090}
4091
4092#if defined(FEAT_EVAL) || defined(PROTO)
4093/*
4094 * Bring the Vim window to the foreground.
4095 */
4096 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004097gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098{
4099 /* TODO */
4100}
4101#endif
4102
4103/*
4104 * Draw a cursor without focus.
4105 */
4106 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004107gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108{
4109 Rect rc;
4110
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111 /*
4112 * Note: FrameRect() excludes right and bottom of rectangle.
4113 */
4114 rc.left = FILL_X(gui.col);
4115 rc.top = FILL_Y(gui.row);
4116 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004117#ifdef FEAT_MBYTE
4118 if (mb_lefthalve(gui.row, gui.col))
4119 rc.right += gui.char_width;
4120#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 rc.bottom = rc.top + gui.char_height;
4122
4123 gui_mch_set_fg_color(color);
4124
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004125 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126}
4127
4128/*
4129 * Draw part of a cursor, only w pixels wide, and h pixels high.
4130 */
4131 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004132gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133{
4134 Rect rc;
4135
4136#ifdef FEAT_RIGHTLEFT
4137 /* vertical line should be on the right of current point */
4138 if (CURSOR_BAR_RIGHT)
4139 rc.left = FILL_X(gui.col + 1) - w;
4140 else
4141#endif
4142 rc.left = FILL_X(gui.col);
4143 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4144 rc.right = rc.left + w;
4145 rc.bottom = rc.top + h;
4146
4147 gui_mch_set_fg_color(color);
4148
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004149 FrameRect(&rc);
4150// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151}
4152
4153
4154
4155/*
4156 * Catch up with any queued X events. This may put keyboard input into the
4157 * input buffer, call resize call-backs, trigger timers etc. If there is
4158 * nothing in the X event queue (& no timers pending), then we return
4159 * immediately.
4160 */
4161 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004162gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163{
4164 /* TODO: find what to do
4165 * maybe call gui_mch_wait_for_chars (0)
4166 * more like look at EventQueue then
4167 * call heart of gui_mch_wait_for_chars;
4168 *
4169 * if (eventther)
4170 * gui_mac_handle_event(&event);
4171 */
4172 EventRecord theEvent;
4173
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004174 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 if (theEvent.what != nullEvent)
4176 gui_mch_wait_for_chars(0);
4177}
4178
4179/*
4180 * Simple wrapper to neglect more easily the time
4181 * spent inside WaitNextEvent while profiling.
4182 */
4183
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 pascal
4185 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004186WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187{
4188 if (((long) sleep) < -1)
4189 sleep = 32767;
4190 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4191}
4192
4193/*
4194 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4195 * from the keyboard.
4196 * wtime == -1 Wait forever.
4197 * wtime == 0 This should never happen.
4198 * wtime > 0 Wait wtime milliseconds for a character.
4199 * Returns OK if a character was found to be available within the given time,
4200 * or FAIL otherwise.
4201 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004202 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004203gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204{
4205 EventMask mask = (everyEvent);
4206 EventRecord event;
4207 long entryTick;
4208 long currentTick;
4209 long sleeppyTick;
4210
4211 /* If we are providing life feedback with the scrollbar,
4212 * we don't want to try to wait for an event, or else
4213 * there won't be any life feedback.
4214 */
4215 if (dragged_sb != NULL)
4216 return FAIL;
4217 /* TODO: Check if FAIL is the proper return code */
4218
4219 entryTick = TickCount();
4220
4221 allow_scrollbar = TRUE;
4222
4223 do
4224 {
4225/* if (dragRectControl == kCreateEmpty)
4226 {
4227 dragRgn = NULL;
4228 dragRectControl = kNothing;
4229 }
4230 else*/ if (dragRectControl == kCreateRect)
4231 {
4232 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004233 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234 dragRectControl = kNothing;
4235 }
4236 /*
4237 * Don't use gui_mch_update() because then we will spin-lock until a
4238 * char arrives, instead we use WaitNextEventWrp() to hang until an
4239 * event arrives. No need to check for input_buf_full because we are
4240 * returning as soon as it contains a single char.
4241 */
4242 /* TODO: reduce wtime accordinly??? */
4243 if (wtime > -1)
4244 sleeppyTick = 60*wtime/1000;
4245 else
4246 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004247 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004249 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 if (input_available())
4251 {
4252 allow_scrollbar = FALSE;
4253 return OK;
4254 }
4255 }
4256 currentTick = TickCount();
4257 }
4258 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4259
4260 allow_scrollbar = FALSE;
4261 return FAIL;
4262}
4263
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264/*
4265 * Output routines.
4266 */
4267
4268/* Flush any output to the screen */
4269 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004270gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271{
4272 /* TODO: Is anything needed here? */
4273}
4274
4275/*
4276 * Clear a rectangular region of the screen from text pos (row1, col1) to
4277 * (row2, col2) inclusive.
4278 */
4279 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004280gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281{
4282 Rect rc;
4283
4284 /*
4285 * Clear one extra pixel at the far right, for when bold characters have
4286 * spilled over to the next column.
4287 */
4288 rc.left = FILL_X(col1);
4289 rc.top = FILL_Y(row1);
4290 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4291 rc.bottom = FILL_Y(row2 + 1);
4292
4293 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004294 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295}
4296
4297/*
4298 * Clear the whole text window.
4299 */
4300 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004301gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302{
4303 Rect rc;
4304
4305 rc.left = 0;
4306 rc.top = 0;
4307 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4308 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4309
4310 gui_mch_set_bg_color(gui.back_pixel);
4311 EraseRect(&rc);
4312/* gui_mch_set_fg_color(gui.norm_pixel);
4313 FrameRect(&rc);
4314*/
4315}
4316
4317/*
4318 * Delete the given number of lines from the given row, scrolling up any
4319 * text further down within the scroll region.
4320 */
4321 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004322gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323{
4324 Rect rc;
4325
4326 /* changed without checking! */
4327 rc.left = FILL_X(gui.scroll_region_left);
4328 rc.right = FILL_X(gui.scroll_region_right + 1);
4329 rc.top = FILL_Y(row);
4330 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4331
4332 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004333 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334
4335 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4336 gui.scroll_region_left,
4337 gui.scroll_region_bot, gui.scroll_region_right);
4338}
4339
4340/*
4341 * Insert the given number of lines before the given row, scrolling down any
4342 * following text within the scroll region.
4343 */
4344 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004345gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346{
4347 Rect rc;
4348
4349 rc.left = FILL_X(gui.scroll_region_left);
4350 rc.right = FILL_X(gui.scroll_region_right + 1);
4351 rc.top = FILL_Y(row);
4352 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4353
4354 gui_mch_set_bg_color(gui.back_pixel);
4355
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004356 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357
4358 /* Update gui.cursor_row if the cursor scrolled or copied over */
4359 if (gui.cursor_row >= gui.row
4360 && gui.cursor_col >= gui.scroll_region_left
4361 && gui.cursor_col <= gui.scroll_region_right)
4362 {
4363 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4364 gui.cursor_row += num_lines;
4365 else if (gui.cursor_row <= gui.scroll_region_bot)
4366 gui.cursor_is_valid = FALSE;
4367 }
4368
4369 gui_clear_block(row, gui.scroll_region_left,
4370 row + num_lines - 1, gui.scroll_region_right);
4371}
4372
4373 /*
4374 * TODO: add a vim format to the clipboard which remember
4375 * LINEWISE, CHARWISE, BLOCKWISE
4376 */
4377
4378 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004379clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380{
4381
4382 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004383 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 Size scrapSize;
4385 ScrapFlavorFlags scrapFlags;
4386 ScrapRef scrap = nil;
4387 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388 int type;
4389 char *searchCR;
4390 char_u *tempclip;
4391
4392
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004393 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 if (error != noErr)
4395 return;
4396
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004397 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4398 if (error == noErr)
4399 {
4400 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4401 if (error == noErr && scrapSize > 1)
4402 flavor = 1;
4403 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004405 if (flavor == 0)
4406 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004407 error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004408 if (error != noErr)
4409 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004411 error = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004412 if (error != noErr)
4413 return;
4414 }
4415
4416 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419 /* In CARBON we don't need a Handle, a pointer is good */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004420 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004421 /* tempclip = lalloc(scrapSize+1, TRUE); */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004422 HLock(textOfClip);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004423 error = GetScrapFlavorData(scrap,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004424 flavor ? VIMSCRAPFLAVOR : kScrapFlavorTypeUnicode,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004425 &scrapSize, *textOfClip);
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004426 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004427
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004428 if (flavor)
4429 type = **textOfClip;
4430 else
4431 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004433 tempclip = lalloc(scrapSize + 1, TRUE);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004434#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004435 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4436#else
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004437 STRNCPY(tempclip, *textOfClip + flavor, scrapSize);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004438#endif
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004439 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004441#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004442 /* Convert from utf-16 (clipboard) */
4443 size_t encLen = 0;
4444 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
4445 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004447 scrapSize = encLen;
4448 vim_free(tempclip);
4449 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004450 }
4451#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004452
4453 searchCR = (char *)tempclip;
4454 while (searchCR != NULL)
4455 {
4456 searchCR = strchr(searchCR, '\r');
4457
4458 if (searchCR != NULL)
4459 searchCR[0] = '\n';
4460
4461 }
4462
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463 clip_yank_selection(type, tempclip, scrapSize, cbd);
4464
4465 vim_free(tempclip);
4466 HUnlock(textOfClip);
4467
4468 DisposeHandle(textOfClip);
4469 }
4470}
4471
4472 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004473clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474{
4475 /*
4476 * TODO: Really nothing to do?
4477 */
4478}
4479
4480 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004481clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482{
4483 return OK;
4484}
4485
4486/*
4487 * Send the current selection to the clipboard.
4488 */
4489 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004490clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491{
4492 Handle textOfClip;
4493 long scrapSize;
4494 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496
4497 char_u *str = NULL;
4498
4499 if (!cbd->owned)
4500 return;
4501
4502 clip_get_selection(cbd);
4503
4504 /*
4505 * Once we set the clipboard, lose ownership. If another application sets
4506 * the clipboard, we don't want to think that we still own it.
4507 *
4508 */
4509
4510 cbd->owned = FALSE;
4511
4512 type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd);
4513
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004514#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004515 size_t utf16_len = 0;
4516 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4517 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004519 scrapSize = utf16_len;
4520 vim_free(str);
4521 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 }
4523#endif
4524
4525 if (type >= 0)
4526 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004529 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530 HLock(textOfClip);
4531
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004532 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004533 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004534 GetCurrentScrap(&scrap);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004535 PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004536 scrapSize, *textOfClip + 1);
4537 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4538 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 HUnlock(textOfClip);
4540 DisposeHandle(textOfClip);
4541 }
4542
4543 vim_free(str);
4544}
4545
4546 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004547gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548{
4549 Rect VimBound;
4550
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004551/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553
4554 if (gui.which_scrollbars[SBAR_LEFT])
4555 {
4556 VimBound.left = -gui.scrollbar_width + 1;
4557 }
4558 else
4559 {
4560 VimBound.left = 0;
4561 }
4562
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004565 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566}
4567
4568/*
4569 * Menu stuff.
4570 */
4571
4572 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004573gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574{
4575 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004576 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577 */
4578}
4579
4580 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004581gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582{
4583 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004584 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 */
4586}
4587
4588/*
4589 * Add a sub menu to the menu bar.
4590 */
4591 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004592gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593{
4594 /*
4595 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4596 * TODO: use menu->mnemonic and menu->actext
4597 * TODO: Try to reuse menu id
4598 * Carbon Help suggest to use only id between 1 and 235
4599 */
4600 static long next_avail_id = 128;
4601 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004602#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004603 CFStringRef name;
4604#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 short index;
4608 vimmenu_T *parent = menu->parent;
4609 vimmenu_T *brother = menu->next;
4610
4611 /* Cannot add a menu if ... */
4612 if ((parent != NULL && parent->submenu_id == 0))
4613 return;
4614
4615 /* menu ID greater than 1024 are reserved for ??? */
4616 if (next_avail_id == 1024)
4617 return;
4618
4619 /* My brother could be the PopUp, find my real brother */
4620 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4621 brother = brother->next;
4622
4623 /* Find where to insert the menu (for MenuBar) */
4624 if ((parent == NULL) && (brother != NULL))
4625 menu_after_me = brother->submenu_id;
4626
4627 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4628 if (!menu_is_menubar(menu->name))
4629 menu_after_me = hierMenu;
4630
4631 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004632#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004633 name = menu_title_removing_mnemonic(menu);
4634#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004636#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 if (name == NULL)
4638 return;
4639
4640 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641 {
4642 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004643 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4644 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645 */
4646 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004647#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004648 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4649 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4650#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004651 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004652#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 next_avail_id++;
4654 }
4655
4656 if (parent == NULL)
4657 {
4658 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4659
4660 /* TODO: Verify if we could only Insert Menu if really part of the
4661 * menubar The Inserted menu are scanned or the Command-key combos
4662 */
4663
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004664 /* Insert the menu */
4665 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666#if 1
4667 /* Vim should normally update it. TODO: verify */
4668 DrawMenuBar();
4669#endif
4670 }
4671 else
4672 {
4673 /* Adding as a submenu */
4674
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004675 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676
4677 /* Call InsertMenuItem followed by SetMenuItemText
4678 * to avoid special character recognition by InsertMenuItem
4679 */
4680 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004681#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004682 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4683#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004685#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4687 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4688 InsertMenu(menu->submenu_handle, hierMenu);
4689 }
4690
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004691#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004692 CFRelease(name);
4693#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004694 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004695#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004696
4697#if 0
4698 /* Done by Vim later on */
4699 DrawMenuBar();
4700#endif
4701}
4702
4703/*
4704 * Add a menu item to a menu
4705 */
4706 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004707gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004709#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004710 CFStringRef name;
4711#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004713#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 vimmenu_T *parent = menu->parent;
4715 int menu_inserted;
4716
4717 /* Cannot add item, if the menu have not been created */
4718 if (parent->submenu_id == 0)
4719 return;
4720
4721 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4722 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4723
4724 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004725#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004726 name = menu_title_removing_mnemonic(menu);
4727#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004729#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730
4731 /* Where are just a menu item, so no handle, no id */
4732 menu->submenu_id = 0;
4733 menu->submenu_handle = NULL;
4734
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 menu_inserted = 0;
4736 if (menu->actext)
4737 {
4738 /* If the accelerator text for the menu item looks like it describes
4739 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4740 * item's command equivalent.
4741 */
4742 int key = 0;
4743 int modifiers = 0;
4744 char_u *p_actext;
4745
4746 p_actext = menu->actext;
4747 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4748 if (*p_actext != 0)
4749 key = 0; /* error: trailing text */
4750 /* find_special_key() returns a keycode with as many of the
4751 * specified modifiers as appropriate already applied (e.g., for
4752 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4753 * as the only modifier). Since we want to display all of the
4754 * modifiers, we need to convert the keycode back to a printable
4755 * character plus modifiers.
4756 * TODO: Write an alternative find_special_key() that doesn't
4757 * apply modifiers.
4758 */
4759 if (key > 0 && key < 32)
4760 {
4761 /* Convert a control key to an uppercase letter. Note that
4762 * by this point it is no longer possible to distinguish
4763 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4764 */
4765 modifiers |= MOD_MASK_CTRL;
4766 key += '@';
4767 }
4768 /* If the keycode is an uppercase letter, set the Shift modifier.
4769 * If it is a lowercase letter, don't set the modifier, but convert
4770 * the letter to uppercase for display in the menu.
4771 */
4772 else if (key >= 'A' && key <= 'Z')
4773 modifiers |= MOD_MASK_SHIFT;
4774 else if (key >= 'a' && key <= 'z')
4775 key += 'A' - 'a';
4776 /* Note: keycodes below 0x22 are reserved by Apple. */
4777 if (key >= 0x22 && vim_isprintc_strict(key))
4778 {
4779 int valid = 1;
4780 char_u mac_mods = kMenuNoModifiers;
4781 /* Convert Vim modifier codes to Menu Manager equivalents. */
4782 if (modifiers & MOD_MASK_SHIFT)
4783 mac_mods |= kMenuShiftModifier;
4784 if (modifiers & MOD_MASK_CTRL)
4785 mac_mods |= kMenuControlModifier;
4786 if (!(modifiers & MOD_MASK_CMD))
4787 mac_mods |= kMenuNoCommandModifier;
4788 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4789 valid = 0; /* TODO: will Alt someday map to Option? */
4790 if (valid)
4791 {
4792 char_u item_txt[10];
4793 /* Insert the menu item after idx, with its command key. */
4794 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4795 item_txt[3] = key;
4796 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4797 /* Set the modifier keys. */
4798 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4799 menu_inserted = 1;
4800 }
4801 }
4802 }
4803 /* Call InsertMenuItem followed by SetMenuItemText
4804 * to avoid special character recognition by InsertMenuItem
4805 */
4806 if (!menu_inserted)
4807 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4808 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004809#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004810 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4811#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004812 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004813#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814
4815#if 0
4816 /* Called by Vim */
4817 DrawMenuBar();
4818#endif
4819
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004820#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004821 CFRelease(name);
4822#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 /* TODO: Can name be freed? */
4824 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004825#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826}
4827
4828 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004829gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830{
4831 /* no tearoff menus */
4832}
4833
4834/*
4835 * Destroy the machine specific menu widget.
4836 */
4837 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004838gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004840 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004841
4842 if (index > 0)
4843 {
4844 if (menu->parent)
4845 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 {
4847 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004848 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849
4850 /* Delete the Menu if it was a hierarchical Menu */
4851 if (menu->submenu_id != 0)
4852 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004853 DeleteMenu(menu->submenu_id);
4854 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855 }
4856 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004857 }
4858#ifdef DEBUG_MAC_MENU
4859 else
4860 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004861 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 }
4863#endif
4864 }
4865 else
4866 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004868 DeleteMenu(menu->submenu_id);
4869 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 }
4871 }
4872 /* Shouldn't this be already done by Vim. TODO: Check */
4873 DrawMenuBar();
4874}
4875
4876/*
4877 * Make a menu either grey or not grey.
4878 */
4879 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004880gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881{
4882 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004883 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884/*
4885 index = menu->index;
4886*/
4887 if (grey)
4888 {
4889 if (menu->children)
4890 DisableMenuItem(menu->submenu_handle, index);
4891 if (menu->parent)
4892 if (menu->parent->submenu_handle)
4893 DisableMenuItem(menu->parent->submenu_handle, index);
4894 }
4895 else
4896 {
4897 if (menu->children)
4898 EnableMenuItem(menu->submenu_handle, index);
4899 if (menu->parent)
4900 if (menu->parent->submenu_handle)
4901 EnableMenuItem(menu->parent->submenu_handle, index);
4902 }
4903}
4904
4905/*
4906 * Make menu item hidden or not hidden
4907 */
4908 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004909gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910{
4911 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004912 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913}
4914
4915
4916/*
4917 * This is called after setting all the menus to grey/hidden or not.
4918 */
4919 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004920gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921{
4922 DrawMenuBar();
4923}
4924
4925
4926/*
4927 * Scrollbar stuff.
4928 */
4929
4930 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004931gui_mch_enable_scrollbar(
4932 scrollbar_T *sb,
4933 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934{
4935 if (flag)
4936 ShowControl(sb->id);
4937 else
4938 HideControl(sb->id);
4939
4940#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004941 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942#endif
4943}
4944
4945 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004946gui_mch_set_scrollbar_thumb(
4947 scrollbar_T *sb,
4948 long val,
4949 long size,
4950 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951{
4952 SetControl32BitMaximum (sb->id, max);
4953 SetControl32BitMinimum (sb->id, 0);
4954 SetControl32BitValue (sb->id, val);
4955#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004956 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957#endif
4958}
4959
4960 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004961gui_mch_set_scrollbar_pos(
4962 scrollbar_T *sb,
4963 int x,
4964 int y,
4965 int w,
4966 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967{
4968 gui_mch_set_bg_color(gui.back_pixel);
4969/* if (gui.which_scrollbars[SBAR_LEFT])
4970 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004971 MoveControl(sb->id, x-16, y);
4972 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973 }
4974 else
4975 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004976 MoveControl(sb->id, x, y);
4977 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 }*/
4979 if (sb == &gui.bottom_sbar)
4980 h += 1;
4981 else
4982 w += 1;
4983
4984 if (gui.which_scrollbars[SBAR_LEFT])
4985 x -= 15;
4986
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004987 MoveControl(sb->id, x, y);
4988 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004990 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991#endif
4992}
4993
4994 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004995gui_mch_create_scrollbar(
4996 scrollbar_T *sb,
4997 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004998{
4999 Rect bounds;
5000
5001 bounds.top = -16;
5002 bounds.bottom = -10;
5003 bounds.right = -10;
5004 bounds.left = -16;
5005
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005006 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 &bounds,
5008 "\pScrollBar",
5009 TRUE,
5010 0, /* current*/
5011 0, /* top */
5012 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 (long) sb->ident);
5015#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005016 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017#endif
5018}
5019
5020 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005021gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005022{
5023 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005024 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005026 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027#endif
5028}
5029
5030
5031/*
5032 * Cursor blink functions.
5033 *
5034 * This is a simple state machine:
5035 * BLINK_NONE not blinking at all
5036 * BLINK_OFF blinking, cursor is not shown
5037 * BLINK_ON blinking, cursor is shown
5038 */
5039 void
5040gui_mch_set_blinking(long wait, long on, long off)
5041{
5042 /* TODO: TODO: TODO: TODO: */
5043/* blink_waittime = wait;
5044 blink_ontime = on;
5045 blink_offtime = off;*/
5046}
5047
5048/*
5049 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5050 */
5051 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005052gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053{
5054 gui_update_cursor(TRUE, FALSE);
5055 /* TODO: TODO: TODO: TODO: */
5056/* gui_w32_rm_blink_timer();
5057 if (blink_state == BLINK_OFF)
5058 gui_update_cursor(TRUE, FALSE);
5059 blink_state = BLINK_NONE;*/
5060}
5061
5062/*
5063 * Start the cursor blinking. If it was already blinking, this restarts the
5064 * waiting time and shows the cursor.
5065 */
5066 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005067gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068{
5069 gui_update_cursor(TRUE, FALSE);
5070 /* TODO: TODO: TODO: TODO: */
5071/* gui_w32_rm_blink_timer(); */
5072
5073 /* Only switch blinking on if none of the times is zero */
5074/* if (blink_waittime && blink_ontime && blink_offtime)
5075 {
5076 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5077 (TIMERPROC)_OnBlinkTimer);
5078 blink_state = BLINK_ON;
5079 gui_update_cursor(TRUE, FALSE);
5080 }*/
5081}
5082
5083/*
5084 * Return the RGB value of a pixel as long.
5085 */
5086 long_u
5087gui_mch_get_rgb(guicolor_T pixel)
5088{
5089 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5090}
5091
5092
5093
5094#ifdef FEAT_BROWSE
5095/*
5096 * Pop open a file browser and return the file selected, in allocated memory,
5097 * or NULL if Cancel is hit.
5098 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5099 * title - Title message for the file browser dialog.
5100 * dflt - Default name of file.
5101 * ext - Default extension to be added to files without extensions.
5102 * initdir - directory in which to open the browser (NULL = current dir)
5103 * filter - Filter for matched files to choose from.
5104 * Has a format like this:
5105 * "C Files (*.c)\0*.c\0"
5106 * "All Files\0*.*\0\0"
5107 * If these two strings were concatenated, then a choice of two file
5108 * filters will be selectable to the user. Then only matching files will
5109 * be shown in the browser. If NULL, the default allows all files.
5110 *
5111 * *NOTE* - the filter string must be terminated with TWO nulls.
5112 */
5113 char_u *
5114gui_mch_browse(
5115 int saving,
5116 char_u *title,
5117 char_u *dflt,
5118 char_u *ext,
5119 char_u *initdir,
5120 char_u *filter)
5121{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122 /* TODO: Add Ammon's safety checl (Dany) */
5123 NavReplyRecord reply;
5124 char_u *fname = NULL;
5125 char_u **fnames = NULL;
5126 long numFiles;
5127 NavDialogOptions navOptions;
5128 OSErr error;
5129
5130 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005131 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132
5133
5134 /* TODO: If we get a :browse args, set the Multiple bit. */
5135 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5136 | kNavDontAutoTranslate
5137 | kNavDontAddTranslateItems
5138 /* | kNavAllowMultipleFiles */
5139 | kNavAllowStationery;
5140
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005141 (void) C2PascalString(title, &navOptions.message);
5142 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 /* Could set clientName?
5144 * windowTitle? (there's no title bar?)
5145 */
5146
5147 if (saving)
5148 {
5149 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005150 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005151 if (!reply.validRecord)
5152 return NULL;
5153 }
5154 else
5155 {
5156 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5157 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5158 if (!reply.validRecord)
5159 return NULL;
5160 }
5161
5162 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5163
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005164 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005165
5166 if (fnames)
5167 {
5168 fname = fnames[0];
5169 vim_free(fnames);
5170 }
5171
5172 /* TODO: Shorten the file name if possible */
5173 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174}
5175#endif /* FEAT_BROWSE */
5176
5177#ifdef FEAT_GUI_DIALOG
5178/*
5179 * Stuff for dialogues
5180 */
5181
5182/*
5183 * Create a dialogue dynamically from the parameter strings.
5184 * type = type of dialogue (question, alert, etc.)
5185 * title = dialogue title. may be NULL for default title.
5186 * message = text to display. Dialogue sizes to accommodate it.
5187 * buttons = '\n' separated list of button captions, default first.
5188 * dfltbutton = number of default button.
5189 *
5190 * This routine returns 1 if the first button is pressed,
5191 * 2 for the second, etc.
5192 *
5193 * 0 indicates Esc was pressed.
5194 * -1 for unexpected error
5195 *
5196 * If stubbing out this fn, return 1.
5197 */
5198
5199typedef struct
5200{
5201 short idx;
5202 short width; /* Size of the text in pixel */
5203 Rect box;
5204} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5205
5206#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5207
5208 static void
5209macMoveDialogItem(
5210 DialogRef theDialog,
5211 short itemNumber,
5212 short X,
5213 short Y,
5214 Rect *inBox)
5215{
5216#if 0 /* USE_CARBONIZED */
5217 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005218 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005220 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221#else
5222 short itemType;
5223 Handle itemHandle;
5224 Rect localBox;
5225 Rect *itemBox = &localBox;
5226
5227 if (inBox != nil)
5228 itemBox = inBox;
5229
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005230 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5231 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5232 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233 /* To move a control (like a button) we need to call both
5234 * MoveControl and SetDialogItem. FAQ 6-18 */
5235 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005236 MoveControl((ControlRef) itemHandle, X, Y);
5237 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005238#endif
5239}
5240
5241 static void
5242macSizeDialogItem(
5243 DialogRef theDialog,
5244 short itemNumber,
5245 short width,
5246 short height)
5247{
5248 short itemType;
5249 Handle itemHandle;
5250 Rect itemBox;
5251
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005252 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253
5254 /* When width or height is zero do not change it */
5255 if (width == 0)
5256 width = itemBox.right - itemBox.left;
5257 if (height == 0)
5258 height = itemBox.bottom - itemBox.top;
5259
5260#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005261 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005262#else
5263 /* Resize the bounding box */
5264 itemBox.right = itemBox.left + width;
5265 itemBox.bottom = itemBox.top + height;
5266
5267 /* To resize a control (like a button) we need to call both
5268 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5269 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005270 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271
5272 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005273 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274#endif
5275}
5276
5277 static void
5278macSetDialogItemText(
5279 DialogRef theDialog,
5280 short itemNumber,
5281 Str255 itemName)
5282{
5283 short itemType;
5284 Handle itemHandle;
5285 Rect itemBox;
5286
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005287 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288
5289 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005290 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005292 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293}
5294
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005295/* TODO: There have been some crashes with dialogs, check your inbox
5296 * (Jussi)
5297 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005298 int
5299gui_mch_dialog(
5300 int type,
5301 char_u *title,
5302 char_u *message,
5303 char_u *buttons,
5304 int dfltbutton,
5305 char_u *textfield)
5306{
5307 Handle buttonDITL;
5308 Handle iconDITL;
5309 Handle inputDITL;
5310 Handle messageDITL;
5311 Handle itemHandle;
5312 Handle iconHandle;
5313 DialogPtr theDialog;
5314 char_u len;
5315 char_u PascalTitle[256]; /* place holder for the title */
5316 char_u name[256];
5317 GrafPtr oldPort;
5318 short itemHit;
5319 char_u *buttonChar;
5320 Rect box;
5321 short button;
5322 short lastButton;
5323 short itemType;
5324 short useIcon;
5325 short width;
5326 short totalButtonWidth = 0; /* the width of all button together incuding spacing */
5327 short widestButton = 0;
5328 short dfltButtonEdge = 20; /* gut feeling */
5329 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5330 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5331 short maximumWidth = 400; /* gut feeling */
5332 short maxButtonWidth = 175; /* gut feeling */
5333
5334 short vertical;
5335 short dialogHeight;
5336 short messageLines = 3;
5337 FontInfo textFontInfo;
5338
5339 vgmDlgItm iconItm;
5340 vgmDlgItm messageItm;
5341 vgmDlgItm inputItm;
5342 vgmDlgItm buttonItm;
5343
5344 WindowRef theWindow;
5345
5346 /* Check 'v' flag in 'guioptions': vertical button placement. */
5347 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5348
5349 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005350 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005351
5352 /* Get the WindowRef */
5353 theWindow = GetDialogWindow(theDialog);
5354
5355 /* Hide the window.
5356 * 1. to avoid seeing slow drawing
5357 * 2. to prevent a problem seen while moving dialog item
5358 * within a visible window. (non-Carbon MacOS 9)
5359 * Could be avoided by changing the resource.
5360 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005361 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005362
5363 /* Change the graphical port to the dialog,
5364 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005365 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005366 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005367
5368 /* Get the info about the default text,
5369 * used to calculate the height of the message
5370 * and of the text field */
5371 GetFontInfo(&textFontInfo);
5372
5373 /* Set the dialog title */
5374 if (title != NULL)
5375 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005376 (void) C2PascalString(title, &PascalTitle);
5377 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 }
5379
5380 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005381 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382 buttonChar = buttons;
5383 button = 0;
5384
5385 for (;*buttonChar != 0;)
5386 {
5387 /* Get the name of the button */
5388 button++;
5389 len = 0;
5390 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5391 {
5392 if (*buttonChar != DLG_HOTKEY_CHAR)
5393 name[++len] = *buttonChar;
5394 }
5395 if (*buttonChar != 0)
5396 buttonChar++;
5397 name[0] = len;
5398
5399 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005400 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005401
5402 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005403 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005404
5405 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005406 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 /* Limite the size of any button to an acceptable value. */
5408 /* TODO: Should be based on the message width */
5409 if (width > maxButtonWidth)
5410 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005411 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005412
5413 totalButtonWidth += width;
5414
5415 if (width > widestButton)
5416 widestButton = width;
5417 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005418 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419 lastButton = button;
5420
5421 /* Add the icon to the Dialog Box. */
5422 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005423 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005424 switch (type)
5425 {
5426 case VIM_GENERIC: useIcon = kNoteIcon;
5427 case VIM_ERROR: useIcon = kStopIcon;
5428 case VIM_WARNING: useIcon = kCautionIcon;
5429 case VIM_INFO: useIcon = kNoteIcon;
5430 case VIM_QUESTION: useIcon = kNoteIcon;
5431 default: useIcon = kStopIcon;
5432 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005433 AppendDITL(theDialog, iconDITL, overlayDITL);
5434 ReleaseResource(iconDITL);
5435 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005436 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005437 iconHandle = GetIcon(useIcon);
5438 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439
5440 /* Add the message to the Dialog box. */
5441 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005442 messageDITL = GetResource('DITL', 132);
5443 AppendDITL(theDialog, messageDITL, overlayDITL);
5444 ReleaseResource(messageDITL);
5445 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5446 (void) C2PascalString(message, &name);
5447 SetDialogItemText(itemHandle, name);
5448 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449
5450 /* Add the input box if needed */
5451 if (textfield != NULL)
5452 {
5453 /* Cheat for now reuse the message and convet to text edit */
5454 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005455 inputDITL = GetResource('DITL', 132);
5456 AppendDITL(theDialog, inputDITL, overlayDITL);
5457 ReleaseResource(inputDITL);
5458 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5459/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5460 (void) C2PascalString(textfield, &name);
5461 SetDialogItemText(itemHandle, name);
5462 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 }
5464
5465 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005466 SetDialogDefaultItem(theDialog, dfltbutton);
5467 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468
5469 /* Reposition element */
5470
5471 /* Check if we need to force vertical */
5472 if (totalButtonWidth > maximumWidth)
5473 vertical = TRUE;
5474
5475 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005476 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005477 iconItm.box.right = box.right;
5478 iconItm.box.bottom = box.bottom;
5479
5480 /* Place Message */
5481 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005482 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5483 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484
5485 /* Place Input */
5486 if (textfield != NULL)
5487 {
5488 inputItm.box.left = messageItm.box.left;
5489 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005490 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5491 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005492 /* Convert the static text into a text edit.
5493 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005494 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5495 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005496 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5497 }
5498
5499 /* Place Button */
5500 if (textfield != NULL)
5501 {
5502 buttonItm.box.left = inputItm.box.left;
5503 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5504 }
5505 else
5506 {
5507 buttonItm.box.left = messageItm.box.left;
5508 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5509 }
5510
5511 for (button=1; button <= lastButton; button++)
5512 {
5513
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005514 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515 /* With vertical, it's better to have all button the same lenght */
5516 if (vertical)
5517 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005518 macSizeDialogItem(theDialog, button, widestButton, 0);
5519 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520 }
5521 /* Calculate position of next button */
5522 if (vertical)
5523 buttonItm.box.top = box.bottom + dfltElementSpacing;
5524 else
5525 buttonItm.box.left = box.right + dfltElementSpacing;
5526 }
5527
5528 /* Resize the dialog box */
5529 dialogHeight = box.bottom + dfltElementSpacing;
5530 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5531
Bram Moolenaar071d4272004-06-13 20:20:40 +00005532 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005533 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005535
5536 /* Display it */
5537 ShowWindow(theWindow);
5538/* BringToFront(theWindow); */
5539 SelectWindow(theWindow);
5540
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005541/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005542#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005543 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005544 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545#endif
5546
5547 /* Hang until one of the button is hit */
5548 do
5549 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005550 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005551 } while ((itemHit < 1) || (itemHit > lastButton));
5552
5553 /* Copy back the text entered by the user into the param */
5554 if (textfield != NULL)
5555 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005556 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5557 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005558#if IOSIZE < 256
5559 /* Truncate the name to IOSIZE if needed */
5560 if (name[0] > IOSIZE)
5561 name[0] = IOSIZE - 1;
5562#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005563 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005564 }
5565
5566 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005567 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005568
5569 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005570 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571
5572 return itemHit;
5573/*
5574 * Usefull thing which could be used
5575 * SetDialogTimeout(): Auto click a button after timeout
5576 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5577 * MoveDialogItem(): Probably better than SetDialogItem
5578 * SizeDialogItem(): (but is it Carbon Only?)
5579 * AutoSizeDialog(): Magic resize of dialog based on text lenght
5580 */
5581}
5582#endif /* FEAT_DIALOG_GUI */
5583
5584/*
5585 * Display the saved error message(s).
5586 */
5587#ifdef USE_MCH_ERRMSG
5588 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005589display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005590{
5591 char *p;
5592 char_u pError[256];
5593
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005594 if (error_ga.ga_data == NULL)
5595 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005597 /* avoid putting up a message box with blanks only */
5598 for (p = (char *)error_ga.ga_data; *p; ++p)
5599 if (!isspace(*p))
5600 {
5601 if (STRLEN(p) > 255)
5602 pError[0] = 255;
5603 else
5604 pError[0] = STRLEN(p);
5605
5606 STRNCPY(&pError[1], p, pError[0]);
5607 ParamText(pError, nil, nil, nil);
5608 Alert(128, nil);
5609 break;
5610 /* TODO: handled message longer than 256 chars
5611 * use auto-sizeable alert
5612 * or dialog with scrollbars (TextEdit zone)
5613 */
5614 }
5615 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005616}
5617#endif
5618
5619/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005620 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005622 void
5623gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624{
5625 Point where;
5626
5627 GetMouse(&where);
5628
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005629 *x = where.h;
5630 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005631}
5632
5633 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005634gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005635{
5636 /* TODO */
5637#if 0
5638 /* From FAQ 3-11 */
5639
5640 CursorDevicePtr myMouse;
5641 Point where;
5642
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005643 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5644 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645 {
5646 /* New way */
5647
5648 /*
5649 * Get first devoice with one button.
5650 * This will probably be the standad mouse
5651 * startat head of cursor dev list
5652 *
5653 */
5654
5655 myMouse = nil;
5656
5657 do
5658 {
5659 /* Get the next cursor device */
5660 CursorDeviceNextDevice(&myMouse);
5661 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005662 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005663
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005664 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665 }
5666 else
5667 {
5668 /* Old way */
5669 where.h = x;
5670 where.v = y;
5671
5672 *(Point *)RawMouse = where;
5673 *(Point *)MTemp = where;
5674 *(Ptr) CrsrNew = 0xFFFF;
5675 }
5676#endif
5677}
5678
5679 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005680gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005681{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682/*
5683 * Clone PopUp to use menu
5684 * Create a object descriptor for the current selection
5685 * Call the procedure
5686 */
5687
5688 MenuHandle CntxMenu;
5689 Point where;
5690 OSStatus status;
5691 UInt32 CntxType;
5692 SInt16 CntxMenuID;
5693 UInt16 CntxMenuItem;
5694 Str255 HelpName = "";
5695 GrafPtr savePort;
5696
5697 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005698 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005700 GetMouse(&where);
5701 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005702 CntxMenu = menu->submenu_handle;
5703
5704 /* TODO: Get the text selection from Vim */
5705
5706 /* Call to Handle Popup */
5707 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemNoHelp, HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
5708
5709 if (status == noErr)
5710 {
5711 if (CntxType == kCMMenuItemSelected)
5712 {
5713 /* Handle the menu CntxMenuID, CntxMenuItem */
5714 /* The submenu can be handle directly by gui_mac_handle_menu */
5715 /* But what about the current menu, is the menu changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005716 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005717 }
5718 else if (CntxMenuID == kCMShowHelpSelected)
5719 {
5720 /* Should come up with the help */
5721 }
5722 }
5723
5724 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005725 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005726}
5727
5728#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5729/* TODO: Is it need for MACOS_X? (Dany) */
5730 void
5731mch_post_buffer_write(buf_T *buf)
5732{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005733 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5734 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735}
5736#endif
5737
5738#ifdef FEAT_TITLE
5739/*
5740 * Set the window title and icon.
5741 * (The icon is not taken care of).
5742 */
5743 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005744gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005745{
5746 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5747 * that 256. Even better get it to fit nicely in the titlebar.
5748 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005749#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005750 CFStringRef windowTitle;
5751 size_t windowTitleLen;
5752#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005753 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005754#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005755
5756 if (title == NULL) /* nothing to do */
5757 return;
5758
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005759#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005760 windowTitleLen = STRLEN(title);
5761 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
5762
5763 if (windowTitle)
5764 {
5765 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5766 CFRelease(windowTitle);
5767 }
5768#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005769 pascalTitle = C2Pascal_save(title);
5770 if (pascalTitle != NULL)
5771 {
5772 SetWTitle(gui.VimWindow, pascalTitle);
5773 vim_free(pascalTitle);
5774 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005775#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776}
5777#endif
5778
5779/*
5780 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5781 */
5782
5783 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005784C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005785{
5786 char_u *PascalPtr = (char_u *) PascalString;
5787 int len;
5788 int i;
5789
5790 PascalPtr[0] = 0;
5791 if (CString == NULL)
5792 return 0;
5793
5794 len = STRLEN(CString);
5795 if (len > 255)
5796 len = 255;
5797
5798 for (i = 0; i < len; i++)
5799 PascalPtr[i+1] = CString[i];
5800
5801 PascalPtr[0] = len;
5802
5803 return 0;
5804}
5805
5806 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005807GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005808{
5809 /* From FAQ 8-12 */
5810 Str255 filePascal;
5811 CInfoPBRec myCPB;
5812 OSErr err;
5813
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005814 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815
5816 myCPB.dirInfo.ioNamePtr = filePascal;
5817 myCPB.dirInfo.ioVRefNum = 0;
5818 myCPB.dirInfo.ioFDirIndex = 0;
5819 myCPB.dirInfo.ioDrDirID = 0;
5820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005821 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822
5823 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005824 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825
5826 /* TODO: Use an error code mechanism */
5827 return 0;
5828}
5829
5830/*
5831 * Convert a FSSpec to a fuill path
5832 */
5833
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005834char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835{
5836 /*
5837 * TODO: Add protection for 256 char max.
5838 */
5839
5840 CInfoPBRec theCPB;
5841 char_u fname[256];
5842 char_u *filenamePtr = fname;
5843 OSErr error;
5844 int folder = 1;
5845#ifdef USE_UNIXFILENAME
5846 SInt16 dfltVol_vRefNum;
5847 SInt32 dfltVol_dirID;
5848 FSRef refFile;
5849 OSStatus status;
5850 UInt32 pathSize = 256;
5851 char_u pathname[256];
5852 char_u *path = pathname;
5853#else
5854 Str255 directoryName;
5855 char_u temporary[255];
5856 char_u *temporaryPtr = temporary;
5857#endif
5858
5859#ifdef USE_UNIXFILENAME
5860 /* Get the default volume */
5861 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005862 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863
5864 if (error)
5865 return NULL;
5866#endif
5867
5868 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005869 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870
5871 /* Get the info about the file specified in FSSpec */
5872 theCPB.dirInfo.ioFDirIndex = 0;
5873 theCPB.dirInfo.ioNamePtr = file.name;
5874 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5875 /*theCPB.hFileInfo.ioDirID = 0;*/
5876 theCPB.dirInfo.ioDrDirID = file.parID;
5877
5878 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5879 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005880 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005881
5882 /* If we are called for a new file we expect fnfErr */
5883 if ((error) && (error != fnfErr))
5884 return NULL;
5885
5886 /* Check if it's a file or folder */
5887 /* default to file if file don't exist */
5888 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
5889 folder = 0; /* It's not a folder */
5890 else
5891 folder = 1;
5892
5893#ifdef USE_UNIXFILENAME
5894 /*
5895 * The function used here are available in Carbon, but
5896 * do nothing une MacOS 8 and 9
5897 */
5898 if (error == fnfErr)
5899 {
5900 /* If the file to be saved does not already exist, it isn't possible
5901 to convert its FSSpec into an FSRef. But we can construct an
5902 FSSpec for the file's parent folder (since we have its volume and
5903 directory IDs), and since that folder does exist, we can convert
5904 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5905 and, finally, append the filename. */
5906 FSSpec dirSpec;
5907 FSRef dirRef;
5908 Str255 emptyFilename = "\p";
5909 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
5910 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
5911 if (error)
5912 return NULL;
5913
5914 error = FSpMakeFSRef(&dirSpec, &dirRef);
5915 if (error)
5916 return NULL;
5917
5918 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
5919 if (status)
5920 return NULL;
5921
5922 STRCAT(path, "/");
5923 STRCAT(path, filenamePtr);
5924 }
5925 else
5926 {
5927 /* If the file to be saved already exists, we can get its full path
5928 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005929 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930 if (error)
5931 return NULL;
5932
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005933 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934 if (status)
5935 return NULL;
5936 }
5937
5938 /* Add a slash at the end if needed */
5939 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005940 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005942 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943#else
5944 /* TODO: Get rid of all USE_UNIXFILENAME below */
5945 /* Set ioNamePtr, it's the same area which is always reused. */
5946 theCPB.dirInfo.ioNamePtr = directoryName;
5947
5948 /* Trick for first entry, set ioDrParID to the first value
5949 * we want for ioDrDirID*/
5950 theCPB.dirInfo.ioDrParID = file.parID;
5951 theCPB.dirInfo.ioDrDirID = file.parID;
5952
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005953 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005954 do
5955 {
5956 theCPB.dirInfo.ioFDirIndex = -1;
5957 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5958 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5959 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
5960 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5961
5962 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5963 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005964 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965
5966 if (error)
5967 return NULL;
5968
5969 /* Put the new directoryName in front of the current fname */
5970 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005971 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005972 STRCAT(filenamePtr, ":");
5973 STRCAT(filenamePtr, temporaryPtr);
5974 }
5975#if 1 /* def USE_UNIXFILENAME */
5976 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
5977 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5978#else
5979 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
5980#endif
5981
5982 /* Get the information about the volume on which the file reside */
5983 theCPB.dirInfo.ioFDirIndex = -1;
5984 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5985 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5986 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
5987 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5988
5989 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5990 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005991 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992
5993 if (error)
5994 return NULL;
5995
5996 /* For MacOS Classic always add the volume name */
5997 /* For MacOS X add the volume name preceded by "Volumes" */
5998 /* when we are not refering to the boot volume */
5999#ifdef USE_UNIXFILENAME
6000 if (file.vRefNum != dfltVol_vRefNum)
6001#endif
6002 {
6003 /* Add the volume name */
6004 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006005 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006006 STRCAT(filenamePtr, ":");
6007 STRCAT(filenamePtr, temporaryPtr);
6008
6009#ifdef USE_UNIXFILENAME
6010 STRCPY(temporaryPtr, filenamePtr);
6011 filenamePtr[0] = 0; /* NULL terminate the string */
6012 STRCAT(filenamePtr, "Volumes:");
6013 STRCAT(filenamePtr, temporaryPtr);
6014#endif
6015 }
6016
6017 /* Append final path separator if it's a folder */
6018 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006019 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020
6021 /* As we use Unix File Name for MacOS X convert it */
6022#ifdef USE_UNIXFILENAME
6023 /* Need to insert leading / */
6024 /* TODO: get the above code to use directly the / */
6025 STRCPY(&temporaryPtr[1], filenamePtr);
6026 temporaryPtr[0] = '/';
6027 STRCPY(filenamePtr, temporaryPtr);
6028 {
6029 char *p;
6030 for (p = fname; *p; p++)
6031 if (*p == ':')
6032 *p = '/';
6033 }
6034#endif
6035
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006036 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006037#endif
6038}
6039
6040#if defined(USE_IM_CONTROL) || defined(PROTO)
6041/*
6042 * Input Method Control functions.
6043 */
6044
6045/*
6046 * Notify cursor position to IM.
6047 */
6048 void
6049im_set_position(int row, int col)
6050{
6051 /* TODO: Implement me! */
6052}
6053
6054/*
6055 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6056 */
6057 void
6058im_set_active(int active)
6059{
6060 KeyScript(active ? smKeySysScript : smKeyRoman);
6061}
6062
6063/*
6064 * Get IM status. When IM is on, return not 0. Else return 0.
6065 */
6066 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006067im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068{
6069 SInt32 script = GetScriptManagerVariable(smKeyScript);
6070 return (script != smRoman
6071 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6072}
6073#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */