blob: 93feabe926a2b72bb5d11ae5773bbfa6cdc6285f [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaar79ee3152007-04-26 16:20:50 +00007 * Port to MPW by Bernhard Pruemmer
Bram Moolenaar071d4272004-06-13 20:20:40 +00008 * 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
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000017 * - 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 Moolenaarbbe8c3f2007-04-26 16:40:56 +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
Bram Moolenaar84a05ac2013-05-06 04:24:17 +020044/* Compile as CodeWarrior External Editor */
Bram Moolenaar071d4272004-06-13 20:20:40 +000045#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!'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000051#ifdef FEAT_MBYTE
52# define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
53#else
54# define SCRAPTEXTFLAVOR kScrapFlavorTypeText
55#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000056
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static EventHandlerUPP mouseWheelHandlerUPP = NULL;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000058SInt32 gMacSystemVersion;
Bram Moolenaar071d4272004-06-13 20:20:40 +000059
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000060#ifdef MACOS_CONVERT
61# define USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +000062
63static int im_is_active = FALSE;
64#if 0
Bram Moolenaared39e1d2008-08-09 17:55:22 +000065 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +000066static int im_start_row = 0;
67static int im_start_col = 0;
68#endif
69
70#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
71
72static TSMDocumentID gTSMDocument;
73
74static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000075static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000076static EventHandlerUPP winEventHandlerUPP = NULL;
77
78static pascal OSStatus gui_mac_handle_window_activate(
79 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
80
81static pascal OSStatus gui_mac_handle_text_input(
82 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
83
84static pascal OSStatus gui_mac_update_input_area(
85 EventHandlerCallRef nextHandler, EventRef theEvent);
86
87static pascal OSStatus gui_mac_unicode_key_event(
88 EventHandlerCallRef nextHandler, EventRef theEvent);
89
Bram Moolenaar26a60b42005-02-22 08:49:11 +000090#endif
91
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
93/* Include some file. TODO: move into os_mac.h */
94#include <Menus.h>
95#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000096#include <Processes.h>
97#ifdef USE_AEVENT
98# include <AppleEvents.h>
99# include <AERegistry.h>
100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
103# include <ControlDefinitions.h>
104# include <Navigation.h> /* Navigation only part of ?? */
105#endif
106
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000107/* Help Manager (balloon.h, HM prefixed functions) are not supported
108 * under Carbon (Jussi) */
109# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000111# include <MacHelp.h>
112# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113
114/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000115 * These seem to be rectangle options. Why are they not found in
116 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118#define kNothing 0
119#define kCreateEmpty 2 /*1*/
120#define kCreateRect 2
121#define kDestroy 3
122
123/*
124 * Dany: Don't like those...
125 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126#define topLeft(r) (((Point*)&(r))[0])
127#define botRight(r) (((Point*)&(r))[1])
128
129
130/* Time of last mouse click, to detect double-click */
131static long lastMouseTick = 0;
132
133/* ??? */
134static RgnHandle cursorRgn;
135static RgnHandle dragRgn;
136static Rect dragRect;
137static short dragRectEnbl;
138static short dragRectControl;
139
140/* This variable is set when waiting for an event, which is the only moment
141 * scrollbar dragging can be done directly. It's not allowed while commands
142 * are executed, because it may move the cursor and that may cause unexpected
143 * problems (e.g., while ":s" is working).
144 */
145static int allow_scrollbar = FALSE;
146
147/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149
150/* Feedback Action for Scrollbar */
151ControlActionUPP gScrollAction;
152ControlActionUPP gScrollDrag;
153
154/* Keeping track of which scrollbar is being dragged */
155static ControlHandle dragged_sb = NULL;
156
Bram Moolenaarc52da9d2008-03-20 13:39:37 +0000157/* Vector of char_u --> control index for hotkeys in dialogs */
158static short *gDialogHotKeys;
159
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000160static struct
161{
162 FMFontFamily family;
163 FMFontSize size;
164 FMFontStyle style;
165 Boolean isPanelVisible;
166} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000167
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000168#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000169# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000170int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000171ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000172# ifdef FEAT_MBYTE
173ATSUStyle gWideFontStyle;
174# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000175Boolean gIsFontFallbackSet;
Bram Moolenaar76b96fc2010-07-17 16:44:59 +0200176UInt32 useAntialias_cached = 0x0;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000177#endif
178
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179/* Colors Macros */
180#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
181#define Red(c) ((c & 0x00FF0000) >> 16)
182#define Green(c) ((c & 0x0000FF00) >> 8)
183#define Blue(c) ((c & 0x000000FF) >> 0)
184
185/* Key mapping */
186
187#define vk_Esc 0x35 /* -> 1B */
188
189#define vk_F1 0x7A /* -> 10 */
190#define vk_F2 0x78 /*0x63*/
191#define vk_F3 0x63 /*0x76*/
192#define vk_F4 0x76 /*0x60*/
193#define vk_F5 0x60 /*0x61*/
194#define vk_F6 0x61 /*0x62*/
195#define vk_F7 0x62 /*0x63*/ /*?*/
196#define vk_F8 0x64
197#define vk_F9 0x65
198#define vk_F10 0x6D
199#define vk_F11 0x67
200#define vk_F12 0x6F
201#define vk_F13 0x69
202#define vk_F14 0x6B
203#define vk_F15 0x71
204
205#define vk_Clr 0x47 /* -> 1B (ESC) */
206#define vk_Enter 0x4C /* -> 03 */
207
208#define vk_Space 0x31 /* -> 20 */
209#define vk_Tab 0x30 /* -> 09 */
210#define vk_Return 0x24 /* -> 0D */
211/* This is wrong for OSX, what is it for? */
212#define vk_Delete 0X08 /* -> 08 BackSpace */
213
214#define vk_Help 0x72 /* -> 05 */
215#define vk_Home 0x73 /* -> 01 */
216#define vk_PageUp 0x74 /* -> 0D */
217#define vk_FwdDelete 0x75 /* -> 7F */
218#define vk_End 0x77 /* -> 04 */
219#define vk_PageDown 0x79 /* -> 0C */
220
221#define vk_Up 0x7E /* -> 1E */
222#define vk_Down 0x7D /* -> 1F */
223#define vk_Left 0x7B /* -> 1C */
224#define vk_Right 0x7C /* -> 1D */
225
226#define vk_Undo vk_F1
227#define vk_Cut vk_F2
228#define vk_Copy vk_F3
229#define vk_Paste vk_F4
230#define vk_PrintScreen vk_F13
231#define vk_SCrollLock vk_F14
232#define vk_Pause vk_F15
233#define vk_NumLock vk_Clr
234#define vk_Insert vk_Help
235
236#define KeySym char
237
238static struct
239{
240 KeySym key_sym;
241 char_u vim_code0;
242 char_u vim_code1;
243} special_keys[] =
244{
245 {vk_Up, 'k', 'u'},
246 {vk_Down, 'k', 'd'},
247 {vk_Left, 'k', 'l'},
248 {vk_Right, 'k', 'r'},
249
250 {vk_F1, 'k', '1'},
251 {vk_F2, 'k', '2'},
252 {vk_F3, 'k', '3'},
253 {vk_F4, 'k', '4'},
254 {vk_F5, 'k', '5'},
255 {vk_F6, 'k', '6'},
256 {vk_F7, 'k', '7'},
257 {vk_F8, 'k', '8'},
258 {vk_F9, 'k', '9'},
259 {vk_F10, 'k', ';'},
260
261 {vk_F11, 'F', '1'},
262 {vk_F12, 'F', '2'},
263 {vk_F13, 'F', '3'},
264 {vk_F14, 'F', '4'},
265 {vk_F15, 'F', '5'},
266
267/* {XK_Help, '%', '1'}, */
268/* {XK_Undo, '&', '8'}, */
269/* {XK_BackSpace, 'k', 'b'}, */
Bram Moolenaard0573012017-10-28 21:11:06 +0200270/* {vk_Delete, 'k', 'b'}, */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271 {vk_Insert, 'k', 'I'},
272 {vk_FwdDelete, 'k', 'D'},
273 {vk_Home, 'k', 'h'},
274 {vk_End, '@', '7'},
275/* {XK_Prior, 'k', 'P'}, */
276/* {XK_Next, 'k', 'N'}, */
277/* {XK_Print, '%', '9'}, */
278
279 {vk_PageUp, 'k', 'P'},
280 {vk_PageDown, 'k', 'N'},
281
282 /* End of list marker: */
283 {(KeySym)0, 0, 0}
284};
285
286/*
287 * ------------------------------------------------------------
288 * Forward declaration (for those needed)
289 * ------------------------------------------------------------
290 */
291
292#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000293OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294#endif
295
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000296#ifdef FEAT_GUI_TABLINE
297static void initialise_tabline(void);
298static WindowRef drawer = NULL; // TODO: put into gui.h
299#endif
300
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000301#ifdef USE_ATSUI_DRAWING
302static void gui_mac_set_font_attributes(GuiFont font);
303static void gui_mac_dispose_atsui_style(void);
304#endif
305
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306/*
307 * ------------------------------------------------------------
308 * Conversion Utility
309 * ------------------------------------------------------------
310 */
311
312/*
313 * C2Pascal_save
314 *
315 * Allocate memory and convert the C-String passed in
316 * into a pascal string
317 *
318 */
319
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000320 char_u *
321C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322{
323 char_u *PascalString;
324 int len;
325
326 if (Cstring == NULL)
327 return NULL;
328
329 len = STRLEN(Cstring);
330
331 if (len > 255) /* Truncate if necessary */
332 len = 255;
333
334 PascalString = alloc(len + 1);
335 if (PascalString != NULL)
336 {
337 mch_memmove(PascalString + 1, Cstring, len);
338 PascalString[0] = len;
339 }
340
341 return PascalString;
342}
343
344/*
345 * C2Pascal_save_and_remove_backslash
346 *
347 * Allocate memory and convert the C-String passed in
348 * into a pascal string. Also remove the backslash at the same time
349 *
350 */
351
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000352 char_u *
353C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354{
355 char_u *PascalString;
356 int len;
357 char_u *p, *c;
358
359 len = STRLEN(Cstring);
360
361 if (len > 255) /* Truncate if necessary */
362 len = 255;
363
364 PascalString = alloc(len + 1);
365 if (PascalString != NULL)
366 {
367 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
368 {
369 if ((*c == '\\') && (c[1] != 0))
370 {
371 c++;
372 }
373 *p = *c;
374 p++;
375 len++;
376 }
377 PascalString[0] = len;
378 }
379
380 return PascalString;
381}
382
383/*
384 * Convert the modifiers of an Event into vim's modifiers (mouse)
385 */
386
387 int_u
388EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
389{
390 int_u vimModifiers = 0x00;
391
392 if (macModifiers & (shiftKey | rightShiftKey))
393 vimModifiers |= MOUSE_SHIFT;
394 if (macModifiers & (controlKey | rightControlKey))
395 vimModifiers |= MOUSE_CTRL;
396 if (macModifiers & (optionKey | rightOptionKey))
397 vimModifiers |= MOUSE_ALT;
398#if 0
399 /* Not yet supported */
400 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
401 vimModifiers |= MOUSE_CMD;
402#endif
403 return (vimModifiers);
404}
405
406/*
407 * Convert the modifiers of an Event into vim's modifiers (keys)
408 */
409
410 static int_u
411EventModifiers2VimModifiers(EventModifiers macModifiers)
412{
413 int_u vimModifiers = 0x00;
414
415 if (macModifiers & (shiftKey | rightShiftKey))
416 vimModifiers |= MOD_MASK_SHIFT;
417 if (macModifiers & (controlKey | rightControlKey))
418 vimModifiers |= MOD_MASK_CTRL;
419 if (macModifiers & (optionKey | rightOptionKey))
420 vimModifiers |= MOD_MASK_ALT;
421#ifdef USE_CMD_KEY
422 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
423 vimModifiers |= MOD_MASK_CMD;
424#endif
425 return (vimModifiers);
426}
427
428/* Convert a string representing a point size into pixels. The string should
429 * be a positive decimal number, with an optional decimal point (eg, "12", or
430 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
431 * character is stored in *end. The flag "vertical" says whether this
432 * calculation is for a vertical (height) size or a horizontal (width) one.
433 *
434 * From gui_w48.c
435 */
436 static int
437points_to_pixels(char_u *str, char_u **end, int vertical)
438{
439 int pixels;
440 int points = 0;
441 int divisor = 0;
442
443 while (*str)
444 {
445 if (*str == '.' && divisor == 0)
446 {
447 /* Start keeping a divisor, for later */
448 divisor = 1;
449 continue;
450 }
451
452 if (!isdigit(*str))
453 break;
454
455 points *= 10;
456 points += *str - '0';
457 divisor *= 10;
458
459 ++str;
460 }
461
462 if (divisor == 0)
463 divisor = 1;
464
465 pixels = points/divisor;
466 *end = str;
467 return pixels;
468}
469
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000470#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000471/*
472 * Deletes all traces of any Windows-style mnemonic text (including any
473 * parentheses) from a menu item and returns the cleaned menu item title.
474 * The caller is responsible for releasing the returned string.
475 */
476 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000477menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000478{
479 CFStringRef name;
480 size_t menuTitleLen;
481 CFIndex displayLen;
482 CFRange mnemonicStart;
483 CFRange mnemonicEnd;
484 CFMutableStringRef cleanedName;
485
486 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000487 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000488
489 if (name)
490 {
491 /* Simple mnemonic-removal algorithm, assumes single parenthesized
492 * mnemonic character towards the end of the menu text */
493 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
494 displayLen = CFStringGetLength(name);
495
496 if (mnemonicStart.location != kCFNotFound
497 && (mnemonicStart.location + 2) < displayLen
498 && CFStringGetCharacterAtIndex(name,
499 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
500 {
501 if (CFStringFindWithOptions(name, CFSTR(")"),
502 CFRangeMake(mnemonicStart.location + 1,
503 displayLen - mnemonicStart.location - 1),
504 kCFCompareBackwards, &mnemonicEnd) &&
505 (mnemonicStart.location + 2) == mnemonicEnd.location)
506 {
507 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
508 if (cleanedName)
509 {
510 CFStringDelete(cleanedName,
511 CFRangeMake(mnemonicStart.location,
512 mnemonicEnd.location + 1 -
513 mnemonicStart.location));
514
515 CFRelease(name);
516 name = cleanedName;
517 }
518 }
519 }
520 }
521
522 return name;
523}
524#endif
525
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526/*
527 * Convert a list of FSSpec aliases into a list of fullpathname
528 * character strings.
529 */
530
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000531 char_u **
532new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533{
534 char_u **fnames = NULL;
535 OSErr newError;
536 long fileCount;
537 FSSpec fileToOpen;
538 long actualSize;
539 AEKeyword dummyKeyword;
540 DescType dummyType;
541
542 /* Get number of files in list */
543 *error = AECountItems(theList, numFiles);
544 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000545 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
547 /* Allocate the pointer list */
548 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
549
550 /* Empty out the list */
551 for (fileCount = 0; fileCount < *numFiles; fileCount++)
552 fnames[fileCount] = NULL;
553
554 /* Scan the list of FSSpec */
555 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
556 {
557 /* Get the alias for the nth file, convert to an FSSpec */
558 newError = AEGetNthPtr(theList, fileCount, typeFSS,
559 &dummyKeyword, &dummyType,
560 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
561 if (newError)
562 {
563 /* Caller is able to clean up */
564 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000565 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567
568 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000569 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 }
571
572 return (fnames);
573}
574
575/*
576 * ------------------------------------------------------------
577 * CodeWarrior External Editor Support
578 * ------------------------------------------------------------
579 */
580#ifdef FEAT_CW_EDITOR
581
582/*
583 * Handle the Window Search event from CodeWarrior
584 *
585 * Description
586 * -----------
587 *
588 * The IDE sends the Window Search AppleEvent to the editor when it
589 * needs to know whether a particular file is open in the editor.
590 *
591 * Event Reply
592 * -----------
593 *
594 * None. Put data in the location specified in the structure received.
595 *
596 * Remarks
597 * -------
598 *
599 * When the editor receives this event, determine whether the specified
600 * file is open. If it is, return the modification date/time for that file
601 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000602 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 *
604 */
605
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606typedef struct WindowSearch WindowSearch;
607struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
608{
609 FSSpec theFile; // identifies the file
610 long *theDate; // where to put the modification date/time
611};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000613 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000614Handle_KAHL_SRCH_AE(
615 const AppleEvent *theAEvent,
616 AppleEvent *theReply,
617 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618{
619 OSErr error = noErr;
620 buf_T *buf;
621 int foundFile = false;
622 DescType typeCode;
623 WindowSearch SearchData;
624 Size actualSize;
625
626 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
627 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000628 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000630 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000632 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633
Bram Moolenaar29323592016-07-24 22:04:11 +0200634 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 if (buf->b_ml.ml_mfp != NULL
636 && SearchData.theFile.parID == buf->b_FSSpec.parID
637 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
638 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
639 {
640 foundFile = true;
641 break;
642 }
643
644 if (foundFile == false)
645 *SearchData.theDate = fnfErr;
646 else
647 *SearchData.theDate = buf->b_mtime;
648
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 return error;
650};
651
652/*
653 * Handle the Modified (from IDE to Editor) event from CodeWarrior
654 *
655 * Description
656 * -----------
657 *
658 * The IDE sends this event to the external editor when it wants to
659 * know which files that are open in the editor have been modified.
660 *
661 * Parameters None.
662 * ----------
663 *
664 * Event Reply
665 * -----------
666 * The reply for this event is:
667 *
668 * keyDirectObject typeAEList required
669 * each element in the list is a structure of typeChar
670 *
671 * Remarks
672 * -------
673 *
674 * When building the reply event, include one element in the list for
675 * each open file that has been modified.
676 *
677 */
678
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679typedef struct ModificationInfo ModificationInfo;
680struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
681{
682 FSSpec theFile; // identifies the file
683 long theDate; // the date/time the file was last modified
684 short saved; // set this to zero when replying, unused
685};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000687 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000688Handle_KAHL_MOD_AE(
689 const AppleEvent *theAEvent,
690 AppleEvent *theReply,
691 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692{
693 OSErr error = noErr;
694 AEDescList replyList;
695 long numFiles;
696 ModificationInfo theFile;
697 buf_T *buf;
698
699 theFile.saved = 0;
700
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000701 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000703 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
705 /* Send the reply */
706/* replyObject.descriptorType = typeNull;
707 replyObject.dataHandle = nil;*/
708
709/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
710 error = AECreateList(nil, 0, false, &replyList);
711 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000712 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713
714#if 0
715 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000717 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
718 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 * sizeof(DescType))
720 */
721
722 /* AEPutDesc */
723#endif
724
725 numFiles = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +0200726 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 if (buf->b_ml.ml_mfp != NULL)
728 {
729 /* Add this file to the list */
730 theFile.theFile = buf->b_FSSpec;
731 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000732/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
733 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 };
735
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736#if 0
737 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#endif
739
740 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000741 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 if (replyList.dataHandle)
744 AEDisposeDesc(&replyList);
745
746 return error;
747};
748
749/*
750 * Handle the Get Text event from CodeWarrior
751 *
752 * Description
753 * -----------
754 *
755 * The IDE sends the Get Text AppleEvent to the editor when it needs
756 * the source code from a file. For example, when the user issues a
757 * Check Syntax or Compile command, the compiler needs access to
758 * the source code contained in the file.
759 *
760 * Event Reply
761 * -----------
762 *
763 * None. Put data in locations specified in the structure received.
764 *
765 * Remarks
766 * -------
767 *
768 * When the editor receives this event, it must set the size of the handle
769 * in theText to fit the data in the file. It must then copy the entire
770 * contents of the specified file into the memory location specified in
771 * theText.
772 *
773 */
774
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775typedef struct CW_GetText CW_GetText;
776struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
777{
778 FSSpec theFile; /* identifies the file */
779 Handle theText; /* the location where you return the text (must be resized properly) */
780 long *unused; /* 0 (not used) */
781 long *theDate; /* where to put the modification date/time */
782};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000784 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000785Handle_KAHL_GTTX_AE(
786 const AppleEvent *theAEvent,
787 AppleEvent *theReply,
788 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789{
790 OSErr error = noErr;
791 buf_T *buf;
792 int foundFile = false;
793 DescType typeCode;
794 CW_GetText GetTextData;
795 Size actualSize;
796 char_u *line;
797 char_u *fullbuffer = NULL;
798 long linesize;
799 long lineStart;
800 long BufferSize;
801 long lineno;
802
803 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
804
805 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000806 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807
Bram Moolenaar29323592016-07-24 22:04:11 +0200808 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 if (buf->b_ml.ml_mfp != NULL)
810 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
811 {
812 foundFile = true;
813 break;
814 }
815
816 if (foundFile)
817 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
820 {
821 /* Must use the right buffer */
822 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
823 linesize = STRLEN(line) + 1;
824 lineStart = BufferSize;
825 BufferSize += linesize;
826 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000827 SetHandleSize(GetTextData.theText, BufferSize);
828 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 break; /* Simple handling for now */
831 }
832 else
833 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000834 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 }
840 }
841 if (fullbuffer != NULL)
842 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000843 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 }
847 if (foundFile == false)
848 *GetTextData.theDate = fnfErr;
849 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000850/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 *GetTextData.theDate = buf->b_mtime;
852 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000854 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000856 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857}
858
859/*
860 *
861 */
862
863/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000864 pascal OSErr
865FindProcessBySignature(
866 const OSType targetType,
867 const OSType targetCreator,
868 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869{
870 OSErr anErr = noErr;
871 Boolean lookingForProcess = true;
872
873 ProcessInfoRec infoRec;
874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 infoRec.processName = nil;
877 infoRec.processAppSpec = nil;
878
879 psnPtr->lowLongOfPSN = kNoProcess;
880 psnPtr->highLongOfPSN = kNoProcess;
881
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000882 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 anErr = GetNextProcess(psnPtr);
885 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 else
888 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000889 anErr = GetProcessInformation(psnPtr, &infoRec);
890 if ((anErr == noErr)
891 && (infoRec.processType == targetType)
892 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 }
895 }
896
897 return anErr;
898}//end FindProcessBySignature
899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000900 void
901Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000903 OSErr anErr = noErr;
904 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
906 AppleEvent theReply = { typeNull, nil };
907 AESendMode sendMode;
908 AppleEvent theEvent = {typeNull, nil };
909 AEIdleUPP idleProcUPP = nil;
910 ModificationInfo ModData;
911
912
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000914 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
917 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000919 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 {
921 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
922 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
923 }
924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000925 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926
927 /* Add the parms */
928 ModData.theFile = buf->b_FSSpec;
929 ModData.theDate = buf->b_mtime;
930
931 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000932 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 sendMode = kAENoReply;
936 else
937 sendMode = kAEWaitReply;
938
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000939 if (anErr == noErr)
940 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
941 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000943/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000945 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 }
947}
948#endif /* FEAT_CW_EDITOR */
949
950/*
951 * ------------------------------------------------------------
952 * Apple Event Handling procedure
953 * ------------------------------------------------------------
954 */
955#ifdef USE_AEVENT
956
957/*
958 * Handle the Unused parms of an AppleEvent
959 */
960
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000961 OSErr
962HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963{
964 OSErr error;
965 long actualSize;
966 DescType dummyType;
967 AEKeyword missedKeyword;
968
969 /* Get the "missed keyword" attribute from the AppleEvent. */
970 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
971 typeKeyword, &dummyType,
972 (Ptr)&missedKeyword, sizeof(missedKeyword),
973 &actualSize);
974
975 /* If the descriptor isn't found, then we got the required parameters. */
976 if (error == errAEDescNotFound)
977 {
978 error = noErr;
979 }
980 else
981 {
982#if 0
983 /* Why is this removed? */
984 error = errAEEventNotHandled;
985#endif
986 }
987
988 return error;
989}
990
991
992/*
993 * Handle the ODoc AppleEvent
994 *
995 * Deals with all files dragged to the application icon.
996 *
997 */
998
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999typedef struct SelectionRange SelectionRange;
1000struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1001{
1002 short unused1; // 0 (not used)
1003 short lineNum; // line to select (<0 to specify range)
1004 long startRange; // start of selection range (if line < 0)
1005 long endRange; // end of selection range (if line < 0)
1006 long unused2; // 0 (not used)
1007 long theDate; // modification date/time
1008};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009
1010/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1011 itor the selection range. If lineNum is zero or greater, scroll the text
1012 to the specified line. If lineNum is less than zero, use the values in
1013 startRange and endRange to select the specified characters. Scroll
1014 the text to display the selection. If lineNum, startRange, and
1015 endRange are all negative, there is no selection range specified.
1016 */
1017
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001018 pascal OSErr
1019HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020{
1021 /*
1022 * TODO: Clean up the code with convert the AppleEvent into
1023 * a ":args"
1024 */
1025 OSErr error = noErr;
1026// OSErr firstError = noErr;
1027// short numErrors = 0;
1028 AEDesc theList;
1029 DescType typeCode;
1030 long numFiles;
1031 // long fileCount;
1032 char_u **fnames;
1033// char_u fname[256];
1034 Size actualSize;
1035 SelectionRange thePosition;
1036 short gotPosition = false;
1037 long lnum;
1038
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 /* the direct object parameter is the list of aliases to files (one or more) */
1040 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1041 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001042 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043
1044
1045 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1046 if (error == noErr)
1047 gotPosition = true;
1048 if (error == errAEDescNotFound)
1049 error = noErr;
1050 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001051 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053/*
1054 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1055
1056 if (^error) then
1057 {
1058 if (thePosition.lineNum >= 0)
1059 {
1060 // Goto this line
1061 }
1062 else
1063 {
1064 // Set the range char wise
1065 }
1066 }
1067 */
1068
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1071
1072 if (error)
1073 {
1074 /* TODO: empty fnames[] first */
1075 vim_free(fnames);
1076 return (error);
1077 }
1078
1079 if (starting > 0)
1080 {
1081 int i;
1082 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001083 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084
1085 /* these are the initial files dropped on the Vim icon */
1086 for (i = 0 ; i < numFiles; i++)
1087 {
1088 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1089 || (p = vim_strsave(fnames[i])) == NULL)
1090 mch_exit(2);
1091 else
1092 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001093 if (fnum == -1)
1094 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1095 }
1096
1097 /* If the file name was already in the buffer list we need to switch
1098 * to it. */
1099 if (curbuf->b_fnum != fnum)
1100 {
1101 char_u cmd[30];
1102
1103 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1104 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001106
1107 /* Change directory to the location of the first file. */
1108 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1109 shorten_fnames(TRUE);
1110
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 goto finished;
1112 }
1113
1114 /* Handle the drop, :edit to get to the file */
1115 handle_drop(numFiles, fnames, FALSE);
1116
1117 /* TODO: Handle the goto/select line more cleanly */
1118 if ((numFiles == 1) & (gotPosition))
1119 {
1120 if (thePosition.lineNum >= 0)
1121 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001122 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123 /* oap->motion_type = MLINE;
1124 setpcmark();*/
1125 if (lnum < 1L)
1126 lnum = 1L;
1127 else if (lnum > curbuf->b_ml.ml_line_count)
1128 lnum = curbuf->b_ml.ml_line_count;
1129 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001130 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 /* beginline(BL_SOL | BL_FIX);*/
1132 }
1133 else
1134 goto_byte(thePosition.startRange + 1);
1135 }
1136
1137 /* Update the screen display */
1138 update_screen(NOT_VALID);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001139
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001140 /* Select the text if possible */
1141 if (gotPosition)
1142 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001143 VIsual_active = TRUE;
1144 VIsual_select = FALSE;
1145 VIsual = curwin->w_cursor;
1146 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001147 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001148 VIsual_mode = 'v';
1149 goto_byte(thePosition.endRange);
1150 }
1151 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001152 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001153 VIsual_mode = 'V';
1154 VIsual.col = 0;
1155 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001156 }
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001157
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 setcursor();
1159 out_flush();
1160
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001161 /* Fake mouse event to wake from stall */
1162 PostEvent(mouseUp, 0);
1163
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001164finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 AEDisposeDesc(&theList); /* dispose what we allocated */
1166
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001167 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001168 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169}
1170
1171/*
1172 *
1173 */
1174
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001175 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001176Handle_aevt_oapp_AE(
1177 const AppleEvent *theAEvent,
1178 AppleEvent *theReply,
1179 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180{
1181 OSErr error = noErr;
1182
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001183 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001184 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185}
1186
1187/*
1188 *
1189 */
1190
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001191 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001192Handle_aevt_quit_AE(
1193 const AppleEvent *theAEvent,
1194 AppleEvent *theReply,
1195 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196{
1197 OSErr error = noErr;
1198
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001199 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001201 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202
1203 /* Need to fake a :confirm qa */
1204 do_cmdline_cmd((char_u *)"confirm qa");
1205
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001206 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207}
1208
1209/*
1210 *
1211 */
1212
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001213 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001214Handle_aevt_pdoc_AE(
1215 const AppleEvent *theAEvent,
1216 AppleEvent *theReply,
1217 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218{
1219 OSErr error = noErr;
1220
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001221 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001223 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224}
1225
1226/*
1227 * Handling of unknown AppleEvent
1228 *
1229 * (Just get rid of all the parms)
1230 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001231 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001232Handle_unknown_AE(
1233 const AppleEvent *theAEvent,
1234 AppleEvent *theReply,
1235 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236{
1237 OSErr error = noErr;
1238
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001239 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001241 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242}
1243
1244
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245/*
1246 * Install the various AppleEvent Handlers
1247 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001248 OSErr
1249InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250{
1251 OSErr error;
1252
1253 /* install open application handler */
1254 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001255 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 if (error)
1257 {
1258 return error;
1259 }
1260
1261 /* install quit application handler */
1262 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001263 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264 if (error)
1265 {
1266 return error;
1267 }
1268
1269 /* install open document handler */
1270 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001271 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272 if (error)
1273 {
1274 return error;
1275 }
1276
1277 /* install print document handler */
1278 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001279 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280
1281/* Install Core Suite */
1282/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001283 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284
1285 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001286 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287
1288 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
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, kAECreateElement,
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, kAEDelete,
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, kAEDoObjectsExist,
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, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001301 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001304 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305
1306 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001307 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308
1309 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001310 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
1312 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001313 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314
1315 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001316 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317
1318 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001319 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001320*/
1321
1322#ifdef FEAT_CW_EDITOR
1323 /*
1324 * Bind codewarrior support handlers
1325 */
1326 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001327 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328 if (error)
1329 {
1330 return error;
1331 }
1332 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001333 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334 if (error)
1335 {
1336 return error;
1337 }
1338 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001339 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340 if (error)
1341 {
1342 return error;
1343 }
1344#endif
1345
1346 return error;
1347
1348}
1349#endif /* USE_AEVENT */
1350
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001351
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001352/*
1353 * Callback function, installed by InstallFontPanelHandler(), below,
1354 * to handle Font Panel events.
1355 */
1356 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001357FontPanelHandler(
1358 EventHandlerCallRef inHandlerCallRef,
1359 EventRef inEvent,
1360 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001361{
1362 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1363 {
1364 gFontPanelInfo.isPanelVisible = false;
1365 return noErr;
1366 }
1367
1368 if (GetEventKind(inEvent) == kEventFontSelection)
1369 {
1370 OSStatus status;
1371 FMFontFamily newFamily;
1372 FMFontSize newSize;
1373 FMFontStyle newStyle;
1374
1375 /* Retrieve the font family ID number. */
1376 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1377 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1378 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1379 &newFamily);
1380 if (status == noErr)
1381 gFontPanelInfo.family = newFamily;
1382
1383 /* Retrieve the font size. */
1384 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1385 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1386 if (status == noErr)
1387 gFontPanelInfo.size = newSize;
1388
1389 /* Retrieve the font style (bold, etc.). Currently unused. */
1390 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1391 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1392 if (status == noErr)
1393 gFontPanelInfo.style = newStyle;
1394 }
1395 return noErr;
1396}
1397
1398
1399 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001400InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001401{
1402 EventTypeSpec eventTypes[2];
1403 EventHandlerUPP handlerUPP;
1404 /* EventHandlerRef handlerRef; */
1405
1406 eventTypes[0].eventClass = kEventClassFont;
1407 eventTypes[0].eventKind = kEventFontSelection;
1408 eventTypes[1].eventClass = kEventClassFont;
1409 eventTypes[1].eventKind = kEventFontPanelClosed;
1410
1411 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1412
1413 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1414 /*userData=*/NULL, /*handlerRef=*/NULL);
1415}
1416
1417
1418/*
1419 * Fill the buffer pointed to by outName with the name and size
1420 * of the font currently selected in the Font Panel.
1421 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001422#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001423 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001424GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001425{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001426 Str255 buf;
1427 ByteCount fontNameLen = 0;
1428 ATSUFontID fid;
1429 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001430
1431 if (!outName)
1432 return;
1433
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001434 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1435 {
1436 /* Canonicalize localized font names */
1437 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1438 gFontPanelInfo.style, &fid, NULL) != noErr)
1439 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001440
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001441 /* Request font name with Mac encoding (otherwise we could
1442 * get an unwanted utf-16 name) */
1443 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1444 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001445 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001446 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001447
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001448 /* Only encode font size, because style (bold, italic, etc) is
1449 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001450 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001451 gFontPanelInfo.size/*,
1452 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1453 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1454 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1455
1456 if ((fontNameLen + STRLEN(styleString)) < 255)
1457 STRCPY(outName + fontNameLen, styleString);
1458 }
1459 else
1460 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001461 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001462 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001463}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001464
1465
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466/*
1467 * ------------------------------------------------------------
1468 * Unfiled yet
1469 * ------------------------------------------------------------
1470 */
1471
1472/*
1473 * gui_mac_get_menu_item_index
1474 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001475 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001477 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001478gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001479{
1480 short index;
1481 short itemIndex = -1;
1482 vimmenu_T *pBrother;
1483
1484 /* Only menu without parent are the:
1485 * -menu in the menubar
1486 * -popup menu
1487 * -toolbar (guess)
1488 *
1489 * Which are not items anyway.
1490 */
1491 if (pMenu->parent)
1492 {
1493 /* Start from the Oldest Brother */
1494 pBrother = pMenu->parent->children;
1495 index = 1;
1496 while ((pBrother) && (itemIndex == -1))
1497 {
1498 if (pBrother == pMenu)
1499 itemIndex = index;
1500 index++;
1501 pBrother = pBrother->next;
1502 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503 }
1504 return itemIndex;
1505}
1506
1507 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001508gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001509{
1510 short index;
1511 vimmenu_T *pChildMenu;
1512 vimmenu_T *pElder = pMenu->parent;
1513
1514
1515 /* Only menu without parent are the:
1516 * -menu in the menubar
1517 * -popup menu
1518 * -toolbar (guess)
1519 *
1520 * Which are not items anyway.
1521 */
1522
1523 if ((pElder) && (pElder->submenu_id == menuID))
1524 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1526 pMenu = pMenu->next;
1527 }
1528 else
1529 {
1530 for (; pMenu != NULL; pMenu = pMenu->next)
1531 {
1532 if (pMenu->children != NULL)
1533 {
1534 pChildMenu = gui_mac_get_vim_menu
1535 (menuID, itemIndex, pMenu->children);
1536 if (pChildMenu)
1537 {
1538 pMenu = pChildMenu;
1539 break;
1540 }
1541 }
1542 }
1543 }
1544 return pMenu;
1545}
1546
1547/*
1548 * ------------------------------------------------------------
1549 * MacOS Feedback procedures
1550 * ------------------------------------------------------------
1551 */
1552 pascal
1553 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001554gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001555{
1556 scrollbar_T *sb;
1557 int value, dragging;
1558 ControlHandle theControlToUse;
1559 int dont_scroll_save = dont_scroll;
1560
1561 theControlToUse = dragged_sb;
1562
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001563 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001564
1565 if (sb == NULL)
1566 return;
1567
1568 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001569 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570 dragging = (partCode != 0);
1571
1572 /* When "allow_scrollbar" is FALSE still need to remember the new
1573 * position, but don't actually scroll by setting "dont_scroll". */
1574 dont_scroll = !allow_scrollbar;
1575 gui_drag_scrollbar(sb, value, dragging);
1576 dont_scroll = dont_scroll_save;
1577}
1578
1579 pascal
1580 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001581gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582{
1583 /* TODO: have live support */
1584 scrollbar_T *sb, *sb_info;
1585 long data;
1586 long value;
1587 int page;
1588 int dragging = FALSE;
1589 int dont_scroll_save = dont_scroll;
1590
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001591 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592
1593 if (sb == NULL)
1594 return;
1595
1596 if (sb->wp != NULL) /* Left or right scrollbar */
1597 {
1598 /*
1599 * Careful: need to get scrollbar info out of first (left) scrollbar
1600 * for window, but keep real scrollbar too because we must pass it to
1601 * gui_drag_scrollbar().
1602 */
1603 sb_info = &sb->wp->w_scrollbars[0];
1604
1605 if (sb_info->size > 5)
1606 page = sb_info->size - 2; /* use two lines of context */
1607 else
1608 page = sb_info->size;
1609 }
1610 else /* Bottom scrollbar */
1611 {
1612 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001613 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614 }
1615
1616 switch (partCode)
1617 {
1618 case kControlUpButtonPart: data = -1; break;
1619 case kControlDownButtonPart: data = 1; break;
1620 case kControlPageDownPart: data = page; break;
1621 case kControlPageUpPart: data = -page; break;
1622 default: data = 0; break;
1623 }
1624
1625 value = sb_info->value + data;
1626/* if (value > sb_info->max)
1627 value = sb_info->max;
1628 else if (value < 0)
1629 value = 0;*/
1630
1631 /* When "allow_scrollbar" is FALSE still need to remember the new
1632 * position, but don't actually scroll by setting "dont_scroll". */
1633 dont_scroll = !allow_scrollbar;
1634 gui_drag_scrollbar(sb, value, dragging);
1635 dont_scroll = dont_scroll_save;
1636
1637 out_flush();
1638 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1639
1640/* if (sb_info->wp != NULL)
1641 {
1642 win_T *wp;
1643 int sb_num;
1644
1645 sb_num = 0;
1646 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1647 sb_num++;
1648
1649 if (wp != NULL)
1650 {
1651 current_scrollbar = sb_num;
1652 scrollbar_value = value;
1653 gui_do_scroll();
1654 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1655 }
1656 }*/
1657}
1658
1659/*
1660 * ------------------------------------------------------------
1661 * MacOS Click Handling procedures
1662 * ------------------------------------------------------------
1663 */
1664
1665
1666/*
1667 * Handle a click inside the window, it may happens in the
1668 * scrollbar or the contents.
1669 *
1670 * TODO: Add support for potential TOOLBAR
1671 */
1672 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001673gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674{
1675 Point thePoint;
1676 int_u vimModifiers;
1677 short thePortion;
1678 ControlHandle theControl;
1679 int vimMouseButton;
1680 short dblClick;
1681
1682 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001683 GlobalToLocal(&thePoint);
1684 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001686 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687
1688 if (theControl != NUL)
1689 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001690 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691
1692 if (thePortion != kControlIndicatorPart)
1693 {
1694 dragged_sb = theControl;
1695 TrackControl(theControl, thePoint, gScrollAction);
1696 dragged_sb = NULL;
1697 }
1698 else
1699 {
1700 dragged_sb = theControl;
1701#if 1
1702 TrackControl(theControl, thePoint, gScrollDrag);
1703#else
1704 TrackControl(theControl, thePoint, NULL);
1705#endif
1706 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1707 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001708 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709 dragged_sb = NULL;
1710 }
1711 }
1712 else
1713 {
1714 /* We are inside the contents */
1715
1716 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1717 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1718
1719 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1720 vimMouseButton = MOUSE_LEFT;
1721
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001723 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 clickIsPopup = FALSE;
1725
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001726 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1727 {
1728 vimMouseButton = MOUSE_RIGHT;
1729 vimModifiers &= ~MOUSE_CTRL;
1730 clickIsPopup = TRUE;
1731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732
1733 /* Is it a double click ? */
1734 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1735
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001736 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737 gui_send_mouse_event(vimMouseButton, thePoint.h,
1738 thePoint.v, dblClick, vimModifiers);
1739
1740 /* Create the rectangle around the cursor to detect
1741 * the mouse dragging
1742 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743#if 0
1744 /* TODO: Do we need to this even for the contextual menu?
1745 * It may be require for popup_setpos, but for popup?
1746 */
1747 if (vimMouseButton == MOUSE_LEFT)
1748#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001750 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751 FILL_Y(Y_2_ROW(thePoint.v)),
1752 FILL_X(X_2_COL(thePoint.h)+1),
1753 FILL_Y(Y_2_ROW(thePoint.v)+1));
1754
1755 dragRectEnbl = TRUE;
1756 dragRectControl = kCreateRect;
1757 }
1758 }
1759}
1760
1761/*
1762 * Handle the click in the titlebar (to move the window)
1763 */
1764 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001765gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766{
1767 Rect movingLimits;
1768 Rect *movingLimitsPtr = &movingLimits;
1769
1770 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001771 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001772 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773}
1774
1775/*
1776 * Handle the click in the grow box
1777 */
1778 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001779gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780{
1781
1782 long newSize;
1783 unsigned short newWidth;
1784 unsigned short newHeight;
1785 Rect resizeLimits;
1786 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787 Rect NewContentRect;
1788
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001789 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790
Bram Moolenaar720c7102007-05-10 18:07:50 +00001791 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 /* TODO: Should this come from Vim? */
1793 resizeLimits.top = 100;
1794 resizeLimits.left = 100;
1795
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1797 newWidth = NewContentRect.right - NewContentRect.left;
1798 newHeight = NewContentRect.bottom - NewContentRect.top;
1799 gui_resize_shell(newWidth, newHeight);
1800 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001801 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802}
1803
1804/*
1805 * Handle the click in the zoom box
1806 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001808gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809{
1810 Rect r;
1811 Point p;
1812 short thePart;
1813
1814 /* ideal width is current */
1815 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1816 if (gui.which_scrollbars[SBAR_LEFT])
1817 p.h += gui.scrollbar_width;
1818 if (gui.which_scrollbars[SBAR_RIGHT])
1819 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001820 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 p.v = 15 * 1024;
1822
1823 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1824 ? inZoomIn : inZoomOut;
1825
1826 if (!TrackBox(whichWindow, theEvent->where, thePart))
1827 return;
1828
1829 /* use returned width */
1830 p.h = r.right - r.left;
1831 /* adjust returned height */
1832 p.v = r.bottom - r.top - 2 * gui.border_offset;
1833 if (gui.which_scrollbars[SBAR_BOTTOM])
1834 p.v -= gui.scrollbar_height;
1835 p.v -= p.v % gui.char_height;
1836 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001837 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 p.v += gui.scrollbar_height;
1839
1840 ZoomWindowIdeal(whichWindow, thePart, &p);
1841
1842 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1843 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1844 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001845 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847
1848/*
1849 * ------------------------------------------------------------
1850 * MacOS Event Handling procedure
1851 * ------------------------------------------------------------
1852 */
1853
1854/*
1855 * Handle the Update Event
1856 */
1857
1858 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001859gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860{
1861 WindowPtr whichWindow;
1862 GrafPtr savePort;
1863 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 Rect *updateRectPtr;
1866 Rect rc;
1867 Rect growRect;
1868 RgnHandle saveRgn;
1869
1870
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 updateRgn = NewRgn();
1872 if (updateRgn == NULL)
1873 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874
1875 /* This could be done by the caller as we
1876 * don't require anything else out of the event
1877 */
1878 whichWindow = (WindowPtr) event->message;
1879
1880 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001881 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882
1883 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001884 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885
1886 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001887 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 /* Redraw the biggest rectangle covering the area
1889 * to be updated.
1890 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1892# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001893 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 * seem to work under MacOS X (Dany)
1895 */
1896 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1897# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001898
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001900 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001902 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903# if 0
1904 /* Code from original Carbon Port (using GetWindowRegion.
1905 * I believe the UpdateRgn is already in local (Dany)
1906 */
1907 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1908 GlobalToLocal(&botRight(updateRect));
1909# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 /* Update the content (i.e. the text) */
1911 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1912 updateRectPtr->right - updateRectPtr->left,
1913 updateRectPtr->bottom - updateRectPtr->top);
1914 /* Clear the border areas if needed */
1915 gui_mch_set_bg_color(gui.back_pixel);
1916 if (updateRectPtr->left < FILL_X(0))
1917 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001918 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1919 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 }
1921 if (updateRectPtr->top < FILL_Y(0))
1922 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001923 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1924 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 }
1926 if (updateRectPtr->right > FILL_X(Columns))
1927 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001928 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001930 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 }
1932 if (updateRectPtr->bottom > FILL_Y(Rows))
1933 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001934 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001936 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001938 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940
1941 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001942 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943
1944 /* Update the GrowBox */
1945 /* Taken from FAQ 33-27 */
1946 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001948 GetClip(saveRgn);
1949 ClipRect(&growRect);
1950 DrawGrowIcon(whichWindow);
1951 SetClip(saveRgn);
1952 DisposeRgn(saveRgn);
1953 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954
1955 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001956 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957}
1958
1959/*
1960 * Handle the activate/deactivate event
1961 * (apply to a window)
1962 */
1963 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001964gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965{
1966 WindowPtr whichWindow;
1967
1968 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001969 /* Dim scrollbars */
1970 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001972 ControlRef rootControl;
1973 GetRootControl(gui.VimWindow, &rootControl);
1974 if ((event->modifiers) & activeFlag)
1975 ActivateControl(rootControl);
1976 else
1977 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001979
1980 /* Activate */
1981 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982}
1983
1984
1985/*
1986 * Handle the suspend/resume event
1987 * (apply to the application)
1988 */
1989 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001990gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991{
1992 /* The frontmost application just changed */
1993
1994 /* NOTE: the suspend may happen before the deactivate
1995 * seen on MacOS X
1996 */
1997
1998 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00001999 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 */
2001 if (event->message & 1)
2002 /* Resume */
2003 gui_focus_change(TRUE);
2004 else
2005 /* Suspend */
2006 gui_focus_change(FALSE);
2007}
2008
2009/*
2010 * Handle the key
2011 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002012#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002013 static pascal OSStatus
2014gui_mac_handle_window_activate(
2015 EventHandlerCallRef nextHandler,
2016 EventRef theEvent,
2017 void *data)
2018{
2019 UInt32 eventClass = GetEventClass(theEvent);
2020 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002021
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002022 if (eventClass == kEventClassWindow)
2023 {
2024 switch (eventKind)
2025 {
2026 case kEventWindowActivated:
2027#if defined(USE_IM_CONTROL)
2028 im_on_window_switch(TRUE);
2029#endif
2030 return noErr;
2031
2032 case kEventWindowDeactivated:
2033#if defined(USE_IM_CONTROL)
2034 im_on_window_switch(FALSE);
2035#endif
2036 return noErr;
2037 }
2038 }
2039
2040 return eventNotHandledErr;
2041}
2042
2043 static pascal OSStatus
2044gui_mac_handle_text_input(
2045 EventHandlerCallRef nextHandler,
2046 EventRef theEvent,
2047 void *data)
2048{
2049 UInt32 eventClass = GetEventClass(theEvent);
2050 UInt32 eventKind = GetEventKind(theEvent);
2051
2052 if (eventClass != kEventClassTextInput)
2053 return eventNotHandledErr;
2054
2055 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2056 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2057 (kEventTextInputOffsetToPos != eventKind) &&
2058 (kEventTextInputPosToOffset != eventKind) &&
2059 (kEventTextInputGetSelectedText != eventKind))
2060 return eventNotHandledErr;
2061
2062 switch (eventKind)
2063 {
2064 case kEventTextInputUpdateActiveInputArea:
2065 return gui_mac_update_input_area(nextHandler, theEvent);
2066 case kEventTextInputUnicodeForKeyEvent:
2067 return gui_mac_unicode_key_event(nextHandler, theEvent);
2068
2069 case kEventTextInputOffsetToPos:
2070 case kEventTextInputPosToOffset:
2071 case kEventTextInputGetSelectedText:
2072 break;
2073 }
2074
2075 return eventNotHandledErr;
2076}
2077
2078 static pascal
2079OSStatus gui_mac_update_input_area(
2080 EventHandlerCallRef nextHandler,
2081 EventRef theEvent)
2082{
2083 return eventNotHandledErr;
2084}
2085
2086static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2087 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002088
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002089# define INLINE_KEY_BUFFER_SIZE 80
2090 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002091gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002092 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002093 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002094{
2095 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002096 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002097 UInt32 actualSize;
2098 UniChar *text;
2099 char_u result[INLINE_KEY_BUFFER_SIZE];
2100 short len = 0;
2101 UInt32 key_sym;
2102 char charcode;
2103 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002104 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002105 size_t encLen;
2106 char_u *to = NULL;
2107 Boolean isSpecial = FALSE;
2108 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002109 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002111 /* Mask the mouse (as per user setting) */
2112 if (p_mh)
2113 ObscureCursor();
2114
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002115 /* Don't use the keys when the dialog wants them. */
2116 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002117 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002118
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002119 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002120 typeUnicodeText, NULL, 0, &actualSize, NULL))
2121 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002122
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002123 text = (UniChar *)alloc(actualSize);
2124 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002125 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002126
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002127 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002128 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002129 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002130
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002131 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002132 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002134
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002135 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002136 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002137 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002138
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002139 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002140 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002141 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002142
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002144 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 require_noerr(err, done);
2146
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002147#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002148 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002149 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002150#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002152 key_char = charcode;
2153 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002154
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002155 /* Find the special key (eg., for cursor keys) */
2156 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002157 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002158 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002159 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2160 if (special_keys[i].key_sym == key_sym)
2161 {
2162 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2163 special_keys[i].vim_code1);
2164 key_char = simplify_key(key_char,
2165 (int *)&vimModifiers);
2166 isSpecial = TRUE;
2167 break;
2168 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002169 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002170
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002171 /* Intercept CMD-. and CTRL-c */
2172 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002173 ((modifiers & cmdKey) && key_char == '.'))
2174 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002175
2176 if (!isSpecial)
2177 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002178 /* remove SHIFT for keys that are already shifted, e.g.,
2179 * '(' and '*' */
2180 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2181 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002182
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002183 /* remove CTRL from keys that already have it */
2184 if (key_char < 0x20)
2185 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002186
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002187 /* don't process unicode characters here */
2188 if (!IS_SPECIAL(key_char))
2189 {
2190 /* Following code to simplify and consolidate vimModifiers
2191 * taken liberally from gui_w48.c */
2192 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002193
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002194 /* Interpret META, include SHIFT, etc. */
2195 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2196 if (key_char == CSI)
2197 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002198
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002199 if (IS_SPECIAL(key_char))
2200 isSpecial = TRUE;
2201 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002202 }
2203
2204 if (vimModifiers)
2205 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002206 result[len++] = CSI;
2207 result[len++] = KS_MODIFIER;
2208 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002209 }
2210
2211 if (isSpecial && IS_SPECIAL(key_char))
2212 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002213 result[len++] = CSI;
2214 result[len++] = K_SECOND(key_char);
2215 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002216 }
2217 else
2218 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002219 encLen = actualSize;
2220 to = mac_utf16_to_enc(text, actualSize, &encLen);
2221 if (to)
2222 {
2223 /* This is basically add_to_input_buf_csi() */
2224 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2225 {
2226 result[len++] = to[i];
2227 if (to[i] == CSI)
2228 {
2229 result[len++] = KS_EXTRA;
2230 result[len++] = (int)KE_CSI;
2231 }
2232 }
2233 vim_free(to);
2234 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002235 }
2236
2237 add_to_input_buf(result, len);
2238 err = noErr;
2239
2240done:
2241 vim_free(text);
2242 if (err == noErr)
2243 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002244 /* Fake event to wake up WNE (required to get
2245 * key repeat working */
2246 PostEvent(keyUp, 0);
2247 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002248 }
2249
2250 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002251}
2252#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002253 void
2254gui_mac_doKeyEvent(EventRecord *theEvent)
2255{
2256 /* TODO: add support for COMMAND KEY */
2257 long menu;
2258 unsigned char string[20];
2259 short num, i;
2260 short len = 0;
2261 KeySym key_sym;
2262 int key_char;
2263 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002264 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265
2266 /* Mask the mouse (as per user setting) */
2267 if (p_mh)
2268 ObscureCursor();
2269
2270 /* Get the key code and it's ASCII representation */
2271 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2272 key_char = theEvent->message & charCodeMask;
2273 num = 1;
2274
2275 /* Intercept CTRL-C */
2276 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002277 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 if (key_char == Ctrl_C && ctrl_c_interrupts)
2279 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002280 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2281 && (key_char == '2' || key_char == '6'))
2282 {
2283 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2284 if (key_char == '2')
2285 key_char = Ctrl_AT;
2286 else
2287 key_char = Ctrl_HAT;
2288 theEvent->modifiers = 0;
2289 }
2290 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291
2292 /* Intercept CMD-. */
2293 if (theEvent->modifiers & cmdKey)
2294 if (key_char == '.')
2295 got_int = TRUE;
2296
2297 /* Handle command key as per menu */
2298 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2299 if (theEvent->modifiers & cmdKey)
2300 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2301 * Why the mouse button? */
2302 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2303 {
2304 menu = MenuKey(key_char);
2305 if (HiWord(menu))
2306 {
2307 gui_mac_handle_menu(menu);
2308 return;
2309 }
2310 }
2311
2312 /* Convert the modifiers */
2313 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2314
2315
2316 /* Handle special keys. */
2317#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002318 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2320#endif
2321 {
2322 /* Find the special key (for non-printable keyt_char) */
2323 if ((key_char < 0x20) || (key_char == 0x7f))
2324 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2325 if (special_keys[i].key_sym == key_sym)
2326 {
2327# if 0
2328 /* We currently don't have not so special key */
2329 if (special_keys[i].vim_code1 == NUL)
2330 key_char = special_keys[i].vim_code0;
2331 else
2332# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002333 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2334 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002335 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 break;
2337 }
2338 }
2339
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002340 /* For some keys the modifier is included in the char itself. */
2341 if (simplify || key_char == TAB || key_char == ' ')
2342 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343
2344 /* Add the modifier to the input bu if needed */
2345 /* Do not want SHIFT-A or CTRL-A with modifier */
2346 if (!IS_SPECIAL(key_char)
2347 && key_sym != vk_Space
2348 && key_sym != vk_Tab
2349 && key_sym != vk_Return
2350 && key_sym != vk_Enter
2351 && key_sym != vk_Esc)
2352 {
2353#if 1
2354 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002355 if ((modifiers == MOD_MASK_SHIFT)
2356 || (modifiers == MOD_MASK_CTRL)
2357 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 modifiers = 0;
2359#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002360 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002362 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002364 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 modifiers = modifiers & ~MOD_MASK_SHIFT;
2366#endif
2367 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002368 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002370 string[len++] = CSI;
2371 string[len++] = KS_MODIFIER;
2372 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 }
2374
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002375 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002377 string[len++] = CSI;
2378 string[len++] = K_SECOND(key_char);
2379 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 }
2381 else
2382 {
2383#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002384 /* Convert characters when needed (e.g., from MacRoman to latin1).
2385 * This doesn't work for the NUL byte. */
2386 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387 {
2388 char_u from[2], *to;
2389 int l;
2390
2391 from[0] = key_char;
2392 from[1] = NUL;
2393 l = 1;
2394 to = string_convert(&input_conv, from, &l);
2395 if (to != NULL)
2396 {
2397 for (i = 0; i < l && len < 19; i++)
2398 {
2399 if (to[i] == CSI)
2400 {
2401 string[len++] = KS_EXTRA;
2402 string[len++] = KE_CSI;
2403 }
2404 else
2405 string[len++] = to[i];
2406 }
2407 vim_free(to);
2408 }
2409 else
2410 string[len++] = key_char;
2411 }
2412 else
2413#endif
2414 string[len++] = key_char;
2415 }
2416
2417 if (len == 1 && string[0] == CSI)
2418 {
2419 /* Turn CSI into K_CSI. */
2420 string[ len++ ] = KS_EXTRA;
2421 string[ len++ ] = KE_CSI;
2422 }
2423
2424 add_to_input_buf(string, len);
2425}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002426#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427
2428/*
2429 * Handle MouseClick
2430 */
2431 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002432gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433{
2434 short thePart;
2435 WindowPtr whichWindow;
2436
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002437 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002439#ifdef FEAT_GUI_TABLINE
2440 /* prevent that the vim window size changes if it's activated by a
2441 click into the tab pane */
2442 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002443 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002444#endif
2445
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 switch (thePart)
2447 {
2448 case (inDesk):
2449 /* TODO: what to do? */
2450 break;
2451
2452 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002453 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 break;
2455
2456 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002457 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 break;
2459
2460 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002461 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 break;
2463
2464 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002465 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 break;
2467
2468 case (inGoAway):
2469 if (TrackGoAway(whichWindow, theEvent->where))
2470 gui_shell_closed();
2471 break;
2472
2473 case (inZoomIn):
2474 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 break;
2477 }
2478}
2479
2480/*
2481 * Handle MouseMoved
2482 * [this event is a moving in and out of a region]
2483 */
2484 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002485gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486{
2487 Point thePoint;
2488 int_u vimModifiers;
2489
2490 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002491 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2493
2494 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002495 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2499 thePoint.v, FALSE, vimModifiers);
2500
2501 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002502 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 FILL_Y(Y_2_ROW(thePoint.v)),
2504 FILL_X(X_2_COL(thePoint.h)+1),
2505 FILL_Y(Y_2_ROW(thePoint.v)+1));
2506
2507 if (dragRectEnbl)
2508 dragRectControl = kCreateRect;
2509
2510}
2511
2512/*
2513 * Handle the mouse release
2514 */
2515 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002516gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517{
2518 Point thePoint;
2519 int_u vimModifiers;
2520
2521 /* TODO: Properly convert the Contextual menu mouse-up */
2522 /* Potential source of the double menu */
2523 lastMouseTick = theEvent->when;
2524 dragRectEnbl = FALSE;
2525 dragRectControl = kCreateEmpty;
2526 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002527 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528
2529 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530 if (clickIsPopup)
2531 {
2532 vimModifiers &= ~MOUSE_CTRL;
2533 clickIsPopup = FALSE;
2534 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002535 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536}
2537
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 static pascal OSStatus
2539gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2540 void *data)
2541{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 Point point;
2543 Rect bounds;
2544 UInt32 mod;
2545 SInt32 delta;
2546 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002547 EventMouseWheelAxis axis;
2548
2549 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2550 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2551 && axis != kEventMouseWheelAxisY)
2552 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553
2554 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2555 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2556 goto bail;
2557 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2558 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2559 goto bail;
2560 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2561 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2562 goto bail;
2563
2564 vim_mod = 0;
2565 if (mod & shiftKey)
2566 vim_mod |= MOUSE_SHIFT;
2567 if (mod & controlKey)
2568 vim_mod |= MOUSE_CTRL;
2569 if (mod & optionKey)
2570 vim_mod |= MOUSE_ALT;
2571
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2573 {
2574 point.h -= bounds.left;
2575 point.v -= bounds.top;
2576 }
2577
2578 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2579 point.h, point.v, FALSE, vim_mod);
2580
Bram Moolenaarc236c162008-07-13 17:41:49 +00002581 /* post a bogus event to wake up WaitNextEvent */
2582 PostEvent(keyUp, 0);
2583
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 return noErr;
2585
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002586bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 /*
2588 * when we fail give any additional callback handler a chance to perform
2589 * it's actions
2590 */
2591 return CallNextEventHandler(nextHandler, theEvent);
2592}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593
Bram Moolenaare00289d2010-08-14 21:56:42 +02002594 void
2595gui_mch_mousehide(int hide)
2596{
2597 /* TODO */
2598}
2599
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600#if 0
2601
2602/*
2603 * This would be the normal way of invoking the contextual menu
2604 * but the Vim API doesn't seem to a support a request to get
2605 * the menu that we should display
2606 */
2607 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002608gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002609{
2610/*
2611 * Clone PopUp to use menu
2612 * Create a object descriptor for the current selection
2613 * Call the procedure
2614 */
2615
2616// Call to Handle Popup
2617 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2618
2619 if (status != noErr)
2620 return;
2621
2622 if (CntxType == kCMMenuItemSelected)
2623 {
2624 /* Handle the menu CntxMenuID, CntxMenuItem */
2625 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002626 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002627 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 }
2629 else if (CntxMenuID == kCMShowHelpSelected)
2630 {
2631 /* Should come up with the help */
2632 }
2633
2634}
2635#endif
2636
2637/*
2638 * Handle menubar selection
2639 */
2640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002641gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642{
2643 short menu = HiWord(menuChoice);
2644 short item = LoWord(menuChoice);
2645 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646
2647 if (menu == 256) /* TODO: use constant or gui.xyz */
2648 {
2649 if (item == 1)
2650 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 }
2652 else if (item != 0)
2653 {
2654 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2655
2656 if (theVimMenu)
2657 gui_menu_cb(theVimMenu);
2658 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002659 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660}
2661
2662/*
2663 * Dispatch the event to proper handler
2664 */
2665
2666 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002667gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668{
2669 OSErr error;
2670
2671 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002672 if (IsShowContextualMenuClick(event))
2673 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002675 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002677 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002679 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002680 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681
2682 /* Handle normal event */
2683 switch (event->what)
2684 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002685#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 case (keyDown):
2687 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002688 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002690#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002692 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 break;
2694
2695 case (mouseDown):
2696 gui_mac_doMouseDownEvent(event);
2697 break;
2698
2699 case (mouseUp):
2700 gui_mac_doMouseUpEvent(event);
2701 break;
2702
2703 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002704 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 break;
2706
2707 case (diskEvt):
2708 /* We don't need special handling for disk insertion */
2709 break;
2710
2711 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002712 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 break;
2714
2715 case (osEvt):
2716 switch ((event->message >> 24) & 0xFF)
2717 {
2718 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002719 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 break;
2721 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002722 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 break;
2724 }
2725 break;
2726
2727#ifdef USE_AEVENT
2728 case (kHighLevelEvent):
2729 /* Someone's talking to us, through AppleEvents */
2730 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2731 break;
2732#endif
2733 }
2734}
2735
2736/*
2737 * ------------------------------------------------------------
2738 * Unknown Stuff
2739 * ------------------------------------------------------------
2740 */
2741
2742
2743 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002744gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745{
2746 char_u c;
2747 char_u *p;
2748 char_u pFontName[256];
2749 Str255 systemFontname;
2750 short font_id;
2751 short size=9;
2752 GuiFont font;
2753#if 0
2754 char_u *fontNamePtr;
2755#endif
2756
2757 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2758 ;
2759
2760 c = *p;
2761 *p = 0;
2762
2763#if 1
2764 STRCPY(&pFontName[1], font_name);
2765 pFontName[0] = STRLEN(font_name);
2766 *p = c;
2767
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002768 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002769 char_u fontName[256];
2770 char_u *styleStart = vim_strchr(font_name, ':');
2771 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2772 vim_strncpy(fontName, font_name, fontNameLen);
2773
2774 ATSUFontID fontRef;
2775 FMFontStyle fontStyle;
2776 font_id = 0;
2777
2778 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2779 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2780 &fontRef) == noErr)
2781 {
2782 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2783 font_id = 0;
2784 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002785
2786 if (font_id == 0)
2787 {
2788 /*
2789 * Try again, this time replacing underscores in the font name
2790 * with spaces (:set guifont allows the two to be used
2791 * interchangeably; the Font Manager doesn't).
2792 */
2793 int i, changed = FALSE;
2794
2795 for (i = pFontName[0]; i > 0; --i)
2796 {
2797 if (pFontName[i] == '_')
2798 {
2799 pFontName[i] = ' ';
2800 changed = TRUE;
2801 }
2802 }
2803 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002804 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2805 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2806 kFontNoLanguageCode, &fontRef) == noErr)
2807 {
2808 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2809 font_id = 0;
2810 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002811 }
2812
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813#else
2814 /* name = C2Pascal_save(menu->dname); */
2815 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2816
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002817 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818#endif
2819
2820
2821 if (font_id == 0)
2822 {
2823 /* Oups, the system font was it the one the user want */
2824
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002825 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2826 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827 if (!EqualString(pFontName, systemFontname, false, false))
2828 return NOFONT;
2829 }
2830 if (*p == ':')
2831 {
2832 p++;
2833 /* Set the values found after ':' */
2834 while (*p)
2835 {
2836 switch (*p++)
2837 {
2838 case 'h':
2839 size = points_to_pixels(p, &p, TRUE);
2840 break;
2841 /*
2842 * TODO: Maybe accept width and styles
2843 */
2844 }
2845 while (*p == ':')
2846 p++;
2847 }
2848 }
2849
2850 if (size < 1)
2851 size = 1; /* Avoid having a size of 0 with system font */
2852
2853 font = (size << 16) + ((long) font_id & 0xFFFF);
2854
2855 return font;
2856}
2857
2858/*
2859 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002860 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 * ------------------------------------------------------------
2862 */
2863
2864/*
2865 * Parse the GUI related command-line arguments. Any arguments used are
2866 * deleted from argv, and *argc is decremented accordingly. This is called
2867 * when vim is started, whether or not the GUI has been started.
2868 */
2869 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002870gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871{
2872 /* TODO: Move most of this stuff toward gui_mch_init */
2873#ifdef USE_EXE_NAME
2874 FSSpec applDir;
2875# ifndef USE_FIND_BUNDLE_PATH
2876 short applVRefNum;
2877 long applDirID;
2878 Str255 volName;
2879# else
2880 ProcessSerialNumber psn;
2881 FSRef applFSRef;
2882# endif
2883#endif
2884
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885#if 0
2886 InitCursor();
2887
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889
2890#ifdef USE_AEVENT
2891 (void) InstallAEHandlers();
2892#endif
2893
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002894 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002896 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002898 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899
2900 DrawMenuBar();
2901
2902
2903#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002904 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002906 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907#endif
2908
2909
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 CreateNewWindow(kDocumentWindowClass,
2911 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002912 &windRect, &gui.VimWindow);
2913 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914
2915 gui.char_width = 7;
2916 gui.char_height = 11;
2917 gui.char_ascent = 6;
2918 gui.num_rows = 24;
2919 gui.num_cols = 80;
2920 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2921
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002922 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2923 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924
2925 dragRectEnbl = FALSE;
2926 dragRgn = NULL;
2927 dragRectControl = kCreateEmpty;
2928 cursorRgn = NewRgn();
2929#endif
2930#ifdef USE_EXE_NAME
2931# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002932 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002934 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935# else
2936 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2937 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002939 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 /* if (err != noErr) return err; */
2941
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002942 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 /* if (err != noErr) return err; */
2944
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002945 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
2947 /* This technic return NIL when we disallow_gui */
2948# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002949 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951}
2952
2953#ifndef ALWAYS_USE_GUI
2954/*
2955 * Check if the GUI can be started. Called before gvimrc is sourced.
2956 * Return OK or FAIL.
2957 */
2958 int
2959gui_mch_init_check(void)
2960{
2961 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2962 * using the >console
2963 */
2964 if (disallow_gui) /* see main.c for reason to disallow */
2965 return FAIL;
2966 return OK;
2967}
2968#endif
2969
2970 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002971receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972{
2973 int x, y;
2974 int_u modifiers;
2975 char_u **fnames = NULL;
2976 int count;
2977 int i, j;
2978
2979 /* Get drop position, modifiers and count of items */
2980 {
2981 Point point;
2982 SInt16 mouseUpModifiers;
2983 UInt16 countItem;
2984
2985 GetDragMouse(theDrag, &point, NULL);
2986 GlobalToLocal(&point);
2987 x = point.h;
2988 y = point.v;
2989 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2990 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2991 CountDragItems(theDrag, &countItem);
2992 count = countItem;
2993 }
2994
2995 fnames = (char_u **)alloc(count * sizeof(char_u *));
2996 if (fnames == NULL)
2997 return dragNotAcceptedErr;
2998
2999 /* Get file names dropped */
3000 for (i = j = 0; i < count; ++i)
3001 {
3002 DragItemRef item;
3003 OSErr err;
3004 Size size;
3005 FlavorType type = flavorTypeHFS;
3006 HFSFlavor hfsFlavor;
3007
3008 fnames[i] = NULL;
3009 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3010 err = GetFlavorDataSize(theDrag, item, type, &size);
3011 if (err != noErr || size > sizeof(hfsFlavor))
3012 continue;
3013 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3014 if (err != noErr)
3015 continue;
3016 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3017 }
3018 count = j;
3019
3020 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003021
3022 /* Fake mouse event to wake from stall */
3023 PostEvent(mouseUp, 0);
3024
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 return noErr;
3026}
3027
3028/*
3029 * Initialise the GUI. Create all the windows, set up all the call-backs
3030 * etc.
3031 */
3032 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003033gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034{
3035 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003036 Rect windRect;
3037 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003039 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003040 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003041
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003042 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003043 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003044
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045#if 1
3046 InitCursor();
3047
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049
3050#ifdef USE_AEVENT
3051 (void) InstallAEHandlers();
3052#endif
3053
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003054 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003056 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003058 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
3060 DrawMenuBar();
3061
3062
3063#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003064 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003066 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067#endif
3068
3069 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003072 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3074 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003075 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076
3077 gui.char_width = 7;
3078 gui.char_height = 11;
3079 gui.char_ascent = 6;
3080 gui.num_rows = 24;
3081 gui.num_cols = 80;
3082 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3083
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003084 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3085 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003087 /* Install Carbon event callbacks. */
3088 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089
3090 dragRectEnbl = FALSE;
3091 dragRgn = NULL;
3092 dragRectControl = kCreateEmpty;
3093 cursorRgn = NewRgn();
3094#endif
3095 /* Display any pending error messages */
3096 display_errors();
3097
3098 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003099 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 gui.norm_pixel = 0x00000000;
3101 gui.back_pixel = 0x00FFFFFF;
3102
3103 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3104 * file). */
3105 set_normal_colors();
3106
3107 /*
3108 * Check that none of the colors are the same as the background color.
3109 * Then store the current values as the defaults.
3110 */
3111 gui_check_colors();
3112 gui.def_norm_pixel = gui.norm_pixel;
3113 gui.def_back_pixel = gui.back_pixel;
3114
3115 /* Get the colors for the highlight groups (gui_check_colors() might have
3116 * changed them) */
3117 highlight_gui_started();
3118
3119 /*
3120 * Setting the gui constants
3121 */
3122#ifdef FEAT_MENU
3123 gui.menu_height = 0;
3124#endif
3125 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3126 gui.border_offset = gui.border_width = 2;
3127
Bram Moolenaar720c7102007-05-10 18:07:50 +00003128 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 gui_mch_draw_string() below), enable it for all font sizes. */
3130 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 eventTypeSpec.eventClass = kEventClassMouse;
3133 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3134 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3135 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3136 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3137 {
3138 mouseWheelHandlerRef = NULL;
3139 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3140 mouseWheelHandlerUPP = NULL;
3141 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003143#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003144 InterfaceTypeList supportedServices = { kUnicodeDocument };
3145 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3146
3147 /* We don't support inline input yet, use input window by default */
3148 UseInputWindow(gTSMDocument, TRUE);
3149
3150 /* Should we activate the document by default? */
3151 // ActivateTSMDocument(gTSMDocument);
3152
3153 EventTypeSpec textEventTypes[] = {
3154 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3155 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3156 { kEventClassTextInput, kEventTextInputPosToOffset },
3157 { kEventClassTextInput, kEventTextInputOffsetToPos },
3158 };
3159
3160 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3161 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3162 NR_ELEMS(textEventTypes),
3163 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003164 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003165 DisposeEventHandlerUPP(keyEventHandlerUPP);
3166 keyEventHandlerUPP = NULL;
3167 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003168
3169 EventTypeSpec windowEventTypes[] = {
3170 { kEventClassWindow, kEventWindowActivated },
3171 { kEventClassWindow, kEventWindowDeactivated },
3172 };
3173
3174 /* Install window event handler to support TSMDocument activate and
3175 * deactivate */
3176 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3177 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3178 winEventHandlerUPP,
3179 NR_ELEMS(windowEventTypes),
3180 windowEventTypes, NULL, NULL))
3181 {
3182 DisposeEventHandlerUPP(winEventHandlerUPP);
3183 winEventHandlerUPP = NULL;
3184 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185#endif
3186
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003187/*
3188#ifdef FEAT_MBYTE
3189 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3190#endif
3191*/
3192
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003193#ifdef FEAT_GUI_TABLINE
3194 /*
3195 * Create the tabline
3196 */
3197 initialise_tabline();
3198#endif
3199
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200 /* TODO: Load bitmap if using TOOLBAR */
3201 return OK;
3202}
3203
3204/*
3205 * Called when the foreground or background color has been changed.
3206 */
3207 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003208gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210 /* TODO:
3211 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003212 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 */
3214}
3215
3216/*
3217 * Open the GUI window which was created by a call to gui_mch_init().
3218 */
3219 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003220gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221{
3222 ShowWindow(gui.VimWindow);
3223
3224 if (gui_win_x != -1 && gui_win_y != -1)
3225 gui_mch_set_winpos(gui_win_x, gui_win_y);
3226
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 /*
3228 * Make the GUI the foreground process (in case it was launched
3229 * from the Terminal or via :gui).
3230 */
3231 {
3232 ProcessSerialNumber psn;
3233 if (GetCurrentProcess(&psn) == noErr)
3234 SetFrontProcess(&psn);
3235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237 return OK;
3238}
3239
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003240#ifdef USE_ATSUI_DRAWING
3241 static void
3242gui_mac_dispose_atsui_style(void)
3243{
3244 if (p_macatsui && gFontStyle)
3245 ATSUDisposeStyle(gFontStyle);
3246#ifdef FEAT_MBYTE
3247 if (p_macatsui && gWideFontStyle)
3248 ATSUDisposeStyle(gWideFontStyle);
3249#endif
3250}
3251#endif
3252
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253 void
3254gui_mch_exit(int rc)
3255{
3256 /* TODO: find out all what is missing here? */
3257 DisposeRgn(cursorRgn);
3258
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003259#ifdef USE_CARBONKEYHANDLER
3260 if (keyEventHandlerUPP)
3261 DisposeEventHandlerUPP(keyEventHandlerUPP);
3262#endif
3263
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 if (mouseWheelHandlerUPP != NULL)
3265 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003267#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003268 gui_mac_dispose_atsui_style();
3269#endif
3270
3271#ifdef USE_CARBONKEYHANDLER
3272 FixTSMDocument(gTSMDocument);
3273 DeactivateTSMDocument(gTSMDocument);
3274 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003275#endif
3276
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 /* Exit to shell? */
3278 exit(rc);
3279}
3280
3281/*
3282 * Get the position of the top left corner of the window.
3283 */
3284 int
3285gui_mch_get_winpos(int *x, int *y)
3286{
3287 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 Rect bounds;
3289 OSStatus status;
3290
3291 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003292 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293
3294 if (status != noErr)
3295 return FAIL;
3296 *x = bounds.left;
3297 *y = bounds.top;
3298 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299}
3300
3301/*
3302 * Set the position of the top left corner of the window to the given
3303 * coordinates.
3304 */
3305 void
3306gui_mch_set_winpos(int x, int y)
3307{
3308 /* TODO: Should make sure the window is move within range
3309 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3310 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003311 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312}
3313
3314 void
3315gui_mch_set_shellsize(
3316 int width,
3317 int height,
3318 int min_width,
3319 int min_height,
3320 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003321 int base_height,
3322 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 CGrafPtr VimPort;
3325 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326
3327 if (gui.which_scrollbars[SBAR_LEFT])
3328 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003329 VimPort = GetWindowPort(gui.VimWindow);
3330 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003332 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 }
3335 else
3336 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003337 VimPort = GetWindowPort(gui.VimWindow);
3338 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 }
3342
3343 SizeWindow(gui.VimWindow, width, height, TRUE);
3344
3345 gui_resize_shell(width, height);
3346}
3347
3348/*
3349 * Get the screen dimensions.
3350 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3351 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003352 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353 */
3354 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003355gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356{
3357 GDHandle dominantDevice = GetMainDevice();
3358 Rect screenRect = (**dominantDevice).gdRect;
3359
3360 *screen_w = screenRect.right - 10;
3361 *screen_h = screenRect.bottom - 40;
3362}
3363
3364
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003365/*
3366 * Open the Font Panel and wait for the user to select a font and
3367 * close the panel. Then fill the buffer pointed to by font_name with
3368 * the name and size of the selected font and return the font's handle,
3369 * or NOFONT in case of an error.
3370 */
3371 static GuiFont
3372gui_mac_select_font(char_u *font_name)
3373{
3374 GuiFont selected_font = NOFONT;
3375 OSStatus status;
3376 FontSelectionQDStyle curr_font;
3377
3378 /* Initialize the Font Panel with the current font. */
3379 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3380 curr_font.size = (gui.norm_font >> 16);
3381 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3382 curr_font.instance.fontStyle = 0;
3383 curr_font.hasColor = false;
3384 curr_font.version = 0; /* version number of the style structure */
3385 status = SetFontInfoForSelection(kFontSelectionQDType,
3386 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3387
3388 gFontPanelInfo.family = curr_font.instance.fontFamily;
3389 gFontPanelInfo.style = curr_font.instance.fontStyle;
3390 gFontPanelInfo.size = curr_font.size;
3391
3392 /* Pop up the Font Panel. */
3393 status = FPShowHideFontPanel();
3394 if (status == noErr)
3395 {
3396 /*
3397 * The Font Panel is modeless. We really need it to be modal,
3398 * so we spin in an event loop until the panel is closed.
3399 */
3400 gFontPanelInfo.isPanelVisible = true;
3401 while (gFontPanelInfo.isPanelVisible)
3402 {
3403 EventRecord e;
3404 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3405 }
3406
3407 GetFontPanelSelection(font_name);
3408 selected_font = gui_mac_find_font(font_name);
3409 }
3410 return selected_font;
3411}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003412
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003413#ifdef USE_ATSUI_DRAWING
3414 static void
3415gui_mac_create_atsui_style(void)
3416{
3417 if (p_macatsui && gFontStyle == NULL)
3418 {
3419 if (ATSUCreateStyle(&gFontStyle) != noErr)
3420 gFontStyle = NULL;
3421 }
3422#ifdef FEAT_MBYTE
3423 if (p_macatsui && gWideFontStyle == NULL)
3424 {
3425 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3426 gWideFontStyle = NULL;
3427 }
3428#endif
3429
3430 p_macatsui_last = p_macatsui;
3431}
3432#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433
3434/*
3435 * Initialise vim to use the font with the given name. Return FAIL if the font
3436 * could not be loaded, OK otherwise.
3437 */
3438 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003439gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440{
3441 /* TODO: Add support for bold italic underline proportional etc... */
3442 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003443 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444 FontInfo font_info;
3445 short font_id;
3446 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003447 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003449#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003450 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003451#endif
3452
Bram Moolenaar071d4272004-06-13 20:20:40 +00003453 if (font_name == NULL)
3454 {
3455 /* First try to get the suggested font */
3456 GetFNum(suggestedFont, &font_id);
3457
3458 if (font_id == 0)
3459 {
3460 /* Then pickup the standard application font */
3461 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003462 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003464 else
3465 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3467 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003468 else if (STRCMP(font_name, "*") == 0)
3469 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003470 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003471
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003473 if (font == NOFONT)
3474 return FAIL;
3475
3476 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003477 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003478 if (new_p_guifont != NULL)
3479 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003481 vim_free(p_guifont);
3482 p_guifont = new_p_guifont;
3483 /* Replace spaces in the font name with underscores. */
3484 for ( ; *new_p_guifont; ++new_p_guifont)
3485 {
3486 if (*new_p_guifont == ' ')
3487 *new_p_guifont = '_';
3488 }
3489 }
3490 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 else
3492 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003493 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003494 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495
3496 if (font == NOFONT)
3497 return FAIL;
3498 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003499
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 gui.norm_font = font;
3501
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003502 hl_set_font_name(used_font_name);
3503
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003504 TextSize(font >> 16);
3505 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003507 GetFontInfo(&font_info);
3508
3509 gui.char_ascent = font_info.ascent;
3510 gui.char_width = CharWidth('_');
3511 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3512
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003513#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003514 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003515 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003516#endif
3517
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519}
3520
Bram Moolenaar02743632005-07-25 20:42:36 +00003521/*
3522 * Adjust gui.char_height (after 'linespace' was changed).
3523 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003525gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526{
3527 FontInfo font_info;
3528
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003529 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3531 gui.char_ascent = font_info.ascent + p_linespace / 2;
3532 return OK;
3533}
3534
3535/*
3536 * Get a font structure for highlighting.
3537 */
3538 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003539gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540{
3541 GuiFont font;
3542
3543 font = gui_mac_find_font(name);
3544
3545 if (font == NOFONT)
3546 {
3547 if (giveErrorIfMissing)
3548 EMSG2(_(e_font), name);
3549 return NOFONT;
3550 }
3551 /*
3552 * TODO : Accept only monospace
3553 */
3554
3555 return font;
3556}
3557
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003558#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003560 * Return the name of font "font" in allocated memory.
3561 * Don't know how to get the actual name, thus use the provided name.
3562 */
3563 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003564gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003565{
3566 if (name == NULL)
3567 return NULL;
3568 return vim_strsave(name);
3569}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003570#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003571
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003572#ifdef USE_ATSUI_DRAWING
3573 static void
3574gui_mac_set_font_attributes(GuiFont font)
3575{
3576 ATSUFontID fontID;
3577 Fixed fontSize;
3578 Fixed fontWidth;
3579
3580 fontID = font & 0xFFFF;
3581 fontSize = Long2Fix(font >> 16);
3582 fontWidth = Long2Fix(gui.char_width);
3583
3584 ATSUAttributeTag attribTags[] =
3585 {
3586 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3587 kATSUMaxATSUITagValue + 1
3588 };
3589
3590 ByteCount attribSizes[] =
3591 {
3592 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3593 sizeof(font)
3594 };
3595
3596 ATSUAttributeValuePtr attribValues[] =
3597 {
3598 &fontID, &fontSize, &fontWidth, &font
3599 };
3600
3601 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3602 {
3603 if (ATSUSetAttributes(gFontStyle,
3604 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3605 attribTags, attribSizes, attribValues) != noErr)
3606 {
3607# ifndef NDEBUG
3608 fprintf(stderr, "couldn't set font style\n");
3609# endif
3610 ATSUDisposeStyle(gFontStyle);
3611 gFontStyle = NULL;
3612 }
3613
3614#ifdef FEAT_MBYTE
3615 if (has_mbyte)
3616 {
3617 /* FIXME: we should use a more mbyte sensitive way to support
3618 * wide font drawing */
3619 fontWidth = Long2Fix(gui.char_width * 2);
3620
3621 if (ATSUSetAttributes(gWideFontStyle,
3622 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3623 attribTags, attribSizes, attribValues) != noErr)
3624 {
3625 ATSUDisposeStyle(gWideFontStyle);
3626 gWideFontStyle = NULL;
3627 }
3628 }
3629#endif
3630 }
3631}
3632#endif
3633
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003634/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 * Set the current text font.
3636 */
3637 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003638gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003640#ifdef USE_ATSUI_DRAWING
3641 GuiFont currFont;
3642 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003643
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003644 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003645 {
3646 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003647 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3648 sizeof(font), &currFont, &actualFontByteCount) == noErr
3649 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003650 {
3651 if (currFont == font)
3652 return;
3653 }
3654
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003655 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003656 }
3657
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003658 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003659 {
3660 /* Setup automatic font substitution. The user's guifontwide
3661 * is tried first, then the system tries other fonts. */
3662/*
3663 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3664 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3665 ATSUCreateFontFallbacks(&gFontFallbacks);
3666 ATSUSetObjFontFallbacks(gFontFallbacks, );
3667*/
3668 if (gui.wide_font)
3669 {
3670 ATSUFontID fallbackFonts;
3671 gIsFontFallbackSet = TRUE;
3672
3673 if (FMGetFontFromFontFamilyInstance(
3674 (gui.wide_font & 0xFFFF),
3675 0,
3676 &fallbackFonts,
3677 NULL) == noErr)
3678 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003679 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3680 &fallbackFonts,
3681 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003682 }
3683/*
3684 ATSUAttributeValuePtr fallbackValues[] = { };
3685*/
3686 }
3687 }
3688#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 TextSize(font >> 16);
3690 TextFont(font & 0xFFFF);
3691}
3692
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693/*
3694 * If a font is not going to be used, free its structure.
3695 */
3696 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003697gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698{
3699 /*
3700 * Free font when "font" is not 0.
3701 * Nothing to do in the current implementation, since
3702 * nothing is allocated for each font used.
3703 */
3704}
3705
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706/*
3707 * Return the Pixel value (color) for the given color name. This routine was
3708 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3709 * Programmer's Guide.
3710 * Return INVALCOLOR when failed.
3711 */
3712 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003713gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714{
3715 /* TODO: Add support for the new named color of MacOS 8
3716 */
3717 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718
Bram Moolenaarab302212016-04-26 20:59:29 +02003719 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003721 LMGetHiliteRGB(&MacColor);
3722 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003724 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725}
3726
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003727 guicolor_T
3728gui_mch_get_rgb_color(int r, int g, int b)
3729{
3730 return gui_get_rgb_color_cmn(r, g, b);
3731}
3732
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733/*
3734 * Set the current text foreground color.
3735 */
3736 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003737gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738{
3739 RGBColor TheColor;
3740
3741 TheColor.red = Red(color) * 0x0101;
3742 TheColor.green = Green(color) * 0x0101;
3743 TheColor.blue = Blue(color) * 0x0101;
3744
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003745 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746}
3747
3748/*
3749 * Set the current text background color.
3750 */
3751 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003752gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753{
3754 RGBColor TheColor;
3755
3756 TheColor.red = Red(color) * 0x0101;
3757 TheColor.green = Green(color) * 0x0101;
3758 TheColor.blue = Blue(color) * 0x0101;
3759
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003760 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761}
3762
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003763RGBColor specialColor;
3764
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003765/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003766 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003767 */
3768 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003769gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003770{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003771 specialColor.red = Red(color) * 0x0101;
3772 specialColor.green = Green(color) * 0x0101;
3773 specialColor.blue = Blue(color) * 0x0101;
3774}
3775
3776/*
3777 * Draw undercurl at the bottom of the character cell.
3778 */
3779 static void
3780draw_undercurl(int flags, int row, int col, int cells)
3781{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003782 int x;
3783 int offset;
3784 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3785 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003786
3787 RGBForeColor(&specialColor);
3788
3789 offset = val[FILL_X(col) % 8];
3790 MoveTo(FILL_X(col), y - offset);
3791
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003792 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003793 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003794 offset = val[x % 8];
3795 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003796 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003797}
3798
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003799
3800 static void
3801draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803#ifdef FEAT_MBYTE
3804 char_u *tofree = NULL;
3805
3806 if (output_conv.vc_type != CONV_NONE)
3807 {
3808 tofree = string_convert(&output_conv, s, &len);
3809 if (tofree != NULL)
3810 s = tofree;
3811 }
3812#endif
3813
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 /*
3815 * On OS X, try using Quartz-style text antialiasing.
3816 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003817 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818 {
3819 /* Quartz antialiasing is available only in OS 10.2 and later. */
3820 UInt32 qd_flags = (p_antialias ?
3821 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003822 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 }
3824
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003825 /*
3826 * When antialiasing we're using srcOr mode, we have to clear the block
3827 * before drawing the text.
3828 * Also needed when 'linespace' is non-zero to remove the cursor and
3829 * underlining.
3830 * But not when drawing transparently.
3831 * The following is like calling gui_mch_clear_block(row, col, row, col +
3832 * len - 1), but without setting the bg color to gui.back_pixel.
3833 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003834 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003835 && !(flags & DRAW_TRANSP))
3836 {
3837 Rect rc;
3838
3839 rc.left = FILL_X(col);
3840 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003841#ifdef FEAT_MBYTE
3842 /* Multibyte computation taken from gui_w32.c */
3843 if (has_mbyte)
3844 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003845 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003846 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003847 }
3848 else
3849#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003850 rc.right = FILL_X(col + len) + (col + len == Columns);
3851 rc.bottom = FILL_Y(row + 1);
3852 EraseRect(&rc);
3853 }
3854
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003855 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 {
3857 StyleParameter face;
3858
3859 face = normal;
3860 if (flags & DRAW_BOLD)
3861 face |= bold;
3862 if (flags & DRAW_UNDERL)
3863 face |= underline;
3864 TextFace(face);
3865
3866 /* Quartz antialiasing works only in srcOr transfer mode. */
3867 TextMode(srcOr);
3868
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 MoveTo(TEXT_X(col), TEXT_Y(row));
3870 DrawText((char*)s, 0, len);
3871 }
3872 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 {
3874 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003875 TextMode(srcCopy);
3876 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877
3878 /* SelectFont(hdc, gui.currFont); */
3879
3880 if (flags & DRAW_TRANSP)
3881 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003882 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 }
3884
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003885 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003886 DrawText((char *)s, 0, len);
3887
3888 if (flags & DRAW_BOLD)
3889 {
3890 TextMode(srcOr);
3891 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3892 DrawText((char *)s, 0, len);
3893 }
3894
3895 if (flags & DRAW_UNDERL)
3896 {
3897 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3898 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3899 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003900 if (flags & DRAW_STRIKE)
3901 {
3902 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3903 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3904 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003905 }
3906
3907 if (flags & DRAW_UNDERC)
3908 draw_undercurl(flags, row, col, len);
3909
3910#ifdef FEAT_MBYTE
3911 vim_free(tofree);
3912#endif
3913}
3914
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003915#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003916
3917 static void
3918draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3919{
3920 /* ATSUI requires utf-16 strings */
3921 UniCharCount utf16_len;
3922 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3923 utf16_len /= sizeof(UniChar);
3924
3925 /* - ATSUI automatically antialiases text (Someone)
3926 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003927#ifdef MAC_ATSUI_DEBUG
3928 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3929 row, col, len, len == 1 ? s[0] : ' ');
3930#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003931 /*
3932 * When antialiasing we're using srcOr mode, we have to clear the block
3933 * before drawing the text.
3934 * Also needed when 'linespace' is non-zero to remove the cursor and
3935 * underlining.
3936 * But not when drawing transparently.
3937 * The following is like calling gui_mch_clear_block(row, col, row, col +
3938 * len - 1), but without setting the bg color to gui.back_pixel.
3939 */
3940 if ((flags & DRAW_TRANSP) == 0)
3941 {
3942 Rect rc;
3943
3944 rc.left = FILL_X(col);
3945 rc.top = FILL_Y(row);
3946 /* Multibyte computation taken from gui_w32.c */
3947 if (has_mbyte)
3948 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003949 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003950 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003951 }
3952 else
3953 rc.right = FILL_X(col + len) + (col + len == Columns);
3954
3955 rc.bottom = FILL_Y(row + 1);
3956 EraseRect(&rc);
3957 }
3958
3959 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003960 TextMode(srcCopy);
3961 TextFace(normal);
3962
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003963 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003964 if (flags & DRAW_TRANSP)
3965 {
3966 TextMode(srcOr);
3967 }
3968
3969 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003970
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003971 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003972 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003973 Boolean attValue = true;
3974 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3975 ByteCount attribSizes[] = { sizeof(Boolean) };
3976 ATSUAttributeValuePtr attribValues[] = { &attValue };
3977
3978 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3979 }
3980
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003981 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3982 : kATSStyleNoAntiAliasing;
3983 if (useAntialias != useAntialias_cached)
3984 {
3985 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3986 ByteCount attribSizes[] = { sizeof(UInt32) };
3987 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3988
3989 if (gFontStyle)
3990 ATSUSetAttributes(gFontStyle, 1, attribTags,
3991 attribSizes, attribValues);
3992 if (gWideFontStyle)
3993 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3994 attribSizes, attribValues);
3995
3996 useAntialias_cached = useAntialias;
3997 }
3998
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003999#ifdef FEAT_MBYTE
4000 if (has_mbyte)
4001 {
4002 int n, width_in_cell, last_width_in_cell;
4003 UniCharArrayOffset offset = 0;
4004 UniCharCount yet_to_draw = 0;
4005 ATSUTextLayout textLayout;
4006 ATSUStyle textStyle;
4007
4008 last_width_in_cell = 1;
4009 ATSUCreateTextLayout(&textLayout);
4010 ATSUSetTextPointerLocation(textLayout, tofree,
4011 kATSUFromTextBeginning,
4012 kATSUToTextEnd, utf16_len);
4013 /*
4014 ATSUSetRunStyle(textLayout, gFontStyle,
4015 kATSUFromTextBeginning, kATSUToTextEnd); */
4016
4017 /* Compute the length in display cells. */
4018 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4019 {
4020 width_in_cell = (*mb_ptr2cells)(s + n);
4021
4022 /* probably we are switching from single byte character
4023 * to multibyte characters (which requires more than one
4024 * cell to draw) */
4025 if (width_in_cell != last_width_in_cell)
4026 {
4027#ifdef MAC_ATSUI_DEBUG
4028 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4029 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4030#endif
4031 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4032 : gFontStyle;
4033
4034 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4035 offset += yet_to_draw;
4036 yet_to_draw = 0;
4037 last_width_in_cell = width_in_cell;
4038 }
4039
4040 yet_to_draw++;
4041 }
4042
4043 if (yet_to_draw)
4044 {
4045#ifdef MAC_ATSUI_DEBUG
4046 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4047 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4048#endif
4049 /* finish the rest style */
4050 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4051 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4052 }
4053
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004054 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004055 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004056 kATSUFromTextBeginning, kATSUToTextEnd,
4057 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004058 ATSUDisposeTextLayout(textLayout);
4059 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004060 else
4061#endif
4062 {
4063 ATSUTextLayout textLayout;
4064
4065 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4066 kATSUFromTextBeginning, kATSUToTextEnd,
4067 utf16_len,
4068 (gFontStyle ? 1 : 0), &utf16_len,
4069 (gFontStyle ? &gFontStyle : NULL),
4070 &textLayout) == noErr)
4071 {
4072 ATSUSetTransientFontMatching(textLayout, TRUE);
4073
4074 ATSUDrawText(textLayout,
4075 kATSUFromTextBeginning, kATSUToTextEnd,
4076 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4077
4078 ATSUDisposeTextLayout(textLayout);
4079 }
4080 }
4081
4082 /* drawing is done, now reset bold to normal */
4083 if (gFontStyle && flags & DRAW_BOLD)
4084 {
4085 Boolean attValue = false;
4086
4087 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4088 ByteCount attribSizes[] = { sizeof(Boolean) };
4089 ATSUAttributeValuePtr attribValues[] = { &attValue };
4090
4091 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4092 attribValues);
4093 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 }
4095
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004096 if (flags & DRAW_UNDERC)
4097 draw_undercurl(flags, row, col, len);
4098
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004100}
4101#endif
4102
4103 void
4104gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4105{
4106#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004107 if (p_macatsui == 0 && p_macatsui_last != 0)
4108 /* switch from macatsui to nomacatsui */
4109 gui_mac_dispose_atsui_style();
4110 else if (p_macatsui != 0 && p_macatsui_last == 0)
4111 /* switch from nomacatsui to macatsui */
4112 gui_mac_create_atsui_style();
4113
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004114 if (p_macatsui)
4115 draw_string_ATSUI(row, col, s, len, flags);
4116 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004118 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119}
4120
4121/*
4122 * Return OK if the key with the termcap name "name" is supported.
4123 */
4124 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004125gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126{
4127 int i;
4128
4129 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4130 if (name[0] == special_keys[i].vim_code0 &&
4131 name[1] == special_keys[i].vim_code1)
4132 return OK;
4133 return FAIL;
4134}
4135
4136 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004137gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004139 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140}
4141
4142 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004143gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144{
4145 /* Do a visual beep by reversing the foreground and background colors */
4146 Rect rc;
4147
4148 /*
4149 * Note: InvertRect() excludes right and bottom of rectangle.
4150 */
4151 rc.left = 0;
4152 rc.top = 0;
4153 rc.right = gui.num_cols * gui.char_width;
4154 rc.bottom = gui.num_rows * gui.char_height;
4155 InvertRect(&rc);
4156
4157 ui_delay((long)msec, TRUE); /* wait for some msec */
4158
4159 InvertRect(&rc);
4160}
4161
4162/*
4163 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4164 */
4165 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004166gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167{
4168 Rect rc;
4169
4170 /*
4171 * Note: InvertRect() excludes right and bottom of rectangle.
4172 */
4173 rc.left = FILL_X(c);
4174 rc.top = FILL_Y(r);
4175 rc.right = rc.left + nc * gui.char_width;
4176 rc.bottom = rc.top + nr * gui.char_height;
4177 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178}
4179
4180/*
4181 * Iconify the GUI window.
4182 */
4183 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004184gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185{
4186 /* TODO: find out what could replace iconify
4187 * -window shade?
4188 * -hide application?
4189 */
4190}
4191
4192#if defined(FEAT_EVAL) || defined(PROTO)
4193/*
4194 * Bring the Vim window to the foreground.
4195 */
4196 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004197gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198{
4199 /* TODO */
4200}
4201#endif
4202
4203/*
4204 * Draw a cursor without focus.
4205 */
4206 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004207gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004208{
4209 Rect rc;
4210
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211 /*
4212 * Note: FrameRect() excludes right and bottom of rectangle.
4213 */
4214 rc.left = FILL_X(gui.col);
4215 rc.top = FILL_Y(gui.row);
4216 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004217#ifdef FEAT_MBYTE
4218 if (mb_lefthalve(gui.row, gui.col))
4219 rc.right += gui.char_width;
4220#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 rc.bottom = rc.top + gui.char_height;
4222
4223 gui_mch_set_fg_color(color);
4224
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004225 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226}
4227
4228/*
4229 * Draw part of a cursor, only w pixels wide, and h pixels high.
4230 */
4231 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004232gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233{
4234 Rect rc;
4235
4236#ifdef FEAT_RIGHTLEFT
4237 /* vertical line should be on the right of current point */
4238 if (CURSOR_BAR_RIGHT)
4239 rc.left = FILL_X(gui.col + 1) - w;
4240 else
4241#endif
4242 rc.left = FILL_X(gui.col);
4243 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4244 rc.right = rc.left + w;
4245 rc.bottom = rc.top + h;
4246
4247 gui_mch_set_fg_color(color);
4248
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004249 FrameRect(&rc);
4250// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251}
4252
4253
4254
4255/*
4256 * Catch up with any queued X events. This may put keyboard input into the
4257 * input buffer, call resize call-backs, trigger timers etc. If there is
4258 * nothing in the X event queue (& no timers pending), then we return
4259 * immediately.
4260 */
4261 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004262gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263{
4264 /* TODO: find what to do
4265 * maybe call gui_mch_wait_for_chars (0)
4266 * more like look at EventQueue then
4267 * call heart of gui_mch_wait_for_chars;
4268 *
4269 * if (eventther)
4270 * gui_mac_handle_event(&event);
4271 */
4272 EventRecord theEvent;
4273
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004274 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275 if (theEvent.what != nullEvent)
4276 gui_mch_wait_for_chars(0);
4277}
4278
4279/*
4280 * Simple wrapper to neglect more easily the time
4281 * spent inside WaitNextEvent while profiling.
4282 */
4283
Bram Moolenaar071d4272004-06-13 20:20:40 +00004284 pascal
4285 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004286WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287{
4288 if (((long) sleep) < -1)
4289 sleep = 32767;
4290 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4291}
4292
4293/*
4294 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4295 * from the keyboard.
4296 * wtime == -1 Wait forever.
4297 * wtime == 0 This should never happen.
4298 * wtime > 0 Wait wtime milliseconds for a character.
4299 * Returns OK if a character was found to be available within the given time,
4300 * or FAIL otherwise.
4301 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004303gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304{
4305 EventMask mask = (everyEvent);
4306 EventRecord event;
4307 long entryTick;
4308 long currentTick;
4309 long sleeppyTick;
4310
4311 /* If we are providing life feedback with the scrollbar,
4312 * we don't want to try to wait for an event, or else
4313 * there won't be any life feedback.
4314 */
4315 if (dragged_sb != NULL)
4316 return FAIL;
4317 /* TODO: Check if FAIL is the proper return code */
4318
4319 entryTick = TickCount();
4320
4321 allow_scrollbar = TRUE;
4322
4323 do
4324 {
4325/* if (dragRectControl == kCreateEmpty)
4326 {
4327 dragRgn = NULL;
4328 dragRectControl = kNothing;
4329 }
4330 else*/ if (dragRectControl == kCreateRect)
4331 {
4332 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004333 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334 dragRectControl = kNothing;
4335 }
4336 /*
4337 * Don't use gui_mch_update() because then we will spin-lock until a
4338 * char arrives, instead we use WaitNextEventWrp() to hang until an
4339 * event arrives. No need to check for input_buf_full because we are
4340 * returning as soon as it contains a single char.
4341 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004342 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004344 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 else
4346 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004347
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004348 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004350 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 if (input_available())
4352 {
4353 allow_scrollbar = FALSE;
4354 return OK;
4355 }
4356 }
4357 currentTick = TickCount();
4358 }
4359 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4360
4361 allow_scrollbar = FALSE;
4362 return FAIL;
4363}
4364
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365/*
4366 * Output routines.
4367 */
4368
4369/* Flush any output to the screen */
4370 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004371gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372{
4373 /* TODO: Is anything needed here? */
4374}
4375
4376/*
4377 * Clear a rectangular region of the screen from text pos (row1, col1) to
4378 * (row2, col2) inclusive.
4379 */
4380 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004381gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382{
4383 Rect rc;
4384
4385 /*
4386 * Clear one extra pixel at the far right, for when bold characters have
4387 * spilled over to the next column.
4388 */
4389 rc.left = FILL_X(col1);
4390 rc.top = FILL_Y(row1);
4391 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4392 rc.bottom = FILL_Y(row2 + 1);
4393
4394 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004395 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396}
4397
4398/*
4399 * Clear the whole text window.
4400 */
4401 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004402gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403{
4404 Rect rc;
4405
4406 rc.left = 0;
4407 rc.top = 0;
4408 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4409 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4410
4411 gui_mch_set_bg_color(gui.back_pixel);
4412 EraseRect(&rc);
4413/* gui_mch_set_fg_color(gui.norm_pixel);
4414 FrameRect(&rc);
4415*/
4416}
4417
4418/*
4419 * Delete the given number of lines from the given row, scrolling up any
4420 * text further down within the scroll region.
4421 */
4422 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004423gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424{
4425 Rect rc;
4426
4427 /* changed without checking! */
4428 rc.left = FILL_X(gui.scroll_region_left);
4429 rc.right = FILL_X(gui.scroll_region_right + 1);
4430 rc.top = FILL_Y(row);
4431 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4432
4433 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004434 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435
4436 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4437 gui.scroll_region_left,
4438 gui.scroll_region_bot, gui.scroll_region_right);
4439}
4440
4441/*
4442 * Insert the given number of lines before the given row, scrolling down any
4443 * following text within the scroll region.
4444 */
4445 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004446gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447{
4448 Rect rc;
4449
4450 rc.left = FILL_X(gui.scroll_region_left);
4451 rc.right = FILL_X(gui.scroll_region_right + 1);
4452 rc.top = FILL_Y(row);
4453 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4454
4455 gui_mch_set_bg_color(gui.back_pixel);
4456
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004457 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458
4459 /* Update gui.cursor_row if the cursor scrolled or copied over */
4460 if (gui.cursor_row >= gui.row
4461 && gui.cursor_col >= gui.scroll_region_left
4462 && gui.cursor_col <= gui.scroll_region_right)
4463 {
4464 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4465 gui.cursor_row += num_lines;
4466 else if (gui.cursor_row <= gui.scroll_region_bot)
4467 gui.cursor_is_valid = FALSE;
4468 }
4469
4470 gui_clear_block(row, gui.scroll_region_left,
4471 row + num_lines - 1, gui.scroll_region_right);
4472}
4473
4474 /*
4475 * TODO: add a vim format to the clipboard which remember
4476 * LINEWISE, CHARWISE, BLOCKWISE
4477 */
4478
4479 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004480clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481{
4482
4483 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004484 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 Size scrapSize;
4486 ScrapFlavorFlags scrapFlags;
4487 ScrapRef scrap = nil;
4488 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489 int type;
4490 char *searchCR;
4491 char_u *tempclip;
4492
4493
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004494 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 if (error != noErr)
4496 return;
4497
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004498 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4499 if (error == noErr)
4500 {
4501 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4502 if (error == noErr && scrapSize > 1)
4503 flavor = 1;
4504 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004506 if (flavor == 0)
4507 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004508 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004509 if (error != noErr)
4510 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004512 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004513 if (error != noErr)
4514 return;
4515 }
4516
4517 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004519 /* In CARBON we don't need a Handle, a pointer is good */
4520 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004522 /* tempclip = lalloc(scrapSize+1, TRUE); */
4523 HLock(textOfClip);
4524 error = GetScrapFlavorData(scrap,
4525 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4526 &scrapSize, *textOfClip);
4527 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004529 if (flavor)
4530 type = **textOfClip;
4531 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004532 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004533
4534 tempclip = lalloc(scrapSize + 1, TRUE);
4535 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4536 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004538#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004539 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004540 /* Convert from utf-16 (clipboard) */
4541 size_t encLen = 0;
4542 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004543
4544 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004546 scrapSize = encLen;
4547 vim_free(tempclip);
4548 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004552
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004553 searchCR = (char *)tempclip;
4554 while (searchCR != NULL)
4555 {
4556 searchCR = strchr(searchCR, '\r');
4557 if (searchCR != NULL)
4558 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004560
4561 clip_yank_selection(type, tempclip, scrapSize, cbd);
4562
4563 vim_free(tempclip);
4564 HUnlock(textOfClip);
4565
4566 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567}
4568
4569 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004570clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571{
4572 /*
4573 * TODO: Really nothing to do?
4574 */
4575}
4576
4577 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004578clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579{
4580 return OK;
4581}
4582
4583/*
4584 * Send the current selection to the clipboard.
4585 */
4586 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004587clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588{
4589 Handle textOfClip;
4590 long scrapSize;
4591 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593
4594 char_u *str = NULL;
4595
4596 if (!cbd->owned)
4597 return;
4598
4599 clip_get_selection(cbd);
4600
4601 /*
4602 * Once we set the clipboard, lose ownership. If another application sets
4603 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 cbd->owned = FALSE;
4606
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004607 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004609#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004610 size_t utf16_len = 0;
4611 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4612 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004614 scrapSize = utf16_len;
4615 vim_free(str);
4616 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 }
4618#endif
4619
4620 if (type >= 0)
4621 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004624 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625 HLock(textOfClip);
4626
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004627 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004628 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004629 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004630 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004631 scrapSize, *textOfClip + 1);
4632 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4633 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 HUnlock(textOfClip);
4635 DisposeHandle(textOfClip);
4636 }
4637
4638 vim_free(str);
4639}
4640
4641 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004642gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004643{
4644 Rect VimBound;
4645
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004646/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648
4649 if (gui.which_scrollbars[SBAR_LEFT])
4650 {
4651 VimBound.left = -gui.scrollbar_width + 1;
4652 }
4653 else
4654 {
4655 VimBound.left = 0;
4656 }
4657
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004660 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661}
4662
4663/*
4664 * Menu stuff.
4665 */
4666
4667 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004668gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004669{
4670 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004671 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672 */
4673}
4674
4675 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004676gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677{
4678 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004679 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 */
4681}
4682
4683/*
4684 * Add a sub menu to the menu bar.
4685 */
4686 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004687gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688{
4689 /*
4690 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4691 * TODO: use menu->mnemonic and menu->actext
4692 * TODO: Try to reuse menu id
4693 * Carbon Help suggest to use only id between 1 and 235
4694 */
4695 static long next_avail_id = 128;
4696 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004697#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004698 CFStringRef name;
4699#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004701#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 short index;
4703 vimmenu_T *parent = menu->parent;
4704 vimmenu_T *brother = menu->next;
4705
4706 /* Cannot add a menu if ... */
4707 if ((parent != NULL && parent->submenu_id == 0))
4708 return;
4709
4710 /* menu ID greater than 1024 are reserved for ??? */
4711 if (next_avail_id == 1024)
4712 return;
4713
4714 /* My brother could be the PopUp, find my real brother */
4715 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4716 brother = brother->next;
4717
4718 /* Find where to insert the menu (for MenuBar) */
4719 if ((parent == NULL) && (brother != NULL))
4720 menu_after_me = brother->submenu_id;
4721
4722 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4723 if (!menu_is_menubar(menu->name))
4724 menu_after_me = hierMenu;
4725
4726 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004727#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004728 name = menu_title_removing_mnemonic(menu);
4729#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004731#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 if (name == NULL)
4733 return;
4734
4735 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736 {
4737 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004738 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4739 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 */
4741 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004742#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004743 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4744 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4745#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004746 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004747#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 next_avail_id++;
4749 }
4750
4751 if (parent == NULL)
4752 {
4753 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4754
4755 /* TODO: Verify if we could only Insert Menu if really part of the
4756 * menubar The Inserted menu are scanned or the Command-key combos
4757 */
4758
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004759 /* Insert the menu */
4760 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761#if 1
4762 /* Vim should normally update it. TODO: verify */
4763 DrawMenuBar();
4764#endif
4765 }
4766 else
4767 {
4768 /* Adding as a submenu */
4769
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004770 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771
4772 /* Call InsertMenuItem followed by SetMenuItemText
4773 * to avoid special character recognition by InsertMenuItem
4774 */
4775 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004776#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004777 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4778#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004780#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4782 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4783 InsertMenu(menu->submenu_handle, hierMenu);
4784 }
4785
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004786#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004787 CFRelease(name);
4788#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004789 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004790#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791
4792#if 0
4793 /* Done by Vim later on */
4794 DrawMenuBar();
4795#endif
4796}
4797
4798/*
4799 * Add a menu item to a menu
4800 */
4801 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004802gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004804#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004805 CFStringRef name;
4806#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004808#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809 vimmenu_T *parent = menu->parent;
4810 int menu_inserted;
4811
4812 /* Cannot add item, if the menu have not been created */
4813 if (parent->submenu_id == 0)
4814 return;
4815
4816 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4817 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4818
4819 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004820#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004821 name = menu_title_removing_mnemonic(menu);
4822#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004824#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825
4826 /* Where are just a menu item, so no handle, no id */
4827 menu->submenu_id = 0;
4828 menu->submenu_handle = NULL;
4829
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830 menu_inserted = 0;
4831 if (menu->actext)
4832 {
4833 /* If the accelerator text for the menu item looks like it describes
4834 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4835 * item's command equivalent.
4836 */
4837 int key = 0;
4838 int modifiers = 0;
4839 char_u *p_actext;
4840
4841 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004842 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 if (*p_actext != 0)
4844 key = 0; /* error: trailing text */
4845 /* find_special_key() returns a keycode with as many of the
4846 * specified modifiers as appropriate already applied (e.g., for
4847 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4848 * as the only modifier). Since we want to display all of the
4849 * modifiers, we need to convert the keycode back to a printable
4850 * character plus modifiers.
4851 * TODO: Write an alternative find_special_key() that doesn't
4852 * apply modifiers.
4853 */
4854 if (key > 0 && key < 32)
4855 {
4856 /* Convert a control key to an uppercase letter. Note that
4857 * by this point it is no longer possible to distinguish
4858 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4859 */
4860 modifiers |= MOD_MASK_CTRL;
4861 key += '@';
4862 }
4863 /* If the keycode is an uppercase letter, set the Shift modifier.
4864 * If it is a lowercase letter, don't set the modifier, but convert
4865 * the letter to uppercase for display in the menu.
4866 */
4867 else if (key >= 'A' && key <= 'Z')
4868 modifiers |= MOD_MASK_SHIFT;
4869 else if (key >= 'a' && key <= 'z')
4870 key += 'A' - 'a';
4871 /* Note: keycodes below 0x22 are reserved by Apple. */
4872 if (key >= 0x22 && vim_isprintc_strict(key))
4873 {
4874 int valid = 1;
4875 char_u mac_mods = kMenuNoModifiers;
4876 /* Convert Vim modifier codes to Menu Manager equivalents. */
4877 if (modifiers & MOD_MASK_SHIFT)
4878 mac_mods |= kMenuShiftModifier;
4879 if (modifiers & MOD_MASK_CTRL)
4880 mac_mods |= kMenuControlModifier;
4881 if (!(modifiers & MOD_MASK_CMD))
4882 mac_mods |= kMenuNoCommandModifier;
4883 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4884 valid = 0; /* TODO: will Alt someday map to Option? */
4885 if (valid)
4886 {
4887 char_u item_txt[10];
4888 /* Insert the menu item after idx, with its command key. */
4889 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4890 item_txt[3] = key;
4891 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4892 /* Set the modifier keys. */
4893 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4894 menu_inserted = 1;
4895 }
4896 }
4897 }
4898 /* Call InsertMenuItem followed by SetMenuItemText
4899 * to avoid special character recognition by InsertMenuItem
4900 */
4901 if (!menu_inserted)
4902 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4903 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004904#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004905 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4906#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004908#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909
4910#if 0
4911 /* Called by Vim */
4912 DrawMenuBar();
4913#endif
4914
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004915#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004916 CFRelease(name);
4917#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 /* TODO: Can name be freed? */
4919 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004920#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921}
4922
4923 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004924gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925{
4926 /* no tearoff menus */
4927}
4928
4929/*
4930 * Destroy the machine specific menu widget.
4931 */
4932 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004933gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004935 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936
4937 if (index > 0)
4938 {
4939 if (menu->parent)
4940 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941 {
4942 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004943 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004944
4945 /* Delete the Menu if it was a hierarchical Menu */
4946 if (menu->submenu_id != 0)
4947 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004948 DeleteMenu(menu->submenu_id);
4949 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004950 }
4951 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 }
4953#ifdef DEBUG_MAC_MENU
4954 else
4955 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004956 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 }
4958#endif
4959 }
4960 else
4961 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004963 DeleteMenu(menu->submenu_id);
4964 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 }
4966 }
4967 /* Shouldn't this be already done by Vim. TODO: Check */
4968 DrawMenuBar();
4969}
4970
4971/*
4972 * Make a menu either grey or not grey.
4973 */
4974 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004975gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004976{
4977 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004978 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979/*
4980 index = menu->index;
4981*/
4982 if (grey)
4983 {
4984 if (menu->children)
4985 DisableMenuItem(menu->submenu_handle, index);
4986 if (menu->parent)
4987 if (menu->parent->submenu_handle)
4988 DisableMenuItem(menu->parent->submenu_handle, index);
4989 }
4990 else
4991 {
4992 if (menu->children)
4993 EnableMenuItem(menu->submenu_handle, index);
4994 if (menu->parent)
4995 if (menu->parent->submenu_handle)
4996 EnableMenuItem(menu->parent->submenu_handle, index);
4997 }
4998}
4999
5000/*
5001 * Make menu item hidden or not hidden
5002 */
5003 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005004gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005{
5006 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005007 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008}
5009
5010
5011/*
5012 * This is called after setting all the menus to grey/hidden or not.
5013 */
5014 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005015gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016{
5017 DrawMenuBar();
5018}
5019
5020
5021/*
5022 * Scrollbar stuff.
5023 */
5024
5025 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005026gui_mch_enable_scrollbar(
5027 scrollbar_T *sb,
5028 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029{
5030 if (flag)
5031 ShowControl(sb->id);
5032 else
5033 HideControl(sb->id);
5034
5035#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005036 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037#endif
5038}
5039
5040 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005041gui_mch_set_scrollbar_thumb(
5042 scrollbar_T *sb,
5043 long val,
5044 long size,
5045 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046{
5047 SetControl32BitMaximum (sb->id, max);
5048 SetControl32BitMinimum (sb->id, 0);
5049 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005050 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02005052 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053#endif
5054}
5055
5056 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005057gui_mch_set_scrollbar_pos(
5058 scrollbar_T *sb,
5059 int x,
5060 int y,
5061 int w,
5062 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063{
5064 gui_mch_set_bg_color(gui.back_pixel);
5065/* if (gui.which_scrollbars[SBAR_LEFT])
5066 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005067 MoveControl(sb->id, x-16, y);
5068 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005069 }
5070 else
5071 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005072 MoveControl(sb->id, x, y);
5073 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005074 }*/
5075 if (sb == &gui.bottom_sbar)
5076 h += 1;
5077 else
5078 w += 1;
5079
5080 if (gui.which_scrollbars[SBAR_LEFT])
5081 x -= 15;
5082
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005083 MoveControl(sb->id, x, y);
5084 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005086 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087#endif
5088}
5089
5090 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005091gui_mch_create_scrollbar(
5092 scrollbar_T *sb,
5093 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094{
5095 Rect bounds;
5096
5097 bounds.top = -16;
5098 bounds.bottom = -10;
5099 bounds.right = -10;
5100 bounds.left = -16;
5101
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005102 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005103 &bounds,
5104 "\pScrollBar",
5105 TRUE,
5106 0, /* current*/
5107 0, /* top */
5108 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110 (long) sb->ident);
5111#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005112 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113#endif
5114}
5115
5116 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005117gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118{
5119 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005120 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005122 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005123#endif
5124}
5125
Bram Moolenaar703a8042016-06-04 16:24:32 +02005126 int
5127gui_mch_is_blinking(void)
5128{
5129 return FALSE;
5130}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005131
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005132 int
5133gui_mch_is_blink_off(void)
5134{
5135 return FALSE;
5136}
5137
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138/*
5139 * Cursor blink functions.
5140 *
5141 * This is a simple state machine:
5142 * BLINK_NONE not blinking at all
5143 * BLINK_OFF blinking, cursor is not shown
5144 * BLINK_ON blinking, cursor is shown
5145 */
5146 void
5147gui_mch_set_blinking(long wait, long on, long off)
5148{
5149 /* TODO: TODO: TODO: TODO: */
5150/* blink_waittime = wait;
5151 blink_ontime = on;
5152 blink_offtime = off;*/
5153}
5154
5155/*
5156 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5157 */
5158 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005159gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005160{
5161 gui_update_cursor(TRUE, FALSE);
5162 /* TODO: TODO: TODO: TODO: */
5163/* gui_w32_rm_blink_timer();
5164 if (blink_state == BLINK_OFF)
5165 gui_update_cursor(TRUE, FALSE);
5166 blink_state = BLINK_NONE;*/
5167}
5168
5169/*
5170 * Start the cursor blinking. If it was already blinking, this restarts the
5171 * waiting time and shows the cursor.
5172 */
5173 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005174gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005175{
5176 gui_update_cursor(TRUE, FALSE);
5177 /* TODO: TODO: TODO: TODO: */
5178/* gui_w32_rm_blink_timer(); */
5179
5180 /* Only switch blinking on if none of the times is zero */
5181/* if (blink_waittime && blink_ontime && blink_offtime)
5182 {
5183 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5184 (TIMERPROC)_OnBlinkTimer);
5185 blink_state = BLINK_ON;
5186 gui_update_cursor(TRUE, FALSE);
5187 }*/
5188}
5189
5190/*
5191 * Return the RGB value of a pixel as long.
5192 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005193 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194gui_mch_get_rgb(guicolor_T pixel)
5195{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005196 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005197}
5198
5199
5200
5201#ifdef FEAT_BROWSE
5202/*
5203 * Pop open a file browser and return the file selected, in allocated memory,
5204 * or NULL if Cancel is hit.
5205 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5206 * title - Title message for the file browser dialog.
5207 * dflt - Default name of file.
5208 * ext - Default extension to be added to files without extensions.
5209 * initdir - directory in which to open the browser (NULL = current dir)
5210 * filter - Filter for matched files to choose from.
5211 * Has a format like this:
5212 * "C Files (*.c)\0*.c\0"
5213 * "All Files\0*.*\0\0"
5214 * If these two strings were concatenated, then a choice of two file
5215 * filters will be selectable to the user. Then only matching files will
5216 * be shown in the browser. If NULL, the default allows all files.
5217 *
5218 * *NOTE* - the filter string must be terminated with TWO nulls.
5219 */
5220 char_u *
5221gui_mch_browse(
5222 int saving,
5223 char_u *title,
5224 char_u *dflt,
5225 char_u *ext,
5226 char_u *initdir,
5227 char_u *filter)
5228{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005229 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 NavReplyRecord reply;
5231 char_u *fname = NULL;
5232 char_u **fnames = NULL;
5233 long numFiles;
5234 NavDialogOptions navOptions;
5235 OSErr error;
5236
5237 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005238 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239
5240
5241 /* TODO: If we get a :browse args, set the Multiple bit. */
5242 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5243 | kNavDontAutoTranslate
5244 | kNavDontAddTranslateItems
5245 /* | kNavAllowMultipleFiles */
5246 | kNavAllowStationery;
5247
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005248 (void) C2PascalString(title, &navOptions.message);
5249 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250 /* Could set clientName?
5251 * windowTitle? (there's no title bar?)
5252 */
5253
5254 if (saving)
5255 {
5256 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005257 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258 if (!reply.validRecord)
5259 return NULL;
5260 }
5261 else
5262 {
5263 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5264 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5265 if (!reply.validRecord)
5266 return NULL;
5267 }
5268
5269 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5270
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005271 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272
5273 if (fnames)
5274 {
5275 fname = fnames[0];
5276 vim_free(fnames);
5277 }
5278
5279 /* TODO: Shorten the file name if possible */
5280 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005281}
5282#endif /* FEAT_BROWSE */
5283
5284#ifdef FEAT_GUI_DIALOG
5285/*
5286 * Stuff for dialogues
5287 */
5288
5289/*
5290 * Create a dialogue dynamically from the parameter strings.
5291 * type = type of dialogue (question, alert, etc.)
5292 * title = dialogue title. may be NULL for default title.
5293 * message = text to display. Dialogue sizes to accommodate it.
5294 * buttons = '\n' separated list of button captions, default first.
5295 * dfltbutton = number of default button.
5296 *
5297 * This routine returns 1 if the first button is pressed,
5298 * 2 for the second, etc.
5299 *
5300 * 0 indicates Esc was pressed.
5301 * -1 for unexpected error
5302 *
5303 * If stubbing out this fn, return 1.
5304 */
5305
5306typedef struct
5307{
5308 short idx;
5309 short width; /* Size of the text in pixel */
5310 Rect box;
5311} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5312
5313#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5314
5315 static void
5316macMoveDialogItem(
5317 DialogRef theDialog,
5318 short itemNumber,
5319 short X,
5320 short Y,
5321 Rect *inBox)
5322{
5323#if 0 /* USE_CARBONIZED */
5324 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005325 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005327 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328#else
5329 short itemType;
5330 Handle itemHandle;
5331 Rect localBox;
5332 Rect *itemBox = &localBox;
5333
5334 if (inBox != nil)
5335 itemBox = inBox;
5336
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005337 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5338 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5339 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340 /* To move a control (like a button) we need to call both
5341 * MoveControl and SetDialogItem. FAQ 6-18 */
5342 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005343 MoveControl((ControlRef) itemHandle, X, Y);
5344 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345#endif
5346}
5347
5348 static void
5349macSizeDialogItem(
5350 DialogRef theDialog,
5351 short itemNumber,
5352 short width,
5353 short height)
5354{
5355 short itemType;
5356 Handle itemHandle;
5357 Rect itemBox;
5358
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005359 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005360
5361 /* When width or height is zero do not change it */
5362 if (width == 0)
5363 width = itemBox.right - itemBox.left;
5364 if (height == 0)
5365 height = itemBox.bottom - itemBox.top;
5366
5367#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005368 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005369#else
5370 /* Resize the bounding box */
5371 itemBox.right = itemBox.left + width;
5372 itemBox.bottom = itemBox.top + height;
5373
5374 /* To resize a control (like a button) we need to call both
5375 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5376 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005377 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378
5379 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005380 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381#endif
5382}
5383
5384 static void
5385macSetDialogItemText(
5386 DialogRef theDialog,
5387 short itemNumber,
5388 Str255 itemName)
5389{
5390 short itemType;
5391 Handle itemHandle;
5392 Rect itemBox;
5393
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005394 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005395
5396 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005397 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005399 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400}
5401
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005402
5403/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5404 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5405 * setting gDialogHotKeys to NULL disables any hotkey handling.
5406 */
5407 static pascal Boolean
5408DialogHotkeyFilterProc (
5409 DialogRef theDialog,
5410 EventRecord *event,
5411 DialogItemIndex *itemHit)
5412{
5413 char_u keyHit;
5414
5415 if (event->what == keyDown || event->what == autoKey)
5416 {
5417 keyHit = (event->message & charCodeMask);
5418
5419 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5420 {
5421#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5422 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5423#endif
5424 *itemHit = gDialogHotKeys[keyHit];
5425
5426 /* When handing off to StdFilterProc, pretend that the user
5427 * clicked the control manually. Note that this is also supposed
5428 * to cause the button to hilite briefly (to give some user
5429 * feedback), but this seems not to actually work (or it's too
5430 * fast to be seen).
5431 */
5432 event->what = kEventControlSimulateHit;
5433
5434 return true; /* we took care of it */
5435 }
5436
5437 /* Defer to the OS's standard behavior for this event.
5438 * This ensures that Enter will still activate the default button. */
5439 return StdFilterProc(theDialog, event, itemHit);
5440 }
5441 return false; /* Let ModalDialog deal with it */
5442}
5443
5444
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005445/* TODO: There have been some crashes with dialogs, check your inbox
5446 * (Jussi)
5447 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005448 int
5449gui_mch_dialog(
5450 int type,
5451 char_u *title,
5452 char_u *message,
5453 char_u *buttons,
5454 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005455 char_u *textfield,
5456 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005457{
5458 Handle buttonDITL;
5459 Handle iconDITL;
5460 Handle inputDITL;
5461 Handle messageDITL;
5462 Handle itemHandle;
5463 Handle iconHandle;
5464 DialogPtr theDialog;
5465 char_u len;
5466 char_u PascalTitle[256]; /* place holder for the title */
5467 char_u name[256];
5468 GrafPtr oldPort;
5469 short itemHit;
5470 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005471 short hotKeys[256]; /* map of hotkey -> control ID */
5472 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473 Rect box;
5474 short button;
5475 short lastButton;
5476 short itemType;
5477 short useIcon;
5478 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005479 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005480 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005481 short widestButton = 0;
5482 short dfltButtonEdge = 20; /* gut feeling */
5483 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5484 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5485 short maximumWidth = 400; /* gut feeling */
5486 short maxButtonWidth = 175; /* gut feeling */
5487
5488 short vertical;
5489 short dialogHeight;
5490 short messageLines = 3;
5491 FontInfo textFontInfo;
5492
5493 vgmDlgItm iconItm;
5494 vgmDlgItm messageItm;
5495 vgmDlgItm inputItm;
5496 vgmDlgItm buttonItm;
5497
5498 WindowRef theWindow;
5499
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005500 ModalFilterUPP dialogUPP;
5501
Bram Moolenaar071d4272004-06-13 20:20:40 +00005502 /* Check 'v' flag in 'guioptions': vertical button placement. */
5503 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5504
5505 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005506 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005507
5508 /* Get the WindowRef */
5509 theWindow = GetDialogWindow(theDialog);
5510
5511 /* Hide the window.
5512 * 1. to avoid seeing slow drawing
5513 * 2. to prevent a problem seen while moving dialog item
5514 * within a visible window. (non-Carbon MacOS 9)
5515 * Could be avoided by changing the resource.
5516 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005517 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518
5519 /* Change the graphical port to the dialog,
5520 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005521 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005522 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523
5524 /* Get the info about the default text,
5525 * used to calculate the height of the message
5526 * and of the text field */
5527 GetFontInfo(&textFontInfo);
5528
5529 /* Set the dialog title */
5530 if (title != NULL)
5531 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005532 (void) C2PascalString(title, &PascalTitle);
5533 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534 }
5535
5536 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005537 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005538 buttonChar = buttons;
5539 button = 0;
5540
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005541 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005542 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005543
Bram Moolenaar071d4272004-06-13 20:20:40 +00005544 for (;*buttonChar != 0;)
5545 {
5546 /* Get the name of the button */
5547 button++;
5548 len = 0;
5549 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5550 {
5551 if (*buttonChar != DLG_HOTKEY_CHAR)
5552 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005553 else
5554 {
5555 aHotKey = (char_u)*(buttonChar+1);
5556 if (aHotKey >= 'A' && aHotKey <= 'Z')
5557 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5558 hotKeys[aHotKey] = button;
5559#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5560 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5561#endif
5562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005564
Bram Moolenaar071d4272004-06-13 20:20:40 +00005565 if (*buttonChar != 0)
5566 buttonChar++;
5567 name[0] = len;
5568
5569 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005570 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571
5572 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005573 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574
5575 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005576 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005577 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005578 /* TODO: Should be based on the message width */
5579 if (width > maxButtonWidth)
5580 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005581 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582
5583 totalButtonWidth += width;
5584
5585 if (width > widestButton)
5586 widestButton = width;
5587 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005588 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589 lastButton = button;
5590
5591 /* Add the icon to the Dialog Box. */
5592 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005593 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005594 switch (type)
5595 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005596 case VIM_GENERIC:
5597 case VIM_INFO:
5598 case VIM_QUESTION: useIcon = kNoteIcon; break;
5599 case VIM_WARNING: useIcon = kCautionIcon; break;
5600 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005601 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005602 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005603 AppendDITL(theDialog, iconDITL, overlayDITL);
5604 ReleaseResource(iconDITL);
5605 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005606 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005607 iconHandle = GetIcon(useIcon);
5608 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609
5610 /* Add the message to the Dialog box. */
5611 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005612 messageDITL = GetResource('DITL', 132);
5613 AppendDITL(theDialog, messageDITL, overlayDITL);
5614 ReleaseResource(messageDITL);
5615 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5616 (void) C2PascalString(message, &name);
5617 SetDialogItemText(itemHandle, name);
5618 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619
5620 /* Add the input box if needed */
5621 if (textfield != NULL)
5622 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005623 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005625 inputDITL = GetResource('DITL', 132);
5626 AppendDITL(theDialog, inputDITL, overlayDITL);
5627 ReleaseResource(inputDITL);
5628 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5629/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5630 (void) C2PascalString(textfield, &name);
5631 SetDialogItemText(itemHandle, name);
5632 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005633
5634 /* Hotkeys don't make sense if there's a text field */
5635 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005636 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005637 else
5638 /* Install hotkey table */
5639 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640
5641 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005642 SetDialogDefaultItem(theDialog, dfltbutton);
5643 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644
5645 /* Reposition element */
5646
5647 /* Check if we need to force vertical */
5648 if (totalButtonWidth > maximumWidth)
5649 vertical = TRUE;
5650
5651 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005652 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 iconItm.box.right = box.right;
5654 iconItm.box.bottom = box.bottom;
5655
5656 /* Place Message */
5657 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005658 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5659 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660
5661 /* Place Input */
5662 if (textfield != NULL)
5663 {
5664 inputItm.box.left = messageItm.box.left;
5665 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005666 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5667 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005668 /* Convert the static text into a text edit.
5669 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005670 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5671 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005672 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5673 }
5674
5675 /* Place Button */
5676 if (textfield != NULL)
5677 {
5678 buttonItm.box.left = inputItm.box.left;
5679 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5680 }
5681 else
5682 {
5683 buttonItm.box.left = messageItm.box.left;
5684 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5685 }
5686
5687 for (button=1; button <= lastButton; button++)
5688 {
5689
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005690 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005691 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 if (vertical)
5693 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005694 macSizeDialogItem(theDialog, button, widestButton, 0);
5695 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696 }
5697 /* Calculate position of next button */
5698 if (vertical)
5699 buttonItm.box.top = box.bottom + dfltElementSpacing;
5700 else
5701 buttonItm.box.left = box.right + dfltElementSpacing;
5702 }
5703
5704 /* Resize the dialog box */
5705 dialogHeight = box.bottom + dfltElementSpacing;
5706 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5707
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005709 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711
5712 /* Display it */
5713 ShowWindow(theWindow);
5714/* BringToFront(theWindow); */
5715 SelectWindow(theWindow);
5716
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005717/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005718#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005719 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005720 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721#endif
5722
Bram Moolenaard68071d2006-05-02 22:08:30 +00005723#ifdef USE_CARBONKEYHANDLER
5724 /* Avoid that we use key events for the main window. */
5725 dialog_busy = TRUE;
5726#endif
5727
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005728 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5729 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5730
Bram Moolenaar071d4272004-06-13 20:20:40 +00005731 /* Hang until one of the button is hit */
5732 do
5733 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005734 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735 } while ((itemHit < 1) || (itemHit > lastButton));
5736
Bram Moolenaard68071d2006-05-02 22:08:30 +00005737#ifdef USE_CARBONKEYHANDLER
5738 dialog_busy = FALSE;
5739#endif
5740
Bram Moolenaar071d4272004-06-13 20:20:40 +00005741 /* Copy back the text entered by the user into the param */
5742 if (textfield != NULL)
5743 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005744 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5745 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005746#if IOSIZE < 256
5747 /* Truncate the name to IOSIZE if needed */
5748 if (name[0] > IOSIZE)
5749 name[0] = IOSIZE - 1;
5750#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005751 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752 }
5753
5754 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005755 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005756
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005757 /* Free the modal filterProc */
5758 DisposeRoutineDescriptor(dialogUPP);
5759
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005760 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005761 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762
5763 return itemHit;
5764/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005765 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005766 * SetDialogTimeout(): Auto click a button after timeout
5767 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5768 * MoveDialogItem(): Probably better than SetDialogItem
5769 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005770 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771 */
5772}
5773#endif /* FEAT_DIALOG_GUI */
5774
5775/*
5776 * Display the saved error message(s).
5777 */
5778#ifdef USE_MCH_ERRMSG
5779 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005780display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781{
5782 char *p;
5783 char_u pError[256];
5784
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005785 if (error_ga.ga_data == NULL)
5786 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005788 /* avoid putting up a message box with blanks only */
5789 for (p = (char *)error_ga.ga_data; *p; ++p)
5790 if (!isspace(*p))
5791 {
5792 if (STRLEN(p) > 255)
5793 pError[0] = 255;
5794 else
5795 pError[0] = STRLEN(p);
5796
5797 STRNCPY(&pError[1], p, pError[0]);
5798 ParamText(pError, nil, nil, nil);
5799 Alert(128, nil);
5800 break;
5801 /* TODO: handled message longer than 256 chars
5802 * use auto-sizeable alert
5803 * or dialog with scrollbars (TextEdit zone)
5804 */
5805 }
5806 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005807}
5808#endif
5809
5810/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005811 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005812 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005813 void
5814gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815{
5816 Point where;
5817
5818 GetMouse(&where);
5819
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005820 *x = where.h;
5821 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822}
5823
5824 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005825gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826{
5827 /* TODO */
5828#if 0
5829 /* From FAQ 3-11 */
5830
5831 CursorDevicePtr myMouse;
5832 Point where;
5833
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005834 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5835 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005836 {
5837 /* New way */
5838
5839 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005840 * Get first device with one button.
5841 * This will probably be the standard mouse
5842 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843 *
5844 */
5845
5846 myMouse = nil;
5847
5848 do
5849 {
5850 /* Get the next cursor device */
5851 CursorDeviceNextDevice(&myMouse);
5852 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005853 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005854
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005855 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 }
5857 else
5858 {
5859 /* Old way */
5860 where.h = x;
5861 where.v = y;
5862
5863 *(Point *)RawMouse = where;
5864 *(Point *)MTemp = where;
5865 *(Ptr) CrsrNew = 0xFFFF;
5866 }
5867#endif
5868}
5869
5870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005871gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005873/*
5874 * Clone PopUp to use menu
5875 * Create a object descriptor for the current selection
5876 * Call the procedure
5877 */
5878
5879 MenuHandle CntxMenu;
5880 Point where;
5881 OSStatus status;
5882 UInt32 CntxType;
5883 SInt16 CntxMenuID;
5884 UInt16 CntxMenuItem;
5885 Str255 HelpName = "";
5886 GrafPtr savePort;
5887
5888 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005889 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005890
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005891 GetMouse(&where);
5892 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005893 CntxMenu = menu->submenu_handle;
5894
5895 /* TODO: Get the text selection from Vim */
5896
5897 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005898 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005899 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005900
5901 if (status == noErr)
5902 {
5903 if (CntxType == kCMMenuItemSelected)
5904 {
5905 /* Handle the menu CntxMenuID, CntxMenuItem */
5906 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005907 /* But what about the current menu, is the menu changed by
5908 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005909 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005910 }
5911 else if (CntxMenuID == kCMShowHelpSelected)
5912 {
5913 /* Should come up with the help */
5914 }
5915 }
5916
5917 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005918 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919}
5920
5921#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5922/* TODO: Is it need for MACOS_X? (Dany) */
5923 void
5924mch_post_buffer_write(buf_T *buf)
5925{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005926 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5927 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928}
5929#endif
5930
5931#ifdef FEAT_TITLE
5932/*
5933 * Set the window title and icon.
5934 * (The icon is not taken care of).
5935 */
5936 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005937gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938{
5939 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5940 * that 256. Even better get it to fit nicely in the titlebar.
5941 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005942#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005943 CFStringRef windowTitle;
5944 size_t windowTitleLen;
5945#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005947#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948
5949 if (title == NULL) /* nothing to do */
5950 return;
5951
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005952#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005953 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005954 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005955
5956 if (windowTitle)
5957 {
5958 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5959 CFRelease(windowTitle);
5960 }
5961#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 pascalTitle = C2Pascal_save(title);
5963 if (pascalTitle != NULL)
5964 {
5965 SetWTitle(gui.VimWindow, pascalTitle);
5966 vim_free(pascalTitle);
5967 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005968#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969}
5970#endif
5971
5972/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005973 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974 */
5975
5976 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005977C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978{
5979 char_u *PascalPtr = (char_u *) PascalString;
5980 int len;
5981 int i;
5982
5983 PascalPtr[0] = 0;
5984 if (CString == NULL)
5985 return 0;
5986
5987 len = STRLEN(CString);
5988 if (len > 255)
5989 len = 255;
5990
5991 for (i = 0; i < len; i++)
5992 PascalPtr[i+1] = CString[i];
5993
5994 PascalPtr[0] = len;
5995
5996 return 0;
5997}
5998
5999 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006000GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001{
6002 /* From FAQ 8-12 */
6003 Str255 filePascal;
6004 CInfoPBRec myCPB;
6005 OSErr err;
6006
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006007 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008
6009 myCPB.dirInfo.ioNamePtr = filePascal;
6010 myCPB.dirInfo.ioVRefNum = 0;
6011 myCPB.dirInfo.ioFDirIndex = 0;
6012 myCPB.dirInfo.ioDrDirID = 0;
6013
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006014 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015
6016 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006017 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006018
6019 /* TODO: Use an error code mechanism */
6020 return 0;
6021}
6022
6023/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006024 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025 */
6026
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006027char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006028{
6029 /*
6030 * TODO: Add protection for 256 char max.
6031 */
6032
6033 CInfoPBRec theCPB;
6034 char_u fname[256];
6035 char_u *filenamePtr = fname;
6036 OSErr error;
6037 int folder = 1;
6038#ifdef USE_UNIXFILENAME
6039 SInt16 dfltVol_vRefNum;
6040 SInt32 dfltVol_dirID;
6041 FSRef refFile;
6042 OSStatus status;
6043 UInt32 pathSize = 256;
6044 char_u pathname[256];
6045 char_u *path = pathname;
6046#else
6047 Str255 directoryName;
6048 char_u temporary[255];
6049 char_u *temporaryPtr = temporary;
6050#endif
6051
6052#ifdef USE_UNIXFILENAME
6053 /* Get the default volume */
6054 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006055 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006056
6057 if (error)
6058 return NULL;
6059#endif
6060
6061 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006062 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063
6064 /* Get the info about the file specified in FSSpec */
6065 theCPB.dirInfo.ioFDirIndex = 0;
6066 theCPB.dirInfo.ioNamePtr = file.name;
6067 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006068 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069 theCPB.dirInfo.ioDrDirID = file.parID;
6070
6071 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6072 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006073 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074
6075 /* If we are called for a new file we expect fnfErr */
6076 if ((error) && (error != fnfErr))
6077 return NULL;
6078
6079 /* Check if it's a file or folder */
6080 /* default to file if file don't exist */
6081 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6082 folder = 0; /* It's not a folder */
6083 else
6084 folder = 1;
6085
6086#ifdef USE_UNIXFILENAME
6087 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006088 * The functions used here are available in Carbon, but do nothing on
6089 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006090 */
6091 if (error == fnfErr)
6092 {
6093 /* If the file to be saved does not already exist, it isn't possible
6094 to convert its FSSpec into an FSRef. But we can construct an
6095 FSSpec for the file's parent folder (since we have its volume and
6096 directory IDs), and since that folder does exist, we can convert
6097 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6098 and, finally, append the filename. */
6099 FSSpec dirSpec;
6100 FSRef dirRef;
6101 Str255 emptyFilename = "\p";
6102 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6103 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6104 if (error)
6105 return NULL;
6106
6107 error = FSpMakeFSRef(&dirSpec, &dirRef);
6108 if (error)
6109 return NULL;
6110
6111 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6112 if (status)
6113 return NULL;
6114
6115 STRCAT(path, "/");
6116 STRCAT(path, filenamePtr);
6117 }
6118 else
6119 {
6120 /* If the file to be saved already exists, we can get its full path
6121 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006122 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123 if (error)
6124 return NULL;
6125
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006126 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006127 if (status)
6128 return NULL;
6129 }
6130
6131 /* Add a slash at the end if needed */
6132 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006133 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006135 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006136#else
6137 /* TODO: Get rid of all USE_UNIXFILENAME below */
6138 /* Set ioNamePtr, it's the same area which is always reused. */
6139 theCPB.dirInfo.ioNamePtr = directoryName;
6140
6141 /* Trick for first entry, set ioDrParID to the first value
6142 * we want for ioDrDirID*/
6143 theCPB.dirInfo.ioDrParID = file.parID;
6144 theCPB.dirInfo.ioDrDirID = file.parID;
6145
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006146 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006147 do
6148 {
6149 theCPB.dirInfo.ioFDirIndex = -1;
6150 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6151 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006152 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006153 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6154
6155 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6156 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006157 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158
6159 if (error)
6160 return NULL;
6161
6162 /* Put the new directoryName in front of the current fname */
6163 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006164 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165 STRCAT(filenamePtr, ":");
6166 STRCAT(filenamePtr, temporaryPtr);
6167 }
6168#if 1 /* def USE_UNIXFILENAME */
6169 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6170 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6171#else
6172 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6173#endif
6174
6175 /* Get the information about the volume on which the file reside */
6176 theCPB.dirInfo.ioFDirIndex = -1;
6177 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6178 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006179 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6181
6182 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6183 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006184 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185
6186 if (error)
6187 return NULL;
6188
6189 /* For MacOS Classic always add the volume name */
6190 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006191 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192#ifdef USE_UNIXFILENAME
6193 if (file.vRefNum != dfltVol_vRefNum)
6194#endif
6195 {
6196 /* Add the volume name */
6197 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006198 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006199 STRCAT(filenamePtr, ":");
6200 STRCAT(filenamePtr, temporaryPtr);
6201
6202#ifdef USE_UNIXFILENAME
6203 STRCPY(temporaryPtr, filenamePtr);
6204 filenamePtr[0] = 0; /* NULL terminate the string */
6205 STRCAT(filenamePtr, "Volumes:");
6206 STRCAT(filenamePtr, temporaryPtr);
6207#endif
6208 }
6209
6210 /* Append final path separator if it's a folder */
6211 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006212 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006213
6214 /* As we use Unix File Name for MacOS X convert it */
6215#ifdef USE_UNIXFILENAME
6216 /* Need to insert leading / */
6217 /* TODO: get the above code to use directly the / */
6218 STRCPY(&temporaryPtr[1], filenamePtr);
6219 temporaryPtr[0] = '/';
6220 STRCPY(filenamePtr, temporaryPtr);
6221 {
6222 char *p;
6223 for (p = fname; *p; p++)
6224 if (*p == ':')
6225 *p = '/';
6226 }
6227#endif
6228
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006229 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230#endif
6231}
6232
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006233#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006234/*
6235 * Input Method Control functions.
6236 */
6237
6238/*
6239 * Notify cursor position to IM.
6240 */
6241 void
6242im_set_position(int row, int col)
6243{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006244#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006246 im_start_row = row;
6247 im_start_col = col;
6248#endif
6249}
6250
6251static ScriptLanguageRecord gTSLWindow;
6252static ScriptLanguageRecord gTSLInsert;
6253static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6254
6255static Component gTSCWindow;
6256static Component gTSCInsert;
6257static Component gTSCDefault;
6258
6259static int im_initialized = 0;
6260
6261 static void
6262im_on_window_switch(int active)
6263{
6264 ScriptLanguageRecord *slptr = NULL;
6265 OSStatus err;
6266
6267 if (! gui.in_use)
6268 return;
6269
6270 if (im_initialized == 0)
6271 {
6272 im_initialized = 1;
6273
6274 /* save default TSM component (should be U.S.) to default */
6275 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6276 kKeyboardInputMethodClass);
6277 }
6278
6279 if (active == TRUE)
6280 {
6281 im_is_active = TRUE;
6282 ActivateTSMDocument(gTSMDocument);
6283 slptr = &gTSLWindow;
6284
6285 if (slptr)
6286 {
6287 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6288 kKeyboardInputMethodClass);
6289 if (err == noErr)
6290 err = SetTextServiceLanguage(slptr);
6291
6292 if (err == noErr)
6293 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6294 }
6295 }
6296 else
6297 {
6298 err = GetTextServiceLanguage(&gTSLWindow);
6299 if (err == noErr)
6300 slptr = &gTSLWindow;
6301
6302 if (slptr)
6303 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6304 kKeyboardInputMethodClass);
6305
6306 im_is_active = FALSE;
6307 DeactivateTSMDocument(gTSMDocument);
6308 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309}
6310
6311/*
6312 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6313 */
6314 void
6315im_set_active(int active)
6316{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006317 ScriptLanguageRecord *slptr = NULL;
6318 OSStatus err;
6319
6320 if (! gui.in_use)
6321 return;
6322
6323 if (im_initialized == 0)
6324 {
6325 im_initialized = 1;
6326
6327 /* save default TSM component (should be U.S.) to default */
6328 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6329 kKeyboardInputMethodClass);
6330 }
6331
6332 if (active == TRUE)
6333 {
6334 im_is_active = TRUE;
6335 ActivateTSMDocument(gTSMDocument);
6336 slptr = &gTSLInsert;
6337
6338 if (slptr)
6339 {
6340 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6341 kKeyboardInputMethodClass);
6342 if (err == noErr)
6343 err = SetTextServiceLanguage(slptr);
6344
6345 if (err == noErr)
6346 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6347 }
6348 }
6349 else
6350 {
6351 err = GetTextServiceLanguage(&gTSLInsert);
6352 if (err == noErr)
6353 slptr = &gTSLInsert;
6354
6355 if (slptr)
6356 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6357 kKeyboardInputMethodClass);
6358
6359 /* restore to default when switch to normal mode, so than we could
6360 * enter commands easier */
6361 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6362 kKeyboardInputMethodClass);
6363 SetTextServiceLanguage(&gTSLDefault);
6364
6365 im_is_active = FALSE;
6366 DeactivateTSMDocument(gTSMDocument);
6367 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006368}
6369
6370/*
6371 * Get IM status. When IM is on, return not 0. Else return 0.
6372 */
6373 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006374im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006375{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006376 if (! gui.in_use)
6377 return 0;
6378
6379 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006380}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006381
Bram Moolenaar071d4272004-06-13 20:20:40 +00006382#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006383
6384
6385
6386
6387#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6388// drawer implementation
6389static MenuRef contextMenu = NULL;
6390enum
6391{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006392 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006393};
6394
6395// the caller has to CFRelease() the returned string
6396 static CFStringRef
6397getTabLabel(tabpage_T *page)
6398{
6399 get_tabline_label(page, FALSE);
6400#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006401 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006402#else
6403 // TODO: check internal encoding?
6404 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6405 kCFStringEncodingMacRoman);
6406#endif
6407}
6408
6409
6410#define DRAWER_SIZE 150
6411#define DRAWER_INSET 16
6412
6413static ControlRef dataBrowser = NULL;
6414
6415// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006416// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006417// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006418// for a very short time. to prevent inconsistent state, we store the labels
6419// of the tabs, not pointers to the tabs (which are invalid for a short time).
6420static CFStringRef *tabLabels = NULL;
6421static int tabLabelsSize = 0;
6422
6423enum
6424{
6425 kTabsColumn = 'Tabs'
6426};
6427
6428 static int
6429getTabCount(void)
6430{
6431 tabpage_T *tp;
6432 int numTabs = 0;
6433
Bram Moolenaar29323592016-07-24 22:04:11 +02006434 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006435 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006436 return numTabs;
6437}
6438
6439// data browser item display callback
6440 static OSStatus
6441dbItemDataCallback(ControlRef browser,
6442 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006443 DataBrowserPropertyID property /* column id */,
6444 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006445 Boolean changeValue)
6446{
6447 OSStatus status = noErr;
6448
6449 // assert(property == kTabsColumn); // why is this violated??
6450
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006451 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006452 // In our case, it's always false.
6453 // (that is: if (changeValue) updateInternalData(); else return
6454 // internalData();
6455 if (!changeValue)
6456 {
6457 CFStringRef str;
6458
6459 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6460 str = tabLabels[itemID - 1];
6461 status = SetDataBrowserItemDataText(itemData, str);
6462 }
6463 else
6464 status = errDataBrowserPropertyNotSupported;
6465
6466 return status;
6467}
6468
6469// data browser action callback
6470 static void
6471dbItemNotificationCallback(ControlRef browser,
6472 DataBrowserItemID item,
6473 DataBrowserItemNotification message)
6474{
6475 switch (message)
6476 {
6477 case kDataBrowserItemSelected:
6478 send_tabline_event(item);
6479 break;
6480 }
6481}
6482
6483// callbacks needed for contextual menu:
6484 static void
6485dbGetContextualMenuCallback(ControlRef browser,
6486 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006487 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006488 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006489 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006490{
6491 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6492 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6493 *helpItemString = NULL;
6494
6495 *menu = contextMenu;
6496}
6497
6498 static void
6499dbSelectContextualMenuCallback(ControlRef browser,
6500 MenuRef menu,
6501 UInt32 selectionType,
6502 SInt16 menuID,
6503 MenuItemIndex menuItem)
6504{
6505 if (selectionType == kCMMenuItemSelected)
6506 {
6507 MenuCommand command;
6508 GetMenuItemCommandID(menu, menuItem, &command);
6509
6510 // get tab that was selected when the context menu appeared
6511 // (there is always one tab selected). TODO: check if the context menu
6512 // isn't opened on an item but on empty space (has to be possible some
6513 // way, the finder does it too ;-) )
6514 Handle items = NewHandle(0);
6515 if (items != NULL)
6516 {
6517 int numItems;
6518
6519 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6520 kDataBrowserItemIsSelected, items);
6521 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6522 if (numItems > 0)
6523 {
6524 int idx;
6525 DataBrowserItemID *itemsPtr;
6526
6527 HLock(items);
6528 itemsPtr = (DataBrowserItemID *)*items;
6529 idx = itemsPtr[0];
6530 HUnlock(items);
6531 send_tabline_menu_event(idx, command);
6532 }
6533 DisposeHandle(items);
6534 }
6535 }
6536}
6537
6538// focus callback of the data browser to always leave focus in vim
6539 static OSStatus
6540dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6541{
6542 assert(GetEventClass(event) == kEventClassControl
6543 && GetEventKind(event) == kEventControlSetFocusPart);
6544
6545 return paramErr;
6546}
6547
6548
6549// drawer callback to resize data browser to drawer size
6550 static OSStatus
6551drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6552{
6553 switch (GetEventKind(event))
6554 {
6555 case kEventWindowBoundsChanged: // move or resize
6556 {
6557 UInt32 attribs;
6558 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6559 NULL, sizeof(attribs), NULL, &attribs);
6560 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6561 {
6562 Rect r;
6563 GetWindowBounds(drawer, kWindowContentRgn, &r);
6564 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6565 SetControlBounds(dataBrowser, &r);
6566 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6567 kTabsColumn, r.right);
6568 }
6569 }
6570 break;
6571 }
6572
6573 return eventNotHandledErr;
6574}
6575
6576// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6577// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6578// blue highlights in the list view on these systems, though. Oh well.)
6579
6580
6581#import <mach-o/dyld.h>
6582
6583enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6584
6585 static OSStatus
6586myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6587 OptionBits inAttributesToSet,
6588 OptionBits inAttributesToClear)
6589{
6590 long osVersion;
6591 char *symbolName;
6592 NSSymbol symbol = NULL;
6593 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6594 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6595
6596 Gestalt(gestaltSystemVersion, &osVersion);
6597 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6598 return noErr;
6599
6600 // C name mangling...
6601 symbolName = "_DataBrowserChangeAttributes";
6602 if (!NSIsSymbolNameDefined(symbolName)
6603 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6604 return noErr;
6605
6606 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6607 if (dataBrowserChangeAttributes == NULL)
6608 return noErr; // well...
6609 return dataBrowserChangeAttributes(inDataBrowser,
6610 inAttributesToSet, inAttributesToClear);
6611}
6612
6613 static void
6614initialise_tabline(void)
6615{
6616 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6617 DataBrowserCallbacks dbCallbacks;
6618 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6619 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6620 DataBrowserListViewColumnDesc colDesc;
6621
6622 // drawers have to have compositing enabled
6623 CreateNewWindow(kDrawerWindowClass,
6624 kWindowStandardHandlerAttribute
6625 | kWindowCompositingAttribute
6626 | kWindowResizableAttribute
6627 | kWindowLiveResizeAttribute,
6628 &drawerRect, &drawer);
6629
6630 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6631 SetDrawerParent(drawer, gui.VimWindow);
6632 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6633
6634
6635 // create list view embedded in drawer
6636 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6637 &dataBrowser);
6638
6639 dbCallbacks.version = kDataBrowserLatestCallbacks;
6640 InitDataBrowserCallbacks(&dbCallbacks);
6641 dbCallbacks.u.v1.itemDataCallback =
6642 NewDataBrowserItemDataUPP(dbItemDataCallback);
6643 dbCallbacks.u.v1.itemNotificationCallback =
6644 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6645 dbCallbacks.u.v1.getContextualMenuCallback =
6646 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6647 dbCallbacks.u.v1.selectContextualMenuCallback =
6648 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6649
6650 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6651
6652 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6653 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6654 SetDataBrowserSelectionFlags(dataBrowser,
6655 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6656 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6657 kDataBrowserTableViewFillHilite);
6658 Boolean b = false;
6659 SetControlData(dataBrowser, kControlEntireControl,
6660 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6661
6662 // enable blue background in data browser (this is only in 10.4 and vim
6663 // has to support older osx versions as well, so we have to load this
6664 // function dynamically)
6665 myDataBrowserChangeAttributes(dataBrowser,
6666 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6667
6668 // install callback that keeps focus in vim and away from the data browser
6669 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6670 NULL, NULL);
6671
6672 // install callback that keeps data browser at the size of the drawer
6673 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6674 NULL, NULL);
6675
6676 // add "tabs" column to data browser
6677 colDesc.propertyDesc.propertyID = kTabsColumn;
6678 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6679
6680 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6681 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6682
6683 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6684 colDesc.headerBtnDesc.minimumWidth = 100;
6685 colDesc.headerBtnDesc.maximumWidth = 150;
6686 colDesc.headerBtnDesc.titleOffset = 0;
6687 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6688 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6689 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6690 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6691
6692 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6693
6694 // create tabline popup menu required by vim docs (see :he tabline-menu)
6695 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar7098ee52015-06-09 19:14:24 +02006696 if (first_tabpage->tp_next != NULL)
6697 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006698 TABLINE_MENU_CLOSE, NULL);
6699 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6700 TABLINE_MENU_NEW, NULL);
6701 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6702 TABLINE_MENU_OPEN, NULL);
6703}
6704
6705
6706/*
6707 * Show or hide the tabline.
6708 */
6709 void
6710gui_mch_show_tabline(int showit)
6711{
6712 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006713 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006714 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006715 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006716}
6717
6718/*
6719 * Return TRUE when tabline is displayed.
6720 */
6721 int
6722gui_mch_showing_tabline(void)
6723{
6724 WindowDrawerState state = GetDrawerState(drawer);
6725
6726 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6727}
6728
6729/*
6730 * Update the labels of the tabline.
6731 */
6732 void
6733gui_mch_update_tabline(void)
6734{
6735 tabpage_T *tp;
6736 int numTabs = getTabCount();
6737 int nr = 1;
6738 int curtabidx = 1;
6739
6740 // adjust data browser
6741 if (tabLabels != NULL)
6742 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006743 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006744
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006745 for (i = 0; i < tabLabelsSize; ++i)
6746 CFRelease(tabLabels[i]);
6747 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006748 }
6749 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6750 tabLabelsSize = numTabs;
6751
6752 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6753 {
6754 if (tp == curtab)
6755 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006756 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006757 }
6758
6759 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6760 kDataBrowserItemNoProperty);
6761 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6762 // can pass NULL for the id array
6763 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6764 kDataBrowserItemNoProperty);
6765
6766 DataBrowserItemID item = curtabidx;
6767 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6768}
6769
6770/*
6771 * Set the current tab to "nr". First tab is 1.
6772 */
6773 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006774gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006775{
6776 DataBrowserItemID item = nr;
6777 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6778
6779 // TODO: call something like this?: (or restore scroll position, or...)
6780 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6781 kDataBrowserRevealOnly);
6782}
6783
6784#endif // FEAT_GUI_TABLINE