blob: bfecf81e65e0e96303dffa81f81762a1574aea74 [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#endif
1346
1347 return error;
1348
1349}
1350#endif /* USE_AEVENT */
1351
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001352
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001353/*
1354 * Callback function, installed by InstallFontPanelHandler(), below,
1355 * to handle Font Panel events.
1356 */
1357 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001358FontPanelHandler(
1359 EventHandlerCallRef inHandlerCallRef,
1360 EventRef inEvent,
1361 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001362{
1363 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1364 {
1365 gFontPanelInfo.isPanelVisible = false;
1366 return noErr;
1367 }
1368
1369 if (GetEventKind(inEvent) == kEventFontSelection)
1370 {
1371 OSStatus status;
1372 FMFontFamily newFamily;
1373 FMFontSize newSize;
1374 FMFontStyle newStyle;
1375
1376 /* Retrieve the font family ID number. */
1377 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1378 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1379 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1380 &newFamily);
1381 if (status == noErr)
1382 gFontPanelInfo.family = newFamily;
1383
1384 /* Retrieve the font size. */
1385 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1386 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1387 if (status == noErr)
1388 gFontPanelInfo.size = newSize;
1389
1390 /* Retrieve the font style (bold, etc.). Currently unused. */
1391 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1392 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1393 if (status == noErr)
1394 gFontPanelInfo.style = newStyle;
1395 }
1396 return noErr;
1397}
1398
1399
1400 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001401InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001402{
1403 EventTypeSpec eventTypes[2];
1404 EventHandlerUPP handlerUPP;
1405 /* EventHandlerRef handlerRef; */
1406
1407 eventTypes[0].eventClass = kEventClassFont;
1408 eventTypes[0].eventKind = kEventFontSelection;
1409 eventTypes[1].eventClass = kEventClassFont;
1410 eventTypes[1].eventKind = kEventFontPanelClosed;
1411
1412 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1413
1414 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1415 /*userData=*/NULL, /*handlerRef=*/NULL);
1416}
1417
1418
1419/*
1420 * Fill the buffer pointed to by outName with the name and size
1421 * of the font currently selected in the Font Panel.
1422 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001424 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001425GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001426{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001427 Str255 buf;
1428 ByteCount fontNameLen = 0;
1429 ATSUFontID fid;
1430 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001431
1432 if (!outName)
1433 return;
1434
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001435 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1436 {
1437 /* Canonicalize localized font names */
1438 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1439 gFontPanelInfo.style, &fid, NULL) != noErr)
1440 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001441
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001442 /* Request font name with Mac encoding (otherwise we could
1443 * get an unwanted utf-16 name) */
1444 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1445 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001446 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001447 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001448
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001449 /* Only encode font size, because style (bold, italic, etc) is
1450 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001451 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001452 gFontPanelInfo.size/*,
1453 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1454 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1455 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1456
1457 if ((fontNameLen + STRLEN(styleString)) < 255)
1458 STRCPY(outName + fontNameLen, styleString);
1459 }
1460 else
1461 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001462 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001463 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001464}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001465
1466
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467/*
1468 * ------------------------------------------------------------
1469 * Unfiled yet
1470 * ------------------------------------------------------------
1471 */
1472
1473/*
1474 * gui_mac_get_menu_item_index
1475 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001476 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001477 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001478 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001479gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480{
1481 short index;
1482 short itemIndex = -1;
1483 vimmenu_T *pBrother;
1484
1485 /* Only menu without parent are the:
1486 * -menu in the menubar
1487 * -popup menu
1488 * -toolbar (guess)
1489 *
1490 * Which are not items anyway.
1491 */
1492 if (pMenu->parent)
1493 {
1494 /* Start from the Oldest Brother */
1495 pBrother = pMenu->parent->children;
1496 index = 1;
1497 while ((pBrother) && (itemIndex == -1))
1498 {
1499 if (pBrother == pMenu)
1500 itemIndex = index;
1501 index++;
1502 pBrother = pBrother->next;
1503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 }
1505 return itemIndex;
1506}
1507
1508 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001509gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510{
1511 short index;
1512 vimmenu_T *pChildMenu;
1513 vimmenu_T *pElder = pMenu->parent;
1514
1515
1516 /* Only menu without parent are the:
1517 * -menu in the menubar
1518 * -popup menu
1519 * -toolbar (guess)
1520 *
1521 * Which are not items anyway.
1522 */
1523
1524 if ((pElder) && (pElder->submenu_id == menuID))
1525 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1527 pMenu = pMenu->next;
1528 }
1529 else
1530 {
1531 for (; pMenu != NULL; pMenu = pMenu->next)
1532 {
1533 if (pMenu->children != NULL)
1534 {
1535 pChildMenu = gui_mac_get_vim_menu
1536 (menuID, itemIndex, pMenu->children);
1537 if (pChildMenu)
1538 {
1539 pMenu = pChildMenu;
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 return pMenu;
1546}
1547
1548/*
1549 * ------------------------------------------------------------
1550 * MacOS Feedback procedures
1551 * ------------------------------------------------------------
1552 */
1553 pascal
1554 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001555gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556{
1557 scrollbar_T *sb;
1558 int value, dragging;
1559 ControlHandle theControlToUse;
1560 int dont_scroll_save = dont_scroll;
1561
1562 theControlToUse = dragged_sb;
1563
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001564 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565
1566 if (sb == NULL)
1567 return;
1568
1569 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001570 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 dragging = (partCode != 0);
1572
1573 /* When "allow_scrollbar" is FALSE still need to remember the new
1574 * position, but don't actually scroll by setting "dont_scroll". */
1575 dont_scroll = !allow_scrollbar;
1576 gui_drag_scrollbar(sb, value, dragging);
1577 dont_scroll = dont_scroll_save;
1578}
1579
1580 pascal
1581 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001582gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583{
1584 /* TODO: have live support */
1585 scrollbar_T *sb, *sb_info;
1586 long data;
1587 long value;
1588 int page;
1589 int dragging = FALSE;
1590 int dont_scroll_save = dont_scroll;
1591
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001592 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 if (sb == NULL)
1595 return;
1596
1597 if (sb->wp != NULL) /* Left or right scrollbar */
1598 {
1599 /*
1600 * Careful: need to get scrollbar info out of first (left) scrollbar
1601 * for window, but keep real scrollbar too because we must pass it to
1602 * gui_drag_scrollbar().
1603 */
1604 sb_info = &sb->wp->w_scrollbars[0];
1605
1606 if (sb_info->size > 5)
1607 page = sb_info->size - 2; /* use two lines of context */
1608 else
1609 page = sb_info->size;
1610 }
1611 else /* Bottom scrollbar */
1612 {
1613 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001614 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 }
1616
1617 switch (partCode)
1618 {
1619 case kControlUpButtonPart: data = -1; break;
1620 case kControlDownButtonPart: data = 1; break;
1621 case kControlPageDownPart: data = page; break;
1622 case kControlPageUpPart: data = -page; break;
1623 default: data = 0; break;
1624 }
1625
1626 value = sb_info->value + data;
1627/* if (value > sb_info->max)
1628 value = sb_info->max;
1629 else if (value < 0)
1630 value = 0;*/
1631
1632 /* When "allow_scrollbar" is FALSE still need to remember the new
1633 * position, but don't actually scroll by setting "dont_scroll". */
1634 dont_scroll = !allow_scrollbar;
1635 gui_drag_scrollbar(sb, value, dragging);
1636 dont_scroll = dont_scroll_save;
1637
1638 out_flush();
1639 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1640
1641/* if (sb_info->wp != NULL)
1642 {
1643 win_T *wp;
1644 int sb_num;
1645
1646 sb_num = 0;
1647 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1648 sb_num++;
1649
1650 if (wp != NULL)
1651 {
1652 current_scrollbar = sb_num;
1653 scrollbar_value = value;
1654 gui_do_scroll();
1655 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1656 }
1657 }*/
1658}
1659
1660/*
1661 * ------------------------------------------------------------
1662 * MacOS Click Handling procedures
1663 * ------------------------------------------------------------
1664 */
1665
1666
1667/*
1668 * Handle a click inside the window, it may happens in the
1669 * scrollbar or the contents.
1670 *
1671 * TODO: Add support for potential TOOLBAR
1672 */
1673 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001674gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675{
1676 Point thePoint;
1677 int_u vimModifiers;
1678 short thePortion;
1679 ControlHandle theControl;
1680 int vimMouseButton;
1681 short dblClick;
1682
1683 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001684 GlobalToLocal(&thePoint);
1685 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001687 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688
1689 if (theControl != NUL)
1690 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001691 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692
1693 if (thePortion != kControlIndicatorPart)
1694 {
1695 dragged_sb = theControl;
1696 TrackControl(theControl, thePoint, gScrollAction);
1697 dragged_sb = NULL;
1698 }
1699 else
1700 {
1701 dragged_sb = theControl;
1702#if 1
1703 TrackControl(theControl, thePoint, gScrollDrag);
1704#else
1705 TrackControl(theControl, thePoint, NULL);
1706#endif
1707 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1708 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001709 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 dragged_sb = NULL;
1711 }
1712 }
1713 else
1714 {
1715 /* We are inside the contents */
1716
1717 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1718 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1719
1720 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1721 vimMouseButton = MOUSE_LEFT;
1722
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001724 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 clickIsPopup = FALSE;
1726
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001727 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1728 {
1729 vimMouseButton = MOUSE_RIGHT;
1730 vimModifiers &= ~MOUSE_CTRL;
1731 clickIsPopup = TRUE;
1732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733
1734 /* Is it a double click ? */
1735 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1736
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001737 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 gui_send_mouse_event(vimMouseButton, thePoint.h,
1739 thePoint.v, dblClick, vimModifiers);
1740
1741 /* Create the rectangle around the cursor to detect
1742 * the mouse dragging
1743 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744#if 0
1745 /* TODO: Do we need to this even for the contextual menu?
1746 * It may be require for popup_setpos, but for popup?
1747 */
1748 if (vimMouseButton == MOUSE_LEFT)
1749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001751 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 FILL_Y(Y_2_ROW(thePoint.v)),
1753 FILL_X(X_2_COL(thePoint.h)+1),
1754 FILL_Y(Y_2_ROW(thePoint.v)+1));
1755
1756 dragRectEnbl = TRUE;
1757 dragRectControl = kCreateRect;
1758 }
1759 }
1760}
1761
1762/*
1763 * Handle the click in the titlebar (to move the window)
1764 */
1765 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001766gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767{
1768 Rect movingLimits;
1769 Rect *movingLimitsPtr = &movingLimits;
1770
1771 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001772 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001773 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774}
1775
1776/*
1777 * Handle the click in the grow box
1778 */
1779 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001780gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781{
1782
1783 long newSize;
1784 unsigned short newWidth;
1785 unsigned short newHeight;
1786 Rect resizeLimits;
1787 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 Rect NewContentRect;
1789
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001790 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791
Bram Moolenaar720c7102007-05-10 18:07:50 +00001792 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 /* TODO: Should this come from Vim? */
1794 resizeLimits.top = 100;
1795 resizeLimits.left = 100;
1796
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1798 newWidth = NewContentRect.right - NewContentRect.left;
1799 newHeight = NewContentRect.bottom - NewContentRect.top;
1800 gui_resize_shell(newWidth, newHeight);
1801 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001802 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803}
1804
1805/*
1806 * Handle the click in the zoom box
1807 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001809gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810{
1811 Rect r;
1812 Point p;
1813 short thePart;
1814
1815 /* ideal width is current */
1816 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1817 if (gui.which_scrollbars[SBAR_LEFT])
1818 p.h += gui.scrollbar_width;
1819 if (gui.which_scrollbars[SBAR_RIGHT])
1820 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001821 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 p.v = 15 * 1024;
1823
1824 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1825 ? inZoomIn : inZoomOut;
1826
1827 if (!TrackBox(whichWindow, theEvent->where, thePart))
1828 return;
1829
1830 /* use returned width */
1831 p.h = r.right - r.left;
1832 /* adjust returned height */
1833 p.v = r.bottom - r.top - 2 * gui.border_offset;
1834 if (gui.which_scrollbars[SBAR_BOTTOM])
1835 p.v -= gui.scrollbar_height;
1836 p.v -= p.v % gui.char_height;
1837 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001838 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 p.v += gui.scrollbar_height;
1840
1841 ZoomWindowIdeal(whichWindow, thePart, &p);
1842
1843 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1844 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1845 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001846 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849/*
1850 * ------------------------------------------------------------
1851 * MacOS Event Handling procedure
1852 * ------------------------------------------------------------
1853 */
1854
1855/*
1856 * Handle the Update Event
1857 */
1858
1859 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001860gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861{
1862 WindowPtr whichWindow;
1863 GrafPtr savePort;
1864 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 Rect *updateRectPtr;
1867 Rect rc;
1868 Rect growRect;
1869 RgnHandle saveRgn;
1870
1871
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 updateRgn = NewRgn();
1873 if (updateRgn == NULL)
1874 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875
1876 /* This could be done by the caller as we
1877 * don't require anything else out of the event
1878 */
1879 whichWindow = (WindowPtr) event->message;
1880
1881 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001882 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883
1884 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001885 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001888 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 /* Redraw the biggest rectangle covering the area
1890 * to be updated.
1891 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1893# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001894 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 * seem to work under MacOS X (Dany)
1896 */
1897 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1898# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001899
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001902
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001903 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904# if 0
1905 /* Code from original Carbon Port (using GetWindowRegion.
1906 * I believe the UpdateRgn is already in local (Dany)
1907 */
1908 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1909 GlobalToLocal(&botRight(updateRect));
1910# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 /* Update the content (i.e. the text) */
1912 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1913 updateRectPtr->right - updateRectPtr->left,
1914 updateRectPtr->bottom - updateRectPtr->top);
1915 /* Clear the border areas if needed */
1916 gui_mch_set_bg_color(gui.back_pixel);
1917 if (updateRectPtr->left < FILL_X(0))
1918 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001919 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1920 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
1922 if (updateRectPtr->top < FILL_Y(0))
1923 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001924 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1925 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
1927 if (updateRectPtr->right > FILL_X(Columns))
1928 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001929 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001931 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 if (updateRectPtr->bottom > FILL_Y(Rows))
1934 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001937 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941
1942 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
1945 /* Update the GrowBox */
1946 /* Taken from FAQ 33-27 */
1947 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001949 GetClip(saveRgn);
1950 ClipRect(&growRect);
1951 DrawGrowIcon(whichWindow);
1952 SetClip(saveRgn);
1953 DisposeRgn(saveRgn);
1954 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955
1956 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001957 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958}
1959
1960/*
1961 * Handle the activate/deactivate event
1962 * (apply to a window)
1963 */
1964 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001965gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966{
1967 WindowPtr whichWindow;
1968
1969 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001970 /* Dim scrollbars */
1971 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001973 ControlRef rootControl;
1974 GetRootControl(gui.VimWindow, &rootControl);
1975 if ((event->modifiers) & activeFlag)
1976 ActivateControl(rootControl);
1977 else
1978 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001980
1981 /* Activate */
1982 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983}
1984
1985
1986/*
1987 * Handle the suspend/resume event
1988 * (apply to the application)
1989 */
1990 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001991gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992{
1993 /* The frontmost application just changed */
1994
1995 /* NOTE: the suspend may happen before the deactivate
1996 * seen on MacOS X
1997 */
1998
1999 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002000 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001 */
2002 if (event->message & 1)
2003 /* Resume */
2004 gui_focus_change(TRUE);
2005 else
2006 /* Suspend */
2007 gui_focus_change(FALSE);
2008}
2009
2010/*
2011 * Handle the key
2012 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002013#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002014 static pascal OSStatus
2015gui_mac_handle_window_activate(
2016 EventHandlerCallRef nextHandler,
2017 EventRef theEvent,
2018 void *data)
2019{
2020 UInt32 eventClass = GetEventClass(theEvent);
2021 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002022
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002023 if (eventClass == kEventClassWindow)
2024 {
2025 switch (eventKind)
2026 {
2027 case kEventWindowActivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002028 im_on_window_switch(TRUE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002029 return noErr;
2030
2031 case kEventWindowDeactivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002032 im_on_window_switch(FALSE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002033 return noErr;
2034 }
2035 }
2036
2037 return eventNotHandledErr;
2038}
2039
2040 static pascal OSStatus
2041gui_mac_handle_text_input(
2042 EventHandlerCallRef nextHandler,
2043 EventRef theEvent,
2044 void *data)
2045{
2046 UInt32 eventClass = GetEventClass(theEvent);
2047 UInt32 eventKind = GetEventKind(theEvent);
2048
2049 if (eventClass != kEventClassTextInput)
2050 return eventNotHandledErr;
2051
2052 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2053 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2054 (kEventTextInputOffsetToPos != eventKind) &&
2055 (kEventTextInputPosToOffset != eventKind) &&
2056 (kEventTextInputGetSelectedText != eventKind))
2057 return eventNotHandledErr;
2058
2059 switch (eventKind)
2060 {
2061 case kEventTextInputUpdateActiveInputArea:
2062 return gui_mac_update_input_area(nextHandler, theEvent);
2063 case kEventTextInputUnicodeForKeyEvent:
2064 return gui_mac_unicode_key_event(nextHandler, theEvent);
2065
2066 case kEventTextInputOffsetToPos:
2067 case kEventTextInputPosToOffset:
2068 case kEventTextInputGetSelectedText:
2069 break;
2070 }
2071
2072 return eventNotHandledErr;
2073}
2074
2075 static pascal
2076OSStatus gui_mac_update_input_area(
2077 EventHandlerCallRef nextHandler,
2078 EventRef theEvent)
2079{
2080 return eventNotHandledErr;
2081}
2082
2083static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2084 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002085
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002086# define INLINE_KEY_BUFFER_SIZE 80
2087 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002088gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002089 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002090 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002091{
2092 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002093 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002094 UInt32 actualSize;
2095 UniChar *text;
2096 char_u result[INLINE_KEY_BUFFER_SIZE];
2097 short len = 0;
2098 UInt32 key_sym;
2099 char charcode;
2100 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002101 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002102 size_t encLen;
2103 char_u *to = NULL;
2104 Boolean isSpecial = FALSE;
2105 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002106 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002108 /* Mask the mouse (as per user setting) */
2109 if (p_mh)
2110 ObscureCursor();
2111
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002112 /* Don't use the keys when the dialog wants them. */
2113 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002114 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002115
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002117 typeUnicodeText, NULL, 0, &actualSize, NULL))
2118 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 text = (UniChar *)alloc(actualSize);
2121 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002122 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002125 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002126 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002127
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002128 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
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(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002133 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
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, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
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, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002141 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002142 require_noerr(err, done);
2143
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002144#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002146 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002147#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002148
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 key_char = charcode;
2150 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002152 /* Find the special key (eg., for cursor keys) */
2153 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002154 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002155 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002156 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2157 if (special_keys[i].key_sym == key_sym)
2158 {
2159 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2160 special_keys[i].vim_code1);
2161 key_char = simplify_key(key_char,
2162 (int *)&vimModifiers);
2163 isSpecial = TRUE;
2164 break;
2165 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002166 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002167
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002168 /* Intercept CMD-. and CTRL-c */
2169 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002170 ((modifiers & cmdKey) && key_char == '.'))
2171 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002172
2173 if (!isSpecial)
2174 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002175 /* remove SHIFT for keys that are already shifted, e.g.,
2176 * '(' and '*' */
2177 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2178 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002179
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002180 /* remove CTRL from keys that already have it */
2181 if (key_char < 0x20)
2182 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002183
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002184 /* don't process unicode characters here */
2185 if (!IS_SPECIAL(key_char))
2186 {
2187 /* Following code to simplify and consolidate vimModifiers
2188 * taken liberally from gui_w48.c */
2189 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002190
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002191 /* Interpret META, include SHIFT, etc. */
2192 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2193 if (key_char == CSI)
2194 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002195
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002196 if (IS_SPECIAL(key_char))
2197 isSpecial = TRUE;
2198 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002199 }
2200
2201 if (vimModifiers)
2202 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002203 result[len++] = CSI;
2204 result[len++] = KS_MODIFIER;
2205 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002206 }
2207
2208 if (isSpecial && IS_SPECIAL(key_char))
2209 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002210 result[len++] = CSI;
2211 result[len++] = K_SECOND(key_char);
2212 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002213 }
2214 else
2215 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002216 encLen = actualSize;
2217 to = mac_utf16_to_enc(text, actualSize, &encLen);
2218 if (to)
2219 {
2220 /* This is basically add_to_input_buf_csi() */
2221 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2222 {
2223 result[len++] = to[i];
2224 if (to[i] == CSI)
2225 {
2226 result[len++] = KS_EXTRA;
2227 result[len++] = (int)KE_CSI;
2228 }
2229 }
2230 vim_free(to);
2231 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002232 }
2233
2234 add_to_input_buf(result, len);
2235 err = noErr;
2236
2237done:
2238 vim_free(text);
2239 if (err == noErr)
2240 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002241 /* Fake event to wake up WNE (required to get
2242 * key repeat working */
2243 PostEvent(keyUp, 0);
2244 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002245 }
2246
2247 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002248}
2249#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 void
2251gui_mac_doKeyEvent(EventRecord *theEvent)
2252{
2253 /* TODO: add support for COMMAND KEY */
2254 long menu;
2255 unsigned char string[20];
2256 short num, i;
2257 short len = 0;
2258 KeySym key_sym;
2259 int key_char;
2260 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002261 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262
2263 /* Mask the mouse (as per user setting) */
2264 if (p_mh)
2265 ObscureCursor();
2266
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002267 /* Get the key code and its ASCII representation */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2269 key_char = theEvent->message & charCodeMask;
2270 num = 1;
2271
2272 /* Intercept CTRL-C */
2273 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002274 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275 if (key_char == Ctrl_C && ctrl_c_interrupts)
2276 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002277 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2278 && (key_char == '2' || key_char == '6'))
2279 {
2280 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2281 if (key_char == '2')
2282 key_char = Ctrl_AT;
2283 else
2284 key_char = Ctrl_HAT;
2285 theEvent->modifiers = 0;
2286 }
2287 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288
2289 /* Intercept CMD-. */
2290 if (theEvent->modifiers & cmdKey)
2291 if (key_char == '.')
2292 got_int = TRUE;
2293
2294 /* Handle command key as per menu */
2295 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2296 if (theEvent->modifiers & cmdKey)
2297 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2298 * Why the mouse button? */
2299 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2300 {
2301 menu = MenuKey(key_char);
2302 if (HiWord(menu))
2303 {
2304 gui_mac_handle_menu(menu);
2305 return;
2306 }
2307 }
2308
2309 /* Convert the modifiers */
2310 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2311
2312
2313 /* Handle special keys. */
2314#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002315 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2317#endif
2318 {
2319 /* Find the special key (for non-printable keyt_char) */
2320 if ((key_char < 0x20) || (key_char == 0x7f))
2321 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2322 if (special_keys[i].key_sym == key_sym)
2323 {
2324# if 0
2325 /* We currently don't have not so special key */
2326 if (special_keys[i].vim_code1 == NUL)
2327 key_char = special_keys[i].vim_code0;
2328 else
2329# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002330 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2331 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002332 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 break;
2334 }
2335 }
2336
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002337 /* For some keys the modifier is included in the char itself. */
2338 if (simplify || key_char == TAB || key_char == ' ')
2339 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340
2341 /* Add the modifier to the input bu if needed */
2342 /* Do not want SHIFT-A or CTRL-A with modifier */
2343 if (!IS_SPECIAL(key_char)
2344 && key_sym != vk_Space
2345 && key_sym != vk_Tab
2346 && key_sym != vk_Return
2347 && key_sym != vk_Enter
2348 && key_sym != vk_Esc)
2349 {
2350#if 1
2351 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002352 if ((modifiers == MOD_MASK_SHIFT)
2353 || (modifiers == MOD_MASK_CTRL)
2354 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 modifiers = 0;
2356#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002357 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002359 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 modifiers = modifiers & ~MOD_MASK_SHIFT;
2363#endif
2364 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002365 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002367 string[len++] = CSI;
2368 string[len++] = KS_MODIFIER;
2369 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 }
2371
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002374 string[len++] = CSI;
2375 string[len++] = K_SECOND(key_char);
2376 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 }
2378 else
2379 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002380 /* Convert characters when needed (e.g., from MacRoman to latin1).
2381 * This doesn't work for the NUL byte. */
2382 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 {
2384 char_u from[2], *to;
2385 int l;
2386
2387 from[0] = key_char;
2388 from[1] = NUL;
2389 l = 1;
2390 to = string_convert(&input_conv, from, &l);
2391 if (to != NULL)
2392 {
2393 for (i = 0; i < l && len < 19; i++)
2394 {
2395 if (to[i] == CSI)
2396 {
2397 string[len++] = KS_EXTRA;
2398 string[len++] = KE_CSI;
2399 }
2400 else
2401 string[len++] = to[i];
2402 }
2403 vim_free(to);
2404 }
2405 else
2406 string[len++] = key_char;
2407 }
2408 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 string[len++] = key_char;
2410 }
2411
2412 if (len == 1 && string[0] == CSI)
2413 {
2414 /* Turn CSI into K_CSI. */
2415 string[ len++ ] = KS_EXTRA;
2416 string[ len++ ] = KE_CSI;
2417 }
2418
2419 add_to_input_buf(string, len);
2420}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002421#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422
2423/*
2424 * Handle MouseClick
2425 */
2426 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002427gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428{
2429 short thePart;
2430 WindowPtr whichWindow;
2431
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002432 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002434#ifdef FEAT_GUI_TABLINE
2435 /* prevent that the vim window size changes if it's activated by a
2436 click into the tab pane */
2437 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002438 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002439#endif
2440
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 switch (thePart)
2442 {
2443 case (inDesk):
2444 /* TODO: what to do? */
2445 break;
2446
2447 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002448 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449 break;
2450
2451 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002452 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453 break;
2454
2455 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002456 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 break;
2458
2459 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002460 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461 break;
2462
2463 case (inGoAway):
2464 if (TrackGoAway(whichWindow, theEvent->where))
2465 gui_shell_closed();
2466 break;
2467
2468 case (inZoomIn):
2469 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 break;
2472 }
2473}
2474
2475/*
2476 * Handle MouseMoved
2477 * [this event is a moving in and out of a region]
2478 */
2479 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002480gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481{
2482 Point thePoint;
2483 int_u vimModifiers;
2484
2485 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002486 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2488
2489 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002490 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2494 thePoint.v, FALSE, vimModifiers);
2495
2496 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002497 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 FILL_Y(Y_2_ROW(thePoint.v)),
2499 FILL_X(X_2_COL(thePoint.h)+1),
2500 FILL_Y(Y_2_ROW(thePoint.v)+1));
2501
2502 if (dragRectEnbl)
2503 dragRectControl = kCreateRect;
2504
2505}
2506
2507/*
2508 * Handle the mouse release
2509 */
2510 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002511gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512{
2513 Point thePoint;
2514 int_u vimModifiers;
2515
2516 /* TODO: Properly convert the Contextual menu mouse-up */
2517 /* Potential source of the double menu */
2518 lastMouseTick = theEvent->when;
2519 dragRectEnbl = FALSE;
2520 dragRectControl = kCreateEmpty;
2521 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002522 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523
2524 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 if (clickIsPopup)
2526 {
2527 vimModifiers &= ~MOUSE_CTRL;
2528 clickIsPopup = FALSE;
2529 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002530 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531}
2532
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 static pascal OSStatus
2534gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2535 void *data)
2536{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537 Point point;
2538 Rect bounds;
2539 UInt32 mod;
2540 SInt32 delta;
2541 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002542 EventMouseWheelAxis axis;
2543
2544 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2545 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2546 && axis != kEventMouseWheelAxisY)
2547 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548
2549 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2550 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2551 goto bail;
2552 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2553 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2554 goto bail;
2555 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2556 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2557 goto bail;
2558
2559 vim_mod = 0;
2560 if (mod & shiftKey)
2561 vim_mod |= MOUSE_SHIFT;
2562 if (mod & controlKey)
2563 vim_mod |= MOUSE_CTRL;
2564 if (mod & optionKey)
2565 vim_mod |= MOUSE_ALT;
2566
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2568 {
2569 point.h -= bounds.left;
2570 point.v -= bounds.top;
2571 }
2572
2573 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2574 point.h, point.v, FALSE, vim_mod);
2575
Bram Moolenaarc236c162008-07-13 17:41:49 +00002576 /* post a bogus event to wake up WaitNextEvent */
2577 PostEvent(keyUp, 0);
2578
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 return noErr;
2580
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002581bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 /*
2583 * when we fail give any additional callback handler a chance to perform
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002584 * its actions
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 */
2586 return CallNextEventHandler(nextHandler, theEvent);
2587}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588
Bram Moolenaare00289d2010-08-14 21:56:42 +02002589 void
2590gui_mch_mousehide(int hide)
2591{
2592 /* TODO */
2593}
2594
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595#if 0
2596
2597/*
2598 * This would be the normal way of invoking the contextual menu
2599 * but the Vim API doesn't seem to a support a request to get
2600 * the menu that we should display
2601 */
2602 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002603gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604{
2605/*
2606 * Clone PopUp to use menu
2607 * Create a object descriptor for the current selection
2608 * Call the procedure
2609 */
2610
2611// Call to Handle Popup
2612 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2613
2614 if (status != noErr)
2615 return;
2616
2617 if (CntxType == kCMMenuItemSelected)
2618 {
2619 /* Handle the menu CntxMenuID, CntxMenuItem */
2620 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002621 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002622 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 }
2624 else if (CntxMenuID == kCMShowHelpSelected)
2625 {
2626 /* Should come up with the help */
2627 }
2628
2629}
2630#endif
2631
2632/*
2633 * Handle menubar selection
2634 */
2635 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002636gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637{
2638 short menu = HiWord(menuChoice);
2639 short item = LoWord(menuChoice);
2640 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641
2642 if (menu == 256) /* TODO: use constant or gui.xyz */
2643 {
2644 if (item == 1)
2645 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 }
2647 else if (item != 0)
2648 {
2649 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2650
2651 if (theVimMenu)
2652 gui_menu_cb(theVimMenu);
2653 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002654 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655}
2656
2657/*
2658 * Dispatch the event to proper handler
2659 */
2660
2661 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002662gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663{
2664 OSErr error;
2665
2666 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002667 if (IsShowContextualMenuClick(event))
2668 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002670 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002672 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002674 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002675 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676
2677 /* Handle normal event */
2678 switch (event->what)
2679 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002680#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 case (keyDown):
2682 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002683 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002685#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002687 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 break;
2689
2690 case (mouseDown):
2691 gui_mac_doMouseDownEvent(event);
2692 break;
2693
2694 case (mouseUp):
2695 gui_mac_doMouseUpEvent(event);
2696 break;
2697
2698 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002699 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 break;
2701
2702 case (diskEvt):
2703 /* We don't need special handling for disk insertion */
2704 break;
2705
2706 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002707 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 break;
2709
2710 case (osEvt):
2711 switch ((event->message >> 24) & 0xFF)
2712 {
2713 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002714 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 break;
2716 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002717 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 break;
2719 }
2720 break;
2721
2722#ifdef USE_AEVENT
2723 case (kHighLevelEvent):
2724 /* Someone's talking to us, through AppleEvents */
2725 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2726 break;
2727#endif
2728 }
2729}
2730
2731/*
2732 * ------------------------------------------------------------
2733 * Unknown Stuff
2734 * ------------------------------------------------------------
2735 */
2736
2737
2738 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002739gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740{
2741 char_u c;
2742 char_u *p;
2743 char_u pFontName[256];
2744 Str255 systemFontname;
2745 short font_id;
2746 short size=9;
2747 GuiFont font;
2748#if 0
2749 char_u *fontNamePtr;
2750#endif
2751
2752 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2753 ;
2754
2755 c = *p;
2756 *p = 0;
2757
2758#if 1
2759 STRCPY(&pFontName[1], font_name);
2760 pFontName[0] = STRLEN(font_name);
2761 *p = c;
2762
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002763 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002764 char_u fontName[256];
2765 char_u *styleStart = vim_strchr(font_name, ':');
2766 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2767 vim_strncpy(fontName, font_name, fontNameLen);
2768
2769 ATSUFontID fontRef;
2770 FMFontStyle fontStyle;
2771 font_id = 0;
2772
2773 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2774 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2775 &fontRef) == noErr)
2776 {
2777 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2778 font_id = 0;
2779 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002780
2781 if (font_id == 0)
2782 {
2783 /*
2784 * Try again, this time replacing underscores in the font name
2785 * with spaces (:set guifont allows the two to be used
2786 * interchangeably; the Font Manager doesn't).
2787 */
2788 int i, changed = FALSE;
2789
2790 for (i = pFontName[0]; i > 0; --i)
2791 {
2792 if (pFontName[i] == '_')
2793 {
2794 pFontName[i] = ' ';
2795 changed = TRUE;
2796 }
2797 }
2798 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002799 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2800 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2801 kFontNoLanguageCode, &fontRef) == noErr)
2802 {
2803 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2804 font_id = 0;
2805 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002806 }
2807
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808#else
2809 /* name = C2Pascal_save(menu->dname); */
2810 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2811
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002812 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813#endif
2814
2815
2816 if (font_id == 0)
2817 {
2818 /* Oups, the system font was it the one the user want */
2819
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002820 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2821 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 if (!EqualString(pFontName, systemFontname, false, false))
2823 return NOFONT;
2824 }
2825 if (*p == ':')
2826 {
2827 p++;
2828 /* Set the values found after ':' */
2829 while (*p)
2830 {
2831 switch (*p++)
2832 {
2833 case 'h':
2834 size = points_to_pixels(p, &p, TRUE);
2835 break;
2836 /*
2837 * TODO: Maybe accept width and styles
2838 */
2839 }
2840 while (*p == ':')
2841 p++;
2842 }
2843 }
2844
2845 if (size < 1)
2846 size = 1; /* Avoid having a size of 0 with system font */
2847
2848 font = (size << 16) + ((long) font_id & 0xFFFF);
2849
2850 return font;
2851}
2852
2853/*
2854 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002855 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856 * ------------------------------------------------------------
2857 */
2858
2859/*
2860 * Parse the GUI related command-line arguments. Any arguments used are
2861 * deleted from argv, and *argc is decremented accordingly. This is called
2862 * when vim is started, whether or not the GUI has been started.
2863 */
2864 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002865gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866{
2867 /* TODO: Move most of this stuff toward gui_mch_init */
2868#ifdef USE_EXE_NAME
2869 FSSpec applDir;
2870# ifndef USE_FIND_BUNDLE_PATH
2871 short applVRefNum;
2872 long applDirID;
2873 Str255 volName;
2874# else
2875 ProcessSerialNumber psn;
2876 FSRef applFSRef;
2877# endif
2878#endif
2879
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880#if 0
2881 InitCursor();
2882
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884
2885#ifdef USE_AEVENT
2886 (void) InstallAEHandlers();
2887#endif
2888
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002889 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002891 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002893 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894
2895 DrawMenuBar();
2896
2897
2898#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002899 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002901 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902#endif
2903
2904
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 CreateNewWindow(kDocumentWindowClass,
2906 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002907 &windRect, &gui.VimWindow);
2908 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909
2910 gui.char_width = 7;
2911 gui.char_height = 11;
2912 gui.char_ascent = 6;
2913 gui.num_rows = 24;
2914 gui.num_cols = 80;
2915 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2916
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002917 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2918 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919
2920 dragRectEnbl = FALSE;
2921 dragRgn = NULL;
2922 dragRectControl = kCreateEmpty;
2923 cursorRgn = NewRgn();
2924#endif
2925#ifdef USE_EXE_NAME
2926# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002927 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002929 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930# else
2931 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2932 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002934 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 /* if (err != noErr) return err; */
2936
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002937 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 /* if (err != noErr) return err; */
2939
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002940 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941
2942 /* This technic return NIL when we disallow_gui */
2943# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002944 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946}
2947
2948#ifndef ALWAYS_USE_GUI
2949/*
2950 * Check if the GUI can be started. Called before gvimrc is sourced.
2951 * Return OK or FAIL.
2952 */
2953 int
2954gui_mch_init_check(void)
2955{
2956 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2957 * using the >console
2958 */
2959 if (disallow_gui) /* see main.c for reason to disallow */
2960 return FAIL;
2961 return OK;
2962}
2963#endif
2964
2965 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002966receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967{
2968 int x, y;
2969 int_u modifiers;
2970 char_u **fnames = NULL;
2971 int count;
2972 int i, j;
2973
2974 /* Get drop position, modifiers and count of items */
2975 {
2976 Point point;
2977 SInt16 mouseUpModifiers;
2978 UInt16 countItem;
2979
2980 GetDragMouse(theDrag, &point, NULL);
2981 GlobalToLocal(&point);
2982 x = point.h;
2983 y = point.v;
2984 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2985 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2986 CountDragItems(theDrag, &countItem);
2987 count = countItem;
2988 }
2989
2990 fnames = (char_u **)alloc(count * sizeof(char_u *));
2991 if (fnames == NULL)
2992 return dragNotAcceptedErr;
2993
2994 /* Get file names dropped */
2995 for (i = j = 0; i < count; ++i)
2996 {
2997 DragItemRef item;
2998 OSErr err;
2999 Size size;
3000 FlavorType type = flavorTypeHFS;
3001 HFSFlavor hfsFlavor;
3002
3003 fnames[i] = NULL;
3004 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3005 err = GetFlavorDataSize(theDrag, item, type, &size);
3006 if (err != noErr || size > sizeof(hfsFlavor))
3007 continue;
3008 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3009 if (err != noErr)
3010 continue;
3011 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3012 }
3013 count = j;
3014
3015 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003016
3017 /* Fake mouse event to wake from stall */
3018 PostEvent(mouseUp, 0);
3019
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 return noErr;
3021}
3022
3023/*
3024 * Initialise the GUI. Create all the windows, set up all the call-backs
3025 * etc.
3026 */
3027 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003028gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029{
3030 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003031 Rect windRect;
3032 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003034 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003035 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003036
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003037 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003038 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003039
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040#if 1
3041 InitCursor();
3042
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044
3045#ifdef USE_AEVENT
3046 (void) InstallAEHandlers();
3047#endif
3048
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003049 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003051 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003053 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054
3055 DrawMenuBar();
3056
3057
3058#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003059 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003061 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062#endif
3063
3064 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003067 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3069 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003070 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071
3072 gui.char_width = 7;
3073 gui.char_height = 11;
3074 gui.char_ascent = 6;
3075 gui.num_rows = 24;
3076 gui.num_cols = 80;
3077 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3078
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003079 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3080 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003082 /* Install Carbon event callbacks. */
3083 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084
3085 dragRectEnbl = FALSE;
3086 dragRgn = NULL;
3087 dragRectControl = kCreateEmpty;
3088 cursorRgn = NewRgn();
3089#endif
3090 /* Display any pending error messages */
3091 display_errors();
3092
3093 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003094 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 gui.norm_pixel = 0x00000000;
3096 gui.back_pixel = 0x00FFFFFF;
3097
3098 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3099 * file). */
3100 set_normal_colors();
3101
3102 /*
3103 * Check that none of the colors are the same as the background color.
3104 * Then store the current values as the defaults.
3105 */
3106 gui_check_colors();
3107 gui.def_norm_pixel = gui.norm_pixel;
3108 gui.def_back_pixel = gui.back_pixel;
3109
3110 /* Get the colors for the highlight groups (gui_check_colors() might have
3111 * changed them) */
3112 highlight_gui_started();
3113
3114 /*
3115 * Setting the gui constants
3116 */
3117#ifdef FEAT_MENU
3118 gui.menu_height = 0;
3119#endif
3120 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3121 gui.border_offset = gui.border_width = 2;
3122
Bram Moolenaar720c7102007-05-10 18:07:50 +00003123 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124 gui_mch_draw_string() below), enable it for all font sizes. */
3125 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127 eventTypeSpec.eventClass = kEventClassMouse;
3128 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3129 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3130 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3131 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3132 {
3133 mouseWheelHandlerRef = NULL;
3134 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3135 mouseWheelHandlerUPP = NULL;
3136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003138#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003139 InterfaceTypeList supportedServices = { kUnicodeDocument };
3140 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3141
3142 /* We don't support inline input yet, use input window by default */
3143 UseInputWindow(gTSMDocument, TRUE);
3144
3145 /* Should we activate the document by default? */
3146 // ActivateTSMDocument(gTSMDocument);
3147
3148 EventTypeSpec textEventTypes[] = {
3149 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3150 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3151 { kEventClassTextInput, kEventTextInputPosToOffset },
3152 { kEventClassTextInput, kEventTextInputOffsetToPos },
3153 };
3154
3155 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3156 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3157 NR_ELEMS(textEventTypes),
3158 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003159 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003160 DisposeEventHandlerUPP(keyEventHandlerUPP);
3161 keyEventHandlerUPP = NULL;
3162 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003163
3164 EventTypeSpec windowEventTypes[] = {
3165 { kEventClassWindow, kEventWindowActivated },
3166 { kEventClassWindow, kEventWindowDeactivated },
3167 };
3168
3169 /* Install window event handler to support TSMDocument activate and
3170 * deactivate */
3171 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3172 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3173 winEventHandlerUPP,
3174 NR_ELEMS(windowEventTypes),
3175 windowEventTypes, NULL, NULL))
3176 {
3177 DisposeEventHandlerUPP(winEventHandlerUPP);
3178 winEventHandlerUPP = NULL;
3179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180#endif
3181
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003182#ifdef FEAT_GUI_TABLINE
3183 /*
3184 * Create the tabline
3185 */
3186 initialise_tabline();
3187#endif
3188
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 /* TODO: Load bitmap if using TOOLBAR */
3190 return OK;
3191}
3192
3193/*
3194 * Called when the foreground or background color has been changed.
3195 */
3196 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003197gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198{
3199 /* TODO:
3200 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003201 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 */
3203}
3204
3205/*
3206 * Open the GUI window which was created by a call to gui_mch_init().
3207 */
3208 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003209gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210{
3211 ShowWindow(gui.VimWindow);
3212
3213 if (gui_win_x != -1 && gui_win_y != -1)
3214 gui_mch_set_winpos(gui_win_x, gui_win_y);
3215
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 /*
3217 * Make the GUI the foreground process (in case it was launched
3218 * from the Terminal or via :gui).
3219 */
3220 {
3221 ProcessSerialNumber psn;
3222 if (GetCurrentProcess(&psn) == noErr)
3223 SetFrontProcess(&psn);
3224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225
3226 return OK;
3227}
3228
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003229#ifdef USE_ATSUI_DRAWING
3230 static void
3231gui_mac_dispose_atsui_style(void)
3232{
3233 if (p_macatsui && gFontStyle)
3234 ATSUDisposeStyle(gFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003235 if (p_macatsui && gWideFontStyle)
3236 ATSUDisposeStyle(gWideFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003237}
3238#endif
3239
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 void
3241gui_mch_exit(int rc)
3242{
3243 /* TODO: find out all what is missing here? */
3244 DisposeRgn(cursorRgn);
3245
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003246#ifdef USE_CARBONKEYHANDLER
3247 if (keyEventHandlerUPP)
3248 DisposeEventHandlerUPP(keyEventHandlerUPP);
3249#endif
3250
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251 if (mouseWheelHandlerUPP != NULL)
3252 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003254#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003255 gui_mac_dispose_atsui_style();
3256#endif
3257
3258#ifdef USE_CARBONKEYHANDLER
3259 FixTSMDocument(gTSMDocument);
3260 DeactivateTSMDocument(gTSMDocument);
3261 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003262#endif
3263
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 /* Exit to shell? */
3265 exit(rc);
3266}
3267
3268/*
3269 * Get the position of the top left corner of the window.
3270 */
3271 int
3272gui_mch_get_winpos(int *x, int *y)
3273{
3274 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275 Rect bounds;
3276 OSStatus status;
3277
3278 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003279 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280
3281 if (status != noErr)
3282 return FAIL;
3283 *x = bounds.left;
3284 *y = bounds.top;
3285 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286}
3287
3288/*
3289 * Set the position of the top left corner of the window to the given
3290 * coordinates.
3291 */
3292 void
3293gui_mch_set_winpos(int x, int y)
3294{
3295 /* TODO: Should make sure the window is move within range
3296 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3297 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003298 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299}
3300
3301 void
3302gui_mch_set_shellsize(
3303 int width,
3304 int height,
3305 int min_width,
3306 int min_height,
3307 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003308 int base_height,
3309 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311 CGrafPtr VimPort;
3312 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313
3314 if (gui.which_scrollbars[SBAR_LEFT])
3315 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003316 VimPort = GetWindowPort(gui.VimWindow);
3317 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003319 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 }
3322 else
3323 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003324 VimPort = GetWindowPort(gui.VimWindow);
3325 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003327 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 }
3329
3330 SizeWindow(gui.VimWindow, width, height, TRUE);
3331
3332 gui_resize_shell(width, height);
3333}
3334
3335/*
3336 * Get the screen dimensions.
3337 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3338 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003339 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 */
3341 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003342gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343{
3344 GDHandle dominantDevice = GetMainDevice();
3345 Rect screenRect = (**dominantDevice).gdRect;
3346
3347 *screen_w = screenRect.right - 10;
3348 *screen_h = screenRect.bottom - 40;
3349}
3350
3351
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003352/*
3353 * Open the Font Panel and wait for the user to select a font and
3354 * close the panel. Then fill the buffer pointed to by font_name with
3355 * the name and size of the selected font and return the font's handle,
3356 * or NOFONT in case of an error.
3357 */
3358 static GuiFont
3359gui_mac_select_font(char_u *font_name)
3360{
3361 GuiFont selected_font = NOFONT;
3362 OSStatus status;
3363 FontSelectionQDStyle curr_font;
3364
3365 /* Initialize the Font Panel with the current font. */
3366 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3367 curr_font.size = (gui.norm_font >> 16);
3368 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3369 curr_font.instance.fontStyle = 0;
3370 curr_font.hasColor = false;
3371 curr_font.version = 0; /* version number of the style structure */
3372 status = SetFontInfoForSelection(kFontSelectionQDType,
3373 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3374
3375 gFontPanelInfo.family = curr_font.instance.fontFamily;
3376 gFontPanelInfo.style = curr_font.instance.fontStyle;
3377 gFontPanelInfo.size = curr_font.size;
3378
3379 /* Pop up the Font Panel. */
3380 status = FPShowHideFontPanel();
3381 if (status == noErr)
3382 {
3383 /*
3384 * The Font Panel is modeless. We really need it to be modal,
3385 * so we spin in an event loop until the panel is closed.
3386 */
3387 gFontPanelInfo.isPanelVisible = true;
3388 while (gFontPanelInfo.isPanelVisible)
3389 {
3390 EventRecord e;
3391 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3392 }
3393
3394 GetFontPanelSelection(font_name);
3395 selected_font = gui_mac_find_font(font_name);
3396 }
3397 return selected_font;
3398}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003399
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003400#ifdef USE_ATSUI_DRAWING
3401 static void
3402gui_mac_create_atsui_style(void)
3403{
3404 if (p_macatsui && gFontStyle == NULL)
3405 {
3406 if (ATSUCreateStyle(&gFontStyle) != noErr)
3407 gFontStyle = NULL;
3408 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003409 if (p_macatsui && gWideFontStyle == NULL)
3410 {
3411 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3412 gWideFontStyle = NULL;
3413 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003414
3415 p_macatsui_last = p_macatsui;
3416}
3417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418
3419/*
3420 * Initialise vim to use the font with the given name. Return FAIL if the font
3421 * could not be loaded, OK otherwise.
3422 */
3423 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003424gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425{
3426 /* TODO: Add support for bold italic underline proportional etc... */
3427 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003428 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429 FontInfo font_info;
3430 short font_id;
3431 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003432 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003434#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003435 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003436#endif
3437
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 if (font_name == NULL)
3439 {
3440 /* First try to get the suggested font */
3441 GetFNum(suggestedFont, &font_id);
3442
3443 if (font_id == 0)
3444 {
3445 /* Then pickup the standard application font */
3446 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003447 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003449 else
3450 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3452 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003453 else if (STRCMP(font_name, "*") == 0)
3454 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003455 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003456
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003457 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003458 if (font == NOFONT)
3459 return FAIL;
3460
3461 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003462 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003463 if (new_p_guifont != NULL)
3464 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003465 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003466 vim_free(p_guifont);
3467 p_guifont = new_p_guifont;
3468 /* Replace spaces in the font name with underscores. */
3469 for ( ; *new_p_guifont; ++new_p_guifont)
3470 {
3471 if (*new_p_guifont == ' ')
3472 *new_p_guifont = '_';
3473 }
3474 }
3475 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 else
3477 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003478 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003479 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480
3481 if (font == NOFONT)
3482 return FAIL;
3483 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003484
Bram Moolenaar071d4272004-06-13 20:20:40 +00003485 gui.norm_font = font;
3486
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003487 hl_set_font_name(used_font_name);
3488
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003489 TextSize(font >> 16);
3490 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003492 GetFontInfo(&font_info);
3493
3494 gui.char_ascent = font_info.ascent;
3495 gui.char_width = CharWidth('_');
3496 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3497
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003498#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003499 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003500 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003501#endif
3502
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504}
3505
Bram Moolenaar02743632005-07-25 20:42:36 +00003506/*
3507 * Adjust gui.char_height (after 'linespace' was changed).
3508 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003510gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511{
3512 FontInfo font_info;
3513
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003514 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3516 gui.char_ascent = font_info.ascent + p_linespace / 2;
3517 return OK;
3518}
3519
3520/*
3521 * Get a font structure for highlighting.
3522 */
3523 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003524gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525{
3526 GuiFont font;
3527
3528 font = gui_mac_find_font(name);
3529
3530 if (font == NOFONT)
3531 {
3532 if (giveErrorIfMissing)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003533 semsg(_(e_font), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534 return NOFONT;
3535 }
3536 /*
3537 * TODO : Accept only monospace
3538 */
3539
3540 return font;
3541}
3542
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003543#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003545 * Return the name of font "font" in allocated memory.
3546 * Don't know how to get the actual name, thus use the provided name.
3547 */
3548 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003549gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003550{
3551 if (name == NULL)
3552 return NULL;
3553 return vim_strsave(name);
3554}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003555#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003556
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003557#ifdef USE_ATSUI_DRAWING
3558 static void
3559gui_mac_set_font_attributes(GuiFont font)
3560{
3561 ATSUFontID fontID;
3562 Fixed fontSize;
3563 Fixed fontWidth;
3564
3565 fontID = font & 0xFFFF;
3566 fontSize = Long2Fix(font >> 16);
3567 fontWidth = Long2Fix(gui.char_width);
3568
3569 ATSUAttributeTag attribTags[] =
3570 {
3571 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3572 kATSUMaxATSUITagValue + 1
3573 };
3574
3575 ByteCount attribSizes[] =
3576 {
3577 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3578 sizeof(font)
3579 };
3580
3581 ATSUAttributeValuePtr attribValues[] =
3582 {
3583 &fontID, &fontSize, &fontWidth, &font
3584 };
3585
3586 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3587 {
3588 if (ATSUSetAttributes(gFontStyle,
3589 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3590 attribTags, attribSizes, attribValues) != noErr)
3591 {
3592# ifndef NDEBUG
3593 fprintf(stderr, "couldn't set font style\n");
3594# endif
3595 ATSUDisposeStyle(gFontStyle);
3596 gFontStyle = NULL;
3597 }
3598
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003599 if (has_mbyte)
3600 {
3601 /* FIXME: we should use a more mbyte sensitive way to support
3602 * wide font drawing */
3603 fontWidth = Long2Fix(gui.char_width * 2);
3604
3605 if (ATSUSetAttributes(gWideFontStyle,
3606 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3607 attribTags, attribSizes, attribValues) != noErr)
3608 {
3609 ATSUDisposeStyle(gWideFontStyle);
3610 gWideFontStyle = NULL;
3611 }
3612 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003613 }
3614}
3615#endif
3616
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003617/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618 * Set the current text font.
3619 */
3620 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003621gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003623#ifdef USE_ATSUI_DRAWING
3624 GuiFont currFont;
3625 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003626
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003627 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003628 {
3629 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003630 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3631 sizeof(font), &currFont, &actualFontByteCount) == noErr
3632 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003633 {
3634 if (currFont == font)
3635 return;
3636 }
3637
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003638 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003639 }
3640
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003641 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003642 {
3643 /* Setup automatic font substitution. The user's guifontwide
3644 * is tried first, then the system tries other fonts. */
3645/*
3646 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3647 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3648 ATSUCreateFontFallbacks(&gFontFallbacks);
3649 ATSUSetObjFontFallbacks(gFontFallbacks, );
3650*/
3651 if (gui.wide_font)
3652 {
3653 ATSUFontID fallbackFonts;
3654 gIsFontFallbackSet = TRUE;
3655
3656 if (FMGetFontFromFontFamilyInstance(
3657 (gui.wide_font & 0xFFFF),
3658 0,
3659 &fallbackFonts,
3660 NULL) == noErr)
3661 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003662 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3663 &fallbackFonts,
3664 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003665 }
3666/*
3667 ATSUAttributeValuePtr fallbackValues[] = { };
3668*/
3669 }
3670 }
3671#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 TextSize(font >> 16);
3673 TextFont(font & 0xFFFF);
3674}
3675
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676/*
3677 * If a font is not going to be used, free its structure.
3678 */
3679 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003680gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681{
3682 /*
3683 * Free font when "font" is not 0.
3684 * Nothing to do in the current implementation, since
3685 * nothing is allocated for each font used.
3686 */
3687}
3688
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689/*
3690 * Return the Pixel value (color) for the given color name. This routine was
3691 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3692 * Programmer's Guide.
3693 * Return INVALCOLOR when failed.
3694 */
3695 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003696gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697{
3698 /* TODO: Add support for the new named color of MacOS 8
3699 */
3700 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701
Bram Moolenaarab302212016-04-26 20:59:29 +02003702 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003704 LMGetHiliteRGB(&MacColor);
3705 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003707 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708}
3709
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003710 guicolor_T
3711gui_mch_get_rgb_color(int r, int g, int b)
3712{
3713 return gui_get_rgb_color_cmn(r, g, b);
3714}
3715
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716/*
3717 * Set the current text foreground color.
3718 */
3719 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003720gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721{
3722 RGBColor TheColor;
3723
3724 TheColor.red = Red(color) * 0x0101;
3725 TheColor.green = Green(color) * 0x0101;
3726 TheColor.blue = Blue(color) * 0x0101;
3727
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003728 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729}
3730
3731/*
3732 * Set the current text background color.
3733 */
3734 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003735gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736{
3737 RGBColor TheColor;
3738
3739 TheColor.red = Red(color) * 0x0101;
3740 TheColor.green = Green(color) * 0x0101;
3741 TheColor.blue = Blue(color) * 0x0101;
3742
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003743 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744}
3745
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003746RGBColor specialColor;
3747
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003748/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003749 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003750 */
3751 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003752gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003753{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003754 specialColor.red = Red(color) * 0x0101;
3755 specialColor.green = Green(color) * 0x0101;
3756 specialColor.blue = Blue(color) * 0x0101;
3757}
3758
3759/*
3760 * Draw undercurl at the bottom of the character cell.
3761 */
3762 static void
3763draw_undercurl(int flags, int row, int col, int cells)
3764{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003765 int x;
3766 int offset;
3767 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3768 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003769
3770 RGBForeColor(&specialColor);
3771
3772 offset = val[FILL_X(col) % 8];
3773 MoveTo(FILL_X(col), y - offset);
3774
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003775 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003776 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003777 offset = val[x % 8];
3778 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003779 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003780}
3781
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003782
3783 static void
3784draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786 char_u *tofree = NULL;
3787
3788 if (output_conv.vc_type != CONV_NONE)
3789 {
3790 tofree = string_convert(&output_conv, s, &len);
3791 if (tofree != NULL)
3792 s = tofree;
3793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 /*
3796 * On OS X, try using Quartz-style text antialiasing.
3797 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003798 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 {
3800 /* Quartz antialiasing is available only in OS 10.2 and later. */
3801 UInt32 qd_flags = (p_antialias ?
3802 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003803 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 }
3805
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003806 /*
3807 * When antialiasing we're using srcOr mode, we have to clear the block
3808 * before drawing the text.
3809 * Also needed when 'linespace' is non-zero to remove the cursor and
3810 * underlining.
3811 * But not when drawing transparently.
3812 * The following is like calling gui_mch_clear_block(row, col, row, col +
3813 * len - 1), but without setting the bg color to gui.back_pixel.
3814 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003815 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003816 && !(flags & DRAW_TRANSP))
3817 {
3818 Rect rc;
3819
3820 rc.left = FILL_X(col);
3821 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003822 /* Multibyte computation taken from gui_w32.c */
3823 if (has_mbyte)
3824 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003825 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003826 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003827 }
3828 else
Bram Moolenaar13505972019-01-24 15:04:48 +01003829 rc.right = FILL_X(col + len) + (col + len == Columns);
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003830 rc.bottom = FILL_Y(row + 1);
3831 EraseRect(&rc);
3832 }
3833
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003834 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 {
3836 StyleParameter face;
3837
3838 face = normal;
3839 if (flags & DRAW_BOLD)
3840 face |= bold;
3841 if (flags & DRAW_UNDERL)
3842 face |= underline;
3843 TextFace(face);
3844
3845 /* Quartz antialiasing works only in srcOr transfer mode. */
3846 TextMode(srcOr);
3847
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 MoveTo(TEXT_X(col), TEXT_Y(row));
3849 DrawText((char*)s, 0, len);
3850 }
3851 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852 {
3853 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003854 TextMode(srcCopy);
3855 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003856
3857 /* SelectFont(hdc, gui.currFont); */
3858
3859 if (flags & DRAW_TRANSP)
3860 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003861 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 }
3863
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003864 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003865 DrawText((char *)s, 0, len);
3866
3867 if (flags & DRAW_BOLD)
3868 {
3869 TextMode(srcOr);
3870 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3871 DrawText((char *)s, 0, len);
3872 }
3873
3874 if (flags & DRAW_UNDERL)
3875 {
3876 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3877 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3878 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003879 if (flags & DRAW_STRIKE)
3880 {
3881 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3882 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3883 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003884 }
3885
3886 if (flags & DRAW_UNDERC)
3887 draw_undercurl(flags, row, col, len);
3888
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003889 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003890}
3891
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003892#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003893
3894 static void
3895draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3896{
3897 /* ATSUI requires utf-16 strings */
3898 UniCharCount utf16_len;
3899 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3900 utf16_len /= sizeof(UniChar);
3901
3902 /* - ATSUI automatically antialiases text (Someone)
3903 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003904#ifdef MAC_ATSUI_DEBUG
3905 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3906 row, col, len, len == 1 ? s[0] : ' ');
3907#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003908 /*
3909 * When antialiasing we're using srcOr mode, we have to clear the block
3910 * before drawing the text.
3911 * Also needed when 'linespace' is non-zero to remove the cursor and
3912 * underlining.
3913 * But not when drawing transparently.
3914 * The following is like calling gui_mch_clear_block(row, col, row, col +
3915 * len - 1), but without setting the bg color to gui.back_pixel.
3916 */
3917 if ((flags & DRAW_TRANSP) == 0)
3918 {
3919 Rect rc;
3920
3921 rc.left = FILL_X(col);
3922 rc.top = FILL_Y(row);
3923 /* Multibyte computation taken from gui_w32.c */
3924 if (has_mbyte)
3925 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003926 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003927 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003928 }
3929 else
3930 rc.right = FILL_X(col + len) + (col + len == Columns);
3931
3932 rc.bottom = FILL_Y(row + 1);
3933 EraseRect(&rc);
3934 }
3935
3936 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003937 TextMode(srcCopy);
3938 TextFace(normal);
3939
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003940 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003941 if (flags & DRAW_TRANSP)
3942 {
3943 TextMode(srcOr);
3944 }
3945
3946 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003947
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003948 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003949 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003950 Boolean attValue = true;
3951 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3952 ByteCount attribSizes[] = { sizeof(Boolean) };
3953 ATSUAttributeValuePtr attribValues[] = { &attValue };
3954
3955 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3956 }
3957
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003958 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3959 : kATSStyleNoAntiAliasing;
3960 if (useAntialias != useAntialias_cached)
3961 {
3962 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3963 ByteCount attribSizes[] = { sizeof(UInt32) };
3964 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3965
3966 if (gFontStyle)
3967 ATSUSetAttributes(gFontStyle, 1, attribTags,
3968 attribSizes, attribValues);
3969 if (gWideFontStyle)
3970 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3971 attribSizes, attribValues);
3972
3973 useAntialias_cached = useAntialias;
3974 }
3975
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003976 if (has_mbyte)
3977 {
3978 int n, width_in_cell, last_width_in_cell;
3979 UniCharArrayOffset offset = 0;
3980 UniCharCount yet_to_draw = 0;
3981 ATSUTextLayout textLayout;
3982 ATSUStyle textStyle;
3983
3984 last_width_in_cell = 1;
3985 ATSUCreateTextLayout(&textLayout);
3986 ATSUSetTextPointerLocation(textLayout, tofree,
3987 kATSUFromTextBeginning,
3988 kATSUToTextEnd, utf16_len);
3989 /*
3990 ATSUSetRunStyle(textLayout, gFontStyle,
3991 kATSUFromTextBeginning, kATSUToTextEnd); */
3992
3993 /* Compute the length in display cells. */
3994 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3995 {
3996 width_in_cell = (*mb_ptr2cells)(s + n);
3997
3998 /* probably we are switching from single byte character
3999 * to multibyte characters (which requires more than one
4000 * cell to draw) */
4001 if (width_in_cell != last_width_in_cell)
4002 {
4003#ifdef MAC_ATSUI_DEBUG
4004 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4005 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4006#endif
4007 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4008 : gFontStyle;
4009
4010 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4011 offset += yet_to_draw;
4012 yet_to_draw = 0;
4013 last_width_in_cell = width_in_cell;
4014 }
4015
4016 yet_to_draw++;
4017 }
4018
4019 if (yet_to_draw)
4020 {
4021#ifdef MAC_ATSUI_DEBUG
4022 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4023 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4024#endif
4025 /* finish the rest style */
4026 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4027 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4028 }
4029
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004030 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004031 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004032 kATSUFromTextBeginning, kATSUToTextEnd,
4033 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004034 ATSUDisposeTextLayout(textLayout);
4035 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004036 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004037 {
4038 ATSUTextLayout textLayout;
4039
4040 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4041 kATSUFromTextBeginning, kATSUToTextEnd,
4042 utf16_len,
4043 (gFontStyle ? 1 : 0), &utf16_len,
4044 (gFontStyle ? &gFontStyle : NULL),
4045 &textLayout) == noErr)
4046 {
4047 ATSUSetTransientFontMatching(textLayout, TRUE);
4048
4049 ATSUDrawText(textLayout,
4050 kATSUFromTextBeginning, kATSUToTextEnd,
4051 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4052
4053 ATSUDisposeTextLayout(textLayout);
4054 }
4055 }
4056
4057 /* drawing is done, now reset bold to normal */
4058 if (gFontStyle && flags & DRAW_BOLD)
4059 {
4060 Boolean attValue = false;
4061
4062 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4063 ByteCount attribSizes[] = { sizeof(Boolean) };
4064 ATSUAttributeValuePtr attribValues[] = { &attValue };
4065
4066 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4067 attribValues);
4068 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069 }
4070
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004071 if (flags & DRAW_UNDERC)
4072 draw_undercurl(flags, row, col, len);
4073
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004075}
4076#endif
4077
4078 void
4079gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4080{
4081#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004082 if (p_macatsui == 0 && p_macatsui_last != 0)
4083 /* switch from macatsui to nomacatsui */
4084 gui_mac_dispose_atsui_style();
4085 else if (p_macatsui != 0 && p_macatsui_last == 0)
4086 /* switch from nomacatsui to macatsui */
4087 gui_mac_create_atsui_style();
4088
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004089 if (p_macatsui)
4090 draw_string_ATSUI(row, col, s, len, flags);
4091 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004093 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094}
4095
4096/*
4097 * Return OK if the key with the termcap name "name" is supported.
4098 */
4099 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004100gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101{
4102 int i;
4103
4104 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4105 if (name[0] == special_keys[i].vim_code0 &&
4106 name[1] == special_keys[i].vim_code1)
4107 return OK;
4108 return FAIL;
4109}
4110
4111 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004112gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004114 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115}
4116
4117 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004118gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119{
4120 /* Do a visual beep by reversing the foreground and background colors */
4121 Rect rc;
4122
4123 /*
4124 * Note: InvertRect() excludes right and bottom of rectangle.
4125 */
4126 rc.left = 0;
4127 rc.top = 0;
4128 rc.right = gui.num_cols * gui.char_width;
4129 rc.bottom = gui.num_rows * gui.char_height;
4130 InvertRect(&rc);
4131
4132 ui_delay((long)msec, TRUE); /* wait for some msec */
4133
4134 InvertRect(&rc);
4135}
4136
4137/*
4138 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4139 */
4140 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004141gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142{
4143 Rect rc;
4144
4145 /*
4146 * Note: InvertRect() excludes right and bottom of rectangle.
4147 */
4148 rc.left = FILL_X(c);
4149 rc.top = FILL_Y(r);
4150 rc.right = rc.left + nc * gui.char_width;
4151 rc.bottom = rc.top + nr * gui.char_height;
4152 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153}
4154
4155/*
4156 * Iconify the GUI window.
4157 */
4158 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004159gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160{
4161 /* TODO: find out what could replace iconify
4162 * -window shade?
4163 * -hide application?
4164 */
4165}
4166
4167#if defined(FEAT_EVAL) || defined(PROTO)
4168/*
4169 * Bring the Vim window to the foreground.
4170 */
4171 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004172gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173{
4174 /* TODO */
4175}
4176#endif
4177
4178/*
4179 * Draw a cursor without focus.
4180 */
4181 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004182gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183{
4184 Rect rc;
4185
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 /*
4187 * Note: FrameRect() excludes right and bottom of rectangle.
4188 */
4189 rc.left = FILL_X(gui.col);
4190 rc.top = FILL_Y(gui.row);
4191 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004192 if (mb_lefthalve(gui.row, gui.col))
4193 rc.right += gui.char_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194 rc.bottom = rc.top + gui.char_height;
4195
4196 gui_mch_set_fg_color(color);
4197
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004198 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199}
4200
4201/*
4202 * Draw part of a cursor, only w pixels wide, and h pixels high.
4203 */
4204 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004205gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206{
4207 Rect rc;
4208
4209#ifdef FEAT_RIGHTLEFT
4210 /* vertical line should be on the right of current point */
4211 if (CURSOR_BAR_RIGHT)
4212 rc.left = FILL_X(gui.col + 1) - w;
4213 else
4214#endif
4215 rc.left = FILL_X(gui.col);
4216 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4217 rc.right = rc.left + w;
4218 rc.bottom = rc.top + h;
4219
4220 gui_mch_set_fg_color(color);
4221
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004222 FrameRect(&rc);
4223// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224}
4225
4226
4227
4228/*
4229 * Catch up with any queued X events. This may put keyboard input into the
4230 * input buffer, call resize call-backs, trigger timers etc. If there is
4231 * nothing in the X event queue (& no timers pending), then we return
4232 * immediately.
4233 */
4234 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004235gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236{
4237 /* TODO: find what to do
4238 * maybe call gui_mch_wait_for_chars (0)
4239 * more like look at EventQueue then
4240 * call heart of gui_mch_wait_for_chars;
4241 *
4242 * if (eventther)
4243 * gui_mac_handle_event(&event);
4244 */
4245 EventRecord theEvent;
4246
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004247 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248 if (theEvent.what != nullEvent)
4249 gui_mch_wait_for_chars(0);
4250}
4251
4252/*
4253 * Simple wrapper to neglect more easily the time
4254 * spent inside WaitNextEvent while profiling.
4255 */
4256
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 pascal
4258 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004259WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260{
4261 if (((long) sleep) < -1)
4262 sleep = 32767;
4263 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4264}
4265
4266/*
4267 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4268 * from the keyboard.
4269 * wtime == -1 Wait forever.
4270 * wtime == 0 This should never happen.
4271 * wtime > 0 Wait wtime milliseconds for a character.
4272 * Returns OK if a character was found to be available within the given time,
4273 * or FAIL otherwise.
4274 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004276gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277{
4278 EventMask mask = (everyEvent);
4279 EventRecord event;
4280 long entryTick;
4281 long currentTick;
4282 long sleeppyTick;
4283
4284 /* If we are providing life feedback with the scrollbar,
4285 * we don't want to try to wait for an event, or else
4286 * there won't be any life feedback.
4287 */
4288 if (dragged_sb != NULL)
4289 return FAIL;
4290 /* TODO: Check if FAIL is the proper return code */
4291
4292 entryTick = TickCount();
4293
4294 allow_scrollbar = TRUE;
4295
4296 do
4297 {
4298/* if (dragRectControl == kCreateEmpty)
4299 {
4300 dragRgn = NULL;
4301 dragRectControl = kNothing;
4302 }
4303 else*/ if (dragRectControl == kCreateRect)
4304 {
4305 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004306 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004307 dragRectControl = kNothing;
4308 }
4309 /*
4310 * Don't use gui_mch_update() because then we will spin-lock until a
4311 * char arrives, instead we use WaitNextEventWrp() to hang until an
4312 * event arrives. No need to check for input_buf_full because we are
4313 * returning as soon as it contains a single char.
4314 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004315 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004317 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318 else
4319 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004320
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004321 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004323 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324 if (input_available())
4325 {
4326 allow_scrollbar = FALSE;
4327 return OK;
4328 }
4329 }
4330 currentTick = TickCount();
4331 }
4332 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4333
4334 allow_scrollbar = FALSE;
4335 return FAIL;
4336}
4337
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338/*
4339 * Output routines.
4340 */
4341
4342/* Flush any output to the screen */
4343 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004344gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345{
4346 /* TODO: Is anything needed here? */
4347}
4348
4349/*
4350 * Clear a rectangular region of the screen from text pos (row1, col1) to
4351 * (row2, col2) inclusive.
4352 */
4353 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004354gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355{
4356 Rect rc;
4357
4358 /*
4359 * Clear one extra pixel at the far right, for when bold characters have
4360 * spilled over to the next column.
4361 */
4362 rc.left = FILL_X(col1);
4363 rc.top = FILL_Y(row1);
4364 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4365 rc.bottom = FILL_Y(row2 + 1);
4366
4367 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004368 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369}
4370
4371/*
4372 * Clear the whole text window.
4373 */
4374 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004375gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376{
4377 Rect rc;
4378
4379 rc.left = 0;
4380 rc.top = 0;
4381 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4382 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4383
4384 gui_mch_set_bg_color(gui.back_pixel);
4385 EraseRect(&rc);
4386/* gui_mch_set_fg_color(gui.norm_pixel);
4387 FrameRect(&rc);
4388*/
4389}
4390
4391/*
4392 * Delete the given number of lines from the given row, scrolling up any
4393 * text further down within the scroll region.
4394 */
4395 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004396gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397{
4398 Rect rc;
4399
4400 /* changed without checking! */
4401 rc.left = FILL_X(gui.scroll_region_left);
4402 rc.right = FILL_X(gui.scroll_region_right + 1);
4403 rc.top = FILL_Y(row);
4404 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4405
4406 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004407 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408
4409 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4410 gui.scroll_region_left,
4411 gui.scroll_region_bot, gui.scroll_region_right);
4412}
4413
4414/*
4415 * Insert the given number of lines before the given row, scrolling down any
4416 * following text within the scroll region.
4417 */
4418 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004419gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420{
4421 Rect rc;
4422
4423 rc.left = FILL_X(gui.scroll_region_left);
4424 rc.right = FILL_X(gui.scroll_region_right + 1);
4425 rc.top = FILL_Y(row);
4426 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4427
4428 gui_mch_set_bg_color(gui.back_pixel);
4429
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004430 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431
4432 /* Update gui.cursor_row if the cursor scrolled or copied over */
4433 if (gui.cursor_row >= gui.row
4434 && gui.cursor_col >= gui.scroll_region_left
4435 && gui.cursor_col <= gui.scroll_region_right)
4436 {
4437 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4438 gui.cursor_row += num_lines;
4439 else if (gui.cursor_row <= gui.scroll_region_bot)
4440 gui.cursor_is_valid = FALSE;
4441 }
4442
4443 gui_clear_block(row, gui.scroll_region_left,
4444 row + num_lines - 1, gui.scroll_region_right);
4445}
4446
4447 /*
4448 * TODO: add a vim format to the clipboard which remember
4449 * LINEWISE, CHARWISE, BLOCKWISE
4450 */
4451
4452 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004453clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454{
4455
4456 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004457 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004458 Size scrapSize;
4459 ScrapFlavorFlags scrapFlags;
4460 ScrapRef scrap = nil;
4461 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462 int type;
4463 char *searchCR;
4464 char_u *tempclip;
4465
4466
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004467 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468 if (error != noErr)
4469 return;
4470
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004471 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4472 if (error == noErr)
4473 {
4474 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4475 if (error == noErr && scrapSize > 1)
4476 flavor = 1;
4477 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004479 if (flavor == 0)
4480 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004481 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004482 if (error != noErr)
4483 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004485 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004486 if (error != noErr)
4487 return;
4488 }
4489
4490 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004492 /* In CARBON we don't need a Handle, a pointer is good */
4493 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004495 /* tempclip = lalloc(scrapSize+1, TRUE); */
4496 HLock(textOfClip);
4497 error = GetScrapFlavorData(scrap,
4498 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4499 &scrapSize, *textOfClip);
4500 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004502 if (flavor)
4503 type = **textOfClip;
4504 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004505 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004506
4507 tempclip = lalloc(scrapSize + 1, TRUE);
4508 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4509 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004511#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004512 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004513 /* Convert from utf-16 (clipboard) */
4514 size_t encLen = 0;
4515 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004516
4517 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004519 scrapSize = encLen;
4520 vim_free(tempclip);
4521 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004523 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004525
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004526 searchCR = (char *)tempclip;
4527 while (searchCR != NULL)
4528 {
4529 searchCR = strchr(searchCR, '\r');
4530 if (searchCR != NULL)
4531 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004533
4534 clip_yank_selection(type, tempclip, scrapSize, cbd);
4535
4536 vim_free(tempclip);
4537 HUnlock(textOfClip);
4538
4539 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540}
4541
4542 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004543clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544{
4545 /*
4546 * TODO: Really nothing to do?
4547 */
4548}
4549
4550 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004551clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552{
4553 return OK;
4554}
4555
4556/*
4557 * Send the current selection to the clipboard.
4558 */
4559 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004560clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561{
4562 Handle textOfClip;
4563 long scrapSize;
4564 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566
4567 char_u *str = NULL;
4568
4569 if (!cbd->owned)
4570 return;
4571
4572 clip_get_selection(cbd);
4573
4574 /*
4575 * Once we set the clipboard, lose ownership. If another application sets
4576 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004578 cbd->owned = FALSE;
4579
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004580 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004582#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004583 size_t utf16_len = 0;
4584 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4585 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004587 scrapSize = utf16_len;
4588 vim_free(str);
4589 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 }
4591#endif
4592
4593 if (type >= 0)
4594 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004595 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004597 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004598 HLock(textOfClip);
4599
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004600 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004601 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004602 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004603 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004604 scrapSize, *textOfClip + 1);
4605 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4606 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 HUnlock(textOfClip);
4608 DisposeHandle(textOfClip);
4609 }
4610
4611 vim_free(str);
4612}
4613
4614 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004615gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616{
4617 Rect VimBound;
4618
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004619/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621
4622 if (gui.which_scrollbars[SBAR_LEFT])
4623 {
4624 VimBound.left = -gui.scrollbar_width + 1;
4625 }
4626 else
4627 {
4628 VimBound.left = 0;
4629 }
4630
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004633 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634}
4635
4636/*
4637 * Menu stuff.
4638 */
4639
4640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004641gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642{
4643 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004644 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645 */
4646}
4647
4648 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004649gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650{
4651 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004652 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 */
4654}
4655
4656/*
4657 * Add a sub menu to the menu bar.
4658 */
4659 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004660gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661{
4662 /*
4663 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4664 * TODO: use menu->mnemonic and menu->actext
4665 * TODO: Try to reuse menu id
4666 * Carbon Help suggest to use only id between 1 and 235
4667 */
4668 static long next_avail_id = 128;
4669 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004670 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 short index;
4672 vimmenu_T *parent = menu->parent;
4673 vimmenu_T *brother = menu->next;
4674
4675 /* Cannot add a menu if ... */
4676 if ((parent != NULL && parent->submenu_id == 0))
4677 return;
4678
4679 /* menu ID greater than 1024 are reserved for ??? */
4680 if (next_avail_id == 1024)
4681 return;
4682
4683 /* My brother could be the PopUp, find my real brother */
4684 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4685 brother = brother->next;
4686
4687 /* Find where to insert the menu (for MenuBar) */
4688 if ((parent == NULL) && (brother != NULL))
4689 menu_after_me = brother->submenu_id;
4690
4691 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4692 if (!menu_is_menubar(menu->name))
4693 menu_after_me = hierMenu;
4694
4695 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004696#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004697 name = menu_title_removing_mnemonic(menu);
4698#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004700#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 if (name == NULL)
4702 return;
4703
4704 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 {
4706 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004707 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4708 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709 */
4710 menu->submenu_id = next_avail_id;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004711 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4712 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 next_avail_id++;
4714 }
4715
4716 if (parent == NULL)
4717 {
4718 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4719
4720 /* TODO: Verify if we could only Insert Menu if really part of the
4721 * menubar The Inserted menu are scanned or the Command-key combos
4722 */
4723
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004724 /* Insert the menu */
4725 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726#if 1
4727 /* Vim should normally update it. TODO: verify */
4728 DrawMenuBar();
4729#endif
4730 }
4731 else
4732 {
4733 /* Adding as a submenu */
4734
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004735 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736
4737 /* Call InsertMenuItem followed by SetMenuItemText
4738 * to avoid special character recognition by InsertMenuItem
4739 */
4740 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004741 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4743 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4744 InsertMenu(menu->submenu_handle, hierMenu);
4745 }
4746
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004747 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748
4749#if 0
4750 /* Done by Vim later on */
4751 DrawMenuBar();
4752#endif
4753}
4754
4755/*
4756 * Add a menu item to a menu
4757 */
4758 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004759gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004761 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762 vimmenu_T *parent = menu->parent;
4763 int menu_inserted;
4764
4765 /* Cannot add item, if the menu have not been created */
4766 if (parent->submenu_id == 0)
4767 return;
4768
4769 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4770 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4771
4772 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004773#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004774 name = menu_title_removing_mnemonic(menu);
4775#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004777#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778
4779 /* Where are just a menu item, so no handle, no id */
4780 menu->submenu_id = 0;
4781 menu->submenu_handle = NULL;
4782
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783 menu_inserted = 0;
4784 if (menu->actext)
4785 {
4786 /* If the accelerator text for the menu item looks like it describes
4787 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4788 * item's command equivalent.
4789 */
4790 int key = 0;
4791 int modifiers = 0;
4792 char_u *p_actext;
4793
4794 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004795 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796 if (*p_actext != 0)
4797 key = 0; /* error: trailing text */
4798 /* find_special_key() returns a keycode with as many of the
4799 * specified modifiers as appropriate already applied (e.g., for
4800 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4801 * as the only modifier). Since we want to display all of the
4802 * modifiers, we need to convert the keycode back to a printable
4803 * character plus modifiers.
4804 * TODO: Write an alternative find_special_key() that doesn't
4805 * apply modifiers.
4806 */
4807 if (key > 0 && key < 32)
4808 {
4809 /* Convert a control key to an uppercase letter. Note that
4810 * by this point it is no longer possible to distinguish
4811 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4812 */
4813 modifiers |= MOD_MASK_CTRL;
4814 key += '@';
4815 }
4816 /* If the keycode is an uppercase letter, set the Shift modifier.
4817 * If it is a lowercase letter, don't set the modifier, but convert
4818 * the letter to uppercase for display in the menu.
4819 */
4820 else if (key >= 'A' && key <= 'Z')
4821 modifiers |= MOD_MASK_SHIFT;
4822 else if (key >= 'a' && key <= 'z')
4823 key += 'A' - 'a';
4824 /* Note: keycodes below 0x22 are reserved by Apple. */
4825 if (key >= 0x22 && vim_isprintc_strict(key))
4826 {
4827 int valid = 1;
4828 char_u mac_mods = kMenuNoModifiers;
4829 /* Convert Vim modifier codes to Menu Manager equivalents. */
4830 if (modifiers & MOD_MASK_SHIFT)
4831 mac_mods |= kMenuShiftModifier;
4832 if (modifiers & MOD_MASK_CTRL)
4833 mac_mods |= kMenuControlModifier;
4834 if (!(modifiers & MOD_MASK_CMD))
4835 mac_mods |= kMenuNoCommandModifier;
4836 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4837 valid = 0; /* TODO: will Alt someday map to Option? */
4838 if (valid)
4839 {
4840 char_u item_txt[10];
4841 /* Insert the menu item after idx, with its command key. */
4842 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4843 item_txt[3] = key;
4844 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4845 /* Set the modifier keys. */
4846 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4847 menu_inserted = 1;
4848 }
4849 }
4850 }
4851 /* Call InsertMenuItem followed by SetMenuItemText
4852 * to avoid special character recognition by InsertMenuItem
4853 */
4854 if (!menu_inserted)
4855 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4856 /* Set the menu item name. */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004857 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858
4859#if 0
4860 /* Called by Vim */
4861 DrawMenuBar();
4862#endif
4863
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004864 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865}
4866
4867 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004868gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869{
4870 /* no tearoff menus */
4871}
4872
4873/*
4874 * Destroy the machine specific menu widget.
4875 */
4876 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004877gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004879 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004880
4881 if (index > 0)
4882 {
4883 if (menu->parent)
4884 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004885 {
4886 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004887 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888
4889 /* Delete the Menu if it was a hierarchical Menu */
4890 if (menu->submenu_id != 0)
4891 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004892 DeleteMenu(menu->submenu_id);
4893 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894 }
4895 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896 }
4897#ifdef DEBUG_MAC_MENU
4898 else
4899 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004900 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 }
4902#endif
4903 }
4904 else
4905 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004907 DeleteMenu(menu->submenu_id);
4908 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 }
4910 }
4911 /* Shouldn't this be already done by Vim. TODO: Check */
4912 DrawMenuBar();
4913}
4914
4915/*
4916 * Make a menu either grey or not grey.
4917 */
4918 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004919gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920{
4921 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004922 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923/*
4924 index = menu->index;
4925*/
4926 if (grey)
4927 {
4928 if (menu->children)
4929 DisableMenuItem(menu->submenu_handle, index);
4930 if (menu->parent)
4931 if (menu->parent->submenu_handle)
4932 DisableMenuItem(menu->parent->submenu_handle, index);
4933 }
4934 else
4935 {
4936 if (menu->children)
4937 EnableMenuItem(menu->submenu_handle, index);
4938 if (menu->parent)
4939 if (menu->parent->submenu_handle)
4940 EnableMenuItem(menu->parent->submenu_handle, index);
4941 }
4942}
4943
4944/*
4945 * Make menu item hidden or not hidden
4946 */
4947 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004948gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949{
4950 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004951 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952}
4953
4954
4955/*
4956 * This is called after setting all the menus to grey/hidden or not.
4957 */
4958 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004959gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004960{
4961 DrawMenuBar();
4962}
4963
4964
4965/*
4966 * Scrollbar stuff.
4967 */
4968
4969 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004970gui_mch_enable_scrollbar(
4971 scrollbar_T *sb,
4972 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973{
4974 if (flag)
4975 ShowControl(sb->id);
4976 else
4977 HideControl(sb->id);
4978
4979#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004980 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981#endif
4982}
4983
4984 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004985gui_mch_set_scrollbar_thumb(
4986 scrollbar_T *sb,
4987 long val,
4988 long size,
4989 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990{
4991 SetControl32BitMaximum (sb->id, max);
4992 SetControl32BitMinimum (sb->id, 0);
4993 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004994 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02004996 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997#endif
4998}
4999
5000 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005001gui_mch_set_scrollbar_pos(
5002 scrollbar_T *sb,
5003 int x,
5004 int y,
5005 int w,
5006 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007{
5008 gui_mch_set_bg_color(gui.back_pixel);
5009/* if (gui.which_scrollbars[SBAR_LEFT])
5010 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005011 MoveControl(sb->id, x-16, y);
5012 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 }
5014 else
5015 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005016 MoveControl(sb->id, x, y);
5017 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 }*/
5019 if (sb == &gui.bottom_sbar)
5020 h += 1;
5021 else
5022 w += 1;
5023
5024 if (gui.which_scrollbars[SBAR_LEFT])
5025 x -= 15;
5026
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005027 MoveControl(sb->id, x, y);
5028 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005030 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005031#endif
5032}
5033
5034 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005035gui_mch_create_scrollbar(
5036 scrollbar_T *sb,
5037 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038{
5039 Rect bounds;
5040
5041 bounds.top = -16;
5042 bounds.bottom = -10;
5043 bounds.right = -10;
5044 bounds.left = -16;
5045
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005046 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 &bounds,
5048 "\pScrollBar",
5049 TRUE,
5050 0, /* current*/
5051 0, /* top */
5052 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 (long) sb->ident);
5055#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005056 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057#endif
5058}
5059
5060 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005061gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062{
5063 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005064 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005066 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067#endif
5068}
5069
Bram Moolenaar703a8042016-06-04 16:24:32 +02005070 int
5071gui_mch_is_blinking(void)
5072{
5073 return FALSE;
5074}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005076 int
5077gui_mch_is_blink_off(void)
5078{
5079 return FALSE;
5080}
5081
Bram Moolenaar071d4272004-06-13 20:20:40 +00005082/*
5083 * Cursor blink functions.
5084 *
5085 * This is a simple state machine:
5086 * BLINK_NONE not blinking at all
5087 * BLINK_OFF blinking, cursor is not shown
5088 * BLINK_ON blinking, cursor is shown
5089 */
5090 void
5091gui_mch_set_blinking(long wait, long on, long off)
5092{
5093 /* TODO: TODO: TODO: TODO: */
5094/* blink_waittime = wait;
5095 blink_ontime = on;
5096 blink_offtime = off;*/
5097}
5098
5099/*
5100 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5101 */
5102 void
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005103gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104{
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005105 if (may_call_gui_update_cursor)
5106 gui_update_cursor(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107 /* TODO: TODO: TODO: TODO: */
5108/* gui_w32_rm_blink_timer();
5109 if (blink_state == BLINK_OFF)
5110 gui_update_cursor(TRUE, FALSE);
5111 blink_state = BLINK_NONE;*/
5112}
5113
5114/*
5115 * Start the cursor blinking. If it was already blinking, this restarts the
5116 * waiting time and shows the cursor.
5117 */
5118 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005119gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120{
5121 gui_update_cursor(TRUE, FALSE);
5122 /* TODO: TODO: TODO: TODO: */
5123/* gui_w32_rm_blink_timer(); */
5124
5125 /* Only switch blinking on if none of the times is zero */
5126/* if (blink_waittime && blink_ontime && blink_offtime)
5127 {
5128 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5129 (TIMERPROC)_OnBlinkTimer);
5130 blink_state = BLINK_ON;
5131 gui_update_cursor(TRUE, FALSE);
5132 }*/
5133}
5134
5135/*
5136 * Return the RGB value of a pixel as long.
5137 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005138 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139gui_mch_get_rgb(guicolor_T pixel)
5140{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005141 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142}
5143
5144
5145
5146#ifdef FEAT_BROWSE
5147/*
5148 * Pop open a file browser and return the file selected, in allocated memory,
5149 * or NULL if Cancel is hit.
5150 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5151 * title - Title message for the file browser dialog.
5152 * dflt - Default name of file.
5153 * ext - Default extension to be added to files without extensions.
5154 * initdir - directory in which to open the browser (NULL = current dir)
5155 * filter - Filter for matched files to choose from.
5156 * Has a format like this:
5157 * "C Files (*.c)\0*.c\0"
5158 * "All Files\0*.*\0\0"
5159 * If these two strings were concatenated, then a choice of two file
5160 * filters will be selectable to the user. Then only matching files will
5161 * be shown in the browser. If NULL, the default allows all files.
5162 *
5163 * *NOTE* - the filter string must be terminated with TWO nulls.
5164 */
5165 char_u *
5166gui_mch_browse(
5167 int saving,
5168 char_u *title,
5169 char_u *dflt,
5170 char_u *ext,
5171 char_u *initdir,
5172 char_u *filter)
5173{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005174 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005175 NavReplyRecord reply;
5176 char_u *fname = NULL;
5177 char_u **fnames = NULL;
5178 long numFiles;
5179 NavDialogOptions navOptions;
5180 OSErr error;
5181
5182 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005183 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184
5185
5186 /* TODO: If we get a :browse args, set the Multiple bit. */
5187 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5188 | kNavDontAutoTranslate
5189 | kNavDontAddTranslateItems
5190 /* | kNavAllowMultipleFiles */
5191 | kNavAllowStationery;
5192
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005193 (void) C2PascalString(title, &navOptions.message);
5194 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005195 /* Could set clientName?
5196 * windowTitle? (there's no title bar?)
5197 */
5198
5199 if (saving)
5200 {
5201 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005202 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 if (!reply.validRecord)
5204 return NULL;
5205 }
5206 else
5207 {
5208 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5209 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5210 if (!reply.validRecord)
5211 return NULL;
5212 }
5213
5214 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5215
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005216 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217
5218 if (fnames)
5219 {
5220 fname = fnames[0];
5221 vim_free(fnames);
5222 }
5223
5224 /* TODO: Shorten the file name if possible */
5225 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005226}
5227#endif /* FEAT_BROWSE */
5228
5229#ifdef FEAT_GUI_DIALOG
5230/*
5231 * Stuff for dialogues
5232 */
5233
5234/*
5235 * Create a dialogue dynamically from the parameter strings.
5236 * type = type of dialogue (question, alert, etc.)
5237 * title = dialogue title. may be NULL for default title.
5238 * message = text to display. Dialogue sizes to accommodate it.
5239 * buttons = '\n' separated list of button captions, default first.
5240 * dfltbutton = number of default button.
5241 *
5242 * This routine returns 1 if the first button is pressed,
5243 * 2 for the second, etc.
5244 *
5245 * 0 indicates Esc was pressed.
5246 * -1 for unexpected error
5247 *
5248 * If stubbing out this fn, return 1.
5249 */
5250
5251typedef struct
5252{
5253 short idx;
5254 short width; /* Size of the text in pixel */
5255 Rect box;
5256} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5257
5258#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5259
5260 static void
5261macMoveDialogItem(
5262 DialogRef theDialog,
5263 short itemNumber,
5264 short X,
5265 short Y,
5266 Rect *inBox)
5267{
5268#if 0 /* USE_CARBONIZED */
5269 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005270 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005272 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273#else
5274 short itemType;
5275 Handle itemHandle;
5276 Rect localBox;
5277 Rect *itemBox = &localBox;
5278
5279 if (inBox != nil)
5280 itemBox = inBox;
5281
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005282 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5283 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5284 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285 /* To move a control (like a button) we need to call both
5286 * MoveControl and SetDialogItem. FAQ 6-18 */
5287 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005288 MoveControl((ControlRef) itemHandle, X, Y);
5289 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290#endif
5291}
5292
5293 static void
5294macSizeDialogItem(
5295 DialogRef theDialog,
5296 short itemNumber,
5297 short width,
5298 short height)
5299{
5300 short itemType;
5301 Handle itemHandle;
5302 Rect itemBox;
5303
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005304 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005305
5306 /* When width or height is zero do not change it */
5307 if (width == 0)
5308 width = itemBox.right - itemBox.left;
5309 if (height == 0)
5310 height = itemBox.bottom - itemBox.top;
5311
5312#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005313 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005314#else
5315 /* Resize the bounding box */
5316 itemBox.right = itemBox.left + width;
5317 itemBox.bottom = itemBox.top + height;
5318
5319 /* To resize a control (like a button) we need to call both
5320 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5321 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005322 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005323
5324 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005325 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326#endif
5327}
5328
5329 static void
5330macSetDialogItemText(
5331 DialogRef theDialog,
5332 short itemNumber,
5333 Str255 itemName)
5334{
5335 short itemType;
5336 Handle itemHandle;
5337 Rect itemBox;
5338
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005339 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340
5341 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005342 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005343 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005344 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345}
5346
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005347
5348/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5349 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5350 * setting gDialogHotKeys to NULL disables any hotkey handling.
5351 */
5352 static pascal Boolean
5353DialogHotkeyFilterProc (
5354 DialogRef theDialog,
5355 EventRecord *event,
5356 DialogItemIndex *itemHit)
5357{
5358 char_u keyHit;
5359
5360 if (event->what == keyDown || event->what == autoKey)
5361 {
5362 keyHit = (event->message & charCodeMask);
5363
5364 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5365 {
5366#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5367 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5368#endif
5369 *itemHit = gDialogHotKeys[keyHit];
5370
5371 /* When handing off to StdFilterProc, pretend that the user
5372 * clicked the control manually. Note that this is also supposed
5373 * to cause the button to hilite briefly (to give some user
5374 * feedback), but this seems not to actually work (or it's too
5375 * fast to be seen).
5376 */
5377 event->what = kEventControlSimulateHit;
5378
5379 return true; /* we took care of it */
5380 }
5381
5382 /* Defer to the OS's standard behavior for this event.
5383 * This ensures that Enter will still activate the default button. */
5384 return StdFilterProc(theDialog, event, itemHit);
5385 }
5386 return false; /* Let ModalDialog deal with it */
5387}
5388
5389
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005390/* TODO: There have been some crashes with dialogs, check your inbox
5391 * (Jussi)
5392 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005393 int
5394gui_mch_dialog(
5395 int type,
5396 char_u *title,
5397 char_u *message,
5398 char_u *buttons,
5399 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005400 char_u *textfield,
5401 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005402{
5403 Handle buttonDITL;
5404 Handle iconDITL;
5405 Handle inputDITL;
5406 Handle messageDITL;
5407 Handle itemHandle;
5408 Handle iconHandle;
5409 DialogPtr theDialog;
5410 char_u len;
5411 char_u PascalTitle[256]; /* place holder for the title */
5412 char_u name[256];
5413 GrafPtr oldPort;
5414 short itemHit;
5415 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005416 short hotKeys[256]; /* map of hotkey -> control ID */
5417 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005418 Rect box;
5419 short button;
5420 short lastButton;
5421 short itemType;
5422 short useIcon;
5423 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005424 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005425 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005426 short widestButton = 0;
5427 short dfltButtonEdge = 20; /* gut feeling */
5428 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5429 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5430 short maximumWidth = 400; /* gut feeling */
5431 short maxButtonWidth = 175; /* gut feeling */
5432
5433 short vertical;
5434 short dialogHeight;
5435 short messageLines = 3;
5436 FontInfo textFontInfo;
5437
5438 vgmDlgItm iconItm;
5439 vgmDlgItm messageItm;
5440 vgmDlgItm inputItm;
5441 vgmDlgItm buttonItm;
5442
5443 WindowRef theWindow;
5444
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005445 ModalFilterUPP dialogUPP;
5446
Bram Moolenaar071d4272004-06-13 20:20:40 +00005447 /* Check 'v' flag in 'guioptions': vertical button placement. */
5448 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5449
5450 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005451 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452
5453 /* Get the WindowRef */
5454 theWindow = GetDialogWindow(theDialog);
5455
5456 /* Hide the window.
5457 * 1. to avoid seeing slow drawing
5458 * 2. to prevent a problem seen while moving dialog item
5459 * within a visible window. (non-Carbon MacOS 9)
5460 * Could be avoided by changing the resource.
5461 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005462 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463
5464 /* Change the graphical port to the dialog,
5465 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005466 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005467 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468
5469 /* Get the info about the default text,
5470 * used to calculate the height of the message
5471 * and of the text field */
5472 GetFontInfo(&textFontInfo);
5473
5474 /* Set the dialog title */
5475 if (title != NULL)
5476 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005477 (void) C2PascalString(title, &PascalTitle);
5478 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479 }
5480
5481 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005482 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 buttonChar = buttons;
5484 button = 0;
5485
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005486 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005487 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005488
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 for (;*buttonChar != 0;)
5490 {
5491 /* Get the name of the button */
5492 button++;
5493 len = 0;
5494 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5495 {
5496 if (*buttonChar != DLG_HOTKEY_CHAR)
5497 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005498 else
5499 {
5500 aHotKey = (char_u)*(buttonChar+1);
5501 if (aHotKey >= 'A' && aHotKey <= 'Z')
5502 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5503 hotKeys[aHotKey] = button;
5504#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5505 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5506#endif
5507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005508 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005509
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510 if (*buttonChar != 0)
5511 buttonChar++;
5512 name[0] = len;
5513
5514 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005515 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005516
5517 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005518 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005519
5520 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005521 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005522 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523 /* TODO: Should be based on the message width */
5524 if (width > maxButtonWidth)
5525 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005526 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527
5528 totalButtonWidth += width;
5529
5530 if (width > widestButton)
5531 widestButton = width;
5532 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005533 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534 lastButton = button;
5535
5536 /* Add the icon to the Dialog Box. */
5537 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005538 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 switch (type)
5540 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005541 case VIM_GENERIC:
5542 case VIM_INFO:
5543 case VIM_QUESTION: useIcon = kNoteIcon; break;
5544 case VIM_WARNING: useIcon = kCautionIcon; break;
5545 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005546 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005547 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005548 AppendDITL(theDialog, iconDITL, overlayDITL);
5549 ReleaseResource(iconDITL);
5550 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005551 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005552 iconHandle = GetIcon(useIcon);
5553 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005554
5555 /* Add the message to the Dialog box. */
5556 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005557 messageDITL = GetResource('DITL', 132);
5558 AppendDITL(theDialog, messageDITL, overlayDITL);
5559 ReleaseResource(messageDITL);
5560 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5561 (void) C2PascalString(message, &name);
5562 SetDialogItemText(itemHandle, name);
5563 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005564
5565 /* Add the input box if needed */
5566 if (textfield != NULL)
5567 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005568 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005569 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005570 inputDITL = GetResource('DITL', 132);
5571 AppendDITL(theDialog, inputDITL, overlayDITL);
5572 ReleaseResource(inputDITL);
5573 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5574/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5575 (void) C2PascalString(textfield, &name);
5576 SetDialogItemText(itemHandle, name);
5577 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005578
5579 /* Hotkeys don't make sense if there's a text field */
5580 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005581 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005582 else
5583 /* Install hotkey table */
5584 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005585
5586 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005587 SetDialogDefaultItem(theDialog, dfltbutton);
5588 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589
5590 /* Reposition element */
5591
5592 /* Check if we need to force vertical */
5593 if (totalButtonWidth > maximumWidth)
5594 vertical = TRUE;
5595
5596 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005597 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005598 iconItm.box.right = box.right;
5599 iconItm.box.bottom = box.bottom;
5600
5601 /* Place Message */
5602 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005603 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5604 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605
5606 /* Place Input */
5607 if (textfield != NULL)
5608 {
5609 inputItm.box.left = messageItm.box.left;
5610 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005611 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5612 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613 /* Convert the static text into a text edit.
5614 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005615 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5616 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5618 }
5619
5620 /* Place Button */
5621 if (textfield != NULL)
5622 {
5623 buttonItm.box.left = inputItm.box.left;
5624 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5625 }
5626 else
5627 {
5628 buttonItm.box.left = messageItm.box.left;
5629 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5630 }
5631
5632 for (button=1; button <= lastButton; button++)
5633 {
5634
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005635 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005636 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 if (vertical)
5638 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005639 macSizeDialogItem(theDialog, button, widestButton, 0);
5640 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005641 }
5642 /* Calculate position of next button */
5643 if (vertical)
5644 buttonItm.box.top = box.bottom + dfltElementSpacing;
5645 else
5646 buttonItm.box.left = box.right + dfltElementSpacing;
5647 }
5648
5649 /* Resize the dialog box */
5650 dialogHeight = box.bottom + dfltElementSpacing;
5651 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5652
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005654 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005655 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005656
5657 /* Display it */
5658 ShowWindow(theWindow);
5659/* BringToFront(theWindow); */
5660 SelectWindow(theWindow);
5661
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005662/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005663#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005664 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005665 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666#endif
5667
Bram Moolenaard68071d2006-05-02 22:08:30 +00005668#ifdef USE_CARBONKEYHANDLER
5669 /* Avoid that we use key events for the main window. */
5670 dialog_busy = TRUE;
5671#endif
5672
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005673 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5674 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5675
Bram Moolenaar071d4272004-06-13 20:20:40 +00005676 /* Hang until one of the button is hit */
5677 do
5678 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005679 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 } while ((itemHit < 1) || (itemHit > lastButton));
5681
Bram Moolenaard68071d2006-05-02 22:08:30 +00005682#ifdef USE_CARBONKEYHANDLER
5683 dialog_busy = FALSE;
5684#endif
5685
Bram Moolenaar071d4272004-06-13 20:20:40 +00005686 /* Copy back the text entered by the user into the param */
5687 if (textfield != NULL)
5688 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005689 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5690 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691#if IOSIZE < 256
5692 /* Truncate the name to IOSIZE if needed */
5693 if (name[0] > IOSIZE)
5694 name[0] = IOSIZE - 1;
5695#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005696 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697 }
5698
5699 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005700 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005702 /* Free the modal filterProc */
5703 DisposeRoutineDescriptor(dialogUPP);
5704
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005705 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005706 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005707
5708 return itemHit;
5709/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005710 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 * SetDialogTimeout(): Auto click a button after timeout
5712 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5713 * MoveDialogItem(): Probably better than SetDialogItem
5714 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005715 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005716 */
5717}
5718#endif /* FEAT_DIALOG_GUI */
5719
5720/*
5721 * Display the saved error message(s).
5722 */
5723#ifdef USE_MCH_ERRMSG
5724 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005725display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005726{
5727 char *p;
5728 char_u pError[256];
5729
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005730 if (error_ga.ga_data == NULL)
5731 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005732
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005733 /* avoid putting up a message box with blanks only */
5734 for (p = (char *)error_ga.ga_data; *p; ++p)
5735 if (!isspace(*p))
5736 {
5737 if (STRLEN(p) > 255)
5738 pError[0] = 255;
5739 else
5740 pError[0] = STRLEN(p);
5741
5742 STRNCPY(&pError[1], p, pError[0]);
5743 ParamText(pError, nil, nil, nil);
5744 Alert(128, nil);
5745 break;
5746 /* TODO: handled message longer than 256 chars
5747 * use auto-sizeable alert
5748 * or dialog with scrollbars (TextEdit zone)
5749 */
5750 }
5751 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752}
5753#endif
5754
5755/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005756 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005757 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005758 void
5759gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760{
5761 Point where;
5762
5763 GetMouse(&where);
5764
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005765 *x = where.h;
5766 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767}
5768
5769 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005770gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771{
5772 /* TODO */
5773#if 0
5774 /* From FAQ 3-11 */
5775
5776 CursorDevicePtr myMouse;
5777 Point where;
5778
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005779 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5780 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 {
5782 /* New way */
5783
5784 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005785 * Get first device with one button.
5786 * This will probably be the standard mouse
5787 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005788 *
5789 */
5790
5791 myMouse = nil;
5792
5793 do
5794 {
5795 /* Get the next cursor device */
5796 CursorDeviceNextDevice(&myMouse);
5797 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005798 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005800 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005801 }
5802 else
5803 {
5804 /* Old way */
5805 where.h = x;
5806 where.v = y;
5807
5808 *(Point *)RawMouse = where;
5809 *(Point *)MTemp = where;
5810 *(Ptr) CrsrNew = 0xFFFF;
5811 }
5812#endif
5813}
5814
5815 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005816gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005817{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005818/*
5819 * Clone PopUp to use menu
5820 * Create a object descriptor for the current selection
5821 * Call the procedure
5822 */
5823
5824 MenuHandle CntxMenu;
5825 Point where;
5826 OSStatus status;
5827 UInt32 CntxType;
5828 SInt16 CntxMenuID;
5829 UInt16 CntxMenuItem;
5830 Str255 HelpName = "";
5831 GrafPtr savePort;
5832
5833 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005834 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005836 GetMouse(&where);
5837 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005838 CntxMenu = menu->submenu_handle;
5839
5840 /* TODO: Get the text selection from Vim */
5841
5842 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005843 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005844 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845
5846 if (status == noErr)
5847 {
5848 if (CntxType == kCMMenuItemSelected)
5849 {
5850 /* Handle the menu CntxMenuID, CntxMenuItem */
5851 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005852 /* But what about the current menu, is the menu changed by
5853 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005854 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855 }
5856 else if (CntxMenuID == kCMShowHelpSelected)
5857 {
5858 /* Should come up with the help */
5859 }
5860 }
5861
5862 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005863 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864}
5865
5866#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5867/* TODO: Is it need for MACOS_X? (Dany) */
5868 void
5869mch_post_buffer_write(buf_T *buf)
5870{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005871 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5872 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005873}
5874#endif
5875
5876#ifdef FEAT_TITLE
5877/*
5878 * Set the window title and icon.
5879 * (The icon is not taken care of).
5880 */
5881 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005882gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883{
5884 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5885 * that 256. Even better get it to fit nicely in the titlebar.
5886 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005887#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005888 CFStringRef windowTitle;
5889 size_t windowTitleLen;
5890#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005892#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005893
5894 if (title == NULL) /* nothing to do */
5895 return;
5896
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005897#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005898 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005899 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005900
5901 if (windowTitle)
5902 {
5903 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5904 CFRelease(windowTitle);
5905 }
5906#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907 pascalTitle = C2Pascal_save(title);
5908 if (pascalTitle != NULL)
5909 {
5910 SetWTitle(gui.VimWindow, pascalTitle);
5911 vim_free(pascalTitle);
5912 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005913#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005914}
5915#endif
5916
5917/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005918 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 */
5920
5921 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005922C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923{
5924 char_u *PascalPtr = (char_u *) PascalString;
5925 int len;
5926 int i;
5927
5928 PascalPtr[0] = 0;
5929 if (CString == NULL)
5930 return 0;
5931
5932 len = STRLEN(CString);
5933 if (len > 255)
5934 len = 255;
5935
5936 for (i = 0; i < len; i++)
5937 PascalPtr[i+1] = CString[i];
5938
5939 PascalPtr[0] = len;
5940
5941 return 0;
5942}
5943
5944 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005945GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946{
5947 /* From FAQ 8-12 */
5948 Str255 filePascal;
5949 CInfoPBRec myCPB;
5950 OSErr err;
5951
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005952 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953
5954 myCPB.dirInfo.ioNamePtr = filePascal;
5955 myCPB.dirInfo.ioVRefNum = 0;
5956 myCPB.dirInfo.ioFDirIndex = 0;
5957 myCPB.dirInfo.ioDrDirID = 0;
5958
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005959 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005960
5961 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005962 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005963
5964 /* TODO: Use an error code mechanism */
5965 return 0;
5966}
5967
5968/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005969 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00005970 */
5971
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005972char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005973{
5974 /*
5975 * TODO: Add protection for 256 char max.
5976 */
5977
5978 CInfoPBRec theCPB;
5979 char_u fname[256];
5980 char_u *filenamePtr = fname;
5981 OSErr error;
5982 int folder = 1;
5983#ifdef USE_UNIXFILENAME
5984 SInt16 dfltVol_vRefNum;
5985 SInt32 dfltVol_dirID;
5986 FSRef refFile;
5987 OSStatus status;
5988 UInt32 pathSize = 256;
5989 char_u pathname[256];
5990 char_u *path = pathname;
5991#else
5992 Str255 directoryName;
5993 char_u temporary[255];
5994 char_u *temporaryPtr = temporary;
5995#endif
5996
5997#ifdef USE_UNIXFILENAME
5998 /* Get the default volume */
5999 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006000 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001
6002 if (error)
6003 return NULL;
6004#endif
6005
6006 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006007 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008
6009 /* Get the info about the file specified in FSSpec */
6010 theCPB.dirInfo.ioFDirIndex = 0;
6011 theCPB.dirInfo.ioNamePtr = file.name;
6012 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006013 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014 theCPB.dirInfo.ioDrDirID = file.parID;
6015
6016 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6017 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006018 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019
6020 /* If we are called for a new file we expect fnfErr */
6021 if ((error) && (error != fnfErr))
6022 return NULL;
6023
6024 /* Check if it's a file or folder */
6025 /* default to file if file don't exist */
6026 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6027 folder = 0; /* It's not a folder */
6028 else
6029 folder = 1;
6030
6031#ifdef USE_UNIXFILENAME
6032 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006033 * The functions used here are available in Carbon, but do nothing on
6034 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035 */
6036 if (error == fnfErr)
6037 {
6038 /* If the file to be saved does not already exist, it isn't possible
6039 to convert its FSSpec into an FSRef. But we can construct an
6040 FSSpec for the file's parent folder (since we have its volume and
6041 directory IDs), and since that folder does exist, we can convert
6042 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6043 and, finally, append the filename. */
6044 FSSpec dirSpec;
6045 FSRef dirRef;
6046 Str255 emptyFilename = "\p";
6047 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6048 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6049 if (error)
6050 return NULL;
6051
6052 error = FSpMakeFSRef(&dirSpec, &dirRef);
6053 if (error)
6054 return NULL;
6055
6056 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6057 if (status)
6058 return NULL;
6059
6060 STRCAT(path, "/");
6061 STRCAT(path, filenamePtr);
6062 }
6063 else
6064 {
6065 /* If the file to be saved already exists, we can get its full path
6066 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006067 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068 if (error)
6069 return NULL;
6070
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006071 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 if (status)
6073 return NULL;
6074 }
6075
6076 /* Add a slash at the end if needed */
6077 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006078 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006080 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006081#else
6082 /* TODO: Get rid of all USE_UNIXFILENAME below */
6083 /* Set ioNamePtr, it's the same area which is always reused. */
6084 theCPB.dirInfo.ioNamePtr = directoryName;
6085
6086 /* Trick for first entry, set ioDrParID to the first value
6087 * we want for ioDrDirID*/
6088 theCPB.dirInfo.ioDrParID = file.parID;
6089 theCPB.dirInfo.ioDrDirID = file.parID;
6090
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006091 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 do
6093 {
6094 theCPB.dirInfo.ioFDirIndex = -1;
6095 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6096 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006097 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6099
6100 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6101 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006102 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103
6104 if (error)
6105 return NULL;
6106
6107 /* Put the new directoryName in front of the current fname */
6108 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006109 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006110 STRCAT(filenamePtr, ":");
6111 STRCAT(filenamePtr, temporaryPtr);
6112 }
6113#if 1 /* def USE_UNIXFILENAME */
6114 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6115 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6116#else
6117 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6118#endif
6119
6120 /* Get the information about the volume on which the file reside */
6121 theCPB.dirInfo.ioFDirIndex = -1;
6122 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6123 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006124 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6126
6127 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6128 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006129 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130
6131 if (error)
6132 return NULL;
6133
6134 /* For MacOS Classic always add the volume name */
6135 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006136 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137#ifdef USE_UNIXFILENAME
6138 if (file.vRefNum != dfltVol_vRefNum)
6139#endif
6140 {
6141 /* Add the volume name */
6142 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006143 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144 STRCAT(filenamePtr, ":");
6145 STRCAT(filenamePtr, temporaryPtr);
6146
6147#ifdef USE_UNIXFILENAME
6148 STRCPY(temporaryPtr, filenamePtr);
6149 filenamePtr[0] = 0; /* NULL terminate the string */
6150 STRCAT(filenamePtr, "Volumes:");
6151 STRCAT(filenamePtr, temporaryPtr);
6152#endif
6153 }
6154
6155 /* Append final path separator if it's a folder */
6156 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006157 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158
6159 /* As we use Unix File Name for MacOS X convert it */
6160#ifdef USE_UNIXFILENAME
6161 /* Need to insert leading / */
6162 /* TODO: get the above code to use directly the / */
6163 STRCPY(&temporaryPtr[1], filenamePtr);
6164 temporaryPtr[0] = '/';
6165 STRCPY(filenamePtr, temporaryPtr);
6166 {
6167 char *p;
6168 for (p = fname; *p; p++)
6169 if (*p == ':')
6170 *p = '/';
6171 }
6172#endif
6173
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006174 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006175#endif
6176}
6177
Bram Moolenaar13505972019-01-24 15:04:48 +01006178#if defined(USE_CARBONKEYHANDLER) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179/*
6180 * Input Method Control functions.
6181 */
6182
6183/*
6184 * Notify cursor position to IM.
6185 */
6186 void
6187im_set_position(int row, int col)
6188{
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006189# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006190 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006191 im_start_row = row;
6192 im_start_col = col;
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006193# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006194}
6195
6196static ScriptLanguageRecord gTSLWindow;
6197static ScriptLanguageRecord gTSLInsert;
6198static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6199
6200static Component gTSCWindow;
6201static Component gTSCInsert;
6202static Component gTSCDefault;
6203
6204static int im_initialized = 0;
6205
6206 static void
6207im_on_window_switch(int active)
6208{
6209 ScriptLanguageRecord *slptr = NULL;
6210 OSStatus err;
6211
6212 if (! gui.in_use)
6213 return;
6214
6215 if (im_initialized == 0)
6216 {
6217 im_initialized = 1;
6218
6219 /* save default TSM component (should be U.S.) to default */
6220 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6221 kKeyboardInputMethodClass);
6222 }
6223
6224 if (active == TRUE)
6225 {
6226 im_is_active = TRUE;
6227 ActivateTSMDocument(gTSMDocument);
6228 slptr = &gTSLWindow;
6229
6230 if (slptr)
6231 {
6232 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6233 kKeyboardInputMethodClass);
6234 if (err == noErr)
6235 err = SetTextServiceLanguage(slptr);
6236
6237 if (err == noErr)
6238 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6239 }
6240 }
6241 else
6242 {
6243 err = GetTextServiceLanguage(&gTSLWindow);
6244 if (err == noErr)
6245 slptr = &gTSLWindow;
6246
6247 if (slptr)
6248 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6249 kKeyboardInputMethodClass);
6250
6251 im_is_active = FALSE;
6252 DeactivateTSMDocument(gTSMDocument);
6253 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254}
6255
6256/*
6257 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6258 */
6259 void
6260im_set_active(int active)
6261{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006262 ScriptLanguageRecord *slptr = NULL;
6263 OSStatus err;
6264
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006265 if (!gui.in_use)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006266 return;
6267
6268 if (im_initialized == 0)
6269 {
6270 im_initialized = 1;
6271
6272 /* save default TSM component (should be U.S.) to default */
6273 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6274 kKeyboardInputMethodClass);
6275 }
6276
6277 if (active == TRUE)
6278 {
6279 im_is_active = TRUE;
6280 ActivateTSMDocument(gTSMDocument);
6281 slptr = &gTSLInsert;
6282
6283 if (slptr)
6284 {
6285 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6286 kKeyboardInputMethodClass);
6287 if (err == noErr)
6288 err = SetTextServiceLanguage(slptr);
6289
6290 if (err == noErr)
6291 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6292 }
6293 }
6294 else
6295 {
6296 err = GetTextServiceLanguage(&gTSLInsert);
6297 if (err == noErr)
6298 slptr = &gTSLInsert;
6299
6300 if (slptr)
6301 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6302 kKeyboardInputMethodClass);
6303
6304 /* restore to default when switch to normal mode, so than we could
6305 * enter commands easier */
6306 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6307 kKeyboardInputMethodClass);
6308 SetTextServiceLanguage(&gTSLDefault);
6309
6310 im_is_active = FALSE;
6311 DeactivateTSMDocument(gTSMDocument);
6312 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006313}
6314
6315/*
6316 * Get IM status. When IM is on, return not 0. Else return 0.
6317 */
6318 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006319im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006321 if (! gui.in_use)
6322 return 0;
6323
6324 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006326
Bram Moolenaar13505972019-01-24 15:04:48 +01006327#endif
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006328
6329
6330
6331#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6332// drawer implementation
6333static MenuRef contextMenu = NULL;
6334enum
6335{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006336 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006337};
6338
6339// the caller has to CFRelease() the returned string
6340 static CFStringRef
6341getTabLabel(tabpage_T *page)
6342{
6343 get_tabline_label(page, FALSE);
6344#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006345 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006346#else
6347 // TODO: check internal encoding?
6348 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6349 kCFStringEncodingMacRoman);
6350#endif
6351}
6352
6353
6354#define DRAWER_SIZE 150
6355#define DRAWER_INSET 16
6356
6357static ControlRef dataBrowser = NULL;
6358
6359// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006360// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006361// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006362// for a very short time. to prevent inconsistent state, we store the labels
6363// of the tabs, not pointers to the tabs (which are invalid for a short time).
6364static CFStringRef *tabLabels = NULL;
6365static int tabLabelsSize = 0;
6366
6367enum
6368{
6369 kTabsColumn = 'Tabs'
6370};
6371
6372 static int
6373getTabCount(void)
6374{
6375 tabpage_T *tp;
6376 int numTabs = 0;
6377
Bram Moolenaar29323592016-07-24 22:04:11 +02006378 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006379 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006380 return numTabs;
6381}
6382
6383// data browser item display callback
6384 static OSStatus
6385dbItemDataCallback(ControlRef browser,
6386 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006387 DataBrowserPropertyID property /* column id */,
6388 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006389 Boolean changeValue)
6390{
6391 OSStatus status = noErr;
6392
6393 // assert(property == kTabsColumn); // why is this violated??
6394
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006395 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006396 // In our case, it's always false.
6397 // (that is: if (changeValue) updateInternalData(); else return
6398 // internalData();
6399 if (!changeValue)
6400 {
6401 CFStringRef str;
6402
6403 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6404 str = tabLabels[itemID - 1];
6405 status = SetDataBrowserItemDataText(itemData, str);
6406 }
6407 else
6408 status = errDataBrowserPropertyNotSupported;
6409
6410 return status;
6411}
6412
6413// data browser action callback
6414 static void
6415dbItemNotificationCallback(ControlRef browser,
6416 DataBrowserItemID item,
6417 DataBrowserItemNotification message)
6418{
6419 switch (message)
6420 {
6421 case kDataBrowserItemSelected:
6422 send_tabline_event(item);
6423 break;
6424 }
6425}
6426
6427// callbacks needed for contextual menu:
6428 static void
6429dbGetContextualMenuCallback(ControlRef browser,
6430 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006431 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006432 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006433 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006434{
6435 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6436 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6437 *helpItemString = NULL;
6438
6439 *menu = contextMenu;
6440}
6441
6442 static void
6443dbSelectContextualMenuCallback(ControlRef browser,
6444 MenuRef menu,
6445 UInt32 selectionType,
6446 SInt16 menuID,
6447 MenuItemIndex menuItem)
6448{
6449 if (selectionType == kCMMenuItemSelected)
6450 {
6451 MenuCommand command;
6452 GetMenuItemCommandID(menu, menuItem, &command);
6453
6454 // get tab that was selected when the context menu appeared
6455 // (there is always one tab selected). TODO: check if the context menu
6456 // isn't opened on an item but on empty space (has to be possible some
6457 // way, the finder does it too ;-) )
6458 Handle items = NewHandle(0);
6459 if (items != NULL)
6460 {
6461 int numItems;
6462
6463 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6464 kDataBrowserItemIsSelected, items);
6465 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6466 if (numItems > 0)
6467 {
6468 int idx;
6469 DataBrowserItemID *itemsPtr;
6470
6471 HLock(items);
6472 itemsPtr = (DataBrowserItemID *)*items;
6473 idx = itemsPtr[0];
6474 HUnlock(items);
6475 send_tabline_menu_event(idx, command);
6476 }
6477 DisposeHandle(items);
6478 }
6479 }
6480}
6481
6482// focus callback of the data browser to always leave focus in vim
6483 static OSStatus
6484dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6485{
6486 assert(GetEventClass(event) == kEventClassControl
6487 && GetEventKind(event) == kEventControlSetFocusPart);
6488
6489 return paramErr;
6490}
6491
6492
6493// drawer callback to resize data browser to drawer size
6494 static OSStatus
6495drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6496{
6497 switch (GetEventKind(event))
6498 {
6499 case kEventWindowBoundsChanged: // move or resize
6500 {
6501 UInt32 attribs;
6502 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6503 NULL, sizeof(attribs), NULL, &attribs);
6504 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6505 {
6506 Rect r;
6507 GetWindowBounds(drawer, kWindowContentRgn, &r);
6508 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6509 SetControlBounds(dataBrowser, &r);
6510 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6511 kTabsColumn, r.right);
6512 }
6513 }
6514 break;
6515 }
6516
6517 return eventNotHandledErr;
6518}
6519
6520// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6521// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6522// blue highlights in the list view on these systems, though. Oh well.)
6523
6524
6525#import <mach-o/dyld.h>
6526
6527enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6528
6529 static OSStatus
6530myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6531 OptionBits inAttributesToSet,
6532 OptionBits inAttributesToClear)
6533{
6534 long osVersion;
6535 char *symbolName;
6536 NSSymbol symbol = NULL;
6537 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6538 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6539
6540 Gestalt(gestaltSystemVersion, &osVersion);
6541 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6542 return noErr;
6543
6544 // C name mangling...
6545 symbolName = "_DataBrowserChangeAttributes";
6546 if (!NSIsSymbolNameDefined(symbolName)
6547 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6548 return noErr;
6549
6550 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6551 if (dataBrowserChangeAttributes == NULL)
6552 return noErr; // well...
6553 return dataBrowserChangeAttributes(inDataBrowser,
6554 inAttributesToSet, inAttributesToClear);
6555}
6556
6557 static void
6558initialise_tabline(void)
6559{
6560 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6561 DataBrowserCallbacks dbCallbacks;
6562 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6563 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6564 DataBrowserListViewColumnDesc colDesc;
6565
6566 // drawers have to have compositing enabled
6567 CreateNewWindow(kDrawerWindowClass,
6568 kWindowStandardHandlerAttribute
6569 | kWindowCompositingAttribute
6570 | kWindowResizableAttribute
6571 | kWindowLiveResizeAttribute,
6572 &drawerRect, &drawer);
6573
6574 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6575 SetDrawerParent(drawer, gui.VimWindow);
6576 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6577
6578
6579 // create list view embedded in drawer
6580 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6581 &dataBrowser);
6582
6583 dbCallbacks.version = kDataBrowserLatestCallbacks;
6584 InitDataBrowserCallbacks(&dbCallbacks);
6585 dbCallbacks.u.v1.itemDataCallback =
6586 NewDataBrowserItemDataUPP(dbItemDataCallback);
6587 dbCallbacks.u.v1.itemNotificationCallback =
6588 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6589 dbCallbacks.u.v1.getContextualMenuCallback =
6590 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6591 dbCallbacks.u.v1.selectContextualMenuCallback =
6592 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6593
6594 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6595
6596 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6597 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6598 SetDataBrowserSelectionFlags(dataBrowser,
6599 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6600 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6601 kDataBrowserTableViewFillHilite);
6602 Boolean b = false;
6603 SetControlData(dataBrowser, kControlEntireControl,
6604 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6605
6606 // enable blue background in data browser (this is only in 10.4 and vim
6607 // has to support older osx versions as well, so we have to load this
6608 // function dynamically)
6609 myDataBrowserChangeAttributes(dataBrowser,
6610 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6611
6612 // install callback that keeps focus in vim and away from the data browser
6613 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6614 NULL, NULL);
6615
6616 // install callback that keeps data browser at the size of the drawer
6617 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6618 NULL, NULL);
6619
6620 // add "tabs" column to data browser
6621 colDesc.propertyDesc.propertyID = kTabsColumn;
6622 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6623
6624 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6625 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6626
6627 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6628 colDesc.headerBtnDesc.minimumWidth = 100;
6629 colDesc.headerBtnDesc.maximumWidth = 150;
6630 colDesc.headerBtnDesc.titleOffset = 0;
6631 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6632 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6633 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6634 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6635
6636 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6637
6638 // create tabline popup menu required by vim docs (see :he tabline-menu)
6639 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar29547192018-12-11 20:39:19 +01006640 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006641 TABLINE_MENU_CLOSE, NULL);
6642 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6643 TABLINE_MENU_NEW, NULL);
6644 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6645 TABLINE_MENU_OPEN, NULL);
6646}
6647
6648
6649/*
6650 * Show or hide the tabline.
6651 */
6652 void
6653gui_mch_show_tabline(int showit)
6654{
6655 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006656 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006657 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006658 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006659}
6660
6661/*
6662 * Return TRUE when tabline is displayed.
6663 */
6664 int
6665gui_mch_showing_tabline(void)
6666{
6667 WindowDrawerState state = GetDrawerState(drawer);
6668
6669 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6670}
6671
6672/*
6673 * Update the labels of the tabline.
6674 */
6675 void
6676gui_mch_update_tabline(void)
6677{
6678 tabpage_T *tp;
6679 int numTabs = getTabCount();
6680 int nr = 1;
6681 int curtabidx = 1;
6682
6683 // adjust data browser
6684 if (tabLabels != NULL)
6685 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006686 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006687
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006688 for (i = 0; i < tabLabelsSize; ++i)
6689 CFRelease(tabLabels[i]);
6690 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006691 }
6692 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6693 tabLabelsSize = numTabs;
6694
6695 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6696 {
6697 if (tp == curtab)
6698 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006699 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006700 }
6701
6702 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6703 kDataBrowserItemNoProperty);
6704 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6705 // can pass NULL for the id array
6706 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6707 kDataBrowserItemNoProperty);
6708
6709 DataBrowserItemID item = curtabidx;
6710 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6711}
6712
6713/*
6714 * Set the current tab to "nr". First tab is 1.
6715 */
6716 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006717gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006718{
6719 DataBrowserItemID item = nr;
6720 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6721
6722 // TODO: call something like this?: (or restore scroll position, or...)
6723 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6724 kDataBrowserRevealOnly);
6725}
6726
6727#endif // FEAT_GUI_TABLINE