blob: d9bb609999dc3f97c5c79fa9d52f364ca82d7af3 [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 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001069
1070 /* Change directory to the location of the first file. */
1071 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1072 shorten_fnames(TRUE);
1073
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 goto finished;
1075 }
1076
1077 /* Handle the drop, :edit to get to the file */
1078 handle_drop(numFiles, fnames, FALSE);
1079
1080 /* TODO: Handle the goto/select line more cleanly */
1081 if ((numFiles == 1) & (gotPosition))
1082 {
1083 if (thePosition.lineNum >= 0)
1084 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001085 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 /* oap->motion_type = MLINE;
1087 setpcmark();*/
1088 if (lnum < 1L)
1089 lnum = 1L;
1090 else if (lnum > curbuf->b_ml.ml_line_count)
1091 lnum = curbuf->b_ml.ml_line_count;
1092 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001093 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 /* beginline(BL_SOL | BL_FIX);*/
1095 }
1096 else
1097 goto_byte(thePosition.startRange + 1);
1098 }
1099
1100 /* Update the screen display */
1101 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001102#ifdef FEAT_VISUAL
1103 /* Select the text if possible */
1104 if (gotPosition)
1105 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001106 VIsual_active = TRUE;
1107 VIsual_select = FALSE;
1108 VIsual = curwin->w_cursor;
1109 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001110 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001111 VIsual_mode = 'v';
1112 goto_byte(thePosition.endRange);
1113 }
1114 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001115 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001116 VIsual_mode = 'V';
1117 VIsual.col = 0;
1118 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001119 }
1120#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 setcursor();
1122 out_flush();
1123
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001124 /* Fake mouse event to wake from stall */
1125 PostEvent(mouseUp, 0);
1126
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 finished:
1128 AEDisposeDesc(&theList); /* dispose what we allocated */
1129
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001130 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 if (error)
1132 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 return(error);
1134 }
1135 return(error);
1136}
1137
1138/*
1139 *
1140 */
1141
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001142 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001143Handle_aevt_oapp_AE(
1144 const AppleEvent *theAEvent,
1145 AppleEvent *theReply,
1146 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147{
1148 OSErr error = noErr;
1149
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001150 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 if (error)
1152 {
1153 return(error);
1154 }
1155
1156 return(error);
1157}
1158
1159/*
1160 *
1161 */
1162
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001163 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001164Handle_aevt_quit_AE(
1165 const AppleEvent *theAEvent,
1166 AppleEvent *theReply,
1167 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168{
1169 OSErr error = noErr;
1170
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001171 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 if (error)
1173 {
1174 return(error);
1175 }
1176
1177 /* Need to fake a :confirm qa */
1178 do_cmdline_cmd((char_u *)"confirm qa");
1179
1180 return(error);
1181}
1182
1183/*
1184 *
1185 */
1186
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001187 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001188Handle_aevt_pdoc_AE(
1189 const AppleEvent *theAEvent,
1190 AppleEvent *theReply,
1191 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192{
1193 OSErr error = noErr;
1194
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001195 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 if (error)
1197 {
1198 return(error);
1199 }
1200
1201 return(error);
1202}
1203
1204/*
1205 * Handling of unknown AppleEvent
1206 *
1207 * (Just get rid of all the parms)
1208 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001209 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001210Handle_unknown_AE(
1211 const AppleEvent *theAEvent,
1212 AppleEvent *theReply,
1213 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214{
1215 OSErr error = noErr;
1216
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001217 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218 if (error)
1219 {
1220 return(error);
1221 }
1222
1223 return(error);
1224}
1225
1226
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227/*
1228 * Install the various AppleEvent Handlers
1229 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001230 OSErr
1231InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001232{
1233 OSErr error;
1234
1235 /* install open application handler */
1236 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001237 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 if (error)
1239 {
1240 return error;
1241 }
1242
1243 /* install quit application handler */
1244 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001245 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246 if (error)
1247 {
1248 return error;
1249 }
1250
1251 /* install open document handler */
1252 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001253 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 if (error)
1255 {
1256 return error;
1257 }
1258
1259 /* install print document handler */
1260 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001261 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262
1263/* Install Core Suite */
1264/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001265 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266
1267 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001268 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269
1270 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001271 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272
1273 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001274 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275
1276 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001277 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001278
1279 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001280 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281
1282 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001283 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284
1285 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001286 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287
1288 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001289 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290
1291 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001292 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293
1294 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001295 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296
1297 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001298 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299
1300 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001301 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302*/
1303
1304#ifdef FEAT_CW_EDITOR
1305 /*
1306 * Bind codewarrior support handlers
1307 */
1308 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001309 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 if (error)
1311 {
1312 return error;
1313 }
1314 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001315 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316 if (error)
1317 {
1318 return error;
1319 }
1320 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001321 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322 if (error)
1323 {
1324 return error;
1325 }
1326#endif
1327
1328 return error;
1329
1330}
1331#endif /* USE_AEVENT */
1332
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001333
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001334/*
1335 * Callback function, installed by InstallFontPanelHandler(), below,
1336 * to handle Font Panel events.
1337 */
1338 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001339FontPanelHandler(
1340 EventHandlerCallRef inHandlerCallRef,
1341 EventRef inEvent,
1342 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001343{
1344 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1345 {
1346 gFontPanelInfo.isPanelVisible = false;
1347 return noErr;
1348 }
1349
1350 if (GetEventKind(inEvent) == kEventFontSelection)
1351 {
1352 OSStatus status;
1353 FMFontFamily newFamily;
1354 FMFontSize newSize;
1355 FMFontStyle newStyle;
1356
1357 /* Retrieve the font family ID number. */
1358 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1359 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1360 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1361 &newFamily);
1362 if (status == noErr)
1363 gFontPanelInfo.family = newFamily;
1364
1365 /* Retrieve the font size. */
1366 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1367 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1368 if (status == noErr)
1369 gFontPanelInfo.size = newSize;
1370
1371 /* Retrieve the font style (bold, etc.). Currently unused. */
1372 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1373 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1374 if (status == noErr)
1375 gFontPanelInfo.style = newStyle;
1376 }
1377 return noErr;
1378}
1379
1380
1381 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001382InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001383{
1384 EventTypeSpec eventTypes[2];
1385 EventHandlerUPP handlerUPP;
1386 /* EventHandlerRef handlerRef; */
1387
1388 eventTypes[0].eventClass = kEventClassFont;
1389 eventTypes[0].eventKind = kEventFontSelection;
1390 eventTypes[1].eventClass = kEventClassFont;
1391 eventTypes[1].eventKind = kEventFontPanelClosed;
1392
1393 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1394
1395 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1396 /*userData=*/NULL, /*handlerRef=*/NULL);
1397}
1398
1399
1400/*
1401 * Fill the buffer pointed to by outName with the name and size
1402 * of the font currently selected in the Font Panel.
1403 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001404#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001405 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001406GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001407{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001408 Str255 buf;
1409 ByteCount fontNameLen = 0;
1410 ATSUFontID fid;
1411 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001412
1413 if (!outName)
1414 return;
1415
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001416 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1417 {
1418 /* Canonicalize localized font names */
1419 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1420 gFontPanelInfo.style, &fid, NULL) != noErr)
1421 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001422
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423 /* Request font name with Mac encoding (otherwise we could
1424 * get an unwanted utf-16 name) */
1425 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1426 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001427 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001429
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001430 /* Only encode font size, because style (bold, italic, etc) is
1431 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001432 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001433 gFontPanelInfo.size/*,
1434 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1435 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1436 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1437
1438 if ((fontNameLen + STRLEN(styleString)) < 255)
1439 STRCPY(outName + fontNameLen, styleString);
1440 }
1441 else
1442 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001443 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001444 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001445}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001446
1447
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448/*
1449 * ------------------------------------------------------------
1450 * Unfiled yet
1451 * ------------------------------------------------------------
1452 */
1453
1454/*
1455 * gui_mac_get_menu_item_index
1456 *
1457 * Returns the index inside the menu wher
1458 */
1459 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001460gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461{
1462 short index;
1463 short itemIndex = -1;
1464 vimmenu_T *pBrother;
1465
1466 /* Only menu without parent are the:
1467 * -menu in the menubar
1468 * -popup menu
1469 * -toolbar (guess)
1470 *
1471 * Which are not items anyway.
1472 */
1473 if (pMenu->parent)
1474 {
1475 /* Start from the Oldest Brother */
1476 pBrother = pMenu->parent->children;
1477 index = 1;
1478 while ((pBrother) && (itemIndex == -1))
1479 {
1480 if (pBrother == pMenu)
1481 itemIndex = index;
1482 index++;
1483 pBrother = pBrother->next;
1484 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485 }
1486 return itemIndex;
1487}
1488
1489 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001490gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491{
1492 short index;
1493 vimmenu_T *pChildMenu;
1494 vimmenu_T *pElder = pMenu->parent;
1495
1496
1497 /* Only menu without parent are the:
1498 * -menu in the menubar
1499 * -popup menu
1500 * -toolbar (guess)
1501 *
1502 * Which are not items anyway.
1503 */
1504
1505 if ((pElder) && (pElder->submenu_id == menuID))
1506 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1508 pMenu = pMenu->next;
1509 }
1510 else
1511 {
1512 for (; pMenu != NULL; pMenu = pMenu->next)
1513 {
1514 if (pMenu->children != NULL)
1515 {
1516 pChildMenu = gui_mac_get_vim_menu
1517 (menuID, itemIndex, pMenu->children);
1518 if (pChildMenu)
1519 {
1520 pMenu = pChildMenu;
1521 break;
1522 }
1523 }
1524 }
1525 }
1526 return pMenu;
1527}
1528
1529/*
1530 * ------------------------------------------------------------
1531 * MacOS Feedback procedures
1532 * ------------------------------------------------------------
1533 */
1534 pascal
1535 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001536gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537{
1538 scrollbar_T *sb;
1539 int value, dragging;
1540 ControlHandle theControlToUse;
1541 int dont_scroll_save = dont_scroll;
1542
1543 theControlToUse = dragged_sb;
1544
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001545 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001546
1547 if (sb == NULL)
1548 return;
1549
1550 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001551 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552 dragging = (partCode != 0);
1553
1554 /* When "allow_scrollbar" is FALSE still need to remember the new
1555 * position, but don't actually scroll by setting "dont_scroll". */
1556 dont_scroll = !allow_scrollbar;
1557 gui_drag_scrollbar(sb, value, dragging);
1558 dont_scroll = dont_scroll_save;
1559}
1560
1561 pascal
1562 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001563gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001564{
1565 /* TODO: have live support */
1566 scrollbar_T *sb, *sb_info;
1567 long data;
1568 long value;
1569 int page;
1570 int dragging = FALSE;
1571 int dont_scroll_save = dont_scroll;
1572
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001573 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574
1575 if (sb == NULL)
1576 return;
1577
1578 if (sb->wp != NULL) /* Left or right scrollbar */
1579 {
1580 /*
1581 * Careful: need to get scrollbar info out of first (left) scrollbar
1582 * for window, but keep real scrollbar too because we must pass it to
1583 * gui_drag_scrollbar().
1584 */
1585 sb_info = &sb->wp->w_scrollbars[0];
1586
1587 if (sb_info->size > 5)
1588 page = sb_info->size - 2; /* use two lines of context */
1589 else
1590 page = sb_info->size;
1591 }
1592 else /* Bottom scrollbar */
1593 {
1594 sb_info = sb;
1595 page = W_WIDTH(curwin) - 5;
1596 }
1597
1598 switch (partCode)
1599 {
1600 case kControlUpButtonPart: data = -1; break;
1601 case kControlDownButtonPart: data = 1; break;
1602 case kControlPageDownPart: data = page; break;
1603 case kControlPageUpPart: data = -page; break;
1604 default: data = 0; break;
1605 }
1606
1607 value = sb_info->value + data;
1608/* if (value > sb_info->max)
1609 value = sb_info->max;
1610 else if (value < 0)
1611 value = 0;*/
1612
1613 /* When "allow_scrollbar" is FALSE still need to remember the new
1614 * position, but don't actually scroll by setting "dont_scroll". */
1615 dont_scroll = !allow_scrollbar;
1616 gui_drag_scrollbar(sb, value, dragging);
1617 dont_scroll = dont_scroll_save;
1618
1619 out_flush();
1620 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1621
1622/* if (sb_info->wp != NULL)
1623 {
1624 win_T *wp;
1625 int sb_num;
1626
1627 sb_num = 0;
1628 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1629 sb_num++;
1630
1631 if (wp != NULL)
1632 {
1633 current_scrollbar = sb_num;
1634 scrollbar_value = value;
1635 gui_do_scroll();
1636 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1637 }
1638 }*/
1639}
1640
1641/*
1642 * ------------------------------------------------------------
1643 * MacOS Click Handling procedures
1644 * ------------------------------------------------------------
1645 */
1646
1647
1648/*
1649 * Handle a click inside the window, it may happens in the
1650 * scrollbar or the contents.
1651 *
1652 * TODO: Add support for potential TOOLBAR
1653 */
1654 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001655gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656{
1657 Point thePoint;
1658 int_u vimModifiers;
1659 short thePortion;
1660 ControlHandle theControl;
1661 int vimMouseButton;
1662 short dblClick;
1663
1664 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001665 GlobalToLocal(&thePoint);
1666 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001668 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669
1670 if (theControl != NUL)
1671 {
1672 /* We hit a scollbar */
1673
1674 if (thePortion != kControlIndicatorPart)
1675 {
1676 dragged_sb = theControl;
1677 TrackControl(theControl, thePoint, gScrollAction);
1678 dragged_sb = NULL;
1679 }
1680 else
1681 {
1682 dragged_sb = theControl;
1683#if 1
1684 TrackControl(theControl, thePoint, gScrollDrag);
1685#else
1686 TrackControl(theControl, thePoint, NULL);
1687#endif
1688 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1689 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001690 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 dragged_sb = NULL;
1692 }
1693 }
1694 else
1695 {
1696 /* We are inside the contents */
1697
1698 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1699 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1700
1701 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1702 vimMouseButton = MOUSE_LEFT;
1703
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001705 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001706 clickIsPopup = FALSE;
1707
1708 if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup()))
1709 if (IsShowContextualMenuClick(theEvent))
1710 {
1711 vimMouseButton = MOUSE_RIGHT;
1712 vimModifiers &= ~MOUSE_CTRL;
1713 clickIsPopup = TRUE;
1714 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715
1716 /* Is it a double click ? */
1717 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1718
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001719 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 gui_send_mouse_event(vimMouseButton, thePoint.h,
1721 thePoint.v, dblClick, vimModifiers);
1722
1723 /* Create the rectangle around the cursor to detect
1724 * the mouse dragging
1725 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726#if 0
1727 /* TODO: Do we need to this even for the contextual menu?
1728 * It may be require for popup_setpos, but for popup?
1729 */
1730 if (vimMouseButton == MOUSE_LEFT)
1731#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001733 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 FILL_Y(Y_2_ROW(thePoint.v)),
1735 FILL_X(X_2_COL(thePoint.h)+1),
1736 FILL_Y(Y_2_ROW(thePoint.v)+1));
1737
1738 dragRectEnbl = TRUE;
1739 dragRectControl = kCreateRect;
1740 }
1741 }
1742}
1743
1744/*
1745 * Handle the click in the titlebar (to move the window)
1746 */
1747 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001748gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749{
1750 Rect movingLimits;
1751 Rect *movingLimitsPtr = &movingLimits;
1752
1753 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001754 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001755 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756}
1757
1758/*
1759 * Handle the click in the grow box
1760 */
1761 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001762gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763{
1764
1765 long newSize;
1766 unsigned short newWidth;
1767 unsigned short newHeight;
1768 Rect resizeLimits;
1769 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 Rect NewContentRect;
1771
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001772 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773
1774 /* Set the minimun size */
1775 /* TODO: Should this come from Vim? */
1776 resizeLimits.top = 100;
1777 resizeLimits.left = 100;
1778
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1780 newWidth = NewContentRect.right - NewContentRect.left;
1781 newHeight = NewContentRect.bottom - NewContentRect.top;
1782 gui_resize_shell(newWidth, newHeight);
1783 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001784 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785}
1786
1787/*
1788 * Handle the click in the zoom box
1789 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001791gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792{
1793 Rect r;
1794 Point p;
1795 short thePart;
1796
1797 /* ideal width is current */
1798 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1799 if (gui.which_scrollbars[SBAR_LEFT])
1800 p.h += gui.scrollbar_width;
1801 if (gui.which_scrollbars[SBAR_RIGHT])
1802 p.h += gui.scrollbar_width;
1803 /* ideal height is as heigh as we can get */
1804 p.v = 15 * 1024;
1805
1806 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1807 ? inZoomIn : inZoomOut;
1808
1809 if (!TrackBox(whichWindow, theEvent->where, thePart))
1810 return;
1811
1812 /* use returned width */
1813 p.h = r.right - r.left;
1814 /* adjust returned height */
1815 p.v = r.bottom - r.top - 2 * gui.border_offset;
1816 if (gui.which_scrollbars[SBAR_BOTTOM])
1817 p.v -= gui.scrollbar_height;
1818 p.v -= p.v % gui.char_height;
1819 p.v += 2 * gui.border_width;
1820 if (gui.which_scrollbars[SBAR_BOTTOM]);
1821 p.v += gui.scrollbar_height;
1822
1823 ZoomWindowIdeal(whichWindow, thePart, &p);
1824
1825 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1826 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1827 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001828 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830
1831/*
1832 * ------------------------------------------------------------
1833 * MacOS Event Handling procedure
1834 * ------------------------------------------------------------
1835 */
1836
1837/*
1838 * Handle the Update Event
1839 */
1840
1841 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001842gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843{
1844 WindowPtr whichWindow;
1845 GrafPtr savePort;
1846 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 Rect *updateRectPtr;
1849 Rect rc;
1850 Rect growRect;
1851 RgnHandle saveRgn;
1852
1853
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 updateRgn = NewRgn();
1855 if (updateRgn == NULL)
1856 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857
1858 /* This could be done by the caller as we
1859 * don't require anything else out of the event
1860 */
1861 whichWindow = (WindowPtr) event->message;
1862
1863 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001864 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865
1866 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001867 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868
1869 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001870 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 /* Redraw the biggest rectangle covering the area
1872 * to be updated.
1873 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1875# if 0
1876 /* Would be more appropriate to use the follwing but doesn't
1877 * seem to work under MacOS X (Dany)
1878 */
1879 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1880# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001881
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001883 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001884
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001885 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886# if 0
1887 /* Code from original Carbon Port (using GetWindowRegion.
1888 * I believe the UpdateRgn is already in local (Dany)
1889 */
1890 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1891 GlobalToLocal(&botRight(updateRect));
1892# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 /* Update the content (i.e. the text) */
1894 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1895 updateRectPtr->right - updateRectPtr->left,
1896 updateRectPtr->bottom - updateRectPtr->top);
1897 /* Clear the border areas if needed */
1898 gui_mch_set_bg_color(gui.back_pixel);
1899 if (updateRectPtr->left < FILL_X(0))
1900 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1902 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 }
1904 if (updateRectPtr->top < FILL_Y(0))
1905 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001906 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1907 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 }
1909 if (updateRectPtr->right > FILL_X(Columns))
1910 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001911 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001913 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 }
1915 if (updateRectPtr->bottom > FILL_Y(Rows))
1916 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001917 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001919 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001921 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001922 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923
1924 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001925 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926
1927 /* Update the GrowBox */
1928 /* Taken from FAQ 33-27 */
1929 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001931 GetClip(saveRgn);
1932 ClipRect(&growRect);
1933 DrawGrowIcon(whichWindow);
1934 SetClip(saveRgn);
1935 DisposeRgn(saveRgn);
1936 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937
1938 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940}
1941
1942/*
1943 * Handle the activate/deactivate event
1944 * (apply to a window)
1945 */
1946 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001947gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948{
1949 WindowPtr whichWindow;
1950
1951 whichWindow = (WindowPtr) event->message;
1952 if ((event->modifiers) & activeFlag)
1953 /* Activate */
1954 gui_focus_change(TRUE);
1955 else
1956 {
1957 /* Deactivate */
1958 gui_focus_change(FALSE);
1959/* DON'T KNOW what the code below was doing
1960 found in the deactivate clause, but the
1961 clause writting TRUE into in_focus (BUG)
1962 */
1963
1964#if 0 /* Removed by Dany as per above June 2001 */
1965 a_bool = false;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001966 SetPreserveGlyph(a_bool);
1967 SetOutlinePreferred(a_bool);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968#endif
1969 }
1970}
1971
1972
1973/*
1974 * Handle the suspend/resume event
1975 * (apply to the application)
1976 */
1977 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001978gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979{
1980 /* The frontmost application just changed */
1981
1982 /* NOTE: the suspend may happen before the deactivate
1983 * seen on MacOS X
1984 */
1985
1986 /* May not need to change focus as the window will
1987 * get an activate/desactivate event
1988 */
1989 if (event->message & 1)
1990 /* Resume */
1991 gui_focus_change(TRUE);
1992 else
1993 /* Suspend */
1994 gui_focus_change(FALSE);
1995}
1996
1997/*
1998 * Handle the key
1999 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002000#ifdef USE_CARBONKEYHANDLER
2001# define INLINE_KEY_BUFFER_SIZE 80
2002 static pascal OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002003gui_mac_doKeyEventCarbon(
2004 EventHandlerCallRef nextHandler,
2005 EventRef theEvent,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002006 void *data)
2007{
2008 /* Multibyte-friendly key event handler */
2009 OSStatus e = -1;
2010 UInt32 actualSize;
2011 UniChar *text;
2012 char_u result[INLINE_KEY_BUFFER_SIZE];
2013 short len = 0;
2014 UInt32 key_sym;
2015 char charcode;
2016 int key_char;
2017 UInt32 modifiers;
2018 size_t encLen;
2019 char_u *to = NULL;
2020 Boolean isSpecial = FALSE;
2021 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002023 /* Mask the mouse (as per user setting) */
2024 if (p_mh)
2025 ObscureCursor();
2026
2027 do
2028 {
2029 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2030 typeUnicodeText, NULL, 0, &actualSize, NULL))
2031 break;
2032
2033 text = (UniChar *)alloc(actualSize);
2034
2035 if (text)
2036 {
2037 do
2038 {
2039 if (noErr != GetEventParameter(theEvent,
2040 kEventParamTextInputSendText,
2041 typeUnicodeText, NULL, actualSize, NULL, text))
2042 break;
2043 EventRef keyEvent;
2044 if (noErr != GetEventParameter(theEvent,
2045 kEventParamTextInputSendKeyboardEvent,
2046 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent))
2047 break;
2048 if (noErr != GetEventParameter(keyEvent,
2049 kEventParamKeyModifiers,
2050 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers))
2051 break;
2052 if (noErr != GetEventParameter(keyEvent,
2053 kEventParamKeyCode,
2054 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym))
2055 break;
2056 if (noErr != GetEventParameter(keyEvent,
2057 kEventParamKeyMacCharCodes,
2058 typeChar, NULL, sizeof(char), NULL, &charcode))
2059 break;
2060
2061 key_char = charcode;
2062
2063 if (modifiers & controlKey)
2064 {
2065 if ((modifiers & ~(controlKey|shiftKey)) == 0
2066 && (key_char == '2' || key_char == '6'))
2067 {
2068 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2069 if (key_char == '2')
2070 key_char = Ctrl_AT;
2071 else
2072 key_char = Ctrl_HAT;
2073
2074 text[0] = (UniChar)key_char;
2075 modifiers = 0;
2076 }
2077 }
2078
2079 if (modifiers & cmdKey)
2080#ifndef USE_CMD_KEY
2081 break; /* Let system handle Cmd+... */
2082#else
2083 {
2084 /* Intercept CMD-. */
2085 if (key_char == '.')
2086 got_int = TRUE;
2087
2088 /* Convert the modifiers */
2089 modifiers = EventModifiers2VimModifiers(modifiers);
2090
2091 /* Following code to simplify and consolidate modifiers
2092 * taken liberally from gui_w48.c */
2093
2094 key_char = simplify_key(key_char, (int *)&modifiers);
2095
2096 /* remove SHIFT for keys that are already shifted, e.g.,
2097 * '(' and '*' */
2098 if (key_char < 0x100 &&
2099 !isalpha(key_char) && isprint(key_char))
2100 modifiers &= ~MOD_MASK_SHIFT;
2101
2102 /* Interpret META, include SHIFT, etc. */
2103 key_char = extract_modifiers(key_char, (int *)&modifiers);
2104 if (key_char == CSI)
2105 key_char = K_CSI;
2106
2107 if (modifiers)
2108 {
2109 result[len++] = CSI;
2110 result[len++] = KS_MODIFIER;
2111 result[len++] = modifiers;
2112 }
2113
2114 isSpecial = TRUE;
2115 }
2116#endif
2117 else
2118 {
2119 /* Find the special key (eg., for cursor keys) */
2120 if (!(actualSize > sizeof(UniChar)) &&
2121 ((text[0] < 0x20) || (text[0] == 0x7f)))
2122 {
2123 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2124 if (special_keys[i].key_sym == key_sym)
2125 {
2126 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2127 special_keys[i].vim_code1);
2128 key_char = simplify_key(key_char,
2129 (int *)&modifiers);
2130 isSpecial = TRUE;
2131 break;
2132 }
2133 }
2134 }
2135
2136 if (isSpecial && IS_SPECIAL(key_char))
2137 {
2138 result[len++] = CSI;
2139 result[len++] = K_SECOND(key_char);
2140 result[len++] = K_THIRD(key_char);
2141 }
2142 else
2143 {
2144 encLen = actualSize;
2145 to = mac_utf16_to_enc(text, actualSize, &encLen);
2146 }
2147
2148 if (to)
2149 {
2150 /* This is basically add_to_input_buf_csi() */
2151 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2152 {
2153 result[len++] = to[i];
2154 if (to[i] == CSI)
2155 {
2156 result[len++] = KS_EXTRA;
2157 result[len++] = (int)KE_CSI;
2158 }
2159 }
2160 vim_free(to);
2161 }
2162
2163 add_to_input_buf(result, len);
2164 e = noErr;
2165 }
2166 while (0);
2167
2168 vim_free(text);
2169 if (e == noErr)
2170 {
2171 /* Fake event to wake up WNE (required to get
2172 * key repeat working */
2173 PostEvent(keyUp, 0);
2174 return noErr;
2175 }
2176 }
2177 }
2178 while (0);
2179
2180 return CallNextEventHandler(nextHandler, theEvent);
2181}
2182#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 void
2184gui_mac_doKeyEvent(EventRecord *theEvent)
2185{
2186 /* TODO: add support for COMMAND KEY */
2187 long menu;
2188 unsigned char string[20];
2189 short num, i;
2190 short len = 0;
2191 KeySym key_sym;
2192 int key_char;
2193 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002194 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195
2196 /* Mask the mouse (as per user setting) */
2197 if (p_mh)
2198 ObscureCursor();
2199
2200 /* Get the key code and it's ASCII representation */
2201 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2202 key_char = theEvent->message & charCodeMask;
2203 num = 1;
2204
2205 /* Intercept CTRL-C */
2206 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002207 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 if (key_char == Ctrl_C && ctrl_c_interrupts)
2209 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002210 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2211 && (key_char == '2' || key_char == '6'))
2212 {
2213 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2214 if (key_char == '2')
2215 key_char = Ctrl_AT;
2216 else
2217 key_char = Ctrl_HAT;
2218 theEvent->modifiers = 0;
2219 }
2220 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221
2222 /* Intercept CMD-. */
2223 if (theEvent->modifiers & cmdKey)
2224 if (key_char == '.')
2225 got_int = TRUE;
2226
2227 /* Handle command key as per menu */
2228 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2229 if (theEvent->modifiers & cmdKey)
2230 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2231 * Why the mouse button? */
2232 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2233 {
2234 menu = MenuKey(key_char);
2235 if (HiWord(menu))
2236 {
2237 gui_mac_handle_menu(menu);
2238 return;
2239 }
2240 }
2241
2242 /* Convert the modifiers */
2243 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2244
2245
2246 /* Handle special keys. */
2247#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002248 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2250#endif
2251 {
2252 /* Find the special key (for non-printable keyt_char) */
2253 if ((key_char < 0x20) || (key_char == 0x7f))
2254 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2255 if (special_keys[i].key_sym == key_sym)
2256 {
2257# if 0
2258 /* We currently don't have not so special key */
2259 if (special_keys[i].vim_code1 == NUL)
2260 key_char = special_keys[i].vim_code0;
2261 else
2262# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002263 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2264 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002265 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 break;
2267 }
2268 }
2269
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002270 /* For some keys the modifier is included in the char itself. */
2271 if (simplify || key_char == TAB || key_char == ' ')
2272 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273
2274 /* Add the modifier to the input bu if needed */
2275 /* Do not want SHIFT-A or CTRL-A with modifier */
2276 if (!IS_SPECIAL(key_char)
2277 && key_sym != vk_Space
2278 && key_sym != vk_Tab
2279 && key_sym != vk_Return
2280 && key_sym != vk_Enter
2281 && key_sym != vk_Esc)
2282 {
2283#if 1
2284 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002285 if ((modifiers == MOD_MASK_SHIFT)
2286 || (modifiers == MOD_MASK_CTRL)
2287 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 modifiers = 0;
2289#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002290 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002292 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002294 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 modifiers = modifiers & ~MOD_MASK_SHIFT;
2296#endif
2297 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002298 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002300 string[len++] = CSI;
2301 string[len++] = KS_MODIFIER;
2302 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 }
2304
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002305 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002307 string[len++] = CSI;
2308 string[len++] = K_SECOND(key_char);
2309 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 }
2311 else
2312 {
2313#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002314 /* Convert characters when needed (e.g., from MacRoman to latin1).
2315 * This doesn't work for the NUL byte. */
2316 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 {
2318 char_u from[2], *to;
2319 int l;
2320
2321 from[0] = key_char;
2322 from[1] = NUL;
2323 l = 1;
2324 to = string_convert(&input_conv, from, &l);
2325 if (to != NULL)
2326 {
2327 for (i = 0; i < l && len < 19; i++)
2328 {
2329 if (to[i] == CSI)
2330 {
2331 string[len++] = KS_EXTRA;
2332 string[len++] = KE_CSI;
2333 }
2334 else
2335 string[len++] = to[i];
2336 }
2337 vim_free(to);
2338 }
2339 else
2340 string[len++] = key_char;
2341 }
2342 else
2343#endif
2344 string[len++] = key_char;
2345 }
2346
2347 if (len == 1 && string[0] == CSI)
2348 {
2349 /* Turn CSI into K_CSI. */
2350 string[ len++ ] = KS_EXTRA;
2351 string[ len++ ] = KE_CSI;
2352 }
2353
2354 add_to_input_buf(string, len);
2355}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002356#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357
2358/*
2359 * Handle MouseClick
2360 */
2361 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002362gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363{
2364 short thePart;
2365 WindowPtr whichWindow;
2366
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002367 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368
2369 switch (thePart)
2370 {
2371 case (inDesk):
2372 /* TODO: what to do? */
2373 break;
2374
2375 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 break;
2378
2379 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002380 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 break;
2382
2383 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002384 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 break;
2386
2387 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002388 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 break;
2390
2391 case (inGoAway):
2392 if (TrackGoAway(whichWindow, theEvent->where))
2393 gui_shell_closed();
2394 break;
2395
2396 case (inZoomIn):
2397 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 break;
2400 }
2401}
2402
2403/*
2404 * Handle MouseMoved
2405 * [this event is a moving in and out of a region]
2406 */
2407 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002408gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409{
2410 Point thePoint;
2411 int_u vimModifiers;
2412
2413 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002414 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2416
2417 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002418 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2422 thePoint.v, FALSE, vimModifiers);
2423
2424 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002425 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 FILL_Y(Y_2_ROW(thePoint.v)),
2427 FILL_X(X_2_COL(thePoint.h)+1),
2428 FILL_Y(Y_2_ROW(thePoint.v)+1));
2429
2430 if (dragRectEnbl)
2431 dragRectControl = kCreateRect;
2432
2433}
2434
2435/*
2436 * Handle the mouse release
2437 */
2438 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002439gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440{
2441 Point thePoint;
2442 int_u vimModifiers;
2443
2444 /* TODO: Properly convert the Contextual menu mouse-up */
2445 /* Potential source of the double menu */
2446 lastMouseTick = theEvent->when;
2447 dragRectEnbl = FALSE;
2448 dragRectControl = kCreateEmpty;
2449 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002450 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451
2452 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 if (clickIsPopup)
2454 {
2455 vimModifiers &= ~MOUSE_CTRL;
2456 clickIsPopup = FALSE;
2457 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002458 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459}
2460
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461 static pascal OSStatus
2462gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2463 void *data)
2464{
2465 EventRef bogusEvent;
2466 Point point;
2467 Rect bounds;
2468 UInt32 mod;
2469 SInt32 delta;
2470 int_u vim_mod;
2471
2472 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2473 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2474 goto bail;
2475 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2476 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2477 goto bail;
2478 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2479 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2480 goto bail;
2481
2482 vim_mod = 0;
2483 if (mod & shiftKey)
2484 vim_mod |= MOUSE_SHIFT;
2485 if (mod & controlKey)
2486 vim_mod |= MOUSE_CTRL;
2487 if (mod & optionKey)
2488 vim_mod |= MOUSE_ALT;
2489
2490 /* post a bogus event to wake up WaitNextEvent */
2491 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2492 kEventAttributeNone, &bogusEvent))
2493 goto bail;
2494 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2495 kEventPriorityLow))
2496 goto bail;
2497
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002498 ReleaseEvent(bogusEvent);
2499
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2501 {
2502 point.h -= bounds.left;
2503 point.v -= bounds.top;
2504 }
2505
2506 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2507 point.h, point.v, FALSE, vim_mod);
2508
2509 return noErr;
2510
2511 bail:
2512 /*
2513 * when we fail give any additional callback handler a chance to perform
2514 * it's actions
2515 */
2516 return CallNextEventHandler(nextHandler, theEvent);
2517}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518
2519#if 0
2520
2521/*
2522 * This would be the normal way of invoking the contextual menu
2523 * but the Vim API doesn't seem to a support a request to get
2524 * the menu that we should display
2525 */
2526 void
2527gui_mac_handle_contextual_menu(event)
2528 EventRecord *event;
2529{
2530/*
2531 * Clone PopUp to use menu
2532 * Create a object descriptor for the current selection
2533 * Call the procedure
2534 */
2535
2536// Call to Handle Popup
2537 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2538
2539 if (status != noErr)
2540 return;
2541
2542 if (CntxType == kCMMenuItemSelected)
2543 {
2544 /* Handle the menu CntxMenuID, CntxMenuItem */
2545 /* The submenu can be handle directly by gui_mac_handle_menu */
2546 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002547 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 }
2549 else if (CntxMenuID == kCMShowHelpSelected)
2550 {
2551 /* Should come up with the help */
2552 }
2553
2554}
2555#endif
2556
2557/*
2558 * Handle menubar selection
2559 */
2560 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002561gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562{
2563 short menu = HiWord(menuChoice);
2564 short item = LoWord(menuChoice);
2565 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566
2567 if (menu == 256) /* TODO: use constant or gui.xyz */
2568 {
2569 if (item == 1)
2570 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 }
2572 else if (item != 0)
2573 {
2574 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2575
2576 if (theVimMenu)
2577 gui_menu_cb(theVimMenu);
2578 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002579 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580}
2581
2582/*
2583 * Dispatch the event to proper handler
2584 */
2585
2586 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002587gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588{
2589 OSErr error;
2590
2591 /* Handle contextual menu right now (if needed) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 if (gui.MacOSHaveCntxMenu)
2593 if (IsShowContextualMenuClick(event))
2594 {
2595# if 0
2596 gui_mac_handle_contextual_menu(event);
2597# else
2598 gui_mac_doMouseDownEvent(event);
2599# endif
2600 return;
2601 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602
2603 /* Handle normal event */
2604 switch (event->what)
2605 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002606#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 case (keyDown):
2608 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002609 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002611#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 case (keyUp):
2613 /* We don't care about when the key get release */
2614 break;
2615
2616 case (mouseDown):
2617 gui_mac_doMouseDownEvent(event);
2618 break;
2619
2620 case (mouseUp):
2621 gui_mac_doMouseUpEvent(event);
2622 break;
2623
2624 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002625 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 break;
2627
2628 case (diskEvt):
2629 /* We don't need special handling for disk insertion */
2630 break;
2631
2632 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002633 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002634 break;
2635
2636 case (osEvt):
2637 switch ((event->message >> 24) & 0xFF)
2638 {
2639 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002640 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 break;
2642 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002643 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 break;
2645 }
2646 break;
2647
2648#ifdef USE_AEVENT
2649 case (kHighLevelEvent):
2650 /* Someone's talking to us, through AppleEvents */
2651 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2652 break;
2653#endif
2654 }
2655}
2656
2657/*
2658 * ------------------------------------------------------------
2659 * Unknown Stuff
2660 * ------------------------------------------------------------
2661 */
2662
2663
2664 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002665gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666{
2667 char_u c;
2668 char_u *p;
2669 char_u pFontName[256];
2670 Str255 systemFontname;
2671 short font_id;
2672 short size=9;
2673 GuiFont font;
2674#if 0
2675 char_u *fontNamePtr;
2676#endif
2677
2678 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2679 ;
2680
2681 c = *p;
2682 *p = 0;
2683
2684#if 1
2685 STRCPY(&pFontName[1], font_name);
2686 pFontName[0] = STRLEN(font_name);
2687 *p = c;
2688
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002689 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002690 char_u fontName[256];
2691 char_u *styleStart = vim_strchr(font_name, ':');
2692 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2693 vim_strncpy(fontName, font_name, fontNameLen);
2694
2695 ATSUFontID fontRef;
2696 FMFontStyle fontStyle;
2697 font_id = 0;
2698
2699 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2700 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2701 &fontRef) == noErr)
2702 {
2703 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2704 font_id = 0;
2705 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002706
2707 if (font_id == 0)
2708 {
2709 /*
2710 * Try again, this time replacing underscores in the font name
2711 * with spaces (:set guifont allows the two to be used
2712 * interchangeably; the Font Manager doesn't).
2713 */
2714 int i, changed = FALSE;
2715
2716 for (i = pFontName[0]; i > 0; --i)
2717 {
2718 if (pFontName[i] == '_')
2719 {
2720 pFontName[i] = ' ';
2721 changed = TRUE;
2722 }
2723 }
2724 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002725 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2726 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2727 kFontNoLanguageCode, &fontRef) == noErr)
2728 {
2729 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2730 font_id = 0;
2731 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002732 }
2733
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734#else
2735 /* name = C2Pascal_save(menu->dname); */
2736 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2737
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002738 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739#endif
2740
2741
2742 if (font_id == 0)
2743 {
2744 /* Oups, the system font was it the one the user want */
2745
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002746 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2747 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 if (!EqualString(pFontName, systemFontname, false, false))
2749 return NOFONT;
2750 }
2751 if (*p == ':')
2752 {
2753 p++;
2754 /* Set the values found after ':' */
2755 while (*p)
2756 {
2757 switch (*p++)
2758 {
2759 case 'h':
2760 size = points_to_pixels(p, &p, TRUE);
2761 break;
2762 /*
2763 * TODO: Maybe accept width and styles
2764 */
2765 }
2766 while (*p == ':')
2767 p++;
2768 }
2769 }
2770
2771 if (size < 1)
2772 size = 1; /* Avoid having a size of 0 with system font */
2773
2774 font = (size << 16) + ((long) font_id & 0xFFFF);
2775
2776 return font;
2777}
2778
2779/*
2780 * ------------------------------------------------------------
2781 * GUI_MCH functionnality
2782 * ------------------------------------------------------------
2783 */
2784
2785/*
2786 * Parse the GUI related command-line arguments. Any arguments used are
2787 * deleted from argv, and *argc is decremented accordingly. This is called
2788 * when vim is started, whether or not the GUI has been started.
2789 */
2790 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002791gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792{
2793 /* TODO: Move most of this stuff toward gui_mch_init */
2794#ifdef USE_EXE_NAME
2795 FSSpec applDir;
2796# ifndef USE_FIND_BUNDLE_PATH
2797 short applVRefNum;
2798 long applDirID;
2799 Str255 volName;
2800# else
2801 ProcessSerialNumber psn;
2802 FSRef applFSRef;
2803# endif
2804#endif
2805
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806 /* Why did I put that in? (Dany) */
2807 MoreMasterPointers (0x40 * 3); /* we love handles */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808
2809#if 0
2810 InitCursor();
2811
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813
2814#ifdef USE_AEVENT
2815 (void) InstallAEHandlers();
2816#endif
2817
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2819 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2820 else
2821 gui.MacOSHaveCntxMenu = false;
2822
2823 if (gui.MacOSHaveCntxMenu)
2824 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002826 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002828 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002830 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831
2832 DrawMenuBar();
2833
2834
2835#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002836 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002838 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839#endif
2840
2841
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 CreateNewWindow(kDocumentWindowClass,
2843 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002844 &windRect, &gui.VimWindow);
2845 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846
2847 gui.char_width = 7;
2848 gui.char_height = 11;
2849 gui.char_ascent = 6;
2850 gui.num_rows = 24;
2851 gui.num_cols = 80;
2852 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2853
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002854 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2855 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856
2857 dragRectEnbl = FALSE;
2858 dragRgn = NULL;
2859 dragRectControl = kCreateEmpty;
2860 cursorRgn = NewRgn();
2861#endif
2862#ifdef USE_EXE_NAME
2863# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002864 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002865 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002866 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867# else
2868 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2869 * of TN2015
2870 * This technic remove the ../Contents/MacOS/etc part
2871 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002872 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 /* if (err != noErr) return err; */
2874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002875 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 /* if (err != noErr) return err; */
2877
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002878 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879
2880 /* This technic return NIL when we disallow_gui */
2881# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002882 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884}
2885
2886#ifndef ALWAYS_USE_GUI
2887/*
2888 * Check if the GUI can be started. Called before gvimrc is sourced.
2889 * Return OK or FAIL.
2890 */
2891 int
2892gui_mch_init_check(void)
2893{
2894 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2895 * using the >console
2896 */
2897 if (disallow_gui) /* see main.c for reason to disallow */
2898 return FAIL;
2899 return OK;
2900}
2901#endif
2902
2903 static OSErr
2904receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag)
2905{
2906 int x, y;
2907 int_u modifiers;
2908 char_u **fnames = NULL;
2909 int count;
2910 int i, j;
2911
2912 /* Get drop position, modifiers and count of items */
2913 {
2914 Point point;
2915 SInt16 mouseUpModifiers;
2916 UInt16 countItem;
2917
2918 GetDragMouse(theDrag, &point, NULL);
2919 GlobalToLocal(&point);
2920 x = point.h;
2921 y = point.v;
2922 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2923 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2924 CountDragItems(theDrag, &countItem);
2925 count = countItem;
2926 }
2927
2928 fnames = (char_u **)alloc(count * sizeof(char_u *));
2929 if (fnames == NULL)
2930 return dragNotAcceptedErr;
2931
2932 /* Get file names dropped */
2933 for (i = j = 0; i < count; ++i)
2934 {
2935 DragItemRef item;
2936 OSErr err;
2937 Size size;
2938 FlavorType type = flavorTypeHFS;
2939 HFSFlavor hfsFlavor;
2940
2941 fnames[i] = NULL;
2942 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2943 err = GetFlavorDataSize(theDrag, item, type, &size);
2944 if (err != noErr || size > sizeof(hfsFlavor))
2945 continue;
2946 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2947 if (err != noErr)
2948 continue;
2949 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
2950 }
2951 count = j;
2952
2953 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002954
2955 /* Fake mouse event to wake from stall */
2956 PostEvent(mouseUp, 0);
2957
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 return noErr;
2959}
2960
2961/*
2962 * Initialise the GUI. Create all the windows, set up all the call-backs
2963 * etc.
2964 */
2965 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002966gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967{
2968 /* TODO: Move most of this stuff toward gui_mch_init */
2969 Rect windRect;
2970 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971 long gestalt_rc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972 EventTypeSpec eventTypeSpec;
2973 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002974#ifdef USE_CARBONKEYHANDLER
2975 EventHandlerRef keyEventHandlerRef;
2976#endif
2977
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002978 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002979 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002980
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981#if 1
2982 InitCursor();
2983
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002985
2986#ifdef USE_AEVENT
2987 (void) InstallAEHandlers();
2988#endif
2989
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002990 /* Ctrl click */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2992 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2993 else
2994 gui.MacOSHaveCntxMenu = false;
2995
2996 if (gui.MacOSHaveCntxMenu)
2997 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002999 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003001 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003003 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004
3005 DrawMenuBar();
3006
3007
3008#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003009 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003011 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012#endif
3013
3014 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 (WindowPtr)-1L, true, 0);
3017 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3018 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003019 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020
3021 gui.char_width = 7;
3022 gui.char_height = 11;
3023 gui.char_ascent = 6;
3024 gui.num_rows = 24;
3025 gui.num_cols = 80;
3026 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3027
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003028 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3029 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003031 /* Install Carbon event callbacks. */
3032 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033
3034 dragRectEnbl = FALSE;
3035 dragRgn = NULL;
3036 dragRectControl = kCreateEmpty;
3037 cursorRgn = NewRgn();
3038#endif
3039 /* Display any pending error messages */
3040 display_errors();
3041
3042 /* Get background/foreground colors from system */
3043 /* TODO: do the approriate call to get real defaults */
3044 gui.norm_pixel = 0x00000000;
3045 gui.back_pixel = 0x00FFFFFF;
3046
3047 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3048 * file). */
3049 set_normal_colors();
3050
3051 /*
3052 * Check that none of the colors are the same as the background color.
3053 * Then store the current values as the defaults.
3054 */
3055 gui_check_colors();
3056 gui.def_norm_pixel = gui.norm_pixel;
3057 gui.def_back_pixel = gui.back_pixel;
3058
3059 /* Get the colors for the highlight groups (gui_check_colors() might have
3060 * changed them) */
3061 highlight_gui_started();
3062
3063 /*
3064 * Setting the gui constants
3065 */
3066#ifdef FEAT_MENU
3067 gui.menu_height = 0;
3068#endif
3069 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3070 gui.border_offset = gui.border_width = 2;
3071
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 /* If Quartz-style text antialiasing is available (see
3073 gui_mch_draw_string() below), enable it for all font sizes. */
3074 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 eventTypeSpec.eventClass = kEventClassMouse;
3077 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3078 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3079 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3080 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3081 {
3082 mouseWheelHandlerRef = NULL;
3083 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3084 mouseWheelHandlerUPP = NULL;
3085 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003087#ifdef USE_CARBONKEYHANDLER
3088 eventTypeSpec.eventClass = kEventClassTextInput;
3089 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3090 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3091 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3092 &eventTypeSpec, NULL, &keyEventHandlerRef))
3093 {
3094 keyEventHandlerRef = NULL;
3095 DisposeEventHandlerUPP(keyEventHandlerUPP);
3096 keyEventHandlerUPP = NULL;
3097 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098#endif
3099
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003100/*
3101#ifdef FEAT_MBYTE
3102 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3103#endif
3104*/
3105
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 /* TODO: Load bitmap if using TOOLBAR */
3107 return OK;
3108}
3109
3110/*
3111 * Called when the foreground or background color has been changed.
3112 */
3113 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003114gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115{
3116 /* TODO:
3117 * This proc is called when Normal is set to a value
3118 * so what msut be done? I don't know
3119 */
3120}
3121
3122/*
3123 * Open the GUI window which was created by a call to gui_mch_init().
3124 */
3125 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003126gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127{
3128 ShowWindow(gui.VimWindow);
3129
3130 if (gui_win_x != -1 && gui_win_y != -1)
3131 gui_mch_set_winpos(gui_win_x, gui_win_y);
3132
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 /*
3134 * Make the GUI the foreground process (in case it was launched
3135 * from the Terminal or via :gui).
3136 */
3137 {
3138 ProcessSerialNumber psn;
3139 if (GetCurrentProcess(&psn) == noErr)
3140 SetFrontProcess(&psn);
3141 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142
3143 return OK;
3144}
3145
3146 void
3147gui_mch_exit(int rc)
3148{
3149 /* TODO: find out all what is missing here? */
3150 DisposeRgn(cursorRgn);
3151
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003152#ifdef USE_CARBONKEYHANDLER
3153 if (keyEventHandlerUPP)
3154 DisposeEventHandlerUPP(keyEventHandlerUPP);
3155#endif
3156
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157 if (mouseWheelHandlerUPP != NULL)
3158 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003160#ifdef USE_ATSUI_DRAWING
3161 if (gFontStyle)
3162 ATSUDisposeStyle(gFontStyle);
3163#endif
3164
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 /* Exit to shell? */
3166 exit(rc);
3167}
3168
3169/*
3170 * Get the position of the top left corner of the window.
3171 */
3172 int
3173gui_mch_get_winpos(int *x, int *y)
3174{
3175 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176 Rect bounds;
3177 OSStatus status;
3178
3179 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003180 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003181
3182 if (status != noErr)
3183 return FAIL;
3184 *x = bounds.left;
3185 *y = bounds.top;
3186 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 return FAIL;
3188}
3189
3190/*
3191 * Set the position of the top left corner of the window to the given
3192 * coordinates.
3193 */
3194 void
3195gui_mch_set_winpos(int x, int y)
3196{
3197 /* TODO: Should make sure the window is move within range
3198 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3199 */
3200 MoveWindow(gui.VimWindow, x, y, TRUE);
3201}
3202
3203 void
3204gui_mch_set_shellsize(
3205 int width,
3206 int height,
3207 int min_width,
3208 int min_height,
3209 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003210 int base_height,
3211 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 CGrafPtr VimPort;
3214 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215
3216 if (gui.which_scrollbars[SBAR_LEFT])
3217 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003218 VimPort = GetWindowPort(gui.VimWindow);
3219 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003221 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223 }
3224 else
3225 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003226 VimPort = GetWindowPort(gui.VimWindow);
3227 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003229 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 }
3231
3232 SizeWindow(gui.VimWindow, width, height, TRUE);
3233
3234 gui_resize_shell(width, height);
3235}
3236
3237/*
3238 * Get the screen dimensions.
3239 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3240 * Is there no way to find out how wide the borders really are?
3241 * TODO: Add live udate of those value on suspend/resume.
3242 */
3243 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003244gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245{
3246 GDHandle dominantDevice = GetMainDevice();
3247 Rect screenRect = (**dominantDevice).gdRect;
3248
3249 *screen_w = screenRect.right - 10;
3250 *screen_h = screenRect.bottom - 40;
3251}
3252
3253
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003254/*
3255 * Open the Font Panel and wait for the user to select a font and
3256 * close the panel. Then fill the buffer pointed to by font_name with
3257 * the name and size of the selected font and return the font's handle,
3258 * or NOFONT in case of an error.
3259 */
3260 static GuiFont
3261gui_mac_select_font(char_u *font_name)
3262{
3263 GuiFont selected_font = NOFONT;
3264 OSStatus status;
3265 FontSelectionQDStyle curr_font;
3266
3267 /* Initialize the Font Panel with the current font. */
3268 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3269 curr_font.size = (gui.norm_font >> 16);
3270 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3271 curr_font.instance.fontStyle = 0;
3272 curr_font.hasColor = false;
3273 curr_font.version = 0; /* version number of the style structure */
3274 status = SetFontInfoForSelection(kFontSelectionQDType,
3275 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3276
3277 gFontPanelInfo.family = curr_font.instance.fontFamily;
3278 gFontPanelInfo.style = curr_font.instance.fontStyle;
3279 gFontPanelInfo.size = curr_font.size;
3280
3281 /* Pop up the Font Panel. */
3282 status = FPShowHideFontPanel();
3283 if (status == noErr)
3284 {
3285 /*
3286 * The Font Panel is modeless. We really need it to be modal,
3287 * so we spin in an event loop until the panel is closed.
3288 */
3289 gFontPanelInfo.isPanelVisible = true;
3290 while (gFontPanelInfo.isPanelVisible)
3291 {
3292 EventRecord e;
3293 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3294 }
3295
3296 GetFontPanelSelection(font_name);
3297 selected_font = gui_mac_find_font(font_name);
3298 }
3299 return selected_font;
3300}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003301
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302
3303/*
3304 * Initialise vim to use the font with the given name. Return FAIL if the font
3305 * could not be loaded, OK otherwise.
3306 */
3307 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003308gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309{
3310 /* TODO: Add support for bold italic underline proportional etc... */
3311 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003312 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 FontInfo font_info;
3314 short font_id;
3315 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003316 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003318#ifdef USE_ATSUI_DRAWING
3319 if (gFontStyle == NULL)
3320 {
3321 if (ATSUCreateStyle(&gFontStyle) != noErr)
3322 gFontStyle = NULL;
3323 }
3324#endif
3325
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 if (font_name == NULL)
3327 {
3328 /* First try to get the suggested font */
3329 GetFNum(suggestedFont, &font_id);
3330
3331 if (font_id == 0)
3332 {
3333 /* Then pickup the standard application font */
3334 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003335 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003337 else
3338 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3340 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003341 else if (STRCMP(font_name, "*") == 0)
3342 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003343 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003344
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003345 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003346 if (font == NOFONT)
3347 return FAIL;
3348
3349 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003350 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003351 if (new_p_guifont != NULL)
3352 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003353 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003354 vim_free(p_guifont);
3355 p_guifont = new_p_guifont;
3356 /* Replace spaces in the font name with underscores. */
3357 for ( ; *new_p_guifont; ++new_p_guifont)
3358 {
3359 if (*new_p_guifont == ' ')
3360 *new_p_guifont = '_';
3361 }
3362 }
3363 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364 else
3365 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003366 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003367 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368
3369 if (font == NOFONT)
3370 return FAIL;
3371 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003372
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 gui.norm_font = font;
3374
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003375 hl_set_font_name(used_font_name);
3376
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003377 TextSize(font >> 16);
3378 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003380 GetFontInfo(&font_info);
3381
3382 gui.char_ascent = font_info.ascent;
3383 gui.char_width = CharWidth('_');
3384 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3385
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003386#ifdef USE_ATSUI_DRAWING
3387 ATSUFontID fontID;
3388 Fixed fontSize;
3389 ATSStyleRenderingOptions fontOptions;
3390
3391 if (gFontStyle)
3392 {
3393 fontID = font & 0xFFFF;
3394 fontSize = Long2Fix(font >> 16);
3395
3396 /* No antialiasing by default (do not attempt to touch antialising
3397 * options on pre-Jaguar) */
3398 fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003399 (gMacSystemVersion >= 0x1020) ?
3400 kATSStyleNoAntiAliasing :
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003401 kATSStyleNoOptions;
3402
3403 ATSUAttributeTag attribTags[] =
3404 {
3405 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3406 kATSUMaxATSUITagValue+1
3407 };
3408 ByteCount attribSizes[] =
3409 {
3410 sizeof(ATSUFontID), sizeof(Fixed),
3411 sizeof(ATSStyleRenderingOptions), sizeof font
3412 };
3413 ATSUAttributeValuePtr attribValues[] =
3414 {
3415 &fontID, &fontSize, &fontOptions, &font
3416 };
3417
3418 /* Convert font id to ATSUFontID */
3419 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3420 {
3421 if (ATSUSetAttributes(gFontStyle,
3422 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3423 attribTags, attribSizes, attribValues) != noErr)
3424 {
3425 ATSUDisposeStyle(gFontStyle);
3426 gFontStyle = NULL;
3427 }
3428 }
3429 }
3430#endif
3431
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433}
3434
Bram Moolenaar02743632005-07-25 20:42:36 +00003435/*
3436 * Adjust gui.char_height (after 'linespace' was changed).
3437 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003439gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440{
3441 FontInfo font_info;
3442
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003443 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3445 gui.char_ascent = font_info.ascent + p_linespace / 2;
3446 return OK;
3447}
3448
3449/*
3450 * Get a font structure for highlighting.
3451 */
3452 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003453gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454{
3455 GuiFont font;
3456
3457 font = gui_mac_find_font(name);
3458
3459 if (font == NOFONT)
3460 {
3461 if (giveErrorIfMissing)
3462 EMSG2(_(e_font), name);
3463 return NOFONT;
3464 }
3465 /*
3466 * TODO : Accept only monospace
3467 */
3468
3469 return font;
3470}
3471
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003472#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003474 * Return the name of font "font" in allocated memory.
3475 * Don't know how to get the actual name, thus use the provided name.
3476 */
3477 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003478gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003479{
3480 if (name == NULL)
3481 return NULL;
3482 return vim_strsave(name);
3483}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003484#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003485
3486/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487 * Set the current text font.
3488 */
3489 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003490gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003492#ifdef USE_ATSUI_DRAWING
3493 GuiFont currFont;
3494 ByteCount actualFontByteCount;
3495 ATSUFontID fontID;
3496 Fixed fontSize;
3497 ATSStyleRenderingOptions fontOptions;
3498
3499 if (gFontStyle)
3500 {
3501 /* Avoid setting same font again */
3502 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
3503 &currFont, &actualFontByteCount) == noErr &&
3504 actualFontByteCount == (sizeof font))
3505 {
3506 if (currFont == font)
3507 return;
3508 }
3509
3510 fontID = font & 0xFFFF;
3511 fontSize = Long2Fix(font >> 16);
3512 /* Respect p_antialias setting only for wide font.
3513 * The reason for doing this at the moment is a bit complicated,
3514 * but it's mainly because a) latin (non-wide) aliased fonts
3515 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3516 * b) wide multibyte input does not suffer from that problem. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003517 /*fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003518 (p_antialias && (font == gui.wide_font)) ?
3519 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003520 */
3521 /*fontOptions = kATSStyleAntiAliasing;*/
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003522
3523 ATSUAttributeTag attribTags[] =
3524 {
3525 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3526 kATSUMaxATSUITagValue+1
3527 };
3528 ByteCount attribSizes[] =
3529 {
3530 sizeof(ATSUFontID), sizeof(Fixed),
3531 sizeof(ATSStyleRenderingOptions), sizeof font
3532 };
3533 ATSUAttributeValuePtr attribValues[] =
3534 {
3535 &fontID, &fontSize, &fontOptions, &font
3536 };
3537
3538 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3539 {
3540 if (ATSUSetAttributes(gFontStyle,
3541 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3542 attribTags, attribSizes, attribValues) != noErr)
3543 {
3544#ifndef NDEBUG
3545 fprintf(stderr, "couldn't set font style\n");
3546#endif
3547 ATSUDisposeStyle(gFontStyle);
3548 gFontStyle = NULL;
3549 }
3550 }
3551
3552 }
3553
3554 if (!gIsFontFallbackSet)
3555 {
3556 /* Setup automatic font substitution. The user's guifontwide
3557 * is tried first, then the system tries other fonts. */
3558/*
3559 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3560 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3561 ATSUCreateFontFallbacks(&gFontFallbacks);
3562 ATSUSetObjFontFallbacks(gFontFallbacks, );
3563*/
3564 if (gui.wide_font)
3565 {
3566 ATSUFontID fallbackFonts;
3567 gIsFontFallbackSet = TRUE;
3568
3569 if (FMGetFontFromFontFamilyInstance(
3570 (gui.wide_font & 0xFFFF),
3571 0,
3572 &fallbackFonts,
3573 NULL) == noErr)
3574 {
3575 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
3576 }
3577/*
3578 ATSUAttributeValuePtr fallbackValues[] = { };
3579*/
3580 }
3581 }
3582#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 TextSize(font >> 16);
3584 TextFont(font & 0xFFFF);
3585}
3586
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587/*
3588 * If a font is not going to be used, free its structure.
3589 */
3590 void
3591gui_mch_free_font(font)
3592 GuiFont font;
3593{
3594 /*
3595 * Free font when "font" is not 0.
3596 * Nothing to do in the current implementation, since
3597 * nothing is allocated for each font used.
3598 */
3599}
3600
3601 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003602hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603{
3604 if (isdigit(c))
3605 return c - '0';
3606 c = TOLOWER_ASC(c);
3607 if (c >= 'a' && c <= 'f')
3608 return c - 'a' + 10;
3609 return -1000;
3610}
3611
3612/*
3613 * Return the Pixel value (color) for the given color name. This routine was
3614 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3615 * Programmer's Guide.
3616 * Return INVALCOLOR when failed.
3617 */
3618 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003619gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620{
3621 /* TODO: Add support for the new named color of MacOS 8
3622 */
3623 RGBColor MacColor;
3624// guicolor_T color = 0;
3625
3626 typedef struct guicolor_tTable
3627 {
3628 char *name;
3629 guicolor_T color;
3630 } guicolor_tTable;
3631
3632 /*
3633 * The comment at the end of each line is the source
3634 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3635 */
3636 static guicolor_tTable table[] =
3637 {
3638 {"Black", RGB(0x00, 0x00, 0x00)},
3639 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3640 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3641 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3642 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3643 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3644 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003645 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3646 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647 {"white", RGB(0xFF, 0xFF, 0xFF)},
3648 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3649 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3650 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3651 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3652 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3653 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3654 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3655 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3656 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3657 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3658 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3659 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3660 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3661 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3662 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3663 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3664 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3665 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003666 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3668 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3669 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3670 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3671 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3672 };
3673
3674 int r, g, b;
3675 int i;
3676
3677 if (name[0] == '#' && strlen((char *) name) == 7)
3678 {
3679 /* Name is in "#rrggbb" format */
3680 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3681 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3682 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3683 if (r < 0 || g < 0 || b < 0)
3684 return INVALCOLOR;
3685 return RGB(r, g, b);
3686 }
3687 else
3688 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003689 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003691 LMGetHiliteRGB(&MacColor);
3692 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 }
3694 /* Check if the name is one of the colors we know */
3695 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3696 if (STRICMP(name, table[i].name) == 0)
3697 return table[i].color;
3698 }
3699
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700 /*
3701 * Last attempt. Look in the file "$VIM/rgb.txt".
3702 */
3703 {
3704#define LINE_LEN 100
3705 FILE *fd;
3706 char line[LINE_LEN];
3707 char_u *fname;
3708
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 if (fname == NULL)
3711 return INVALCOLOR;
3712
3713 fd = fopen((char *)fname, "rt");
3714 vim_free(fname);
3715 if (fd == NULL)
3716 return INVALCOLOR;
3717
3718 while (!feof(fd))
3719 {
3720 int len;
3721 int pos;
3722 char *color;
3723
3724 fgets(line, LINE_LEN, fd);
3725 len = strlen(line);
3726
3727 if (len <= 1 || line[len-1] != '\n')
3728 continue;
3729
3730 line[len-1] = '\0';
3731
3732 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3733 if (i != 3)
3734 continue;
3735
3736 color = line + pos;
3737
3738 if (STRICMP(color, name) == 0)
3739 {
3740 fclose(fd);
3741 return (guicolor_T) RGB(r, g, b);
3742 }
3743 }
3744 fclose(fd);
3745 }
3746
3747 return INVALCOLOR;
3748}
3749
3750/*
3751 * Set the current text foreground color.
3752 */
3753 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003754gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755{
3756 RGBColor TheColor;
3757
3758 TheColor.red = Red(color) * 0x0101;
3759 TheColor.green = Green(color) * 0x0101;
3760 TheColor.blue = Blue(color) * 0x0101;
3761
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003762 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763}
3764
3765/*
3766 * Set the current text background color.
3767 */
3768 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003769gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770{
3771 RGBColor TheColor;
3772
3773 TheColor.red = Red(color) * 0x0101;
3774 TheColor.green = Green(color) * 0x0101;
3775 TheColor.blue = Blue(color) * 0x0101;
3776
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003777 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003778}
3779
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003780RGBColor specialColor;
3781
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003782/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003783 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003784 */
3785 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003786gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003787{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003788 specialColor.red = Red(color) * 0x0101;
3789 specialColor.green = Green(color) * 0x0101;
3790 specialColor.blue = Blue(color) * 0x0101;
3791}
3792
3793/*
3794 * Draw undercurl at the bottom of the character cell.
3795 */
3796 static void
3797draw_undercurl(int flags, int row, int col, int cells)
3798{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003799 int x;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003800 int offset;
3801 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3802 int y = FILL_Y(row + 1) - 1;
3803
3804 RGBForeColor(&specialColor);
3805
3806 offset = val[FILL_X(col) % 8];
3807 MoveTo(FILL_X(col), y - offset);
3808
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003809 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003810 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003811 offset = val[x % 8];
3812 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003813 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003814}
3815
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003816#ifndef USE_ATSUI_DRAWING
3817
3818 static void
3819draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821#ifdef FEAT_MBYTE
3822 char_u *tofree = NULL;
3823
3824 if (output_conv.vc_type != CONV_NONE)
3825 {
3826 tofree = string_convert(&output_conv, s, &len);
3827 if (tofree != NULL)
3828 s = tofree;
3829 }
3830#endif
3831
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 /*
3833 * On OS X, try using Quartz-style text antialiasing.
3834 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003835 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003836 {
3837 /* Quartz antialiasing is available only in OS 10.2 and later. */
3838 UInt32 qd_flags = (p_antialias ?
3839 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003840 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841 }
3842
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003843 /*
3844 * When antialiasing we're using srcOr mode, we have to clear the block
3845 * before drawing the text.
3846 * Also needed when 'linespace' is non-zero to remove the cursor and
3847 * underlining.
3848 * But not when drawing transparently.
3849 * The following is like calling gui_mch_clear_block(row, col, row, col +
3850 * len - 1), but without setting the bg color to gui.back_pixel.
3851 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003852 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003853 && !(flags & DRAW_TRANSP))
3854 {
3855 Rect rc;
3856
3857 rc.left = FILL_X(col);
3858 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003859#ifdef FEAT_MBYTE
3860 /* Multibyte computation taken from gui_w32.c */
3861 if (has_mbyte)
3862 {
3863 int cell_len = 0;
3864 int n;
3865
3866 /* Compute the length in display cells. */
3867 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3868 cell_len += (*mb_ptr2cells)(s + n);
3869 rc.right = FILL_X(col + cell_len);
3870 }
3871 else
3872#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003873 rc.right = FILL_X(col + len) + (col + len == Columns);
3874 rc.bottom = FILL_Y(row + 1);
3875 EraseRect(&rc);
3876 }
3877
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003878 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879 {
3880 StyleParameter face;
3881
3882 face = normal;
3883 if (flags & DRAW_BOLD)
3884 face |= bold;
3885 if (flags & DRAW_UNDERL)
3886 face |= underline;
3887 TextFace(face);
3888
3889 /* Quartz antialiasing works only in srcOr transfer mode. */
3890 TextMode(srcOr);
3891
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892 MoveTo(TEXT_X(col), TEXT_Y(row));
3893 DrawText((char*)s, 0, len);
3894 }
3895 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 {
3897 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003898 TextMode(srcCopy);
3899 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900
3901 /* SelectFont(hdc, gui.currFont); */
3902
3903 if (flags & DRAW_TRANSP)
3904 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003905 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 }
3907
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003908 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003909 DrawText((char *)s, 0, len);
3910
3911 if (flags & DRAW_BOLD)
3912 {
3913 TextMode(srcOr);
3914 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3915 DrawText((char *)s, 0, len);
3916 }
3917
3918 if (flags & DRAW_UNDERL)
3919 {
3920 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3921 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3922 }
3923 }
3924
3925 if (flags & DRAW_UNDERC)
3926 draw_undercurl(flags, row, col, len);
3927
3928#ifdef FEAT_MBYTE
3929 vim_free(tofree);
3930#endif
3931}
3932
3933#else /* USE_ATSUI_DRAWING */
3934
3935 static void
3936draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3937{
3938 /* ATSUI requires utf-16 strings */
3939 UniCharCount utf16_len;
3940 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3941 utf16_len /= sizeof(UniChar);
3942
3943 /* - ATSUI automatically antialiases text (Someone)
3944 * - for some reason it does not work... (Jussi) */
3945
3946 /*
3947 * When antialiasing we're using srcOr mode, we have to clear the block
3948 * before drawing the text.
3949 * Also needed when 'linespace' is non-zero to remove the cursor and
3950 * underlining.
3951 * But not when drawing transparently.
3952 * The following is like calling gui_mch_clear_block(row, col, row, col +
3953 * len - 1), but without setting the bg color to gui.back_pixel.
3954 */
3955 if ((flags & DRAW_TRANSP) == 0)
3956 {
3957 Rect rc;
3958
3959 rc.left = FILL_X(col);
3960 rc.top = FILL_Y(row);
3961 /* Multibyte computation taken from gui_w32.c */
3962 if (has_mbyte)
3963 {
3964 int cell_len = 0;
3965 int n;
3966
3967 /* Compute the length in display cells. */
3968 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3969 cell_len += (*mb_ptr2cells)(s + n);
3970 rc.right = FILL_X(col + cell_len);
3971 }
3972 else
3973 rc.right = FILL_X(col + len) + (col + len == Columns);
3974
3975 rc.bottom = FILL_Y(row + 1);
3976 EraseRect(&rc);
3977 }
3978
3979 {
3980 /* Use old-style, non-antialiased QuickDraw text rendering. */
3981 TextMode(srcCopy);
3982 TextFace(normal);
3983
3984 /* SelectFont(hdc, gui.currFont); */
3985
3986 if (flags & DRAW_TRANSP)
3987 {
3988 TextMode(srcOr);
3989 }
3990
3991 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003992 ATSUTextLayout textLayout;
3993
3994 if (ATSUCreateTextLayoutWithTextPtr(tofree,
3995 kATSUFromTextBeginning, kATSUToTextEnd,
3996 utf16_len,
3997 (gFontStyle ? 1 : 0), &utf16_len,
3998 (gFontStyle ? &gFontStyle : NULL),
3999 &textLayout) == noErr)
4000 {
4001 ATSUSetTransientFontMatching(textLayout, TRUE);
4002
4003 ATSUDrawText(textLayout,
4004 kATSUFromTextBeginning, kATSUToTextEnd,
4005 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4006
4007 ATSUDisposeTextLayout(textLayout);
4008 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009 }
4010
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004011 if (flags & DRAW_UNDERC)
4012 draw_undercurl(flags, row, col, len);
4013
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004015}
4016#endif
4017
4018 void
4019gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4020{
4021#if defined(USE_ATSUI_DRAWING)
4022 draw_string_ATSUI(row, col, s, len, flags);
4023#else
4024 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025#endif
4026}
4027
4028/*
4029 * Return OK if the key with the termcap name "name" is supported.
4030 */
4031 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004032gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033{
4034 int i;
4035
4036 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4037 if (name[0] == special_keys[i].vim_code0 &&
4038 name[1] == special_keys[i].vim_code1)
4039 return OK;
4040 return FAIL;
4041}
4042
4043 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004044gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004046 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047}
4048
4049 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004050gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051{
4052 /* Do a visual beep by reversing the foreground and background colors */
4053 Rect rc;
4054
4055 /*
4056 * Note: InvertRect() excludes right and bottom of rectangle.
4057 */
4058 rc.left = 0;
4059 rc.top = 0;
4060 rc.right = gui.num_cols * gui.char_width;
4061 rc.bottom = gui.num_rows * gui.char_height;
4062 InvertRect(&rc);
4063
4064 ui_delay((long)msec, TRUE); /* wait for some msec */
4065
4066 InvertRect(&rc);
4067}
4068
4069/*
4070 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4071 */
4072 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004073gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074{
4075 Rect rc;
4076
4077 /*
4078 * Note: InvertRect() excludes right and bottom of rectangle.
4079 */
4080 rc.left = FILL_X(c);
4081 rc.top = FILL_Y(r);
4082 rc.right = rc.left + nc * gui.char_width;
4083 rc.bottom = rc.top + nr * gui.char_height;
4084 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085}
4086
4087/*
4088 * Iconify the GUI window.
4089 */
4090 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004091gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092{
4093 /* TODO: find out what could replace iconify
4094 * -window shade?
4095 * -hide application?
4096 */
4097}
4098
4099#if defined(FEAT_EVAL) || defined(PROTO)
4100/*
4101 * Bring the Vim window to the foreground.
4102 */
4103 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004104gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105{
4106 /* TODO */
4107}
4108#endif
4109
4110/*
4111 * Draw a cursor without focus.
4112 */
4113 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004114gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115{
4116 Rect rc;
4117
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 /*
4119 * Note: FrameRect() excludes right and bottom of rectangle.
4120 */
4121 rc.left = FILL_X(gui.col);
4122 rc.top = FILL_Y(gui.row);
4123 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004124#ifdef FEAT_MBYTE
4125 if (mb_lefthalve(gui.row, gui.col))
4126 rc.right += gui.char_width;
4127#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 rc.bottom = rc.top + gui.char_height;
4129
4130 gui_mch_set_fg_color(color);
4131
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004132 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133}
4134
4135/*
4136 * Draw part of a cursor, only w pixels wide, and h pixels high.
4137 */
4138 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004139gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140{
4141 Rect rc;
4142
4143#ifdef FEAT_RIGHTLEFT
4144 /* vertical line should be on the right of current point */
4145 if (CURSOR_BAR_RIGHT)
4146 rc.left = FILL_X(gui.col + 1) - w;
4147 else
4148#endif
4149 rc.left = FILL_X(gui.col);
4150 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4151 rc.right = rc.left + w;
4152 rc.bottom = rc.top + h;
4153
4154 gui_mch_set_fg_color(color);
4155
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004156 FrameRect(&rc);
4157// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158}
4159
4160
4161
4162/*
4163 * Catch up with any queued X events. This may put keyboard input into the
4164 * input buffer, call resize call-backs, trigger timers etc. If there is
4165 * nothing in the X event queue (& no timers pending), then we return
4166 * immediately.
4167 */
4168 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004169gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170{
4171 /* TODO: find what to do
4172 * maybe call gui_mch_wait_for_chars (0)
4173 * more like look at EventQueue then
4174 * call heart of gui_mch_wait_for_chars;
4175 *
4176 * if (eventther)
4177 * gui_mac_handle_event(&event);
4178 */
4179 EventRecord theEvent;
4180
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004181 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182 if (theEvent.what != nullEvent)
4183 gui_mch_wait_for_chars(0);
4184}
4185
4186/*
4187 * Simple wrapper to neglect more easily the time
4188 * spent inside WaitNextEvent while profiling.
4189 */
4190
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 pascal
4192 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004193WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194{
4195 if (((long) sleep) < -1)
4196 sleep = 32767;
4197 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4198}
4199
4200/*
4201 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4202 * from the keyboard.
4203 * wtime == -1 Wait forever.
4204 * wtime == 0 This should never happen.
4205 * wtime > 0 Wait wtime milliseconds for a character.
4206 * Returns OK if a character was found to be available within the given time,
4207 * or FAIL otherwise.
4208 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004210gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211{
4212 EventMask mask = (everyEvent);
4213 EventRecord event;
4214 long entryTick;
4215 long currentTick;
4216 long sleeppyTick;
4217
4218 /* If we are providing life feedback with the scrollbar,
4219 * we don't want to try to wait for an event, or else
4220 * there won't be any life feedback.
4221 */
4222 if (dragged_sb != NULL)
4223 return FAIL;
4224 /* TODO: Check if FAIL is the proper return code */
4225
4226 entryTick = TickCount();
4227
4228 allow_scrollbar = TRUE;
4229
4230 do
4231 {
4232/* if (dragRectControl == kCreateEmpty)
4233 {
4234 dragRgn = NULL;
4235 dragRectControl = kNothing;
4236 }
4237 else*/ if (dragRectControl == kCreateRect)
4238 {
4239 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004240 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 dragRectControl = kNothing;
4242 }
4243 /*
4244 * Don't use gui_mch_update() because then we will spin-lock until a
4245 * char arrives, instead we use WaitNextEventWrp() to hang until an
4246 * event arrives. No need to check for input_buf_full because we are
4247 * returning as soon as it contains a single char.
4248 */
4249 /* TODO: reduce wtime accordinly??? */
4250 if (wtime > -1)
4251 sleeppyTick = 60*wtime/1000;
4252 else
4253 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004254 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004256 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 if (input_available())
4258 {
4259 allow_scrollbar = FALSE;
4260 return OK;
4261 }
4262 }
4263 currentTick = TickCount();
4264 }
4265 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4266
4267 allow_scrollbar = FALSE;
4268 return FAIL;
4269}
4270
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271/*
4272 * Output routines.
4273 */
4274
4275/* Flush any output to the screen */
4276 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004277gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278{
4279 /* TODO: Is anything needed here? */
4280}
4281
4282/*
4283 * Clear a rectangular region of the screen from text pos (row1, col1) to
4284 * (row2, col2) inclusive.
4285 */
4286 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004287gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288{
4289 Rect rc;
4290
4291 /*
4292 * Clear one extra pixel at the far right, for when bold characters have
4293 * spilled over to the next column.
4294 */
4295 rc.left = FILL_X(col1);
4296 rc.top = FILL_Y(row1);
4297 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4298 rc.bottom = FILL_Y(row2 + 1);
4299
4300 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004301 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302}
4303
4304/*
4305 * Clear the whole text window.
4306 */
4307 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004308gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309{
4310 Rect rc;
4311
4312 rc.left = 0;
4313 rc.top = 0;
4314 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4315 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4316
4317 gui_mch_set_bg_color(gui.back_pixel);
4318 EraseRect(&rc);
4319/* gui_mch_set_fg_color(gui.norm_pixel);
4320 FrameRect(&rc);
4321*/
4322}
4323
4324/*
4325 * Delete the given number of lines from the given row, scrolling up any
4326 * text further down within the scroll region.
4327 */
4328 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004329gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330{
4331 Rect rc;
4332
4333 /* changed without checking! */
4334 rc.left = FILL_X(gui.scroll_region_left);
4335 rc.right = FILL_X(gui.scroll_region_right + 1);
4336 rc.top = FILL_Y(row);
4337 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4338
4339 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004340 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341
4342 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4343 gui.scroll_region_left,
4344 gui.scroll_region_bot, gui.scroll_region_right);
4345}
4346
4347/*
4348 * Insert the given number of lines before the given row, scrolling down any
4349 * following text within the scroll region.
4350 */
4351 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004352gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353{
4354 Rect rc;
4355
4356 rc.left = FILL_X(gui.scroll_region_left);
4357 rc.right = FILL_X(gui.scroll_region_right + 1);
4358 rc.top = FILL_Y(row);
4359 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4360
4361 gui_mch_set_bg_color(gui.back_pixel);
4362
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004363 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364
4365 /* Update gui.cursor_row if the cursor scrolled or copied over */
4366 if (gui.cursor_row >= gui.row
4367 && gui.cursor_col >= gui.scroll_region_left
4368 && gui.cursor_col <= gui.scroll_region_right)
4369 {
4370 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4371 gui.cursor_row += num_lines;
4372 else if (gui.cursor_row <= gui.scroll_region_bot)
4373 gui.cursor_is_valid = FALSE;
4374 }
4375
4376 gui_clear_block(row, gui.scroll_region_left,
4377 row + num_lines - 1, gui.scroll_region_right);
4378}
4379
4380 /*
4381 * TODO: add a vim format to the clipboard which remember
4382 * LINEWISE, CHARWISE, BLOCKWISE
4383 */
4384
4385 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004386clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387{
4388
4389 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004390 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 Size scrapSize;
4392 ScrapFlavorFlags scrapFlags;
4393 ScrapRef scrap = nil;
4394 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395 int type;
4396 char *searchCR;
4397 char_u *tempclip;
4398
4399
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004400 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 if (error != noErr)
4402 return;
4403
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004404 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4405 if (error == noErr)
4406 {
4407 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4408 if (error == noErr && scrapSize > 1)
4409 flavor = 1;
4410 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004412 if (flavor == 0)
4413 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004414 error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004415 if (error != noErr)
4416 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004418 error = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004419 if (error != noErr)
4420 return;
4421 }
4422
4423 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 /* In CARBON we don't need a Handle, a pointer is good */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004427 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 /* tempclip = lalloc(scrapSize+1, TRUE); */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004429 HLock(textOfClip);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004430 error = GetScrapFlavorData(scrap,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004431 flavor ? VIMSCRAPFLAVOR : kScrapFlavorTypeUnicode,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004432 &scrapSize, *textOfClip);
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004433 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004435 if (flavor)
4436 type = **textOfClip;
4437 else
4438 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004440 tempclip = lalloc(scrapSize + 1, TRUE);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004441#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004442 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4443#else
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004444 STRNCPY(tempclip, *textOfClip + flavor, scrapSize);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004445#endif
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004446 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004448#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004449 /* Convert from utf-16 (clipboard) */
4450 size_t encLen = 0;
4451 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
4452 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004454 scrapSize = encLen;
4455 vim_free(tempclip);
4456 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 }
4458#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004459
4460 searchCR = (char *)tempclip;
4461 while (searchCR != NULL)
4462 {
4463 searchCR = strchr(searchCR, '\r');
4464
4465 if (searchCR != NULL)
4466 searchCR[0] = '\n';
4467
4468 }
4469
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 clip_yank_selection(type, tempclip, scrapSize, cbd);
4471
4472 vim_free(tempclip);
4473 HUnlock(textOfClip);
4474
4475 DisposeHandle(textOfClip);
4476 }
4477}
4478
4479 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004480clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481{
4482 /*
4483 * TODO: Really nothing to do?
4484 */
4485}
4486
4487 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004488clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489{
4490 return OK;
4491}
4492
4493/*
4494 * Send the current selection to the clipboard.
4495 */
4496 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004497clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498{
4499 Handle textOfClip;
4500 long scrapSize;
4501 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503
4504 char_u *str = NULL;
4505
4506 if (!cbd->owned)
4507 return;
4508
4509 clip_get_selection(cbd);
4510
4511 /*
4512 * Once we set the clipboard, lose ownership. If another application sets
4513 * the clipboard, we don't want to think that we still own it.
4514 *
4515 */
4516
4517 cbd->owned = FALSE;
4518
4519 type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd);
4520
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004521#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004522 size_t utf16_len = 0;
4523 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4524 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004526 scrapSize = utf16_len;
4527 vim_free(str);
4528 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 }
4530#endif
4531
4532 if (type >= 0)
4533 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004536 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 HLock(textOfClip);
4538
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004539 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004540 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004541 GetCurrentScrap(&scrap);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004542 PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004543 scrapSize, *textOfClip + 1);
4544 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4545 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 HUnlock(textOfClip);
4547 DisposeHandle(textOfClip);
4548 }
4549
4550 vim_free(str);
4551}
4552
4553 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004554gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555{
4556 Rect VimBound;
4557
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004558/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560
4561 if (gui.which_scrollbars[SBAR_LEFT])
4562 {
4563 VimBound.left = -gui.scrollbar_width + 1;
4564 }
4565 else
4566 {
4567 VimBound.left = 0;
4568 }
4569
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004572 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573}
4574
4575/*
4576 * Menu stuff.
4577 */
4578
4579 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004580gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581{
4582 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004583 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 */
4585}
4586
4587 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004588gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589{
4590 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004591 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 */
4593}
4594
4595/*
4596 * Add a sub menu to the menu bar.
4597 */
4598 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004599gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600{
4601 /*
4602 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4603 * TODO: use menu->mnemonic and menu->actext
4604 * TODO: Try to reuse menu id
4605 * Carbon Help suggest to use only id between 1 and 235
4606 */
4607 static long next_avail_id = 128;
4608 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004609#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004610 CFStringRef name;
4611#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004613#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 short index;
4615 vimmenu_T *parent = menu->parent;
4616 vimmenu_T *brother = menu->next;
4617
4618 /* Cannot add a menu if ... */
4619 if ((parent != NULL && parent->submenu_id == 0))
4620 return;
4621
4622 /* menu ID greater than 1024 are reserved for ??? */
4623 if (next_avail_id == 1024)
4624 return;
4625
4626 /* My brother could be the PopUp, find my real brother */
4627 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4628 brother = brother->next;
4629
4630 /* Find where to insert the menu (for MenuBar) */
4631 if ((parent == NULL) && (brother != NULL))
4632 menu_after_me = brother->submenu_id;
4633
4634 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4635 if (!menu_is_menubar(menu->name))
4636 menu_after_me = hierMenu;
4637
4638 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004639#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004640 name = menu_title_removing_mnemonic(menu);
4641#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004643#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 if (name == NULL)
4645 return;
4646
4647 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 {
4649 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004650 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4651 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652 */
4653 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004654#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004655 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4656 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4657#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004658 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004659#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660 next_avail_id++;
4661 }
4662
4663 if (parent == NULL)
4664 {
4665 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4666
4667 /* TODO: Verify if we could only Insert Menu if really part of the
4668 * menubar The Inserted menu are scanned or the Command-key combos
4669 */
4670
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004671 /* Insert the menu */
4672 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673#if 1
4674 /* Vim should normally update it. TODO: verify */
4675 DrawMenuBar();
4676#endif
4677 }
4678 else
4679 {
4680 /* Adding as a submenu */
4681
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004682 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683
4684 /* Call InsertMenuItem followed by SetMenuItemText
4685 * to avoid special character recognition by InsertMenuItem
4686 */
4687 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004688#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004689 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4690#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004692#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4694 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4695 InsertMenu(menu->submenu_handle, hierMenu);
4696 }
4697
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004698#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004699 CFRelease(name);
4700#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004701 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703
4704#if 0
4705 /* Done by Vim later on */
4706 DrawMenuBar();
4707#endif
4708}
4709
4710/*
4711 * Add a menu item to a menu
4712 */
4713 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004714gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004716#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004717 CFStringRef name;
4718#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004720#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 vimmenu_T *parent = menu->parent;
4722 int menu_inserted;
4723
4724 /* Cannot add item, if the menu have not been created */
4725 if (parent->submenu_id == 0)
4726 return;
4727
4728 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4729 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4730
4731 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004732#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004733 name = menu_title_removing_mnemonic(menu);
4734#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004736#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737
4738 /* Where are just a menu item, so no handle, no id */
4739 menu->submenu_id = 0;
4740 menu->submenu_handle = NULL;
4741
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 menu_inserted = 0;
4743 if (menu->actext)
4744 {
4745 /* If the accelerator text for the menu item looks like it describes
4746 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4747 * item's command equivalent.
4748 */
4749 int key = 0;
4750 int modifiers = 0;
4751 char_u *p_actext;
4752
4753 p_actext = menu->actext;
4754 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4755 if (*p_actext != 0)
4756 key = 0; /* error: trailing text */
4757 /* find_special_key() returns a keycode with as many of the
4758 * specified modifiers as appropriate already applied (e.g., for
4759 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4760 * as the only modifier). Since we want to display all of the
4761 * modifiers, we need to convert the keycode back to a printable
4762 * character plus modifiers.
4763 * TODO: Write an alternative find_special_key() that doesn't
4764 * apply modifiers.
4765 */
4766 if (key > 0 && key < 32)
4767 {
4768 /* Convert a control key to an uppercase letter. Note that
4769 * by this point it is no longer possible to distinguish
4770 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4771 */
4772 modifiers |= MOD_MASK_CTRL;
4773 key += '@';
4774 }
4775 /* If the keycode is an uppercase letter, set the Shift modifier.
4776 * If it is a lowercase letter, don't set the modifier, but convert
4777 * the letter to uppercase for display in the menu.
4778 */
4779 else if (key >= 'A' && key <= 'Z')
4780 modifiers |= MOD_MASK_SHIFT;
4781 else if (key >= 'a' && key <= 'z')
4782 key += 'A' - 'a';
4783 /* Note: keycodes below 0x22 are reserved by Apple. */
4784 if (key >= 0x22 && vim_isprintc_strict(key))
4785 {
4786 int valid = 1;
4787 char_u mac_mods = kMenuNoModifiers;
4788 /* Convert Vim modifier codes to Menu Manager equivalents. */
4789 if (modifiers & MOD_MASK_SHIFT)
4790 mac_mods |= kMenuShiftModifier;
4791 if (modifiers & MOD_MASK_CTRL)
4792 mac_mods |= kMenuControlModifier;
4793 if (!(modifiers & MOD_MASK_CMD))
4794 mac_mods |= kMenuNoCommandModifier;
4795 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4796 valid = 0; /* TODO: will Alt someday map to Option? */
4797 if (valid)
4798 {
4799 char_u item_txt[10];
4800 /* Insert the menu item after idx, with its command key. */
4801 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4802 item_txt[3] = key;
4803 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4804 /* Set the modifier keys. */
4805 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4806 menu_inserted = 1;
4807 }
4808 }
4809 }
4810 /* Call InsertMenuItem followed by SetMenuItemText
4811 * to avoid special character recognition by InsertMenuItem
4812 */
4813 if (!menu_inserted)
4814 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4815 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004816#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004817 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4818#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004820#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821
4822#if 0
4823 /* Called by Vim */
4824 DrawMenuBar();
4825#endif
4826
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004827#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004828 CFRelease(name);
4829#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830 /* TODO: Can name be freed? */
4831 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004832#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833}
4834
4835 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004836gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837{
4838 /* no tearoff menus */
4839}
4840
4841/*
4842 * Destroy the machine specific menu widget.
4843 */
4844 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004845gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004847 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848
4849 if (index > 0)
4850 {
4851 if (menu->parent)
4852 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 {
4854 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004855 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856
4857 /* Delete the Menu if it was a hierarchical Menu */
4858 if (menu->submenu_id != 0)
4859 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004860 DeleteMenu(menu->submenu_id);
4861 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 }
4863 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004864 }
4865#ifdef DEBUG_MAC_MENU
4866 else
4867 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004868 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869 }
4870#endif
4871 }
4872 else
4873 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004875 DeleteMenu(menu->submenu_id);
4876 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 }
4878 }
4879 /* Shouldn't this be already done by Vim. TODO: Check */
4880 DrawMenuBar();
4881}
4882
4883/*
4884 * Make a menu either grey or not grey.
4885 */
4886 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004887gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888{
4889 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004890 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891/*
4892 index = menu->index;
4893*/
4894 if (grey)
4895 {
4896 if (menu->children)
4897 DisableMenuItem(menu->submenu_handle, index);
4898 if (menu->parent)
4899 if (menu->parent->submenu_handle)
4900 DisableMenuItem(menu->parent->submenu_handle, index);
4901 }
4902 else
4903 {
4904 if (menu->children)
4905 EnableMenuItem(menu->submenu_handle, index);
4906 if (menu->parent)
4907 if (menu->parent->submenu_handle)
4908 EnableMenuItem(menu->parent->submenu_handle, index);
4909 }
4910}
4911
4912/*
4913 * Make menu item hidden or not hidden
4914 */
4915 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004916gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004917{
4918 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004919 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920}
4921
4922
4923/*
4924 * This is called after setting all the menus to grey/hidden or not.
4925 */
4926 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004927gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928{
4929 DrawMenuBar();
4930}
4931
4932
4933/*
4934 * Scrollbar stuff.
4935 */
4936
4937 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004938gui_mch_enable_scrollbar(
4939 scrollbar_T *sb,
4940 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941{
4942 if (flag)
4943 ShowControl(sb->id);
4944 else
4945 HideControl(sb->id);
4946
4947#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004948 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949#endif
4950}
4951
4952 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004953gui_mch_set_scrollbar_thumb(
4954 scrollbar_T *sb,
4955 long val,
4956 long size,
4957 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004958{
4959 SetControl32BitMaximum (sb->id, max);
4960 SetControl32BitMinimum (sb->id, 0);
4961 SetControl32BitValue (sb->id, val);
4962#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004963 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004964#endif
4965}
4966
4967 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004968gui_mch_set_scrollbar_pos(
4969 scrollbar_T *sb,
4970 int x,
4971 int y,
4972 int w,
4973 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974{
4975 gui_mch_set_bg_color(gui.back_pixel);
4976/* if (gui.which_scrollbars[SBAR_LEFT])
4977 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004978 MoveControl(sb->id, x-16, y);
4979 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980 }
4981 else
4982 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004983 MoveControl(sb->id, x, y);
4984 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985 }*/
4986 if (sb == &gui.bottom_sbar)
4987 h += 1;
4988 else
4989 w += 1;
4990
4991 if (gui.which_scrollbars[SBAR_LEFT])
4992 x -= 15;
4993
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004994 MoveControl(sb->id, x, y);
4995 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004997 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004998#endif
4999}
5000
5001 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005002gui_mch_create_scrollbar(
5003 scrollbar_T *sb,
5004 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005{
5006 Rect bounds;
5007
5008 bounds.top = -16;
5009 bounds.bottom = -10;
5010 bounds.right = -10;
5011 bounds.left = -16;
5012
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005013 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 &bounds,
5015 "\pScrollBar",
5016 TRUE,
5017 0, /* current*/
5018 0, /* top */
5019 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005021 (long) sb->ident);
5022#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005023 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024#endif
5025}
5026
5027 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005028gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029{
5030 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005031 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005033 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034#endif
5035}
5036
5037
5038/*
5039 * Cursor blink functions.
5040 *
5041 * This is a simple state machine:
5042 * BLINK_NONE not blinking at all
5043 * BLINK_OFF blinking, cursor is not shown
5044 * BLINK_ON blinking, cursor is shown
5045 */
5046 void
5047gui_mch_set_blinking(long wait, long on, long off)
5048{
5049 /* TODO: TODO: TODO: TODO: */
5050/* blink_waittime = wait;
5051 blink_ontime = on;
5052 blink_offtime = off;*/
5053}
5054
5055/*
5056 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5057 */
5058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005059gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060{
5061 gui_update_cursor(TRUE, FALSE);
5062 /* TODO: TODO: TODO: TODO: */
5063/* gui_w32_rm_blink_timer();
5064 if (blink_state == BLINK_OFF)
5065 gui_update_cursor(TRUE, FALSE);
5066 blink_state = BLINK_NONE;*/
5067}
5068
5069/*
5070 * Start the cursor blinking. If it was already blinking, this restarts the
5071 * waiting time and shows the cursor.
5072 */
5073 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005074gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075{
5076 gui_update_cursor(TRUE, FALSE);
5077 /* TODO: TODO: TODO: TODO: */
5078/* gui_w32_rm_blink_timer(); */
5079
5080 /* Only switch blinking on if none of the times is zero */
5081/* if (blink_waittime && blink_ontime && blink_offtime)
5082 {
5083 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5084 (TIMERPROC)_OnBlinkTimer);
5085 blink_state = BLINK_ON;
5086 gui_update_cursor(TRUE, FALSE);
5087 }*/
5088}
5089
5090/*
5091 * Return the RGB value of a pixel as long.
5092 */
5093 long_u
5094gui_mch_get_rgb(guicolor_T pixel)
5095{
5096 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5097}
5098
5099
5100
5101#ifdef FEAT_BROWSE
5102/*
5103 * Pop open a file browser and return the file selected, in allocated memory,
5104 * or NULL if Cancel is hit.
5105 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5106 * title - Title message for the file browser dialog.
5107 * dflt - Default name of file.
5108 * ext - Default extension to be added to files without extensions.
5109 * initdir - directory in which to open the browser (NULL = current dir)
5110 * filter - Filter for matched files to choose from.
5111 * Has a format like this:
5112 * "C Files (*.c)\0*.c\0"
5113 * "All Files\0*.*\0\0"
5114 * If these two strings were concatenated, then a choice of two file
5115 * filters will be selectable to the user. Then only matching files will
5116 * be shown in the browser. If NULL, the default allows all files.
5117 *
5118 * *NOTE* - the filter string must be terminated with TWO nulls.
5119 */
5120 char_u *
5121gui_mch_browse(
5122 int saving,
5123 char_u *title,
5124 char_u *dflt,
5125 char_u *ext,
5126 char_u *initdir,
5127 char_u *filter)
5128{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005129 /* TODO: Add Ammon's safety checl (Dany) */
5130 NavReplyRecord reply;
5131 char_u *fname = NULL;
5132 char_u **fnames = NULL;
5133 long numFiles;
5134 NavDialogOptions navOptions;
5135 OSErr error;
5136
5137 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005138 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139
5140
5141 /* TODO: If we get a :browse args, set the Multiple bit. */
5142 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5143 | kNavDontAutoTranslate
5144 | kNavDontAddTranslateItems
5145 /* | kNavAllowMultipleFiles */
5146 | kNavAllowStationery;
5147
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005148 (void) C2PascalString(title, &navOptions.message);
5149 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150 /* Could set clientName?
5151 * windowTitle? (there's no title bar?)
5152 */
5153
5154 if (saving)
5155 {
5156 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005157 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158 if (!reply.validRecord)
5159 return NULL;
5160 }
5161 else
5162 {
5163 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5164 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5165 if (!reply.validRecord)
5166 return NULL;
5167 }
5168
5169 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5170
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005171 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172
5173 if (fnames)
5174 {
5175 fname = fnames[0];
5176 vim_free(fnames);
5177 }
5178
5179 /* TODO: Shorten the file name if possible */
5180 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181}
5182#endif /* FEAT_BROWSE */
5183
5184#ifdef FEAT_GUI_DIALOG
5185/*
5186 * Stuff for dialogues
5187 */
5188
5189/*
5190 * Create a dialogue dynamically from the parameter strings.
5191 * type = type of dialogue (question, alert, etc.)
5192 * title = dialogue title. may be NULL for default title.
5193 * message = text to display. Dialogue sizes to accommodate it.
5194 * buttons = '\n' separated list of button captions, default first.
5195 * dfltbutton = number of default button.
5196 *
5197 * This routine returns 1 if the first button is pressed,
5198 * 2 for the second, etc.
5199 *
5200 * 0 indicates Esc was pressed.
5201 * -1 for unexpected error
5202 *
5203 * If stubbing out this fn, return 1.
5204 */
5205
5206typedef struct
5207{
5208 short idx;
5209 short width; /* Size of the text in pixel */
5210 Rect box;
5211} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5212
5213#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5214
5215 static void
5216macMoveDialogItem(
5217 DialogRef theDialog,
5218 short itemNumber,
5219 short X,
5220 short Y,
5221 Rect *inBox)
5222{
5223#if 0 /* USE_CARBONIZED */
5224 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005225 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005226 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005227 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005228#else
5229 short itemType;
5230 Handle itemHandle;
5231 Rect localBox;
5232 Rect *itemBox = &localBox;
5233
5234 if (inBox != nil)
5235 itemBox = inBox;
5236
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005237 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5238 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5239 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 /* To move a control (like a button) we need to call both
5241 * MoveControl and SetDialogItem. FAQ 6-18 */
5242 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005243 MoveControl((ControlRef) itemHandle, X, Y);
5244 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245#endif
5246}
5247
5248 static void
5249macSizeDialogItem(
5250 DialogRef theDialog,
5251 short itemNumber,
5252 short width,
5253 short height)
5254{
5255 short itemType;
5256 Handle itemHandle;
5257 Rect itemBox;
5258
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005259 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260
5261 /* When width or height is zero do not change it */
5262 if (width == 0)
5263 width = itemBox.right - itemBox.left;
5264 if (height == 0)
5265 height = itemBox.bottom - itemBox.top;
5266
5267#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005268 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005269#else
5270 /* Resize the bounding box */
5271 itemBox.right = itemBox.left + width;
5272 itemBox.bottom = itemBox.top + height;
5273
5274 /* To resize a control (like a button) we need to call both
5275 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5276 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005277 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278
5279 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005280 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005281#endif
5282}
5283
5284 static void
5285macSetDialogItemText(
5286 DialogRef theDialog,
5287 short itemNumber,
5288 Str255 itemName)
5289{
5290 short itemType;
5291 Handle itemHandle;
5292 Rect itemBox;
5293
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005294 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005295
5296 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005297 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005298 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005299 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300}
5301
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005302/* TODO: There have been some crashes with dialogs, check your inbox
5303 * (Jussi)
5304 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005305 int
5306gui_mch_dialog(
5307 int type,
5308 char_u *title,
5309 char_u *message,
5310 char_u *buttons,
5311 int dfltbutton,
5312 char_u *textfield)
5313{
5314 Handle buttonDITL;
5315 Handle iconDITL;
5316 Handle inputDITL;
5317 Handle messageDITL;
5318 Handle itemHandle;
5319 Handle iconHandle;
5320 DialogPtr theDialog;
5321 char_u len;
5322 char_u PascalTitle[256]; /* place holder for the title */
5323 char_u name[256];
5324 GrafPtr oldPort;
5325 short itemHit;
5326 char_u *buttonChar;
5327 Rect box;
5328 short button;
5329 short lastButton;
5330 short itemType;
5331 short useIcon;
5332 short width;
5333 short totalButtonWidth = 0; /* the width of all button together incuding spacing */
5334 short widestButton = 0;
5335 short dfltButtonEdge = 20; /* gut feeling */
5336 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5337 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5338 short maximumWidth = 400; /* gut feeling */
5339 short maxButtonWidth = 175; /* gut feeling */
5340
5341 short vertical;
5342 short dialogHeight;
5343 short messageLines = 3;
5344 FontInfo textFontInfo;
5345
5346 vgmDlgItm iconItm;
5347 vgmDlgItm messageItm;
5348 vgmDlgItm inputItm;
5349 vgmDlgItm buttonItm;
5350
5351 WindowRef theWindow;
5352
5353 /* Check 'v' flag in 'guioptions': vertical button placement. */
5354 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5355
5356 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005357 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005358
5359 /* Get the WindowRef */
5360 theWindow = GetDialogWindow(theDialog);
5361
5362 /* Hide the window.
5363 * 1. to avoid seeing slow drawing
5364 * 2. to prevent a problem seen while moving dialog item
5365 * within a visible window. (non-Carbon MacOS 9)
5366 * Could be avoided by changing the resource.
5367 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005368 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005369
5370 /* Change the graphical port to the dialog,
5371 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005372 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005373 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005374
5375 /* Get the info about the default text,
5376 * used to calculate the height of the message
5377 * and of the text field */
5378 GetFontInfo(&textFontInfo);
5379
5380 /* Set the dialog title */
5381 if (title != NULL)
5382 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005383 (void) C2PascalString(title, &PascalTitle);
5384 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005385 }
5386
5387 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005388 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005389 buttonChar = buttons;
5390 button = 0;
5391
5392 for (;*buttonChar != 0;)
5393 {
5394 /* Get the name of the button */
5395 button++;
5396 len = 0;
5397 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5398 {
5399 if (*buttonChar != DLG_HOTKEY_CHAR)
5400 name[++len] = *buttonChar;
5401 }
5402 if (*buttonChar != 0)
5403 buttonChar++;
5404 name[0] = len;
5405
5406 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005407 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005408
5409 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005410 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005411
5412 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005413 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005414 /* Limite the size of any button to an acceptable value. */
5415 /* TODO: Should be based on the message width */
5416 if (width > maxButtonWidth)
5417 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005418 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419
5420 totalButtonWidth += width;
5421
5422 if (width > widestButton)
5423 widestButton = width;
5424 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005425 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005426 lastButton = button;
5427
5428 /* Add the icon to the Dialog Box. */
5429 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005430 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005431 switch (type)
5432 {
5433 case VIM_GENERIC: useIcon = kNoteIcon;
5434 case VIM_ERROR: useIcon = kStopIcon;
5435 case VIM_WARNING: useIcon = kCautionIcon;
5436 case VIM_INFO: useIcon = kNoteIcon;
5437 case VIM_QUESTION: useIcon = kNoteIcon;
5438 default: useIcon = kStopIcon;
5439 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005440 AppendDITL(theDialog, iconDITL, overlayDITL);
5441 ReleaseResource(iconDITL);
5442 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005443 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005444 iconHandle = GetIcon(useIcon);
5445 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446
5447 /* Add the message to the Dialog box. */
5448 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005449 messageDITL = GetResource('DITL', 132);
5450 AppendDITL(theDialog, messageDITL, overlayDITL);
5451 ReleaseResource(messageDITL);
5452 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5453 (void) C2PascalString(message, &name);
5454 SetDialogItemText(itemHandle, name);
5455 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456
5457 /* Add the input box if needed */
5458 if (textfield != NULL)
5459 {
5460 /* Cheat for now reuse the message and convet to text edit */
5461 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005462 inputDITL = GetResource('DITL', 132);
5463 AppendDITL(theDialog, inputDITL, overlayDITL);
5464 ReleaseResource(inputDITL);
5465 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5466/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5467 (void) C2PascalString(textfield, &name);
5468 SetDialogItemText(itemHandle, name);
5469 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470 }
5471
5472 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005473 SetDialogDefaultItem(theDialog, dfltbutton);
5474 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005475
5476 /* Reposition element */
5477
5478 /* Check if we need to force vertical */
5479 if (totalButtonWidth > maximumWidth)
5480 vertical = TRUE;
5481
5482 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005483 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484 iconItm.box.right = box.right;
5485 iconItm.box.bottom = box.bottom;
5486
5487 /* Place Message */
5488 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005489 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5490 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005491
5492 /* Place Input */
5493 if (textfield != NULL)
5494 {
5495 inputItm.box.left = messageItm.box.left;
5496 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005497 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5498 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005499 /* Convert the static text into a text edit.
5500 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005501 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5502 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5504 }
5505
5506 /* Place Button */
5507 if (textfield != NULL)
5508 {
5509 buttonItm.box.left = inputItm.box.left;
5510 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5511 }
5512 else
5513 {
5514 buttonItm.box.left = messageItm.box.left;
5515 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5516 }
5517
5518 for (button=1; button <= lastButton; button++)
5519 {
5520
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005521 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005522 /* With vertical, it's better to have all button the same lenght */
5523 if (vertical)
5524 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005525 macSizeDialogItem(theDialog, button, widestButton, 0);
5526 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 }
5528 /* Calculate position of next button */
5529 if (vertical)
5530 buttonItm.box.top = box.bottom + dfltElementSpacing;
5531 else
5532 buttonItm.box.left = box.right + dfltElementSpacing;
5533 }
5534
5535 /* Resize the dialog box */
5536 dialogHeight = box.bottom + dfltElementSpacing;
5537 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5538
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005540 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005541 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005542
5543 /* Display it */
5544 ShowWindow(theWindow);
5545/* BringToFront(theWindow); */
5546 SelectWindow(theWindow);
5547
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005548/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005549#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005550 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005551 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005552#endif
5553
5554 /* Hang until one of the button is hit */
5555 do
5556 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005557 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005558 } while ((itemHit < 1) || (itemHit > lastButton));
5559
5560 /* Copy back the text entered by the user into the param */
5561 if (textfield != NULL)
5562 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005563 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5564 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005565#if IOSIZE < 256
5566 /* Truncate the name to IOSIZE if needed */
5567 if (name[0] > IOSIZE)
5568 name[0] = IOSIZE - 1;
5569#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005570 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571 }
5572
5573 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005574 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005575
5576 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005577 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005578
5579 return itemHit;
5580/*
5581 * Usefull thing which could be used
5582 * SetDialogTimeout(): Auto click a button after timeout
5583 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5584 * MoveDialogItem(): Probably better than SetDialogItem
5585 * SizeDialogItem(): (but is it Carbon Only?)
5586 * AutoSizeDialog(): Magic resize of dialog based on text lenght
5587 */
5588}
5589#endif /* FEAT_DIALOG_GUI */
5590
5591/*
5592 * Display the saved error message(s).
5593 */
5594#ifdef USE_MCH_ERRMSG
5595 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005596display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005597{
5598 char *p;
5599 char_u pError[256];
5600
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005601 if (error_ga.ga_data == NULL)
5602 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005603
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005604 /* avoid putting up a message box with blanks only */
5605 for (p = (char *)error_ga.ga_data; *p; ++p)
5606 if (!isspace(*p))
5607 {
5608 if (STRLEN(p) > 255)
5609 pError[0] = 255;
5610 else
5611 pError[0] = STRLEN(p);
5612
5613 STRNCPY(&pError[1], p, pError[0]);
5614 ParamText(pError, nil, nil, nil);
5615 Alert(128, nil);
5616 break;
5617 /* TODO: handled message longer than 256 chars
5618 * use auto-sizeable alert
5619 * or dialog with scrollbars (TextEdit zone)
5620 */
5621 }
5622 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623}
5624#endif
5625
5626/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005627 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005628 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005629 void
5630gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005631{
5632 Point where;
5633
5634 GetMouse(&where);
5635
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005636 *x = where.h;
5637 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638}
5639
5640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005641gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005642{
5643 /* TODO */
5644#if 0
5645 /* From FAQ 3-11 */
5646
5647 CursorDevicePtr myMouse;
5648 Point where;
5649
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005650 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5651 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 {
5653 /* New way */
5654
5655 /*
5656 * Get first devoice with one button.
5657 * This will probably be the standad mouse
5658 * startat head of cursor dev list
5659 *
5660 */
5661
5662 myMouse = nil;
5663
5664 do
5665 {
5666 /* Get the next cursor device */
5667 CursorDeviceNextDevice(&myMouse);
5668 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005669 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005671 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005672 }
5673 else
5674 {
5675 /* Old way */
5676 where.h = x;
5677 where.v = y;
5678
5679 *(Point *)RawMouse = where;
5680 *(Point *)MTemp = where;
5681 *(Ptr) CrsrNew = 0xFFFF;
5682 }
5683#endif
5684}
5685
5686 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005687gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689/*
5690 * Clone PopUp to use menu
5691 * Create a object descriptor for the current selection
5692 * Call the procedure
5693 */
5694
5695 MenuHandle CntxMenu;
5696 Point where;
5697 OSStatus status;
5698 UInt32 CntxType;
5699 SInt16 CntxMenuID;
5700 UInt16 CntxMenuItem;
5701 Str255 HelpName = "";
5702 GrafPtr savePort;
5703
5704 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005705 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 GetMouse(&where);
5708 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709 CntxMenu = menu->submenu_handle;
5710
5711 /* TODO: Get the text selection from Vim */
5712
5713 /* Call to Handle Popup */
5714 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemNoHelp, HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
5715
5716 if (status == noErr)
5717 {
5718 if (CntxType == kCMMenuItemSelected)
5719 {
5720 /* Handle the menu CntxMenuID, CntxMenuItem */
5721 /* The submenu can be handle directly by gui_mac_handle_menu */
5722 /* But what about the current menu, is the menu changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005723 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724 }
5725 else if (CntxMenuID == kCMShowHelpSelected)
5726 {
5727 /* Should come up with the help */
5728 }
5729 }
5730
5731 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005732 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733}
5734
5735#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5736/* TODO: Is it need for MACOS_X? (Dany) */
5737 void
5738mch_post_buffer_write(buf_T *buf)
5739{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005740 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5741 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005742}
5743#endif
5744
5745#ifdef FEAT_TITLE
5746/*
5747 * Set the window title and icon.
5748 * (The icon is not taken care of).
5749 */
5750 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005751gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752{
5753 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5754 * that 256. Even better get it to fit nicely in the titlebar.
5755 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005756#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005757 CFStringRef windowTitle;
5758 size_t windowTitleLen;
5759#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005761#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762
5763 if (title == NULL) /* nothing to do */
5764 return;
5765
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005766#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005767 windowTitleLen = STRLEN(title);
5768 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
5769
5770 if (windowTitle)
5771 {
5772 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5773 CFRelease(windowTitle);
5774 }
5775#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776 pascalTitle = C2Pascal_save(title);
5777 if (pascalTitle != NULL)
5778 {
5779 SetWTitle(gui.VimWindow, pascalTitle);
5780 vim_free(pascalTitle);
5781 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005782#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783}
5784#endif
5785
5786/*
5787 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5788 */
5789
5790 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005791C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792{
5793 char_u *PascalPtr = (char_u *) PascalString;
5794 int len;
5795 int i;
5796
5797 PascalPtr[0] = 0;
5798 if (CString == NULL)
5799 return 0;
5800
5801 len = STRLEN(CString);
5802 if (len > 255)
5803 len = 255;
5804
5805 for (i = 0; i < len; i++)
5806 PascalPtr[i+1] = CString[i];
5807
5808 PascalPtr[0] = len;
5809
5810 return 0;
5811}
5812
5813 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005814GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815{
5816 /* From FAQ 8-12 */
5817 Str255 filePascal;
5818 CInfoPBRec myCPB;
5819 OSErr err;
5820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005821 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822
5823 myCPB.dirInfo.ioNamePtr = filePascal;
5824 myCPB.dirInfo.ioVRefNum = 0;
5825 myCPB.dirInfo.ioFDirIndex = 0;
5826 myCPB.dirInfo.ioDrDirID = 0;
5827
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005828 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829
5830 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005831 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832
5833 /* TODO: Use an error code mechanism */
5834 return 0;
5835}
5836
5837/*
5838 * Convert a FSSpec to a fuill path
5839 */
5840
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005841char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842{
5843 /*
5844 * TODO: Add protection for 256 char max.
5845 */
5846
5847 CInfoPBRec theCPB;
5848 char_u fname[256];
5849 char_u *filenamePtr = fname;
5850 OSErr error;
5851 int folder = 1;
5852#ifdef USE_UNIXFILENAME
5853 SInt16 dfltVol_vRefNum;
5854 SInt32 dfltVol_dirID;
5855 FSRef refFile;
5856 OSStatus status;
5857 UInt32 pathSize = 256;
5858 char_u pathname[256];
5859 char_u *path = pathname;
5860#else
5861 Str255 directoryName;
5862 char_u temporary[255];
5863 char_u *temporaryPtr = temporary;
5864#endif
5865
5866#ifdef USE_UNIXFILENAME
5867 /* Get the default volume */
5868 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005869 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870
5871 if (error)
5872 return NULL;
5873#endif
5874
5875 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005876 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877
5878 /* Get the info about the file specified in FSSpec */
5879 theCPB.dirInfo.ioFDirIndex = 0;
5880 theCPB.dirInfo.ioNamePtr = file.name;
5881 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5882 /*theCPB.hFileInfo.ioDirID = 0;*/
5883 theCPB.dirInfo.ioDrDirID = file.parID;
5884
5885 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5886 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005887 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888
5889 /* If we are called for a new file we expect fnfErr */
5890 if ((error) && (error != fnfErr))
5891 return NULL;
5892
5893 /* Check if it's a file or folder */
5894 /* default to file if file don't exist */
5895 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
5896 folder = 0; /* It's not a folder */
5897 else
5898 folder = 1;
5899
5900#ifdef USE_UNIXFILENAME
5901 /*
5902 * The function used here are available in Carbon, but
5903 * do nothing une MacOS 8 and 9
5904 */
5905 if (error == fnfErr)
5906 {
5907 /* If the file to be saved does not already exist, it isn't possible
5908 to convert its FSSpec into an FSRef. But we can construct an
5909 FSSpec for the file's parent folder (since we have its volume and
5910 directory IDs), and since that folder does exist, we can convert
5911 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5912 and, finally, append the filename. */
5913 FSSpec dirSpec;
5914 FSRef dirRef;
5915 Str255 emptyFilename = "\p";
5916 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
5917 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
5918 if (error)
5919 return NULL;
5920
5921 error = FSpMakeFSRef(&dirSpec, &dirRef);
5922 if (error)
5923 return NULL;
5924
5925 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
5926 if (status)
5927 return NULL;
5928
5929 STRCAT(path, "/");
5930 STRCAT(path, filenamePtr);
5931 }
5932 else
5933 {
5934 /* If the file to be saved already exists, we can get its full path
5935 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005936 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005937 if (error)
5938 return NULL;
5939
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005940 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941 if (status)
5942 return NULL;
5943 }
5944
5945 /* Add a slash at the end if needed */
5946 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005947 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005949 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950#else
5951 /* TODO: Get rid of all USE_UNIXFILENAME below */
5952 /* Set ioNamePtr, it's the same area which is always reused. */
5953 theCPB.dirInfo.ioNamePtr = directoryName;
5954
5955 /* Trick for first entry, set ioDrParID to the first value
5956 * we want for ioDrDirID*/
5957 theCPB.dirInfo.ioDrParID = file.parID;
5958 theCPB.dirInfo.ioDrDirID = file.parID;
5959
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005960 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005961 do
5962 {
5963 theCPB.dirInfo.ioFDirIndex = -1;
5964 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5965 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5966 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
5967 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5968
5969 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5970 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005971 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005972
5973 if (error)
5974 return NULL;
5975
5976 /* Put the new directoryName in front of the current fname */
5977 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005978 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005979 STRCAT(filenamePtr, ":");
5980 STRCAT(filenamePtr, temporaryPtr);
5981 }
5982#if 1 /* def USE_UNIXFILENAME */
5983 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
5984 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5985#else
5986 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
5987#endif
5988
5989 /* Get the information about the volume on which the file reside */
5990 theCPB.dirInfo.ioFDirIndex = -1;
5991 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5992 theCPB.dirInfo.ioVRefNum = file.vRefNum;
5993 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */
5994 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5995
5996 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5997 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005998 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005999
6000 if (error)
6001 return NULL;
6002
6003 /* For MacOS Classic always add the volume name */
6004 /* For MacOS X add the volume name preceded by "Volumes" */
6005 /* when we are not refering to the boot volume */
6006#ifdef USE_UNIXFILENAME
6007 if (file.vRefNum != dfltVol_vRefNum)
6008#endif
6009 {
6010 /* Add the volume name */
6011 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006012 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006013 STRCAT(filenamePtr, ":");
6014 STRCAT(filenamePtr, temporaryPtr);
6015
6016#ifdef USE_UNIXFILENAME
6017 STRCPY(temporaryPtr, filenamePtr);
6018 filenamePtr[0] = 0; /* NULL terminate the string */
6019 STRCAT(filenamePtr, "Volumes:");
6020 STRCAT(filenamePtr, temporaryPtr);
6021#endif
6022 }
6023
6024 /* Append final path separator if it's a folder */
6025 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006026 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006027
6028 /* As we use Unix File Name for MacOS X convert it */
6029#ifdef USE_UNIXFILENAME
6030 /* Need to insert leading / */
6031 /* TODO: get the above code to use directly the / */
6032 STRCPY(&temporaryPtr[1], filenamePtr);
6033 temporaryPtr[0] = '/';
6034 STRCPY(filenamePtr, temporaryPtr);
6035 {
6036 char *p;
6037 for (p = fname; *p; p++)
6038 if (*p == ':')
6039 *p = '/';
6040 }
6041#endif
6042
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006043 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044#endif
6045}
6046
6047#if defined(USE_IM_CONTROL) || defined(PROTO)
6048/*
6049 * Input Method Control functions.
6050 */
6051
6052/*
6053 * Notify cursor position to IM.
6054 */
6055 void
6056im_set_position(int row, int col)
6057{
6058 /* TODO: Implement me! */
6059}
6060
6061/*
6062 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6063 */
6064 void
6065im_set_active(int active)
6066{
6067 KeyScript(active ? smKeySysScript : smKeyRoman);
6068}
6069
6070/*
6071 * Get IM status. When IM is on, return not 0. Else return 0.
6072 */
6073 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006074im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006075{
6076 SInt32 script = GetScriptManagerVariable(smKeyScript);
6077 return (script != smRoman
6078 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6079}
6080#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */