blob: 185cdee28e5a4dfeb033ff02a0e49705fd6a9223 [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))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 c++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 *p = *c;
365 p++;
366 len++;
367 }
368 PascalString[0] = len;
369 }
370
371 return PascalString;
372}
373
374/*
375 * Convert the modifiers of an Event into vim's modifiers (mouse)
376 */
377
378 int_u
379EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
380{
381 int_u vimModifiers = 0x00;
382
383 if (macModifiers & (shiftKey | rightShiftKey))
384 vimModifiers |= MOUSE_SHIFT;
385 if (macModifiers & (controlKey | rightControlKey))
386 vimModifiers |= MOUSE_CTRL;
387 if (macModifiers & (optionKey | rightOptionKey))
388 vimModifiers |= MOUSE_ALT;
389#if 0
390 /* Not yet supported */
391 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
392 vimModifiers |= MOUSE_CMD;
393#endif
394 return (vimModifiers);
395}
396
397/*
398 * Convert the modifiers of an Event into vim's modifiers (keys)
399 */
400
401 static int_u
402EventModifiers2VimModifiers(EventModifiers macModifiers)
403{
404 int_u vimModifiers = 0x00;
405
406 if (macModifiers & (shiftKey | rightShiftKey))
407 vimModifiers |= MOD_MASK_SHIFT;
408 if (macModifiers & (controlKey | rightControlKey))
409 vimModifiers |= MOD_MASK_CTRL;
410 if (macModifiers & (optionKey | rightOptionKey))
411 vimModifiers |= MOD_MASK_ALT;
412#ifdef USE_CMD_KEY
413 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
414 vimModifiers |= MOD_MASK_CMD;
415#endif
416 return (vimModifiers);
417}
418
419/* Convert a string representing a point size into pixels. The string should
420 * be a positive decimal number, with an optional decimal point (eg, "12", or
421 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
422 * character is stored in *end. The flag "vertical" says whether this
423 * calculation is for a vertical (height) size or a horizontal (width) one.
424 *
425 * From gui_w48.c
426 */
427 static int
428points_to_pixels(char_u *str, char_u **end, int vertical)
429{
430 int pixels;
431 int points = 0;
432 int divisor = 0;
433
434 while (*str)
435 {
436 if (*str == '.' && divisor == 0)
437 {
438 /* Start keeping a divisor, for later */
439 divisor = 1;
440 continue;
441 }
442
443 if (!isdigit(*str))
444 break;
445
446 points *= 10;
447 points += *str - '0';
448 divisor *= 10;
449
450 ++str;
451 }
452
453 if (divisor == 0)
454 divisor = 1;
455
456 pixels = points/divisor;
457 *end = str;
458 return pixels;
459}
460
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000461#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000462/*
463 * Deletes all traces of any Windows-style mnemonic text (including any
464 * parentheses) from a menu item and returns the cleaned menu item title.
465 * The caller is responsible for releasing the returned string.
466 */
467 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000468menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000469{
470 CFStringRef name;
471 size_t menuTitleLen;
472 CFIndex displayLen;
473 CFRange mnemonicStart;
474 CFRange mnemonicEnd;
475 CFMutableStringRef cleanedName;
476
477 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000478 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000479
480 if (name)
481 {
482 /* Simple mnemonic-removal algorithm, assumes single parenthesized
483 * mnemonic character towards the end of the menu text */
484 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
485 displayLen = CFStringGetLength(name);
486
487 if (mnemonicStart.location != kCFNotFound
488 && (mnemonicStart.location + 2) < displayLen
489 && CFStringGetCharacterAtIndex(name,
490 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
491 {
492 if (CFStringFindWithOptions(name, CFSTR(")"),
493 CFRangeMake(mnemonicStart.location + 1,
494 displayLen - mnemonicStart.location - 1),
495 kCFCompareBackwards, &mnemonicEnd) &&
496 (mnemonicStart.location + 2) == mnemonicEnd.location)
497 {
498 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
499 if (cleanedName)
500 {
501 CFStringDelete(cleanedName,
502 CFRangeMake(mnemonicStart.location,
503 mnemonicEnd.location + 1 -
504 mnemonicStart.location));
505
506 CFRelease(name);
507 name = cleanedName;
508 }
509 }
510 }
511 }
512
513 return name;
514}
515#endif
516
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517/*
518 * Convert a list of FSSpec aliases into a list of fullpathname
519 * character strings.
520 */
521
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000522 char_u **
523new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524{
525 char_u **fnames = NULL;
526 OSErr newError;
527 long fileCount;
528 FSSpec fileToOpen;
529 long actualSize;
530 AEKeyword dummyKeyword;
531 DescType dummyType;
532
533 /* Get number of files in list */
534 *error = AECountItems(theList, numFiles);
535 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000536 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537
538 /* Allocate the pointer list */
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200539 fnames = ALLOC_MULT(char_u *, *numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540
541 /* Empty out the list */
542 for (fileCount = 0; fileCount < *numFiles; fileCount++)
543 fnames[fileCount] = NULL;
544
545 /* Scan the list of FSSpec */
546 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
547 {
548 /* Get the alias for the nth file, convert to an FSSpec */
549 newError = AEGetNthPtr(theList, fileCount, typeFSS,
550 &dummyKeyword, &dummyType,
551 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
552 if (newError)
553 {
554 /* Caller is able to clean up */
555 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000556 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 }
558
559 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000560 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 }
562
563 return (fnames);
564}
565
566/*
567 * ------------------------------------------------------------
568 * CodeWarrior External Editor Support
569 * ------------------------------------------------------------
570 */
571#ifdef FEAT_CW_EDITOR
572
573/*
574 * Handle the Window Search event from CodeWarrior
575 *
576 * Description
577 * -----------
578 *
579 * The IDE sends the Window Search AppleEvent to the editor when it
580 * needs to know whether a particular file is open in the editor.
581 *
582 * Event Reply
583 * -----------
584 *
585 * None. Put data in the location specified in the structure received.
586 *
587 * Remarks
588 * -------
589 *
590 * When the editor receives this event, determine whether the specified
591 * file is open. If it is, return the modification date/time for that file
592 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000593 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 *
595 */
596
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597typedef struct WindowSearch WindowSearch;
598struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
599{
600 FSSpec theFile; // identifies the file
601 long *theDate; // where to put the modification date/time
602};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000604 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000605Handle_KAHL_SRCH_AE(
606 const AppleEvent *theAEvent,
607 AppleEvent *theReply,
608 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609{
610 OSErr error = noErr;
611 buf_T *buf;
612 int foundFile = false;
613 DescType typeCode;
614 WindowSearch SearchData;
615 Size actualSize;
616
617 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
618 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000619 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000621 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000623 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624
Bram Moolenaar29323592016-07-24 22:04:11 +0200625 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 if (buf->b_ml.ml_mfp != NULL
627 && SearchData.theFile.parID == buf->b_FSSpec.parID
628 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
629 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
630 {
631 foundFile = true;
632 break;
633 }
634
635 if (foundFile == false)
636 *SearchData.theDate = fnfErr;
637 else
638 *SearchData.theDate = buf->b_mtime;
639
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 return error;
641};
642
643/*
644 * Handle the Modified (from IDE to Editor) event from CodeWarrior
645 *
646 * Description
647 * -----------
648 *
649 * The IDE sends this event to the external editor when it wants to
650 * know which files that are open in the editor have been modified.
651 *
652 * Parameters None.
653 * ----------
654 *
655 * Event Reply
656 * -----------
657 * The reply for this event is:
658 *
659 * keyDirectObject typeAEList required
660 * each element in the list is a structure of typeChar
661 *
662 * Remarks
663 * -------
664 *
665 * When building the reply event, include one element in the list for
666 * each open file that has been modified.
667 *
668 */
669
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670typedef struct ModificationInfo ModificationInfo;
671struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
672{
673 FSSpec theFile; // identifies the file
674 long theDate; // the date/time the file was last modified
675 short saved; // set this to zero when replying, unused
676};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000678 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000679Handle_KAHL_MOD_AE(
680 const AppleEvent *theAEvent,
681 AppleEvent *theReply,
682 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683{
684 OSErr error = noErr;
685 AEDescList replyList;
686 long numFiles;
687 ModificationInfo theFile;
688 buf_T *buf;
689
690 theFile.saved = 0;
691
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000692 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000694 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695
696 /* Send the reply */
697/* replyObject.descriptorType = typeNull;
698 replyObject.dataHandle = nil;*/
699
700/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
701 error = AECreateList(nil, 0, false, &replyList);
702 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000703 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
705#if 0
706 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000708 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
709 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 * sizeof(DescType))
711 */
712
713 /* AEPutDesc */
714#endif
715
716 numFiles = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +0200717 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 if (buf->b_ml.ml_mfp != NULL)
719 {
720 /* Add this file to the list */
721 theFile.theFile = buf->b_FSSpec;
722 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000723/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
724 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 };
726
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727#if 0
728 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729#endif
730
731 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000732 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 if (replyList.dataHandle)
735 AEDisposeDesc(&replyList);
736
737 return error;
738};
739
740/*
741 * Handle the Get Text event from CodeWarrior
742 *
743 * Description
744 * -----------
745 *
746 * The IDE sends the Get Text AppleEvent to the editor when it needs
747 * the source code from a file. For example, when the user issues a
748 * Check Syntax or Compile command, the compiler needs access to
749 * the source code contained in the file.
750 *
751 * Event Reply
752 * -----------
753 *
754 * None. Put data in locations specified in the structure received.
755 *
756 * Remarks
757 * -------
758 *
759 * When the editor receives this event, it must set the size of the handle
760 * in theText to fit the data in the file. It must then copy the entire
761 * contents of the specified file into the memory location specified in
762 * theText.
763 *
764 */
765
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766typedef struct CW_GetText CW_GetText;
767struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
768{
769 FSSpec theFile; /* identifies the file */
770 Handle theText; /* the location where you return the text (must be resized properly) */
771 long *unused; /* 0 (not used) */
772 long *theDate; /* where to put the modification date/time */
773};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000775 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000776Handle_KAHL_GTTX_AE(
777 const AppleEvent *theAEvent,
778 AppleEvent *theReply,
779 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780{
781 OSErr error = noErr;
782 buf_T *buf;
783 int foundFile = false;
784 DescType typeCode;
785 CW_GetText GetTextData;
786 Size actualSize;
787 char_u *line;
788 char_u *fullbuffer = NULL;
789 long linesize;
790 long lineStart;
791 long BufferSize;
792 long lineno;
793
794 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
795
796 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000797 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798
Bram Moolenaar29323592016-07-24 22:04:11 +0200799 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 if (buf->b_ml.ml_mfp != NULL)
801 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
802 {
803 foundFile = true;
804 break;
805 }
806
807 if (foundFile)
808 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000809 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
811 {
812 /* Must use the right buffer */
813 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
814 linesize = STRLEN(line) + 1;
815 lineStart = BufferSize;
816 BufferSize += linesize;
817 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 SetHandleSize(GetTextData.theText, BufferSize);
819 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 break; /* Simple handling for now */
822 }
823 else
824 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000825 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000827 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000829 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 }
831 }
832 if (fullbuffer != NULL)
833 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000834 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 }
838 if (foundFile == false)
839 *GetTextData.theDate = fnfErr;
840 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000841/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842 *GetTextData.theDate = buf->b_mtime;
843 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000847 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848}
849
850/*
851 *
852 */
853
854/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000855 pascal OSErr
856FindProcessBySignature(
857 const OSType targetType,
858 const OSType targetCreator,
859 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860{
861 OSErr anErr = noErr;
862 Boolean lookingForProcess = true;
863
864 ProcessInfoRec infoRec;
865
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000866 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 infoRec.processName = nil;
868 infoRec.processAppSpec = nil;
869
870 psnPtr->lowLongOfPSN = kNoProcess;
871 psnPtr->highLongOfPSN = kNoProcess;
872
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000873 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 anErr = GetNextProcess(psnPtr);
876 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 else
879 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000880 anErr = GetProcessInformation(psnPtr, &infoRec);
881 if ((anErr == noErr)
882 && (infoRec.processType == targetType)
883 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 }
886 }
887
888 return anErr;
889}//end FindProcessBySignature
890
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000891 void
892Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000894 OSErr anErr = noErr;
895 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
897 AppleEvent theReply = { typeNull, nil };
898 AESendMode sendMode;
899 AppleEvent theEvent = {typeNull, nil };
900 AEIdleUPP idleProcUPP = nil;
901 ModificationInfo ModData;
902
903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000904 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000905 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000907 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
908 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000910 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 {
912 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
913 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
914 }
915
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917
918 /* Add the parms */
919 ModData.theFile = buf->b_FSSpec;
920 ModData.theDate = buf->b_mtime;
921
922 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000923 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000925 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 sendMode = kAENoReply;
927 else
928 sendMode = kAEWaitReply;
929
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000930 if (anErr == noErr)
931 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
932 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000936 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 }
938}
939#endif /* FEAT_CW_EDITOR */
940
941/*
942 * ------------------------------------------------------------
943 * Apple Event Handling procedure
944 * ------------------------------------------------------------
945 */
946#ifdef USE_AEVENT
947
948/*
949 * Handle the Unused parms of an AppleEvent
950 */
951
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000952 OSErr
953HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954{
955 OSErr error;
956 long actualSize;
957 DescType dummyType;
958 AEKeyword missedKeyword;
959
960 /* Get the "missed keyword" attribute from the AppleEvent. */
961 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
962 typeKeyword, &dummyType,
963 (Ptr)&missedKeyword, sizeof(missedKeyword),
964 &actualSize);
965
966 /* If the descriptor isn't found, then we got the required parameters. */
967 if (error == errAEDescNotFound)
968 {
969 error = noErr;
970 }
971 else
972 {
973#if 0
974 /* Why is this removed? */
975 error = errAEEventNotHandled;
976#endif
977 }
978
979 return error;
980}
981
982
983/*
984 * Handle the ODoc AppleEvent
985 *
986 * Deals with all files dragged to the application icon.
987 *
988 */
989
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990typedef struct SelectionRange SelectionRange;
991struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
992{
993 short unused1; // 0 (not used)
994 short lineNum; // line to select (<0 to specify range)
995 long startRange; // start of selection range (if line < 0)
996 long endRange; // end of selection range (if line < 0)
997 long unused2; // 0 (not used)
998 long theDate; // modification date/time
999};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001001static long drop_numFiles;
1002static short drop_gotPosition;
1003static SelectionRange drop_thePosition;
1004
1005 static void
1006drop_callback(void *cookie UNUSED)
1007{
1008 /* TODO: Handle the goto/select line more cleanly */
1009 if ((drop_numFiles == 1) & (drop_gotPosition))
1010 {
1011 if (drop_thePosition.lineNum >= 0)
1012 {
1013 lnum = drop_thePosition.lineNum + 1;
1014 /* oap->motion_type = MLINE;
1015 setpcmark();*/
1016 if (lnum < 1L)
1017 lnum = 1L;
1018 else if (lnum > curbuf->b_ml.ml_line_count)
1019 lnum = curbuf->b_ml.ml_line_count;
1020 curwin->w_cursor.lnum = lnum;
1021 curwin->w_cursor.col = 0;
1022 /* beginline(BL_SOL | BL_FIX);*/
1023 }
1024 else
1025 goto_byte(drop_thePosition.startRange + 1);
1026 }
1027
1028 /* Update the screen display */
1029 update_screen(NOT_VALID);
1030
1031 /* Select the text if possible */
1032 if (drop_gotPosition)
1033 {
1034 VIsual_active = TRUE;
1035 VIsual_select = FALSE;
1036 VIsual = curwin->w_cursor;
1037 if (drop_thePosition.lineNum < 0)
1038 {
1039 VIsual_mode = 'v';
1040 goto_byte(drop_thePosition.endRange);
1041 }
1042 else
1043 {
1044 VIsual_mode = 'V';
1045 VIsual.col = 0;
1046 }
1047 }
1048}
1049
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1051 itor the selection range. If lineNum is zero or greater, scroll the text
1052 to the specified line. If lineNum is less than zero, use the values in
1053 startRange and endRange to select the specified characters. Scroll
1054 the text to display the selection. If lineNum, startRange, and
1055 endRange are all negative, there is no selection range specified.
1056 */
1057
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001058 pascal OSErr
1059HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060{
1061 /*
1062 * TODO: Clean up the code with convert the AppleEvent into
1063 * a ":args"
1064 */
1065 OSErr error = noErr;
1066// OSErr firstError = noErr;
1067// short numErrors = 0;
1068 AEDesc theList;
1069 DescType typeCode;
1070 long numFiles;
1071 // long fileCount;
1072 char_u **fnames;
1073// char_u fname[256];
1074 Size actualSize;
1075 SelectionRange thePosition;
1076 short gotPosition = false;
1077 long lnum;
1078
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 /* the direct object parameter is the list of aliases to files (one or more) */
1080 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1081 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001082 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083
1084
1085 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1086 if (error == noErr)
1087 gotPosition = true;
1088 if (error == errAEDescNotFound)
1089 error = noErr;
1090 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001091 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093/*
1094 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1095
1096 if (^error) then
1097 {
1098 if (thePosition.lineNum >= 0)
1099 {
1100 // Goto this line
1101 }
1102 else
1103 {
1104 // Set the range char wise
1105 }
1106 }
1107 */
1108
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1111
1112 if (error)
1113 {
1114 /* TODO: empty fnames[] first */
1115 vim_free(fnames);
1116 return (error);
1117 }
1118
1119 if (starting > 0)
1120 {
1121 int i;
1122 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001123 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124
1125 /* these are the initial files dropped on the Vim icon */
1126 for (i = 0 ; i < numFiles; i++)
1127 {
1128 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1129 || (p = vim_strsave(fnames[i])) == NULL)
1130 mch_exit(2);
1131 else
1132 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001133 if (fnum == -1)
1134 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1135 }
1136
1137 /* If the file name was already in the buffer list we need to switch
1138 * to it. */
1139 if (curbuf->b_fnum != fnum)
1140 {
1141 char_u cmd[30];
1142
1143 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1144 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001146
1147 /* Change directory to the location of the first file. */
Bram Moolenaarb7407d32018-02-03 17:36:27 +01001148 if (GARGCOUNT > 0
1149 && vim_chdirfile(alist_name(&GARGLIST[0]), "drop") == OK)
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001150 shorten_fnames(TRUE);
1151
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 goto finished;
1153 }
1154
1155 /* Handle the drop, :edit to get to the file */
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001156 drop_numFiles = numFiles;
1157 drop_gotPosition = gotPosition;
1158 drop_thePosition = thePosition;
1159 handle_drop(numFiles, fnames, FALSE, drop_callback, NULL);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001160
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 setcursor();
1162 out_flush();
1163
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001164 /* Fake mouse event to wake from stall */
1165 PostEvent(mouseUp, 0);
1166
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001167finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168 AEDisposeDesc(&theList); /* dispose what we allocated */
1169
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001170 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001171 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172}
1173
1174/*
1175 *
1176 */
1177
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001178 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001179Handle_aevt_oapp_AE(
1180 const AppleEvent *theAEvent,
1181 AppleEvent *theReply,
1182 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183{
1184 OSErr error = noErr;
1185
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001186 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001187 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188}
1189
1190/*
1191 *
1192 */
1193
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001194 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001195Handle_aevt_quit_AE(
1196 const AppleEvent *theAEvent,
1197 AppleEvent *theReply,
1198 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001199{
1200 OSErr error = noErr;
1201
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001202 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001204 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205
1206 /* Need to fake a :confirm qa */
1207 do_cmdline_cmd((char_u *)"confirm qa");
1208
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001209 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210}
1211
1212/*
1213 *
1214 */
1215
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001216 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001217Handle_aevt_pdoc_AE(
1218 const AppleEvent *theAEvent,
1219 AppleEvent *theReply,
1220 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221{
1222 OSErr error = noErr;
1223
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001224 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001226 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227}
1228
1229/*
1230 * Handling of unknown AppleEvent
1231 *
1232 * (Just get rid of all the parms)
1233 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001234 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001235Handle_unknown_AE(
1236 const AppleEvent *theAEvent,
1237 AppleEvent *theReply,
1238 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001239{
1240 OSErr error = noErr;
1241
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001242 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001244 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245}
1246
1247
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248/*
1249 * Install the various AppleEvent Handlers
1250 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001251 OSErr
1252InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253{
1254 OSErr error;
1255
1256 /* install open application handler */
1257 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001258 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261
1262 /* install quit application handler */
1263 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001264 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267
1268 /* install open document handler */
1269 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001270 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273
1274 /* install print document handler */
1275 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001276 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277
1278/* Install Core Suite */
1279/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001280 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281
1282 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001283 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284
1285 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001286 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287
1288 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001289 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290
1291 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001292 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293
1294 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001295 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296
1297 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001298 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299
1300 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001301 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001304 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305
1306 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001307 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308
1309 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001310 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
1312 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001313 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314
1315 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001316 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317*/
1318
1319#ifdef FEAT_CW_EDITOR
1320 /*
1321 * Bind codewarrior support handlers
1322 */
1323 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001324 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325 if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001328 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329 if (error)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001331 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001332 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001333#endif
1334
1335 return error;
1336
1337}
1338#endif /* USE_AEVENT */
1339
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001340
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001341/*
1342 * Callback function, installed by InstallFontPanelHandler(), below,
1343 * to handle Font Panel events.
1344 */
1345 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001346FontPanelHandler(
1347 EventHandlerCallRef inHandlerCallRef,
1348 EventRef inEvent,
1349 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001350{
1351 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1352 {
1353 gFontPanelInfo.isPanelVisible = false;
1354 return noErr;
1355 }
1356
1357 if (GetEventKind(inEvent) == kEventFontSelection)
1358 {
1359 OSStatus status;
1360 FMFontFamily newFamily;
1361 FMFontSize newSize;
1362 FMFontStyle newStyle;
1363
1364 /* Retrieve the font family ID number. */
1365 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1366 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1367 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1368 &newFamily);
1369 if (status == noErr)
1370 gFontPanelInfo.family = newFamily;
1371
1372 /* Retrieve the font size. */
1373 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1374 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1375 if (status == noErr)
1376 gFontPanelInfo.size = newSize;
1377
1378 /* Retrieve the font style (bold, etc.). Currently unused. */
1379 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1380 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1381 if (status == noErr)
1382 gFontPanelInfo.style = newStyle;
1383 }
1384 return noErr;
1385}
1386
1387
1388 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001389InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001390{
1391 EventTypeSpec eventTypes[2];
1392 EventHandlerUPP handlerUPP;
1393 /* EventHandlerRef handlerRef; */
1394
1395 eventTypes[0].eventClass = kEventClassFont;
1396 eventTypes[0].eventKind = kEventFontSelection;
1397 eventTypes[1].eventClass = kEventClassFont;
1398 eventTypes[1].eventKind = kEventFontPanelClosed;
1399
1400 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1401
1402 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1403 /*userData=*/NULL, /*handlerRef=*/NULL);
1404}
1405
1406
1407/*
1408 * Fill the buffer pointed to by outName with the name and size
1409 * of the font currently selected in the Font Panel.
1410 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001411#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001412 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001413GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001414{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001415 Str255 buf;
1416 ByteCount fontNameLen = 0;
1417 ATSUFontID fid;
1418 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001419
1420 if (!outName)
1421 return;
1422
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1424 {
1425 /* Canonicalize localized font names */
1426 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1427 gFontPanelInfo.style, &fid, NULL) != noErr)
1428 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001429
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001430 /* Request font name with Mac encoding (otherwise we could
1431 * get an unwanted utf-16 name) */
1432 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1433 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001434 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001435 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001436
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001437 /* Only encode font size, because style (bold, italic, etc) is
1438 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001439 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001440 gFontPanelInfo.size/*,
1441 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1442 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1443 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1444
1445 if ((fontNameLen + STRLEN(styleString)) < 255)
1446 STRCPY(outName + fontNameLen, styleString);
1447 }
1448 else
1449 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001450 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001451 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001452}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001453
1454
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455/*
1456 * ------------------------------------------------------------
1457 * Unfiled yet
1458 * ------------------------------------------------------------
1459 */
1460
1461/*
1462 * gui_mac_get_menu_item_index
1463 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001464 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001466 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001467gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468{
1469 short index;
1470 short itemIndex = -1;
1471 vimmenu_T *pBrother;
1472
1473 /* Only menu without parent are the:
1474 * -menu in the menubar
1475 * -popup menu
1476 * -toolbar (guess)
1477 *
1478 * Which are not items anyway.
1479 */
1480 if (pMenu->parent)
1481 {
1482 /* Start from the Oldest Brother */
1483 pBrother = pMenu->parent->children;
1484 index = 1;
1485 while ((pBrother) && (itemIndex == -1))
1486 {
1487 if (pBrother == pMenu)
1488 itemIndex = index;
1489 index++;
1490 pBrother = pBrother->next;
1491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001492 }
1493 return itemIndex;
1494}
1495
1496 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001497gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498{
1499 short index;
1500 vimmenu_T *pChildMenu;
1501 vimmenu_T *pElder = pMenu->parent;
1502
1503
1504 /* Only menu without parent are the:
1505 * -menu in the menubar
1506 * -popup menu
1507 * -toolbar (guess)
1508 *
1509 * Which are not items anyway.
1510 */
1511
1512 if ((pElder) && (pElder->submenu_id == menuID))
1513 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1515 pMenu = pMenu->next;
1516 }
1517 else
1518 {
1519 for (; pMenu != NULL; pMenu = pMenu->next)
1520 {
1521 if (pMenu->children != NULL)
1522 {
1523 pChildMenu = gui_mac_get_vim_menu
1524 (menuID, itemIndex, pMenu->children);
1525 if (pChildMenu)
1526 {
1527 pMenu = pChildMenu;
1528 break;
1529 }
1530 }
1531 }
1532 }
1533 return pMenu;
1534}
1535
1536/*
1537 * ------------------------------------------------------------
1538 * MacOS Feedback procedures
1539 * ------------------------------------------------------------
1540 */
1541 pascal
1542 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001543gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544{
1545 scrollbar_T *sb;
1546 int value, dragging;
1547 ControlHandle theControlToUse;
1548 int dont_scroll_save = dont_scroll;
1549
1550 theControlToUse = dragged_sb;
1551
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001552 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553
1554 if (sb == NULL)
1555 return;
1556
1557 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001558 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559 dragging = (partCode != 0);
1560
1561 /* When "allow_scrollbar" is FALSE still need to remember the new
1562 * position, but don't actually scroll by setting "dont_scroll". */
1563 dont_scroll = !allow_scrollbar;
1564 gui_drag_scrollbar(sb, value, dragging);
1565 dont_scroll = dont_scroll_save;
1566}
1567
1568 pascal
1569 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001570gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571{
1572 /* TODO: have live support */
1573 scrollbar_T *sb, *sb_info;
1574 long data;
1575 long value;
1576 int page;
1577 int dragging = FALSE;
1578 int dont_scroll_save = dont_scroll;
1579
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001580 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581
1582 if (sb == NULL)
1583 return;
1584
1585 if (sb->wp != NULL) /* Left or right scrollbar */
1586 {
1587 /*
1588 * Careful: need to get scrollbar info out of first (left) scrollbar
1589 * for window, but keep real scrollbar too because we must pass it to
1590 * gui_drag_scrollbar().
1591 */
1592 sb_info = &sb->wp->w_scrollbars[0];
1593
1594 if (sb_info->size > 5)
1595 page = sb_info->size - 2; /* use two lines of context */
1596 else
1597 page = sb_info->size;
1598 }
1599 else /* Bottom scrollbar */
1600 {
1601 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001602 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 }
1604
1605 switch (partCode)
1606 {
1607 case kControlUpButtonPart: data = -1; break;
1608 case kControlDownButtonPart: data = 1; break;
1609 case kControlPageDownPart: data = page; break;
1610 case kControlPageUpPart: data = -page; break;
1611 default: data = 0; break;
1612 }
1613
1614 value = sb_info->value + data;
1615/* if (value > sb_info->max)
1616 value = sb_info->max;
1617 else if (value < 0)
1618 value = 0;*/
1619
1620 /* When "allow_scrollbar" is FALSE still need to remember the new
1621 * position, but don't actually scroll by setting "dont_scroll". */
1622 dont_scroll = !allow_scrollbar;
1623 gui_drag_scrollbar(sb, value, dragging);
1624 dont_scroll = dont_scroll_save;
1625
1626 out_flush();
1627 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1628
1629/* if (sb_info->wp != NULL)
1630 {
1631 win_T *wp;
1632 int sb_num;
1633
1634 sb_num = 0;
1635 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1636 sb_num++;
1637
1638 if (wp != NULL)
1639 {
1640 current_scrollbar = sb_num;
1641 scrollbar_value = value;
1642 gui_do_scroll();
1643 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1644 }
1645 }*/
1646}
1647
1648/*
1649 * ------------------------------------------------------------
1650 * MacOS Click Handling procedures
1651 * ------------------------------------------------------------
1652 */
1653
1654
1655/*
1656 * Handle a click inside the window, it may happens in the
1657 * scrollbar or the contents.
1658 *
1659 * TODO: Add support for potential TOOLBAR
1660 */
1661 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001662gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663{
1664 Point thePoint;
1665 int_u vimModifiers;
1666 short thePortion;
1667 ControlHandle theControl;
1668 int vimMouseButton;
1669 short dblClick;
1670
1671 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001672 GlobalToLocal(&thePoint);
1673 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001674
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001675 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676
1677 if (theControl != NUL)
1678 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001679 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680
1681 if (thePortion != kControlIndicatorPart)
1682 {
1683 dragged_sb = theControl;
1684 TrackControl(theControl, thePoint, gScrollAction);
1685 dragged_sb = NULL;
1686 }
1687 else
1688 {
1689 dragged_sb = theControl;
1690#if 1
1691 TrackControl(theControl, thePoint, gScrollDrag);
1692#else
1693 TrackControl(theControl, thePoint, NULL);
1694#endif
1695 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1696 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001697 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698 dragged_sb = NULL;
1699 }
1700 }
1701 else
1702 {
1703 /* We are inside the contents */
1704
1705 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1706 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1707
1708 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1709 vimMouseButton = MOUSE_LEFT;
1710
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001712 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713 clickIsPopup = FALSE;
1714
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001715 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1716 {
1717 vimMouseButton = MOUSE_RIGHT;
1718 vimModifiers &= ~MOUSE_CTRL;
1719 clickIsPopup = TRUE;
1720 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721
1722 /* Is it a double click ? */
1723 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1724
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001725 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 gui_send_mouse_event(vimMouseButton, thePoint.h,
1727 thePoint.v, dblClick, vimModifiers);
1728
1729 /* Create the rectangle around the cursor to detect
1730 * the mouse dragging
1731 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732#if 0
1733 /* TODO: Do we need to this even for the contextual menu?
1734 * It may be require for popup_setpos, but for popup?
1735 */
1736 if (vimMouseButton == MOUSE_LEFT)
1737#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001739 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 FILL_Y(Y_2_ROW(thePoint.v)),
1741 FILL_X(X_2_COL(thePoint.h)+1),
1742 FILL_Y(Y_2_ROW(thePoint.v)+1));
1743
1744 dragRectEnbl = TRUE;
1745 dragRectControl = kCreateRect;
1746 }
1747 }
1748}
1749
1750/*
1751 * Handle the click in the titlebar (to move the window)
1752 */
1753 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001754gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755{
1756 Rect movingLimits;
1757 Rect *movingLimitsPtr = &movingLimits;
1758
1759 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001760 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001761 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762}
1763
1764/*
1765 * Handle the click in the grow box
1766 */
1767 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001768gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769{
1770
1771 long newSize;
1772 unsigned short newWidth;
1773 unsigned short newHeight;
1774 Rect resizeLimits;
1775 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776 Rect NewContentRect;
1777
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001778 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779
Bram Moolenaar720c7102007-05-10 18:07:50 +00001780 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 /* TODO: Should this come from Vim? */
1782 resizeLimits.top = 100;
1783 resizeLimits.left = 100;
1784
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1786 newWidth = NewContentRect.right - NewContentRect.left;
1787 newHeight = NewContentRect.bottom - NewContentRect.top;
1788 gui_resize_shell(newWidth, newHeight);
1789 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001790 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791}
1792
1793/*
1794 * Handle the click in the zoom box
1795 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001797gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798{
1799 Rect r;
1800 Point p;
1801 short thePart;
1802
1803 /* ideal width is current */
1804 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1805 if (gui.which_scrollbars[SBAR_LEFT])
1806 p.h += gui.scrollbar_width;
1807 if (gui.which_scrollbars[SBAR_RIGHT])
1808 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001809 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810 p.v = 15 * 1024;
1811
1812 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1813 ? inZoomIn : inZoomOut;
1814
1815 if (!TrackBox(whichWindow, theEvent->where, thePart))
1816 return;
1817
1818 /* use returned width */
1819 p.h = r.right - r.left;
1820 /* adjust returned height */
1821 p.v = r.bottom - r.top - 2 * gui.border_offset;
1822 if (gui.which_scrollbars[SBAR_BOTTOM])
1823 p.v -= gui.scrollbar_height;
1824 p.v -= p.v % gui.char_height;
1825 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001826 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 p.v += gui.scrollbar_height;
1828
1829 ZoomWindowIdeal(whichWindow, thePart, &p);
1830
1831 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1832 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1833 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001834 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836
1837/*
1838 * ------------------------------------------------------------
1839 * MacOS Event Handling procedure
1840 * ------------------------------------------------------------
1841 */
1842
1843/*
1844 * Handle the Update Event
1845 */
1846
1847 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001848gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849{
1850 WindowPtr whichWindow;
1851 GrafPtr savePort;
1852 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 Rect *updateRectPtr;
1855 Rect rc;
1856 Rect growRect;
1857 RgnHandle saveRgn;
1858
1859
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 updateRgn = NewRgn();
1861 if (updateRgn == NULL)
1862 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863
1864 /* This could be done by the caller as we
1865 * don't require anything else out of the event
1866 */
1867 whichWindow = (WindowPtr) event->message;
1868
1869 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001870 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871
1872 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001873 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874
1875 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001876 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 /* Redraw the biggest rectangle covering the area
1878 * to be updated.
1879 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1881# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001882 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 * seem to work under MacOS X (Dany)
1884 */
1885 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1886# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001887
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001890
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001891 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892# if 0
1893 /* Code from original Carbon Port (using GetWindowRegion.
1894 * I believe the UpdateRgn is already in local (Dany)
1895 */
1896 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1897 GlobalToLocal(&botRight(updateRect));
1898# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 /* Update the content (i.e. the text) */
1900 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1901 updateRectPtr->right - updateRectPtr->left,
1902 updateRectPtr->bottom - updateRectPtr->top);
1903 /* Clear the border areas if needed */
1904 gui_mch_set_bg_color(gui.back_pixel);
1905 if (updateRectPtr->left < FILL_X(0))
1906 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001907 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1908 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 }
1910 if (updateRectPtr->top < FILL_Y(0))
1911 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001912 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1913 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 }
1915 if (updateRectPtr->right > FILL_X(Columns))
1916 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001917 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001919 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 }
1921 if (updateRectPtr->bottom > FILL_Y(Rows))
1922 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001923 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001925 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001927 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001928 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929
1930 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001931 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932
1933 /* Update the GrowBox */
1934 /* Taken from FAQ 33-27 */
1935 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001937 GetClip(saveRgn);
1938 ClipRect(&growRect);
1939 DrawGrowIcon(whichWindow);
1940 SetClip(saveRgn);
1941 DisposeRgn(saveRgn);
1942 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943
1944 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001945 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946}
1947
1948/*
1949 * Handle the activate/deactivate event
1950 * (apply to a window)
1951 */
1952 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001953gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954{
1955 WindowPtr whichWindow;
1956
1957 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001958 /* Dim scrollbars */
1959 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001961 ControlRef rootControl;
1962 GetRootControl(gui.VimWindow, &rootControl);
1963 if ((event->modifiers) & activeFlag)
1964 ActivateControl(rootControl);
1965 else
1966 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001968
1969 /* Activate */
1970 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971}
1972
1973
1974/*
1975 * Handle the suspend/resume event
1976 * (apply to the application)
1977 */
1978 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001979gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980{
1981 /* The frontmost application just changed */
1982
1983 /* NOTE: the suspend may happen before the deactivate
1984 * seen on MacOS X
1985 */
1986
1987 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00001988 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 */
1990 if (event->message & 1)
1991 /* Resume */
1992 gui_focus_change(TRUE);
1993 else
1994 /* Suspend */
1995 gui_focus_change(FALSE);
1996}
1997
1998/*
1999 * Handle the key
2000 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002001#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002002 static pascal OSStatus
2003gui_mac_handle_window_activate(
2004 EventHandlerCallRef nextHandler,
2005 EventRef theEvent,
2006 void *data)
2007{
2008 UInt32 eventClass = GetEventClass(theEvent);
2009 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002010
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002011 if (eventClass == kEventClassWindow)
2012 {
2013 switch (eventKind)
2014 {
2015 case kEventWindowActivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002016 im_on_window_switch(TRUE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002017 return noErr;
2018
2019 case kEventWindowDeactivated:
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002020 im_on_window_switch(FALSE);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002021 return noErr;
2022 }
2023 }
2024
2025 return eventNotHandledErr;
2026}
2027
2028 static pascal OSStatus
2029gui_mac_handle_text_input(
2030 EventHandlerCallRef nextHandler,
2031 EventRef theEvent,
2032 void *data)
2033{
2034 UInt32 eventClass = GetEventClass(theEvent);
2035 UInt32 eventKind = GetEventKind(theEvent);
2036
2037 if (eventClass != kEventClassTextInput)
2038 return eventNotHandledErr;
2039
2040 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2041 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2042 (kEventTextInputOffsetToPos != eventKind) &&
2043 (kEventTextInputPosToOffset != eventKind) &&
2044 (kEventTextInputGetSelectedText != eventKind))
2045 return eventNotHandledErr;
2046
2047 switch (eventKind)
2048 {
2049 case kEventTextInputUpdateActiveInputArea:
2050 return gui_mac_update_input_area(nextHandler, theEvent);
2051 case kEventTextInputUnicodeForKeyEvent:
2052 return gui_mac_unicode_key_event(nextHandler, theEvent);
2053
2054 case kEventTextInputOffsetToPos:
2055 case kEventTextInputPosToOffset:
2056 case kEventTextInputGetSelectedText:
2057 break;
2058 }
2059
2060 return eventNotHandledErr;
2061}
2062
2063 static pascal
2064OSStatus gui_mac_update_input_area(
2065 EventHandlerCallRef nextHandler,
2066 EventRef theEvent)
2067{
2068 return eventNotHandledErr;
2069}
2070
2071static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2072 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002073
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002074# define INLINE_KEY_BUFFER_SIZE 80
2075 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002076gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002077 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002078 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002079{
2080 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002081 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002082 UInt32 actualSize;
2083 UniChar *text;
2084 char_u result[INLINE_KEY_BUFFER_SIZE];
2085 short len = 0;
2086 UInt32 key_sym;
2087 char charcode;
2088 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002089 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002090 size_t encLen;
2091 char_u *to = NULL;
2092 Boolean isSpecial = FALSE;
2093 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002094 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002095
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002096 /* Mask the mouse (as per user setting) */
2097 if (p_mh)
2098 ObscureCursor();
2099
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002100 /* Don't use the keys when the dialog wants them. */
2101 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002102 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002103
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002104 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002105 typeUnicodeText, NULL, 0, &actualSize, NULL))
2106 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002107
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002108 text = alloc(actualSize);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002109 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002110 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002111
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002112 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002113 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002114 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002115
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002117 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002118 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002122 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002125 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
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(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002130 require_noerr(err, done);
2131
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002132#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002134 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002135#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002136
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002137 key_char = charcode;
2138 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002139
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002140 /* Find the special key (eg., for cursor keys) */
2141 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002142 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002144 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2145 if (special_keys[i].key_sym == key_sym)
2146 {
2147 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2148 special_keys[i].vim_code1);
2149 key_char = simplify_key(key_char,
2150 (int *)&vimModifiers);
2151 isSpecial = TRUE;
2152 break;
2153 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002154 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002156 /* Intercept CMD-. and CTRL-c */
2157 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002158 ((modifiers & cmdKey) && key_char == '.'))
2159 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002160
2161 if (!isSpecial)
2162 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002163 /* remove SHIFT for keys that are already shifted, e.g.,
2164 * '(' and '*' */
2165 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2166 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002167
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002168 /* remove CTRL from keys that already have it */
2169 if (key_char < 0x20)
2170 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002171
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002172 /* don't process unicode characters here */
2173 if (!IS_SPECIAL(key_char))
2174 {
2175 /* Following code to simplify and consolidate vimModifiers
2176 * taken liberally from gui_w48.c */
2177 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002178
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002179 /* Interpret META, include SHIFT, etc. */
Bram Moolenaar459fd782019-10-13 16:43:39 +02002180 key_char = extract_modifiers(key_char, (int *)&vimModifiers,
2181 TRUE, NULL);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002182 if (key_char == CSI)
2183 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002184
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002185 if (IS_SPECIAL(key_char))
2186 isSpecial = TRUE;
2187 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002188 }
2189
2190 if (vimModifiers)
2191 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002192 result[len++] = CSI;
2193 result[len++] = KS_MODIFIER;
2194 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002195 }
2196
2197 if (isSpecial && IS_SPECIAL(key_char))
2198 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002199 result[len++] = CSI;
2200 result[len++] = K_SECOND(key_char);
2201 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002202 }
2203 else
2204 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002205 encLen = actualSize;
2206 to = mac_utf16_to_enc(text, actualSize, &encLen);
2207 if (to)
2208 {
2209 /* This is basically add_to_input_buf_csi() */
2210 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2211 {
2212 result[len++] = to[i];
2213 if (to[i] == CSI)
2214 {
2215 result[len++] = KS_EXTRA;
2216 result[len++] = (int)KE_CSI;
2217 }
2218 }
2219 vim_free(to);
2220 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002221 }
2222
2223 add_to_input_buf(result, len);
2224 err = noErr;
2225
2226done:
2227 vim_free(text);
2228 if (err == noErr)
2229 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002230 /* Fake event to wake up WNE (required to get
2231 * key repeat working */
2232 PostEvent(keyUp, 0);
2233 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002234 }
2235
2236 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002237}
2238#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 void
2240gui_mac_doKeyEvent(EventRecord *theEvent)
2241{
2242 /* TODO: add support for COMMAND KEY */
2243 long menu;
2244 unsigned char string[20];
2245 short num, i;
2246 short len = 0;
2247 KeySym key_sym;
2248 int key_char;
2249 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002250 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251
2252 /* Mask the mouse (as per user setting) */
2253 if (p_mh)
2254 ObscureCursor();
2255
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002256 /* Get the key code and its ASCII representation */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2258 key_char = theEvent->message & charCodeMask;
2259 num = 1;
2260
2261 /* Intercept CTRL-C */
2262 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002263 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264 if (key_char == Ctrl_C && ctrl_c_interrupts)
2265 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002266 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2267 && (key_char == '2' || key_char == '6'))
2268 {
2269 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2270 if (key_char == '2')
2271 key_char = Ctrl_AT;
2272 else
2273 key_char = Ctrl_HAT;
2274 theEvent->modifiers = 0;
2275 }
2276 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277
2278 /* Intercept CMD-. */
2279 if (theEvent->modifiers & cmdKey)
2280 if (key_char == '.')
2281 got_int = TRUE;
2282
2283 /* Handle command key as per menu */
2284 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2285 if (theEvent->modifiers & cmdKey)
2286 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2287 * Why the mouse button? */
2288 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2289 {
2290 menu = MenuKey(key_char);
2291 if (HiWord(menu))
2292 {
2293 gui_mac_handle_menu(menu);
2294 return;
2295 }
2296 }
2297
2298 /* Convert the modifiers */
2299 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2300
2301
2302 /* Handle special keys. */
2303#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002304 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2306#endif
2307 {
2308 /* Find the special key (for non-printable keyt_char) */
2309 if ((key_char < 0x20) || (key_char == 0x7f))
2310 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2311 if (special_keys[i].key_sym == key_sym)
2312 {
2313# if 0
2314 /* We currently don't have not so special key */
2315 if (special_keys[i].vim_code1 == NUL)
2316 key_char = special_keys[i].vim_code0;
2317 else
2318# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002319 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2320 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002321 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 break;
2323 }
2324 }
2325
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002326 /* For some keys the modifier is included in the char itself. */
2327 if (simplify || key_char == TAB || key_char == ' ')
2328 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329
2330 /* Add the modifier to the input bu if needed */
2331 /* Do not want SHIFT-A or CTRL-A with modifier */
2332 if (!IS_SPECIAL(key_char)
2333 && key_sym != vk_Space
2334 && key_sym != vk_Tab
2335 && key_sym != vk_Return
2336 && key_sym != vk_Enter
2337 && key_sym != vk_Esc)
2338 {
2339#if 1
2340 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002341 if ((modifiers == MOD_MASK_SHIFT)
2342 || (modifiers == MOD_MASK_CTRL)
2343 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344 modifiers = 0;
2345#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002346 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002348 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002350 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 modifiers = modifiers & ~MOD_MASK_SHIFT;
2352#endif
2353 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002354 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002356 string[len++] = CSI;
2357 string[len++] = KS_MODIFIER;
2358 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 }
2360
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002363 string[len++] = CSI;
2364 string[len++] = K_SECOND(key_char);
2365 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 }
2367 else
2368 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002369 /* Convert characters when needed (e.g., from MacRoman to latin1).
2370 * This doesn't work for the NUL byte. */
2371 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 {
2373 char_u from[2], *to;
2374 int l;
2375
2376 from[0] = key_char;
2377 from[1] = NUL;
2378 l = 1;
2379 to = string_convert(&input_conv, from, &l);
2380 if (to != NULL)
2381 {
2382 for (i = 0; i < l && len < 19; i++)
2383 {
2384 if (to[i] == CSI)
2385 {
2386 string[len++] = KS_EXTRA;
2387 string[len++] = KE_CSI;
2388 }
2389 else
2390 string[len++] = to[i];
2391 }
2392 vim_free(to);
2393 }
2394 else
2395 string[len++] = key_char;
2396 }
2397 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 string[len++] = key_char;
2399 }
2400
2401 if (len == 1 && string[0] == CSI)
2402 {
2403 /* Turn CSI into K_CSI. */
2404 string[ len++ ] = KS_EXTRA;
2405 string[ len++ ] = KE_CSI;
2406 }
2407
2408 add_to_input_buf(string, len);
2409}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002410#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411
2412/*
2413 * Handle MouseClick
2414 */
2415 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002416gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417{
2418 short thePart;
2419 WindowPtr whichWindow;
2420
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002421 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002423#ifdef FEAT_GUI_TABLINE
2424 /* prevent that the vim window size changes if it's activated by a
2425 click into the tab pane */
2426 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002427 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002428#endif
2429
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 switch (thePart)
2431 {
2432 case (inDesk):
2433 /* TODO: what to do? */
2434 break;
2435
2436 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002437 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 break;
2439
2440 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002441 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 break;
2443
2444 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002445 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 break;
2447
2448 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002449 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 break;
2451
2452 case (inGoAway):
2453 if (TrackGoAway(whichWindow, theEvent->where))
2454 gui_shell_closed();
2455 break;
2456
2457 case (inZoomIn):
2458 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 break;
2461 }
2462}
2463
2464/*
2465 * Handle MouseMoved
2466 * [this event is a moving in and out of a region]
2467 */
2468 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002469gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470{
2471 Point thePoint;
2472 int_u vimModifiers;
2473
2474 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002475 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2477
2478 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002479 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2483 thePoint.v, FALSE, vimModifiers);
2484
2485 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002486 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 FILL_Y(Y_2_ROW(thePoint.v)),
2488 FILL_X(X_2_COL(thePoint.h)+1),
2489 FILL_Y(Y_2_ROW(thePoint.v)+1));
2490
2491 if (dragRectEnbl)
2492 dragRectControl = kCreateRect;
2493
2494}
2495
2496/*
2497 * Handle the mouse release
2498 */
2499 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002500gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501{
2502 Point thePoint;
2503 int_u vimModifiers;
2504
2505 /* TODO: Properly convert the Contextual menu mouse-up */
2506 /* Potential source of the double menu */
2507 lastMouseTick = theEvent->when;
2508 dragRectEnbl = FALSE;
2509 dragRectControl = kCreateEmpty;
2510 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002511 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512
2513 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514 if (clickIsPopup)
2515 {
2516 vimModifiers &= ~MOUSE_CTRL;
2517 clickIsPopup = FALSE;
2518 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002519 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520}
2521
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 static pascal OSStatus
2523gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2524 void *data)
2525{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526 Point point;
2527 Rect bounds;
2528 UInt32 mod;
2529 SInt32 delta;
2530 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002531 EventMouseWheelAxis axis;
2532
2533 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2534 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2535 && axis != kEventMouseWheelAxisY)
2536 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537
2538 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2539 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2540 goto bail;
2541 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2542 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2543 goto bail;
2544 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2545 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2546 goto bail;
2547
2548 vim_mod = 0;
2549 if (mod & shiftKey)
2550 vim_mod |= MOUSE_SHIFT;
2551 if (mod & controlKey)
2552 vim_mod |= MOUSE_CTRL;
2553 if (mod & optionKey)
2554 vim_mod |= MOUSE_ALT;
2555
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2557 {
2558 point.h -= bounds.left;
2559 point.v -= bounds.top;
2560 }
2561
2562 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2563 point.h, point.v, FALSE, vim_mod);
2564
Bram Moolenaarc236c162008-07-13 17:41:49 +00002565 /* post a bogus event to wake up WaitNextEvent */
2566 PostEvent(keyUp, 0);
2567
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 return noErr;
2569
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002570bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 /*
2572 * when we fail give any additional callback handler a chance to perform
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01002573 * its actions
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 */
2575 return CallNextEventHandler(nextHandler, theEvent);
2576}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577
Bram Moolenaare00289d2010-08-14 21:56:42 +02002578 void
2579gui_mch_mousehide(int hide)
2580{
2581 /* TODO */
2582}
2583
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584#if 0
2585
2586/*
2587 * This would be the normal way of invoking the contextual menu
2588 * but the Vim API doesn't seem to a support a request to get
2589 * the menu that we should display
2590 */
2591 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002592gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593{
2594/*
2595 * Clone PopUp to use menu
2596 * Create a object descriptor for the current selection
2597 * Call the procedure
2598 */
2599
2600// Call to Handle Popup
2601 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2602
2603 if (status != noErr)
2604 return;
2605
2606 if (CntxType == kCMMenuItemSelected)
2607 {
2608 /* Handle the menu CntxMenuID, CntxMenuItem */
2609 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002610 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002611 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 }
2613 else if (CntxMenuID == kCMShowHelpSelected)
2614 {
2615 /* Should come up with the help */
2616 }
2617
2618}
2619#endif
2620
2621/*
2622 * Handle menubar selection
2623 */
2624 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002625gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626{
2627 short menu = HiWord(menuChoice);
2628 short item = LoWord(menuChoice);
2629 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630
2631 if (menu == 256) /* TODO: use constant or gui.xyz */
2632 {
2633 if (item == 1)
2634 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 }
2636 else if (item != 0)
2637 {
2638 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2639
2640 if (theVimMenu)
2641 gui_menu_cb(theVimMenu);
2642 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002643 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644}
2645
2646/*
2647 * Dispatch the event to proper handler
2648 */
2649
2650 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002651gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652{
2653 OSErr error;
2654
2655 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002656 if (IsShowContextualMenuClick(event))
2657 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002659 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002661 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002663 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665
2666 /* Handle normal event */
2667 switch (event->what)
2668 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002669#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670 case (keyDown):
2671 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002672 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002674#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002676 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 break;
2678
2679 case (mouseDown):
2680 gui_mac_doMouseDownEvent(event);
2681 break;
2682
2683 case (mouseUp):
2684 gui_mac_doMouseUpEvent(event);
2685 break;
2686
2687 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002688 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 break;
2690
2691 case (diskEvt):
2692 /* We don't need special handling for disk insertion */
2693 break;
2694
2695 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002696 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697 break;
2698
2699 case (osEvt):
2700 switch ((event->message >> 24) & 0xFF)
2701 {
2702 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002703 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 break;
2705 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002706 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 break;
2708 }
2709 break;
2710
2711#ifdef USE_AEVENT
2712 case (kHighLevelEvent):
2713 /* Someone's talking to us, through AppleEvents */
2714 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2715 break;
2716#endif
2717 }
2718}
2719
2720/*
2721 * ------------------------------------------------------------
2722 * Unknown Stuff
2723 * ------------------------------------------------------------
2724 */
2725
2726
2727 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002728gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729{
2730 char_u c;
2731 char_u *p;
2732 char_u pFontName[256];
2733 Str255 systemFontname;
2734 short font_id;
2735 short size=9;
2736 GuiFont font;
2737#if 0
2738 char_u *fontNamePtr;
2739#endif
2740
2741 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2742 ;
2743
2744 c = *p;
2745 *p = 0;
2746
2747#if 1
2748 STRCPY(&pFontName[1], font_name);
2749 pFontName[0] = STRLEN(font_name);
2750 *p = c;
2751
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002752 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002753 char_u fontName[256];
2754 char_u *styleStart = vim_strchr(font_name, ':');
2755 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2756 vim_strncpy(fontName, font_name, fontNameLen);
2757
2758 ATSUFontID fontRef;
2759 FMFontStyle fontStyle;
2760 font_id = 0;
2761
2762 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2763 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2764 &fontRef) == noErr)
2765 {
2766 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2767 font_id = 0;
2768 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002769
2770 if (font_id == 0)
2771 {
2772 /*
2773 * Try again, this time replacing underscores in the font name
2774 * with spaces (:set guifont allows the two to be used
2775 * interchangeably; the Font Manager doesn't).
2776 */
2777 int i, changed = FALSE;
2778
2779 for (i = pFontName[0]; i > 0; --i)
2780 {
2781 if (pFontName[i] == '_')
2782 {
2783 pFontName[i] = ' ';
2784 changed = TRUE;
2785 }
2786 }
2787 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002788 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2789 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2790 kFontNoLanguageCode, &fontRef) == noErr)
2791 {
2792 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2793 font_id = 0;
2794 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002795 }
2796
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797#else
2798 /* name = C2Pascal_save(menu->dname); */
2799 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2800
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002801 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802#endif
2803
2804
2805 if (font_id == 0)
2806 {
2807 /* Oups, the system font was it the one the user want */
2808
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002809 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2810 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 if (!EqualString(pFontName, systemFontname, false, false))
2812 return NOFONT;
2813 }
2814 if (*p == ':')
2815 {
2816 p++;
2817 /* Set the values found after ':' */
2818 while (*p)
2819 {
2820 switch (*p++)
2821 {
2822 case 'h':
2823 size = points_to_pixels(p, &p, TRUE);
2824 break;
2825 /*
2826 * TODO: Maybe accept width and styles
2827 */
2828 }
2829 while (*p == ':')
2830 p++;
2831 }
2832 }
2833
2834 if (size < 1)
2835 size = 1; /* Avoid having a size of 0 with system font */
2836
2837 font = (size << 16) + ((long) font_id & 0xFFFF);
2838
2839 return font;
2840}
2841
2842/*
2843 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002844 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 * ------------------------------------------------------------
2846 */
2847
2848/*
2849 * Parse the GUI related command-line arguments. Any arguments used are
2850 * deleted from argv, and *argc is decremented accordingly. This is called
2851 * when vim is started, whether or not the GUI has been started.
2852 */
2853 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002854gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855{
2856 /* TODO: Move most of this stuff toward gui_mch_init */
2857#ifdef USE_EXE_NAME
2858 FSSpec applDir;
2859# ifndef USE_FIND_BUNDLE_PATH
2860 short applVRefNum;
2861 long applDirID;
2862 Str255 volName;
2863# else
2864 ProcessSerialNumber psn;
2865 FSRef applFSRef;
2866# endif
2867#endif
2868
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869#if 0
2870 InitCursor();
2871
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873
2874#ifdef USE_AEVENT
2875 (void) InstallAEHandlers();
2876#endif
2877
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002878 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002880 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002882 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883
2884 DrawMenuBar();
2885
2886
2887#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002888 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002890 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891#endif
2892
2893
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 CreateNewWindow(kDocumentWindowClass,
2895 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002896 &windRect, &gui.VimWindow);
2897 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
2899 gui.char_width = 7;
2900 gui.char_height = 11;
2901 gui.char_ascent = 6;
2902 gui.num_rows = 24;
2903 gui.num_cols = 80;
2904 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2905
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002906 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2907 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908
2909 dragRectEnbl = FALSE;
2910 dragRgn = NULL;
2911 dragRectControl = kCreateEmpty;
2912 cursorRgn = NewRgn();
2913#endif
2914#ifdef USE_EXE_NAME
2915# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002916 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002918 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919# else
2920 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2921 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002923 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 /* if (err != noErr) return err; */
2925
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002926 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 /* if (err != noErr) return err; */
2928
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002929 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930
2931 /* This technic return NIL when we disallow_gui */
2932# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002933 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935}
2936
2937#ifndef ALWAYS_USE_GUI
2938/*
2939 * Check if the GUI can be started. Called before gvimrc is sourced.
2940 * Return OK or FAIL.
2941 */
2942 int
2943gui_mch_init_check(void)
2944{
2945 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2946 * using the >console
2947 */
2948 if (disallow_gui) /* see main.c for reason to disallow */
2949 return FAIL;
2950 return OK;
2951}
2952#endif
2953
2954 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002955receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956{
2957 int x, y;
2958 int_u modifiers;
2959 char_u **fnames = NULL;
2960 int count;
2961 int i, j;
2962
2963 /* Get drop position, modifiers and count of items */
2964 {
2965 Point point;
2966 SInt16 mouseUpModifiers;
2967 UInt16 countItem;
2968
2969 GetDragMouse(theDrag, &point, NULL);
2970 GlobalToLocal(&point);
2971 x = point.h;
2972 y = point.v;
2973 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2974 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2975 CountDragItems(theDrag, &countItem);
2976 count = countItem;
2977 }
2978
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002979 fnames = ALLOC_MULT(char_u *, count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 if (fnames == NULL)
2981 return dragNotAcceptedErr;
2982
2983 /* Get file names dropped */
2984 for (i = j = 0; i < count; ++i)
2985 {
2986 DragItemRef item;
2987 OSErr err;
2988 Size size;
2989 FlavorType type = flavorTypeHFS;
2990 HFSFlavor hfsFlavor;
2991
2992 fnames[i] = NULL;
2993 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2994 err = GetFlavorDataSize(theDrag, item, type, &size);
2995 if (err != noErr || size > sizeof(hfsFlavor))
2996 continue;
2997 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2998 if (err != noErr)
2999 continue;
3000 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3001 }
3002 count = j;
3003
3004 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003005
3006 /* Fake mouse event to wake from stall */
3007 PostEvent(mouseUp, 0);
3008
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 return noErr;
3010}
3011
3012/*
3013 * Initialise the GUI. Create all the windows, set up all the call-backs
3014 * etc.
3015 */
3016 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003017gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018{
3019 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003020 Rect windRect;
3021 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003023 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003024 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003025
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003026 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003027 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003028
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029#if 1
3030 InitCursor();
3031
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033
3034#ifdef USE_AEVENT
3035 (void) InstallAEHandlers();
3036#endif
3037
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003038 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003040 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003042 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043
3044 DrawMenuBar();
3045
3046
3047#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003048 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003050 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051#endif
3052
3053 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003056 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3058 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003059 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060
3061 gui.char_width = 7;
3062 gui.char_height = 11;
3063 gui.char_ascent = 6;
3064 gui.num_rows = 24;
3065 gui.num_cols = 80;
3066 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3067
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003068 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3069 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003071 /* Install Carbon event callbacks. */
3072 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073
3074 dragRectEnbl = FALSE;
3075 dragRgn = NULL;
3076 dragRectControl = kCreateEmpty;
3077 cursorRgn = NewRgn();
3078#endif
3079 /* Display any pending error messages */
3080 display_errors();
3081
3082 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003083 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084 gui.norm_pixel = 0x00000000;
3085 gui.back_pixel = 0x00FFFFFF;
3086
3087 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3088 * file). */
3089 set_normal_colors();
3090
3091 /*
3092 * Check that none of the colors are the same as the background color.
3093 * Then store the current values as the defaults.
3094 */
3095 gui_check_colors();
3096 gui.def_norm_pixel = gui.norm_pixel;
3097 gui.def_back_pixel = gui.back_pixel;
3098
3099 /* Get the colors for the highlight groups (gui_check_colors() might have
3100 * changed them) */
3101 highlight_gui_started();
3102
3103 /*
3104 * Setting the gui constants
3105 */
3106#ifdef FEAT_MENU
3107 gui.menu_height = 0;
3108#endif
3109 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3110 gui.border_offset = gui.border_width = 2;
3111
Bram Moolenaar720c7102007-05-10 18:07:50 +00003112 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113 gui_mch_draw_string() below), enable it for all font sizes. */
3114 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 eventTypeSpec.eventClass = kEventClassMouse;
3117 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3118 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3119 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3120 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3121 {
3122 mouseWheelHandlerRef = NULL;
3123 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3124 mouseWheelHandlerUPP = NULL;
3125 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003127#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003128 InterfaceTypeList supportedServices = { kUnicodeDocument };
3129 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3130
3131 /* We don't support inline input yet, use input window by default */
3132 UseInputWindow(gTSMDocument, TRUE);
3133
3134 /* Should we activate the document by default? */
3135 // ActivateTSMDocument(gTSMDocument);
3136
3137 EventTypeSpec textEventTypes[] = {
3138 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3139 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3140 { kEventClassTextInput, kEventTextInputPosToOffset },
3141 { kEventClassTextInput, kEventTextInputOffsetToPos },
3142 };
3143
3144 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3145 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3146 NR_ELEMS(textEventTypes),
3147 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003148 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003149 DisposeEventHandlerUPP(keyEventHandlerUPP);
3150 keyEventHandlerUPP = NULL;
3151 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003152
3153 EventTypeSpec windowEventTypes[] = {
3154 { kEventClassWindow, kEventWindowActivated },
3155 { kEventClassWindow, kEventWindowDeactivated },
3156 };
3157
3158 /* Install window event handler to support TSMDocument activate and
3159 * deactivate */
3160 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3161 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3162 winEventHandlerUPP,
3163 NR_ELEMS(windowEventTypes),
3164 windowEventTypes, NULL, NULL))
3165 {
3166 DisposeEventHandlerUPP(winEventHandlerUPP);
3167 winEventHandlerUPP = NULL;
3168 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169#endif
3170
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003171#ifdef FEAT_GUI_TABLINE
3172 /*
3173 * Create the tabline
3174 */
3175 initialise_tabline();
3176#endif
3177
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 /* TODO: Load bitmap if using TOOLBAR */
3179 return OK;
3180}
3181
3182/*
3183 * Called when the foreground or background color has been changed.
3184 */
3185 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003186gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187{
3188 /* TODO:
3189 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003190 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191 */
3192}
3193
3194/*
3195 * Open the GUI window which was created by a call to gui_mch_init().
3196 */
3197 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003198gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199{
3200 ShowWindow(gui.VimWindow);
3201
3202 if (gui_win_x != -1 && gui_win_y != -1)
3203 gui_mch_set_winpos(gui_win_x, gui_win_y);
3204
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 /*
3206 * Make the GUI the foreground process (in case it was launched
3207 * from the Terminal or via :gui).
3208 */
3209 {
3210 ProcessSerialNumber psn;
3211 if (GetCurrentProcess(&psn) == noErr)
3212 SetFrontProcess(&psn);
3213 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214
3215 return OK;
3216}
3217
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003218#ifdef USE_ATSUI_DRAWING
3219 static void
3220gui_mac_dispose_atsui_style(void)
3221{
3222 if (p_macatsui && gFontStyle)
3223 ATSUDisposeStyle(gFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003224 if (p_macatsui && gWideFontStyle)
3225 ATSUDisposeStyle(gWideFontStyle);
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003226}
3227#endif
3228
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 void
3230gui_mch_exit(int rc)
3231{
3232 /* TODO: find out all what is missing here? */
3233 DisposeRgn(cursorRgn);
3234
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003235#ifdef USE_CARBONKEYHANDLER
3236 if (keyEventHandlerUPP)
3237 DisposeEventHandlerUPP(keyEventHandlerUPP);
3238#endif
3239
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 if (mouseWheelHandlerUPP != NULL)
3241 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003243#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003244 gui_mac_dispose_atsui_style();
3245#endif
3246
3247#ifdef USE_CARBONKEYHANDLER
3248 FixTSMDocument(gTSMDocument);
3249 DeactivateTSMDocument(gTSMDocument);
3250 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003251#endif
3252
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253 /* Exit to shell? */
3254 exit(rc);
3255}
3256
3257/*
3258 * Get the position of the top left corner of the window.
3259 */
3260 int
3261gui_mch_get_winpos(int *x, int *y)
3262{
3263 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 Rect bounds;
3265 OSStatus status;
3266
3267 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003268 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269
3270 if (status != noErr)
3271 return FAIL;
3272 *x = bounds.left;
3273 *y = bounds.top;
3274 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275}
3276
3277/*
3278 * Set the position of the top left corner of the window to the given
3279 * coordinates.
3280 */
3281 void
3282gui_mch_set_winpos(int x, int y)
3283{
3284 /* TODO: Should make sure the window is move within range
3285 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3286 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003287 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288}
3289
3290 void
3291gui_mch_set_shellsize(
3292 int width,
3293 int height,
3294 int min_width,
3295 int min_height,
3296 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003297 int base_height,
3298 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 CGrafPtr VimPort;
3301 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302
3303 if (gui.which_scrollbars[SBAR_LEFT])
3304 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003305 VimPort = GetWindowPort(gui.VimWindow);
3306 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003308 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 }
3311 else
3312 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003313 VimPort = GetWindowPort(gui.VimWindow);
3314 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003316 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 }
3318
3319 SizeWindow(gui.VimWindow, width, height, TRUE);
3320
3321 gui_resize_shell(width, height);
3322}
3323
3324/*
3325 * Get the screen dimensions.
3326 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3327 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003328 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329 */
3330 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003331gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332{
3333 GDHandle dominantDevice = GetMainDevice();
3334 Rect screenRect = (**dominantDevice).gdRect;
3335
3336 *screen_w = screenRect.right - 10;
3337 *screen_h = screenRect.bottom - 40;
3338}
3339
3340
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003341/*
3342 * Open the Font Panel and wait for the user to select a font and
3343 * close the panel. Then fill the buffer pointed to by font_name with
3344 * the name and size of the selected font and return the font's handle,
3345 * or NOFONT in case of an error.
3346 */
3347 static GuiFont
3348gui_mac_select_font(char_u *font_name)
3349{
3350 GuiFont selected_font = NOFONT;
3351 OSStatus status;
3352 FontSelectionQDStyle curr_font;
3353
3354 /* Initialize the Font Panel with the current font. */
3355 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3356 curr_font.size = (gui.norm_font >> 16);
3357 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3358 curr_font.instance.fontStyle = 0;
3359 curr_font.hasColor = false;
3360 curr_font.version = 0; /* version number of the style structure */
3361 status = SetFontInfoForSelection(kFontSelectionQDType,
3362 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3363
3364 gFontPanelInfo.family = curr_font.instance.fontFamily;
3365 gFontPanelInfo.style = curr_font.instance.fontStyle;
3366 gFontPanelInfo.size = curr_font.size;
3367
3368 /* Pop up the Font Panel. */
3369 status = FPShowHideFontPanel();
3370 if (status == noErr)
3371 {
3372 /*
3373 * The Font Panel is modeless. We really need it to be modal,
3374 * so we spin in an event loop until the panel is closed.
3375 */
3376 gFontPanelInfo.isPanelVisible = true;
3377 while (gFontPanelInfo.isPanelVisible)
3378 {
3379 EventRecord e;
3380 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3381 }
3382
3383 GetFontPanelSelection(font_name);
3384 selected_font = gui_mac_find_font(font_name);
3385 }
3386 return selected_font;
3387}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003388
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003389#ifdef USE_ATSUI_DRAWING
3390 static void
3391gui_mac_create_atsui_style(void)
3392{
3393 if (p_macatsui && gFontStyle == NULL)
3394 {
3395 if (ATSUCreateStyle(&gFontStyle) != noErr)
3396 gFontStyle = NULL;
3397 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003398 if (p_macatsui && gWideFontStyle == NULL)
3399 {
3400 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3401 gWideFontStyle = NULL;
3402 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003403
3404 p_macatsui_last = p_macatsui;
3405}
3406#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407
3408/*
3409 * Initialise vim to use the font with the given name. Return FAIL if the font
3410 * could not be loaded, OK otherwise.
3411 */
3412 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003413gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414{
3415 /* TODO: Add support for bold italic underline proportional etc... */
3416 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003417 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418 FontInfo font_info;
3419 short font_id;
3420 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003421 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003423#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003424 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003425#endif
3426
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 if (font_name == NULL)
3428 {
3429 /* First try to get the suggested font */
3430 GetFNum(suggestedFont, &font_id);
3431
3432 if (font_id == 0)
3433 {
3434 /* Then pickup the standard application font */
3435 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003436 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003438 else
3439 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3441 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003442 else if (STRCMP(font_name, "*") == 0)
3443 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003444 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003445
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003446 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003447 if (font == NOFONT)
3448 return FAIL;
3449
3450 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003451 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003452 if (new_p_guifont != NULL)
3453 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003454 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003455 vim_free(p_guifont);
3456 p_guifont = new_p_guifont;
3457 /* Replace spaces in the font name with underscores. */
3458 for ( ; *new_p_guifont; ++new_p_guifont)
3459 {
3460 if (*new_p_guifont == ' ')
3461 *new_p_guifont = '_';
3462 }
3463 }
3464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 else
3466 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003467 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003468 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469
3470 if (font == NOFONT)
3471 return FAIL;
3472 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003473
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 gui.norm_font = font;
3475
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003476 hl_set_font_name(used_font_name);
3477
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003478 TextSize(font >> 16);
3479 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003481 GetFontInfo(&font_info);
3482
3483 gui.char_ascent = font_info.ascent;
3484 gui.char_width = CharWidth('_');
3485 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3486
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003487#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003488 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003489 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003490#endif
3491
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493}
3494
Bram Moolenaar02743632005-07-25 20:42:36 +00003495/*
3496 * Adjust gui.char_height (after 'linespace' was changed).
3497 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003499gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500{
3501 FontInfo font_info;
3502
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003503 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3505 gui.char_ascent = font_info.ascent + p_linespace / 2;
3506 return OK;
3507}
3508
3509/*
3510 * Get a font structure for highlighting.
3511 */
3512 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003513gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514{
3515 GuiFont font;
3516
3517 font = gui_mac_find_font(name);
3518
3519 if (font == NOFONT)
3520 {
3521 if (giveErrorIfMissing)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003522 semsg(_(e_font), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523 return NOFONT;
3524 }
3525 /*
3526 * TODO : Accept only monospace
3527 */
3528
3529 return font;
3530}
3531
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003532#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003533/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003534 * Return the name of font "font" in allocated memory.
3535 * Don't know how to get the actual name, thus use the provided name.
3536 */
3537 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003538gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003539{
3540 if (name == NULL)
3541 return NULL;
3542 return vim_strsave(name);
3543}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003544#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003545
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003546#ifdef USE_ATSUI_DRAWING
3547 static void
3548gui_mac_set_font_attributes(GuiFont font)
3549{
3550 ATSUFontID fontID;
3551 Fixed fontSize;
3552 Fixed fontWidth;
3553
3554 fontID = font & 0xFFFF;
3555 fontSize = Long2Fix(font >> 16);
3556 fontWidth = Long2Fix(gui.char_width);
3557
3558 ATSUAttributeTag attribTags[] =
3559 {
3560 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3561 kATSUMaxATSUITagValue + 1
3562 };
3563
3564 ByteCount attribSizes[] =
3565 {
3566 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3567 sizeof(font)
3568 };
3569
3570 ATSUAttributeValuePtr attribValues[] =
3571 {
3572 &fontID, &fontSize, &fontWidth, &font
3573 };
3574
3575 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3576 {
3577 if (ATSUSetAttributes(gFontStyle,
3578 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3579 attribTags, attribSizes, attribValues) != noErr)
3580 {
3581# ifndef NDEBUG
3582 fprintf(stderr, "couldn't set font style\n");
3583# endif
3584 ATSUDisposeStyle(gFontStyle);
3585 gFontStyle = NULL;
3586 }
3587
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003588 if (has_mbyte)
3589 {
3590 /* FIXME: we should use a more mbyte sensitive way to support
3591 * wide font drawing */
3592 fontWidth = Long2Fix(gui.char_width * 2);
3593
3594 if (ATSUSetAttributes(gWideFontStyle,
3595 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3596 attribTags, attribSizes, attribValues) != noErr)
3597 {
3598 ATSUDisposeStyle(gWideFontStyle);
3599 gWideFontStyle = NULL;
3600 }
3601 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003602 }
3603}
3604#endif
3605
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003606/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 * Set the current text font.
3608 */
3609 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003610gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003612#ifdef USE_ATSUI_DRAWING
3613 GuiFont currFont;
3614 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003615
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003616 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003617 {
3618 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003619 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3620 sizeof(font), &currFont, &actualFontByteCount) == noErr
3621 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003622 {
3623 if (currFont == font)
3624 return;
3625 }
3626
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003627 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003628 }
3629
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003630 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003631 {
3632 /* Setup automatic font substitution. The user's guifontwide
3633 * is tried first, then the system tries other fonts. */
3634/*
3635 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3636 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3637 ATSUCreateFontFallbacks(&gFontFallbacks);
3638 ATSUSetObjFontFallbacks(gFontFallbacks, );
3639*/
3640 if (gui.wide_font)
3641 {
3642 ATSUFontID fallbackFonts;
3643 gIsFontFallbackSet = TRUE;
3644
3645 if (FMGetFontFromFontFamilyInstance(
3646 (gui.wide_font & 0xFFFF),
3647 0,
3648 &fallbackFonts,
3649 NULL) == noErr)
3650 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003651 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3652 &fallbackFonts,
3653 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003654 }
3655/*
3656 ATSUAttributeValuePtr fallbackValues[] = { };
3657*/
3658 }
3659 }
3660#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 TextSize(font >> 16);
3662 TextFont(font & 0xFFFF);
3663}
3664
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665/*
3666 * If a font is not going to be used, free its structure.
3667 */
3668 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003669gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670{
3671 /*
3672 * Free font when "font" is not 0.
3673 * Nothing to do in the current implementation, since
3674 * nothing is allocated for each font used.
3675 */
3676}
3677
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678/*
3679 * Return the Pixel value (color) for the given color name. This routine was
3680 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3681 * Programmer's Guide.
3682 * Return INVALCOLOR when failed.
3683 */
3684 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003685gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003686{
3687 /* TODO: Add support for the new named color of MacOS 8
3688 */
3689 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690
Bram Moolenaarab302212016-04-26 20:59:29 +02003691 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003693 LMGetHiliteRGB(&MacColor);
3694 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003696 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697}
3698
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003699 guicolor_T
3700gui_mch_get_rgb_color(int r, int g, int b)
3701{
3702 return gui_get_rgb_color_cmn(r, g, b);
3703}
3704
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705/*
3706 * Set the current text foreground color.
3707 */
3708 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003709gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710{
3711 RGBColor TheColor;
3712
3713 TheColor.red = Red(color) * 0x0101;
3714 TheColor.green = Green(color) * 0x0101;
3715 TheColor.blue = Blue(color) * 0x0101;
3716
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003717 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718}
3719
3720/*
3721 * Set the current text background color.
3722 */
3723 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003724gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725{
3726 RGBColor TheColor;
3727
3728 TheColor.red = Red(color) * 0x0101;
3729 TheColor.green = Green(color) * 0x0101;
3730 TheColor.blue = Blue(color) * 0x0101;
3731
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003732 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733}
3734
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003735RGBColor specialColor;
3736
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003737/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003738 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003739 */
3740 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003741gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003742{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003743 specialColor.red = Red(color) * 0x0101;
3744 specialColor.green = Green(color) * 0x0101;
3745 specialColor.blue = Blue(color) * 0x0101;
3746}
3747
3748/*
3749 * Draw undercurl at the bottom of the character cell.
3750 */
3751 static void
3752draw_undercurl(int flags, int row, int col, int cells)
3753{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003754 int x;
3755 int offset;
3756 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3757 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003758
3759 RGBForeColor(&specialColor);
3760
3761 offset = val[FILL_X(col) % 8];
3762 MoveTo(FILL_X(col), y - offset);
3763
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003764 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003765 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003766 offset = val[x % 8];
3767 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003768 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003769}
3770
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003771
3772 static void
3773draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 char_u *tofree = NULL;
3776
3777 if (output_conv.vc_type != CONV_NONE)
3778 {
3779 tofree = string_convert(&output_conv, s, &len);
3780 if (tofree != NULL)
3781 s = tofree;
3782 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784 /*
3785 * On OS X, try using Quartz-style text antialiasing.
3786 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003787 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 {
3789 /* Quartz antialiasing is available only in OS 10.2 and later. */
3790 UInt32 qd_flags = (p_antialias ?
3791 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003792 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793 }
3794
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003795 /*
3796 * When antialiasing we're using srcOr mode, we have to clear the block
3797 * before drawing the text.
3798 * Also needed when 'linespace' is non-zero to remove the cursor and
3799 * underlining.
3800 * But not when drawing transparently.
3801 * The following is like calling gui_mch_clear_block(row, col, row, col +
3802 * len - 1), but without setting the bg color to gui.back_pixel.
3803 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003804 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003805 && !(flags & DRAW_TRANSP))
3806 {
3807 Rect rc;
3808
3809 rc.left = FILL_X(col);
3810 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003811 /* Multibyte computation taken from gui_w32.c */
3812 if (has_mbyte)
3813 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003814 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003815 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003816 }
3817 else
Bram Moolenaar13505972019-01-24 15:04:48 +01003818 rc.right = FILL_X(col + len) + (col + len == Columns);
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003819 rc.bottom = FILL_Y(row + 1);
3820 EraseRect(&rc);
3821 }
3822
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003823 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 {
3825 StyleParameter face;
3826
3827 face = normal;
3828 if (flags & DRAW_BOLD)
3829 face |= bold;
3830 if (flags & DRAW_UNDERL)
3831 face |= underline;
3832 TextFace(face);
3833
3834 /* Quartz antialiasing works only in srcOr transfer mode. */
3835 TextMode(srcOr);
3836
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 MoveTo(TEXT_X(col), TEXT_Y(row));
3838 DrawText((char*)s, 0, len);
3839 }
3840 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841 {
3842 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003843 TextMode(srcCopy);
3844 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845
3846 /* SelectFont(hdc, gui.currFont); */
3847
3848 if (flags & DRAW_TRANSP)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003849 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003851 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003852 DrawText((char *)s, 0, len);
3853
3854 if (flags & DRAW_BOLD)
3855 {
3856 TextMode(srcOr);
3857 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3858 DrawText((char *)s, 0, len);
3859 }
3860
3861 if (flags & DRAW_UNDERL)
3862 {
3863 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3864 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3865 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003866 if (flags & DRAW_STRIKE)
3867 {
3868 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3869 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3870 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003871 }
3872
3873 if (flags & DRAW_UNDERC)
3874 draw_undercurl(flags, row, col, len);
3875
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003876 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003877}
3878
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003879#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003880
3881 static void
3882draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3883{
3884 /* ATSUI requires utf-16 strings */
3885 UniCharCount utf16_len;
3886 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3887 utf16_len /= sizeof(UniChar);
3888
3889 /* - ATSUI automatically antialiases text (Someone)
3890 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003891#ifdef MAC_ATSUI_DEBUG
3892 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3893 row, col, len, len == 1 ? s[0] : ' ');
3894#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003895 /*
3896 * When antialiasing we're using srcOr mode, we have to clear the block
3897 * before drawing the text.
3898 * Also needed when 'linespace' is non-zero to remove the cursor and
3899 * underlining.
3900 * But not when drawing transparently.
3901 * The following is like calling gui_mch_clear_block(row, col, row, col +
3902 * len - 1), but without setting the bg color to gui.back_pixel.
3903 */
3904 if ((flags & DRAW_TRANSP) == 0)
3905 {
3906 Rect rc;
3907
3908 rc.left = FILL_X(col);
3909 rc.top = FILL_Y(row);
3910 /* Multibyte computation taken from gui_w32.c */
3911 if (has_mbyte)
3912 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003913 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003914 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003915 }
3916 else
3917 rc.right = FILL_X(col + len) + (col + len == Columns);
3918
3919 rc.bottom = FILL_Y(row + 1);
3920 EraseRect(&rc);
3921 }
3922
3923 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003924 TextMode(srcCopy);
3925 TextFace(normal);
3926
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003927 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003928 if (flags & DRAW_TRANSP)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003929 TextMode(srcOr);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003930
3931 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003932
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003933 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003934 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003935 Boolean attValue = true;
3936 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3937 ByteCount attribSizes[] = { sizeof(Boolean) };
3938 ATSUAttributeValuePtr attribValues[] = { &attValue };
3939
3940 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3941 }
3942
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003943 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3944 : kATSStyleNoAntiAliasing;
3945 if (useAntialias != useAntialias_cached)
3946 {
3947 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3948 ByteCount attribSizes[] = { sizeof(UInt32) };
3949 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3950
3951 if (gFontStyle)
3952 ATSUSetAttributes(gFontStyle, 1, attribTags,
3953 attribSizes, attribValues);
3954 if (gWideFontStyle)
3955 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3956 attribSizes, attribValues);
3957
3958 useAntialias_cached = useAntialias;
3959 }
3960
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003961 if (has_mbyte)
3962 {
3963 int n, width_in_cell, last_width_in_cell;
3964 UniCharArrayOffset offset = 0;
3965 UniCharCount yet_to_draw = 0;
3966 ATSUTextLayout textLayout;
3967 ATSUStyle textStyle;
3968
3969 last_width_in_cell = 1;
3970 ATSUCreateTextLayout(&textLayout);
3971 ATSUSetTextPointerLocation(textLayout, tofree,
3972 kATSUFromTextBeginning,
3973 kATSUToTextEnd, utf16_len);
3974 /*
3975 ATSUSetRunStyle(textLayout, gFontStyle,
3976 kATSUFromTextBeginning, kATSUToTextEnd); */
3977
3978 /* Compute the length in display cells. */
3979 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3980 {
3981 width_in_cell = (*mb_ptr2cells)(s + n);
3982
3983 /* probably we are switching from single byte character
3984 * to multibyte characters (which requires more than one
3985 * cell to draw) */
3986 if (width_in_cell != last_width_in_cell)
3987 {
3988#ifdef MAC_ATSUI_DEBUG
3989 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
3990 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
3991#endif
3992 textStyle = last_width_in_cell > 1 ? gWideFontStyle
3993 : gFontStyle;
3994
3995 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
3996 offset += yet_to_draw;
3997 yet_to_draw = 0;
3998 last_width_in_cell = width_in_cell;
3999 }
4000
4001 yet_to_draw++;
4002 }
4003
4004 if (yet_to_draw)
4005 {
4006#ifdef MAC_ATSUI_DEBUG
4007 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4008 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4009#endif
4010 /* finish the rest style */
4011 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4012 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4013 }
4014
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004015 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004016 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004017 kATSUFromTextBeginning, kATSUToTextEnd,
4018 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004019 ATSUDisposeTextLayout(textLayout);
4020 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004021 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004022 {
4023 ATSUTextLayout textLayout;
4024
4025 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4026 kATSUFromTextBeginning, kATSUToTextEnd,
4027 utf16_len,
4028 (gFontStyle ? 1 : 0), &utf16_len,
4029 (gFontStyle ? &gFontStyle : NULL),
4030 &textLayout) == noErr)
4031 {
4032 ATSUSetTransientFontMatching(textLayout, TRUE);
4033
4034 ATSUDrawText(textLayout,
4035 kATSUFromTextBeginning, kATSUToTextEnd,
4036 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4037
4038 ATSUDisposeTextLayout(textLayout);
4039 }
4040 }
4041
4042 /* drawing is done, now reset bold to normal */
4043 if (gFontStyle && flags & DRAW_BOLD)
4044 {
4045 Boolean attValue = false;
4046
4047 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4048 ByteCount attribSizes[] = { sizeof(Boolean) };
4049 ATSUAttributeValuePtr attribValues[] = { &attValue };
4050
4051 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4052 attribValues);
4053 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 }
4055
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004056 if (flags & DRAW_UNDERC)
4057 draw_undercurl(flags, row, col, len);
4058
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004060}
4061#endif
4062
4063 void
4064gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4065{
4066#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004067 if (p_macatsui == 0 && p_macatsui_last != 0)
4068 /* switch from macatsui to nomacatsui */
4069 gui_mac_dispose_atsui_style();
4070 else if (p_macatsui != 0 && p_macatsui_last == 0)
4071 /* switch from nomacatsui to macatsui */
4072 gui_mac_create_atsui_style();
4073
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004074 if (p_macatsui)
4075 draw_string_ATSUI(row, col, s, len, flags);
4076 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004077#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004078 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079}
4080
4081/*
4082 * Return OK if the key with the termcap name "name" is supported.
4083 */
4084 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004085gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086{
4087 int i;
4088
4089 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4090 if (name[0] == special_keys[i].vim_code0 &&
4091 name[1] == special_keys[i].vim_code1)
4092 return OK;
4093 return FAIL;
4094}
4095
4096 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004097gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004099 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100}
4101
4102 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004103gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104{
4105 /* Do a visual beep by reversing the foreground and background colors */
4106 Rect rc;
4107
4108 /*
4109 * Note: InvertRect() excludes right and bottom of rectangle.
4110 */
4111 rc.left = 0;
4112 rc.top = 0;
4113 rc.right = gui.num_cols * gui.char_width;
4114 rc.bottom = gui.num_rows * gui.char_height;
4115 InvertRect(&rc);
4116
4117 ui_delay((long)msec, TRUE); /* wait for some msec */
4118
4119 InvertRect(&rc);
4120}
4121
4122/*
4123 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4124 */
4125 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004126gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127{
4128 Rect rc;
4129
4130 /*
4131 * Note: InvertRect() excludes right and bottom of rectangle.
4132 */
4133 rc.left = FILL_X(c);
4134 rc.top = FILL_Y(r);
4135 rc.right = rc.left + nc * gui.char_width;
4136 rc.bottom = rc.top + nr * gui.char_height;
4137 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138}
4139
4140/*
4141 * Iconify the GUI window.
4142 */
4143 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004144gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145{
4146 /* TODO: find out what could replace iconify
4147 * -window shade?
4148 * -hide application?
4149 */
4150}
4151
4152#if defined(FEAT_EVAL) || defined(PROTO)
4153/*
4154 * Bring the Vim window to the foreground.
4155 */
4156 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004157gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158{
4159 /* TODO */
4160}
4161#endif
4162
4163/*
4164 * Draw a cursor without focus.
4165 */
4166 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004167gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168{
4169 Rect rc;
4170
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 /*
4172 * Note: FrameRect() excludes right and bottom of rectangle.
4173 */
4174 rc.left = FILL_X(gui.col);
4175 rc.top = FILL_Y(gui.row);
4176 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004177 if (mb_lefthalve(gui.row, gui.col))
4178 rc.right += gui.char_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 rc.bottom = rc.top + gui.char_height;
4180
4181 gui_mch_set_fg_color(color);
4182
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004183 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184}
4185
4186/*
4187 * Draw part of a cursor, only w pixels wide, and h pixels high.
4188 */
4189 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004190gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191{
4192 Rect rc;
4193
4194#ifdef FEAT_RIGHTLEFT
4195 /* vertical line should be on the right of current point */
4196 if (CURSOR_BAR_RIGHT)
4197 rc.left = FILL_X(gui.col + 1) - w;
4198 else
4199#endif
4200 rc.left = FILL_X(gui.col);
4201 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4202 rc.right = rc.left + w;
4203 rc.bottom = rc.top + h;
4204
4205 gui_mch_set_fg_color(color);
4206
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004207 FrameRect(&rc);
4208// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209}
4210
4211
4212
4213/*
4214 * Catch up with any queued X events. This may put keyboard input into the
4215 * input buffer, call resize call-backs, trigger timers etc. If there is
4216 * nothing in the X event queue (& no timers pending), then we return
4217 * immediately.
4218 */
4219 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004220gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221{
4222 /* TODO: find what to do
4223 * maybe call gui_mch_wait_for_chars (0)
4224 * more like look at EventQueue then
4225 * call heart of gui_mch_wait_for_chars;
4226 *
4227 * if (eventther)
4228 * gui_mac_handle_event(&event);
4229 */
4230 EventRecord theEvent;
4231
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004232 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233 if (theEvent.what != nullEvent)
4234 gui_mch_wait_for_chars(0);
4235}
4236
4237/*
4238 * Simple wrapper to neglect more easily the time
4239 * spent inside WaitNextEvent while profiling.
4240 */
4241
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 pascal
4243 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004244WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245{
4246 if (((long) sleep) < -1)
4247 sleep = 32767;
4248 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4249}
4250
4251/*
4252 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4253 * from the keyboard.
4254 * wtime == -1 Wait forever.
4255 * wtime == 0 This should never happen.
4256 * wtime > 0 Wait wtime milliseconds for a character.
4257 * Returns OK if a character was found to be available within the given time,
4258 * or FAIL otherwise.
4259 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004261gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262{
4263 EventMask mask = (everyEvent);
4264 EventRecord event;
4265 long entryTick;
4266 long currentTick;
4267 long sleeppyTick;
4268
4269 /* If we are providing life feedback with the scrollbar,
4270 * we don't want to try to wait for an event, or else
4271 * there won't be any life feedback.
4272 */
4273 if (dragged_sb != NULL)
4274 return FAIL;
4275 /* TODO: Check if FAIL is the proper return code */
4276
4277 entryTick = TickCount();
4278
4279 allow_scrollbar = TRUE;
4280
4281 do
4282 {
4283/* if (dragRectControl == kCreateEmpty)
4284 {
4285 dragRgn = NULL;
4286 dragRectControl = kNothing;
4287 }
4288 else*/ if (dragRectControl == kCreateRect)
4289 {
4290 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004291 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 dragRectControl = kNothing;
4293 }
4294 /*
4295 * Don't use gui_mch_update() because then we will spin-lock until a
4296 * char arrives, instead we use WaitNextEventWrp() to hang until an
4297 * event arrives. No need to check for input_buf_full because we are
4298 * returning as soon as it contains a single char.
4299 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004300 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004302 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303 else
4304 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004305
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004306 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004307 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004308 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 if (input_available())
4310 {
4311 allow_scrollbar = FALSE;
4312 return OK;
4313 }
4314 }
4315 currentTick = TickCount();
4316 }
4317 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4318
4319 allow_scrollbar = FALSE;
4320 return FAIL;
4321}
4322
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323/*
4324 * Output routines.
4325 */
4326
4327/* Flush any output to the screen */
4328 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004329gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330{
4331 /* TODO: Is anything needed here? */
4332}
4333
4334/*
4335 * Clear a rectangular region of the screen from text pos (row1, col1) to
4336 * (row2, col2) inclusive.
4337 */
4338 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004339gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340{
4341 Rect rc;
4342
4343 /*
4344 * Clear one extra pixel at the far right, for when bold characters have
4345 * spilled over to the next column.
4346 */
4347 rc.left = FILL_X(col1);
4348 rc.top = FILL_Y(row1);
4349 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4350 rc.bottom = FILL_Y(row2 + 1);
4351
4352 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004353 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354}
4355
4356/*
4357 * Clear the whole text window.
4358 */
4359 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004360gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361{
4362 Rect rc;
4363
4364 rc.left = 0;
4365 rc.top = 0;
4366 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4367 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4368
4369 gui_mch_set_bg_color(gui.back_pixel);
4370 EraseRect(&rc);
4371/* gui_mch_set_fg_color(gui.norm_pixel);
4372 FrameRect(&rc);
4373*/
4374}
4375
4376/*
4377 * Delete the given number of lines from the given row, scrolling up any
4378 * text further down within the scroll region.
4379 */
4380 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004381gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382{
4383 Rect rc;
4384
4385 /* changed without checking! */
4386 rc.left = FILL_X(gui.scroll_region_left);
4387 rc.right = FILL_X(gui.scroll_region_right + 1);
4388 rc.top = FILL_Y(row);
4389 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4390
4391 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004392 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393
4394 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4395 gui.scroll_region_left,
4396 gui.scroll_region_bot, gui.scroll_region_right);
4397}
4398
4399/*
4400 * Insert the given number of lines before the given row, scrolling down any
4401 * following text within the scroll region.
4402 */
4403 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004404gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405{
4406 Rect rc;
4407
4408 rc.left = FILL_X(gui.scroll_region_left);
4409 rc.right = FILL_X(gui.scroll_region_right + 1);
4410 rc.top = FILL_Y(row);
4411 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4412
4413 gui_mch_set_bg_color(gui.back_pixel);
4414
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004415 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416
4417 /* Update gui.cursor_row if the cursor scrolled or copied over */
4418 if (gui.cursor_row >= gui.row
4419 && gui.cursor_col >= gui.scroll_region_left
4420 && gui.cursor_col <= gui.scroll_region_right)
4421 {
4422 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4423 gui.cursor_row += num_lines;
4424 else if (gui.cursor_row <= gui.scroll_region_bot)
4425 gui.cursor_is_valid = FALSE;
4426 }
4427
4428 gui_clear_block(row, gui.scroll_region_left,
4429 row + num_lines - 1, gui.scroll_region_right);
4430}
4431
4432 /*
4433 * TODO: add a vim format to the clipboard which remember
4434 * LINEWISE, CHARWISE, BLOCKWISE
4435 */
4436
4437 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02004438clip_mch_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439{
4440
4441 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004442 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 Size scrapSize;
4444 ScrapFlavorFlags scrapFlags;
4445 ScrapRef scrap = nil;
4446 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 int type;
4448 char *searchCR;
4449 char_u *tempclip;
4450
4451
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004452 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453 if (error != noErr)
4454 return;
4455
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004456 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4457 if (error == noErr)
4458 {
4459 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4460 if (error == noErr && scrapSize > 1)
4461 flavor = 1;
4462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004464 if (flavor == 0)
4465 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004466 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004467 if (error != noErr)
4468 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004470 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004471 if (error != noErr)
4472 return;
4473 }
4474
4475 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004477 /* In CARBON we don't need a Handle, a pointer is good */
4478 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004480 /* tempclip = alloc(scrapSize+1); */
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004481 HLock(textOfClip);
4482 error = GetScrapFlavorData(scrap,
4483 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4484 &scrapSize, *textOfClip);
4485 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004487 if (flavor)
4488 type = **textOfClip;
4489 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004490 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004491
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004492 tempclip = alloc(scrapSize + 1);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004493 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4494 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004496#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004497 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004498 /* Convert from utf-16 (clipboard) */
4499 size_t encLen = 0;
4500 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004501
4502 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004504 scrapSize = encLen;
4505 vim_free(tempclip);
4506 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004508 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004510
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004511 searchCR = (char *)tempclip;
4512 while (searchCR != NULL)
4513 {
4514 searchCR = strchr(searchCR, '\r');
4515 if (searchCR != NULL)
4516 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004518
4519 clip_yank_selection(type, tempclip, scrapSize, cbd);
4520
4521 vim_free(tempclip);
4522 HUnlock(textOfClip);
4523
4524 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525}
4526
4527 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02004528clip_mch_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529{
4530 /*
4531 * TODO: Really nothing to do?
4532 */
4533}
4534
4535 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02004536clip_mch_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537{
4538 return OK;
4539}
4540
4541/*
4542 * Send the current selection to the clipboard.
4543 */
4544 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02004545clip_mch_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546{
4547 Handle textOfClip;
4548 long scrapSize;
4549 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551
4552 char_u *str = NULL;
4553
4554 if (!cbd->owned)
4555 return;
4556
4557 clip_get_selection(cbd);
4558
4559 /*
4560 * Once we set the clipboard, lose ownership. If another application sets
4561 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 cbd->owned = FALSE;
4564
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004565 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004567#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004568 size_t utf16_len = 0;
4569 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4570 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004572 scrapSize = utf16_len;
4573 vim_free(str);
4574 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575 }
4576#endif
4577
4578 if (type >= 0)
4579 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004582 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583 HLock(textOfClip);
4584
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004585 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004586 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004587 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004588 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004589 scrapSize, *textOfClip + 1);
4590 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4591 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 HUnlock(textOfClip);
4593 DisposeHandle(textOfClip);
4594 }
4595
4596 vim_free(str);
4597}
4598
4599 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004600gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004601{
4602 Rect VimBound;
4603
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004604/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606
4607 if (gui.which_scrollbars[SBAR_LEFT])
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 VimBound.left = -gui.scrollbar_width + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 VimBound.left = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004614 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615}
4616
4617/*
4618 * Menu stuff.
4619 */
4620
4621 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004622gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623{
4624 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004625 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 */
4627}
4628
4629 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004630gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631{
4632 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004633 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 */
4635}
4636
4637/*
4638 * Add a sub menu to the menu bar.
4639 */
4640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004641gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642{
4643 /*
4644 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4645 * TODO: use menu->mnemonic and menu->actext
4646 * TODO: Try to reuse menu id
4647 * Carbon Help suggest to use only id between 1 and 235
4648 */
4649 static long next_avail_id = 128;
4650 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004651 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652 short index;
4653 vimmenu_T *parent = menu->parent;
4654 vimmenu_T *brother = menu->next;
4655
4656 /* Cannot add a menu if ... */
4657 if ((parent != NULL && parent->submenu_id == 0))
4658 return;
4659
4660 /* menu ID greater than 1024 are reserved for ??? */
4661 if (next_avail_id == 1024)
4662 return;
4663
4664 /* My brother could be the PopUp, find my real brother */
4665 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4666 brother = brother->next;
4667
4668 /* Find where to insert the menu (for MenuBar) */
4669 if ((parent == NULL) && (brother != NULL))
4670 menu_after_me = brother->submenu_id;
4671
4672 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4673 if (!menu_is_menubar(menu->name))
4674 menu_after_me = hierMenu;
4675
4676 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004677#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004678 name = menu_title_removing_mnemonic(menu);
4679#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004681#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 if (name == NULL)
4683 return;
4684
4685 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 {
4687 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004688 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4689 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 */
4691 menu->submenu_id = next_avail_id;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004692 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4693 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694 next_avail_id++;
4695 }
4696
4697 if (parent == NULL)
4698 {
4699 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4700
4701 /* TODO: Verify if we could only Insert Menu if really part of the
4702 * menubar The Inserted menu are scanned or the Command-key combos
4703 */
4704
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004705 /* Insert the menu */
4706 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004707#if 1
4708 /* Vim should normally update it. TODO: verify */
4709 DrawMenuBar();
4710#endif
4711 }
4712 else
4713 {
4714 /* Adding as a submenu */
4715
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004716 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717
4718 /* Call InsertMenuItem followed by SetMenuItemText
4719 * to avoid special character recognition by InsertMenuItem
4720 */
4721 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004722 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4724 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4725 InsertMenu(menu->submenu_handle, hierMenu);
4726 }
4727
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004728 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729
4730#if 0
4731 /* Done by Vim later on */
4732 DrawMenuBar();
4733#endif
4734}
4735
4736/*
4737 * Add a menu item to a menu
4738 */
4739 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004740gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004742 CFStringRef name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743 vimmenu_T *parent = menu->parent;
4744 int menu_inserted;
4745
4746 /* Cannot add item, if the menu have not been created */
4747 if (parent->submenu_id == 0)
4748 return;
4749
4750 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4751 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4752
4753 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004754#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004755 name = menu_title_removing_mnemonic(menu);
4756#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004758#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759
4760 /* Where are just a menu item, so no handle, no id */
4761 menu->submenu_id = 0;
4762 menu->submenu_handle = NULL;
4763
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 menu_inserted = 0;
4765 if (menu->actext)
4766 {
4767 /* If the accelerator text for the menu item looks like it describes
4768 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4769 * item's command equivalent.
4770 */
4771 int key = 0;
4772 int modifiers = 0;
4773 char_u *p_actext;
4774
4775 p_actext = menu->actext;
Bram Moolenaar459fd782019-10-13 16:43:39 +02004776 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE,
4777 TRUE, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 if (*p_actext != 0)
4779 key = 0; /* error: trailing text */
4780 /* find_special_key() returns a keycode with as many of the
4781 * specified modifiers as appropriate already applied (e.g., for
4782 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4783 * as the only modifier). Since we want to display all of the
4784 * modifiers, we need to convert the keycode back to a printable
4785 * character plus modifiers.
4786 * TODO: Write an alternative find_special_key() that doesn't
4787 * apply modifiers.
4788 */
4789 if (key > 0 && key < 32)
4790 {
4791 /* Convert a control key to an uppercase letter. Note that
4792 * by this point it is no longer possible to distinguish
4793 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4794 */
4795 modifiers |= MOD_MASK_CTRL;
4796 key += '@';
4797 }
4798 /* If the keycode is an uppercase letter, set the Shift modifier.
4799 * If it is a lowercase letter, don't set the modifier, but convert
4800 * the letter to uppercase for display in the menu.
4801 */
4802 else if (key >= 'A' && key <= 'Z')
4803 modifiers |= MOD_MASK_SHIFT;
4804 else if (key >= 'a' && key <= 'z')
4805 key += 'A' - 'a';
4806 /* Note: keycodes below 0x22 are reserved by Apple. */
4807 if (key >= 0x22 && vim_isprintc_strict(key))
4808 {
4809 int valid = 1;
4810 char_u mac_mods = kMenuNoModifiers;
4811 /* Convert Vim modifier codes to Menu Manager equivalents. */
4812 if (modifiers & MOD_MASK_SHIFT)
4813 mac_mods |= kMenuShiftModifier;
4814 if (modifiers & MOD_MASK_CTRL)
4815 mac_mods |= kMenuControlModifier;
4816 if (!(modifiers & MOD_MASK_CMD))
4817 mac_mods |= kMenuNoCommandModifier;
4818 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4819 valid = 0; /* TODO: will Alt someday map to Option? */
4820 if (valid)
4821 {
4822 char_u item_txt[10];
4823 /* Insert the menu item after idx, with its command key. */
4824 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4825 item_txt[3] = key;
4826 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4827 /* Set the modifier keys. */
4828 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4829 menu_inserted = 1;
4830 }
4831 }
4832 }
4833 /* Call InsertMenuItem followed by SetMenuItemText
4834 * to avoid special character recognition by InsertMenuItem
4835 */
4836 if (!menu_inserted)
4837 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4838 /* Set the menu item name. */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004839 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840
4841#if 0
4842 /* Called by Vim */
4843 DrawMenuBar();
4844#endif
4845
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004846 CFRelease(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004847}
4848
4849 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004850gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851{
4852 /* no tearoff menus */
4853}
4854
4855/*
4856 * Destroy the machine specific menu widget.
4857 */
4858 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004859gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004861 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862
4863 if (index > 0)
4864 {
4865 if (menu->parent)
4866 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 {
4868 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004869 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870
4871 /* Delete the Menu if it was a hierarchical Menu */
4872 if (menu->submenu_id != 0)
4873 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004874 DeleteMenu(menu->submenu_id);
4875 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 }
4877 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 }
4879#ifdef DEBUG_MAC_MENU
4880 else
4881 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004882 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004883 }
4884#endif
4885 }
4886 else
4887 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004889 DeleteMenu(menu->submenu_id);
4890 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891 }
4892 }
4893 /* Shouldn't this be already done by Vim. TODO: Check */
4894 DrawMenuBar();
4895}
4896
4897/*
4898 * Make a menu either grey or not grey.
4899 */
4900 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004901gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004902{
4903 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004904 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905/*
4906 index = menu->index;
4907*/
4908 if (grey)
4909 {
4910 if (menu->children)
4911 DisableMenuItem(menu->submenu_handle, index);
4912 if (menu->parent)
4913 if (menu->parent->submenu_handle)
4914 DisableMenuItem(menu->parent->submenu_handle, index);
4915 }
4916 else
4917 {
4918 if (menu->children)
4919 EnableMenuItem(menu->submenu_handle, index);
4920 if (menu->parent)
4921 if (menu->parent->submenu_handle)
4922 EnableMenuItem(menu->parent->submenu_handle, index);
4923 }
4924}
4925
4926/*
4927 * Make menu item hidden or not hidden
4928 */
4929 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004930gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004931{
4932 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004933 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934}
4935
4936
4937/*
4938 * This is called after setting all the menus to grey/hidden or not.
4939 */
4940 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004941gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942{
4943 DrawMenuBar();
4944}
4945
4946
4947/*
4948 * Scrollbar stuff.
4949 */
4950
4951 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004952gui_mch_enable_scrollbar(
4953 scrollbar_T *sb,
4954 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955{
4956 if (flag)
4957 ShowControl(sb->id);
4958 else
4959 HideControl(sb->id);
4960
4961#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004962 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004963#endif
4964}
4965
4966 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004967gui_mch_set_scrollbar_thumb(
4968 scrollbar_T *sb,
4969 long val,
4970 long size,
4971 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004972{
4973 SetControl32BitMaximum (sb->id, max);
4974 SetControl32BitMinimum (sb->id, 0);
4975 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004976 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02004978 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979#endif
4980}
4981
4982 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004983gui_mch_set_scrollbar_pos(
4984 scrollbar_T *sb,
4985 int x,
4986 int y,
4987 int w,
4988 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989{
4990 gui_mch_set_bg_color(gui.back_pixel);
4991/* if (gui.which_scrollbars[SBAR_LEFT])
4992 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004993 MoveControl(sb->id, x-16, y);
4994 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995 }
4996 else
4997 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004998 MoveControl(sb->id, x, y);
4999 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005000 }*/
5001 if (sb == &gui.bottom_sbar)
5002 h += 1;
5003 else
5004 w += 1;
5005
5006 if (gui.which_scrollbars[SBAR_LEFT])
5007 x -= 15;
5008
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005009 MoveControl(sb->id, x, y);
5010 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005011#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005012 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013#endif
5014}
5015
5016 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005017gui_mch_create_scrollbar(
5018 scrollbar_T *sb,
5019 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020{
5021 Rect bounds;
5022
5023 bounds.top = -16;
5024 bounds.bottom = -10;
5025 bounds.right = -10;
5026 bounds.left = -16;
5027
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005028 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029 &bounds,
5030 "\pScrollBar",
5031 TRUE,
5032 0, /* current*/
5033 0, /* top */
5034 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036 (long) sb->ident);
5037#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005038 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039#endif
5040}
5041
5042 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005043gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044{
5045 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005046 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005048 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049#endif
5050}
5051
Bram Moolenaar703a8042016-06-04 16:24:32 +02005052 int
5053gui_mch_is_blinking(void)
5054{
5055 return FALSE;
5056}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005058 int
5059gui_mch_is_blink_off(void)
5060{
5061 return FALSE;
5062}
5063
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064/*
5065 * Cursor blink functions.
5066 *
5067 * This is a simple state machine:
5068 * BLINK_NONE not blinking at all
5069 * BLINK_OFF blinking, cursor is not shown
5070 * BLINK_ON blinking, cursor is shown
5071 */
5072 void
5073gui_mch_set_blinking(long wait, long on, long off)
5074{
5075 /* TODO: TODO: TODO: TODO: */
5076/* blink_waittime = wait;
5077 blink_ontime = on;
5078 blink_offtime = off;*/
5079}
5080
5081/*
5082 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5083 */
5084 void
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005085gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086{
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005087 if (may_call_gui_update_cursor)
5088 gui_update_cursor(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 /* TODO: TODO: TODO: TODO: */
5090/* gui_w32_rm_blink_timer();
5091 if (blink_state == BLINK_OFF)
5092 gui_update_cursor(TRUE, FALSE);
5093 blink_state = BLINK_NONE;*/
5094}
5095
5096/*
5097 * Start the cursor blinking. If it was already blinking, this restarts the
5098 * waiting time and shows the cursor.
5099 */
5100 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005101gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102{
5103 gui_update_cursor(TRUE, FALSE);
5104 /* TODO: TODO: TODO: TODO: */
5105/* gui_w32_rm_blink_timer(); */
5106
5107 /* Only switch blinking on if none of the times is zero */
5108/* if (blink_waittime && blink_ontime && blink_offtime)
5109 {
5110 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5111 (TIMERPROC)_OnBlinkTimer);
5112 blink_state = BLINK_ON;
5113 gui_update_cursor(TRUE, FALSE);
5114 }*/
5115}
5116
5117/*
5118 * Return the RGB value of a pixel as long.
5119 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005120 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121gui_mch_get_rgb(guicolor_T pixel)
5122{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005123 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124}
5125
5126
5127
5128#ifdef FEAT_BROWSE
5129/*
5130 * Pop open a file browser and return the file selected, in allocated memory,
5131 * or NULL if Cancel is hit.
5132 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5133 * title - Title message for the file browser dialog.
5134 * dflt - Default name of file.
5135 * ext - Default extension to be added to files without extensions.
5136 * initdir - directory in which to open the browser (NULL = current dir)
5137 * filter - Filter for matched files to choose from.
5138 * Has a format like this:
5139 * "C Files (*.c)\0*.c\0"
5140 * "All Files\0*.*\0\0"
5141 * If these two strings were concatenated, then a choice of two file
5142 * filters will be selectable to the user. Then only matching files will
5143 * be shown in the browser. If NULL, the default allows all files.
5144 *
5145 * *NOTE* - the filter string must be terminated with TWO nulls.
5146 */
5147 char_u *
5148gui_mch_browse(
5149 int saving,
5150 char_u *title,
5151 char_u *dflt,
5152 char_u *ext,
5153 char_u *initdir,
5154 char_u *filter)
5155{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005156 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157 NavReplyRecord reply;
5158 char_u *fname = NULL;
5159 char_u **fnames = NULL;
5160 long numFiles;
5161 NavDialogOptions navOptions;
5162 OSErr error;
5163
5164 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005165 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166
5167
5168 /* TODO: If we get a :browse args, set the Multiple bit. */
5169 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5170 | kNavDontAutoTranslate
5171 | kNavDontAddTranslateItems
5172 /* | kNavAllowMultipleFiles */
5173 | kNavAllowStationery;
5174
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005175 (void) C2PascalString(title, &navOptions.message);
5176 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177 /* Could set clientName?
5178 * windowTitle? (there's no title bar?)
5179 */
5180
5181 if (saving)
5182 {
5183 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005184 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005185 if (!reply.validRecord)
5186 return NULL;
5187 }
5188 else
5189 {
5190 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5191 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5192 if (!reply.validRecord)
5193 return NULL;
5194 }
5195
5196 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5197
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005198 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199
5200 if (fnames)
5201 {
5202 fname = fnames[0];
5203 vim_free(fnames);
5204 }
5205
5206 /* TODO: Shorten the file name if possible */
5207 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208}
5209#endif /* FEAT_BROWSE */
5210
5211#ifdef FEAT_GUI_DIALOG
5212/*
5213 * Stuff for dialogues
5214 */
5215
5216/*
5217 * Create a dialogue dynamically from the parameter strings.
5218 * type = type of dialogue (question, alert, etc.)
5219 * title = dialogue title. may be NULL for default title.
5220 * message = text to display. Dialogue sizes to accommodate it.
5221 * buttons = '\n' separated list of button captions, default first.
5222 * dfltbutton = number of default button.
5223 *
5224 * This routine returns 1 if the first button is pressed,
5225 * 2 for the second, etc.
5226 *
5227 * 0 indicates Esc was pressed.
5228 * -1 for unexpected error
5229 *
5230 * If stubbing out this fn, return 1.
5231 */
5232
5233typedef struct
5234{
5235 short idx;
5236 short width; /* Size of the text in pixel */
5237 Rect box;
5238} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5239
5240#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5241
5242 static void
5243macMoveDialogItem(
5244 DialogRef theDialog,
5245 short itemNumber,
5246 short X,
5247 short Y,
5248 Rect *inBox)
5249{
5250#if 0 /* USE_CARBONIZED */
5251 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005252 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005254 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255#else
5256 short itemType;
5257 Handle itemHandle;
5258 Rect localBox;
5259 Rect *itemBox = &localBox;
5260
5261 if (inBox != nil)
5262 itemBox = inBox;
5263
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005264 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5265 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5266 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267 /* To move a control (like a button) we need to call both
5268 * MoveControl and SetDialogItem. FAQ 6-18 */
5269 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005270 MoveControl((ControlRef) itemHandle, X, Y);
5271 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272#endif
5273}
5274
5275 static void
5276macSizeDialogItem(
5277 DialogRef theDialog,
5278 short itemNumber,
5279 short width,
5280 short height)
5281{
5282 short itemType;
5283 Handle itemHandle;
5284 Rect itemBox;
5285
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005286 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005287
5288 /* When width or height is zero do not change it */
5289 if (width == 0)
5290 width = itemBox.right - itemBox.left;
5291 if (height == 0)
5292 height = itemBox.bottom - itemBox.top;
5293
5294#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005295 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296#else
5297 /* Resize the bounding box */
5298 itemBox.right = itemBox.left + width;
5299 itemBox.bottom = itemBox.top + height;
5300
5301 /* To resize a control (like a button) we need to call both
5302 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5303 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005304 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005305
5306 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005307 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005308#endif
5309}
5310
5311 static void
5312macSetDialogItemText(
5313 DialogRef theDialog,
5314 short itemNumber,
5315 Str255 itemName)
5316{
5317 short itemType;
5318 Handle itemHandle;
5319 Rect itemBox;
5320
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005321 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005322
5323 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005324 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005325 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005326 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327}
5328
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005329
5330/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5331 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5332 * setting gDialogHotKeys to NULL disables any hotkey handling.
5333 */
5334 static pascal Boolean
5335DialogHotkeyFilterProc (
5336 DialogRef theDialog,
5337 EventRecord *event,
5338 DialogItemIndex *itemHit)
5339{
5340 char_u keyHit;
5341
5342 if (event->what == keyDown || event->what == autoKey)
5343 {
5344 keyHit = (event->message & charCodeMask);
5345
5346 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5347 {
5348#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5349 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5350#endif
5351 *itemHit = gDialogHotKeys[keyHit];
5352
5353 /* When handing off to StdFilterProc, pretend that the user
5354 * clicked the control manually. Note that this is also supposed
5355 * to cause the button to hilite briefly (to give some user
5356 * feedback), but this seems not to actually work (or it's too
5357 * fast to be seen).
5358 */
5359 event->what = kEventControlSimulateHit;
5360
5361 return true; /* we took care of it */
5362 }
5363
5364 /* Defer to the OS's standard behavior for this event.
5365 * This ensures that Enter will still activate the default button. */
5366 return StdFilterProc(theDialog, event, itemHit);
5367 }
5368 return false; /* Let ModalDialog deal with it */
5369}
5370
5371
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005372/* TODO: There have been some crashes with dialogs, check your inbox
5373 * (Jussi)
5374 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375 int
5376gui_mch_dialog(
5377 int type,
5378 char_u *title,
5379 char_u *message,
5380 char_u *buttons,
5381 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005382 char_u *textfield,
5383 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005384{
5385 Handle buttonDITL;
5386 Handle iconDITL;
5387 Handle inputDITL;
5388 Handle messageDITL;
5389 Handle itemHandle;
5390 Handle iconHandle;
5391 DialogPtr theDialog;
5392 char_u len;
5393 char_u PascalTitle[256]; /* place holder for the title */
5394 char_u name[256];
5395 GrafPtr oldPort;
5396 short itemHit;
5397 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005398 short hotKeys[256]; /* map of hotkey -> control ID */
5399 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 Rect box;
5401 short button;
5402 short lastButton;
5403 short itemType;
5404 short useIcon;
5405 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005406 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005407 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005408 short widestButton = 0;
5409 short dfltButtonEdge = 20; /* gut feeling */
5410 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5411 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5412 short maximumWidth = 400; /* gut feeling */
5413 short maxButtonWidth = 175; /* gut feeling */
5414
5415 short vertical;
5416 short dialogHeight;
5417 short messageLines = 3;
5418 FontInfo textFontInfo;
5419
5420 vgmDlgItm iconItm;
5421 vgmDlgItm messageItm;
5422 vgmDlgItm inputItm;
5423 vgmDlgItm buttonItm;
5424
5425 WindowRef theWindow;
5426
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005427 ModalFilterUPP dialogUPP;
5428
Bram Moolenaar071d4272004-06-13 20:20:40 +00005429 /* Check 'v' flag in 'guioptions': vertical button placement. */
5430 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5431
5432 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005433 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005434
5435 /* Get the WindowRef */
5436 theWindow = GetDialogWindow(theDialog);
5437
5438 /* Hide the window.
5439 * 1. to avoid seeing slow drawing
5440 * 2. to prevent a problem seen while moving dialog item
5441 * within a visible window. (non-Carbon MacOS 9)
5442 * Could be avoided by changing the resource.
5443 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005444 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005445
5446 /* Change the graphical port to the dialog,
5447 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005448 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005449 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450
5451 /* Get the info about the default text,
5452 * used to calculate the height of the message
5453 * and of the text field */
5454 GetFontInfo(&textFontInfo);
5455
5456 /* Set the dialog title */
5457 if (title != NULL)
5458 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005459 (void) C2PascalString(title, &PascalTitle);
5460 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005461 }
5462
5463 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005464 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 buttonChar = buttons;
5466 button = 0;
5467
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005468 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005469 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005470
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471 for (;*buttonChar != 0;)
5472 {
5473 /* Get the name of the button */
5474 button++;
5475 len = 0;
5476 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5477 {
5478 if (*buttonChar != DLG_HOTKEY_CHAR)
5479 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005480 else
5481 {
5482 aHotKey = (char_u)*(buttonChar+1);
5483 if (aHotKey >= 'A' && aHotKey <= 'Z')
5484 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5485 hotKeys[aHotKey] = button;
5486#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5487 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5488#endif
5489 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005490 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005491
Bram Moolenaar071d4272004-06-13 20:20:40 +00005492 if (*buttonChar != 0)
5493 buttonChar++;
5494 name[0] = len;
5495
5496 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005497 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005498
5499 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005500 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005501
5502 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005503 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005504 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005505 /* TODO: Should be based on the message width */
5506 if (width > maxButtonWidth)
5507 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005508 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005509
5510 totalButtonWidth += width;
5511
5512 if (width > widestButton)
5513 widestButton = width;
5514 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005515 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005516 lastButton = button;
5517
5518 /* Add the icon to the Dialog Box. */
5519 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005520 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 switch (type)
5522 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005523 case VIM_GENERIC:
5524 case VIM_INFO:
5525 case VIM_QUESTION: useIcon = kNoteIcon; break;
5526 case VIM_WARNING: useIcon = kCautionIcon; break;
5527 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005528 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005529 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005530 AppendDITL(theDialog, iconDITL, overlayDITL);
5531 ReleaseResource(iconDITL);
5532 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005533 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005534 iconHandle = GetIcon(useIcon);
5535 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005536
5537 /* Add the message to the Dialog box. */
5538 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005539 messageDITL = GetResource('DITL', 132);
5540 AppendDITL(theDialog, messageDITL, overlayDITL);
5541 ReleaseResource(messageDITL);
5542 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5543 (void) C2PascalString(message, &name);
5544 SetDialogItemText(itemHandle, name);
5545 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005546
5547 /* Add the input box if needed */
5548 if (textfield != NULL)
5549 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005550 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005551 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005552 inputDITL = GetResource('DITL', 132);
5553 AppendDITL(theDialog, inputDITL, overlayDITL);
5554 ReleaseResource(inputDITL);
5555 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5556/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5557 (void) C2PascalString(textfield, &name);
5558 SetDialogItemText(itemHandle, name);
5559 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005560
5561 /* Hotkeys don't make sense if there's a text field */
5562 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005564 else
5565 /* Install hotkey table */
5566 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005567
5568 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005569 SetDialogDefaultItem(theDialog, dfltbutton);
5570 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571
5572 /* Reposition element */
5573
5574 /* Check if we need to force vertical */
5575 if (totalButtonWidth > maximumWidth)
5576 vertical = TRUE;
5577
5578 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005579 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005580 iconItm.box.right = box.right;
5581 iconItm.box.bottom = box.bottom;
5582
5583 /* Place Message */
5584 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005585 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5586 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587
5588 /* Place Input */
5589 if (textfield != NULL)
5590 {
5591 inputItm.box.left = messageItm.box.left;
5592 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005593 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5594 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595 /* Convert the static text into a text edit.
5596 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005597 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5598 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5600 }
5601
5602 /* Place Button */
5603 if (textfield != NULL)
5604 {
5605 buttonItm.box.left = inputItm.box.left;
5606 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5607 }
5608 else
5609 {
5610 buttonItm.box.left = messageItm.box.left;
5611 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5612 }
5613
5614 for (button=1; button <= lastButton; button++)
5615 {
5616
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005617 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005618 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 if (vertical)
5620 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005621 macSizeDialogItem(theDialog, button, widestButton, 0);
5622 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623 }
5624 /* Calculate position of next button */
5625 if (vertical)
5626 buttonItm.box.top = box.bottom + dfltElementSpacing;
5627 else
5628 buttonItm.box.left = box.right + dfltElementSpacing;
5629 }
5630
5631 /* Resize the dialog box */
5632 dialogHeight = box.bottom + dfltElementSpacing;
5633 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5634
Bram Moolenaar071d4272004-06-13 20:20:40 +00005635 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005636 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638
5639 /* Display it */
5640 ShowWindow(theWindow);
5641/* BringToFront(theWindow); */
5642 SelectWindow(theWindow);
5643
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005644/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005646 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005647 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005648#endif
5649
Bram Moolenaard68071d2006-05-02 22:08:30 +00005650#ifdef USE_CARBONKEYHANDLER
5651 /* Avoid that we use key events for the main window. */
5652 dialog_busy = TRUE;
5653#endif
5654
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005655 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5656 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5657
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658 /* Hang until one of the button is hit */
5659 do
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005660 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaarabab0b02019-03-30 18:47:01 +01005661 while ((itemHit < 1) || (itemHit > lastButton));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005662
Bram Moolenaard68071d2006-05-02 22:08:30 +00005663#ifdef USE_CARBONKEYHANDLER
5664 dialog_busy = FALSE;
5665#endif
5666
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667 /* Copy back the text entered by the user into the param */
5668 if (textfield != NULL)
5669 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005670 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5671 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005672#if IOSIZE < 256
5673 /* Truncate the name to IOSIZE if needed */
5674 if (name[0] > IOSIZE)
5675 name[0] = IOSIZE - 1;
5676#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005677 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005678 }
5679
5680 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005681 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005683 /* Free the modal filterProc */
5684 DisposeRoutineDescriptor(dialogUPP);
5685
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005686 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005687 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688
5689 return itemHit;
5690/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005691 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 * SetDialogTimeout(): Auto click a button after timeout
5693 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5694 * MoveDialogItem(): Probably better than SetDialogItem
5695 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005696 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697 */
5698}
5699#endif /* FEAT_DIALOG_GUI */
5700
5701/*
5702 * Display the saved error message(s).
5703 */
5704#ifdef USE_MCH_ERRMSG
5705 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005706display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005707{
5708 char *p;
5709 char_u pError[256];
5710
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005711 if (error_ga.ga_data == NULL)
5712 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005713
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005714 /* avoid putting up a message box with blanks only */
5715 for (p = (char *)error_ga.ga_data; *p; ++p)
5716 if (!isspace(*p))
5717 {
5718 if (STRLEN(p) > 255)
5719 pError[0] = 255;
5720 else
5721 pError[0] = STRLEN(p);
5722
5723 STRNCPY(&pError[1], p, pError[0]);
5724 ParamText(pError, nil, nil, nil);
5725 Alert(128, nil);
5726 break;
5727 /* TODO: handled message longer than 256 chars
5728 * use auto-sizeable alert
5729 * or dialog with scrollbars (TextEdit zone)
5730 */
5731 }
5732 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733}
5734#endif
5735
5736/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005737 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005738 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005739 void
5740gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005741{
5742 Point where;
5743
5744 GetMouse(&where);
5745
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005746 *x = where.h;
5747 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005748}
5749
5750 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005751gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752{
5753 /* TODO */
5754#if 0
5755 /* From FAQ 3-11 */
5756
5757 CursorDevicePtr myMouse;
5758 Point where;
5759
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005760 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5761 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762 {
5763 /* New way */
5764
5765 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005766 * Get first device with one button.
5767 * This will probably be the standard mouse
5768 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005769 *
5770 */
5771
5772 myMouse = nil;
5773
5774 do
5775 {
5776 /* Get the next cursor device */
5777 CursorDeviceNextDevice(&myMouse);
5778 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005779 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005781 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005782 }
5783 else
5784 {
5785 /* Old way */
5786 where.h = x;
5787 where.v = y;
5788
5789 *(Point *)RawMouse = where;
5790 *(Point *)MTemp = where;
5791 *(Ptr) CrsrNew = 0xFFFF;
5792 }
5793#endif
5794}
5795
5796 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005797gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005798{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799/*
5800 * Clone PopUp to use menu
5801 * Create a object descriptor for the current selection
5802 * Call the procedure
5803 */
5804
5805 MenuHandle CntxMenu;
5806 Point where;
5807 OSStatus status;
5808 UInt32 CntxType;
5809 SInt16 CntxMenuID;
5810 UInt16 CntxMenuItem;
5811 Str255 HelpName = "";
5812 GrafPtr savePort;
5813
5814 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005815 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005817 GetMouse(&where);
5818 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819 CntxMenu = menu->submenu_handle;
5820
5821 /* TODO: Get the text selection from Vim */
5822
5823 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005824 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005825 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826
5827 if (status == noErr)
5828 {
5829 if (CntxType == kCMMenuItemSelected)
5830 {
5831 /* Handle the menu CntxMenuID, CntxMenuItem */
5832 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005833 /* But what about the current menu, is the menu changed by
5834 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005835 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005836 }
5837 else if (CntxMenuID == kCMShowHelpSelected)
5838 {
5839 /* Should come up with the help */
5840 }
5841 }
5842
5843 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005844 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845}
5846
5847#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5848/* TODO: Is it need for MACOS_X? (Dany) */
5849 void
5850mch_post_buffer_write(buf_T *buf)
5851{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005852 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5853 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005854}
5855#endif
5856
5857#ifdef FEAT_TITLE
5858/*
5859 * Set the window title and icon.
5860 * (The icon is not taken care of).
5861 */
5862 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005863gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864{
5865 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5866 * that 256. Even better get it to fit nicely in the titlebar.
5867 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005868#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005869 CFStringRef windowTitle;
5870 size_t windowTitleLen;
5871#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874
5875 if (title == NULL) /* nothing to do */
5876 return;
5877
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005878#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005879 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005880 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005881
5882 if (windowTitle)
5883 {
5884 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5885 CFRelease(windowTitle);
5886 }
5887#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888 pascalTitle = C2Pascal_save(title);
5889 if (pascalTitle != NULL)
5890 {
5891 SetWTitle(gui.VimWindow, pascalTitle);
5892 vim_free(pascalTitle);
5893 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005894#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895}
5896#endif
5897
5898/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005899 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005900 */
5901
5902 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005903C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005904{
5905 char_u *PascalPtr = (char_u *) PascalString;
5906 int len;
5907 int i;
5908
5909 PascalPtr[0] = 0;
5910 if (CString == NULL)
5911 return 0;
5912
5913 len = STRLEN(CString);
5914 if (len > 255)
5915 len = 255;
5916
5917 for (i = 0; i < len; i++)
5918 PascalPtr[i+1] = CString[i];
5919
5920 PascalPtr[0] = len;
5921
5922 return 0;
5923}
5924
5925 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005926GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005927{
5928 /* From FAQ 8-12 */
5929 Str255 filePascal;
5930 CInfoPBRec myCPB;
5931 OSErr err;
5932
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005933 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934
5935 myCPB.dirInfo.ioNamePtr = filePascal;
5936 myCPB.dirInfo.ioVRefNum = 0;
5937 myCPB.dirInfo.ioFDirIndex = 0;
5938 myCPB.dirInfo.ioDrDirID = 0;
5939
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005940 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941
5942 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005943 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944
5945 /* TODO: Use an error code mechanism */
5946 return 0;
5947}
5948
5949/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005950 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951 */
5952
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005953char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005954{
5955 /*
5956 * TODO: Add protection for 256 char max.
5957 */
5958
5959 CInfoPBRec theCPB;
5960 char_u fname[256];
5961 char_u *filenamePtr = fname;
5962 OSErr error;
5963 int folder = 1;
5964#ifdef USE_UNIXFILENAME
5965 SInt16 dfltVol_vRefNum;
5966 SInt32 dfltVol_dirID;
5967 FSRef refFile;
5968 OSStatus status;
5969 UInt32 pathSize = 256;
5970 char_u pathname[256];
5971 char_u *path = pathname;
5972#else
5973 Str255 directoryName;
5974 char_u temporary[255];
5975 char_u *temporaryPtr = temporary;
5976#endif
5977
5978#ifdef USE_UNIXFILENAME
5979 /* Get the default volume */
5980 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005981 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982
5983 if (error)
5984 return NULL;
5985#endif
5986
5987 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005988 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005989
5990 /* Get the info about the file specified in FSSpec */
5991 theCPB.dirInfo.ioFDirIndex = 0;
5992 theCPB.dirInfo.ioNamePtr = file.name;
5993 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00005994 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005995 theCPB.dirInfo.ioDrDirID = file.parID;
5996
5997 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5998 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005999 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006000
6001 /* If we are called for a new file we expect fnfErr */
6002 if ((error) && (error != fnfErr))
6003 return NULL;
6004
6005 /* Check if it's a file or folder */
6006 /* default to file if file don't exist */
6007 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6008 folder = 0; /* It's not a folder */
6009 else
6010 folder = 1;
6011
6012#ifdef USE_UNIXFILENAME
6013 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006014 * The functions used here are available in Carbon, but do nothing on
6015 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006016 */
6017 if (error == fnfErr)
6018 {
6019 /* If the file to be saved does not already exist, it isn't possible
6020 to convert its FSSpec into an FSRef. But we can construct an
6021 FSSpec for the file's parent folder (since we have its volume and
6022 directory IDs), and since that folder does exist, we can convert
6023 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6024 and, finally, append the filename. */
6025 FSSpec dirSpec;
6026 FSRef dirRef;
6027 Str255 emptyFilename = "\p";
6028 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6029 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6030 if (error)
6031 return NULL;
6032
6033 error = FSpMakeFSRef(&dirSpec, &dirRef);
6034 if (error)
6035 return NULL;
6036
6037 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6038 if (status)
6039 return NULL;
6040
6041 STRCAT(path, "/");
6042 STRCAT(path, filenamePtr);
6043 }
6044 else
6045 {
6046 /* If the file to be saved already exists, we can get its full path
6047 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006048 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006049 if (error)
6050 return NULL;
6051
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006052 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006053 if (status)
6054 return NULL;
6055 }
6056
6057 /* Add a slash at the end if needed */
6058 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006059 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006061 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062#else
6063 /* TODO: Get rid of all USE_UNIXFILENAME below */
6064 /* Set ioNamePtr, it's the same area which is always reused. */
6065 theCPB.dirInfo.ioNamePtr = directoryName;
6066
6067 /* Trick for first entry, set ioDrParID to the first value
6068 * we want for ioDrDirID*/
6069 theCPB.dirInfo.ioDrParID = file.parID;
6070 theCPB.dirInfo.ioDrDirID = file.parID;
6071
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006072 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006073 do
6074 {
6075 theCPB.dirInfo.ioFDirIndex = -1;
6076 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6077 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006078 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6080
6081 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6082 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006083 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084
6085 if (error)
6086 return NULL;
6087
6088 /* Put the new directoryName in front of the current fname */
6089 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006090 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091 STRCAT(filenamePtr, ":");
6092 STRCAT(filenamePtr, temporaryPtr);
6093 }
6094#if 1 /* def USE_UNIXFILENAME */
6095 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6096 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6097#else
6098 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6099#endif
6100
6101 /* Get the information about the volume on which the file reside */
6102 theCPB.dirInfo.ioFDirIndex = -1;
6103 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6104 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006105 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006106 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6107
6108 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6109 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006110 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006111
6112 if (error)
6113 return NULL;
6114
6115 /* For MacOS Classic always add the volume name */
6116 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006117 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118#ifdef USE_UNIXFILENAME
6119 if (file.vRefNum != dfltVol_vRefNum)
6120#endif
6121 {
6122 /* Add the volume name */
6123 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006124 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 STRCAT(filenamePtr, ":");
6126 STRCAT(filenamePtr, temporaryPtr);
6127
6128#ifdef USE_UNIXFILENAME
6129 STRCPY(temporaryPtr, filenamePtr);
6130 filenamePtr[0] = 0; /* NULL terminate the string */
6131 STRCAT(filenamePtr, "Volumes:");
6132 STRCAT(filenamePtr, temporaryPtr);
6133#endif
6134 }
6135
6136 /* Append final path separator if it's a folder */
6137 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006138 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139
6140 /* As we use Unix File Name for MacOS X convert it */
6141#ifdef USE_UNIXFILENAME
6142 /* Need to insert leading / */
6143 /* TODO: get the above code to use directly the / */
6144 STRCPY(&temporaryPtr[1], filenamePtr);
6145 temporaryPtr[0] = '/';
6146 STRCPY(filenamePtr, temporaryPtr);
6147 {
6148 char *p;
6149 for (p = fname; *p; p++)
6150 if (*p == ':')
6151 *p = '/';
6152 }
6153#endif
6154
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006155 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006156#endif
6157}
6158
Bram Moolenaar13505972019-01-24 15:04:48 +01006159#if defined(USE_CARBONKEYHANDLER) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160/*
6161 * Input Method Control functions.
6162 */
6163
6164/*
6165 * Notify cursor position to IM.
6166 */
6167 void
6168im_set_position(int row, int col)
6169{
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006170# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006172 im_start_row = row;
6173 im_start_col = col;
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006174# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006175}
6176
6177static ScriptLanguageRecord gTSLWindow;
6178static ScriptLanguageRecord gTSLInsert;
6179static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6180
6181static Component gTSCWindow;
6182static Component gTSCInsert;
6183static Component gTSCDefault;
6184
6185static int im_initialized = 0;
6186
6187 static void
6188im_on_window_switch(int active)
6189{
6190 ScriptLanguageRecord *slptr = NULL;
6191 OSStatus err;
6192
6193 if (! gui.in_use)
6194 return;
6195
6196 if (im_initialized == 0)
6197 {
6198 im_initialized = 1;
6199
6200 /* save default TSM component (should be U.S.) to default */
6201 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6202 kKeyboardInputMethodClass);
6203 }
6204
6205 if (active == TRUE)
6206 {
6207 im_is_active = TRUE;
6208 ActivateTSMDocument(gTSMDocument);
6209 slptr = &gTSLWindow;
6210
6211 if (slptr)
6212 {
6213 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6214 kKeyboardInputMethodClass);
6215 if (err == noErr)
6216 err = SetTextServiceLanguage(slptr);
6217
6218 if (err == noErr)
6219 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6220 }
6221 }
6222 else
6223 {
6224 err = GetTextServiceLanguage(&gTSLWindow);
6225 if (err == noErr)
6226 slptr = &gTSLWindow;
6227
6228 if (slptr)
6229 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6230 kKeyboardInputMethodClass);
6231
6232 im_is_active = FALSE;
6233 DeactivateTSMDocument(gTSMDocument);
6234 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235}
6236
6237/*
6238 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6239 */
6240 void
6241im_set_active(int active)
6242{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006243 ScriptLanguageRecord *slptr = NULL;
6244 OSStatus err;
6245
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006246 if (!gui.in_use)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006247 return;
6248
6249 if (im_initialized == 0)
6250 {
6251 im_initialized = 1;
6252
6253 /* save default TSM component (should be U.S.) to default */
6254 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6255 kKeyboardInputMethodClass);
6256 }
6257
6258 if (active == TRUE)
6259 {
6260 im_is_active = TRUE;
6261 ActivateTSMDocument(gTSMDocument);
6262 slptr = &gTSLInsert;
6263
6264 if (slptr)
6265 {
6266 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6267 kKeyboardInputMethodClass);
6268 if (err == noErr)
6269 err = SetTextServiceLanguage(slptr);
6270
6271 if (err == noErr)
6272 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6273 }
6274 }
6275 else
6276 {
6277 err = GetTextServiceLanguage(&gTSLInsert);
6278 if (err == noErr)
6279 slptr = &gTSLInsert;
6280
6281 if (slptr)
6282 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6283 kKeyboardInputMethodClass);
6284
6285 /* restore to default when switch to normal mode, so than we could
6286 * enter commands easier */
6287 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6288 kKeyboardInputMethodClass);
6289 SetTextServiceLanguage(&gTSLDefault);
6290
6291 im_is_active = FALSE;
6292 DeactivateTSMDocument(gTSMDocument);
6293 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294}
6295
6296/*
6297 * Get IM status. When IM is on, return not 0. Else return 0.
6298 */
6299 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006300im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006301{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006302 if (! gui.in_use)
6303 return 0;
6304
6305 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006307
Bram Moolenaar13505972019-01-24 15:04:48 +01006308#endif
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006309
6310
6311
6312#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6313// drawer implementation
6314static MenuRef contextMenu = NULL;
6315enum
6316{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006317 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006318};
6319
6320// the caller has to CFRelease() the returned string
6321 static CFStringRef
6322getTabLabel(tabpage_T *page)
6323{
6324 get_tabline_label(page, FALSE);
6325#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006326 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006327#else
6328 // TODO: check internal encoding?
6329 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6330 kCFStringEncodingMacRoman);
6331#endif
6332}
6333
6334
6335#define DRAWER_SIZE 150
6336#define DRAWER_INSET 16
6337
6338static ControlRef dataBrowser = NULL;
6339
6340// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006341// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006342// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006343// for a very short time. to prevent inconsistent state, we store the labels
6344// of the tabs, not pointers to the tabs (which are invalid for a short time).
6345static CFStringRef *tabLabels = NULL;
6346static int tabLabelsSize = 0;
6347
6348enum
6349{
6350 kTabsColumn = 'Tabs'
6351};
6352
6353 static int
6354getTabCount(void)
6355{
6356 tabpage_T *tp;
6357 int numTabs = 0;
6358
Bram Moolenaar29323592016-07-24 22:04:11 +02006359 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006360 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006361 return numTabs;
6362}
6363
6364// data browser item display callback
6365 static OSStatus
6366dbItemDataCallback(ControlRef browser,
6367 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006368 DataBrowserPropertyID property /* column id */,
6369 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006370 Boolean changeValue)
6371{
6372 OSStatus status = noErr;
6373
6374 // assert(property == kTabsColumn); // why is this violated??
6375
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006376 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006377 // In our case, it's always false.
6378 // (that is: if (changeValue) updateInternalData(); else return
6379 // internalData();
6380 if (!changeValue)
6381 {
6382 CFStringRef str;
6383
6384 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6385 str = tabLabels[itemID - 1];
6386 status = SetDataBrowserItemDataText(itemData, str);
6387 }
6388 else
6389 status = errDataBrowserPropertyNotSupported;
6390
6391 return status;
6392}
6393
6394// data browser action callback
6395 static void
6396dbItemNotificationCallback(ControlRef browser,
6397 DataBrowserItemID item,
6398 DataBrowserItemNotification message)
6399{
6400 switch (message)
6401 {
6402 case kDataBrowserItemSelected:
6403 send_tabline_event(item);
6404 break;
6405 }
6406}
6407
6408// callbacks needed for contextual menu:
6409 static void
6410dbGetContextualMenuCallback(ControlRef browser,
6411 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006412 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006413 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006414 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006415{
6416 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6417 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6418 *helpItemString = NULL;
6419
6420 *menu = contextMenu;
6421}
6422
6423 static void
6424dbSelectContextualMenuCallback(ControlRef browser,
6425 MenuRef menu,
6426 UInt32 selectionType,
6427 SInt16 menuID,
6428 MenuItemIndex menuItem)
6429{
6430 if (selectionType == kCMMenuItemSelected)
6431 {
6432 MenuCommand command;
6433 GetMenuItemCommandID(menu, menuItem, &command);
6434
6435 // get tab that was selected when the context menu appeared
6436 // (there is always one tab selected). TODO: check if the context menu
6437 // isn't opened on an item but on empty space (has to be possible some
6438 // way, the finder does it too ;-) )
6439 Handle items = NewHandle(0);
6440 if (items != NULL)
6441 {
6442 int numItems;
6443
6444 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6445 kDataBrowserItemIsSelected, items);
6446 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6447 if (numItems > 0)
6448 {
6449 int idx;
6450 DataBrowserItemID *itemsPtr;
6451
6452 HLock(items);
6453 itemsPtr = (DataBrowserItemID *)*items;
6454 idx = itemsPtr[0];
6455 HUnlock(items);
6456 send_tabline_menu_event(idx, command);
6457 }
6458 DisposeHandle(items);
6459 }
6460 }
6461}
6462
6463// focus callback of the data browser to always leave focus in vim
6464 static OSStatus
6465dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6466{
6467 assert(GetEventClass(event) == kEventClassControl
6468 && GetEventKind(event) == kEventControlSetFocusPart);
6469
6470 return paramErr;
6471}
6472
6473
6474// drawer callback to resize data browser to drawer size
6475 static OSStatus
6476drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6477{
6478 switch (GetEventKind(event))
6479 {
6480 case kEventWindowBoundsChanged: // move or resize
6481 {
6482 UInt32 attribs;
6483 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6484 NULL, sizeof(attribs), NULL, &attribs);
6485 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6486 {
6487 Rect r;
6488 GetWindowBounds(drawer, kWindowContentRgn, &r);
6489 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6490 SetControlBounds(dataBrowser, &r);
6491 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6492 kTabsColumn, r.right);
6493 }
6494 }
6495 break;
6496 }
6497
6498 return eventNotHandledErr;
6499}
6500
6501// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6502// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6503// blue highlights in the list view on these systems, though. Oh well.)
6504
6505
6506#import <mach-o/dyld.h>
6507
6508enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6509
6510 static OSStatus
6511myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6512 OptionBits inAttributesToSet,
6513 OptionBits inAttributesToClear)
6514{
6515 long osVersion;
6516 char *symbolName;
6517 NSSymbol symbol = NULL;
6518 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6519 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6520
6521 Gestalt(gestaltSystemVersion, &osVersion);
6522 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6523 return noErr;
6524
6525 // C name mangling...
6526 symbolName = "_DataBrowserChangeAttributes";
6527 if (!NSIsSymbolNameDefined(symbolName)
6528 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6529 return noErr;
6530
6531 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6532 if (dataBrowserChangeAttributes == NULL)
6533 return noErr; // well...
6534 return dataBrowserChangeAttributes(inDataBrowser,
6535 inAttributesToSet, inAttributesToClear);
6536}
6537
6538 static void
6539initialise_tabline(void)
6540{
6541 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6542 DataBrowserCallbacks dbCallbacks;
6543 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6544 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6545 DataBrowserListViewColumnDesc colDesc;
6546
6547 // drawers have to have compositing enabled
6548 CreateNewWindow(kDrawerWindowClass,
6549 kWindowStandardHandlerAttribute
6550 | kWindowCompositingAttribute
6551 | kWindowResizableAttribute
6552 | kWindowLiveResizeAttribute,
6553 &drawerRect, &drawer);
6554
6555 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6556 SetDrawerParent(drawer, gui.VimWindow);
6557 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6558
6559
6560 // create list view embedded in drawer
6561 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6562 &dataBrowser);
6563
6564 dbCallbacks.version = kDataBrowserLatestCallbacks;
6565 InitDataBrowserCallbacks(&dbCallbacks);
6566 dbCallbacks.u.v1.itemDataCallback =
6567 NewDataBrowserItemDataUPP(dbItemDataCallback);
6568 dbCallbacks.u.v1.itemNotificationCallback =
6569 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6570 dbCallbacks.u.v1.getContextualMenuCallback =
6571 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6572 dbCallbacks.u.v1.selectContextualMenuCallback =
6573 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6574
6575 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6576
6577 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6578 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6579 SetDataBrowserSelectionFlags(dataBrowser,
6580 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6581 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6582 kDataBrowserTableViewFillHilite);
6583 Boolean b = false;
6584 SetControlData(dataBrowser, kControlEntireControl,
6585 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6586
6587 // enable blue background in data browser (this is only in 10.4 and vim
6588 // has to support older osx versions as well, so we have to load this
6589 // function dynamically)
6590 myDataBrowserChangeAttributes(dataBrowser,
6591 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6592
6593 // install callback that keeps focus in vim and away from the data browser
6594 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6595 NULL, NULL);
6596
6597 // install callback that keeps data browser at the size of the drawer
6598 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6599 NULL, NULL);
6600
6601 // add "tabs" column to data browser
6602 colDesc.propertyDesc.propertyID = kTabsColumn;
6603 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6604
6605 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6606 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6607
6608 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6609 colDesc.headerBtnDesc.minimumWidth = 100;
6610 colDesc.headerBtnDesc.maximumWidth = 150;
6611 colDesc.headerBtnDesc.titleOffset = 0;
6612 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6613 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6614 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6615 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6616
6617 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6618
6619 // create tabline popup menu required by vim docs (see :he tabline-menu)
6620 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar29547192018-12-11 20:39:19 +01006621 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006622 TABLINE_MENU_CLOSE, NULL);
6623 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6624 TABLINE_MENU_NEW, NULL);
6625 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6626 TABLINE_MENU_OPEN, NULL);
6627}
6628
6629
6630/*
6631 * Show or hide the tabline.
6632 */
6633 void
6634gui_mch_show_tabline(int showit)
6635{
6636 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006637 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006638 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006639 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006640}
6641
6642/*
6643 * Return TRUE when tabline is displayed.
6644 */
6645 int
6646gui_mch_showing_tabline(void)
6647{
6648 WindowDrawerState state = GetDrawerState(drawer);
6649
6650 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6651}
6652
6653/*
6654 * Update the labels of the tabline.
6655 */
6656 void
6657gui_mch_update_tabline(void)
6658{
6659 tabpage_T *tp;
6660 int numTabs = getTabCount();
6661 int nr = 1;
6662 int curtabidx = 1;
6663
6664 // adjust data browser
6665 if (tabLabels != NULL)
6666 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006667 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006668
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006669 for (i = 0; i < tabLabelsSize; ++i)
6670 CFRelease(tabLabels[i]);
6671 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006672 }
6673 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6674 tabLabelsSize = numTabs;
6675
6676 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6677 {
6678 if (tp == curtab)
6679 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006680 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006681 }
6682
6683 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6684 kDataBrowserItemNoProperty);
6685 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6686 // can pass NULL for the id array
6687 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6688 kDataBrowserItemNoProperty);
6689
6690 DataBrowserItemID item = curtabidx;
6691 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6692}
6693
6694/*
6695 * Set the current tab to "nr". First tab is 1.
6696 */
6697 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006698gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006699{
6700 DataBrowserItemID item = nr;
6701 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6702
6703 // TODO: call something like this?: (or restore scroll position, or...)
6704 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6705 kDataBrowserRevealOnly);
6706}
6707
6708#endif // FEAT_GUI_TABLINE