blob: 232b6f2beb7b2614fe0b1f8304d58cd0bd98c74a [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 Moolenaar13505972019-01-24 15:04:48 +010051#define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000052
Bram Moolenaar071d4272004-06-13 20:20:40 +000053static EventHandlerUPP mouseWheelHandlerUPP = NULL;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000054SInt32 gMacSystemVersion;
Bram Moolenaar071d4272004-06-13 20:20:40 +000055
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000056#ifdef MACOS_CONVERT
57# define USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +000058
59static int im_is_active = FALSE;
Bram Moolenaar259f26a2018-05-15 22:25:40 +020060# if 0
Bram Moolenaared39e1d2008-08-09 17:55:22 +000061 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +000062static int im_start_row = 0;
63static int im_start_col = 0;
Bram Moolenaar259f26a2018-05-15 22:25:40 +020064# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +000065
Bram Moolenaar259f26a2018-05-15 22:25:40 +020066# define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
Bram Moolenaar1b60e502008-03-12 13:40:54 +000067
68static TSMDocumentID gTSMDocument;
69
70static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000071static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000072static EventHandlerUPP winEventHandlerUPP = NULL;
73
74static pascal OSStatus gui_mac_handle_window_activate(
75 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
76
77static pascal OSStatus gui_mac_handle_text_input(
78 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
79
80static pascal OSStatus gui_mac_update_input_area(
81 EventHandlerCallRef nextHandler, EventRef theEvent);
82
83static pascal OSStatus gui_mac_unicode_key_event(
84 EventHandlerCallRef nextHandler, EventRef theEvent);
85
Bram Moolenaar26a60b42005-02-22 08:49:11 +000086#endif
87
Bram Moolenaar071d4272004-06-13 20:20:40 +000088
89/* Include some file. TODO: move into os_mac.h */
90#include <Menus.h>
91#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000092#include <Processes.h>
93#ifdef USE_AEVENT
94# include <AppleEvents.h>
95# include <AERegistry.h>
96#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000097# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000098#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
99# include <ControlDefinitions.h>
100# include <Navigation.h> /* Navigation only part of ?? */
101#endif
102
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000103/* Help Manager (balloon.h, HM prefixed functions) are not supported
104 * under Carbon (Jussi) */
105# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000107# include <MacHelp.h>
108# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000111 * These seem to be rectangle options. Why are they not found in
112 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114#define kNothing 0
115#define kCreateEmpty 2 /*1*/
116#define kCreateRect 2
117#define kDestroy 3
118
119/*
120 * Dany: Don't like those...
121 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122#define topLeft(r) (((Point*)&(r))[0])
123#define botRight(r) (((Point*)&(r))[1])
124
125
126/* Time of last mouse click, to detect double-click */
127static long lastMouseTick = 0;
128
129/* ??? */
130static RgnHandle cursorRgn;
131static RgnHandle dragRgn;
132static Rect dragRect;
133static short dragRectEnbl;
134static short dragRectControl;
135
136/* This variable is set when waiting for an event, which is the only moment
137 * scrollbar dragging can be done directly. It's not allowed while commands
138 * are executed, because it may move the cursor and that may cause unexpected
139 * problems (e.g., while ":s" is working).
140 */
141static int allow_scrollbar = FALSE;
142
143/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145
146/* Feedback Action for Scrollbar */
147ControlActionUPP gScrollAction;
148ControlActionUPP gScrollDrag;
149
150/* Keeping track of which scrollbar is being dragged */
151static ControlHandle dragged_sb = NULL;
152
Bram Moolenaarc52da9d2008-03-20 13:39:37 +0000153/* Vector of char_u --> control index for hotkeys in dialogs */
154static short *gDialogHotKeys;
155
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000156static struct
157{
158 FMFontFamily family;
159 FMFontSize size;
160 FMFontStyle style;
161 Boolean isPanelVisible;
162} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000163
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000164#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000165# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000166int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000167ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000168ATSUStyle gWideFontStyle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000169Boolean gIsFontFallbackSet;
Bram Moolenaar76b96fc2010-07-17 16:44:59 +0200170UInt32 useAntialias_cached = 0x0;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000171#endif
172
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173/* Colors Macros */
174#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
175#define Red(c) ((c & 0x00FF0000) >> 16)
176#define Green(c) ((c & 0x0000FF00) >> 8)
177#define Blue(c) ((c & 0x000000FF) >> 0)
178
179/* Key mapping */
180
181#define vk_Esc 0x35 /* -> 1B */
182
183#define vk_F1 0x7A /* -> 10 */
184#define vk_F2 0x78 /*0x63*/
185#define vk_F3 0x63 /*0x76*/
186#define vk_F4 0x76 /*0x60*/
187#define vk_F5 0x60 /*0x61*/
188#define vk_F6 0x61 /*0x62*/
189#define vk_F7 0x62 /*0x63*/ /*?*/
190#define vk_F8 0x64
191#define vk_F9 0x65
192#define vk_F10 0x6D
193#define vk_F11 0x67
194#define vk_F12 0x6F
195#define vk_F13 0x69
196#define vk_F14 0x6B
197#define vk_F15 0x71
198
199#define vk_Clr 0x47 /* -> 1B (ESC) */
200#define vk_Enter 0x4C /* -> 03 */
201
202#define vk_Space 0x31 /* -> 20 */
203#define vk_Tab 0x30 /* -> 09 */
204#define vk_Return 0x24 /* -> 0D */
205/* This is wrong for OSX, what is it for? */
206#define vk_Delete 0X08 /* -> 08 BackSpace */
207
208#define vk_Help 0x72 /* -> 05 */
209#define vk_Home 0x73 /* -> 01 */
210#define vk_PageUp 0x74 /* -> 0D */
211#define vk_FwdDelete 0x75 /* -> 7F */
212#define vk_End 0x77 /* -> 04 */
213#define vk_PageDown 0x79 /* -> 0C */
214
215#define vk_Up 0x7E /* -> 1E */
216#define vk_Down 0x7D /* -> 1F */
217#define vk_Left 0x7B /* -> 1C */
218#define vk_Right 0x7C /* -> 1D */
219
220#define vk_Undo vk_F1
221#define vk_Cut vk_F2
222#define vk_Copy vk_F3
223#define vk_Paste vk_F4
224#define vk_PrintScreen vk_F13
225#define vk_SCrollLock vk_F14
226#define vk_Pause vk_F15
227#define vk_NumLock vk_Clr
228#define vk_Insert vk_Help
229
230#define KeySym char
231
232static struct
233{
234 KeySym key_sym;
235 char_u vim_code0;
236 char_u vim_code1;
237} special_keys[] =
238{
239 {vk_Up, 'k', 'u'},
240 {vk_Down, 'k', 'd'},
241 {vk_Left, 'k', 'l'},
242 {vk_Right, 'k', 'r'},
243
244 {vk_F1, 'k', '1'},
245 {vk_F2, 'k', '2'},
246 {vk_F3, 'k', '3'},
247 {vk_F4, 'k', '4'},
248 {vk_F5, 'k', '5'},
249 {vk_F6, 'k', '6'},
250 {vk_F7, 'k', '7'},
251 {vk_F8, 'k', '8'},
252 {vk_F9, 'k', '9'},
253 {vk_F10, 'k', ';'},
254
255 {vk_F11, 'F', '1'},
256 {vk_F12, 'F', '2'},
257 {vk_F13, 'F', '3'},
258 {vk_F14, 'F', '4'},
259 {vk_F15, 'F', '5'},
260
261/* {XK_Help, '%', '1'}, */
262/* {XK_Undo, '&', '8'}, */
263/* {XK_BackSpace, 'k', 'b'}, */
Bram Moolenaard0573012017-10-28 21:11:06 +0200264/* {vk_Delete, 'k', 'b'}, */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 {vk_Insert, 'k', 'I'},
266 {vk_FwdDelete, 'k', 'D'},
267 {vk_Home, 'k', 'h'},
268 {vk_End, '@', '7'},
269/* {XK_Prior, 'k', 'P'}, */
270/* {XK_Next, 'k', 'N'}, */
271/* {XK_Print, '%', '9'}, */
272
273 {vk_PageUp, 'k', 'P'},
274 {vk_PageDown, 'k', 'N'},
275
276 /* End of list marker: */
277 {(KeySym)0, 0, 0}
278};
279
280/*
281 * ------------------------------------------------------------
282 * Forward declaration (for those needed)
283 * ------------------------------------------------------------
284 */
285
286#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000287OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288#endif
289
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000290#ifdef FEAT_GUI_TABLINE
291static void initialise_tabline(void);
292static WindowRef drawer = NULL; // TODO: put into gui.h
293#endif
294
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000295#ifdef USE_ATSUI_DRAWING
296static void gui_mac_set_font_attributes(GuiFont font);
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000297#endif
298
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299/*
300 * ------------------------------------------------------------
301 * Conversion Utility
302 * ------------------------------------------------------------
303 */
304
305/*
306 * C2Pascal_save
307 *
308 * Allocate memory and convert the C-String passed in
309 * into a pascal string
310 *
311 */
312
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000313 char_u *
314C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000315{
316 char_u *PascalString;
317 int len;
318
319 if (Cstring == NULL)
320 return NULL;
321
322 len = STRLEN(Cstring);
323
324 if (len > 255) /* Truncate if necessary */
325 len = 255;
326
327 PascalString = alloc(len + 1);
328 if (PascalString != NULL)
329 {
330 mch_memmove(PascalString + 1, Cstring, len);
331 PascalString[0] = len;
332 }
333
334 return PascalString;
335}
336
337/*
338 * C2Pascal_save_and_remove_backslash
339 *
340 * Allocate memory and convert the C-String passed in
341 * into a pascal string. Also remove the backslash at the same time
342 *
343 */
344
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000345 char_u *
346C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347{
348 char_u *PascalString;
349 int len;
350 char_u *p, *c;
351
352 len = STRLEN(Cstring);
353
354 if (len > 255) /* Truncate if necessary */
355 len = 255;
356
357 PascalString = alloc(len + 1);
358 if (PascalString != NULL)
359 {
360 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
361 {
362 if ((*c == '\\') && (c[1] != 0))
363 {
364 c++;
365 }
366 *p = *c;
367 p++;
368 len++;
369 }
370 PascalString[0] = len;
371 }
372
373 return PascalString;
374}
375
376/*
377 * Convert the modifiers of an Event into vim's modifiers (mouse)
378 */
379
380 int_u
381EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
382{
383 int_u vimModifiers = 0x00;
384
385 if (macModifiers & (shiftKey | rightShiftKey))
386 vimModifiers |= MOUSE_SHIFT;
387 if (macModifiers & (controlKey | rightControlKey))
388 vimModifiers |= MOUSE_CTRL;
389 if (macModifiers & (optionKey | rightOptionKey))
390 vimModifiers |= MOUSE_ALT;
391#if 0
392 /* Not yet supported */
393 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
394 vimModifiers |= MOUSE_CMD;
395#endif
396 return (vimModifiers);
397}
398
399/*
400 * Convert the modifiers of an Event into vim's modifiers (keys)
401 */
402
403 static int_u
404EventModifiers2VimModifiers(EventModifiers macModifiers)
405{
406 int_u vimModifiers = 0x00;
407
408 if (macModifiers & (shiftKey | rightShiftKey))
409 vimModifiers |= MOD_MASK_SHIFT;
410 if (macModifiers & (controlKey | rightControlKey))
411 vimModifiers |= MOD_MASK_CTRL;
412 if (macModifiers & (optionKey | rightOptionKey))
413 vimModifiers |= MOD_MASK_ALT;
414#ifdef USE_CMD_KEY
415 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
416 vimModifiers |= MOD_MASK_CMD;
417#endif
418 return (vimModifiers);
419}
420
421/* Convert a string representing a point size into pixels. The string should
422 * be a positive decimal number, with an optional decimal point (eg, "12", or
423 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
424 * character is stored in *end. The flag "vertical" says whether this
425 * calculation is for a vertical (height) size or a horizontal (width) one.
426 *
427 * From gui_w48.c
428 */
429 static int
430points_to_pixels(char_u *str, char_u **end, int vertical)
431{
432 int pixels;
433 int points = 0;
434 int divisor = 0;
435
436 while (*str)
437 {
438 if (*str == '.' && divisor == 0)
439 {
440 /* Start keeping a divisor, for later */
441 divisor = 1;
442 continue;
443 }
444
445 if (!isdigit(*str))
446 break;
447
448 points *= 10;
449 points += *str - '0';
450 divisor *= 10;
451
452 ++str;
453 }
454
455 if (divisor == 0)
456 divisor = 1;
457
458 pixels = points/divisor;
459 *end = str;
460 return pixels;
461}
462
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000463#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000464/*
465 * Deletes all traces of any Windows-style mnemonic text (including any
466 * parentheses) from a menu item and returns the cleaned menu item title.
467 * The caller is responsible for releasing the returned string.
468 */
469 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000470menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000471{
472 CFStringRef name;
473 size_t menuTitleLen;
474 CFIndex displayLen;
475 CFRange mnemonicStart;
476 CFRange mnemonicEnd;
477 CFMutableStringRef cleanedName;
478
479 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000480 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000481
482 if (name)
483 {
484 /* Simple mnemonic-removal algorithm, assumes single parenthesized
485 * mnemonic character towards the end of the menu text */
486 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
487 displayLen = CFStringGetLength(name);
488
489 if (mnemonicStart.location != kCFNotFound
490 && (mnemonicStart.location + 2) < displayLen
491 && CFStringGetCharacterAtIndex(name,
492 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
493 {
494 if (CFStringFindWithOptions(name, CFSTR(")"),
495 CFRangeMake(mnemonicStart.location + 1,
496 displayLen - mnemonicStart.location - 1),
497 kCFCompareBackwards, &mnemonicEnd) &&
498 (mnemonicStart.location + 2) == mnemonicEnd.location)
499 {
500 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
501 if (cleanedName)
502 {
503 CFStringDelete(cleanedName,
504 CFRangeMake(mnemonicStart.location,
505 mnemonicEnd.location + 1 -
506 mnemonicStart.location));
507
508 CFRelease(name);
509 name = cleanedName;
510 }
511 }
512 }
513 }
514
515 return name;
516}
517#endif
518
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519/*
520 * Convert a list of FSSpec aliases into a list of fullpathname
521 * character strings.
522 */
523
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000524 char_u **
525new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526{
527 char_u **fnames = NULL;
528 OSErr newError;
529 long fileCount;
530 FSSpec fileToOpen;
531 long actualSize;
532 AEKeyword dummyKeyword;
533 DescType dummyType;
534
535 /* Get number of files in list */
536 *error = AECountItems(theList, numFiles);
537 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000538 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539
540 /* Allocate the pointer list */
541 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
542
543 /* Empty out the list */
544 for (fileCount = 0; fileCount < *numFiles; fileCount++)
545 fnames[fileCount] = NULL;
546
547 /* Scan the list of FSSpec */
548 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
549 {
550 /* Get the alias for the nth file, convert to an FSSpec */
551 newError = AEGetNthPtr(theList, fileCount, typeFSS,
552 &dummyKeyword, &dummyType,
553 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
554 if (newError)
555 {
556 /* Caller is able to clean up */
557 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000558 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 }
560
561 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000562 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 }
564
565 return (fnames);
566}
567
568/*
569 * ------------------------------------------------------------
570 * CodeWarrior External Editor Support
571 * ------------------------------------------------------------
572 */
573#ifdef FEAT_CW_EDITOR
574
575/*
576 * Handle the Window Search event from CodeWarrior
577 *
578 * Description
579 * -----------
580 *
581 * The IDE sends the Window Search AppleEvent to the editor when it
582 * needs to know whether a particular file is open in the editor.
583 *
584 * Event Reply
585 * -----------
586 *
587 * None. Put data in the location specified in the structure received.
588 *
589 * Remarks
590 * -------
591 *
592 * When the editor receives this event, determine whether the specified
593 * file is open. If it is, return the modification date/time for that file
594 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000595 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 *
597 */
598
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599typedef struct WindowSearch WindowSearch;
600struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
601{
602 FSSpec theFile; // identifies the file
603 long *theDate; // where to put the modification date/time
604};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000606 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000607Handle_KAHL_SRCH_AE(
608 const AppleEvent *theAEvent,
609 AppleEvent *theReply,
610 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611{
612 OSErr error = noErr;
613 buf_T *buf;
614 int foundFile = false;
615 DescType typeCode;
616 WindowSearch SearchData;
617 Size actualSize;
618
619 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
620 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000621 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000623 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000625 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626
Bram Moolenaar29323592016-07-24 22:04:11 +0200627 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 if (buf->b_ml.ml_mfp != NULL
629 && SearchData.theFile.parID == buf->b_FSSpec.parID
630 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
631 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
632 {
633 foundFile = true;
634 break;
635 }
636
637 if (foundFile == false)
638 *SearchData.theDate = fnfErr;
639 else
640 *SearchData.theDate = buf->b_mtime;
641
Bram Moolenaar071d4272004-06-13 20:20:40 +0000642 return error;
643};
644
645/*
646 * Handle the Modified (from IDE to Editor) event from CodeWarrior
647 *
648 * Description
649 * -----------
650 *
651 * The IDE sends this event to the external editor when it wants to
652 * know which files that are open in the editor have been modified.
653 *
654 * Parameters None.
655 * ----------
656 *
657 * Event Reply
658 * -----------
659 * The reply for this event is:
660 *
661 * keyDirectObject typeAEList required
662 * each element in the list is a structure of typeChar
663 *
664 * Remarks
665 * -------
666 *
667 * When building the reply event, include one element in the list for
668 * each open file that has been modified.
669 *
670 */
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672typedef struct ModificationInfo ModificationInfo;
673struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
674{
675 FSSpec theFile; // identifies the file
676 long theDate; // the date/time the file was last modified
677 short saved; // set this to zero when replying, unused
678};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000680 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000681Handle_KAHL_MOD_AE(
682 const AppleEvent *theAEvent,
683 AppleEvent *theReply,
684 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685{
686 OSErr error = noErr;
687 AEDescList replyList;
688 long numFiles;
689 ModificationInfo theFile;
690 buf_T *buf;
691
692 theFile.saved = 0;
693
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000694 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000696 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697
698 /* Send the reply */
699/* replyObject.descriptorType = typeNull;
700 replyObject.dataHandle = nil;*/
701
702/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
703 error = AECreateList(nil, 0, false, &replyList);
704 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000705 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706
707#if 0
708 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000710 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
711 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712 * sizeof(DescType))
713 */
714
715 /* AEPutDesc */
716#endif
717
718 numFiles = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +0200719 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 if (buf->b_ml.ml_mfp != NULL)
721 {
722 /* Add this file to the list */
723 theFile.theFile = buf->b_FSSpec;
724 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000725/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
726 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 };
728
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729#if 0
730 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731#endif
732
733 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000734 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 if (replyList.dataHandle)
737 AEDisposeDesc(&replyList);
738
739 return error;
740};
741
742/*
743 * Handle the Get Text event from CodeWarrior
744 *
745 * Description
746 * -----------
747 *
748 * The IDE sends the Get Text AppleEvent to the editor when it needs
749 * the source code from a file. For example, when the user issues a
750 * Check Syntax or Compile command, the compiler needs access to
751 * the source code contained in the file.
752 *
753 * Event Reply
754 * -----------
755 *
756 * None. Put data in locations specified in the structure received.
757 *
758 * Remarks
759 * -------
760 *
761 * When the editor receives this event, it must set the size of the handle
762 * in theText to fit the data in the file. It must then copy the entire
763 * contents of the specified file into the memory location specified in
764 * theText.
765 *
766 */
767
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768typedef struct CW_GetText CW_GetText;
769struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
770{
771 FSSpec theFile; /* identifies the file */
772 Handle theText; /* the location where you return the text (must be resized properly) */
773 long *unused; /* 0 (not used) */
774 long *theDate; /* where to put the modification date/time */
775};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000777 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000778Handle_KAHL_GTTX_AE(
779 const AppleEvent *theAEvent,
780 AppleEvent *theReply,
781 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782{
783 OSErr error = noErr;
784 buf_T *buf;
785 int foundFile = false;
786 DescType typeCode;
787 CW_GetText GetTextData;
788 Size actualSize;
789 char_u *line;
790 char_u *fullbuffer = NULL;
791 long linesize;
792 long lineStart;
793 long BufferSize;
794 long lineno;
795
796 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
797
798 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000799 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800
Bram Moolenaar29323592016-07-24 22:04:11 +0200801 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 if (buf->b_ml.ml_mfp != NULL)
803 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
804 {
805 foundFile = true;
806 break;
807 }
808
809 if (foundFile)
810 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000811 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
813 {
814 /* Must use the right buffer */
815 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
816 linesize = STRLEN(line) + 1;
817 lineStart = BufferSize;
818 BufferSize += linesize;
819 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000820 SetHandleSize(GetTextData.theText, BufferSize);
821 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000823 break; /* Simple handling for now */
824 }
825 else
826 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000827 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000829 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000831 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 }
833 }
834 if (fullbuffer != NULL)
835 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 }
840 if (foundFile == false)
841 *GetTextData.theDate = fnfErr;
842 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000843/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 *GetTextData.theDate = buf->b_mtime;
845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000847 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000849 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850}
851
852/*
853 *
854 */
855
856/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000857 pascal OSErr
858FindProcessBySignature(
859 const OSType targetType,
860 const OSType targetCreator,
861 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862{
863 OSErr anErr = noErr;
864 Boolean lookingForProcess = true;
865
866 ProcessInfoRec infoRec;
867
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000868 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 infoRec.processName = nil;
870 infoRec.processAppSpec = nil;
871
872 psnPtr->lowLongOfPSN = kNoProcess;
873 psnPtr->highLongOfPSN = kNoProcess;
874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000877 anErr = GetNextProcess(psnPtr);
878 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 else
881 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000882 anErr = GetProcessInformation(psnPtr, &infoRec);
883 if ((anErr == noErr)
884 && (infoRec.processType == targetType)
885 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 }
888 }
889
890 return anErr;
891}//end FindProcessBySignature
892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000893 void
894Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000896 OSErr anErr = noErr;
897 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
899 AppleEvent theReply = { typeNull, nil };
900 AESendMode sendMode;
901 AppleEvent theEvent = {typeNull, nil };
902 AEIdleUPP idleProcUPP = nil;
903 ModificationInfo ModData;
904
905
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000906 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000907 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000909 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
910 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000912 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000913 {
914 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
915 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
916 }
917
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000918 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919
920 /* Add the parms */
921 ModData.theFile = buf->b_FSSpec;
922 ModData.theDate = buf->b_mtime;
923
924 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000925 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000927 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 sendMode = kAENoReply;
929 else
930 sendMode = kAEWaitReply;
931
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000932 if (anErr == noErr)
933 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
934 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000936/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000938 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000939 }
940}
941#endif /* FEAT_CW_EDITOR */
942
943/*
944 * ------------------------------------------------------------
945 * Apple Event Handling procedure
946 * ------------------------------------------------------------
947 */
948#ifdef USE_AEVENT
949
950/*
951 * Handle the Unused parms of an AppleEvent
952 */
953
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000954 OSErr
955HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956{
957 OSErr error;
958 long actualSize;
959 DescType dummyType;
960 AEKeyword missedKeyword;
961
962 /* Get the "missed keyword" attribute from the AppleEvent. */
963 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
964 typeKeyword, &dummyType,
965 (Ptr)&missedKeyword, sizeof(missedKeyword),
966 &actualSize);
967
968 /* If the descriptor isn't found, then we got the required parameters. */
969 if (error == errAEDescNotFound)
970 {
971 error = noErr;
972 }
973 else
974 {
975#if 0
976 /* Why is this removed? */
977 error = errAEEventNotHandled;
978#endif
979 }
980
981 return error;
982}
983
984
985/*
986 * Handle the ODoc AppleEvent
987 *
988 * Deals with all files dragged to the application icon.
989 *
990 */
991
Bram Moolenaar071d4272004-06-13 20:20:40 +0000992typedef struct SelectionRange SelectionRange;
993struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
994{
995 short unused1; // 0 (not used)
996 short lineNum; // line to select (<0 to specify range)
997 long startRange; // start of selection range (if line < 0)
998 long endRange; // end of selection range (if line < 0)
999 long unused2; // 0 (not used)
1000 long theDate; // modification date/time
1001};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001002
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001003static long drop_numFiles;
1004static short drop_gotPosition;
1005static SelectionRange drop_thePosition;
1006
1007 static void
1008drop_callback(void *cookie UNUSED)
1009{
1010 /* TODO: Handle the goto/select line more cleanly */
1011 if ((drop_numFiles == 1) & (drop_gotPosition))
1012 {
1013 if (drop_thePosition.lineNum >= 0)
1014 {
1015 lnum = drop_thePosition.lineNum + 1;
1016 /* oap->motion_type = MLINE;
1017 setpcmark();*/
1018 if (lnum < 1L)
1019 lnum = 1L;
1020 else if (lnum > curbuf->b_ml.ml_line_count)
1021 lnum = curbuf->b_ml.ml_line_count;
1022 curwin->w_cursor.lnum = lnum;
1023 curwin->w_cursor.col = 0;
1024 /* beginline(BL_SOL | BL_FIX);*/
1025 }
1026 else
1027 goto_byte(drop_thePosition.startRange + 1);
1028 }
1029
1030 /* Update the screen display */
1031 update_screen(NOT_VALID);
1032
1033 /* Select the text if possible */
1034 if (drop_gotPosition)
1035 {
1036 VIsual_active = TRUE;
1037 VIsual_select = FALSE;
1038 VIsual = curwin->w_cursor;
1039 if (drop_thePosition.lineNum < 0)
1040 {
1041 VIsual_mode = 'v';
1042 goto_byte(drop_thePosition.endRange);
1043 }
1044 else
1045 {
1046 VIsual_mode = 'V';
1047 VIsual.col = 0;
1048 }
1049 }
1050}
1051
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1053 itor the selection range. If lineNum is zero or greater, scroll the text
1054 to the specified line. If lineNum is less than zero, use the values in
1055 startRange and endRange to select the specified characters. Scroll
1056 the text to display the selection. If lineNum, startRange, and
1057 endRange are all negative, there is no selection range specified.
1058 */
1059
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001060 pascal OSErr
1061HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062{
1063 /*
1064 * TODO: Clean up the code with convert the AppleEvent into
1065 * a ":args"
1066 */
1067 OSErr error = noErr;
1068// OSErr firstError = noErr;
1069// short numErrors = 0;
1070 AEDesc theList;
1071 DescType typeCode;
1072 long numFiles;
1073 // long fileCount;
1074 char_u **fnames;
1075// char_u fname[256];
1076 Size actualSize;
1077 SelectionRange thePosition;
1078 short gotPosition = false;
1079 long lnum;
1080
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 /* the direct object parameter is the list of aliases to files (one or more) */
1082 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1083 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001084 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085
1086
1087 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1088 if (error == noErr)
1089 gotPosition = true;
1090 if (error == errAEDescNotFound)
1091 error = noErr;
1092 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001093 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095/*
1096 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1097
1098 if (^error) then
1099 {
1100 if (thePosition.lineNum >= 0)
1101 {
1102 // Goto this line
1103 }
1104 else
1105 {
1106 // Set the range char wise
1107 }
1108 }
1109 */
1110
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1113
1114 if (error)
1115 {
1116 /* TODO: empty fnames[] first */
1117 vim_free(fnames);
1118 return (error);
1119 }
1120
1121 if (starting > 0)
1122 {
1123 int i;
1124 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001125 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126
1127 /* these are the initial files dropped on the Vim icon */
1128 for (i = 0 ; i < numFiles; i++)
1129 {
1130 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1131 || (p = vim_strsave(fnames[i])) == NULL)
1132 mch_exit(2);
1133 else
1134 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001135 if (fnum == -1)
1136 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1137 }
1138
1139 /* If the file name was already in the buffer list we need to switch
1140 * to it. */
1141 if (curbuf->b_fnum != fnum)
1142 {
1143 char_u cmd[30];
1144
1145 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1146 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001148
1149 /* Change directory to the location of the first file. */
Bram Moolenaarb7407d32018-02-03 17:36:27 +01001150 if (GARGCOUNT > 0
1151 && vim_chdirfile(alist_name(&GARGLIST[0]), "drop") == OK)
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001152 shorten_fnames(TRUE);
1153
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154 goto finished;
1155 }
1156
1157 /* Handle the drop, :edit to get to the file */
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001158 drop_numFiles = numFiles;
1159 drop_gotPosition = gotPosition;
1160 drop_thePosition = thePosition;
1161 handle_drop(numFiles, fnames, FALSE, drop_callback, NULL);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001162
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 setcursor();
1164 out_flush();
1165
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001166 /* Fake mouse event to wake from stall */
1167 PostEvent(mouseUp, 0);
1168
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001169finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170 AEDisposeDesc(&theList); /* dispose what we allocated */
1171
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001172 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001173 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174}
1175
1176/*
1177 *
1178 */
1179
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001180 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001181Handle_aevt_oapp_AE(
1182 const AppleEvent *theAEvent,
1183 AppleEvent *theReply,
1184 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185{
1186 OSErr error = noErr;
1187
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001188 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001189 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190}
1191
1192/*
1193 *
1194 */
1195
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001196 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001197Handle_aevt_quit_AE(
1198 const AppleEvent *theAEvent,
1199 AppleEvent *theReply,
1200 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201{
1202 OSErr error = noErr;
1203
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001204 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001206 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207
1208 /* Need to fake a :confirm qa */
1209 do_cmdline_cmd((char_u *)"confirm qa");
1210
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001211 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212}
1213
1214/*
1215 *
1216 */
1217
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001218 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001219Handle_aevt_pdoc_AE(
1220 const AppleEvent *theAEvent,
1221 AppleEvent *theReply,
1222 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223{
1224 OSErr error = noErr;
1225
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001226 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001228 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229}
1230
1231/*
1232 * Handling of unknown AppleEvent
1233 *
1234 * (Just get rid of all the parms)
1235 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001236 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001237Handle_unknown_AE(
1238 const AppleEvent *theAEvent,
1239 AppleEvent *theReply,
1240 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241{
1242 OSErr error = noErr;
1243
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001244 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001246 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247}
1248
1249
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250/*
1251 * Install the various AppleEvent Handlers
1252 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001253 OSErr
1254InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255{
1256 OSErr error;
1257
1258 /* install open application handler */
1259 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001260 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261 if (error)
1262 {
1263 return error;
1264 }
1265
1266 /* install quit application handler */
1267 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001268 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 if (error)
1270 {
1271 return error;
1272 }
1273
1274 /* install open document handler */
1275 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001276 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 if (error)
1278 {
1279 return error;
1280 }
1281
1282 /* install print document handler */
1283 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001284 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285
1286/* Install Core Suite */
1287/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001288 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289
1290 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001291 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292
1293 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001294 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295
1296 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001297 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298
1299 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001300 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
1302 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001303 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304
1305 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001306 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
1308 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001309 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310
1311 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001312 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313
1314 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001315 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316
1317 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001318 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319
1320 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001321 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322
1323 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001324 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325*/
1326
1327#ifdef FEAT_CW_EDITOR
1328 /*
1329 * Bind codewarrior support handlers
1330 */
1331 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001332 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001333 if (error)
1334 {
1335 return error;
1336 }
1337 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001338 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 if (error)
1340 {
1341 return error;
1342 }
1343 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001344 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345 if (error)
1346 {
1347 return error;
1348 }
1349#endif
1350
1351 return error;
1352
1353}
1354#endif /* USE_AEVENT */
1355
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001356
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001357/*
1358 * Callback function, installed by InstallFontPanelHandler(), below,
1359 * to handle Font Panel events.
1360 */
1361 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001362FontPanelHandler(
1363 EventHandlerCallRef inHandlerCallRef,
1364 EventRef inEvent,
1365 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001366{
1367 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1368 {
1369 gFontPanelInfo.isPanelVisible = false;
1370 return noErr;
1371 }
1372
1373 if (GetEventKind(inEvent) == kEventFontSelection)
1374 {
1375 OSStatus status;
1376 FMFontFamily newFamily;
1377 FMFontSize newSize;
1378 FMFontStyle newStyle;
1379
1380 /* Retrieve the font family ID number. */
1381 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1382 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1383 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1384 &newFamily);
1385 if (status == noErr)
1386 gFontPanelInfo.family = newFamily;
1387
1388 /* Retrieve the font size. */
1389 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1390 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1391 if (status == noErr)
1392 gFontPanelInfo.size = newSize;
1393
1394 /* Retrieve the font style (bold, etc.). Currently unused. */
1395 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1396 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1397 if (status == noErr)
1398 gFontPanelInfo.style = newStyle;
1399 }
1400 return noErr;
1401}
1402
1403
1404 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001405InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001406{
1407 EventTypeSpec eventTypes[2];
1408 EventHandlerUPP handlerUPP;
1409 /* EventHandlerRef handlerRef; */
1410
1411 eventTypes[0].eventClass = kEventClassFont;
1412 eventTypes[0].eventKind = kEventFontSelection;
1413 eventTypes[1].eventClass = kEventClassFont;
1414 eventTypes[1].eventKind = kEventFontPanelClosed;
1415
1416 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1417
1418 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1419 /*userData=*/NULL, /*handlerRef=*/NULL);
1420}
1421
1422
1423/*
1424 * Fill the buffer pointed to by outName with the name and size
1425 * of the font currently selected in the Font Panel.
1426 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001427#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001428 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001429GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001430{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001431 Str255 buf;
1432 ByteCount fontNameLen = 0;
1433 ATSUFontID fid;
1434 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001435
1436 if (!outName)
1437 return;
1438
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001439 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1440 {
1441 /* Canonicalize localized font names */
1442 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1443 gFontPanelInfo.style, &fid, NULL) != noErr)
1444 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001445
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001446 /* Request font name with Mac encoding (otherwise we could
1447 * get an unwanted utf-16 name) */
1448 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1449 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001450 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001451 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001452
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001453 /* Only encode font size, because style (bold, italic, etc) is
1454 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001455 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001456 gFontPanelInfo.size/*,
1457 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1458 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1459 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1460
1461 if ((fontNameLen + STRLEN(styleString)) < 255)
1462 STRCPY(outName + fontNameLen, styleString);
1463 }
1464 else
1465 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001466 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001467 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001468}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001469
1470
Bram Moolenaar071d4272004-06-13 20:20:40 +00001471/*
1472 * ------------------------------------------------------------
1473 * Unfiled yet
1474 * ------------------------------------------------------------
1475 */
1476
1477/*
1478 * gui_mac_get_menu_item_index
1479 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001480 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001482 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001483gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484{
1485 short index;
1486 short itemIndex = -1;
1487 vimmenu_T *pBrother;
1488
1489 /* Only menu without parent are the:
1490 * -menu in the menubar
1491 * -popup menu
1492 * -toolbar (guess)
1493 *
1494 * Which are not items anyway.
1495 */
1496 if (pMenu->parent)
1497 {
1498 /* Start from the Oldest Brother */
1499 pBrother = pMenu->parent->children;
1500 index = 1;
1501 while ((pBrother) && (itemIndex == -1))
1502 {
1503 if (pBrother == pMenu)
1504 itemIndex = index;
1505 index++;
1506 pBrother = pBrother->next;
1507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 }
1509 return itemIndex;
1510}
1511
1512 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001513gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514{
1515 short index;
1516 vimmenu_T *pChildMenu;
1517 vimmenu_T *pElder = pMenu->parent;
1518
1519
1520 /* Only menu without parent are the:
1521 * -menu in the menubar
1522 * -popup menu
1523 * -toolbar (guess)
1524 *
1525 * Which are not items anyway.
1526 */
1527
1528 if ((pElder) && (pElder->submenu_id == menuID))
1529 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1531 pMenu = pMenu->next;
1532 }
1533 else
1534 {
1535 for (; pMenu != NULL; pMenu = pMenu->next)
1536 {
1537 if (pMenu->children != NULL)
1538 {
1539 pChildMenu = gui_mac_get_vim_menu
1540 (menuID, itemIndex, pMenu->children);
1541 if (pChildMenu)
1542 {
1543 pMenu = pChildMenu;
1544 break;
1545 }
1546 }
1547 }
1548 }
1549 return pMenu;
1550}
1551
1552/*
1553 * ------------------------------------------------------------
1554 * MacOS Feedback procedures
1555 * ------------------------------------------------------------
1556 */
1557 pascal
1558 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001559gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560{
1561 scrollbar_T *sb;
1562 int value, dragging;
1563 ControlHandle theControlToUse;
1564 int dont_scroll_save = dont_scroll;
1565
1566 theControlToUse = dragged_sb;
1567
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001568 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569
1570 if (sb == NULL)
1571 return;
1572
1573 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001574 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 dragging = (partCode != 0);
1576
1577 /* When "allow_scrollbar" is FALSE still need to remember the new
1578 * position, but don't actually scroll by setting "dont_scroll". */
1579 dont_scroll = !allow_scrollbar;
1580 gui_drag_scrollbar(sb, value, dragging);
1581 dont_scroll = dont_scroll_save;
1582}
1583
1584 pascal
1585 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001586gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587{
1588 /* TODO: have live support */
1589 scrollbar_T *sb, *sb_info;
1590 long data;
1591 long value;
1592 int page;
1593 int dragging = FALSE;
1594 int dont_scroll_save = dont_scroll;
1595
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001596 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597
1598 if (sb == NULL)
1599 return;
1600
1601 if (sb->wp != NULL) /* Left or right scrollbar */
1602 {
1603 /*
1604 * Careful: need to get scrollbar info out of first (left) scrollbar
1605 * for window, but keep real scrollbar too because we must pass it to
1606 * gui_drag_scrollbar().
1607 */
1608 sb_info = &sb->wp->w_scrollbars[0];
1609
1610 if (sb_info->size > 5)
1611 page = sb_info->size - 2; /* use two lines of context */
1612 else
1613 page = sb_info->size;
1614 }
1615 else /* Bottom scrollbar */
1616 {
1617 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001618 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001619 }
1620
1621 switch (partCode)
1622 {
1623 case kControlUpButtonPart: data = -1; break;
1624 case kControlDownButtonPart: data = 1; break;
1625 case kControlPageDownPart: data = page; break;
1626 case kControlPageUpPart: data = -page; break;
1627 default: data = 0; break;
1628 }
1629
1630 value = sb_info->value + data;
1631/* if (value > sb_info->max)
1632 value = sb_info->max;
1633 else if (value < 0)
1634 value = 0;*/
1635
1636 /* When "allow_scrollbar" is FALSE still need to remember the new
1637 * position, but don't actually scroll by setting "dont_scroll". */
1638 dont_scroll = !allow_scrollbar;
1639 gui_drag_scrollbar(sb, value, dragging);
1640 dont_scroll = dont_scroll_save;
1641
1642 out_flush();
1643 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1644
1645/* if (sb_info->wp != NULL)
1646 {
1647 win_T *wp;
1648 int sb_num;
1649
1650 sb_num = 0;
1651 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1652 sb_num++;
1653
1654 if (wp != NULL)
1655 {
1656 current_scrollbar = sb_num;
1657 scrollbar_value = value;
1658 gui_do_scroll();
1659 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1660 }
1661 }*/
1662}
1663
1664/*
1665 * ------------------------------------------------------------
1666 * MacOS Click Handling procedures
1667 * ------------------------------------------------------------
1668 */
1669
1670
1671/*
1672 * Handle a click inside the window, it may happens in the
1673 * scrollbar or the contents.
1674 *
1675 * TODO: Add support for potential TOOLBAR
1676 */
1677 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001678gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679{
1680 Point thePoint;
1681 int_u vimModifiers;
1682 short thePortion;
1683 ControlHandle theControl;
1684 int vimMouseButton;
1685 short dblClick;
1686
1687 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001688 GlobalToLocal(&thePoint);
1689 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001691 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692
1693 if (theControl != NUL)
1694 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001695 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696
1697 if (thePortion != kControlIndicatorPart)
1698 {
1699 dragged_sb = theControl;
1700 TrackControl(theControl, thePoint, gScrollAction);
1701 dragged_sb = NULL;
1702 }
1703 else
1704 {
1705 dragged_sb = theControl;
1706#if 1
1707 TrackControl(theControl, thePoint, gScrollDrag);
1708#else
1709 TrackControl(theControl, thePoint, NULL);
1710#endif
1711 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1712 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001713 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 dragged_sb = NULL;
1715 }
1716 }
1717 else
1718 {
1719 /* We are inside the contents */
1720
1721 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1722 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1723
1724 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1725 vimMouseButton = MOUSE_LEFT;
1726
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001728 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 clickIsPopup = FALSE;
1730
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001731 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1732 {
1733 vimMouseButton = MOUSE_RIGHT;
1734 vimModifiers &= ~MOUSE_CTRL;
1735 clickIsPopup = TRUE;
1736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737
1738 /* Is it a double click ? */
1739 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1740
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001741 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 gui_send_mouse_event(vimMouseButton, thePoint.h,
1743 thePoint.v, dblClick, vimModifiers);
1744
1745 /* Create the rectangle around the cursor to detect
1746 * the mouse dragging
1747 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748#if 0
1749 /* TODO: Do we need to this even for the contextual menu?
1750 * It may be require for popup_setpos, but for popup?
1751 */
1752 if (vimMouseButton == MOUSE_LEFT)
1753#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001755 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 FILL_Y(Y_2_ROW(thePoint.v)),
1757 FILL_X(X_2_COL(thePoint.h)+1),
1758 FILL_Y(Y_2_ROW(thePoint.v)+1));
1759
1760 dragRectEnbl = TRUE;
1761 dragRectControl = kCreateRect;
1762 }
1763 }
1764}
1765
1766/*
1767 * Handle the click in the titlebar (to move the window)
1768 */
1769 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001770gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771{
1772 Rect movingLimits;
1773 Rect *movingLimitsPtr = &movingLimits;
1774
1775 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001776 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001777 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778}
1779
1780/*
1781 * Handle the click in the grow box
1782 */
1783 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001784gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785{
1786
1787 long newSize;
1788 unsigned short newWidth;
1789 unsigned short newHeight;
1790 Rect resizeLimits;
1791 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 Rect NewContentRect;
1793
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001794 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795
Bram Moolenaar720c7102007-05-10 18:07:50 +00001796 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 /* TODO: Should this come from Vim? */
1798 resizeLimits.top = 100;
1799 resizeLimits.left = 100;
1800
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1802 newWidth = NewContentRect.right - NewContentRect.left;
1803 newHeight = NewContentRect.bottom - NewContentRect.top;
1804 gui_resize_shell(newWidth, newHeight);
1805 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001806 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807}
1808
1809/*
1810 * Handle the click in the zoom box
1811 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001813gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814{
1815 Rect r;
1816 Point p;
1817 short thePart;
1818
1819 /* ideal width is current */
1820 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1821 if (gui.which_scrollbars[SBAR_LEFT])
1822 p.h += gui.scrollbar_width;
1823 if (gui.which_scrollbars[SBAR_RIGHT])
1824 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001825 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 p.v = 15 * 1024;
1827
1828 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1829 ? inZoomIn : inZoomOut;
1830
1831 if (!TrackBox(whichWindow, theEvent->where, thePart))
1832 return;
1833
1834 /* use returned width */
1835 p.h = r.right - r.left;
1836 /* adjust returned height */
1837 p.v = r.bottom - r.top - 2 * gui.border_offset;
1838 if (gui.which_scrollbars[SBAR_BOTTOM])
1839 p.v -= gui.scrollbar_height;
1840 p.v -= p.v % gui.char_height;
1841 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001842 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 p.v += gui.scrollbar_height;
1844
1845 ZoomWindowIdeal(whichWindow, thePart, &p);
1846
1847 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1848 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1849 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001850 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852
1853/*
1854 * ------------------------------------------------------------
1855 * MacOS Event Handling procedure
1856 * ------------------------------------------------------------
1857 */
1858
1859/*
1860 * Handle the Update Event
1861 */
1862
1863 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001864gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865{
1866 WindowPtr whichWindow;
1867 GrafPtr savePort;
1868 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 Rect *updateRectPtr;
1871 Rect rc;
1872 Rect growRect;
1873 RgnHandle saveRgn;
1874
1875
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 updateRgn = NewRgn();
1877 if (updateRgn == NULL)
1878 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879
1880 /* This could be done by the caller as we
1881 * don't require anything else out of the event
1882 */
1883 whichWindow = (WindowPtr) event->message;
1884
1885 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001886 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887
1888 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890
1891 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001892 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 /* Redraw the biggest rectangle covering the area
1894 * to be updated.
1895 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1897# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001898 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 * seem to work under MacOS X (Dany)
1900 */
1901 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1902# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001903
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001905 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001907 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908# if 0
1909 /* Code from original Carbon Port (using GetWindowRegion.
1910 * I believe the UpdateRgn is already in local (Dany)
1911 */
1912 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1913 GlobalToLocal(&botRight(updateRect));
1914# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 /* Update the content (i.e. the text) */
1916 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1917 updateRectPtr->right - updateRectPtr->left,
1918 updateRectPtr->bottom - updateRectPtr->top);
1919 /* Clear the border areas if needed */
1920 gui_mch_set_bg_color(gui.back_pixel);
1921 if (updateRectPtr->left < FILL_X(0))
1922 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001923 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1924 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 }
1926 if (updateRectPtr->top < FILL_Y(0))
1927 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001928 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1929 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 }
1931 if (updateRectPtr->right > FILL_X(Columns))
1932 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001933 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 }
1937 if (updateRectPtr->bottom > FILL_Y(Rows))
1938 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001941 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001944 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001947 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948
1949 /* Update the GrowBox */
1950 /* Taken from FAQ 33-27 */
1951 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001953 GetClip(saveRgn);
1954 ClipRect(&growRect);
1955 DrawGrowIcon(whichWindow);
1956 SetClip(saveRgn);
1957 DisposeRgn(saveRgn);
1958 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959
1960 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001961 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962}
1963
1964/*
1965 * Handle the activate/deactivate event
1966 * (apply to a window)
1967 */
1968 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001969gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970{
1971 WindowPtr whichWindow;
1972
1973 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001974 /* Dim scrollbars */
1975 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001977 ControlRef rootControl;
1978 GetRootControl(gui.VimWindow, &rootControl);
1979 if ((event->modifiers) & activeFlag)
1980 ActivateControl(rootControl);
1981 else
1982 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001984
1985 /* Activate */
1986 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987}
1988
1989
1990/*
1991 * Handle the suspend/resume event
1992 * (apply to the application)
1993 */
1994 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001995gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001996{
1997 /* The frontmost application just changed */
1998
1999 /* NOTE: the suspend may happen before the deactivate
2000 * seen on MacOS X
2001 */
2002
2003 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002004 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005 */
2006 if (event->message & 1)
2007 /* Resume */
2008 gui_focus_change(TRUE);
2009 else
2010 /* Suspend */
2011 gui_focus_change(FALSE);
2012}
2013
2014/*
2015 * Handle the key
2016 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002017#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002018 static pascal OSStatus
2019gui_mac_handle_window_activate(
2020 EventHandlerCallRef nextHandler,
2021 EventRef theEvent,
2022 void *data)
2023{
2024 UInt32 eventClass = GetEventClass(theEvent);
2025 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002026
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002027 if (eventClass == kEventClassWindow)
2028 {
2029 switch (eventKind)
2030 {
2031 case kEventWindowActivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002032 im_on_window_switch(TRUE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002033 return noErr;
2034
2035 case kEventWindowDeactivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002036 im_on_window_switch(FALSE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002037 return noErr;
2038 }
2039 }
2040
2041 return eventNotHandledErr;
2042}
2043
2044 static pascal OSStatus
2045gui_mac_handle_text_input(
2046 EventHandlerCallRef nextHandler,
2047 EventRef theEvent,
2048 void *data)
2049{
2050 UInt32 eventClass = GetEventClass(theEvent);
2051 UInt32 eventKind = GetEventKind(theEvent);
2052
2053 if (eventClass != kEventClassTextInput)
2054 return eventNotHandledErr;
2055
2056 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2057 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2058 (kEventTextInputOffsetToPos != eventKind) &&
2059 (kEventTextInputPosToOffset != eventKind) &&
2060 (kEventTextInputGetSelectedText != eventKind))
2061 return eventNotHandledErr;
2062
2063 switch (eventKind)
2064 {
2065 case kEventTextInputUpdateActiveInputArea:
2066 return gui_mac_update_input_area(nextHandler, theEvent);
2067 case kEventTextInputUnicodeForKeyEvent:
2068 return gui_mac_unicode_key_event(nextHandler, theEvent);
2069
2070 case kEventTextInputOffsetToPos:
2071 case kEventTextInputPosToOffset:
2072 case kEventTextInputGetSelectedText:
2073 break;
2074 }
2075
2076 return eventNotHandledErr;
2077}
2078
2079 static pascal
2080OSStatus gui_mac_update_input_area(
2081 EventHandlerCallRef nextHandler,
2082 EventRef theEvent)
2083{
2084 return eventNotHandledErr;
2085}
2086
2087static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2088 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002089
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002090# define INLINE_KEY_BUFFER_SIZE 80
2091 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002092gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002093 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002094 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002095{
2096 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002097 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002098 UInt32 actualSize;
2099 UniChar *text;
2100 char_u result[INLINE_KEY_BUFFER_SIZE];
2101 short len = 0;
2102 UInt32 key_sym;
2103 char charcode;
2104 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002105 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002106 size_t encLen;
2107 char_u *to = NULL;
2108 Boolean isSpecial = FALSE;
2109 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002110 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002112 /* Mask the mouse (as per user setting) */
2113 if (p_mh)
2114 ObscureCursor();
2115
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 /* Don't use the keys when the dialog wants them. */
2117 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002118 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 typeUnicodeText, NULL, 0, &actualSize, NULL))
2122 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 text = (UniChar *)alloc(actualSize);
2125 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002126 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002127
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002128 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002130 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002131
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002132 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002133 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002134 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002135
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002136 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002138 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002139
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002140 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002141 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002142 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002143
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002144 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002145 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002146 require_noerr(err, done);
2147
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002148#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002150 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002153 key_char = charcode;
2154 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002156 /* Find the special key (eg., for cursor keys) */
2157 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002158 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002159 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002160 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2161 if (special_keys[i].key_sym == key_sym)
2162 {
2163 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2164 special_keys[i].vim_code1);
2165 key_char = simplify_key(key_char,
2166 (int *)&vimModifiers);
2167 isSpecial = TRUE;
2168 break;
2169 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002170 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002171
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002172 /* Intercept CMD-. and CTRL-c */
2173 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002174 ((modifiers & cmdKey) && key_char == '.'))
2175 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002176
2177 if (!isSpecial)
2178 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002179 /* remove SHIFT for keys that are already shifted, e.g.,
2180 * '(' and '*' */
2181 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2182 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002183
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002184 /* remove CTRL from keys that already have it */
2185 if (key_char < 0x20)
2186 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002187
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002188 /* don't process unicode characters here */
2189 if (!IS_SPECIAL(key_char))
2190 {
2191 /* Following code to simplify and consolidate vimModifiers
2192 * taken liberally from gui_w48.c */
2193 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002194
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002195 /* Interpret META, include SHIFT, etc. */
2196 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2197 if (key_char == CSI)
2198 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002199
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002200 if (IS_SPECIAL(key_char))
2201 isSpecial = TRUE;
2202 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002203 }
2204
2205 if (vimModifiers)
2206 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002207 result[len++] = CSI;
2208 result[len++] = KS_MODIFIER;
2209 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002210 }
2211
2212 if (isSpecial && IS_SPECIAL(key_char))
2213 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002214 result[len++] = CSI;
2215 result[len++] = K_SECOND(key_char);
2216 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002217 }
2218 else
2219 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002220 encLen = actualSize;
2221 to = mac_utf16_to_enc(text, actualSize, &encLen);
2222 if (to)
2223 {
2224 /* This is basically add_to_input_buf_csi() */
2225 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2226 {
2227 result[len++] = to[i];
2228 if (to[i] == CSI)
2229 {
2230 result[len++] = KS_EXTRA;
2231 result[len++] = (int)KE_CSI;
2232 }
2233 }
2234 vim_free(to);
2235 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002236 }
2237
2238 add_to_input_buf(result, len);
2239 err = noErr;
2240
2241done:
2242 vim_free(text);
2243 if (err == noErr)
2244 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002245 /* Fake event to wake up WNE (required to get
2246 * key repeat working */
2247 PostEvent(keyUp, 0);
2248 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002249 }
2250
2251 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002252}
2253#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 void
2255gui_mac_doKeyEvent(EventRecord *theEvent)
2256{
2257 /* TODO: add support for COMMAND KEY */
2258 long menu;
2259 unsigned char string[20];
2260 short num, i;
2261 short len = 0;
2262 KeySym key_sym;
2263 int key_char;
2264 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002265 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266
2267 /* Mask the mouse (as per user setting) */
2268 if (p_mh)
2269 ObscureCursor();
2270
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002271 /* Get the key code and its ASCII representation */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002272 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2273 key_char = theEvent->message & charCodeMask;
2274 num = 1;
2275
2276 /* Intercept CTRL-C */
2277 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002278 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 if (key_char == Ctrl_C && ctrl_c_interrupts)
2280 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002281 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2282 && (key_char == '2' || key_char == '6'))
2283 {
2284 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2285 if (key_char == '2')
2286 key_char = Ctrl_AT;
2287 else
2288 key_char = Ctrl_HAT;
2289 theEvent->modifiers = 0;
2290 }
2291 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292
2293 /* Intercept CMD-. */
2294 if (theEvent->modifiers & cmdKey)
2295 if (key_char == '.')
2296 got_int = TRUE;
2297
2298 /* Handle command key as per menu */
2299 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2300 if (theEvent->modifiers & cmdKey)
2301 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2302 * Why the mouse button? */
2303 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2304 {
2305 menu = MenuKey(key_char);
2306 if (HiWord(menu))
2307 {
2308 gui_mac_handle_menu(menu);
2309 return;
2310 }
2311 }
2312
2313 /* Convert the modifiers */
2314 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2315
2316
2317 /* Handle special keys. */
2318#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002319 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2321#endif
2322 {
2323 /* Find the special key (for non-printable keyt_char) */
2324 if ((key_char < 0x20) || (key_char == 0x7f))
2325 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2326 if (special_keys[i].key_sym == key_sym)
2327 {
2328# if 0
2329 /* We currently don't have not so special key */
2330 if (special_keys[i].vim_code1 == NUL)
2331 key_char = special_keys[i].vim_code0;
2332 else
2333# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002334 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2335 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002336 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 break;
2338 }
2339 }
2340
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002341 /* For some keys the modifier is included in the char itself. */
2342 if (simplify || key_char == TAB || key_char == ' ')
2343 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344
2345 /* Add the modifier to the input bu if needed */
2346 /* Do not want SHIFT-A or CTRL-A with modifier */
2347 if (!IS_SPECIAL(key_char)
2348 && key_sym != vk_Space
2349 && key_sym != vk_Tab
2350 && key_sym != vk_Return
2351 && key_sym != vk_Enter
2352 && key_sym != vk_Esc)
2353 {
2354#if 1
2355 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002356 if ((modifiers == MOD_MASK_SHIFT)
2357 || (modifiers == MOD_MASK_CTRL)
2358 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 modifiers = 0;
2360#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002363 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002365 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 modifiers = modifiers & ~MOD_MASK_SHIFT;
2367#endif
2368 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002369 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002371 string[len++] = CSI;
2372 string[len++] = KS_MODIFIER;
2373 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 }
2375
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002378 string[len++] = CSI;
2379 string[len++] = K_SECOND(key_char);
2380 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 }
2382 else
2383 {
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
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 string[len++] = key_char;
2414 }
2415
2416 if (len == 1 && string[0] == CSI)
2417 {
2418 /* Turn CSI into K_CSI. */
2419 string[ len++ ] = KS_EXTRA;
2420 string[ len++ ] = KE_CSI;
2421 }
2422
2423 add_to_input_buf(string, len);
2424}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002425#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426
2427/*
2428 * Handle MouseClick
2429 */
2430 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002431gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432{
2433 short thePart;
2434 WindowPtr whichWindow;
2435
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002436 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002438#ifdef FEAT_GUI_TABLINE
2439 /* prevent that the vim window size changes if it's activated by a
2440 click into the tab pane */
2441 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002442 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002443#endif
2444
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445 switch (thePart)
2446 {
2447 case (inDesk):
2448 /* TODO: what to do? */
2449 break;
2450
2451 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002452 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 break;
2454
2455 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002456 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 break;
2458
2459 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002460 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461 break;
2462
2463 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002464 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 break;
2466
2467 case (inGoAway):
2468 if (TrackGoAway(whichWindow, theEvent->where))
2469 gui_shell_closed();
2470 break;
2471
2472 case (inZoomIn):
2473 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 break;
2476 }
2477}
2478
2479/*
2480 * Handle MouseMoved
2481 * [this event is a moving in and out of a region]
2482 */
2483 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002484gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485{
2486 Point thePoint;
2487 int_u vimModifiers;
2488
2489 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002490 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2492
2493 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002494 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2498 thePoint.v, FALSE, vimModifiers);
2499
2500 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002501 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 FILL_Y(Y_2_ROW(thePoint.v)),
2503 FILL_X(X_2_COL(thePoint.h)+1),
2504 FILL_Y(Y_2_ROW(thePoint.v)+1));
2505
2506 if (dragRectEnbl)
2507 dragRectControl = kCreateRect;
2508
2509}
2510
2511/*
2512 * Handle the mouse release
2513 */
2514 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002515gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516{
2517 Point thePoint;
2518 int_u vimModifiers;
2519
2520 /* TODO: Properly convert the Contextual menu mouse-up */
2521 /* Potential source of the double menu */
2522 lastMouseTick = theEvent->when;
2523 dragRectEnbl = FALSE;
2524 dragRectControl = kCreateEmpty;
2525 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002526 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527
2528 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529 if (clickIsPopup)
2530 {
2531 vimModifiers &= ~MOUSE_CTRL;
2532 clickIsPopup = FALSE;
2533 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002534 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535}
2536
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537 static pascal OSStatus
2538gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2539 void *data)
2540{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 Point point;
2542 Rect bounds;
2543 UInt32 mod;
2544 SInt32 delta;
2545 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002546 EventMouseWheelAxis axis;
2547
2548 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2549 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2550 && axis != kEventMouseWheelAxisY)
2551 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552
2553 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2554 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2555 goto bail;
2556 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2557 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2558 goto bail;
2559 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2560 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2561 goto bail;
2562
2563 vim_mod = 0;
2564 if (mod & shiftKey)
2565 vim_mod |= MOUSE_SHIFT;
2566 if (mod & controlKey)
2567 vim_mod |= MOUSE_CTRL;
2568 if (mod & optionKey)
2569 vim_mod |= MOUSE_ALT;
2570
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2572 {
2573 point.h -= bounds.left;
2574 point.v -= bounds.top;
2575 }
2576
2577 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2578 point.h, point.v, FALSE, vim_mod);
2579
Bram Moolenaarc236c162008-07-13 17:41:49 +00002580 /* post a bogus event to wake up WaitNextEvent */
2581 PostEvent(keyUp, 0);
2582
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 return noErr;
2584
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002585bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 /*
2587 * when we fail give any additional callback handler a chance to perform
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002588 * its actions
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 */
2590 return CallNextEventHandler(nextHandler, theEvent);
2591}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592
Bram Moolenaare00289d2010-08-14 21:56:42 +02002593 void
2594gui_mch_mousehide(int hide)
2595{
2596 /* TODO */
2597}
2598
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599#if 0
2600
2601/*
2602 * This would be the normal way of invoking the contextual menu
2603 * but the Vim API doesn't seem to a support a request to get
2604 * the menu that we should display
2605 */
2606 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002607gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608{
2609/*
2610 * Clone PopUp to use menu
2611 * Create a object descriptor for the current selection
2612 * Call the procedure
2613 */
2614
2615// Call to Handle Popup
2616 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2617
2618 if (status != noErr)
2619 return;
2620
2621 if (CntxType == kCMMenuItemSelected)
2622 {
2623 /* Handle the menu CntxMenuID, CntxMenuItem */
2624 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002625 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002626 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 }
2628 else if (CntxMenuID == kCMShowHelpSelected)
2629 {
2630 /* Should come up with the help */
2631 }
2632
2633}
2634#endif
2635
2636/*
2637 * Handle menubar selection
2638 */
2639 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002640gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641{
2642 short menu = HiWord(menuChoice);
2643 short item = LoWord(menuChoice);
2644 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645
2646 if (menu == 256) /* TODO: use constant or gui.xyz */
2647 {
2648 if (item == 1)
2649 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 }
2651 else if (item != 0)
2652 {
2653 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2654
2655 if (theVimMenu)
2656 gui_menu_cb(theVimMenu);
2657 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002658 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659}
2660
2661/*
2662 * Dispatch the event to proper handler
2663 */
2664
2665 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002666gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667{
2668 OSErr error;
2669
2670 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002671 if (IsShowContextualMenuClick(event))
2672 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002674 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002676 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002678 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002679 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680
2681 /* Handle normal event */
2682 switch (event->what)
2683 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002684#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 case (keyDown):
2686 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002687 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002689#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002691 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 break;
2693
2694 case (mouseDown):
2695 gui_mac_doMouseDownEvent(event);
2696 break;
2697
2698 case (mouseUp):
2699 gui_mac_doMouseUpEvent(event);
2700 break;
2701
2702 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002703 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 break;
2705
2706 case (diskEvt):
2707 /* We don't need special handling for disk insertion */
2708 break;
2709
2710 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002711 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 break;
2713
2714 case (osEvt):
2715 switch ((event->message >> 24) & 0xFF)
2716 {
2717 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002718 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719 break;
2720 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002721 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 break;
2723 }
2724 break;
2725
2726#ifdef USE_AEVENT
2727 case (kHighLevelEvent):
2728 /* Someone's talking to us, through AppleEvents */
2729 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2730 break;
2731#endif
2732 }
2733}
2734
2735/*
2736 * ------------------------------------------------------------
2737 * Unknown Stuff
2738 * ------------------------------------------------------------
2739 */
2740
2741
2742 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002743gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744{
2745 char_u c;
2746 char_u *p;
2747 char_u pFontName[256];
2748 Str255 systemFontname;
2749 short font_id;
2750 short size=9;
2751 GuiFont font;
2752#if 0
2753 char_u *fontNamePtr;
2754#endif
2755
2756 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2757 ;
2758
2759 c = *p;
2760 *p = 0;
2761
2762#if 1
2763 STRCPY(&pFontName[1], font_name);
2764 pFontName[0] = STRLEN(font_name);
2765 *p = c;
2766
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002767 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002768 char_u fontName[256];
2769 char_u *styleStart = vim_strchr(font_name, ':');
2770 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2771 vim_strncpy(fontName, font_name, fontNameLen);
2772
2773 ATSUFontID fontRef;
2774 FMFontStyle fontStyle;
2775 font_id = 0;
2776
2777 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2778 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2779 &fontRef) == noErr)
2780 {
2781 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2782 font_id = 0;
2783 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002784
2785 if (font_id == 0)
2786 {
2787 /*
2788 * Try again, this time replacing underscores in the font name
2789 * with spaces (:set guifont allows the two to be used
2790 * interchangeably; the Font Manager doesn't).
2791 */
2792 int i, changed = FALSE;
2793
2794 for (i = pFontName[0]; i > 0; --i)
2795 {
2796 if (pFontName[i] == '_')
2797 {
2798 pFontName[i] = ' ';
2799 changed = TRUE;
2800 }
2801 }
2802 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002803 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2804 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2805 kFontNoLanguageCode, &fontRef) == noErr)
2806 {
2807 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2808 font_id = 0;
2809 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002810 }
2811
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812#else
2813 /* name = C2Pascal_save(menu->dname); */
2814 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2815
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002816 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817#endif
2818
2819
2820 if (font_id == 0)
2821 {
2822 /* Oups, the system font was it the one the user want */
2823
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002824 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2825 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 if (!EqualString(pFontName, systemFontname, false, false))
2827 return NOFONT;
2828 }
2829 if (*p == ':')
2830 {
2831 p++;
2832 /* Set the values found after ':' */
2833 while (*p)
2834 {
2835 switch (*p++)
2836 {
2837 case 'h':
2838 size = points_to_pixels(p, &p, TRUE);
2839 break;
2840 /*
2841 * TODO: Maybe accept width and styles
2842 */
2843 }
2844 while (*p == ':')
2845 p++;
2846 }
2847 }
2848
2849 if (size < 1)
2850 size = 1; /* Avoid having a size of 0 with system font */
2851
2852 font = (size << 16) + ((long) font_id & 0xFFFF);
2853
2854 return font;
2855}
2856
2857/*
2858 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002859 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 * ------------------------------------------------------------
2861 */
2862
2863/*
2864 * Parse the GUI related command-line arguments. Any arguments used are
2865 * deleted from argv, and *argc is decremented accordingly. This is called
2866 * when vim is started, whether or not the GUI has been started.
2867 */
2868 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002869gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870{
2871 /* TODO: Move most of this stuff toward gui_mch_init */
2872#ifdef USE_EXE_NAME
2873 FSSpec applDir;
2874# ifndef USE_FIND_BUNDLE_PATH
2875 short applVRefNum;
2876 long applDirID;
2877 Str255 volName;
2878# else
2879 ProcessSerialNumber psn;
2880 FSRef applFSRef;
2881# endif
2882#endif
2883
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884#if 0
2885 InitCursor();
2886
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888
2889#ifdef USE_AEVENT
2890 (void) InstallAEHandlers();
2891#endif
2892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002893 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002895 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002897 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
2899 DrawMenuBar();
2900
2901
2902#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002903 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906#endif
2907
2908
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909 CreateNewWindow(kDocumentWindowClass,
2910 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002911 &windRect, &gui.VimWindow);
2912 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913
2914 gui.char_width = 7;
2915 gui.char_height = 11;
2916 gui.char_ascent = 6;
2917 gui.num_rows = 24;
2918 gui.num_cols = 80;
2919 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2920
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002921 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2922 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923
2924 dragRectEnbl = FALSE;
2925 dragRgn = NULL;
2926 dragRectControl = kCreateEmpty;
2927 cursorRgn = NewRgn();
2928#endif
2929#ifdef USE_EXE_NAME
2930# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002931 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002933 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934# else
2935 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2936 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002938 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 /* if (err != noErr) return err; */
2940
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002941 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 /* if (err != noErr) return err; */
2943
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002944 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945
2946 /* This technic return NIL when we disallow_gui */
2947# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002948 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950}
2951
2952#ifndef ALWAYS_USE_GUI
2953/*
2954 * Check if the GUI can be started. Called before gvimrc is sourced.
2955 * Return OK or FAIL.
2956 */
2957 int
2958gui_mch_init_check(void)
2959{
2960 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2961 * using the >console
2962 */
2963 if (disallow_gui) /* see main.c for reason to disallow */
2964 return FAIL;
2965 return OK;
2966}
2967#endif
2968
2969 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002970receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971{
2972 int x, y;
2973 int_u modifiers;
2974 char_u **fnames = NULL;
2975 int count;
2976 int i, j;
2977
2978 /* Get drop position, modifiers and count of items */
2979 {
2980 Point point;
2981 SInt16 mouseUpModifiers;
2982 UInt16 countItem;
2983
2984 GetDragMouse(theDrag, &point, NULL);
2985 GlobalToLocal(&point);
2986 x = point.h;
2987 y = point.v;
2988 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2989 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2990 CountDragItems(theDrag, &countItem);
2991 count = countItem;
2992 }
2993
2994 fnames = (char_u **)alloc(count * sizeof(char_u *));
2995 if (fnames == NULL)
2996 return dragNotAcceptedErr;
2997
2998 /* Get file names dropped */
2999 for (i = j = 0; i < count; ++i)
3000 {
3001 DragItemRef item;
3002 OSErr err;
3003 Size size;
3004 FlavorType type = flavorTypeHFS;
3005 HFSFlavor hfsFlavor;
3006
3007 fnames[i] = NULL;
3008 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3009 err = GetFlavorDataSize(theDrag, item, type, &size);
3010 if (err != noErr || size > sizeof(hfsFlavor))
3011 continue;
3012 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3013 if (err != noErr)
3014 continue;
3015 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3016 }
3017 count = j;
3018
3019 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003020
3021 /* Fake mouse event to wake from stall */
3022 PostEvent(mouseUp, 0);
3023
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024 return noErr;
3025}
3026
3027/*
3028 * Initialise the GUI. Create all the windows, set up all the call-backs
3029 * etc.
3030 */
3031 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003032gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033{
3034 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003035 Rect windRect;
3036 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003038 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003039 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003040
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003041 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003042 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003043
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044#if 1
3045 InitCursor();
3046
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048
3049#ifdef USE_AEVENT
3050 (void) InstallAEHandlers();
3051#endif
3052
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003053 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003055 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003057 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058
3059 DrawMenuBar();
3060
3061
3062#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003063 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066#endif
3067
3068 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003071 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3073 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003074 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075
3076 gui.char_width = 7;
3077 gui.char_height = 11;
3078 gui.char_ascent = 6;
3079 gui.num_rows = 24;
3080 gui.num_cols = 80;
3081 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3082
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003083 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3084 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003086 /* Install Carbon event callbacks. */
3087 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088
3089 dragRectEnbl = FALSE;
3090 dragRgn = NULL;
3091 dragRectControl = kCreateEmpty;
3092 cursorRgn = NewRgn();
3093#endif
3094 /* Display any pending error messages */
3095 display_errors();
3096
3097 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003098 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 gui.norm_pixel = 0x00000000;
3100 gui.back_pixel = 0x00FFFFFF;
3101
3102 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3103 * file). */
3104 set_normal_colors();
3105
3106 /*
3107 * Check that none of the colors are the same as the background color.
3108 * Then store the current values as the defaults.
3109 */
3110 gui_check_colors();
3111 gui.def_norm_pixel = gui.norm_pixel;
3112 gui.def_back_pixel = gui.back_pixel;
3113
3114 /* Get the colors for the highlight groups (gui_check_colors() might have
3115 * changed them) */
3116 highlight_gui_started();
3117
3118 /*
3119 * Setting the gui constants
3120 */
3121#ifdef FEAT_MENU
3122 gui.menu_height = 0;
3123#endif
3124 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3125 gui.border_offset = gui.border_width = 2;
3126
Bram Moolenaar720c7102007-05-10 18:07:50 +00003127 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 gui_mch_draw_string() below), enable it for all font sizes. */
3129 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 eventTypeSpec.eventClass = kEventClassMouse;
3132 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3133 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3134 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3135 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3136 {
3137 mouseWheelHandlerRef = NULL;
3138 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3139 mouseWheelHandlerUPP = NULL;
3140 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003142#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003143 InterfaceTypeList supportedServices = { kUnicodeDocument };
3144 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3145
3146 /* We don't support inline input yet, use input window by default */
3147 UseInputWindow(gTSMDocument, TRUE);
3148
3149 /* Should we activate the document by default? */
3150 // ActivateTSMDocument(gTSMDocument);
3151
3152 EventTypeSpec textEventTypes[] = {
3153 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3154 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3155 { kEventClassTextInput, kEventTextInputPosToOffset },
3156 { kEventClassTextInput, kEventTextInputOffsetToPos },
3157 };
3158
3159 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3160 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3161 NR_ELEMS(textEventTypes),
3162 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003163 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003164 DisposeEventHandlerUPP(keyEventHandlerUPP);
3165 keyEventHandlerUPP = NULL;
3166 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003167
3168 EventTypeSpec windowEventTypes[] = {
3169 { kEventClassWindow, kEventWindowActivated },
3170 { kEventClassWindow, kEventWindowDeactivated },
3171 };
3172
3173 /* Install window event handler to support TSMDocument activate and
3174 * deactivate */
3175 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3176 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3177 winEventHandlerUPP,
3178 NR_ELEMS(windowEventTypes),
3179 windowEventTypes, NULL, NULL))
3180 {
3181 DisposeEventHandlerUPP(winEventHandlerUPP);
3182 winEventHandlerUPP = NULL;
3183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184#endif
3185
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003186#ifdef FEAT_GUI_TABLINE
3187 /*
3188 * Create the tabline
3189 */
3190 initialise_tabline();
3191#endif
3192
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193 /* TODO: Load bitmap if using TOOLBAR */
3194 return OK;
3195}
3196
3197/*
3198 * Called when the foreground or background color has been changed.
3199 */
3200 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003201gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202{
3203 /* TODO:
3204 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003205 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206 */
3207}
3208
3209/*
3210 * Open the GUI window which was created by a call to gui_mch_init().
3211 */
3212 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003213gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214{
3215 ShowWindow(gui.VimWindow);
3216
3217 if (gui_win_x != -1 && gui_win_y != -1)
3218 gui_mch_set_winpos(gui_win_x, gui_win_y);
3219
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 /*
3221 * Make the GUI the foreground process (in case it was launched
3222 * from the Terminal or via :gui).
3223 */
3224 {
3225 ProcessSerialNumber psn;
3226 if (GetCurrentProcess(&psn) == noErr)
3227 SetFrontProcess(&psn);
3228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229
3230 return OK;
3231}
3232
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003233#ifdef USE_ATSUI_DRAWING
3234 static void
3235gui_mac_dispose_atsui_style(void)
3236{
3237 if (p_macatsui && gFontStyle)
3238 ATSUDisposeStyle(gFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003239 if (p_macatsui && gWideFontStyle)
3240 ATSUDisposeStyle(gWideFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003241}
3242#endif
3243
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 void
3245gui_mch_exit(int rc)
3246{
3247 /* TODO: find out all what is missing here? */
3248 DisposeRgn(cursorRgn);
3249
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003250#ifdef USE_CARBONKEYHANDLER
3251 if (keyEventHandlerUPP)
3252 DisposeEventHandlerUPP(keyEventHandlerUPP);
3253#endif
3254
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 if (mouseWheelHandlerUPP != NULL)
3256 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003258#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003259 gui_mac_dispose_atsui_style();
3260#endif
3261
3262#ifdef USE_CARBONKEYHANDLER
3263 FixTSMDocument(gTSMDocument);
3264 DeactivateTSMDocument(gTSMDocument);
3265 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003266#endif
3267
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 /* Exit to shell? */
3269 exit(rc);
3270}
3271
3272/*
3273 * Get the position of the top left corner of the window.
3274 */
3275 int
3276gui_mch_get_winpos(int *x, int *y)
3277{
3278 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 Rect bounds;
3280 OSStatus status;
3281
3282 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003283 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284
3285 if (status != noErr)
3286 return FAIL;
3287 *x = bounds.left;
3288 *y = bounds.top;
3289 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290}
3291
3292/*
3293 * Set the position of the top left corner of the window to the given
3294 * coordinates.
3295 */
3296 void
3297gui_mch_set_winpos(int x, int y)
3298{
3299 /* TODO: Should make sure the window is move within range
3300 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3301 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003302 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303}
3304
3305 void
3306gui_mch_set_shellsize(
3307 int width,
3308 int height,
3309 int min_width,
3310 int min_height,
3311 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003312 int base_height,
3313 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315 CGrafPtr VimPort;
3316 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317
3318 if (gui.which_scrollbars[SBAR_LEFT])
3319 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003320 VimPort = GetWindowPort(gui.VimWindow);
3321 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003323 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 }
3326 else
3327 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003328 VimPort = GetWindowPort(gui.VimWindow);
3329 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003331 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332 }
3333
3334 SizeWindow(gui.VimWindow, width, height, TRUE);
3335
3336 gui_resize_shell(width, height);
3337}
3338
3339/*
3340 * Get the screen dimensions.
3341 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3342 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003343 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 */
3345 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003346gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347{
3348 GDHandle dominantDevice = GetMainDevice();
3349 Rect screenRect = (**dominantDevice).gdRect;
3350
3351 *screen_w = screenRect.right - 10;
3352 *screen_h = screenRect.bottom - 40;
3353}
3354
3355
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003356/*
3357 * Open the Font Panel and wait for the user to select a font and
3358 * close the panel. Then fill the buffer pointed to by font_name with
3359 * the name and size of the selected font and return the font's handle,
3360 * or NOFONT in case of an error.
3361 */
3362 static GuiFont
3363gui_mac_select_font(char_u *font_name)
3364{
3365 GuiFont selected_font = NOFONT;
3366 OSStatus status;
3367 FontSelectionQDStyle curr_font;
3368
3369 /* Initialize the Font Panel with the current font. */
3370 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3371 curr_font.size = (gui.norm_font >> 16);
3372 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3373 curr_font.instance.fontStyle = 0;
3374 curr_font.hasColor = false;
3375 curr_font.version = 0; /* version number of the style structure */
3376 status = SetFontInfoForSelection(kFontSelectionQDType,
3377 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3378
3379 gFontPanelInfo.family = curr_font.instance.fontFamily;
3380 gFontPanelInfo.style = curr_font.instance.fontStyle;
3381 gFontPanelInfo.size = curr_font.size;
3382
3383 /* Pop up the Font Panel. */
3384 status = FPShowHideFontPanel();
3385 if (status == noErr)
3386 {
3387 /*
3388 * The Font Panel is modeless. We really need it to be modal,
3389 * so we spin in an event loop until the panel is closed.
3390 */
3391 gFontPanelInfo.isPanelVisible = true;
3392 while (gFontPanelInfo.isPanelVisible)
3393 {
3394 EventRecord e;
3395 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3396 }
3397
3398 GetFontPanelSelection(font_name);
3399 selected_font = gui_mac_find_font(font_name);
3400 }
3401 return selected_font;
3402}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003403
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003404#ifdef USE_ATSUI_DRAWING
3405 static void
3406gui_mac_create_atsui_style(void)
3407{
3408 if (p_macatsui && gFontStyle == NULL)
3409 {
3410 if (ATSUCreateStyle(&gFontStyle) != noErr)
3411 gFontStyle = NULL;
3412 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003413 if (p_macatsui && gWideFontStyle == NULL)
3414 {
3415 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3416 gWideFontStyle = NULL;
3417 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003418
3419 p_macatsui_last = p_macatsui;
3420}
3421#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422
3423/*
3424 * Initialise vim to use the font with the given name. Return FAIL if the font
3425 * could not be loaded, OK otherwise.
3426 */
3427 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003428gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429{
3430 /* TODO: Add support for bold italic underline proportional etc... */
3431 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003432 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433 FontInfo font_info;
3434 short font_id;
3435 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003436 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003438#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003439 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003440#endif
3441
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442 if (font_name == NULL)
3443 {
3444 /* First try to get the suggested font */
3445 GetFNum(suggestedFont, &font_id);
3446
3447 if (font_id == 0)
3448 {
3449 /* Then pickup the standard application font */
3450 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003451 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003453 else
3454 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3456 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003457 else if (STRCMP(font_name, "*") == 0)
3458 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003459 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003460
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003461 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003462 if (font == NOFONT)
3463 return FAIL;
3464
3465 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003466 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003467 if (new_p_guifont != NULL)
3468 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003469 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003470 vim_free(p_guifont);
3471 p_guifont = new_p_guifont;
3472 /* Replace spaces in the font name with underscores. */
3473 for ( ; *new_p_guifont; ++new_p_guifont)
3474 {
3475 if (*new_p_guifont == ' ')
3476 *new_p_guifont = '_';
3477 }
3478 }
3479 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 else
3481 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003482 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003483 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484
3485 if (font == NOFONT)
3486 return FAIL;
3487 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003488
Bram Moolenaar071d4272004-06-13 20:20:40 +00003489 gui.norm_font = font;
3490
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003491 hl_set_font_name(used_font_name);
3492
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003493 TextSize(font >> 16);
3494 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003496 GetFontInfo(&font_info);
3497
3498 gui.char_ascent = font_info.ascent;
3499 gui.char_width = CharWidth('_');
3500 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3501
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003502#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003503 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003504 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003505#endif
3506
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508}
3509
Bram Moolenaar02743632005-07-25 20:42:36 +00003510/*
3511 * Adjust gui.char_height (after 'linespace' was changed).
3512 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003514gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515{
3516 FontInfo font_info;
3517
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003518 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3520 gui.char_ascent = font_info.ascent + p_linespace / 2;
3521 return OK;
3522}
3523
3524/*
3525 * Get a font structure for highlighting.
3526 */
3527 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003528gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529{
3530 GuiFont font;
3531
3532 font = gui_mac_find_font(name);
3533
3534 if (font == NOFONT)
3535 {
3536 if (giveErrorIfMissing)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003537 semsg(_(e_font), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 return NOFONT;
3539 }
3540 /*
3541 * TODO : Accept only monospace
3542 */
3543
3544 return font;
3545}
3546
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003547#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003549 * Return the name of font "font" in allocated memory.
3550 * Don't know how to get the actual name, thus use the provided name.
3551 */
3552 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003553gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003554{
3555 if (name == NULL)
3556 return NULL;
3557 return vim_strsave(name);
3558}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003559#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003560
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003561#ifdef USE_ATSUI_DRAWING
3562 static void
3563gui_mac_set_font_attributes(GuiFont font)
3564{
3565 ATSUFontID fontID;
3566 Fixed fontSize;
3567 Fixed fontWidth;
3568
3569 fontID = font & 0xFFFF;
3570 fontSize = Long2Fix(font >> 16);
3571 fontWidth = Long2Fix(gui.char_width);
3572
3573 ATSUAttributeTag attribTags[] =
3574 {
3575 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3576 kATSUMaxATSUITagValue + 1
3577 };
3578
3579 ByteCount attribSizes[] =
3580 {
3581 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3582 sizeof(font)
3583 };
3584
3585 ATSUAttributeValuePtr attribValues[] =
3586 {
3587 &fontID, &fontSize, &fontWidth, &font
3588 };
3589
3590 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3591 {
3592 if (ATSUSetAttributes(gFontStyle,
3593 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3594 attribTags, attribSizes, attribValues) != noErr)
3595 {
3596# ifndef NDEBUG
3597 fprintf(stderr, "couldn't set font style\n");
3598# endif
3599 ATSUDisposeStyle(gFontStyle);
3600 gFontStyle = NULL;
3601 }
3602
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003603 if (has_mbyte)
3604 {
3605 /* FIXME: we should use a more mbyte sensitive way to support
3606 * wide font drawing */
3607 fontWidth = Long2Fix(gui.char_width * 2);
3608
3609 if (ATSUSetAttributes(gWideFontStyle,
3610 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3611 attribTags, attribSizes, attribValues) != noErr)
3612 {
3613 ATSUDisposeStyle(gWideFontStyle);
3614 gWideFontStyle = NULL;
3615 }
3616 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003617 }
3618}
3619#endif
3620
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003621/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 * Set the current text font.
3623 */
3624 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003625gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003626{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003627#ifdef USE_ATSUI_DRAWING
3628 GuiFont currFont;
3629 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003630
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003631 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003632 {
3633 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003634 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3635 sizeof(font), &currFont, &actualFontByteCount) == noErr
3636 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003637 {
3638 if (currFont == font)
3639 return;
3640 }
3641
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003642 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003643 }
3644
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003645 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003646 {
3647 /* Setup automatic font substitution. The user's guifontwide
3648 * is tried first, then the system tries other fonts. */
3649/*
3650 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3651 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3652 ATSUCreateFontFallbacks(&gFontFallbacks);
3653 ATSUSetObjFontFallbacks(gFontFallbacks, );
3654*/
3655 if (gui.wide_font)
3656 {
3657 ATSUFontID fallbackFonts;
3658 gIsFontFallbackSet = TRUE;
3659
3660 if (FMGetFontFromFontFamilyInstance(
3661 (gui.wide_font & 0xFFFF),
3662 0,
3663 &fallbackFonts,
3664 NULL) == noErr)
3665 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003666 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3667 &fallbackFonts,
3668 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003669 }
3670/*
3671 ATSUAttributeValuePtr fallbackValues[] = { };
3672*/
3673 }
3674 }
3675#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 TextSize(font >> 16);
3677 TextFont(font & 0xFFFF);
3678}
3679
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680/*
3681 * If a font is not going to be used, free its structure.
3682 */
3683 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003684gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685{
3686 /*
3687 * Free font when "font" is not 0.
3688 * Nothing to do in the current implementation, since
3689 * nothing is allocated for each font used.
3690 */
3691}
3692
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693/*
3694 * Return the Pixel value (color) for the given color name. This routine was
3695 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3696 * Programmer's Guide.
3697 * Return INVALCOLOR when failed.
3698 */
3699 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003700gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701{
3702 /* TODO: Add support for the new named color of MacOS 8
3703 */
3704 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705
Bram Moolenaarab302212016-04-26 20:59:29 +02003706 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003708 LMGetHiliteRGB(&MacColor);
3709 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003711 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712}
3713
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003714 guicolor_T
3715gui_mch_get_rgb_color(int r, int g, int b)
3716{
3717 return gui_get_rgb_color_cmn(r, g, b);
3718}
3719
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720/*
3721 * Set the current text foreground color.
3722 */
3723 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003724gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725{
3726 RGBColor TheColor;
3727
3728 TheColor.red = Red(color) * 0x0101;
3729 TheColor.green = Green(color) * 0x0101;
3730 TheColor.blue = Blue(color) * 0x0101;
3731
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003732 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733}
3734
3735/*
3736 * Set the current text background color.
3737 */
3738 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003739gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740{
3741 RGBColor TheColor;
3742
3743 TheColor.red = Red(color) * 0x0101;
3744 TheColor.green = Green(color) * 0x0101;
3745 TheColor.blue = Blue(color) * 0x0101;
3746
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003747 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748}
3749
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003750RGBColor specialColor;
3751
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003752/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003753 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003754 */
3755 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003756gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003757{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003758 specialColor.red = Red(color) * 0x0101;
3759 specialColor.green = Green(color) * 0x0101;
3760 specialColor.blue = Blue(color) * 0x0101;
3761}
3762
3763/*
3764 * Draw undercurl at the bottom of the character cell.
3765 */
3766 static void
3767draw_undercurl(int flags, int row, int col, int cells)
3768{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003769 int x;
3770 int offset;
3771 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3772 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003773
3774 RGBForeColor(&specialColor);
3775
3776 offset = val[FILL_X(col) % 8];
3777 MoveTo(FILL_X(col), y - offset);
3778
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003779 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003780 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003781 offset = val[x % 8];
3782 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003783 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003784}
3785
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003786
3787 static void
3788draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 char_u *tofree = NULL;
3791
3792 if (output_conv.vc_type != CONV_NONE)
3793 {
3794 tofree = string_convert(&output_conv, s, &len);
3795 if (tofree != NULL)
3796 s = tofree;
3797 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 /*
3800 * On OS X, try using Quartz-style text antialiasing.
3801 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003802 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803 {
3804 /* Quartz antialiasing is available only in OS 10.2 and later. */
3805 UInt32 qd_flags = (p_antialias ?
3806 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003807 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 }
3809
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003810 /*
3811 * When antialiasing we're using srcOr mode, we have to clear the block
3812 * before drawing the text.
3813 * Also needed when 'linespace' is non-zero to remove the cursor and
3814 * underlining.
3815 * But not when drawing transparently.
3816 * The following is like calling gui_mch_clear_block(row, col, row, col +
3817 * len - 1), but without setting the bg color to gui.back_pixel.
3818 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003819 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003820 && !(flags & DRAW_TRANSP))
3821 {
3822 Rect rc;
3823
3824 rc.left = FILL_X(col);
3825 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003826 /* Multibyte computation taken from gui_w32.c */
3827 if (has_mbyte)
3828 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003829 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003830 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003831 }
3832 else
Bram Moolenaar13505972019-01-24 15:04:48 +01003833 rc.right = FILL_X(col + len) + (col + len == Columns);
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003834 rc.bottom = FILL_Y(row + 1);
3835 EraseRect(&rc);
3836 }
3837
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003838 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 {
3840 StyleParameter face;
3841
3842 face = normal;
3843 if (flags & DRAW_BOLD)
3844 face |= bold;
3845 if (flags & DRAW_UNDERL)
3846 face |= underline;
3847 TextFace(face);
3848
3849 /* Quartz antialiasing works only in srcOr transfer mode. */
3850 TextMode(srcOr);
3851
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852 MoveTo(TEXT_X(col), TEXT_Y(row));
3853 DrawText((char*)s, 0, len);
3854 }
3855 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856 {
3857 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003858 TextMode(srcCopy);
3859 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860
3861 /* SelectFont(hdc, gui.currFont); */
3862
3863 if (flags & DRAW_TRANSP)
3864 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003865 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 }
3867
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003868 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003869 DrawText((char *)s, 0, len);
3870
3871 if (flags & DRAW_BOLD)
3872 {
3873 TextMode(srcOr);
3874 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3875 DrawText((char *)s, 0, len);
3876 }
3877
3878 if (flags & DRAW_UNDERL)
3879 {
3880 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3881 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3882 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003883 if (flags & DRAW_STRIKE)
3884 {
3885 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3886 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3887 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003888 }
3889
3890 if (flags & DRAW_UNDERC)
3891 draw_undercurl(flags, row, col, len);
3892
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003893 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003894}
3895
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003896#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003897
3898 static void
3899draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3900{
3901 /* ATSUI requires utf-16 strings */
3902 UniCharCount utf16_len;
3903 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3904 utf16_len /= sizeof(UniChar);
3905
3906 /* - ATSUI automatically antialiases text (Someone)
3907 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003908#ifdef MAC_ATSUI_DEBUG
3909 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3910 row, col, len, len == 1 ? s[0] : ' ');
3911#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003912 /*
3913 * When antialiasing we're using srcOr mode, we have to clear the block
3914 * before drawing the text.
3915 * Also needed when 'linespace' is non-zero to remove the cursor and
3916 * underlining.
3917 * But not when drawing transparently.
3918 * The following is like calling gui_mch_clear_block(row, col, row, col +
3919 * len - 1), but without setting the bg color to gui.back_pixel.
3920 */
3921 if ((flags & DRAW_TRANSP) == 0)
3922 {
3923 Rect rc;
3924
3925 rc.left = FILL_X(col);
3926 rc.top = FILL_Y(row);
3927 /* Multibyte computation taken from gui_w32.c */
3928 if (has_mbyte)
3929 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003930 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003931 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003932 }
3933 else
3934 rc.right = FILL_X(col + len) + (col + len == Columns);
3935
3936 rc.bottom = FILL_Y(row + 1);
3937 EraseRect(&rc);
3938 }
3939
3940 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003941 TextMode(srcCopy);
3942 TextFace(normal);
3943
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003944 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003945 if (flags & DRAW_TRANSP)
3946 {
3947 TextMode(srcOr);
3948 }
3949
3950 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003951
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003952 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003953 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003954 Boolean attValue = true;
3955 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3956 ByteCount attribSizes[] = { sizeof(Boolean) };
3957 ATSUAttributeValuePtr attribValues[] = { &attValue };
3958
3959 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3960 }
3961
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003962 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3963 : kATSStyleNoAntiAliasing;
3964 if (useAntialias != useAntialias_cached)
3965 {
3966 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3967 ByteCount attribSizes[] = { sizeof(UInt32) };
3968 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3969
3970 if (gFontStyle)
3971 ATSUSetAttributes(gFontStyle, 1, attribTags,
3972 attribSizes, attribValues);
3973 if (gWideFontStyle)
3974 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3975 attribSizes, attribValues);
3976
3977 useAntialias_cached = useAntialias;
3978 }
3979
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003980 if (has_mbyte)
3981 {
3982 int n, width_in_cell, last_width_in_cell;
3983 UniCharArrayOffset offset = 0;
3984 UniCharCount yet_to_draw = 0;
3985 ATSUTextLayout textLayout;
3986 ATSUStyle textStyle;
3987
3988 last_width_in_cell = 1;
3989 ATSUCreateTextLayout(&textLayout);
3990 ATSUSetTextPointerLocation(textLayout, tofree,
3991 kATSUFromTextBeginning,
3992 kATSUToTextEnd, utf16_len);
3993 /*
3994 ATSUSetRunStyle(textLayout, gFontStyle,
3995 kATSUFromTextBeginning, kATSUToTextEnd); */
3996
3997 /* Compute the length in display cells. */
3998 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3999 {
4000 width_in_cell = (*mb_ptr2cells)(s + n);
4001
4002 /* probably we are switching from single byte character
4003 * to multibyte characters (which requires more than one
4004 * cell to draw) */
4005 if (width_in_cell != last_width_in_cell)
4006 {
4007#ifdef MAC_ATSUI_DEBUG
4008 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4009 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4010#endif
4011 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4012 : gFontStyle;
4013
4014 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4015 offset += yet_to_draw;
4016 yet_to_draw = 0;
4017 last_width_in_cell = width_in_cell;
4018 }
4019
4020 yet_to_draw++;
4021 }
4022
4023 if (yet_to_draw)
4024 {
4025#ifdef MAC_ATSUI_DEBUG
4026 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4027 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4028#endif
4029 /* finish the rest style */
4030 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4031 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4032 }
4033
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004034 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004035 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004036 kATSUFromTextBeginning, kATSUToTextEnd,
4037 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004038 ATSUDisposeTextLayout(textLayout);
4039 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004040 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004041 {
4042 ATSUTextLayout textLayout;
4043
4044 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4045 kATSUFromTextBeginning, kATSUToTextEnd,
4046 utf16_len,
4047 (gFontStyle ? 1 : 0), &utf16_len,
4048 (gFontStyle ? &gFontStyle : NULL),
4049 &textLayout) == noErr)
4050 {
4051 ATSUSetTransientFontMatching(textLayout, TRUE);
4052
4053 ATSUDrawText(textLayout,
4054 kATSUFromTextBeginning, kATSUToTextEnd,
4055 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4056
4057 ATSUDisposeTextLayout(textLayout);
4058 }
4059 }
4060
4061 /* drawing is done, now reset bold to normal */
4062 if (gFontStyle && flags & DRAW_BOLD)
4063 {
4064 Boolean attValue = false;
4065
4066 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4067 ByteCount attribSizes[] = { sizeof(Boolean) };
4068 ATSUAttributeValuePtr attribValues[] = { &attValue };
4069
4070 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4071 attribValues);
4072 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073 }
4074
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004075 if (flags & DRAW_UNDERC)
4076 draw_undercurl(flags, row, col, len);
4077
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004079}
4080#endif
4081
4082 void
4083gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4084{
4085#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004086 if (p_macatsui == 0 && p_macatsui_last != 0)
4087 /* switch from macatsui to nomacatsui */
4088 gui_mac_dispose_atsui_style();
4089 else if (p_macatsui != 0 && p_macatsui_last == 0)
4090 /* switch from nomacatsui to macatsui */
4091 gui_mac_create_atsui_style();
4092
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004093 if (p_macatsui)
4094 draw_string_ATSUI(row, col, s, len, flags);
4095 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004097 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098}
4099
4100/*
4101 * Return OK if the key with the termcap name "name" is supported.
4102 */
4103 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004104gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105{
4106 int i;
4107
4108 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4109 if (name[0] == special_keys[i].vim_code0 &&
4110 name[1] == special_keys[i].vim_code1)
4111 return OK;
4112 return FAIL;
4113}
4114
4115 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004116gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004118 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119}
4120
4121 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004122gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123{
4124 /* Do a visual beep by reversing the foreground and background colors */
4125 Rect rc;
4126
4127 /*
4128 * Note: InvertRect() excludes right and bottom of rectangle.
4129 */
4130 rc.left = 0;
4131 rc.top = 0;
4132 rc.right = gui.num_cols * gui.char_width;
4133 rc.bottom = gui.num_rows * gui.char_height;
4134 InvertRect(&rc);
4135
4136 ui_delay((long)msec, TRUE); /* wait for some msec */
4137
4138 InvertRect(&rc);
4139}
4140
4141/*
4142 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4143 */
4144 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004145gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146{
4147 Rect rc;
4148
4149 /*
4150 * Note: InvertRect() excludes right and bottom of rectangle.
4151 */
4152 rc.left = FILL_X(c);
4153 rc.top = FILL_Y(r);
4154 rc.right = rc.left + nc * gui.char_width;
4155 rc.bottom = rc.top + nr * gui.char_height;
4156 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157}
4158
4159/*
4160 * Iconify the GUI window.
4161 */
4162 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004163gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164{
4165 /* TODO: find out what could replace iconify
4166 * -window shade?
4167 * -hide application?
4168 */
4169}
4170
4171#if defined(FEAT_EVAL) || defined(PROTO)
4172/*
4173 * Bring the Vim window to the foreground.
4174 */
4175 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004176gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177{
4178 /* TODO */
4179}
4180#endif
4181
4182/*
4183 * Draw a cursor without focus.
4184 */
4185 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004186gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187{
4188 Rect rc;
4189
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190 /*
4191 * Note: FrameRect() excludes right and bottom of rectangle.
4192 */
4193 rc.left = FILL_X(gui.col);
4194 rc.top = FILL_Y(gui.row);
4195 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004196 if (mb_lefthalve(gui.row, gui.col))
4197 rc.right += gui.char_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198 rc.bottom = rc.top + gui.char_height;
4199
4200 gui_mch_set_fg_color(color);
4201
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004202 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203}
4204
4205/*
4206 * Draw part of a cursor, only w pixels wide, and h pixels high.
4207 */
4208 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004209gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210{
4211 Rect rc;
4212
4213#ifdef FEAT_RIGHTLEFT
4214 /* vertical line should be on the right of current point */
4215 if (CURSOR_BAR_RIGHT)
4216 rc.left = FILL_X(gui.col + 1) - w;
4217 else
4218#endif
4219 rc.left = FILL_X(gui.col);
4220 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4221 rc.right = rc.left + w;
4222 rc.bottom = rc.top + h;
4223
4224 gui_mch_set_fg_color(color);
4225
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004226 FrameRect(&rc);
4227// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228}
4229
4230
4231
4232/*
4233 * Catch up with any queued X events. This may put keyboard input into the
4234 * input buffer, call resize call-backs, trigger timers etc. If there is
4235 * nothing in the X event queue (& no timers pending), then we return
4236 * immediately.
4237 */
4238 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004239gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004240{
4241 /* TODO: find what to do
4242 * maybe call gui_mch_wait_for_chars (0)
4243 * more like look at EventQueue then
4244 * call heart of gui_mch_wait_for_chars;
4245 *
4246 * if (eventther)
4247 * gui_mac_handle_event(&event);
4248 */
4249 EventRecord theEvent;
4250
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004251 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252 if (theEvent.what != nullEvent)
4253 gui_mch_wait_for_chars(0);
4254}
4255
4256/*
4257 * Simple wrapper to neglect more easily the time
4258 * spent inside WaitNextEvent while profiling.
4259 */
4260
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 pascal
4262 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004263WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264{
4265 if (((long) sleep) < -1)
4266 sleep = 32767;
4267 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4268}
4269
4270/*
4271 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4272 * from the keyboard.
4273 * wtime == -1 Wait forever.
4274 * wtime == 0 This should never happen.
4275 * wtime > 0 Wait wtime milliseconds for a character.
4276 * Returns OK if a character was found to be available within the given time,
4277 * or FAIL otherwise.
4278 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004280gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281{
4282 EventMask mask = (everyEvent);
4283 EventRecord event;
4284 long entryTick;
4285 long currentTick;
4286 long sleeppyTick;
4287
4288 /* If we are providing life feedback with the scrollbar,
4289 * we don't want to try to wait for an event, or else
4290 * there won't be any life feedback.
4291 */
4292 if (dragged_sb != NULL)
4293 return FAIL;
4294 /* TODO: Check if FAIL is the proper return code */
4295
4296 entryTick = TickCount();
4297
4298 allow_scrollbar = TRUE;
4299
4300 do
4301 {
4302/* if (dragRectControl == kCreateEmpty)
4303 {
4304 dragRgn = NULL;
4305 dragRectControl = kNothing;
4306 }
4307 else*/ if (dragRectControl == kCreateRect)
4308 {
4309 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004310 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311 dragRectControl = kNothing;
4312 }
4313 /*
4314 * Don't use gui_mch_update() because then we will spin-lock until a
4315 * char arrives, instead we use WaitNextEventWrp() to hang until an
4316 * event arrives. No need to check for input_buf_full because we are
4317 * returning as soon as it contains a single char.
4318 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004319 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004321 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322 else
4323 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004324
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004325 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004326 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004327 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 if (input_available())
4329 {
4330 allow_scrollbar = FALSE;
4331 return OK;
4332 }
4333 }
4334 currentTick = TickCount();
4335 }
4336 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4337
4338 allow_scrollbar = FALSE;
4339 return FAIL;
4340}
4341
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342/*
4343 * Output routines.
4344 */
4345
4346/* Flush any output to the screen */
4347 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004348gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349{
4350 /* TODO: Is anything needed here? */
4351}
4352
4353/*
4354 * Clear a rectangular region of the screen from text pos (row1, col1) to
4355 * (row2, col2) inclusive.
4356 */
4357 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004358gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359{
4360 Rect rc;
4361
4362 /*
4363 * Clear one extra pixel at the far right, for when bold characters have
4364 * spilled over to the next column.
4365 */
4366 rc.left = FILL_X(col1);
4367 rc.top = FILL_Y(row1);
4368 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4369 rc.bottom = FILL_Y(row2 + 1);
4370
4371 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004372 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373}
4374
4375/*
4376 * Clear the whole text window.
4377 */
4378 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004379gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380{
4381 Rect rc;
4382
4383 rc.left = 0;
4384 rc.top = 0;
4385 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4386 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4387
4388 gui_mch_set_bg_color(gui.back_pixel);
4389 EraseRect(&rc);
4390/* gui_mch_set_fg_color(gui.norm_pixel);
4391 FrameRect(&rc);
4392*/
4393}
4394
4395/*
4396 * Delete the given number of lines from the given row, scrolling up any
4397 * text further down within the scroll region.
4398 */
4399 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004400gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401{
4402 Rect rc;
4403
4404 /* changed without checking! */
4405 rc.left = FILL_X(gui.scroll_region_left);
4406 rc.right = FILL_X(gui.scroll_region_right + 1);
4407 rc.top = FILL_Y(row);
4408 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4409
4410 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004411 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412
4413 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4414 gui.scroll_region_left,
4415 gui.scroll_region_bot, gui.scroll_region_right);
4416}
4417
4418/*
4419 * Insert the given number of lines before the given row, scrolling down any
4420 * following text within the scroll region.
4421 */
4422 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004423gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424{
4425 Rect rc;
4426
4427 rc.left = FILL_X(gui.scroll_region_left);
4428 rc.right = FILL_X(gui.scroll_region_right + 1);
4429 rc.top = FILL_Y(row);
4430 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4431
4432 gui_mch_set_bg_color(gui.back_pixel);
4433
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004434 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435
4436 /* Update gui.cursor_row if the cursor scrolled or copied over */
4437 if (gui.cursor_row >= gui.row
4438 && gui.cursor_col >= gui.scroll_region_left
4439 && gui.cursor_col <= gui.scroll_region_right)
4440 {
4441 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4442 gui.cursor_row += num_lines;
4443 else if (gui.cursor_row <= gui.scroll_region_bot)
4444 gui.cursor_is_valid = FALSE;
4445 }
4446
4447 gui_clear_block(row, gui.scroll_region_left,
4448 row + num_lines - 1, gui.scroll_region_right);
4449}
4450
4451 /*
4452 * TODO: add a vim format to the clipboard which remember
4453 * LINEWISE, CHARWISE, BLOCKWISE
4454 */
4455
4456 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004457clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458{
4459
4460 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004461 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462 Size scrapSize;
4463 ScrapFlavorFlags scrapFlags;
4464 ScrapRef scrap = nil;
4465 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466 int type;
4467 char *searchCR;
4468 char_u *tempclip;
4469
4470
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004471 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 if (error != noErr)
4473 return;
4474
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004475 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4476 if (error == noErr)
4477 {
4478 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4479 if (error == noErr && scrapSize > 1)
4480 flavor = 1;
4481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004483 if (flavor == 0)
4484 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004485 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004486 if (error != noErr)
4487 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004489 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004490 if (error != noErr)
4491 return;
4492 }
4493
4494 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004496 /* In CARBON we don't need a Handle, a pointer is good */
4497 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004499 /* tempclip = lalloc(scrapSize+1, TRUE); */
4500 HLock(textOfClip);
4501 error = GetScrapFlavorData(scrap,
4502 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4503 &scrapSize, *textOfClip);
4504 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004506 if (flavor)
4507 type = **textOfClip;
4508 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004509 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004510
4511 tempclip = lalloc(scrapSize + 1, TRUE);
4512 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4513 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004515#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004516 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004517 /* Convert from utf-16 (clipboard) */
4518 size_t encLen = 0;
4519 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004520
4521 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004523 scrapSize = encLen;
4524 vim_free(tempclip);
4525 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004527 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004529
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004530 searchCR = (char *)tempclip;
4531 while (searchCR != NULL)
4532 {
4533 searchCR = strchr(searchCR, '\r');
4534 if (searchCR != NULL)
4535 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004537
4538 clip_yank_selection(type, tempclip, scrapSize, cbd);
4539
4540 vim_free(tempclip);
4541 HUnlock(textOfClip);
4542
4543 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544}
4545
4546 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004547clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548{
4549 /*
4550 * TODO: Really nothing to do?
4551 */
4552}
4553
4554 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004555clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556{
4557 return OK;
4558}
4559
4560/*
4561 * Send the current selection to the clipboard.
4562 */
4563 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004564clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565{
4566 Handle textOfClip;
4567 long scrapSize;
4568 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570
4571 char_u *str = NULL;
4572
4573 if (!cbd->owned)
4574 return;
4575
4576 clip_get_selection(cbd);
4577
4578 /*
4579 * Once we set the clipboard, lose ownership. If another application sets
4580 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582 cbd->owned = FALSE;
4583
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004584 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004586#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004587 size_t utf16_len = 0;
4588 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4589 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004591 scrapSize = utf16_len;
4592 vim_free(str);
4593 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594 }
4595#endif
4596
4597 if (type >= 0)
4598 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004601 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 HLock(textOfClip);
4603
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004604 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004605 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004606 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004607 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004608 scrapSize, *textOfClip + 1);
4609 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4610 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 HUnlock(textOfClip);
4612 DisposeHandle(textOfClip);
4613 }
4614
4615 vim_free(str);
4616}
4617
4618 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004619gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620{
4621 Rect VimBound;
4622
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004623/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625
4626 if (gui.which_scrollbars[SBAR_LEFT])
4627 {
4628 VimBound.left = -gui.scrollbar_width + 1;
4629 }
4630 else
4631 {
4632 VimBound.left = 0;
4633 }
4634
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004637 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638}
4639
4640/*
4641 * Menu stuff.
4642 */
4643
4644 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004645gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646{
4647 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004648 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 */
4650}
4651
4652 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004653gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654{
4655 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004656 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 */
4658}
4659
4660/*
4661 * Add a sub menu to the menu bar.
4662 */
4663 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004664gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665{
4666 /*
4667 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4668 * TODO: use menu->mnemonic and menu->actext
4669 * TODO: Try to reuse menu id
4670 * Carbon Help suggest to use only id between 1 and 235
4671 */
4672 static long next_avail_id = 128;
4673 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004674 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675 short index;
4676 vimmenu_T *parent = menu->parent;
4677 vimmenu_T *brother = menu->next;
4678
4679 /* Cannot add a menu if ... */
4680 if ((parent != NULL && parent->submenu_id == 0))
4681 return;
4682
4683 /* menu ID greater than 1024 are reserved for ??? */
4684 if (next_avail_id == 1024)
4685 return;
4686
4687 /* My brother could be the PopUp, find my real brother */
4688 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4689 brother = brother->next;
4690
4691 /* Find where to insert the menu (for MenuBar) */
4692 if ((parent == NULL) && (brother != NULL))
4693 menu_after_me = brother->submenu_id;
4694
4695 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4696 if (!menu_is_menubar(menu->name))
4697 menu_after_me = hierMenu;
4698
4699 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004700#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004701 name = menu_title_removing_mnemonic(menu);
4702#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004704#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 if (name == NULL)
4706 return;
4707
4708 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709 {
4710 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004711 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4712 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 */
4714 menu->submenu_id = next_avail_id;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004715 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4716 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717 next_avail_id++;
4718 }
4719
4720 if (parent == NULL)
4721 {
4722 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4723
4724 /* TODO: Verify if we could only Insert Menu if really part of the
4725 * menubar The Inserted menu are scanned or the Command-key combos
4726 */
4727
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004728 /* Insert the menu */
4729 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730#if 1
4731 /* Vim should normally update it. TODO: verify */
4732 DrawMenuBar();
4733#endif
4734 }
4735 else
4736 {
4737 /* Adding as a submenu */
4738
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004739 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740
4741 /* Call InsertMenuItem followed by SetMenuItemText
4742 * to avoid special character recognition by InsertMenuItem
4743 */
4744 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004745 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4747 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4748 InsertMenu(menu->submenu_handle, hierMenu);
4749 }
4750
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004751 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752
4753#if 0
4754 /* Done by Vim later on */
4755 DrawMenuBar();
4756#endif
4757}
4758
4759/*
4760 * Add a menu item to a menu
4761 */
4762 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004763gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004765 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766 vimmenu_T *parent = menu->parent;
4767 int menu_inserted;
4768
4769 /* Cannot add item, if the menu have not been created */
4770 if (parent->submenu_id == 0)
4771 return;
4772
4773 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4774 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4775
4776 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004777#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004778 name = menu_title_removing_mnemonic(menu);
4779#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004781#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782
4783 /* Where are just a menu item, so no handle, no id */
4784 menu->submenu_id = 0;
4785 menu->submenu_handle = NULL;
4786
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 menu_inserted = 0;
4788 if (menu->actext)
4789 {
4790 /* If the accelerator text for the menu item looks like it describes
4791 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4792 * item's command equivalent.
4793 */
4794 int key = 0;
4795 int modifiers = 0;
4796 char_u *p_actext;
4797
4798 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004799 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800 if (*p_actext != 0)
4801 key = 0; /* error: trailing text */
4802 /* find_special_key() returns a keycode with as many of the
4803 * specified modifiers as appropriate already applied (e.g., for
4804 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4805 * as the only modifier). Since we want to display all of the
4806 * modifiers, we need to convert the keycode back to a printable
4807 * character plus modifiers.
4808 * TODO: Write an alternative find_special_key() that doesn't
4809 * apply modifiers.
4810 */
4811 if (key > 0 && key < 32)
4812 {
4813 /* Convert a control key to an uppercase letter. Note that
4814 * by this point it is no longer possible to distinguish
4815 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4816 */
4817 modifiers |= MOD_MASK_CTRL;
4818 key += '@';
4819 }
4820 /* If the keycode is an uppercase letter, set the Shift modifier.
4821 * If it is a lowercase letter, don't set the modifier, but convert
4822 * the letter to uppercase for display in the menu.
4823 */
4824 else if (key >= 'A' && key <= 'Z')
4825 modifiers |= MOD_MASK_SHIFT;
4826 else if (key >= 'a' && key <= 'z')
4827 key += 'A' - 'a';
4828 /* Note: keycodes below 0x22 are reserved by Apple. */
4829 if (key >= 0x22 && vim_isprintc_strict(key))
4830 {
4831 int valid = 1;
4832 char_u mac_mods = kMenuNoModifiers;
4833 /* Convert Vim modifier codes to Menu Manager equivalents. */
4834 if (modifiers & MOD_MASK_SHIFT)
4835 mac_mods |= kMenuShiftModifier;
4836 if (modifiers & MOD_MASK_CTRL)
4837 mac_mods |= kMenuControlModifier;
4838 if (!(modifiers & MOD_MASK_CMD))
4839 mac_mods |= kMenuNoCommandModifier;
4840 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4841 valid = 0; /* TODO: will Alt someday map to Option? */
4842 if (valid)
4843 {
4844 char_u item_txt[10];
4845 /* Insert the menu item after idx, with its command key. */
4846 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4847 item_txt[3] = key;
4848 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4849 /* Set the modifier keys. */
4850 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4851 menu_inserted = 1;
4852 }
4853 }
4854 }
4855 /* Call InsertMenuItem followed by SetMenuItemText
4856 * to avoid special character recognition by InsertMenuItem
4857 */
4858 if (!menu_inserted)
4859 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4860 /* Set the menu item name. */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004861 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862
4863#if 0
4864 /* Called by Vim */
4865 DrawMenuBar();
4866#endif
4867
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004868 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869}
4870
4871 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004872gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873{
4874 /* no tearoff menus */
4875}
4876
4877/*
4878 * Destroy the machine specific menu widget.
4879 */
4880 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004881gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004883 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884
4885 if (index > 0)
4886 {
4887 if (menu->parent)
4888 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 {
4890 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004891 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892
4893 /* Delete the Menu if it was a hierarchical Menu */
4894 if (menu->submenu_id != 0)
4895 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004896 DeleteMenu(menu->submenu_id);
4897 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898 }
4899 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900 }
4901#ifdef DEBUG_MAC_MENU
4902 else
4903 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004904 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905 }
4906#endif
4907 }
4908 else
4909 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004911 DeleteMenu(menu->submenu_id);
4912 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913 }
4914 }
4915 /* Shouldn't this be already done by Vim. TODO: Check */
4916 DrawMenuBar();
4917}
4918
4919/*
4920 * Make a menu either grey or not grey.
4921 */
4922 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004923gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004924{
4925 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004926 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927/*
4928 index = menu->index;
4929*/
4930 if (grey)
4931 {
4932 if (menu->children)
4933 DisableMenuItem(menu->submenu_handle, index);
4934 if (menu->parent)
4935 if (menu->parent->submenu_handle)
4936 DisableMenuItem(menu->parent->submenu_handle, index);
4937 }
4938 else
4939 {
4940 if (menu->children)
4941 EnableMenuItem(menu->submenu_handle, index);
4942 if (menu->parent)
4943 if (menu->parent->submenu_handle)
4944 EnableMenuItem(menu->parent->submenu_handle, index);
4945 }
4946}
4947
4948/*
4949 * Make menu item hidden or not hidden
4950 */
4951 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004952gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953{
4954 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004955 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956}
4957
4958
4959/*
4960 * This is called after setting all the menus to grey/hidden or not.
4961 */
4962 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004963gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004964{
4965 DrawMenuBar();
4966}
4967
4968
4969/*
4970 * Scrollbar stuff.
4971 */
4972
4973 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004974gui_mch_enable_scrollbar(
4975 scrollbar_T *sb,
4976 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977{
4978 if (flag)
4979 ShowControl(sb->id);
4980 else
4981 HideControl(sb->id);
4982
4983#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004984 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985#endif
4986}
4987
4988 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004989gui_mch_set_scrollbar_thumb(
4990 scrollbar_T *sb,
4991 long val,
4992 long size,
4993 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994{
4995 SetControl32BitMaximum (sb->id, max);
4996 SetControl32BitMinimum (sb->id, 0);
4997 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004998 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02005000 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001#endif
5002}
5003
5004 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005005gui_mch_set_scrollbar_pos(
5006 scrollbar_T *sb,
5007 int x,
5008 int y,
5009 int w,
5010 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005011{
5012 gui_mch_set_bg_color(gui.back_pixel);
5013/* if (gui.which_scrollbars[SBAR_LEFT])
5014 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005015 MoveControl(sb->id, x-16, y);
5016 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 }
5018 else
5019 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005020 MoveControl(sb->id, x, y);
5021 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005022 }*/
5023 if (sb == &gui.bottom_sbar)
5024 h += 1;
5025 else
5026 w += 1;
5027
5028 if (gui.which_scrollbars[SBAR_LEFT])
5029 x -= 15;
5030
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005031 MoveControl(sb->id, x, y);
5032 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005034 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035#endif
5036}
5037
5038 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005039gui_mch_create_scrollbar(
5040 scrollbar_T *sb,
5041 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005042{
5043 Rect bounds;
5044
5045 bounds.top = -16;
5046 bounds.bottom = -10;
5047 bounds.right = -10;
5048 bounds.left = -16;
5049
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005050 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 &bounds,
5052 "\pScrollBar",
5053 TRUE,
5054 0, /* current*/
5055 0, /* top */
5056 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058 (long) sb->ident);
5059#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005060 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005061#endif
5062}
5063
5064 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005065gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005066{
5067 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005068 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005069#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005070 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071#endif
5072}
5073
Bram Moolenaar703a8042016-06-04 16:24:32 +02005074 int
5075gui_mch_is_blinking(void)
5076{
5077 return FALSE;
5078}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005079
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005080 int
5081gui_mch_is_blink_off(void)
5082{
5083 return FALSE;
5084}
5085
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086/*
5087 * Cursor blink functions.
5088 *
5089 * This is a simple state machine:
5090 * BLINK_NONE not blinking at all
5091 * BLINK_OFF blinking, cursor is not shown
5092 * BLINK_ON blinking, cursor is shown
5093 */
5094 void
5095gui_mch_set_blinking(long wait, long on, long off)
5096{
5097 /* TODO: TODO: TODO: TODO: */
5098/* blink_waittime = wait;
5099 blink_ontime = on;
5100 blink_offtime = off;*/
5101}
5102
5103/*
5104 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5105 */
5106 void
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005107gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005108{
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005109 if (may_call_gui_update_cursor)
5110 gui_update_cursor(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 /* TODO: TODO: TODO: TODO: */
5112/* gui_w32_rm_blink_timer();
5113 if (blink_state == BLINK_OFF)
5114 gui_update_cursor(TRUE, FALSE);
5115 blink_state = BLINK_NONE;*/
5116}
5117
5118/*
5119 * Start the cursor blinking. If it was already blinking, this restarts the
5120 * waiting time and shows the cursor.
5121 */
5122 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005123gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124{
5125 gui_update_cursor(TRUE, FALSE);
5126 /* TODO: TODO: TODO: TODO: */
5127/* gui_w32_rm_blink_timer(); */
5128
5129 /* Only switch blinking on if none of the times is zero */
5130/* if (blink_waittime && blink_ontime && blink_offtime)
5131 {
5132 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5133 (TIMERPROC)_OnBlinkTimer);
5134 blink_state = BLINK_ON;
5135 gui_update_cursor(TRUE, FALSE);
5136 }*/
5137}
5138
5139/*
5140 * Return the RGB value of a pixel as long.
5141 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005142 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143gui_mch_get_rgb(guicolor_T pixel)
5144{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005145 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005146}
5147
5148
5149
5150#ifdef FEAT_BROWSE
5151/*
5152 * Pop open a file browser and return the file selected, in allocated memory,
5153 * or NULL if Cancel is hit.
5154 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5155 * title - Title message for the file browser dialog.
5156 * dflt - Default name of file.
5157 * ext - Default extension to be added to files without extensions.
5158 * initdir - directory in which to open the browser (NULL = current dir)
5159 * filter - Filter for matched files to choose from.
5160 * Has a format like this:
5161 * "C Files (*.c)\0*.c\0"
5162 * "All Files\0*.*\0\0"
5163 * If these two strings were concatenated, then a choice of two file
5164 * filters will be selectable to the user. Then only matching files will
5165 * be shown in the browser. If NULL, the default allows all files.
5166 *
5167 * *NOTE* - the filter string must be terminated with TWO nulls.
5168 */
5169 char_u *
5170gui_mch_browse(
5171 int saving,
5172 char_u *title,
5173 char_u *dflt,
5174 char_u *ext,
5175 char_u *initdir,
5176 char_u *filter)
5177{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005178 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 NavReplyRecord reply;
5180 char_u *fname = NULL;
5181 char_u **fnames = NULL;
5182 long numFiles;
5183 NavDialogOptions navOptions;
5184 OSErr error;
5185
5186 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005187 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188
5189
5190 /* TODO: If we get a :browse args, set the Multiple bit. */
5191 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5192 | kNavDontAutoTranslate
5193 | kNavDontAddTranslateItems
5194 /* | kNavAllowMultipleFiles */
5195 | kNavAllowStationery;
5196
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005197 (void) C2PascalString(title, &navOptions.message);
5198 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199 /* Could set clientName?
5200 * windowTitle? (there's no title bar?)
5201 */
5202
5203 if (saving)
5204 {
5205 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005206 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005207 if (!reply.validRecord)
5208 return NULL;
5209 }
5210 else
5211 {
5212 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5213 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5214 if (!reply.validRecord)
5215 return NULL;
5216 }
5217
5218 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5219
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005220 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221
5222 if (fnames)
5223 {
5224 fname = fnames[0];
5225 vim_free(fnames);
5226 }
5227
5228 /* TODO: Shorten the file name if possible */
5229 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230}
5231#endif /* FEAT_BROWSE */
5232
5233#ifdef FEAT_GUI_DIALOG
5234/*
5235 * Stuff for dialogues
5236 */
5237
5238/*
5239 * Create a dialogue dynamically from the parameter strings.
5240 * type = type of dialogue (question, alert, etc.)
5241 * title = dialogue title. may be NULL for default title.
5242 * message = text to display. Dialogue sizes to accommodate it.
5243 * buttons = '\n' separated list of button captions, default first.
5244 * dfltbutton = number of default button.
5245 *
5246 * This routine returns 1 if the first button is pressed,
5247 * 2 for the second, etc.
5248 *
5249 * 0 indicates Esc was pressed.
5250 * -1 for unexpected error
5251 *
5252 * If stubbing out this fn, return 1.
5253 */
5254
5255typedef struct
5256{
5257 short idx;
5258 short width; /* Size of the text in pixel */
5259 Rect box;
5260} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5261
5262#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5263
5264 static void
5265macMoveDialogItem(
5266 DialogRef theDialog,
5267 short itemNumber,
5268 short X,
5269 short Y,
5270 Rect *inBox)
5271{
5272#if 0 /* USE_CARBONIZED */
5273 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005274 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005276 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005277#else
5278 short itemType;
5279 Handle itemHandle;
5280 Rect localBox;
5281 Rect *itemBox = &localBox;
5282
5283 if (inBox != nil)
5284 itemBox = inBox;
5285
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005286 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5287 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5288 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005289 /* To move a control (like a button) we need to call both
5290 * MoveControl and SetDialogItem. FAQ 6-18 */
5291 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005292 MoveControl((ControlRef) itemHandle, X, Y);
5293 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294#endif
5295}
5296
5297 static void
5298macSizeDialogItem(
5299 DialogRef theDialog,
5300 short itemNumber,
5301 short width,
5302 short height)
5303{
5304 short itemType;
5305 Handle itemHandle;
5306 Rect itemBox;
5307
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005308 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005309
5310 /* When width or height is zero do not change it */
5311 if (width == 0)
5312 width = itemBox.right - itemBox.left;
5313 if (height == 0)
5314 height = itemBox.bottom - itemBox.top;
5315
5316#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005317 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005318#else
5319 /* Resize the bounding box */
5320 itemBox.right = itemBox.left + width;
5321 itemBox.bottom = itemBox.top + height;
5322
5323 /* To resize a control (like a button) we need to call both
5324 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5325 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005326 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327
5328 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005329 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330#endif
5331}
5332
5333 static void
5334macSetDialogItemText(
5335 DialogRef theDialog,
5336 short itemNumber,
5337 Str255 itemName)
5338{
5339 short itemType;
5340 Handle itemHandle;
5341 Rect itemBox;
5342
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005343 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344
5345 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005346 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005347 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005348 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005349}
5350
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005351
5352/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5353 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5354 * setting gDialogHotKeys to NULL disables any hotkey handling.
5355 */
5356 static pascal Boolean
5357DialogHotkeyFilterProc (
5358 DialogRef theDialog,
5359 EventRecord *event,
5360 DialogItemIndex *itemHit)
5361{
5362 char_u keyHit;
5363
5364 if (event->what == keyDown || event->what == autoKey)
5365 {
5366 keyHit = (event->message & charCodeMask);
5367
5368 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5369 {
5370#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5371 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5372#endif
5373 *itemHit = gDialogHotKeys[keyHit];
5374
5375 /* When handing off to StdFilterProc, pretend that the user
5376 * clicked the control manually. Note that this is also supposed
5377 * to cause the button to hilite briefly (to give some user
5378 * feedback), but this seems not to actually work (or it's too
5379 * fast to be seen).
5380 */
5381 event->what = kEventControlSimulateHit;
5382
5383 return true; /* we took care of it */
5384 }
5385
5386 /* Defer to the OS's standard behavior for this event.
5387 * This ensures that Enter will still activate the default button. */
5388 return StdFilterProc(theDialog, event, itemHit);
5389 }
5390 return false; /* Let ModalDialog deal with it */
5391}
5392
5393
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005394/* TODO: There have been some crashes with dialogs, check your inbox
5395 * (Jussi)
5396 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397 int
5398gui_mch_dialog(
5399 int type,
5400 char_u *title,
5401 char_u *message,
5402 char_u *buttons,
5403 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005404 char_u *textfield,
5405 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005406{
5407 Handle buttonDITL;
5408 Handle iconDITL;
5409 Handle inputDITL;
5410 Handle messageDITL;
5411 Handle itemHandle;
5412 Handle iconHandle;
5413 DialogPtr theDialog;
5414 char_u len;
5415 char_u PascalTitle[256]; /* place holder for the title */
5416 char_u name[256];
5417 GrafPtr oldPort;
5418 short itemHit;
5419 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005420 short hotKeys[256]; /* map of hotkey -> control ID */
5421 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005422 Rect box;
5423 short button;
5424 short lastButton;
5425 short itemType;
5426 short useIcon;
5427 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005428 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005429 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005430 short widestButton = 0;
5431 short dfltButtonEdge = 20; /* gut feeling */
5432 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5433 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5434 short maximumWidth = 400; /* gut feeling */
5435 short maxButtonWidth = 175; /* gut feeling */
5436
5437 short vertical;
5438 short dialogHeight;
5439 short messageLines = 3;
5440 FontInfo textFontInfo;
5441
5442 vgmDlgItm iconItm;
5443 vgmDlgItm messageItm;
5444 vgmDlgItm inputItm;
5445 vgmDlgItm buttonItm;
5446
5447 WindowRef theWindow;
5448
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005449 ModalFilterUPP dialogUPP;
5450
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451 /* Check 'v' flag in 'guioptions': vertical button placement. */
5452 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5453
5454 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005455 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456
5457 /* Get the WindowRef */
5458 theWindow = GetDialogWindow(theDialog);
5459
5460 /* Hide the window.
5461 * 1. to avoid seeing slow drawing
5462 * 2. to prevent a problem seen while moving dialog item
5463 * within a visible window. (non-Carbon MacOS 9)
5464 * Could be avoided by changing the resource.
5465 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005466 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467
5468 /* Change the graphical port to the dialog,
5469 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005470 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005471 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005472
5473 /* Get the info about the default text,
5474 * used to calculate the height of the message
5475 * and of the text field */
5476 GetFontInfo(&textFontInfo);
5477
5478 /* Set the dialog title */
5479 if (title != NULL)
5480 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005481 (void) C2PascalString(title, &PascalTitle);
5482 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 }
5484
5485 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005486 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005487 buttonChar = buttons;
5488 button = 0;
5489
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005490 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005491 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005492
Bram Moolenaar071d4272004-06-13 20:20:40 +00005493 for (;*buttonChar != 0;)
5494 {
5495 /* Get the name of the button */
5496 button++;
5497 len = 0;
5498 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5499 {
5500 if (*buttonChar != DLG_HOTKEY_CHAR)
5501 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005502 else
5503 {
5504 aHotKey = (char_u)*(buttonChar+1);
5505 if (aHotKey >= 'A' && aHotKey <= 'Z')
5506 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5507 hotKeys[aHotKey] = button;
5508#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5509 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5510#endif
5511 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005512 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005513
Bram Moolenaar071d4272004-06-13 20:20:40 +00005514 if (*buttonChar != 0)
5515 buttonChar++;
5516 name[0] = len;
5517
5518 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005519 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520
5521 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005522 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523
5524 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005525 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005526 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 /* TODO: Should be based on the message width */
5528 if (width > maxButtonWidth)
5529 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005530 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531
5532 totalButtonWidth += width;
5533
5534 if (width > widestButton)
5535 widestButton = width;
5536 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005537 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005538 lastButton = button;
5539
5540 /* Add the icon to the Dialog Box. */
5541 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005542 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005543 switch (type)
5544 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005545 case VIM_GENERIC:
5546 case VIM_INFO:
5547 case VIM_QUESTION: useIcon = kNoteIcon; break;
5548 case VIM_WARNING: useIcon = kCautionIcon; break;
5549 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005550 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005551 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005552 AppendDITL(theDialog, iconDITL, overlayDITL);
5553 ReleaseResource(iconDITL);
5554 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005555 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005556 iconHandle = GetIcon(useIcon);
5557 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005558
5559 /* Add the message to the Dialog box. */
5560 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005561 messageDITL = GetResource('DITL', 132);
5562 AppendDITL(theDialog, messageDITL, overlayDITL);
5563 ReleaseResource(messageDITL);
5564 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5565 (void) C2PascalString(message, &name);
5566 SetDialogItemText(itemHandle, name);
5567 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005568
5569 /* Add the input box if needed */
5570 if (textfield != NULL)
5571 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005572 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005574 inputDITL = GetResource('DITL', 132);
5575 AppendDITL(theDialog, inputDITL, overlayDITL);
5576 ReleaseResource(inputDITL);
5577 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5578/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5579 (void) C2PascalString(textfield, &name);
5580 SetDialogItemText(itemHandle, name);
5581 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005582
5583 /* Hotkeys don't make sense if there's a text field */
5584 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005585 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005586 else
5587 /* Install hotkey table */
5588 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589
5590 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005591 SetDialogDefaultItem(theDialog, dfltbutton);
5592 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005593
5594 /* Reposition element */
5595
5596 /* Check if we need to force vertical */
5597 if (totalButtonWidth > maximumWidth)
5598 vertical = TRUE;
5599
5600 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005601 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005602 iconItm.box.right = box.right;
5603 iconItm.box.bottom = box.bottom;
5604
5605 /* Place Message */
5606 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005607 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5608 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609
5610 /* Place Input */
5611 if (textfield != NULL)
5612 {
5613 inputItm.box.left = messageItm.box.left;
5614 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005615 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5616 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 /* Convert the static text into a text edit.
5618 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005619 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5620 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5622 }
5623
5624 /* Place Button */
5625 if (textfield != NULL)
5626 {
5627 buttonItm.box.left = inputItm.box.left;
5628 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5629 }
5630 else
5631 {
5632 buttonItm.box.left = messageItm.box.left;
5633 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5634 }
5635
5636 for (button=1; button <= lastButton; button++)
5637 {
5638
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005639 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005640 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005641 if (vertical)
5642 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005643 macSizeDialogItem(theDialog, button, widestButton, 0);
5644 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645 }
5646 /* Calculate position of next button */
5647 if (vertical)
5648 buttonItm.box.top = box.bottom + dfltElementSpacing;
5649 else
5650 buttonItm.box.left = box.right + dfltElementSpacing;
5651 }
5652
5653 /* Resize the dialog box */
5654 dialogHeight = box.bottom + dfltElementSpacing;
5655 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5656
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005658 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005659 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660
5661 /* Display it */
5662 ShowWindow(theWindow);
5663/* BringToFront(theWindow); */
5664 SelectWindow(theWindow);
5665
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005666/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005668 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005669 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670#endif
5671
Bram Moolenaard68071d2006-05-02 22:08:30 +00005672#ifdef USE_CARBONKEYHANDLER
5673 /* Avoid that we use key events for the main window. */
5674 dialog_busy = TRUE;
5675#endif
5676
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005677 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5678 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5679
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 /* Hang until one of the button is hit */
5681 do
5682 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005683 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684 } while ((itemHit < 1) || (itemHit > lastButton));
5685
Bram Moolenaard68071d2006-05-02 22:08:30 +00005686#ifdef USE_CARBONKEYHANDLER
5687 dialog_busy = FALSE;
5688#endif
5689
Bram Moolenaar071d4272004-06-13 20:20:40 +00005690 /* Copy back the text entered by the user into the param */
5691 if (textfield != NULL)
5692 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005693 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5694 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695#if IOSIZE < 256
5696 /* Truncate the name to IOSIZE if needed */
5697 if (name[0] > IOSIZE)
5698 name[0] = IOSIZE - 1;
5699#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005700 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701 }
5702
5703 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005704 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005706 /* Free the modal filterProc */
5707 DisposeRoutineDescriptor(dialogUPP);
5708
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005709 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005710 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711
5712 return itemHit;
5713/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005714 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005715 * SetDialogTimeout(): Auto click a button after timeout
5716 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5717 * MoveDialogItem(): Probably better than SetDialogItem
5718 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005719 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 */
5721}
5722#endif /* FEAT_DIALOG_GUI */
5723
5724/*
5725 * Display the saved error message(s).
5726 */
5727#ifdef USE_MCH_ERRMSG
5728 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005729display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005730{
5731 char *p;
5732 char_u pError[256];
5733
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005734 if (error_ga.ga_data == NULL)
5735 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005737 /* avoid putting up a message box with blanks only */
5738 for (p = (char *)error_ga.ga_data; *p; ++p)
5739 if (!isspace(*p))
5740 {
5741 if (STRLEN(p) > 255)
5742 pError[0] = 255;
5743 else
5744 pError[0] = STRLEN(p);
5745
5746 STRNCPY(&pError[1], p, pError[0]);
5747 ParamText(pError, nil, nil, nil);
5748 Alert(128, nil);
5749 break;
5750 /* TODO: handled message longer than 256 chars
5751 * use auto-sizeable alert
5752 * or dialog with scrollbars (TextEdit zone)
5753 */
5754 }
5755 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005756}
5757#endif
5758
5759/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005760 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005761 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005762 void
5763gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005764{
5765 Point where;
5766
5767 GetMouse(&where);
5768
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005769 *x = where.h;
5770 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771}
5772
5773 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005774gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775{
5776 /* TODO */
5777#if 0
5778 /* From FAQ 3-11 */
5779
5780 CursorDevicePtr myMouse;
5781 Point where;
5782
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005783 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5784 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005785 {
5786 /* New way */
5787
5788 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005789 * Get first device with one button.
5790 * This will probably be the standard mouse
5791 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792 *
5793 */
5794
5795 myMouse = nil;
5796
5797 do
5798 {
5799 /* Get the next cursor device */
5800 CursorDeviceNextDevice(&myMouse);
5801 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005802 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005803
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005804 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005805 }
5806 else
5807 {
5808 /* Old way */
5809 where.h = x;
5810 where.v = y;
5811
5812 *(Point *)RawMouse = where;
5813 *(Point *)MTemp = where;
5814 *(Ptr) CrsrNew = 0xFFFF;
5815 }
5816#endif
5817}
5818
5819 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005820gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005821{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822/*
5823 * Clone PopUp to use menu
5824 * Create a object descriptor for the current selection
5825 * Call the procedure
5826 */
5827
5828 MenuHandle CntxMenu;
5829 Point where;
5830 OSStatus status;
5831 UInt32 CntxType;
5832 SInt16 CntxMenuID;
5833 UInt16 CntxMenuItem;
5834 Str255 HelpName = "";
5835 GrafPtr savePort;
5836
5837 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005838 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005840 GetMouse(&where);
5841 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842 CntxMenu = menu->submenu_handle;
5843
5844 /* TODO: Get the text selection from Vim */
5845
5846 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005847 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005848 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849
5850 if (status == noErr)
5851 {
5852 if (CntxType == kCMMenuItemSelected)
5853 {
5854 /* Handle the menu CntxMenuID, CntxMenuItem */
5855 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005856 /* But what about the current menu, is the menu changed by
5857 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005858 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005859 }
5860 else if (CntxMenuID == kCMShowHelpSelected)
5861 {
5862 /* Should come up with the help */
5863 }
5864 }
5865
5866 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005867 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868}
5869
5870#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5871/* TODO: Is it need for MACOS_X? (Dany) */
5872 void
5873mch_post_buffer_write(buf_T *buf)
5874{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005875 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5876 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877}
5878#endif
5879
5880#ifdef FEAT_TITLE
5881/*
5882 * Set the window title and icon.
5883 * (The icon is not taken care of).
5884 */
5885 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005886gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005887{
5888 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5889 * that 256. Even better get it to fit nicely in the titlebar.
5890 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005891#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005892 CFStringRef windowTitle;
5893 size_t windowTitleLen;
5894#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005896#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005897
5898 if (title == NULL) /* nothing to do */
5899 return;
5900
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005901#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005902 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005903 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005904
5905 if (windowTitle)
5906 {
5907 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5908 CFRelease(windowTitle);
5909 }
5910#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911 pascalTitle = C2Pascal_save(title);
5912 if (pascalTitle != NULL)
5913 {
5914 SetWTitle(gui.VimWindow, pascalTitle);
5915 vim_free(pascalTitle);
5916 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005917#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005918}
5919#endif
5920
5921/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005922 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923 */
5924
5925 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005926C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005927{
5928 char_u *PascalPtr = (char_u *) PascalString;
5929 int len;
5930 int i;
5931
5932 PascalPtr[0] = 0;
5933 if (CString == NULL)
5934 return 0;
5935
5936 len = STRLEN(CString);
5937 if (len > 255)
5938 len = 255;
5939
5940 for (i = 0; i < len; i++)
5941 PascalPtr[i+1] = CString[i];
5942
5943 PascalPtr[0] = len;
5944
5945 return 0;
5946}
5947
5948 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005949GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950{
5951 /* From FAQ 8-12 */
5952 Str255 filePascal;
5953 CInfoPBRec myCPB;
5954 OSErr err;
5955
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005956 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005957
5958 myCPB.dirInfo.ioNamePtr = filePascal;
5959 myCPB.dirInfo.ioVRefNum = 0;
5960 myCPB.dirInfo.ioFDirIndex = 0;
5961 myCPB.dirInfo.ioDrDirID = 0;
5962
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005963 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964
5965 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005966 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005967
5968 /* TODO: Use an error code mechanism */
5969 return 0;
5970}
5971
5972/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005973 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974 */
5975
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005976char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005977{
5978 /*
5979 * TODO: Add protection for 256 char max.
5980 */
5981
5982 CInfoPBRec theCPB;
5983 char_u fname[256];
5984 char_u *filenamePtr = fname;
5985 OSErr error;
5986 int folder = 1;
5987#ifdef USE_UNIXFILENAME
5988 SInt16 dfltVol_vRefNum;
5989 SInt32 dfltVol_dirID;
5990 FSRef refFile;
5991 OSStatus status;
5992 UInt32 pathSize = 256;
5993 char_u pathname[256];
5994 char_u *path = pathname;
5995#else
5996 Str255 directoryName;
5997 char_u temporary[255];
5998 char_u *temporaryPtr = temporary;
5999#endif
6000
6001#ifdef USE_UNIXFILENAME
6002 /* Get the default volume */
6003 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006004 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005
6006 if (error)
6007 return NULL;
6008#endif
6009
6010 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006011 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012
6013 /* Get the info about the file specified in FSSpec */
6014 theCPB.dirInfo.ioFDirIndex = 0;
6015 theCPB.dirInfo.ioNamePtr = file.name;
6016 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006017 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006018 theCPB.dirInfo.ioDrDirID = file.parID;
6019
6020 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6021 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006022 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006023
6024 /* If we are called for a new file we expect fnfErr */
6025 if ((error) && (error != fnfErr))
6026 return NULL;
6027
6028 /* Check if it's a file or folder */
6029 /* default to file if file don't exist */
6030 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6031 folder = 0; /* It's not a folder */
6032 else
6033 folder = 1;
6034
6035#ifdef USE_UNIXFILENAME
6036 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006037 * The functions used here are available in Carbon, but do nothing on
6038 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006039 */
6040 if (error == fnfErr)
6041 {
6042 /* If the file to be saved does not already exist, it isn't possible
6043 to convert its FSSpec into an FSRef. But we can construct an
6044 FSSpec for the file's parent folder (since we have its volume and
6045 directory IDs), and since that folder does exist, we can convert
6046 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6047 and, finally, append the filename. */
6048 FSSpec dirSpec;
6049 FSRef dirRef;
6050 Str255 emptyFilename = "\p";
6051 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6052 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6053 if (error)
6054 return NULL;
6055
6056 error = FSpMakeFSRef(&dirSpec, &dirRef);
6057 if (error)
6058 return NULL;
6059
6060 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6061 if (status)
6062 return NULL;
6063
6064 STRCAT(path, "/");
6065 STRCAT(path, filenamePtr);
6066 }
6067 else
6068 {
6069 /* If the file to be saved already exists, we can get its full path
6070 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006071 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 if (error)
6073 return NULL;
6074
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006075 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006076 if (status)
6077 return NULL;
6078 }
6079
6080 /* Add a slash at the end if needed */
6081 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006082 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006084 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006085#else
6086 /* TODO: Get rid of all USE_UNIXFILENAME below */
6087 /* Set ioNamePtr, it's the same area which is always reused. */
6088 theCPB.dirInfo.ioNamePtr = directoryName;
6089
6090 /* Trick for first entry, set ioDrParID to the first value
6091 * we want for ioDrDirID*/
6092 theCPB.dirInfo.ioDrParID = file.parID;
6093 theCPB.dirInfo.ioDrDirID = file.parID;
6094
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006095 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096 do
6097 {
6098 theCPB.dirInfo.ioFDirIndex = -1;
6099 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6100 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006101 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6103
6104 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6105 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006106 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107
6108 if (error)
6109 return NULL;
6110
6111 /* Put the new directoryName in front of the current fname */
6112 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006113 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006114 STRCAT(filenamePtr, ":");
6115 STRCAT(filenamePtr, temporaryPtr);
6116 }
6117#if 1 /* def USE_UNIXFILENAME */
6118 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6119 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6120#else
6121 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6122#endif
6123
6124 /* Get the information about the volume on which the file reside */
6125 theCPB.dirInfo.ioFDirIndex = -1;
6126 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6127 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006128 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006129 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6130
6131 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6132 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006133 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134
6135 if (error)
6136 return NULL;
6137
6138 /* For MacOS Classic always add the volume name */
6139 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006140 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141#ifdef USE_UNIXFILENAME
6142 if (file.vRefNum != dfltVol_vRefNum)
6143#endif
6144 {
6145 /* Add the volume name */
6146 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006147 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006148 STRCAT(filenamePtr, ":");
6149 STRCAT(filenamePtr, temporaryPtr);
6150
6151#ifdef USE_UNIXFILENAME
6152 STRCPY(temporaryPtr, filenamePtr);
6153 filenamePtr[0] = 0; /* NULL terminate the string */
6154 STRCAT(filenamePtr, "Volumes:");
6155 STRCAT(filenamePtr, temporaryPtr);
6156#endif
6157 }
6158
6159 /* Append final path separator if it's a folder */
6160 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006161 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006162
6163 /* As we use Unix File Name for MacOS X convert it */
6164#ifdef USE_UNIXFILENAME
6165 /* Need to insert leading / */
6166 /* TODO: get the above code to use directly the / */
6167 STRCPY(&temporaryPtr[1], filenamePtr);
6168 temporaryPtr[0] = '/';
6169 STRCPY(filenamePtr, temporaryPtr);
6170 {
6171 char *p;
6172 for (p = fname; *p; p++)
6173 if (*p == ':')
6174 *p = '/';
6175 }
6176#endif
6177
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006178 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179#endif
6180}
6181
Bram Moolenaar13505972019-01-24 15:04:48 +01006182#if defined(USE_CARBONKEYHANDLER) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006183/*
6184 * Input Method Control functions.
6185 */
6186
6187/*
6188 * Notify cursor position to IM.
6189 */
6190 void
6191im_set_position(int row, int col)
6192{
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006193# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006195 im_start_row = row;
6196 im_start_col = col;
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006197# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006198}
6199
6200static ScriptLanguageRecord gTSLWindow;
6201static ScriptLanguageRecord gTSLInsert;
6202static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6203
6204static Component gTSCWindow;
6205static Component gTSCInsert;
6206static Component gTSCDefault;
6207
6208static int im_initialized = 0;
6209
6210 static void
6211im_on_window_switch(int active)
6212{
6213 ScriptLanguageRecord *slptr = NULL;
6214 OSStatus err;
6215
6216 if (! gui.in_use)
6217 return;
6218
6219 if (im_initialized == 0)
6220 {
6221 im_initialized = 1;
6222
6223 /* save default TSM component (should be U.S.) to default */
6224 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6225 kKeyboardInputMethodClass);
6226 }
6227
6228 if (active == TRUE)
6229 {
6230 im_is_active = TRUE;
6231 ActivateTSMDocument(gTSMDocument);
6232 slptr = &gTSLWindow;
6233
6234 if (slptr)
6235 {
6236 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6237 kKeyboardInputMethodClass);
6238 if (err == noErr)
6239 err = SetTextServiceLanguage(slptr);
6240
6241 if (err == noErr)
6242 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6243 }
6244 }
6245 else
6246 {
6247 err = GetTextServiceLanguage(&gTSLWindow);
6248 if (err == noErr)
6249 slptr = &gTSLWindow;
6250
6251 if (slptr)
6252 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6253 kKeyboardInputMethodClass);
6254
6255 im_is_active = FALSE;
6256 DeactivateTSMDocument(gTSMDocument);
6257 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258}
6259
6260/*
6261 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6262 */
6263 void
6264im_set_active(int active)
6265{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006266 ScriptLanguageRecord *slptr = NULL;
6267 OSStatus err;
6268
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006269 if (!gui.in_use)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006270 return;
6271
6272 if (im_initialized == 0)
6273 {
6274 im_initialized = 1;
6275
6276 /* save default TSM component (should be U.S.) to default */
6277 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6278 kKeyboardInputMethodClass);
6279 }
6280
6281 if (active == TRUE)
6282 {
6283 im_is_active = TRUE;
6284 ActivateTSMDocument(gTSMDocument);
6285 slptr = &gTSLInsert;
6286
6287 if (slptr)
6288 {
6289 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6290 kKeyboardInputMethodClass);
6291 if (err == noErr)
6292 err = SetTextServiceLanguage(slptr);
6293
6294 if (err == noErr)
6295 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6296 }
6297 }
6298 else
6299 {
6300 err = GetTextServiceLanguage(&gTSLInsert);
6301 if (err == noErr)
6302 slptr = &gTSLInsert;
6303
6304 if (slptr)
6305 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6306 kKeyboardInputMethodClass);
6307
6308 /* restore to default when switch to normal mode, so than we could
6309 * enter commands easier */
6310 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6311 kKeyboardInputMethodClass);
6312 SetTextServiceLanguage(&gTSLDefault);
6313
6314 im_is_active = FALSE;
6315 DeactivateTSMDocument(gTSMDocument);
6316 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006317}
6318
6319/*
6320 * Get IM status. When IM is on, return not 0. Else return 0.
6321 */
6322 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006323im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006324{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006325 if (! gui.in_use)
6326 return 0;
6327
6328 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006330
Bram Moolenaar13505972019-01-24 15:04:48 +01006331#endif
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006332
6333
6334
6335#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6336// drawer implementation
6337static MenuRef contextMenu = NULL;
6338enum
6339{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006340 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006341};
6342
6343// the caller has to CFRelease() the returned string
6344 static CFStringRef
6345getTabLabel(tabpage_T *page)
6346{
6347 get_tabline_label(page, FALSE);
6348#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006349 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006350#else
6351 // TODO: check internal encoding?
6352 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6353 kCFStringEncodingMacRoman);
6354#endif
6355}
6356
6357
6358#define DRAWER_SIZE 150
6359#define DRAWER_INSET 16
6360
6361static ControlRef dataBrowser = NULL;
6362
6363// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006364// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006365// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006366// for a very short time. to prevent inconsistent state, we store the labels
6367// of the tabs, not pointers to the tabs (which are invalid for a short time).
6368static CFStringRef *tabLabels = NULL;
6369static int tabLabelsSize = 0;
6370
6371enum
6372{
6373 kTabsColumn = 'Tabs'
6374};
6375
6376 static int
6377getTabCount(void)
6378{
6379 tabpage_T *tp;
6380 int numTabs = 0;
6381
Bram Moolenaar29323592016-07-24 22:04:11 +02006382 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006383 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006384 return numTabs;
6385}
6386
6387// data browser item display callback
6388 static OSStatus
6389dbItemDataCallback(ControlRef browser,
6390 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006391 DataBrowserPropertyID property /* column id */,
6392 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006393 Boolean changeValue)
6394{
6395 OSStatus status = noErr;
6396
6397 // assert(property == kTabsColumn); // why is this violated??
6398
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006399 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006400 // In our case, it's always false.
6401 // (that is: if (changeValue) updateInternalData(); else return
6402 // internalData();
6403 if (!changeValue)
6404 {
6405 CFStringRef str;
6406
6407 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6408 str = tabLabels[itemID - 1];
6409 status = SetDataBrowserItemDataText(itemData, str);
6410 }
6411 else
6412 status = errDataBrowserPropertyNotSupported;
6413
6414 return status;
6415}
6416
6417// data browser action callback
6418 static void
6419dbItemNotificationCallback(ControlRef browser,
6420 DataBrowserItemID item,
6421 DataBrowserItemNotification message)
6422{
6423 switch (message)
6424 {
6425 case kDataBrowserItemSelected:
6426 send_tabline_event(item);
6427 break;
6428 }
6429}
6430
6431// callbacks needed for contextual menu:
6432 static void
6433dbGetContextualMenuCallback(ControlRef browser,
6434 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006435 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006436 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006437 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006438{
6439 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6440 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6441 *helpItemString = NULL;
6442
6443 *menu = contextMenu;
6444}
6445
6446 static void
6447dbSelectContextualMenuCallback(ControlRef browser,
6448 MenuRef menu,
6449 UInt32 selectionType,
6450 SInt16 menuID,
6451 MenuItemIndex menuItem)
6452{
6453 if (selectionType == kCMMenuItemSelected)
6454 {
6455 MenuCommand command;
6456 GetMenuItemCommandID(menu, menuItem, &command);
6457
6458 // get tab that was selected when the context menu appeared
6459 // (there is always one tab selected). TODO: check if the context menu
6460 // isn't opened on an item but on empty space (has to be possible some
6461 // way, the finder does it too ;-) )
6462 Handle items = NewHandle(0);
6463 if (items != NULL)
6464 {
6465 int numItems;
6466
6467 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6468 kDataBrowserItemIsSelected, items);
6469 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6470 if (numItems > 0)
6471 {
6472 int idx;
6473 DataBrowserItemID *itemsPtr;
6474
6475 HLock(items);
6476 itemsPtr = (DataBrowserItemID *)*items;
6477 idx = itemsPtr[0];
6478 HUnlock(items);
6479 send_tabline_menu_event(idx, command);
6480 }
6481 DisposeHandle(items);
6482 }
6483 }
6484}
6485
6486// focus callback of the data browser to always leave focus in vim
6487 static OSStatus
6488dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6489{
6490 assert(GetEventClass(event) == kEventClassControl
6491 && GetEventKind(event) == kEventControlSetFocusPart);
6492
6493 return paramErr;
6494}
6495
6496
6497// drawer callback to resize data browser to drawer size
6498 static OSStatus
6499drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6500{
6501 switch (GetEventKind(event))
6502 {
6503 case kEventWindowBoundsChanged: // move or resize
6504 {
6505 UInt32 attribs;
6506 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6507 NULL, sizeof(attribs), NULL, &attribs);
6508 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6509 {
6510 Rect r;
6511 GetWindowBounds(drawer, kWindowContentRgn, &r);
6512 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6513 SetControlBounds(dataBrowser, &r);
6514 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6515 kTabsColumn, r.right);
6516 }
6517 }
6518 break;
6519 }
6520
6521 return eventNotHandledErr;
6522}
6523
6524// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6525// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6526// blue highlights in the list view on these systems, though. Oh well.)
6527
6528
6529#import <mach-o/dyld.h>
6530
6531enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6532
6533 static OSStatus
6534myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6535 OptionBits inAttributesToSet,
6536 OptionBits inAttributesToClear)
6537{
6538 long osVersion;
6539 char *symbolName;
6540 NSSymbol symbol = NULL;
6541 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6542 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6543
6544 Gestalt(gestaltSystemVersion, &osVersion);
6545 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6546 return noErr;
6547
6548 // C name mangling...
6549 symbolName = "_DataBrowserChangeAttributes";
6550 if (!NSIsSymbolNameDefined(symbolName)
6551 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6552 return noErr;
6553
6554 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6555 if (dataBrowserChangeAttributes == NULL)
6556 return noErr; // well...
6557 return dataBrowserChangeAttributes(inDataBrowser,
6558 inAttributesToSet, inAttributesToClear);
6559}
6560
6561 static void
6562initialise_tabline(void)
6563{
6564 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6565 DataBrowserCallbacks dbCallbacks;
6566 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6567 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6568 DataBrowserListViewColumnDesc colDesc;
6569
6570 // drawers have to have compositing enabled
6571 CreateNewWindow(kDrawerWindowClass,
6572 kWindowStandardHandlerAttribute
6573 | kWindowCompositingAttribute
6574 | kWindowResizableAttribute
6575 | kWindowLiveResizeAttribute,
6576 &drawerRect, &drawer);
6577
6578 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6579 SetDrawerParent(drawer, gui.VimWindow);
6580 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6581
6582
6583 // create list view embedded in drawer
6584 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6585 &dataBrowser);
6586
6587 dbCallbacks.version = kDataBrowserLatestCallbacks;
6588 InitDataBrowserCallbacks(&dbCallbacks);
6589 dbCallbacks.u.v1.itemDataCallback =
6590 NewDataBrowserItemDataUPP(dbItemDataCallback);
6591 dbCallbacks.u.v1.itemNotificationCallback =
6592 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6593 dbCallbacks.u.v1.getContextualMenuCallback =
6594 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6595 dbCallbacks.u.v1.selectContextualMenuCallback =
6596 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6597
6598 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6599
6600 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6601 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6602 SetDataBrowserSelectionFlags(dataBrowser,
6603 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6604 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6605 kDataBrowserTableViewFillHilite);
6606 Boolean b = false;
6607 SetControlData(dataBrowser, kControlEntireControl,
6608 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6609
6610 // enable blue background in data browser (this is only in 10.4 and vim
6611 // has to support older osx versions as well, so we have to load this
6612 // function dynamically)
6613 myDataBrowserChangeAttributes(dataBrowser,
6614 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6615
6616 // install callback that keeps focus in vim and away from the data browser
6617 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6618 NULL, NULL);
6619
6620 // install callback that keeps data browser at the size of the drawer
6621 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6622 NULL, NULL);
6623
6624 // add "tabs" column to data browser
6625 colDesc.propertyDesc.propertyID = kTabsColumn;
6626 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6627
6628 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6629 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6630
6631 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6632 colDesc.headerBtnDesc.minimumWidth = 100;
6633 colDesc.headerBtnDesc.maximumWidth = 150;
6634 colDesc.headerBtnDesc.titleOffset = 0;
6635 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6636 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6637 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6638 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6639
6640 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6641
6642 // create tabline popup menu required by vim docs (see :he tabline-menu)
6643 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar29547192018-12-11 20:39:19 +01006644 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006645 TABLINE_MENU_CLOSE, NULL);
6646 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6647 TABLINE_MENU_NEW, NULL);
6648 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6649 TABLINE_MENU_OPEN, NULL);
6650}
6651
6652
6653/*
6654 * Show or hide the tabline.
6655 */
6656 void
6657gui_mch_show_tabline(int showit)
6658{
6659 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006660 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006661 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006662 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006663}
6664
6665/*
6666 * Return TRUE when tabline is displayed.
6667 */
6668 int
6669gui_mch_showing_tabline(void)
6670{
6671 WindowDrawerState state = GetDrawerState(drawer);
6672
6673 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6674}
6675
6676/*
6677 * Update the labels of the tabline.
6678 */
6679 void
6680gui_mch_update_tabline(void)
6681{
6682 tabpage_T *tp;
6683 int numTabs = getTabCount();
6684 int nr = 1;
6685 int curtabidx = 1;
6686
6687 // adjust data browser
6688 if (tabLabels != NULL)
6689 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006690 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006691
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006692 for (i = 0; i < tabLabelsSize; ++i)
6693 CFRelease(tabLabels[i]);
6694 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006695 }
6696 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6697 tabLabelsSize = numTabs;
6698
6699 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6700 {
6701 if (tp == curtab)
6702 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006703 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006704 }
6705
6706 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6707 kDataBrowserItemNoProperty);
6708 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6709 // can pass NULL for the id array
6710 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6711 kDataBrowserItemNoProperty);
6712
6713 DataBrowserItemID item = curtabidx;
6714 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6715}
6716
6717/*
6718 * Set the current tab to "nr". First tab is 1.
6719 */
6720 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006721gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006722{
6723 DataBrowserItemID item = nr;
6724 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6725
6726 // TODO: call something like this?: (or restore scroll position, or...)
6727 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6728 kDataBrowserRevealOnly);
6729}
6730
6731#endif // FEAT_GUI_TABLINE