blob: a6305936e22443e544c12ac66edaa99d06c51690 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Macintosh port by Dany St-Amant
6 * and Axel Kielhorn
Bram Moolenaar79ee3152007-04-26 16:20:50 +00007 * Port to MPW by Bernhard Pruemmer
Bram Moolenaar071d4272004-06-13 20:20:40 +00008 * Initial Carbon port by Ammon Skidmore
9 *
10 * Do ":help uganda" in Vim to read copying and usage conditions.
11 * Do ":help credits" in Vim to see a list of people who contributed.
12 * See README.txt for an overview of the Vim source code.
13 */
14
15/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000016 * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000017 * - Comments mentioning FAQ refer to the book:
18 * "Macworld Mac Programming FAQs" from "IDG Books"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019 */
20
21/*
22 * TODO: Change still to merge from the macvim's iDisk
23 *
24 * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse
25 * uses of MenuItemIndex, changes in gui_mch_set_shellsize,
26 * ScrapManager error handling.
27 * Comments about function remaining to Carbonize.
28 *
29 */
30
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +000031/* TODO (Jussi)
32 * * Clipboard does not work (at least some cases)
33 * * ATSU font rendering has some problems
34 * * Investigate and remove dead code (there is still lots of that)
35 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000036
37#include <Devices.h> /* included first to avoid CR problems */
38#include "vim.h"
39
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000040#define USE_CARBONIZED
41#define USE_AEVENT /* Enable AEVENT */
42#undef USE_OFFSETED_WINDOW /* Debugging feature: start Vim window OFFSETed */
Bram Moolenaar071d4272004-06-13 20:20:40 +000043
Bram Moolenaar84a05ac2013-05-06 04:24:17 +020044/* Compile as CodeWarrior External Editor */
Bram Moolenaar071d4272004-06-13 20:20:40 +000045#if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46# define USE_AEVENT /* Need Apple Event Support */
47#endif
48
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000049/* Vim's Scrap flavor. */
50#define VIMSCRAPFLAVOR 'VIM!'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000051#ifdef FEAT_MBYTE
52# define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
53#else
54# define SCRAPTEXTFLAVOR kScrapFlavorTypeText
55#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000056
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static EventHandlerUPP mouseWheelHandlerUPP = NULL;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000058SInt32 gMacSystemVersion;
Bram Moolenaar071d4272004-06-13 20:20:40 +000059
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000060#ifdef MACOS_CONVERT
61# define USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +000062
63static int im_is_active = FALSE;
Bram Moolenaar259f26a2018-05-15 22:25:40 +020064# if 0
Bram Moolenaared39e1d2008-08-09 17:55:22 +000065 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +000066static int im_start_row = 0;
67static int im_start_col = 0;
Bram Moolenaar259f26a2018-05-15 22:25:40 +020068# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +000069
Bram Moolenaar259f26a2018-05-15 22:25:40 +020070# define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
Bram Moolenaar1b60e502008-03-12 13:40:54 +000071
72static TSMDocumentID gTSMDocument;
73
74static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000075static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000076static EventHandlerUPP winEventHandlerUPP = NULL;
77
78static pascal OSStatus gui_mac_handle_window_activate(
79 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
80
81static pascal OSStatus gui_mac_handle_text_input(
82 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
83
84static pascal OSStatus gui_mac_update_input_area(
85 EventHandlerCallRef nextHandler, EventRef theEvent);
86
87static pascal OSStatus gui_mac_unicode_key_event(
88 EventHandlerCallRef nextHandler, EventRef theEvent);
89
Bram Moolenaar26a60b42005-02-22 08:49:11 +000090#endif
91
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
93/* Include some file. TODO: move into os_mac.h */
94#include <Menus.h>
95#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000096#include <Processes.h>
97#ifdef USE_AEVENT
98# include <AppleEvents.h>
99# include <AERegistry.h>
100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
103# include <ControlDefinitions.h>
104# include <Navigation.h> /* Navigation only part of ?? */
105#endif
106
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000107/* Help Manager (balloon.h, HM prefixed functions) are not supported
108 * under Carbon (Jussi) */
109# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000111# include <MacHelp.h>
112# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113
114/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000115 * These seem to be rectangle options. Why are they not found in
116 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118#define kNothing 0
119#define kCreateEmpty 2 /*1*/
120#define kCreateRect 2
121#define kDestroy 3
122
123/*
124 * Dany: Don't like those...
125 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126#define topLeft(r) (((Point*)&(r))[0])
127#define botRight(r) (((Point*)&(r))[1])
128
129
130/* Time of last mouse click, to detect double-click */
131static long lastMouseTick = 0;
132
133/* ??? */
134static RgnHandle cursorRgn;
135static RgnHandle dragRgn;
136static Rect dragRect;
137static short dragRectEnbl;
138static short dragRectControl;
139
140/* This variable is set when waiting for an event, which is the only moment
141 * scrollbar dragging can be done directly. It's not allowed while commands
142 * are executed, because it may move the cursor and that may cause unexpected
143 * problems (e.g., while ":s" is working).
144 */
145static int allow_scrollbar = FALSE;
146
147/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149
150/* Feedback Action for Scrollbar */
151ControlActionUPP gScrollAction;
152ControlActionUPP gScrollDrag;
153
154/* Keeping track of which scrollbar is being dragged */
155static ControlHandle dragged_sb = NULL;
156
Bram Moolenaarc52da9d2008-03-20 13:39:37 +0000157/* Vector of char_u --> control index for hotkeys in dialogs */
158static short *gDialogHotKeys;
159
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000160static struct
161{
162 FMFontFamily family;
163 FMFontSize size;
164 FMFontStyle style;
165 Boolean isPanelVisible;
166} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000167
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000168#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000169# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000170int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000171ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000172# ifdef FEAT_MBYTE
173ATSUStyle gWideFontStyle;
174# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000175Boolean gIsFontFallbackSet;
Bram Moolenaar76b96fc2010-07-17 16:44:59 +0200176UInt32 useAntialias_cached = 0x0;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000177#endif
178
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179/* Colors Macros */
180#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
181#define Red(c) ((c & 0x00FF0000) >> 16)
182#define Green(c) ((c & 0x0000FF00) >> 8)
183#define Blue(c) ((c & 0x000000FF) >> 0)
184
185/* Key mapping */
186
187#define vk_Esc 0x35 /* -> 1B */
188
189#define vk_F1 0x7A /* -> 10 */
190#define vk_F2 0x78 /*0x63*/
191#define vk_F3 0x63 /*0x76*/
192#define vk_F4 0x76 /*0x60*/
193#define vk_F5 0x60 /*0x61*/
194#define vk_F6 0x61 /*0x62*/
195#define vk_F7 0x62 /*0x63*/ /*?*/
196#define vk_F8 0x64
197#define vk_F9 0x65
198#define vk_F10 0x6D
199#define vk_F11 0x67
200#define vk_F12 0x6F
201#define vk_F13 0x69
202#define vk_F14 0x6B
203#define vk_F15 0x71
204
205#define vk_Clr 0x47 /* -> 1B (ESC) */
206#define vk_Enter 0x4C /* -> 03 */
207
208#define vk_Space 0x31 /* -> 20 */
209#define vk_Tab 0x30 /* -> 09 */
210#define vk_Return 0x24 /* -> 0D */
211/* This is wrong for OSX, what is it for? */
212#define vk_Delete 0X08 /* -> 08 BackSpace */
213
214#define vk_Help 0x72 /* -> 05 */
215#define vk_Home 0x73 /* -> 01 */
216#define vk_PageUp 0x74 /* -> 0D */
217#define vk_FwdDelete 0x75 /* -> 7F */
218#define vk_End 0x77 /* -> 04 */
219#define vk_PageDown 0x79 /* -> 0C */
220
221#define vk_Up 0x7E /* -> 1E */
222#define vk_Down 0x7D /* -> 1F */
223#define vk_Left 0x7B /* -> 1C */
224#define vk_Right 0x7C /* -> 1D */
225
226#define vk_Undo vk_F1
227#define vk_Cut vk_F2
228#define vk_Copy vk_F3
229#define vk_Paste vk_F4
230#define vk_PrintScreen vk_F13
231#define vk_SCrollLock vk_F14
232#define vk_Pause vk_F15
233#define vk_NumLock vk_Clr
234#define vk_Insert vk_Help
235
236#define KeySym char
237
238static struct
239{
240 KeySym key_sym;
241 char_u vim_code0;
242 char_u vim_code1;
243} special_keys[] =
244{
245 {vk_Up, 'k', 'u'},
246 {vk_Down, 'k', 'd'},
247 {vk_Left, 'k', 'l'},
248 {vk_Right, 'k', 'r'},
249
250 {vk_F1, 'k', '1'},
251 {vk_F2, 'k', '2'},
252 {vk_F3, 'k', '3'},
253 {vk_F4, 'k', '4'},
254 {vk_F5, 'k', '5'},
255 {vk_F6, 'k', '6'},
256 {vk_F7, 'k', '7'},
257 {vk_F8, 'k', '8'},
258 {vk_F9, 'k', '9'},
259 {vk_F10, 'k', ';'},
260
261 {vk_F11, 'F', '1'},
262 {vk_F12, 'F', '2'},
263 {vk_F13, 'F', '3'},
264 {vk_F14, 'F', '4'},
265 {vk_F15, 'F', '5'},
266
267/* {XK_Help, '%', '1'}, */
268/* {XK_Undo, '&', '8'}, */
269/* {XK_BackSpace, 'k', 'b'}, */
Bram Moolenaard0573012017-10-28 21:11:06 +0200270/* {vk_Delete, 'k', 'b'}, */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271 {vk_Insert, 'k', 'I'},
272 {vk_FwdDelete, 'k', 'D'},
273 {vk_Home, 'k', 'h'},
274 {vk_End, '@', '7'},
275/* {XK_Prior, 'k', 'P'}, */
276/* {XK_Next, 'k', 'N'}, */
277/* {XK_Print, '%', '9'}, */
278
279 {vk_PageUp, 'k', 'P'},
280 {vk_PageDown, 'k', 'N'},
281
282 /* End of list marker: */
283 {(KeySym)0, 0, 0}
284};
285
286/*
287 * ------------------------------------------------------------
288 * Forward declaration (for those needed)
289 * ------------------------------------------------------------
290 */
291
292#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000293OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294#endif
295
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000296#ifdef FEAT_GUI_TABLINE
297static void initialise_tabline(void);
298static WindowRef drawer = NULL; // TODO: put into gui.h
299#endif
300
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000301#ifdef USE_ATSUI_DRAWING
302static void gui_mac_set_font_attributes(GuiFont font);
303static void gui_mac_dispose_atsui_style(void);
304#endif
305
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306/*
307 * ------------------------------------------------------------
308 * Conversion Utility
309 * ------------------------------------------------------------
310 */
311
312/*
313 * C2Pascal_save
314 *
315 * Allocate memory and convert the C-String passed in
316 * into a pascal string
317 *
318 */
319
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000320 char_u *
321C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322{
323 char_u *PascalString;
324 int len;
325
326 if (Cstring == NULL)
327 return NULL;
328
329 len = STRLEN(Cstring);
330
331 if (len > 255) /* Truncate if necessary */
332 len = 255;
333
334 PascalString = alloc(len + 1);
335 if (PascalString != NULL)
336 {
337 mch_memmove(PascalString + 1, Cstring, len);
338 PascalString[0] = len;
339 }
340
341 return PascalString;
342}
343
344/*
345 * C2Pascal_save_and_remove_backslash
346 *
347 * Allocate memory and convert the C-String passed in
348 * into a pascal string. Also remove the backslash at the same time
349 *
350 */
351
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000352 char_u *
353C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354{
355 char_u *PascalString;
356 int len;
357 char_u *p, *c;
358
359 len = STRLEN(Cstring);
360
361 if (len > 255) /* Truncate if necessary */
362 len = 255;
363
364 PascalString = alloc(len + 1);
365 if (PascalString != NULL)
366 {
367 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
368 {
369 if ((*c == '\\') && (c[1] != 0))
370 {
371 c++;
372 }
373 *p = *c;
374 p++;
375 len++;
376 }
377 PascalString[0] = len;
378 }
379
380 return PascalString;
381}
382
383/*
384 * Convert the modifiers of an Event into vim's modifiers (mouse)
385 */
386
387 int_u
388EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
389{
390 int_u vimModifiers = 0x00;
391
392 if (macModifiers & (shiftKey | rightShiftKey))
393 vimModifiers |= MOUSE_SHIFT;
394 if (macModifiers & (controlKey | rightControlKey))
395 vimModifiers |= MOUSE_CTRL;
396 if (macModifiers & (optionKey | rightOptionKey))
397 vimModifiers |= MOUSE_ALT;
398#if 0
399 /* Not yet supported */
400 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
401 vimModifiers |= MOUSE_CMD;
402#endif
403 return (vimModifiers);
404}
405
406/*
407 * Convert the modifiers of an Event into vim's modifiers (keys)
408 */
409
410 static int_u
411EventModifiers2VimModifiers(EventModifiers macModifiers)
412{
413 int_u vimModifiers = 0x00;
414
415 if (macModifiers & (shiftKey | rightShiftKey))
416 vimModifiers |= MOD_MASK_SHIFT;
417 if (macModifiers & (controlKey | rightControlKey))
418 vimModifiers |= MOD_MASK_CTRL;
419 if (macModifiers & (optionKey | rightOptionKey))
420 vimModifiers |= MOD_MASK_ALT;
421#ifdef USE_CMD_KEY
422 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
423 vimModifiers |= MOD_MASK_CMD;
424#endif
425 return (vimModifiers);
426}
427
428/* Convert a string representing a point size into pixels. The string should
429 * be a positive decimal number, with an optional decimal point (eg, "12", or
430 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
431 * character is stored in *end. The flag "vertical" says whether this
432 * calculation is for a vertical (height) size or a horizontal (width) one.
433 *
434 * From gui_w48.c
435 */
436 static int
437points_to_pixels(char_u *str, char_u **end, int vertical)
438{
439 int pixels;
440 int points = 0;
441 int divisor = 0;
442
443 while (*str)
444 {
445 if (*str == '.' && divisor == 0)
446 {
447 /* Start keeping a divisor, for later */
448 divisor = 1;
449 continue;
450 }
451
452 if (!isdigit(*str))
453 break;
454
455 points *= 10;
456 points += *str - '0';
457 divisor *= 10;
458
459 ++str;
460 }
461
462 if (divisor == 0)
463 divisor = 1;
464
465 pixels = points/divisor;
466 *end = str;
467 return pixels;
468}
469
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000470#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000471/*
472 * Deletes all traces of any Windows-style mnemonic text (including any
473 * parentheses) from a menu item and returns the cleaned menu item title.
474 * The caller is responsible for releasing the returned string.
475 */
476 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000477menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000478{
479 CFStringRef name;
480 size_t menuTitleLen;
481 CFIndex displayLen;
482 CFRange mnemonicStart;
483 CFRange mnemonicEnd;
484 CFMutableStringRef cleanedName;
485
486 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000487 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000488
489 if (name)
490 {
491 /* Simple mnemonic-removal algorithm, assumes single parenthesized
492 * mnemonic character towards the end of the menu text */
493 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
494 displayLen = CFStringGetLength(name);
495
496 if (mnemonicStart.location != kCFNotFound
497 && (mnemonicStart.location + 2) < displayLen
498 && CFStringGetCharacterAtIndex(name,
499 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
500 {
501 if (CFStringFindWithOptions(name, CFSTR(")"),
502 CFRangeMake(mnemonicStart.location + 1,
503 displayLen - mnemonicStart.location - 1),
504 kCFCompareBackwards, &mnemonicEnd) &&
505 (mnemonicStart.location + 2) == mnemonicEnd.location)
506 {
507 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
508 if (cleanedName)
509 {
510 CFStringDelete(cleanedName,
511 CFRangeMake(mnemonicStart.location,
512 mnemonicEnd.location + 1 -
513 mnemonicStart.location));
514
515 CFRelease(name);
516 name = cleanedName;
517 }
518 }
519 }
520 }
521
522 return name;
523}
524#endif
525
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526/*
527 * Convert a list of FSSpec aliases into a list of fullpathname
528 * character strings.
529 */
530
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000531 char_u **
532new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533{
534 char_u **fnames = NULL;
535 OSErr newError;
536 long fileCount;
537 FSSpec fileToOpen;
538 long actualSize;
539 AEKeyword dummyKeyword;
540 DescType dummyType;
541
542 /* Get number of files in list */
543 *error = AECountItems(theList, numFiles);
544 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000545 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
547 /* Allocate the pointer list */
548 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
549
550 /* Empty out the list */
551 for (fileCount = 0; fileCount < *numFiles; fileCount++)
552 fnames[fileCount] = NULL;
553
554 /* Scan the list of FSSpec */
555 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
556 {
557 /* Get the alias for the nth file, convert to an FSSpec */
558 newError = AEGetNthPtr(theList, fileCount, typeFSS,
559 &dummyKeyword, &dummyType,
560 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
561 if (newError)
562 {
563 /* Caller is able to clean up */
564 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000565 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567
568 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000569 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 }
571
572 return (fnames);
573}
574
575/*
576 * ------------------------------------------------------------
577 * CodeWarrior External Editor Support
578 * ------------------------------------------------------------
579 */
580#ifdef FEAT_CW_EDITOR
581
582/*
583 * Handle the Window Search event from CodeWarrior
584 *
585 * Description
586 * -----------
587 *
588 * The IDE sends the Window Search AppleEvent to the editor when it
589 * needs to know whether a particular file is open in the editor.
590 *
591 * Event Reply
592 * -----------
593 *
594 * None. Put data in the location specified in the structure received.
595 *
596 * Remarks
597 * -------
598 *
599 * When the editor receives this event, determine whether the specified
600 * file is open. If it is, return the modification date/time for that file
601 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000602 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 *
604 */
605
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606typedef struct WindowSearch WindowSearch;
607struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
608{
609 FSSpec theFile; // identifies the file
610 long *theDate; // where to put the modification date/time
611};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000613 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000614Handle_KAHL_SRCH_AE(
615 const AppleEvent *theAEvent,
616 AppleEvent *theReply,
617 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618{
619 OSErr error = noErr;
620 buf_T *buf;
621 int foundFile = false;
622 DescType typeCode;
623 WindowSearch SearchData;
624 Size actualSize;
625
626 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
627 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000628 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000630 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000632 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633
Bram Moolenaar29323592016-07-24 22:04:11 +0200634 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 if (buf->b_ml.ml_mfp != NULL
636 && SearchData.theFile.parID == buf->b_FSSpec.parID
637 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
638 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
639 {
640 foundFile = true;
641 break;
642 }
643
644 if (foundFile == false)
645 *SearchData.theDate = fnfErr;
646 else
647 *SearchData.theDate = buf->b_mtime;
648
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 return error;
650};
651
652/*
653 * Handle the Modified (from IDE to Editor) event from CodeWarrior
654 *
655 * Description
656 * -----------
657 *
658 * The IDE sends this event to the external editor when it wants to
659 * know which files that are open in the editor have been modified.
660 *
661 * Parameters None.
662 * ----------
663 *
664 * Event Reply
665 * -----------
666 * The reply for this event is:
667 *
668 * keyDirectObject typeAEList required
669 * each element in the list is a structure of typeChar
670 *
671 * Remarks
672 * -------
673 *
674 * When building the reply event, include one element in the list for
675 * each open file that has been modified.
676 *
677 */
678
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679typedef struct ModificationInfo ModificationInfo;
680struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
681{
682 FSSpec theFile; // identifies the file
683 long theDate; // the date/time the file was last modified
684 short saved; // set this to zero when replying, unused
685};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000687 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000688Handle_KAHL_MOD_AE(
689 const AppleEvent *theAEvent,
690 AppleEvent *theReply,
691 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692{
693 OSErr error = noErr;
694 AEDescList replyList;
695 long numFiles;
696 ModificationInfo theFile;
697 buf_T *buf;
698
699 theFile.saved = 0;
700
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000701 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000703 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
705 /* Send the reply */
706/* replyObject.descriptorType = typeNull;
707 replyObject.dataHandle = nil;*/
708
709/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
710 error = AECreateList(nil, 0, false, &replyList);
711 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000712 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713
714#if 0
715 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000717 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
718 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 * sizeof(DescType))
720 */
721
722 /* AEPutDesc */
723#endif
724
725 numFiles = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +0200726 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 if (buf->b_ml.ml_mfp != NULL)
728 {
729 /* Add this file to the list */
730 theFile.theFile = buf->b_FSSpec;
731 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000732/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
733 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 };
735
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736#if 0
737 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#endif
739
740 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000741 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 if (replyList.dataHandle)
744 AEDisposeDesc(&replyList);
745
746 return error;
747};
748
749/*
750 * Handle the Get Text event from CodeWarrior
751 *
752 * Description
753 * -----------
754 *
755 * The IDE sends the Get Text AppleEvent to the editor when it needs
756 * the source code from a file. For example, when the user issues a
757 * Check Syntax or Compile command, the compiler needs access to
758 * the source code contained in the file.
759 *
760 * Event Reply
761 * -----------
762 *
763 * None. Put data in locations specified in the structure received.
764 *
765 * Remarks
766 * -------
767 *
768 * When the editor receives this event, it must set the size of the handle
769 * in theText to fit the data in the file. It must then copy the entire
770 * contents of the specified file into the memory location specified in
771 * theText.
772 *
773 */
774
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775typedef struct CW_GetText CW_GetText;
776struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
777{
778 FSSpec theFile; /* identifies the file */
779 Handle theText; /* the location where you return the text (must be resized properly) */
780 long *unused; /* 0 (not used) */
781 long *theDate; /* where to put the modification date/time */
782};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000784 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000785Handle_KAHL_GTTX_AE(
786 const AppleEvent *theAEvent,
787 AppleEvent *theReply,
788 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789{
790 OSErr error = noErr;
791 buf_T *buf;
792 int foundFile = false;
793 DescType typeCode;
794 CW_GetText GetTextData;
795 Size actualSize;
796 char_u *line;
797 char_u *fullbuffer = NULL;
798 long linesize;
799 long lineStart;
800 long BufferSize;
801 long lineno;
802
803 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
804
805 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000806 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807
Bram Moolenaar29323592016-07-24 22:04:11 +0200808 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 if (buf->b_ml.ml_mfp != NULL)
810 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
811 {
812 foundFile = true;
813 break;
814 }
815
816 if (foundFile)
817 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
820 {
821 /* Must use the right buffer */
822 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
823 linesize = STRLEN(line) + 1;
824 lineStart = BufferSize;
825 BufferSize += linesize;
826 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000827 SetHandleSize(GetTextData.theText, BufferSize);
828 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 break; /* Simple handling for now */
831 }
832 else
833 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000834 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 }
840 }
841 if (fullbuffer != NULL)
842 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000843 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 }
847 if (foundFile == false)
848 *GetTextData.theDate = fnfErr;
849 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000850/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 *GetTextData.theDate = buf->b_mtime;
852 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000854 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000856 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857}
858
859/*
860 *
861 */
862
863/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000864 pascal OSErr
865FindProcessBySignature(
866 const OSType targetType,
867 const OSType targetCreator,
868 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869{
870 OSErr anErr = noErr;
871 Boolean lookingForProcess = true;
872
873 ProcessInfoRec infoRec;
874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 infoRec.processName = nil;
877 infoRec.processAppSpec = nil;
878
879 psnPtr->lowLongOfPSN = kNoProcess;
880 psnPtr->highLongOfPSN = kNoProcess;
881
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000882 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 anErr = GetNextProcess(psnPtr);
885 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 else
888 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000889 anErr = GetProcessInformation(psnPtr, &infoRec);
890 if ((anErr == noErr)
891 && (infoRec.processType == targetType)
892 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 }
895 }
896
897 return anErr;
898}//end FindProcessBySignature
899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000900 void
901Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000903 OSErr anErr = noErr;
904 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
906 AppleEvent theReply = { typeNull, nil };
907 AESendMode sendMode;
908 AppleEvent theEvent = {typeNull, nil };
909 AEIdleUPP idleProcUPP = nil;
910 ModificationInfo ModData;
911
912
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000914 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
917 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000919 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 {
921 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
922 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
923 }
924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000925 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926
927 /* Add the parms */
928 ModData.theFile = buf->b_FSSpec;
929 ModData.theDate = buf->b_mtime;
930
931 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000932 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 sendMode = kAENoReply;
936 else
937 sendMode = kAEWaitReply;
938
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000939 if (anErr == noErr)
940 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
941 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000943/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000945 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 }
947}
948#endif /* FEAT_CW_EDITOR */
949
950/*
951 * ------------------------------------------------------------
952 * Apple Event Handling procedure
953 * ------------------------------------------------------------
954 */
955#ifdef USE_AEVENT
956
957/*
958 * Handle the Unused parms of an AppleEvent
959 */
960
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000961 OSErr
962HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963{
964 OSErr error;
965 long actualSize;
966 DescType dummyType;
967 AEKeyword missedKeyword;
968
969 /* Get the "missed keyword" attribute from the AppleEvent. */
970 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
971 typeKeyword, &dummyType,
972 (Ptr)&missedKeyword, sizeof(missedKeyword),
973 &actualSize);
974
975 /* If the descriptor isn't found, then we got the required parameters. */
976 if (error == errAEDescNotFound)
977 {
978 error = noErr;
979 }
980 else
981 {
982#if 0
983 /* Why is this removed? */
984 error = errAEEventNotHandled;
985#endif
986 }
987
988 return error;
989}
990
991
992/*
993 * Handle the ODoc AppleEvent
994 *
995 * Deals with all files dragged to the application icon.
996 *
997 */
998
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999typedef struct SelectionRange SelectionRange;
1000struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1001{
1002 short unused1; // 0 (not used)
1003 short lineNum; // line to select (<0 to specify range)
1004 long startRange; // start of selection range (if line < 0)
1005 long endRange; // end of selection range (if line < 0)
1006 long unused2; // 0 (not used)
1007 long theDate; // modification date/time
1008};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001010static long drop_numFiles;
1011static short drop_gotPosition;
1012static SelectionRange drop_thePosition;
1013
1014 static void
1015drop_callback(void *cookie UNUSED)
1016{
1017 /* TODO: Handle the goto/select line more cleanly */
1018 if ((drop_numFiles == 1) & (drop_gotPosition))
1019 {
1020 if (drop_thePosition.lineNum >= 0)
1021 {
1022 lnum = drop_thePosition.lineNum + 1;
1023 /* oap->motion_type = MLINE;
1024 setpcmark();*/
1025 if (lnum < 1L)
1026 lnum = 1L;
1027 else if (lnum > curbuf->b_ml.ml_line_count)
1028 lnum = curbuf->b_ml.ml_line_count;
1029 curwin->w_cursor.lnum = lnum;
1030 curwin->w_cursor.col = 0;
1031 /* beginline(BL_SOL | BL_FIX);*/
1032 }
1033 else
1034 goto_byte(drop_thePosition.startRange + 1);
1035 }
1036
1037 /* Update the screen display */
1038 update_screen(NOT_VALID);
1039
1040 /* Select the text if possible */
1041 if (drop_gotPosition)
1042 {
1043 VIsual_active = TRUE;
1044 VIsual_select = FALSE;
1045 VIsual = curwin->w_cursor;
1046 if (drop_thePosition.lineNum < 0)
1047 {
1048 VIsual_mode = 'v';
1049 goto_byte(drop_thePosition.endRange);
1050 }
1051 else
1052 {
1053 VIsual_mode = 'V';
1054 VIsual.col = 0;
1055 }
1056 }
1057}
1058
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1060 itor the selection range. If lineNum is zero or greater, scroll the text
1061 to the specified line. If lineNum is less than zero, use the values in
1062 startRange and endRange to select the specified characters. Scroll
1063 the text to display the selection. If lineNum, startRange, and
1064 endRange are all negative, there is no selection range specified.
1065 */
1066
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001067 pascal OSErr
1068HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069{
1070 /*
1071 * TODO: Clean up the code with convert the AppleEvent into
1072 * a ":args"
1073 */
1074 OSErr error = noErr;
1075// OSErr firstError = noErr;
1076// short numErrors = 0;
1077 AEDesc theList;
1078 DescType typeCode;
1079 long numFiles;
1080 // long fileCount;
1081 char_u **fnames;
1082// char_u fname[256];
1083 Size actualSize;
1084 SelectionRange thePosition;
1085 short gotPosition = false;
1086 long lnum;
1087
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 /* the direct object parameter is the list of aliases to files (one or more) */
1089 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1090 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001091 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092
1093
1094 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1095 if (error == noErr)
1096 gotPosition = true;
1097 if (error == errAEDescNotFound)
1098 error = noErr;
1099 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001100 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102/*
1103 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1104
1105 if (^error) then
1106 {
1107 if (thePosition.lineNum >= 0)
1108 {
1109 // Goto this line
1110 }
1111 else
1112 {
1113 // Set the range char wise
1114 }
1115 }
1116 */
1117
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1120
1121 if (error)
1122 {
1123 /* TODO: empty fnames[] first */
1124 vim_free(fnames);
1125 return (error);
1126 }
1127
1128 if (starting > 0)
1129 {
1130 int i;
1131 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001132 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133
1134 /* these are the initial files dropped on the Vim icon */
1135 for (i = 0 ; i < numFiles; i++)
1136 {
1137 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1138 || (p = vim_strsave(fnames[i])) == NULL)
1139 mch_exit(2);
1140 else
1141 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001142 if (fnum == -1)
1143 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1144 }
1145
1146 /* If the file name was already in the buffer list we need to switch
1147 * to it. */
1148 if (curbuf->b_fnum != fnum)
1149 {
1150 char_u cmd[30];
1151
1152 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1153 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001155
1156 /* Change directory to the location of the first file. */
Bram Moolenaarb7407d32018-02-03 17:36:27 +01001157 if (GARGCOUNT > 0
1158 && vim_chdirfile(alist_name(&GARGLIST[0]), "drop") == OK)
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001159 shorten_fnames(TRUE);
1160
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 goto finished;
1162 }
1163
1164 /* Handle the drop, :edit to get to the file */
Bram Moolenaar92d147b2018-07-29 17:35:23 +02001165 drop_numFiles = numFiles;
1166 drop_gotPosition = gotPosition;
1167 drop_thePosition = thePosition;
1168 handle_drop(numFiles, fnames, FALSE, drop_callback, NULL);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001169
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170 setcursor();
1171 out_flush();
1172
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001173 /* Fake mouse event to wake from stall */
1174 PostEvent(mouseUp, 0);
1175
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001176finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177 AEDisposeDesc(&theList); /* dispose what we allocated */
1178
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001179 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001180 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181}
1182
1183/*
1184 *
1185 */
1186
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001187 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001188Handle_aevt_oapp_AE(
1189 const AppleEvent *theAEvent,
1190 AppleEvent *theReply,
1191 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192{
1193 OSErr error = noErr;
1194
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001195 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001196 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197}
1198
1199/*
1200 *
1201 */
1202
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001203 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001204Handle_aevt_quit_AE(
1205 const AppleEvent *theAEvent,
1206 AppleEvent *theReply,
1207 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208{
1209 OSErr error = noErr;
1210
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001211 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001213 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214
1215 /* Need to fake a :confirm qa */
1216 do_cmdline_cmd((char_u *)"confirm qa");
1217
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001218 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219}
1220
1221/*
1222 *
1223 */
1224
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001225 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001226Handle_aevt_pdoc_AE(
1227 const AppleEvent *theAEvent,
1228 AppleEvent *theReply,
1229 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001230{
1231 OSErr error = noErr;
1232
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001233 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001235 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236}
1237
1238/*
1239 * Handling of unknown AppleEvent
1240 *
1241 * (Just get rid of all the parms)
1242 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001243 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001244Handle_unknown_AE(
1245 const AppleEvent *theAEvent,
1246 AppleEvent *theReply,
1247 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248{
1249 OSErr error = noErr;
1250
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001251 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001253 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254}
1255
1256
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257/*
1258 * Install the various AppleEvent Handlers
1259 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001260 OSErr
1261InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262{
1263 OSErr error;
1264
1265 /* install open application handler */
1266 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001267 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 if (error)
1269 {
1270 return error;
1271 }
1272
1273 /* install quit application handler */
1274 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001275 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 if (error)
1277 {
1278 return error;
1279 }
1280
1281 /* install open document handler */
1282 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001283 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 if (error)
1285 {
1286 return error;
1287 }
1288
1289 /* install print document handler */
1290 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001291 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292
1293/* Install Core Suite */
1294/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
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, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001298 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299
1300 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001301 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
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, kAEDelete,
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, kAEDoObjectsExist,
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, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001313 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314
1315 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001316 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317
1318 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001319 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001320
1321 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001322 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323
1324 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001325 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326
1327 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001328 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329
1330 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001331 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332*/
1333
1334#ifdef FEAT_CW_EDITOR
1335 /*
1336 * Bind codewarrior support handlers
1337 */
1338 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001339 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340 if (error)
1341 {
1342 return error;
1343 }
1344 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001345 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001346 if (error)
1347 {
1348 return error;
1349 }
1350 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001351 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 if (error)
1353 {
1354 return error;
1355 }
1356#endif
1357
1358 return error;
1359
1360}
1361#endif /* USE_AEVENT */
1362
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001363
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001364/*
1365 * Callback function, installed by InstallFontPanelHandler(), below,
1366 * to handle Font Panel events.
1367 */
1368 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001369FontPanelHandler(
1370 EventHandlerCallRef inHandlerCallRef,
1371 EventRef inEvent,
1372 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001373{
1374 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1375 {
1376 gFontPanelInfo.isPanelVisible = false;
1377 return noErr;
1378 }
1379
1380 if (GetEventKind(inEvent) == kEventFontSelection)
1381 {
1382 OSStatus status;
1383 FMFontFamily newFamily;
1384 FMFontSize newSize;
1385 FMFontStyle newStyle;
1386
1387 /* Retrieve the font family ID number. */
1388 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1389 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1390 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1391 &newFamily);
1392 if (status == noErr)
1393 gFontPanelInfo.family = newFamily;
1394
1395 /* Retrieve the font size. */
1396 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1397 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1398 if (status == noErr)
1399 gFontPanelInfo.size = newSize;
1400
1401 /* Retrieve the font style (bold, etc.). Currently unused. */
1402 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1403 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1404 if (status == noErr)
1405 gFontPanelInfo.style = newStyle;
1406 }
1407 return noErr;
1408}
1409
1410
1411 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001412InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001413{
1414 EventTypeSpec eventTypes[2];
1415 EventHandlerUPP handlerUPP;
1416 /* EventHandlerRef handlerRef; */
1417
1418 eventTypes[0].eventClass = kEventClassFont;
1419 eventTypes[0].eventKind = kEventFontSelection;
1420 eventTypes[1].eventClass = kEventClassFont;
1421 eventTypes[1].eventKind = kEventFontPanelClosed;
1422
1423 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1424
1425 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1426 /*userData=*/NULL, /*handlerRef=*/NULL);
1427}
1428
1429
1430/*
1431 * Fill the buffer pointed to by outName with the name and size
1432 * of the font currently selected in the Font Panel.
1433 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001434#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001435 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001436GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001437{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001438 Str255 buf;
1439 ByteCount fontNameLen = 0;
1440 ATSUFontID fid;
1441 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001442
1443 if (!outName)
1444 return;
1445
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001446 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1447 {
1448 /* Canonicalize localized font names */
1449 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1450 gFontPanelInfo.style, &fid, NULL) != noErr)
1451 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001452
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001453 /* Request font name with Mac encoding (otherwise we could
1454 * get an unwanted utf-16 name) */
1455 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1456 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001457 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001458 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001459
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001460 /* Only encode font size, because style (bold, italic, etc) is
1461 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001462 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001463 gFontPanelInfo.size/*,
1464 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1465 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1466 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1467
1468 if ((fontNameLen + STRLEN(styleString)) < 255)
1469 STRCPY(outName + fontNameLen, styleString);
1470 }
1471 else
1472 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001473 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001474 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001475}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001476
1477
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478/*
1479 * ------------------------------------------------------------
1480 * Unfiled yet
1481 * ------------------------------------------------------------
1482 */
1483
1484/*
1485 * gui_mac_get_menu_item_index
1486 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001487 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001489 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001490gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491{
1492 short index;
1493 short itemIndex = -1;
1494 vimmenu_T *pBrother;
1495
1496 /* Only menu without parent are the:
1497 * -menu in the menubar
1498 * -popup menu
1499 * -toolbar (guess)
1500 *
1501 * Which are not items anyway.
1502 */
1503 if (pMenu->parent)
1504 {
1505 /* Start from the Oldest Brother */
1506 pBrother = pMenu->parent->children;
1507 index = 1;
1508 while ((pBrother) && (itemIndex == -1))
1509 {
1510 if (pBrother == pMenu)
1511 itemIndex = index;
1512 index++;
1513 pBrother = pBrother->next;
1514 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515 }
1516 return itemIndex;
1517}
1518
1519 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001520gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001521{
1522 short index;
1523 vimmenu_T *pChildMenu;
1524 vimmenu_T *pElder = pMenu->parent;
1525
1526
1527 /* Only menu without parent are the:
1528 * -menu in the menubar
1529 * -popup menu
1530 * -toolbar (guess)
1531 *
1532 * Which are not items anyway.
1533 */
1534
1535 if ((pElder) && (pElder->submenu_id == menuID))
1536 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1538 pMenu = pMenu->next;
1539 }
1540 else
1541 {
1542 for (; pMenu != NULL; pMenu = pMenu->next)
1543 {
1544 if (pMenu->children != NULL)
1545 {
1546 pChildMenu = gui_mac_get_vim_menu
1547 (menuID, itemIndex, pMenu->children);
1548 if (pChildMenu)
1549 {
1550 pMenu = pChildMenu;
1551 break;
1552 }
1553 }
1554 }
1555 }
1556 return pMenu;
1557}
1558
1559/*
1560 * ------------------------------------------------------------
1561 * MacOS Feedback procedures
1562 * ------------------------------------------------------------
1563 */
1564 pascal
1565 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001566gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567{
1568 scrollbar_T *sb;
1569 int value, dragging;
1570 ControlHandle theControlToUse;
1571 int dont_scroll_save = dont_scroll;
1572
1573 theControlToUse = dragged_sb;
1574
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001575 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576
1577 if (sb == NULL)
1578 return;
1579
1580 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001581 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582 dragging = (partCode != 0);
1583
1584 /* When "allow_scrollbar" is FALSE still need to remember the new
1585 * position, but don't actually scroll by setting "dont_scroll". */
1586 dont_scroll = !allow_scrollbar;
1587 gui_drag_scrollbar(sb, value, dragging);
1588 dont_scroll = dont_scroll_save;
1589}
1590
1591 pascal
1592 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001593gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594{
1595 /* TODO: have live support */
1596 scrollbar_T *sb, *sb_info;
1597 long data;
1598 long value;
1599 int page;
1600 int dragging = FALSE;
1601 int dont_scroll_save = dont_scroll;
1602
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001603 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604
1605 if (sb == NULL)
1606 return;
1607
1608 if (sb->wp != NULL) /* Left or right scrollbar */
1609 {
1610 /*
1611 * Careful: need to get scrollbar info out of first (left) scrollbar
1612 * for window, but keep real scrollbar too because we must pass it to
1613 * gui_drag_scrollbar().
1614 */
1615 sb_info = &sb->wp->w_scrollbars[0];
1616
1617 if (sb_info->size > 5)
1618 page = sb_info->size - 2; /* use two lines of context */
1619 else
1620 page = sb_info->size;
1621 }
1622 else /* Bottom scrollbar */
1623 {
1624 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001625 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626 }
1627
1628 switch (partCode)
1629 {
1630 case kControlUpButtonPart: data = -1; break;
1631 case kControlDownButtonPart: data = 1; break;
1632 case kControlPageDownPart: data = page; break;
1633 case kControlPageUpPart: data = -page; break;
1634 default: data = 0; break;
1635 }
1636
1637 value = sb_info->value + data;
1638/* if (value > sb_info->max)
1639 value = sb_info->max;
1640 else if (value < 0)
1641 value = 0;*/
1642
1643 /* When "allow_scrollbar" is FALSE still need to remember the new
1644 * position, but don't actually scroll by setting "dont_scroll". */
1645 dont_scroll = !allow_scrollbar;
1646 gui_drag_scrollbar(sb, value, dragging);
1647 dont_scroll = dont_scroll_save;
1648
1649 out_flush();
1650 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1651
1652/* if (sb_info->wp != NULL)
1653 {
1654 win_T *wp;
1655 int sb_num;
1656
1657 sb_num = 0;
1658 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1659 sb_num++;
1660
1661 if (wp != NULL)
1662 {
1663 current_scrollbar = sb_num;
1664 scrollbar_value = value;
1665 gui_do_scroll();
1666 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1667 }
1668 }*/
1669}
1670
1671/*
1672 * ------------------------------------------------------------
1673 * MacOS Click Handling procedures
1674 * ------------------------------------------------------------
1675 */
1676
1677
1678/*
1679 * Handle a click inside the window, it may happens in the
1680 * scrollbar or the contents.
1681 *
1682 * TODO: Add support for potential TOOLBAR
1683 */
1684 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001685gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686{
1687 Point thePoint;
1688 int_u vimModifiers;
1689 short thePortion;
1690 ControlHandle theControl;
1691 int vimMouseButton;
1692 short dblClick;
1693
1694 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001695 GlobalToLocal(&thePoint);
1696 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001698 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699
1700 if (theControl != NUL)
1701 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001702 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703
1704 if (thePortion != kControlIndicatorPart)
1705 {
1706 dragged_sb = theControl;
1707 TrackControl(theControl, thePoint, gScrollAction);
1708 dragged_sb = NULL;
1709 }
1710 else
1711 {
1712 dragged_sb = theControl;
1713#if 1
1714 TrackControl(theControl, thePoint, gScrollDrag);
1715#else
1716 TrackControl(theControl, thePoint, NULL);
1717#endif
1718 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1719 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001720 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721 dragged_sb = NULL;
1722 }
1723 }
1724 else
1725 {
1726 /* We are inside the contents */
1727
1728 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1729 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1730
1731 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1732 vimMouseButton = MOUSE_LEFT;
1733
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001735 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 clickIsPopup = FALSE;
1737
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001738 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1739 {
1740 vimMouseButton = MOUSE_RIGHT;
1741 vimModifiers &= ~MOUSE_CTRL;
1742 clickIsPopup = TRUE;
1743 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744
1745 /* Is it a double click ? */
1746 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1747
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001748 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 gui_send_mouse_event(vimMouseButton, thePoint.h,
1750 thePoint.v, dblClick, vimModifiers);
1751
1752 /* Create the rectangle around the cursor to detect
1753 * the mouse dragging
1754 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755#if 0
1756 /* TODO: Do we need to this even for the contextual menu?
1757 * It may be require for popup_setpos, but for popup?
1758 */
1759 if (vimMouseButton == MOUSE_LEFT)
1760#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001762 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 FILL_Y(Y_2_ROW(thePoint.v)),
1764 FILL_X(X_2_COL(thePoint.h)+1),
1765 FILL_Y(Y_2_ROW(thePoint.v)+1));
1766
1767 dragRectEnbl = TRUE;
1768 dragRectControl = kCreateRect;
1769 }
1770 }
1771}
1772
1773/*
1774 * Handle the click in the titlebar (to move the window)
1775 */
1776 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001777gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778{
1779 Rect movingLimits;
1780 Rect *movingLimitsPtr = &movingLimits;
1781
1782 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001783 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001784 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785}
1786
1787/*
1788 * Handle the click in the grow box
1789 */
1790 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001791gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792{
1793
1794 long newSize;
1795 unsigned short newWidth;
1796 unsigned short newHeight;
1797 Rect resizeLimits;
1798 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799 Rect NewContentRect;
1800
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001801 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802
Bram Moolenaar720c7102007-05-10 18:07:50 +00001803 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804 /* TODO: Should this come from Vim? */
1805 resizeLimits.top = 100;
1806 resizeLimits.left = 100;
1807
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1809 newWidth = NewContentRect.right - NewContentRect.left;
1810 newHeight = NewContentRect.bottom - NewContentRect.top;
1811 gui_resize_shell(newWidth, newHeight);
1812 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001813 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814}
1815
1816/*
1817 * Handle the click in the zoom box
1818 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001820gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821{
1822 Rect r;
1823 Point p;
1824 short thePart;
1825
1826 /* ideal width is current */
1827 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1828 if (gui.which_scrollbars[SBAR_LEFT])
1829 p.h += gui.scrollbar_width;
1830 if (gui.which_scrollbars[SBAR_RIGHT])
1831 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001832 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 p.v = 15 * 1024;
1834
1835 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1836 ? inZoomIn : inZoomOut;
1837
1838 if (!TrackBox(whichWindow, theEvent->where, thePart))
1839 return;
1840
1841 /* use returned width */
1842 p.h = r.right - r.left;
1843 /* adjust returned height */
1844 p.v = r.bottom - r.top - 2 * gui.border_offset;
1845 if (gui.which_scrollbars[SBAR_BOTTOM])
1846 p.v -= gui.scrollbar_height;
1847 p.v -= p.v % gui.char_height;
1848 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001849 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 p.v += gui.scrollbar_height;
1851
1852 ZoomWindowIdeal(whichWindow, thePart, &p);
1853
1854 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1855 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1856 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001857 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859
1860/*
1861 * ------------------------------------------------------------
1862 * MacOS Event Handling procedure
1863 * ------------------------------------------------------------
1864 */
1865
1866/*
1867 * Handle the Update Event
1868 */
1869
1870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001871gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872{
1873 WindowPtr whichWindow;
1874 GrafPtr savePort;
1875 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 Rect *updateRectPtr;
1878 Rect rc;
1879 Rect growRect;
1880 RgnHandle saveRgn;
1881
1882
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 updateRgn = NewRgn();
1884 if (updateRgn == NULL)
1885 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 /* This could be done by the caller as we
1888 * don't require anything else out of the event
1889 */
1890 whichWindow = (WindowPtr) event->message;
1891
1892 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001893 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894
1895 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001896 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897
1898 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001899 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 /* Redraw the biggest rectangle covering the area
1901 * to be updated.
1902 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1904# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001905 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 * seem to work under MacOS X (Dany)
1907 */
1908 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1909# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001910
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001912 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001913
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001914 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915# if 0
1916 /* Code from original Carbon Port (using GetWindowRegion.
1917 * I believe the UpdateRgn is already in local (Dany)
1918 */
1919 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1920 GlobalToLocal(&botRight(updateRect));
1921# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 /* Update the content (i.e. the text) */
1923 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1924 updateRectPtr->right - updateRectPtr->left,
1925 updateRectPtr->bottom - updateRectPtr->top);
1926 /* Clear the border areas if needed */
1927 gui_mch_set_bg_color(gui.back_pixel);
1928 if (updateRectPtr->left < FILL_X(0))
1929 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001930 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1931 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 if (updateRectPtr->top < FILL_Y(0))
1934 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1936 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 }
1938 if (updateRectPtr->right > FILL_X(Columns))
1939 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001942 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 }
1944 if (updateRectPtr->bottom > FILL_Y(Rows))
1945 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001946 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001948 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001950 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001951 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952
1953 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001954 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955
1956 /* Update the GrowBox */
1957 /* Taken from FAQ 33-27 */
1958 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001960 GetClip(saveRgn);
1961 ClipRect(&growRect);
1962 DrawGrowIcon(whichWindow);
1963 SetClip(saveRgn);
1964 DisposeRgn(saveRgn);
1965 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966
1967 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001968 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969}
1970
1971/*
1972 * Handle the activate/deactivate event
1973 * (apply to a window)
1974 */
1975 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001976gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977{
1978 WindowPtr whichWindow;
1979
1980 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001981 /* Dim scrollbars */
1982 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001984 ControlRef rootControl;
1985 GetRootControl(gui.VimWindow, &rootControl);
1986 if ((event->modifiers) & activeFlag)
1987 ActivateControl(rootControl);
1988 else
1989 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001991
1992 /* Activate */
1993 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994}
1995
1996
1997/*
1998 * Handle the suspend/resume event
1999 * (apply to the application)
2000 */
2001 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002002gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003{
2004 /* The frontmost application just changed */
2005
2006 /* NOTE: the suspend may happen before the deactivate
2007 * seen on MacOS X
2008 */
2009
2010 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002011 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 */
2013 if (event->message & 1)
2014 /* Resume */
2015 gui_focus_change(TRUE);
2016 else
2017 /* Suspend */
2018 gui_focus_change(FALSE);
2019}
2020
2021/*
2022 * Handle the key
2023 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002024#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002025 static pascal OSStatus
2026gui_mac_handle_window_activate(
2027 EventHandlerCallRef nextHandler,
2028 EventRef theEvent,
2029 void *data)
2030{
2031 UInt32 eventClass = GetEventClass(theEvent);
2032 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002033
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002034 if (eventClass == kEventClassWindow)
2035 {
2036 switch (eventKind)
2037 {
2038 case kEventWindowActivated:
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002039# if defined(FEAT_MBYTE)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002040 im_on_window_switch(TRUE);
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002041# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002042 return noErr;
2043
2044 case kEventWindowDeactivated:
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002045# if defined(FEAT_MBYTE)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002046 im_on_window_switch(FALSE);
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002047# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002048 return noErr;
2049 }
2050 }
2051
2052 return eventNotHandledErr;
2053}
2054
2055 static pascal OSStatus
2056gui_mac_handle_text_input(
2057 EventHandlerCallRef nextHandler,
2058 EventRef theEvent,
2059 void *data)
2060{
2061 UInt32 eventClass = GetEventClass(theEvent);
2062 UInt32 eventKind = GetEventKind(theEvent);
2063
2064 if (eventClass != kEventClassTextInput)
2065 return eventNotHandledErr;
2066
2067 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2068 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2069 (kEventTextInputOffsetToPos != eventKind) &&
2070 (kEventTextInputPosToOffset != eventKind) &&
2071 (kEventTextInputGetSelectedText != eventKind))
2072 return eventNotHandledErr;
2073
2074 switch (eventKind)
2075 {
2076 case kEventTextInputUpdateActiveInputArea:
2077 return gui_mac_update_input_area(nextHandler, theEvent);
2078 case kEventTextInputUnicodeForKeyEvent:
2079 return gui_mac_unicode_key_event(nextHandler, theEvent);
2080
2081 case kEventTextInputOffsetToPos:
2082 case kEventTextInputPosToOffset:
2083 case kEventTextInputGetSelectedText:
2084 break;
2085 }
2086
2087 return eventNotHandledErr;
2088}
2089
2090 static pascal
2091OSStatus gui_mac_update_input_area(
2092 EventHandlerCallRef nextHandler,
2093 EventRef theEvent)
2094{
2095 return eventNotHandledErr;
2096}
2097
2098static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2099 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002100
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002101# define INLINE_KEY_BUFFER_SIZE 80
2102 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002103gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002104 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002105 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002106{
2107 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002108 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002109 UInt32 actualSize;
2110 UniChar *text;
2111 char_u result[INLINE_KEY_BUFFER_SIZE];
2112 short len = 0;
2113 UInt32 key_sym;
2114 char charcode;
2115 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002117 size_t encLen;
2118 char_u *to = NULL;
2119 Boolean isSpecial = FALSE;
2120 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123 /* Mask the mouse (as per user setting) */
2124 if (p_mh)
2125 ObscureCursor();
2126
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002127 /* Don't use the keys when the dialog wants them. */
2128 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002130
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002131 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002132 typeUnicodeText, NULL, 0, &actualSize, NULL))
2133 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002134
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002135 text = (UniChar *)alloc(actualSize);
2136 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002138
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002139 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002140 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002141 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002142
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002144 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002146
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002147 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002148 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002150
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002151 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002152 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002153 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002154
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002155 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002156 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002157 require_noerr(err, done);
2158
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002159#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002160 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002161 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002162#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002163
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002164 key_char = charcode;
2165 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002166
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002167 /* Find the special key (eg., for cursor keys) */
2168 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002169 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002170 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002171 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2172 if (special_keys[i].key_sym == key_sym)
2173 {
2174 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2175 special_keys[i].vim_code1);
2176 key_char = simplify_key(key_char,
2177 (int *)&vimModifiers);
2178 isSpecial = TRUE;
2179 break;
2180 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002181 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002182
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002183 /* Intercept CMD-. and CTRL-c */
2184 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002185 ((modifiers & cmdKey) && key_char == '.'))
2186 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002187
2188 if (!isSpecial)
2189 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002190 /* remove SHIFT for keys that are already shifted, e.g.,
2191 * '(' and '*' */
2192 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2193 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002194
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002195 /* remove CTRL from keys that already have it */
2196 if (key_char < 0x20)
2197 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002198
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002199 /* don't process unicode characters here */
2200 if (!IS_SPECIAL(key_char))
2201 {
2202 /* Following code to simplify and consolidate vimModifiers
2203 * taken liberally from gui_w48.c */
2204 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002205
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002206 /* Interpret META, include SHIFT, etc. */
2207 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2208 if (key_char == CSI)
2209 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002210
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002211 if (IS_SPECIAL(key_char))
2212 isSpecial = TRUE;
2213 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002214 }
2215
2216 if (vimModifiers)
2217 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002218 result[len++] = CSI;
2219 result[len++] = KS_MODIFIER;
2220 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002221 }
2222
2223 if (isSpecial && IS_SPECIAL(key_char))
2224 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002225 result[len++] = CSI;
2226 result[len++] = K_SECOND(key_char);
2227 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002228 }
2229 else
2230 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002231 encLen = actualSize;
2232 to = mac_utf16_to_enc(text, actualSize, &encLen);
2233 if (to)
2234 {
2235 /* This is basically add_to_input_buf_csi() */
2236 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2237 {
2238 result[len++] = to[i];
2239 if (to[i] == CSI)
2240 {
2241 result[len++] = KS_EXTRA;
2242 result[len++] = (int)KE_CSI;
2243 }
2244 }
2245 vim_free(to);
2246 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002247 }
2248
2249 add_to_input_buf(result, len);
2250 err = noErr;
2251
2252done:
2253 vim_free(text);
2254 if (err == noErr)
2255 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002256 /* Fake event to wake up WNE (required to get
2257 * key repeat working */
2258 PostEvent(keyUp, 0);
2259 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002260 }
2261
2262 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002263}
2264#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 void
2266gui_mac_doKeyEvent(EventRecord *theEvent)
2267{
2268 /* TODO: add support for COMMAND KEY */
2269 long menu;
2270 unsigned char string[20];
2271 short num, i;
2272 short len = 0;
2273 KeySym key_sym;
2274 int key_char;
2275 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002276 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277
2278 /* Mask the mouse (as per user setting) */
2279 if (p_mh)
2280 ObscureCursor();
2281
2282 /* Get the key code and it's ASCII representation */
2283 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2284 key_char = theEvent->message & charCodeMask;
2285 num = 1;
2286
2287 /* Intercept CTRL-C */
2288 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002289 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 if (key_char == Ctrl_C && ctrl_c_interrupts)
2291 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002292 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2293 && (key_char == '2' || key_char == '6'))
2294 {
2295 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2296 if (key_char == '2')
2297 key_char = Ctrl_AT;
2298 else
2299 key_char = Ctrl_HAT;
2300 theEvent->modifiers = 0;
2301 }
2302 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303
2304 /* Intercept CMD-. */
2305 if (theEvent->modifiers & cmdKey)
2306 if (key_char == '.')
2307 got_int = TRUE;
2308
2309 /* Handle command key as per menu */
2310 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2311 if (theEvent->modifiers & cmdKey)
2312 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2313 * Why the mouse button? */
2314 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2315 {
2316 menu = MenuKey(key_char);
2317 if (HiWord(menu))
2318 {
2319 gui_mac_handle_menu(menu);
2320 return;
2321 }
2322 }
2323
2324 /* Convert the modifiers */
2325 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2326
2327
2328 /* Handle special keys. */
2329#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002330 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2332#endif
2333 {
2334 /* Find the special key (for non-printable keyt_char) */
2335 if ((key_char < 0x20) || (key_char == 0x7f))
2336 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2337 if (special_keys[i].key_sym == key_sym)
2338 {
2339# if 0
2340 /* We currently don't have not so special key */
2341 if (special_keys[i].vim_code1 == NUL)
2342 key_char = special_keys[i].vim_code0;
2343 else
2344# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002345 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2346 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002347 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 break;
2349 }
2350 }
2351
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002352 /* For some keys the modifier is included in the char itself. */
2353 if (simplify || key_char == TAB || key_char == ' ')
2354 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355
2356 /* Add the modifier to the input bu if needed */
2357 /* Do not want SHIFT-A or CTRL-A with modifier */
2358 if (!IS_SPECIAL(key_char)
2359 && key_sym != vk_Space
2360 && key_sym != vk_Tab
2361 && key_sym != vk_Return
2362 && key_sym != vk_Enter
2363 && key_sym != vk_Esc)
2364 {
2365#if 1
2366 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002367 if ((modifiers == MOD_MASK_SHIFT)
2368 || (modifiers == MOD_MASK_CTRL)
2369 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 modifiers = 0;
2371#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002374 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 modifiers = modifiers & ~MOD_MASK_SHIFT;
2378#endif
2379 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002380 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002382 string[len++] = CSI;
2383 string[len++] = KS_MODIFIER;
2384 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 }
2386
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002387 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002389 string[len++] = CSI;
2390 string[len++] = K_SECOND(key_char);
2391 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 }
2393 else
2394 {
2395#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002396 /* Convert characters when needed (e.g., from MacRoman to latin1).
2397 * This doesn't work for the NUL byte. */
2398 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 {
2400 char_u from[2], *to;
2401 int l;
2402
2403 from[0] = key_char;
2404 from[1] = NUL;
2405 l = 1;
2406 to = string_convert(&input_conv, from, &l);
2407 if (to != NULL)
2408 {
2409 for (i = 0; i < l && len < 19; i++)
2410 {
2411 if (to[i] == CSI)
2412 {
2413 string[len++] = KS_EXTRA;
2414 string[len++] = KE_CSI;
2415 }
2416 else
2417 string[len++] = to[i];
2418 }
2419 vim_free(to);
2420 }
2421 else
2422 string[len++] = key_char;
2423 }
2424 else
2425#endif
2426 string[len++] = key_char;
2427 }
2428
2429 if (len == 1 && string[0] == CSI)
2430 {
2431 /* Turn CSI into K_CSI. */
2432 string[ len++ ] = KS_EXTRA;
2433 string[ len++ ] = KE_CSI;
2434 }
2435
2436 add_to_input_buf(string, len);
2437}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002438#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439
2440/*
2441 * Handle MouseClick
2442 */
2443 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002444gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445{
2446 short thePart;
2447 WindowPtr whichWindow;
2448
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002449 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002451#ifdef FEAT_GUI_TABLINE
2452 /* prevent that the vim window size changes if it's activated by a
2453 click into the tab pane */
2454 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002455 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002456#endif
2457
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 switch (thePart)
2459 {
2460 case (inDesk):
2461 /* TODO: what to do? */
2462 break;
2463
2464 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002465 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 break;
2467
2468 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002469 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 break;
2471
2472 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002473 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 break;
2475
2476 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002477 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 break;
2479
2480 case (inGoAway):
2481 if (TrackGoAway(whichWindow, theEvent->where))
2482 gui_shell_closed();
2483 break;
2484
2485 case (inZoomIn):
2486 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 break;
2489 }
2490}
2491
2492/*
2493 * Handle MouseMoved
2494 * [this event is a moving in and out of a region]
2495 */
2496 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002497gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498{
2499 Point thePoint;
2500 int_u vimModifiers;
2501
2502 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002503 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2505
2506 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002507 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2511 thePoint.v, FALSE, vimModifiers);
2512
2513 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002514 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 FILL_Y(Y_2_ROW(thePoint.v)),
2516 FILL_X(X_2_COL(thePoint.h)+1),
2517 FILL_Y(Y_2_ROW(thePoint.v)+1));
2518
2519 if (dragRectEnbl)
2520 dragRectControl = kCreateRect;
2521
2522}
2523
2524/*
2525 * Handle the mouse release
2526 */
2527 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002528gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529{
2530 Point thePoint;
2531 int_u vimModifiers;
2532
2533 /* TODO: Properly convert the Contextual menu mouse-up */
2534 /* Potential source of the double menu */
2535 lastMouseTick = theEvent->when;
2536 dragRectEnbl = FALSE;
2537 dragRectControl = kCreateEmpty;
2538 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002539 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540
2541 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 if (clickIsPopup)
2543 {
2544 vimModifiers &= ~MOUSE_CTRL;
2545 clickIsPopup = FALSE;
2546 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002547 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548}
2549
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 static pascal OSStatus
2551gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2552 void *data)
2553{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 Point point;
2555 Rect bounds;
2556 UInt32 mod;
2557 SInt32 delta;
2558 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002559 EventMouseWheelAxis axis;
2560
2561 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2562 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2563 && axis != kEventMouseWheelAxisY)
2564 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565
2566 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2567 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2568 goto bail;
2569 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2570 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2571 goto bail;
2572 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2573 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2574 goto bail;
2575
2576 vim_mod = 0;
2577 if (mod & shiftKey)
2578 vim_mod |= MOUSE_SHIFT;
2579 if (mod & controlKey)
2580 vim_mod |= MOUSE_CTRL;
2581 if (mod & optionKey)
2582 vim_mod |= MOUSE_ALT;
2583
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2585 {
2586 point.h -= bounds.left;
2587 point.v -= bounds.top;
2588 }
2589
2590 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2591 point.h, point.v, FALSE, vim_mod);
2592
Bram Moolenaarc236c162008-07-13 17:41:49 +00002593 /* post a bogus event to wake up WaitNextEvent */
2594 PostEvent(keyUp, 0);
2595
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 return noErr;
2597
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002598bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 /*
2600 * when we fail give any additional callback handler a chance to perform
2601 * it's actions
2602 */
2603 return CallNextEventHandler(nextHandler, theEvent);
2604}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605
Bram Moolenaare00289d2010-08-14 21:56:42 +02002606 void
2607gui_mch_mousehide(int hide)
2608{
2609 /* TODO */
2610}
2611
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612#if 0
2613
2614/*
2615 * This would be the normal way of invoking the contextual menu
2616 * but the Vim API doesn't seem to a support a request to get
2617 * the menu that we should display
2618 */
2619 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002620gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621{
2622/*
2623 * Clone PopUp to use menu
2624 * Create a object descriptor for the current selection
2625 * Call the procedure
2626 */
2627
2628// Call to Handle Popup
2629 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2630
2631 if (status != noErr)
2632 return;
2633
2634 if (CntxType == kCMMenuItemSelected)
2635 {
2636 /* Handle the menu CntxMenuID, CntxMenuItem */
2637 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002638 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002639 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 }
2641 else if (CntxMenuID == kCMShowHelpSelected)
2642 {
2643 /* Should come up with the help */
2644 }
2645
2646}
2647#endif
2648
2649/*
2650 * Handle menubar selection
2651 */
2652 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002653gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654{
2655 short menu = HiWord(menuChoice);
2656 short item = LoWord(menuChoice);
2657 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658
2659 if (menu == 256) /* TODO: use constant or gui.xyz */
2660 {
2661 if (item == 1)
2662 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 }
2664 else if (item != 0)
2665 {
2666 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2667
2668 if (theVimMenu)
2669 gui_menu_cb(theVimMenu);
2670 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002671 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672}
2673
2674/*
2675 * Dispatch the event to proper handler
2676 */
2677
2678 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002679gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680{
2681 OSErr error;
2682
2683 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002684 if (IsShowContextualMenuClick(event))
2685 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002687 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002689 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002691 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002692 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693
2694 /* Handle normal event */
2695 switch (event->what)
2696 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002697#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 case (keyDown):
2699 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002700 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002704 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 break;
2706
2707 case (mouseDown):
2708 gui_mac_doMouseDownEvent(event);
2709 break;
2710
2711 case (mouseUp):
2712 gui_mac_doMouseUpEvent(event);
2713 break;
2714
2715 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002716 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 break;
2718
2719 case (diskEvt):
2720 /* We don't need special handling for disk insertion */
2721 break;
2722
2723 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002724 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 break;
2726
2727 case (osEvt):
2728 switch ((event->message >> 24) & 0xFF)
2729 {
2730 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002731 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 break;
2733 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002734 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735 break;
2736 }
2737 break;
2738
2739#ifdef USE_AEVENT
2740 case (kHighLevelEvent):
2741 /* Someone's talking to us, through AppleEvents */
2742 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2743 break;
2744#endif
2745 }
2746}
2747
2748/*
2749 * ------------------------------------------------------------
2750 * Unknown Stuff
2751 * ------------------------------------------------------------
2752 */
2753
2754
2755 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002756gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757{
2758 char_u c;
2759 char_u *p;
2760 char_u pFontName[256];
2761 Str255 systemFontname;
2762 short font_id;
2763 short size=9;
2764 GuiFont font;
2765#if 0
2766 char_u *fontNamePtr;
2767#endif
2768
2769 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2770 ;
2771
2772 c = *p;
2773 *p = 0;
2774
2775#if 1
2776 STRCPY(&pFontName[1], font_name);
2777 pFontName[0] = STRLEN(font_name);
2778 *p = c;
2779
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002780 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002781 char_u fontName[256];
2782 char_u *styleStart = vim_strchr(font_name, ':');
2783 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2784 vim_strncpy(fontName, font_name, fontNameLen);
2785
2786 ATSUFontID fontRef;
2787 FMFontStyle fontStyle;
2788 font_id = 0;
2789
2790 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2791 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2792 &fontRef) == noErr)
2793 {
2794 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2795 font_id = 0;
2796 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002797
2798 if (font_id == 0)
2799 {
2800 /*
2801 * Try again, this time replacing underscores in the font name
2802 * with spaces (:set guifont allows the two to be used
2803 * interchangeably; the Font Manager doesn't).
2804 */
2805 int i, changed = FALSE;
2806
2807 for (i = pFontName[0]; i > 0; --i)
2808 {
2809 if (pFontName[i] == '_')
2810 {
2811 pFontName[i] = ' ';
2812 changed = TRUE;
2813 }
2814 }
2815 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002816 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2817 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2818 kFontNoLanguageCode, &fontRef) == noErr)
2819 {
2820 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2821 font_id = 0;
2822 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002823 }
2824
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825#else
2826 /* name = C2Pascal_save(menu->dname); */
2827 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2828
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002829 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830#endif
2831
2832
2833 if (font_id == 0)
2834 {
2835 /* Oups, the system font was it the one the user want */
2836
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002837 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2838 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839 if (!EqualString(pFontName, systemFontname, false, false))
2840 return NOFONT;
2841 }
2842 if (*p == ':')
2843 {
2844 p++;
2845 /* Set the values found after ':' */
2846 while (*p)
2847 {
2848 switch (*p++)
2849 {
2850 case 'h':
2851 size = points_to_pixels(p, &p, TRUE);
2852 break;
2853 /*
2854 * TODO: Maybe accept width and styles
2855 */
2856 }
2857 while (*p == ':')
2858 p++;
2859 }
2860 }
2861
2862 if (size < 1)
2863 size = 1; /* Avoid having a size of 0 with system font */
2864
2865 font = (size << 16) + ((long) font_id & 0xFFFF);
2866
2867 return font;
2868}
2869
2870/*
2871 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002872 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 * ------------------------------------------------------------
2874 */
2875
2876/*
2877 * Parse the GUI related command-line arguments. Any arguments used are
2878 * deleted from argv, and *argc is decremented accordingly. This is called
2879 * when vim is started, whether or not the GUI has been started.
2880 */
2881 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002882gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883{
2884 /* TODO: Move most of this stuff toward gui_mch_init */
2885#ifdef USE_EXE_NAME
2886 FSSpec applDir;
2887# ifndef USE_FIND_BUNDLE_PATH
2888 short applVRefNum;
2889 long applDirID;
2890 Str255 volName;
2891# else
2892 ProcessSerialNumber psn;
2893 FSRef applFSRef;
2894# endif
2895#endif
2896
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897#if 0
2898 InitCursor();
2899
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901
2902#ifdef USE_AEVENT
2903 (void) InstallAEHandlers();
2904#endif
2905
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002906 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002908 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002910 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911
2912 DrawMenuBar();
2913
2914
2915#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002916 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002918 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919#endif
2920
2921
Bram Moolenaar071d4272004-06-13 20:20:40 +00002922 CreateNewWindow(kDocumentWindowClass,
2923 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002924 &windRect, &gui.VimWindow);
2925 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926
2927 gui.char_width = 7;
2928 gui.char_height = 11;
2929 gui.char_ascent = 6;
2930 gui.num_rows = 24;
2931 gui.num_cols = 80;
2932 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2933
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002934 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2935 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936
2937 dragRectEnbl = FALSE;
2938 dragRgn = NULL;
2939 dragRectControl = kCreateEmpty;
2940 cursorRgn = NewRgn();
2941#endif
2942#ifdef USE_EXE_NAME
2943# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002944 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947# else
2948 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2949 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002951 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 /* if (err != noErr) return err; */
2953
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002954 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 /* if (err != noErr) return err; */
2956
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002957 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958
2959 /* This technic return NIL when we disallow_gui */
2960# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002961 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963}
2964
2965#ifndef ALWAYS_USE_GUI
2966/*
2967 * Check if the GUI can be started. Called before gvimrc is sourced.
2968 * Return OK or FAIL.
2969 */
2970 int
2971gui_mch_init_check(void)
2972{
2973 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2974 * using the >console
2975 */
2976 if (disallow_gui) /* see main.c for reason to disallow */
2977 return FAIL;
2978 return OK;
2979}
2980#endif
2981
2982 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002983receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984{
2985 int x, y;
2986 int_u modifiers;
2987 char_u **fnames = NULL;
2988 int count;
2989 int i, j;
2990
2991 /* Get drop position, modifiers and count of items */
2992 {
2993 Point point;
2994 SInt16 mouseUpModifiers;
2995 UInt16 countItem;
2996
2997 GetDragMouse(theDrag, &point, NULL);
2998 GlobalToLocal(&point);
2999 x = point.h;
3000 y = point.v;
3001 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
3002 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
3003 CountDragItems(theDrag, &countItem);
3004 count = countItem;
3005 }
3006
3007 fnames = (char_u **)alloc(count * sizeof(char_u *));
3008 if (fnames == NULL)
3009 return dragNotAcceptedErr;
3010
3011 /* Get file names dropped */
3012 for (i = j = 0; i < count; ++i)
3013 {
3014 DragItemRef item;
3015 OSErr err;
3016 Size size;
3017 FlavorType type = flavorTypeHFS;
3018 HFSFlavor hfsFlavor;
3019
3020 fnames[i] = NULL;
3021 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3022 err = GetFlavorDataSize(theDrag, item, type, &size);
3023 if (err != noErr || size > sizeof(hfsFlavor))
3024 continue;
3025 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3026 if (err != noErr)
3027 continue;
3028 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3029 }
3030 count = j;
3031
3032 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003033
3034 /* Fake mouse event to wake from stall */
3035 PostEvent(mouseUp, 0);
3036
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 return noErr;
3038}
3039
3040/*
3041 * Initialise the GUI. Create all the windows, set up all the call-backs
3042 * etc.
3043 */
3044 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003045gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046{
3047 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003048 Rect windRect;
3049 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003051 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003052 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003053
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003054 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003055 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003056
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057#if 1
3058 InitCursor();
3059
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061
3062#ifdef USE_AEVENT
3063 (void) InstallAEHandlers();
3064#endif
3065
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003066 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003068 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003070 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071
3072 DrawMenuBar();
3073
3074
3075#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003076 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003078 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079#endif
3080
3081 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003084 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3086 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003087 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088
3089 gui.char_width = 7;
3090 gui.char_height = 11;
3091 gui.char_ascent = 6;
3092 gui.num_rows = 24;
3093 gui.num_cols = 80;
3094 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3095
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003096 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3097 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003099 /* Install Carbon event callbacks. */
3100 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101
3102 dragRectEnbl = FALSE;
3103 dragRgn = NULL;
3104 dragRectControl = kCreateEmpty;
3105 cursorRgn = NewRgn();
3106#endif
3107 /* Display any pending error messages */
3108 display_errors();
3109
3110 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003111 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112 gui.norm_pixel = 0x00000000;
3113 gui.back_pixel = 0x00FFFFFF;
3114
3115 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3116 * file). */
3117 set_normal_colors();
3118
3119 /*
3120 * Check that none of the colors are the same as the background color.
3121 * Then store the current values as the defaults.
3122 */
3123 gui_check_colors();
3124 gui.def_norm_pixel = gui.norm_pixel;
3125 gui.def_back_pixel = gui.back_pixel;
3126
3127 /* Get the colors for the highlight groups (gui_check_colors() might have
3128 * changed them) */
3129 highlight_gui_started();
3130
3131 /*
3132 * Setting the gui constants
3133 */
3134#ifdef FEAT_MENU
3135 gui.menu_height = 0;
3136#endif
3137 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3138 gui.border_offset = gui.border_width = 2;
3139
Bram Moolenaar720c7102007-05-10 18:07:50 +00003140 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141 gui_mch_draw_string() below), enable it for all font sizes. */
3142 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 eventTypeSpec.eventClass = kEventClassMouse;
3145 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3146 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3147 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3148 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3149 {
3150 mouseWheelHandlerRef = NULL;
3151 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3152 mouseWheelHandlerUPP = NULL;
3153 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003155#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003156 InterfaceTypeList supportedServices = { kUnicodeDocument };
3157 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3158
3159 /* We don't support inline input yet, use input window by default */
3160 UseInputWindow(gTSMDocument, TRUE);
3161
3162 /* Should we activate the document by default? */
3163 // ActivateTSMDocument(gTSMDocument);
3164
3165 EventTypeSpec textEventTypes[] = {
3166 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3167 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3168 { kEventClassTextInput, kEventTextInputPosToOffset },
3169 { kEventClassTextInput, kEventTextInputOffsetToPos },
3170 };
3171
3172 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3173 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3174 NR_ELEMS(textEventTypes),
3175 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003176 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003177 DisposeEventHandlerUPP(keyEventHandlerUPP);
3178 keyEventHandlerUPP = NULL;
3179 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003180
3181 EventTypeSpec windowEventTypes[] = {
3182 { kEventClassWindow, kEventWindowActivated },
3183 { kEventClassWindow, kEventWindowDeactivated },
3184 };
3185
3186 /* Install window event handler to support TSMDocument activate and
3187 * deactivate */
3188 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3189 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3190 winEventHandlerUPP,
3191 NR_ELEMS(windowEventTypes),
3192 windowEventTypes, NULL, NULL))
3193 {
3194 DisposeEventHandlerUPP(winEventHandlerUPP);
3195 winEventHandlerUPP = NULL;
3196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#endif
3198
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003199/*
3200#ifdef FEAT_MBYTE
3201 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3202#endif
3203*/
3204
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003205#ifdef FEAT_GUI_TABLINE
3206 /*
3207 * Create the tabline
3208 */
3209 initialise_tabline();
3210#endif
3211
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 /* TODO: Load bitmap if using TOOLBAR */
3213 return OK;
3214}
3215
3216/*
3217 * Called when the foreground or background color has been changed.
3218 */
3219 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003220gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221{
3222 /* TODO:
3223 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003224 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 */
3226}
3227
3228/*
3229 * Open the GUI window which was created by a call to gui_mch_init().
3230 */
3231 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003232gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233{
3234 ShowWindow(gui.VimWindow);
3235
3236 if (gui_win_x != -1 && gui_win_y != -1)
3237 gui_mch_set_winpos(gui_win_x, gui_win_y);
3238
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239 /*
3240 * Make the GUI the foreground process (in case it was launched
3241 * from the Terminal or via :gui).
3242 */
3243 {
3244 ProcessSerialNumber psn;
3245 if (GetCurrentProcess(&psn) == noErr)
3246 SetFrontProcess(&psn);
3247 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248
3249 return OK;
3250}
3251
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003252#ifdef USE_ATSUI_DRAWING
3253 static void
3254gui_mac_dispose_atsui_style(void)
3255{
3256 if (p_macatsui && gFontStyle)
3257 ATSUDisposeStyle(gFontStyle);
3258#ifdef FEAT_MBYTE
3259 if (p_macatsui && gWideFontStyle)
3260 ATSUDisposeStyle(gWideFontStyle);
3261#endif
3262}
3263#endif
3264
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 void
3266gui_mch_exit(int rc)
3267{
3268 /* TODO: find out all what is missing here? */
3269 DisposeRgn(cursorRgn);
3270
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003271#ifdef USE_CARBONKEYHANDLER
3272 if (keyEventHandlerUPP)
3273 DisposeEventHandlerUPP(keyEventHandlerUPP);
3274#endif
3275
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276 if (mouseWheelHandlerUPP != NULL)
3277 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003279#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003280 gui_mac_dispose_atsui_style();
3281#endif
3282
3283#ifdef USE_CARBONKEYHANDLER
3284 FixTSMDocument(gTSMDocument);
3285 DeactivateTSMDocument(gTSMDocument);
3286 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003287#endif
3288
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 /* Exit to shell? */
3290 exit(rc);
3291}
3292
3293/*
3294 * Get the position of the top left corner of the window.
3295 */
3296 int
3297gui_mch_get_winpos(int *x, int *y)
3298{
3299 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 Rect bounds;
3301 OSStatus status;
3302
3303 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003304 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305
3306 if (status != noErr)
3307 return FAIL;
3308 *x = bounds.left;
3309 *y = bounds.top;
3310 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311}
3312
3313/*
3314 * Set the position of the top left corner of the window to the given
3315 * coordinates.
3316 */
3317 void
3318gui_mch_set_winpos(int x, int y)
3319{
3320 /* TODO: Should make sure the window is move within range
3321 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3322 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003323 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324}
3325
3326 void
3327gui_mch_set_shellsize(
3328 int width,
3329 int height,
3330 int min_width,
3331 int min_height,
3332 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003333 int base_height,
3334 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 CGrafPtr VimPort;
3337 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338
3339 if (gui.which_scrollbars[SBAR_LEFT])
3340 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003341 VimPort = GetWindowPort(gui.VimWindow);
3342 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003344 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 }
3347 else
3348 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003349 VimPort = GetWindowPort(gui.VimWindow);
3350 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003351 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003352 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353 }
3354
3355 SizeWindow(gui.VimWindow, width, height, TRUE);
3356
3357 gui_resize_shell(width, height);
3358}
3359
3360/*
3361 * Get the screen dimensions.
3362 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3363 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003364 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 */
3366 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003367gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368{
3369 GDHandle dominantDevice = GetMainDevice();
3370 Rect screenRect = (**dominantDevice).gdRect;
3371
3372 *screen_w = screenRect.right - 10;
3373 *screen_h = screenRect.bottom - 40;
3374}
3375
3376
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003377/*
3378 * Open the Font Panel and wait for the user to select a font and
3379 * close the panel. Then fill the buffer pointed to by font_name with
3380 * the name and size of the selected font and return the font's handle,
3381 * or NOFONT in case of an error.
3382 */
3383 static GuiFont
3384gui_mac_select_font(char_u *font_name)
3385{
3386 GuiFont selected_font = NOFONT;
3387 OSStatus status;
3388 FontSelectionQDStyle curr_font;
3389
3390 /* Initialize the Font Panel with the current font. */
3391 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3392 curr_font.size = (gui.norm_font >> 16);
3393 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3394 curr_font.instance.fontStyle = 0;
3395 curr_font.hasColor = false;
3396 curr_font.version = 0; /* version number of the style structure */
3397 status = SetFontInfoForSelection(kFontSelectionQDType,
3398 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3399
3400 gFontPanelInfo.family = curr_font.instance.fontFamily;
3401 gFontPanelInfo.style = curr_font.instance.fontStyle;
3402 gFontPanelInfo.size = curr_font.size;
3403
3404 /* Pop up the Font Panel. */
3405 status = FPShowHideFontPanel();
3406 if (status == noErr)
3407 {
3408 /*
3409 * The Font Panel is modeless. We really need it to be modal,
3410 * so we spin in an event loop until the panel is closed.
3411 */
3412 gFontPanelInfo.isPanelVisible = true;
3413 while (gFontPanelInfo.isPanelVisible)
3414 {
3415 EventRecord e;
3416 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3417 }
3418
3419 GetFontPanelSelection(font_name);
3420 selected_font = gui_mac_find_font(font_name);
3421 }
3422 return selected_font;
3423}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003424
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003425#ifdef USE_ATSUI_DRAWING
3426 static void
3427gui_mac_create_atsui_style(void)
3428{
3429 if (p_macatsui && gFontStyle == NULL)
3430 {
3431 if (ATSUCreateStyle(&gFontStyle) != noErr)
3432 gFontStyle = NULL;
3433 }
3434#ifdef FEAT_MBYTE
3435 if (p_macatsui && gWideFontStyle == NULL)
3436 {
3437 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3438 gWideFontStyle = NULL;
3439 }
3440#endif
3441
3442 p_macatsui_last = p_macatsui;
3443}
3444#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445
3446/*
3447 * Initialise vim to use the font with the given name. Return FAIL if the font
3448 * could not be loaded, OK otherwise.
3449 */
3450 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003451gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452{
3453 /* TODO: Add support for bold italic underline proportional etc... */
3454 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003455 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456 FontInfo font_info;
3457 short font_id;
3458 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003459 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003461#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003462 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003463#endif
3464
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 if (font_name == NULL)
3466 {
3467 /* First try to get the suggested font */
3468 GetFNum(suggestedFont, &font_id);
3469
3470 if (font_id == 0)
3471 {
3472 /* Then pickup the standard application font */
3473 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003474 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003475 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003476 else
3477 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3479 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003480 else if (STRCMP(font_name, "*") == 0)
3481 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003482 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003483
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003484 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003485 if (font == NOFONT)
3486 return FAIL;
3487
3488 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003489 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003490 if (new_p_guifont != NULL)
3491 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003492 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003493 vim_free(p_guifont);
3494 p_guifont = new_p_guifont;
3495 /* Replace spaces in the font name with underscores. */
3496 for ( ; *new_p_guifont; ++new_p_guifont)
3497 {
3498 if (*new_p_guifont == ' ')
3499 *new_p_guifont = '_';
3500 }
3501 }
3502 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 else
3504 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003505 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003506 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507
3508 if (font == NOFONT)
3509 return FAIL;
3510 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003511
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512 gui.norm_font = font;
3513
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003514 hl_set_font_name(used_font_name);
3515
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003516 TextSize(font >> 16);
3517 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003519 GetFontInfo(&font_info);
3520
3521 gui.char_ascent = font_info.ascent;
3522 gui.char_width = CharWidth('_');
3523 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3524
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003525#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003526 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003527 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003528#endif
3529
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531}
3532
Bram Moolenaar02743632005-07-25 20:42:36 +00003533/*
3534 * Adjust gui.char_height (after 'linespace' was changed).
3535 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003537gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538{
3539 FontInfo font_info;
3540
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003541 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3543 gui.char_ascent = font_info.ascent + p_linespace / 2;
3544 return OK;
3545}
3546
3547/*
3548 * Get a font structure for highlighting.
3549 */
3550 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003551gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552{
3553 GuiFont font;
3554
3555 font = gui_mac_find_font(name);
3556
3557 if (font == NOFONT)
3558 {
3559 if (giveErrorIfMissing)
3560 EMSG2(_(e_font), name);
3561 return NOFONT;
3562 }
3563 /*
3564 * TODO : Accept only monospace
3565 */
3566
3567 return font;
3568}
3569
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003570#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003572 * Return the name of font "font" in allocated memory.
3573 * Don't know how to get the actual name, thus use the provided name.
3574 */
3575 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003576gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003577{
3578 if (name == NULL)
3579 return NULL;
3580 return vim_strsave(name);
3581}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003582#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003583
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003584#ifdef USE_ATSUI_DRAWING
3585 static void
3586gui_mac_set_font_attributes(GuiFont font)
3587{
3588 ATSUFontID fontID;
3589 Fixed fontSize;
3590 Fixed fontWidth;
3591
3592 fontID = font & 0xFFFF;
3593 fontSize = Long2Fix(font >> 16);
3594 fontWidth = Long2Fix(gui.char_width);
3595
3596 ATSUAttributeTag attribTags[] =
3597 {
3598 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3599 kATSUMaxATSUITagValue + 1
3600 };
3601
3602 ByteCount attribSizes[] =
3603 {
3604 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3605 sizeof(font)
3606 };
3607
3608 ATSUAttributeValuePtr attribValues[] =
3609 {
3610 &fontID, &fontSize, &fontWidth, &font
3611 };
3612
3613 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3614 {
3615 if (ATSUSetAttributes(gFontStyle,
3616 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3617 attribTags, attribSizes, attribValues) != noErr)
3618 {
3619# ifndef NDEBUG
3620 fprintf(stderr, "couldn't set font style\n");
3621# endif
3622 ATSUDisposeStyle(gFontStyle);
3623 gFontStyle = NULL;
3624 }
3625
3626#ifdef FEAT_MBYTE
3627 if (has_mbyte)
3628 {
3629 /* FIXME: we should use a more mbyte sensitive way to support
3630 * wide font drawing */
3631 fontWidth = Long2Fix(gui.char_width * 2);
3632
3633 if (ATSUSetAttributes(gWideFontStyle,
3634 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3635 attribTags, attribSizes, attribValues) != noErr)
3636 {
3637 ATSUDisposeStyle(gWideFontStyle);
3638 gWideFontStyle = NULL;
3639 }
3640 }
3641#endif
3642 }
3643}
3644#endif
3645
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003646/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647 * Set the current text font.
3648 */
3649 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003650gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003652#ifdef USE_ATSUI_DRAWING
3653 GuiFont currFont;
3654 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003655
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003656 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003657 {
3658 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003659 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3660 sizeof(font), &currFont, &actualFontByteCount) == noErr
3661 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003662 {
3663 if (currFont == font)
3664 return;
3665 }
3666
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003667 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003668 }
3669
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003670 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003671 {
3672 /* Setup automatic font substitution. The user's guifontwide
3673 * is tried first, then the system tries other fonts. */
3674/*
3675 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3676 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3677 ATSUCreateFontFallbacks(&gFontFallbacks);
3678 ATSUSetObjFontFallbacks(gFontFallbacks, );
3679*/
3680 if (gui.wide_font)
3681 {
3682 ATSUFontID fallbackFonts;
3683 gIsFontFallbackSet = TRUE;
3684
3685 if (FMGetFontFromFontFamilyInstance(
3686 (gui.wide_font & 0xFFFF),
3687 0,
3688 &fallbackFonts,
3689 NULL) == noErr)
3690 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003691 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3692 &fallbackFonts,
3693 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003694 }
3695/*
3696 ATSUAttributeValuePtr fallbackValues[] = { };
3697*/
3698 }
3699 }
3700#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 TextSize(font >> 16);
3702 TextFont(font & 0xFFFF);
3703}
3704
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705/*
3706 * If a font is not going to be used, free its structure.
3707 */
3708 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003709gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710{
3711 /*
3712 * Free font when "font" is not 0.
3713 * Nothing to do in the current implementation, since
3714 * nothing is allocated for each font used.
3715 */
3716}
3717
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718/*
3719 * Return the Pixel value (color) for the given color name. This routine was
3720 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3721 * Programmer's Guide.
3722 * Return INVALCOLOR when failed.
3723 */
3724 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003725gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726{
3727 /* TODO: Add support for the new named color of MacOS 8
3728 */
3729 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730
Bram Moolenaarab302212016-04-26 20:59:29 +02003731 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003733 LMGetHiliteRGB(&MacColor);
3734 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003736 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737}
3738
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003739 guicolor_T
3740gui_mch_get_rgb_color(int r, int g, int b)
3741{
3742 return gui_get_rgb_color_cmn(r, g, b);
3743}
3744
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745/*
3746 * Set the current text foreground color.
3747 */
3748 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003749gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750{
3751 RGBColor TheColor;
3752
3753 TheColor.red = Red(color) * 0x0101;
3754 TheColor.green = Green(color) * 0x0101;
3755 TheColor.blue = Blue(color) * 0x0101;
3756
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003757 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758}
3759
3760/*
3761 * Set the current text background color.
3762 */
3763 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003764gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765{
3766 RGBColor TheColor;
3767
3768 TheColor.red = Red(color) * 0x0101;
3769 TheColor.green = Green(color) * 0x0101;
3770 TheColor.blue = Blue(color) * 0x0101;
3771
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003772 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773}
3774
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003775RGBColor specialColor;
3776
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003777/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003778 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003779 */
3780 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003781gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003782{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003783 specialColor.red = Red(color) * 0x0101;
3784 specialColor.green = Green(color) * 0x0101;
3785 specialColor.blue = Blue(color) * 0x0101;
3786}
3787
3788/*
3789 * Draw undercurl at the bottom of the character cell.
3790 */
3791 static void
3792draw_undercurl(int flags, int row, int col, int cells)
3793{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003794 int x;
3795 int offset;
3796 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3797 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003798
3799 RGBForeColor(&specialColor);
3800
3801 offset = val[FILL_X(col) % 8];
3802 MoveTo(FILL_X(col), y - offset);
3803
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003804 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003805 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003806 offset = val[x % 8];
3807 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003808 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003809}
3810
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003811
3812 static void
3813draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815#ifdef FEAT_MBYTE
3816 char_u *tofree = NULL;
3817
3818 if (output_conv.vc_type != CONV_NONE)
3819 {
3820 tofree = string_convert(&output_conv, s, &len);
3821 if (tofree != NULL)
3822 s = tofree;
3823 }
3824#endif
3825
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 /*
3827 * On OS X, try using Quartz-style text antialiasing.
3828 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003829 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 {
3831 /* Quartz antialiasing is available only in OS 10.2 and later. */
3832 UInt32 qd_flags = (p_antialias ?
3833 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003834 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 }
3836
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003837 /*
3838 * When antialiasing we're using srcOr mode, we have to clear the block
3839 * before drawing the text.
3840 * Also needed when 'linespace' is non-zero to remove the cursor and
3841 * underlining.
3842 * But not when drawing transparently.
3843 * The following is like calling gui_mch_clear_block(row, col, row, col +
3844 * len - 1), but without setting the bg color to gui.back_pixel.
3845 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003846 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003847 && !(flags & DRAW_TRANSP))
3848 {
3849 Rect rc;
3850
3851 rc.left = FILL_X(col);
3852 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003853#ifdef FEAT_MBYTE
3854 /* Multibyte computation taken from gui_w32.c */
3855 if (has_mbyte)
3856 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003857 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003858 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003859 }
3860 else
3861#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003862 rc.right = FILL_X(col + len) + (col + len == Columns);
3863 rc.bottom = FILL_Y(row + 1);
3864 EraseRect(&rc);
3865 }
3866
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003867 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 {
3869 StyleParameter face;
3870
3871 face = normal;
3872 if (flags & DRAW_BOLD)
3873 face |= bold;
3874 if (flags & DRAW_UNDERL)
3875 face |= underline;
3876 TextFace(face);
3877
3878 /* Quartz antialiasing works only in srcOr transfer mode. */
3879 TextMode(srcOr);
3880
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 MoveTo(TEXT_X(col), TEXT_Y(row));
3882 DrawText((char*)s, 0, len);
3883 }
3884 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 {
3886 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003887 TextMode(srcCopy);
3888 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889
3890 /* SelectFont(hdc, gui.currFont); */
3891
3892 if (flags & DRAW_TRANSP)
3893 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003894 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 }
3896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003897 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003898 DrawText((char *)s, 0, len);
3899
3900 if (flags & DRAW_BOLD)
3901 {
3902 TextMode(srcOr);
3903 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3904 DrawText((char *)s, 0, len);
3905 }
3906
3907 if (flags & DRAW_UNDERL)
3908 {
3909 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3910 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3911 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003912 if (flags & DRAW_STRIKE)
3913 {
3914 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3915 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3916 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003917 }
3918
3919 if (flags & DRAW_UNDERC)
3920 draw_undercurl(flags, row, col, len);
3921
3922#ifdef FEAT_MBYTE
3923 vim_free(tofree);
3924#endif
3925}
3926
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003927#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003928
3929 static void
3930draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3931{
3932 /* ATSUI requires utf-16 strings */
3933 UniCharCount utf16_len;
3934 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3935 utf16_len /= sizeof(UniChar);
3936
3937 /* - ATSUI automatically antialiases text (Someone)
3938 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003939#ifdef MAC_ATSUI_DEBUG
3940 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3941 row, col, len, len == 1 ? s[0] : ' ');
3942#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003943 /*
3944 * When antialiasing we're using srcOr mode, we have to clear the block
3945 * before drawing the text.
3946 * Also needed when 'linespace' is non-zero to remove the cursor and
3947 * underlining.
3948 * But not when drawing transparently.
3949 * The following is like calling gui_mch_clear_block(row, col, row, col +
3950 * len - 1), but without setting the bg color to gui.back_pixel.
3951 */
3952 if ((flags & DRAW_TRANSP) == 0)
3953 {
3954 Rect rc;
3955
3956 rc.left = FILL_X(col);
3957 rc.top = FILL_Y(row);
3958 /* Multibyte computation taken from gui_w32.c */
3959 if (has_mbyte)
3960 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003961 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003962 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003963 }
3964 else
3965 rc.right = FILL_X(col + len) + (col + len == Columns);
3966
3967 rc.bottom = FILL_Y(row + 1);
3968 EraseRect(&rc);
3969 }
3970
3971 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003972 TextMode(srcCopy);
3973 TextFace(normal);
3974
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003975 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003976 if (flags & DRAW_TRANSP)
3977 {
3978 TextMode(srcOr);
3979 }
3980
3981 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003982
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003983 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003984 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003985 Boolean attValue = true;
3986 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3987 ByteCount attribSizes[] = { sizeof(Boolean) };
3988 ATSUAttributeValuePtr attribValues[] = { &attValue };
3989
3990 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3991 }
3992
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003993 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3994 : kATSStyleNoAntiAliasing;
3995 if (useAntialias != useAntialias_cached)
3996 {
3997 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3998 ByteCount attribSizes[] = { sizeof(UInt32) };
3999 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4000
4001 if (gFontStyle)
4002 ATSUSetAttributes(gFontStyle, 1, attribTags,
4003 attribSizes, attribValues);
4004 if (gWideFontStyle)
4005 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4006 attribSizes, attribValues);
4007
4008 useAntialias_cached = useAntialias;
4009 }
4010
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004011#ifdef FEAT_MBYTE
4012 if (has_mbyte)
4013 {
4014 int n, width_in_cell, last_width_in_cell;
4015 UniCharArrayOffset offset = 0;
4016 UniCharCount yet_to_draw = 0;
4017 ATSUTextLayout textLayout;
4018 ATSUStyle textStyle;
4019
4020 last_width_in_cell = 1;
4021 ATSUCreateTextLayout(&textLayout);
4022 ATSUSetTextPointerLocation(textLayout, tofree,
4023 kATSUFromTextBeginning,
4024 kATSUToTextEnd, utf16_len);
4025 /*
4026 ATSUSetRunStyle(textLayout, gFontStyle,
4027 kATSUFromTextBeginning, kATSUToTextEnd); */
4028
4029 /* Compute the length in display cells. */
4030 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4031 {
4032 width_in_cell = (*mb_ptr2cells)(s + n);
4033
4034 /* probably we are switching from single byte character
4035 * to multibyte characters (which requires more than one
4036 * cell to draw) */
4037 if (width_in_cell != last_width_in_cell)
4038 {
4039#ifdef MAC_ATSUI_DEBUG
4040 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4041 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4042#endif
4043 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4044 : gFontStyle;
4045
4046 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4047 offset += yet_to_draw;
4048 yet_to_draw = 0;
4049 last_width_in_cell = width_in_cell;
4050 }
4051
4052 yet_to_draw++;
4053 }
4054
4055 if (yet_to_draw)
4056 {
4057#ifdef MAC_ATSUI_DEBUG
4058 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4059 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4060#endif
4061 /* finish the rest style */
4062 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4063 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4064 }
4065
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004066 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004067 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004068 kATSUFromTextBeginning, kATSUToTextEnd,
4069 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004070 ATSUDisposeTextLayout(textLayout);
4071 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004072 else
4073#endif
4074 {
4075 ATSUTextLayout textLayout;
4076
4077 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4078 kATSUFromTextBeginning, kATSUToTextEnd,
4079 utf16_len,
4080 (gFontStyle ? 1 : 0), &utf16_len,
4081 (gFontStyle ? &gFontStyle : NULL),
4082 &textLayout) == noErr)
4083 {
4084 ATSUSetTransientFontMatching(textLayout, TRUE);
4085
4086 ATSUDrawText(textLayout,
4087 kATSUFromTextBeginning, kATSUToTextEnd,
4088 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4089
4090 ATSUDisposeTextLayout(textLayout);
4091 }
4092 }
4093
4094 /* drawing is done, now reset bold to normal */
4095 if (gFontStyle && flags & DRAW_BOLD)
4096 {
4097 Boolean attValue = false;
4098
4099 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4100 ByteCount attribSizes[] = { sizeof(Boolean) };
4101 ATSUAttributeValuePtr attribValues[] = { &attValue };
4102
4103 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4104 attribValues);
4105 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 }
4107
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004108 if (flags & DRAW_UNDERC)
4109 draw_undercurl(flags, row, col, len);
4110
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004112}
4113#endif
4114
4115 void
4116gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4117{
4118#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004119 if (p_macatsui == 0 && p_macatsui_last != 0)
4120 /* switch from macatsui to nomacatsui */
4121 gui_mac_dispose_atsui_style();
4122 else if (p_macatsui != 0 && p_macatsui_last == 0)
4123 /* switch from nomacatsui to macatsui */
4124 gui_mac_create_atsui_style();
4125
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004126 if (p_macatsui)
4127 draw_string_ATSUI(row, col, s, len, flags);
4128 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004130 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131}
4132
4133/*
4134 * Return OK if the key with the termcap name "name" is supported.
4135 */
4136 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004137gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138{
4139 int i;
4140
4141 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4142 if (name[0] == special_keys[i].vim_code0 &&
4143 name[1] == special_keys[i].vim_code1)
4144 return OK;
4145 return FAIL;
4146}
4147
4148 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004149gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004151 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152}
4153
4154 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004155gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156{
4157 /* Do a visual beep by reversing the foreground and background colors */
4158 Rect rc;
4159
4160 /*
4161 * Note: InvertRect() excludes right and bottom of rectangle.
4162 */
4163 rc.left = 0;
4164 rc.top = 0;
4165 rc.right = gui.num_cols * gui.char_width;
4166 rc.bottom = gui.num_rows * gui.char_height;
4167 InvertRect(&rc);
4168
4169 ui_delay((long)msec, TRUE); /* wait for some msec */
4170
4171 InvertRect(&rc);
4172}
4173
4174/*
4175 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4176 */
4177 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004178gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179{
4180 Rect rc;
4181
4182 /*
4183 * Note: InvertRect() excludes right and bottom of rectangle.
4184 */
4185 rc.left = FILL_X(c);
4186 rc.top = FILL_Y(r);
4187 rc.right = rc.left + nc * gui.char_width;
4188 rc.bottom = rc.top + nr * gui.char_height;
4189 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190}
4191
4192/*
4193 * Iconify the GUI window.
4194 */
4195 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004196gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004197{
4198 /* TODO: find out what could replace iconify
4199 * -window shade?
4200 * -hide application?
4201 */
4202}
4203
4204#if defined(FEAT_EVAL) || defined(PROTO)
4205/*
4206 * Bring the Vim window to the foreground.
4207 */
4208 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004209gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210{
4211 /* TODO */
4212}
4213#endif
4214
4215/*
4216 * Draw a cursor without focus.
4217 */
4218 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004219gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220{
4221 Rect rc;
4222
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 /*
4224 * Note: FrameRect() excludes right and bottom of rectangle.
4225 */
4226 rc.left = FILL_X(gui.col);
4227 rc.top = FILL_Y(gui.row);
4228 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004229#ifdef FEAT_MBYTE
4230 if (mb_lefthalve(gui.row, gui.col))
4231 rc.right += gui.char_width;
4232#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233 rc.bottom = rc.top + gui.char_height;
4234
4235 gui_mch_set_fg_color(color);
4236
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004237 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238}
4239
4240/*
4241 * Draw part of a cursor, only w pixels wide, and h pixels high.
4242 */
4243 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004244gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245{
4246 Rect rc;
4247
4248#ifdef FEAT_RIGHTLEFT
4249 /* vertical line should be on the right of current point */
4250 if (CURSOR_BAR_RIGHT)
4251 rc.left = FILL_X(gui.col + 1) - w;
4252 else
4253#endif
4254 rc.left = FILL_X(gui.col);
4255 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4256 rc.right = rc.left + w;
4257 rc.bottom = rc.top + h;
4258
4259 gui_mch_set_fg_color(color);
4260
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004261 FrameRect(&rc);
4262// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263}
4264
4265
4266
4267/*
4268 * Catch up with any queued X events. This may put keyboard input into the
4269 * input buffer, call resize call-backs, trigger timers etc. If there is
4270 * nothing in the X event queue (& no timers pending), then we return
4271 * immediately.
4272 */
4273 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004274gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275{
4276 /* TODO: find what to do
4277 * maybe call gui_mch_wait_for_chars (0)
4278 * more like look at EventQueue then
4279 * call heart of gui_mch_wait_for_chars;
4280 *
4281 * if (eventther)
4282 * gui_mac_handle_event(&event);
4283 */
4284 EventRecord theEvent;
4285
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004286 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 if (theEvent.what != nullEvent)
4288 gui_mch_wait_for_chars(0);
4289}
4290
4291/*
4292 * Simple wrapper to neglect more easily the time
4293 * spent inside WaitNextEvent while profiling.
4294 */
4295
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 pascal
4297 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004298WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004299{
4300 if (((long) sleep) < -1)
4301 sleep = 32767;
4302 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4303}
4304
4305/*
4306 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4307 * from the keyboard.
4308 * wtime == -1 Wait forever.
4309 * wtime == 0 This should never happen.
4310 * wtime > 0 Wait wtime milliseconds for a character.
4311 * Returns OK if a character was found to be available within the given time,
4312 * or FAIL otherwise.
4313 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004315gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316{
4317 EventMask mask = (everyEvent);
4318 EventRecord event;
4319 long entryTick;
4320 long currentTick;
4321 long sleeppyTick;
4322
4323 /* If we are providing life feedback with the scrollbar,
4324 * we don't want to try to wait for an event, or else
4325 * there won't be any life feedback.
4326 */
4327 if (dragged_sb != NULL)
4328 return FAIL;
4329 /* TODO: Check if FAIL is the proper return code */
4330
4331 entryTick = TickCount();
4332
4333 allow_scrollbar = TRUE;
4334
4335 do
4336 {
4337/* if (dragRectControl == kCreateEmpty)
4338 {
4339 dragRgn = NULL;
4340 dragRectControl = kNothing;
4341 }
4342 else*/ if (dragRectControl == kCreateRect)
4343 {
4344 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004345 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 dragRectControl = kNothing;
4347 }
4348 /*
4349 * Don't use gui_mch_update() because then we will spin-lock until a
4350 * char arrives, instead we use WaitNextEventWrp() to hang until an
4351 * event arrives. No need to check for input_buf_full because we are
4352 * returning as soon as it contains a single char.
4353 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004354 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004356 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 else
4358 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004359
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004360 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004362 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 if (input_available())
4364 {
4365 allow_scrollbar = FALSE;
4366 return OK;
4367 }
4368 }
4369 currentTick = TickCount();
4370 }
4371 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4372
4373 allow_scrollbar = FALSE;
4374 return FAIL;
4375}
4376
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377/*
4378 * Output routines.
4379 */
4380
4381/* Flush any output to the screen */
4382 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004383gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384{
4385 /* TODO: Is anything needed here? */
4386}
4387
4388/*
4389 * Clear a rectangular region of the screen from text pos (row1, col1) to
4390 * (row2, col2) inclusive.
4391 */
4392 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004393gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394{
4395 Rect rc;
4396
4397 /*
4398 * Clear one extra pixel at the far right, for when bold characters have
4399 * spilled over to the next column.
4400 */
4401 rc.left = FILL_X(col1);
4402 rc.top = FILL_Y(row1);
4403 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4404 rc.bottom = FILL_Y(row2 + 1);
4405
4406 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004407 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408}
4409
4410/*
4411 * Clear the whole text window.
4412 */
4413 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004414gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415{
4416 Rect rc;
4417
4418 rc.left = 0;
4419 rc.top = 0;
4420 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4421 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4422
4423 gui_mch_set_bg_color(gui.back_pixel);
4424 EraseRect(&rc);
4425/* gui_mch_set_fg_color(gui.norm_pixel);
4426 FrameRect(&rc);
4427*/
4428}
4429
4430/*
4431 * Delete the given number of lines from the given row, scrolling up any
4432 * text further down within the scroll region.
4433 */
4434 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004435gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436{
4437 Rect rc;
4438
4439 /* changed without checking! */
4440 rc.left = FILL_X(gui.scroll_region_left);
4441 rc.right = FILL_X(gui.scroll_region_right + 1);
4442 rc.top = FILL_Y(row);
4443 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4444
4445 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004446 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447
4448 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4449 gui.scroll_region_left,
4450 gui.scroll_region_bot, gui.scroll_region_right);
4451}
4452
4453/*
4454 * Insert the given number of lines before the given row, scrolling down any
4455 * following text within the scroll region.
4456 */
4457 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004458gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459{
4460 Rect rc;
4461
4462 rc.left = FILL_X(gui.scroll_region_left);
4463 rc.right = FILL_X(gui.scroll_region_right + 1);
4464 rc.top = FILL_Y(row);
4465 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4466
4467 gui_mch_set_bg_color(gui.back_pixel);
4468
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004469 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470
4471 /* Update gui.cursor_row if the cursor scrolled or copied over */
4472 if (gui.cursor_row >= gui.row
4473 && gui.cursor_col >= gui.scroll_region_left
4474 && gui.cursor_col <= gui.scroll_region_right)
4475 {
4476 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4477 gui.cursor_row += num_lines;
4478 else if (gui.cursor_row <= gui.scroll_region_bot)
4479 gui.cursor_is_valid = FALSE;
4480 }
4481
4482 gui_clear_block(row, gui.scroll_region_left,
4483 row + num_lines - 1, gui.scroll_region_right);
4484}
4485
4486 /*
4487 * TODO: add a vim format to the clipboard which remember
4488 * LINEWISE, CHARWISE, BLOCKWISE
4489 */
4490
4491 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004492clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493{
4494
4495 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004496 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 Size scrapSize;
4498 ScrapFlavorFlags scrapFlags;
4499 ScrapRef scrap = nil;
4500 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 int type;
4502 char *searchCR;
4503 char_u *tempclip;
4504
4505
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004506 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 if (error != noErr)
4508 return;
4509
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004510 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4511 if (error == noErr)
4512 {
4513 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4514 if (error == noErr && scrapSize > 1)
4515 flavor = 1;
4516 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004518 if (flavor == 0)
4519 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004520 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004521 if (error != noErr)
4522 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004524 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004525 if (error != noErr)
4526 return;
4527 }
4528
4529 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004531 /* In CARBON we don't need a Handle, a pointer is good */
4532 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004534 /* tempclip = lalloc(scrapSize+1, TRUE); */
4535 HLock(textOfClip);
4536 error = GetScrapFlavorData(scrap,
4537 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4538 &scrapSize, *textOfClip);
4539 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004541 if (flavor)
4542 type = **textOfClip;
4543 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004544 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004545
4546 tempclip = lalloc(scrapSize + 1, TRUE);
4547 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4548 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004550#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004551 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004552 /* Convert from utf-16 (clipboard) */
4553 size_t encLen = 0;
4554 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004555
4556 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004558 scrapSize = encLen;
4559 vim_free(tempclip);
4560 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004564
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004565 searchCR = (char *)tempclip;
4566 while (searchCR != NULL)
4567 {
4568 searchCR = strchr(searchCR, '\r');
4569 if (searchCR != NULL)
4570 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004572
4573 clip_yank_selection(type, tempclip, scrapSize, cbd);
4574
4575 vim_free(tempclip);
4576 HUnlock(textOfClip);
4577
4578 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579}
4580
4581 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004582clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583{
4584 /*
4585 * TODO: Really nothing to do?
4586 */
4587}
4588
4589 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004590clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591{
4592 return OK;
4593}
4594
4595/*
4596 * Send the current selection to the clipboard.
4597 */
4598 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004599clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600{
4601 Handle textOfClip;
4602 long scrapSize;
4603 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605
4606 char_u *str = NULL;
4607
4608 if (!cbd->owned)
4609 return;
4610
4611 clip_get_selection(cbd);
4612
4613 /*
4614 * Once we set the clipboard, lose ownership. If another application sets
4615 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 cbd->owned = FALSE;
4618
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004619 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004621#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004622 size_t utf16_len = 0;
4623 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4624 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004626 scrapSize = utf16_len;
4627 vim_free(str);
4628 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 }
4630#endif
4631
4632 if (type >= 0)
4633 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004636 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 HLock(textOfClip);
4638
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004639 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004640 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004641 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004642 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004643 scrapSize, *textOfClip + 1);
4644 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4645 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646 HUnlock(textOfClip);
4647 DisposeHandle(textOfClip);
4648 }
4649
4650 vim_free(str);
4651}
4652
4653 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004654gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655{
4656 Rect VimBound;
4657
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004658/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660
4661 if (gui.which_scrollbars[SBAR_LEFT])
4662 {
4663 VimBound.left = -gui.scrollbar_width + 1;
4664 }
4665 else
4666 {
4667 VimBound.left = 0;
4668 }
4669
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004672 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673}
4674
4675/*
4676 * Menu stuff.
4677 */
4678
4679 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004680gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681{
4682 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004683 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684 */
4685}
4686
4687 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004688gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689{
4690 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004691 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 */
4693}
4694
4695/*
4696 * Add a sub menu to the menu bar.
4697 */
4698 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004699gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700{
4701 /*
4702 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4703 * TODO: use menu->mnemonic and menu->actext
4704 * TODO: Try to reuse menu id
4705 * Carbon Help suggest to use only id between 1 and 235
4706 */
4707 static long next_avail_id = 128;
4708 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004709#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004710 CFStringRef name;
4711#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004713#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 short index;
4715 vimmenu_T *parent = menu->parent;
4716 vimmenu_T *brother = menu->next;
4717
4718 /* Cannot add a menu if ... */
4719 if ((parent != NULL && parent->submenu_id == 0))
4720 return;
4721
4722 /* menu ID greater than 1024 are reserved for ??? */
4723 if (next_avail_id == 1024)
4724 return;
4725
4726 /* My brother could be the PopUp, find my real brother */
4727 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4728 brother = brother->next;
4729
4730 /* Find where to insert the menu (for MenuBar) */
4731 if ((parent == NULL) && (brother != NULL))
4732 menu_after_me = brother->submenu_id;
4733
4734 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4735 if (!menu_is_menubar(menu->name))
4736 menu_after_me = hierMenu;
4737
4738 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004739#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004740 name = menu_title_removing_mnemonic(menu);
4741#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004743#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 if (name == NULL)
4745 return;
4746
4747 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 {
4749 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004750 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4751 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752 */
4753 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004754#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004755 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4756 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4757#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004758 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004759#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 next_avail_id++;
4761 }
4762
4763 if (parent == NULL)
4764 {
4765 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4766
4767 /* TODO: Verify if we could only Insert Menu if really part of the
4768 * menubar The Inserted menu are scanned or the Command-key combos
4769 */
4770
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004771 /* Insert the menu */
4772 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773#if 1
4774 /* Vim should normally update it. TODO: verify */
4775 DrawMenuBar();
4776#endif
4777 }
4778 else
4779 {
4780 /* Adding as a submenu */
4781
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004782 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783
4784 /* Call InsertMenuItem followed by SetMenuItemText
4785 * to avoid special character recognition by InsertMenuItem
4786 */
4787 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004788#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004789 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4790#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004792#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4794 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4795 InsertMenu(menu->submenu_handle, hierMenu);
4796 }
4797
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004798#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004799 CFRelease(name);
4800#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004801 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004802#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803
4804#if 0
4805 /* Done by Vim later on */
4806 DrawMenuBar();
4807#endif
4808}
4809
4810/*
4811 * Add a menu item to a menu
4812 */
4813 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004814gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004816#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004817 CFStringRef name;
4818#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004820#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 vimmenu_T *parent = menu->parent;
4822 int menu_inserted;
4823
4824 /* Cannot add item, if the menu have not been created */
4825 if (parent->submenu_id == 0)
4826 return;
4827
4828 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4829 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4830
4831 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004832#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004833 name = menu_title_removing_mnemonic(menu);
4834#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004835 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004836#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837
4838 /* Where are just a menu item, so no handle, no id */
4839 menu->submenu_id = 0;
4840 menu->submenu_handle = NULL;
4841
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 menu_inserted = 0;
4843 if (menu->actext)
4844 {
4845 /* If the accelerator text for the menu item looks like it describes
4846 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4847 * item's command equivalent.
4848 */
4849 int key = 0;
4850 int modifiers = 0;
4851 char_u *p_actext;
4852
4853 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004854 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855 if (*p_actext != 0)
4856 key = 0; /* error: trailing text */
4857 /* find_special_key() returns a keycode with as many of the
4858 * specified modifiers as appropriate already applied (e.g., for
4859 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4860 * as the only modifier). Since we want to display all of the
4861 * modifiers, we need to convert the keycode back to a printable
4862 * character plus modifiers.
4863 * TODO: Write an alternative find_special_key() that doesn't
4864 * apply modifiers.
4865 */
4866 if (key > 0 && key < 32)
4867 {
4868 /* Convert a control key to an uppercase letter. Note that
4869 * by this point it is no longer possible to distinguish
4870 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4871 */
4872 modifiers |= MOD_MASK_CTRL;
4873 key += '@';
4874 }
4875 /* If the keycode is an uppercase letter, set the Shift modifier.
4876 * If it is a lowercase letter, don't set the modifier, but convert
4877 * the letter to uppercase for display in the menu.
4878 */
4879 else if (key >= 'A' && key <= 'Z')
4880 modifiers |= MOD_MASK_SHIFT;
4881 else if (key >= 'a' && key <= 'z')
4882 key += 'A' - 'a';
4883 /* Note: keycodes below 0x22 are reserved by Apple. */
4884 if (key >= 0x22 && vim_isprintc_strict(key))
4885 {
4886 int valid = 1;
4887 char_u mac_mods = kMenuNoModifiers;
4888 /* Convert Vim modifier codes to Menu Manager equivalents. */
4889 if (modifiers & MOD_MASK_SHIFT)
4890 mac_mods |= kMenuShiftModifier;
4891 if (modifiers & MOD_MASK_CTRL)
4892 mac_mods |= kMenuControlModifier;
4893 if (!(modifiers & MOD_MASK_CMD))
4894 mac_mods |= kMenuNoCommandModifier;
4895 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4896 valid = 0; /* TODO: will Alt someday map to Option? */
4897 if (valid)
4898 {
4899 char_u item_txt[10];
4900 /* Insert the menu item after idx, with its command key. */
4901 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4902 item_txt[3] = key;
4903 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4904 /* Set the modifier keys. */
4905 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4906 menu_inserted = 1;
4907 }
4908 }
4909 }
4910 /* Call InsertMenuItem followed by SetMenuItemText
4911 * to avoid special character recognition by InsertMenuItem
4912 */
4913 if (!menu_inserted)
4914 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4915 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004916#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004917 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4918#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004920#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921
4922#if 0
4923 /* Called by Vim */
4924 DrawMenuBar();
4925#endif
4926
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004927#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004928 CFRelease(name);
4929#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930 /* TODO: Can name be freed? */
4931 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004932#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933}
4934
4935 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004936gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937{
4938 /* no tearoff menus */
4939}
4940
4941/*
4942 * Destroy the machine specific menu widget.
4943 */
4944 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004945gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004947 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004948
4949 if (index > 0)
4950 {
4951 if (menu->parent)
4952 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953 {
4954 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004955 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956
4957 /* Delete the Menu if it was a hierarchical Menu */
4958 if (menu->submenu_id != 0)
4959 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004960 DeleteMenu(menu->submenu_id);
4961 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 }
4963 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004964 }
4965#ifdef DEBUG_MAC_MENU
4966 else
4967 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004968 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004969 }
4970#endif
4971 }
4972 else
4973 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004975 DeleteMenu(menu->submenu_id);
4976 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 }
4978 }
4979 /* Shouldn't this be already done by Vim. TODO: Check */
4980 DrawMenuBar();
4981}
4982
4983/*
4984 * Make a menu either grey or not grey.
4985 */
4986 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004987gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988{
4989 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004990 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991/*
4992 index = menu->index;
4993*/
4994 if (grey)
4995 {
4996 if (menu->children)
4997 DisableMenuItem(menu->submenu_handle, index);
4998 if (menu->parent)
4999 if (menu->parent->submenu_handle)
5000 DisableMenuItem(menu->parent->submenu_handle, index);
5001 }
5002 else
5003 {
5004 if (menu->children)
5005 EnableMenuItem(menu->submenu_handle, index);
5006 if (menu->parent)
5007 if (menu->parent->submenu_handle)
5008 EnableMenuItem(menu->parent->submenu_handle, index);
5009 }
5010}
5011
5012/*
5013 * Make menu item hidden or not hidden
5014 */
5015 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005016gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017{
5018 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005019 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005020}
5021
5022
5023/*
5024 * This is called after setting all the menus to grey/hidden or not.
5025 */
5026 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005027gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005028{
5029 DrawMenuBar();
5030}
5031
5032
5033/*
5034 * Scrollbar stuff.
5035 */
5036
5037 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005038gui_mch_enable_scrollbar(
5039 scrollbar_T *sb,
5040 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041{
5042 if (flag)
5043 ShowControl(sb->id);
5044 else
5045 HideControl(sb->id);
5046
5047#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005048 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049#endif
5050}
5051
5052 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005053gui_mch_set_scrollbar_thumb(
5054 scrollbar_T *sb,
5055 long val,
5056 long size,
5057 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058{
5059 SetControl32BitMaximum (sb->id, max);
5060 SetControl32BitMinimum (sb->id, 0);
5061 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005062 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02005064 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065#endif
5066}
5067
5068 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005069gui_mch_set_scrollbar_pos(
5070 scrollbar_T *sb,
5071 int x,
5072 int y,
5073 int w,
5074 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075{
5076 gui_mch_set_bg_color(gui.back_pixel);
5077/* if (gui.which_scrollbars[SBAR_LEFT])
5078 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005079 MoveControl(sb->id, x-16, y);
5080 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005081 }
5082 else
5083 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005084 MoveControl(sb->id, x, y);
5085 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 }*/
5087 if (sb == &gui.bottom_sbar)
5088 h += 1;
5089 else
5090 w += 1;
5091
5092 if (gui.which_scrollbars[SBAR_LEFT])
5093 x -= 15;
5094
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005095 MoveControl(sb->id, x, y);
5096 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005097#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005098 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099#endif
5100}
5101
5102 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005103gui_mch_create_scrollbar(
5104 scrollbar_T *sb,
5105 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106{
5107 Rect bounds;
5108
5109 bounds.top = -16;
5110 bounds.bottom = -10;
5111 bounds.right = -10;
5112 bounds.left = -16;
5113
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005114 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115 &bounds,
5116 "\pScrollBar",
5117 TRUE,
5118 0, /* current*/
5119 0, /* top */
5120 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122 (long) sb->ident);
5123#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005124 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125#endif
5126}
5127
5128 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005129gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130{
5131 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005132 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005134 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135#endif
5136}
5137
Bram Moolenaar703a8042016-06-04 16:24:32 +02005138 int
5139gui_mch_is_blinking(void)
5140{
5141 return FALSE;
5142}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005144 int
5145gui_mch_is_blink_off(void)
5146{
5147 return FALSE;
5148}
5149
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150/*
5151 * Cursor blink functions.
5152 *
5153 * This is a simple state machine:
5154 * BLINK_NONE not blinking at all
5155 * BLINK_OFF blinking, cursor is not shown
5156 * BLINK_ON blinking, cursor is shown
5157 */
5158 void
5159gui_mch_set_blinking(long wait, long on, long off)
5160{
5161 /* TODO: TODO: TODO: TODO: */
5162/* blink_waittime = wait;
5163 blink_ontime = on;
5164 blink_offtime = off;*/
5165}
5166
5167/*
5168 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5169 */
5170 void
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005171gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172{
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005173 if (may_call_gui_update_cursor)
5174 gui_update_cursor(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005175 /* TODO: TODO: TODO: TODO: */
5176/* gui_w32_rm_blink_timer();
5177 if (blink_state == BLINK_OFF)
5178 gui_update_cursor(TRUE, FALSE);
5179 blink_state = BLINK_NONE;*/
5180}
5181
5182/*
5183 * Start the cursor blinking. If it was already blinking, this restarts the
5184 * waiting time and shows the cursor.
5185 */
5186 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005187gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188{
5189 gui_update_cursor(TRUE, FALSE);
5190 /* TODO: TODO: TODO: TODO: */
5191/* gui_w32_rm_blink_timer(); */
5192
5193 /* Only switch blinking on if none of the times is zero */
5194/* if (blink_waittime && blink_ontime && blink_offtime)
5195 {
5196 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5197 (TIMERPROC)_OnBlinkTimer);
5198 blink_state = BLINK_ON;
5199 gui_update_cursor(TRUE, FALSE);
5200 }*/
5201}
5202
5203/*
5204 * Return the RGB value of a pixel as long.
5205 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005206 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005207gui_mch_get_rgb(guicolor_T pixel)
5208{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005209 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005210}
5211
5212
5213
5214#ifdef FEAT_BROWSE
5215/*
5216 * Pop open a file browser and return the file selected, in allocated memory,
5217 * or NULL if Cancel is hit.
5218 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5219 * title - Title message for the file browser dialog.
5220 * dflt - Default name of file.
5221 * ext - Default extension to be added to files without extensions.
5222 * initdir - directory in which to open the browser (NULL = current dir)
5223 * filter - Filter for matched files to choose from.
5224 * Has a format like this:
5225 * "C Files (*.c)\0*.c\0"
5226 * "All Files\0*.*\0\0"
5227 * If these two strings were concatenated, then a choice of two file
5228 * filters will be selectable to the user. Then only matching files will
5229 * be shown in the browser. If NULL, the default allows all files.
5230 *
5231 * *NOTE* - the filter string must be terminated with TWO nulls.
5232 */
5233 char_u *
5234gui_mch_browse(
5235 int saving,
5236 char_u *title,
5237 char_u *dflt,
5238 char_u *ext,
5239 char_u *initdir,
5240 char_u *filter)
5241{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005242 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243 NavReplyRecord reply;
5244 char_u *fname = NULL;
5245 char_u **fnames = NULL;
5246 long numFiles;
5247 NavDialogOptions navOptions;
5248 OSErr error;
5249
5250 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005251 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252
5253
5254 /* TODO: If we get a :browse args, set the Multiple bit. */
5255 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5256 | kNavDontAutoTranslate
5257 | kNavDontAddTranslateItems
5258 /* | kNavAllowMultipleFiles */
5259 | kNavAllowStationery;
5260
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005261 (void) C2PascalString(title, &navOptions.message);
5262 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263 /* Could set clientName?
5264 * windowTitle? (there's no title bar?)
5265 */
5266
5267 if (saving)
5268 {
5269 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005270 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271 if (!reply.validRecord)
5272 return NULL;
5273 }
5274 else
5275 {
5276 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5277 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5278 if (!reply.validRecord)
5279 return NULL;
5280 }
5281
5282 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5283
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005284 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285
5286 if (fnames)
5287 {
5288 fname = fnames[0];
5289 vim_free(fnames);
5290 }
5291
5292 /* TODO: Shorten the file name if possible */
5293 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294}
5295#endif /* FEAT_BROWSE */
5296
5297#ifdef FEAT_GUI_DIALOG
5298/*
5299 * Stuff for dialogues
5300 */
5301
5302/*
5303 * Create a dialogue dynamically from the parameter strings.
5304 * type = type of dialogue (question, alert, etc.)
5305 * title = dialogue title. may be NULL for default title.
5306 * message = text to display. Dialogue sizes to accommodate it.
5307 * buttons = '\n' separated list of button captions, default first.
5308 * dfltbutton = number of default button.
5309 *
5310 * This routine returns 1 if the first button is pressed,
5311 * 2 for the second, etc.
5312 *
5313 * 0 indicates Esc was pressed.
5314 * -1 for unexpected error
5315 *
5316 * If stubbing out this fn, return 1.
5317 */
5318
5319typedef struct
5320{
5321 short idx;
5322 short width; /* Size of the text in pixel */
5323 Rect box;
5324} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5325
5326#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5327
5328 static void
5329macMoveDialogItem(
5330 DialogRef theDialog,
5331 short itemNumber,
5332 short X,
5333 short Y,
5334 Rect *inBox)
5335{
5336#if 0 /* USE_CARBONIZED */
5337 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005338 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005339 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005340 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005341#else
5342 short itemType;
5343 Handle itemHandle;
5344 Rect localBox;
5345 Rect *itemBox = &localBox;
5346
5347 if (inBox != nil)
5348 itemBox = inBox;
5349
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005350 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5351 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5352 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353 /* To move a control (like a button) we need to call both
5354 * MoveControl and SetDialogItem. FAQ 6-18 */
5355 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005356 MoveControl((ControlRef) itemHandle, X, Y);
5357 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005358#endif
5359}
5360
5361 static void
5362macSizeDialogItem(
5363 DialogRef theDialog,
5364 short itemNumber,
5365 short width,
5366 short height)
5367{
5368 short itemType;
5369 Handle itemHandle;
5370 Rect itemBox;
5371
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005372 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373
5374 /* When width or height is zero do not change it */
5375 if (width == 0)
5376 width = itemBox.right - itemBox.left;
5377 if (height == 0)
5378 height = itemBox.bottom - itemBox.top;
5379
5380#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005381 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382#else
5383 /* Resize the bounding box */
5384 itemBox.right = itemBox.left + width;
5385 itemBox.bottom = itemBox.top + height;
5386
5387 /* To resize a control (like a button) we need to call both
5388 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5389 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005390 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005391
5392 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005393 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394#endif
5395}
5396
5397 static void
5398macSetDialogItemText(
5399 DialogRef theDialog,
5400 short itemNumber,
5401 Str255 itemName)
5402{
5403 short itemType;
5404 Handle itemHandle;
5405 Rect itemBox;
5406
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005407 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005408
5409 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005410 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005411 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005412 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005413}
5414
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005415
5416/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5417 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5418 * setting gDialogHotKeys to NULL disables any hotkey handling.
5419 */
5420 static pascal Boolean
5421DialogHotkeyFilterProc (
5422 DialogRef theDialog,
5423 EventRecord *event,
5424 DialogItemIndex *itemHit)
5425{
5426 char_u keyHit;
5427
5428 if (event->what == keyDown || event->what == autoKey)
5429 {
5430 keyHit = (event->message & charCodeMask);
5431
5432 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5433 {
5434#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5435 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5436#endif
5437 *itemHit = gDialogHotKeys[keyHit];
5438
5439 /* When handing off to StdFilterProc, pretend that the user
5440 * clicked the control manually. Note that this is also supposed
5441 * to cause the button to hilite briefly (to give some user
5442 * feedback), but this seems not to actually work (or it's too
5443 * fast to be seen).
5444 */
5445 event->what = kEventControlSimulateHit;
5446
5447 return true; /* we took care of it */
5448 }
5449
5450 /* Defer to the OS's standard behavior for this event.
5451 * This ensures that Enter will still activate the default button. */
5452 return StdFilterProc(theDialog, event, itemHit);
5453 }
5454 return false; /* Let ModalDialog deal with it */
5455}
5456
5457
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005458/* TODO: There have been some crashes with dialogs, check your inbox
5459 * (Jussi)
5460 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005461 int
5462gui_mch_dialog(
5463 int type,
5464 char_u *title,
5465 char_u *message,
5466 char_u *buttons,
5467 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005468 char_u *textfield,
5469 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470{
5471 Handle buttonDITL;
5472 Handle iconDITL;
5473 Handle inputDITL;
5474 Handle messageDITL;
5475 Handle itemHandle;
5476 Handle iconHandle;
5477 DialogPtr theDialog;
5478 char_u len;
5479 char_u PascalTitle[256]; /* place holder for the title */
5480 char_u name[256];
5481 GrafPtr oldPort;
5482 short itemHit;
5483 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005484 short hotKeys[256]; /* map of hotkey -> control ID */
5485 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486 Rect box;
5487 short button;
5488 short lastButton;
5489 short itemType;
5490 short useIcon;
5491 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005492 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005493 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005494 short widestButton = 0;
5495 short dfltButtonEdge = 20; /* gut feeling */
5496 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5497 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5498 short maximumWidth = 400; /* gut feeling */
5499 short maxButtonWidth = 175; /* gut feeling */
5500
5501 short vertical;
5502 short dialogHeight;
5503 short messageLines = 3;
5504 FontInfo textFontInfo;
5505
5506 vgmDlgItm iconItm;
5507 vgmDlgItm messageItm;
5508 vgmDlgItm inputItm;
5509 vgmDlgItm buttonItm;
5510
5511 WindowRef theWindow;
5512
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005513 ModalFilterUPP dialogUPP;
5514
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515 /* Check 'v' flag in 'guioptions': vertical button placement. */
5516 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5517
5518 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005519 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520
5521 /* Get the WindowRef */
5522 theWindow = GetDialogWindow(theDialog);
5523
5524 /* Hide the window.
5525 * 1. to avoid seeing slow drawing
5526 * 2. to prevent a problem seen while moving dialog item
5527 * within a visible window. (non-Carbon MacOS 9)
5528 * Could be avoided by changing the resource.
5529 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005530 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531
5532 /* Change the graphical port to the dialog,
5533 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005534 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005535 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005536
5537 /* Get the info about the default text,
5538 * used to calculate the height of the message
5539 * and of the text field */
5540 GetFontInfo(&textFontInfo);
5541
5542 /* Set the dialog title */
5543 if (title != NULL)
5544 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005545 (void) C2PascalString(title, &PascalTitle);
5546 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005547 }
5548
5549 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005550 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005551 buttonChar = buttons;
5552 button = 0;
5553
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005554 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005555 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005556
Bram Moolenaar071d4272004-06-13 20:20:40 +00005557 for (;*buttonChar != 0;)
5558 {
5559 /* Get the name of the button */
5560 button++;
5561 len = 0;
5562 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5563 {
5564 if (*buttonChar != DLG_HOTKEY_CHAR)
5565 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005566 else
5567 {
5568 aHotKey = (char_u)*(buttonChar+1);
5569 if (aHotKey >= 'A' && aHotKey <= 'Z')
5570 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5571 hotKeys[aHotKey] = button;
5572#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5573 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5574#endif
5575 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005577
Bram Moolenaar071d4272004-06-13 20:20:40 +00005578 if (*buttonChar != 0)
5579 buttonChar++;
5580 name[0] = len;
5581
5582 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005583 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005584
5585 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005586 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587
5588 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005589 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005590 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005591 /* TODO: Should be based on the message width */
5592 if (width > maxButtonWidth)
5593 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005594 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595
5596 totalButtonWidth += width;
5597
5598 if (width > widestButton)
5599 widestButton = width;
5600 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005601 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005602 lastButton = button;
5603
5604 /* Add the icon to the Dialog Box. */
5605 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005606 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 switch (type)
5608 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005609 case VIM_GENERIC:
5610 case VIM_INFO:
5611 case VIM_QUESTION: useIcon = kNoteIcon; break;
5612 case VIM_WARNING: useIcon = kCautionIcon; break;
5613 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005614 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005615 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005616 AppendDITL(theDialog, iconDITL, overlayDITL);
5617 ReleaseResource(iconDITL);
5618 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005620 iconHandle = GetIcon(useIcon);
5621 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005622
5623 /* Add the message to the Dialog box. */
5624 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005625 messageDITL = GetResource('DITL', 132);
5626 AppendDITL(theDialog, messageDITL, overlayDITL);
5627 ReleaseResource(messageDITL);
5628 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5629 (void) C2PascalString(message, &name);
5630 SetDialogItemText(itemHandle, name);
5631 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005632
5633 /* Add the input box if needed */
5634 if (textfield != NULL)
5635 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005636 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005638 inputDITL = GetResource('DITL', 132);
5639 AppendDITL(theDialog, inputDITL, overlayDITL);
5640 ReleaseResource(inputDITL);
5641 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5642/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5643 (void) C2PascalString(textfield, &name);
5644 SetDialogItemText(itemHandle, name);
5645 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005646
5647 /* Hotkeys don't make sense if there's a text field */
5648 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005649 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005650 else
5651 /* Install hotkey table */
5652 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653
5654 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005655 SetDialogDefaultItem(theDialog, dfltbutton);
5656 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657
5658 /* Reposition element */
5659
5660 /* Check if we need to force vertical */
5661 if (totalButtonWidth > maximumWidth)
5662 vertical = TRUE;
5663
5664 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005665 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666 iconItm.box.right = box.right;
5667 iconItm.box.bottom = box.bottom;
5668
5669 /* Place Message */
5670 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005671 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5672 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005673
5674 /* Place Input */
5675 if (textfield != NULL)
5676 {
5677 inputItm.box.left = messageItm.box.left;
5678 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005679 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5680 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005681 /* Convert the static text into a text edit.
5682 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005683 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5684 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5686 }
5687
5688 /* Place Button */
5689 if (textfield != NULL)
5690 {
5691 buttonItm.box.left = inputItm.box.left;
5692 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5693 }
5694 else
5695 {
5696 buttonItm.box.left = messageItm.box.left;
5697 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5698 }
5699
5700 for (button=1; button <= lastButton; button++)
5701 {
5702
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005703 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005704 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705 if (vertical)
5706 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 macSizeDialogItem(theDialog, button, widestButton, 0);
5708 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709 }
5710 /* Calculate position of next button */
5711 if (vertical)
5712 buttonItm.box.top = box.bottom + dfltElementSpacing;
5713 else
5714 buttonItm.box.left = box.right + dfltElementSpacing;
5715 }
5716
5717 /* Resize the dialog box */
5718 dialogHeight = box.bottom + dfltElementSpacing;
5719 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5720
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005722 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005723 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724
5725 /* Display it */
5726 ShowWindow(theWindow);
5727/* BringToFront(theWindow); */
5728 SelectWindow(theWindow);
5729
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005730/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005731#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005732 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005733 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005734#endif
5735
Bram Moolenaard68071d2006-05-02 22:08:30 +00005736#ifdef USE_CARBONKEYHANDLER
5737 /* Avoid that we use key events for the main window. */
5738 dialog_busy = TRUE;
5739#endif
5740
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005741 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5742 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5743
Bram Moolenaar071d4272004-06-13 20:20:40 +00005744 /* Hang until one of the button is hit */
5745 do
5746 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005747 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005748 } while ((itemHit < 1) || (itemHit > lastButton));
5749
Bram Moolenaard68071d2006-05-02 22:08:30 +00005750#ifdef USE_CARBONKEYHANDLER
5751 dialog_busy = FALSE;
5752#endif
5753
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754 /* Copy back the text entered by the user into the param */
5755 if (textfield != NULL)
5756 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005757 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5758 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759#if IOSIZE < 256
5760 /* Truncate the name to IOSIZE if needed */
5761 if (name[0] > IOSIZE)
5762 name[0] = IOSIZE - 1;
5763#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005764 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005765 }
5766
5767 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005768 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005769
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005770 /* Free the modal filterProc */
5771 DisposeRoutineDescriptor(dialogUPP);
5772
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005773 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005774 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775
5776 return itemHit;
5777/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005778 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779 * SetDialogTimeout(): Auto click a button after timeout
5780 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5781 * MoveDialogItem(): Probably better than SetDialogItem
5782 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005783 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005784 */
5785}
5786#endif /* FEAT_DIALOG_GUI */
5787
5788/*
5789 * Display the saved error message(s).
5790 */
5791#ifdef USE_MCH_ERRMSG
5792 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005793display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794{
5795 char *p;
5796 char_u pError[256];
5797
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005798 if (error_ga.ga_data == NULL)
5799 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005800
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005801 /* avoid putting up a message box with blanks only */
5802 for (p = (char *)error_ga.ga_data; *p; ++p)
5803 if (!isspace(*p))
5804 {
5805 if (STRLEN(p) > 255)
5806 pError[0] = 255;
5807 else
5808 pError[0] = STRLEN(p);
5809
5810 STRNCPY(&pError[1], p, pError[0]);
5811 ParamText(pError, nil, nil, nil);
5812 Alert(128, nil);
5813 break;
5814 /* TODO: handled message longer than 256 chars
5815 * use auto-sizeable alert
5816 * or dialog with scrollbars (TextEdit zone)
5817 */
5818 }
5819 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005820}
5821#endif
5822
5823/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005824 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005826 void
5827gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005828{
5829 Point where;
5830
5831 GetMouse(&where);
5832
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005833 *x = where.h;
5834 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835}
5836
5837 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005838gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839{
5840 /* TODO */
5841#if 0
5842 /* From FAQ 3-11 */
5843
5844 CursorDevicePtr myMouse;
5845 Point where;
5846
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005847 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5848 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849 {
5850 /* New way */
5851
5852 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005853 * Get first device with one button.
5854 * This will probably be the standard mouse
5855 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 *
5857 */
5858
5859 myMouse = nil;
5860
5861 do
5862 {
5863 /* Get the next cursor device */
5864 CursorDeviceNextDevice(&myMouse);
5865 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005866 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005867
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005868 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005869 }
5870 else
5871 {
5872 /* Old way */
5873 where.h = x;
5874 where.v = y;
5875
5876 *(Point *)RawMouse = where;
5877 *(Point *)MTemp = where;
5878 *(Ptr) CrsrNew = 0xFFFF;
5879 }
5880#endif
5881}
5882
5883 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005884gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886/*
5887 * Clone PopUp to use menu
5888 * Create a object descriptor for the current selection
5889 * Call the procedure
5890 */
5891
5892 MenuHandle CntxMenu;
5893 Point where;
5894 OSStatus status;
5895 UInt32 CntxType;
5896 SInt16 CntxMenuID;
5897 UInt16 CntxMenuItem;
5898 Str255 HelpName = "";
5899 GrafPtr savePort;
5900
5901 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005902 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005904 GetMouse(&where);
5905 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005906 CntxMenu = menu->submenu_handle;
5907
5908 /* TODO: Get the text selection from Vim */
5909
5910 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005911 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005912 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913
5914 if (status == noErr)
5915 {
5916 if (CntxType == kCMMenuItemSelected)
5917 {
5918 /* Handle the menu CntxMenuID, CntxMenuItem */
5919 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005920 /* But what about the current menu, is the menu changed by
5921 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005922 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923 }
5924 else if (CntxMenuID == kCMShowHelpSelected)
5925 {
5926 /* Should come up with the help */
5927 }
5928 }
5929
5930 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005931 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932}
5933
5934#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5935/* TODO: Is it need for MACOS_X? (Dany) */
5936 void
5937mch_post_buffer_write(buf_T *buf)
5938{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005939 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5940 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941}
5942#endif
5943
5944#ifdef FEAT_TITLE
5945/*
5946 * Set the window title and icon.
5947 * (The icon is not taken care of).
5948 */
5949 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005950gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951{
5952 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5953 * that 256. Even better get it to fit nicely in the titlebar.
5954 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005955#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005956 CFStringRef windowTitle;
5957 size_t windowTitleLen;
5958#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005959 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005960#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005961
5962 if (title == NULL) /* nothing to do */
5963 return;
5964
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005965#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005966 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005967 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005968
5969 if (windowTitle)
5970 {
5971 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5972 CFRelease(windowTitle);
5973 }
5974#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005975 pascalTitle = C2Pascal_save(title);
5976 if (pascalTitle != NULL)
5977 {
5978 SetWTitle(gui.VimWindow, pascalTitle);
5979 vim_free(pascalTitle);
5980 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005981#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982}
5983#endif
5984
5985/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005986 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987 */
5988
5989 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005990C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991{
5992 char_u *PascalPtr = (char_u *) PascalString;
5993 int len;
5994 int i;
5995
5996 PascalPtr[0] = 0;
5997 if (CString == NULL)
5998 return 0;
5999
6000 len = STRLEN(CString);
6001 if (len > 255)
6002 len = 255;
6003
6004 for (i = 0; i < len; i++)
6005 PascalPtr[i+1] = CString[i];
6006
6007 PascalPtr[0] = len;
6008
6009 return 0;
6010}
6011
6012 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006013GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014{
6015 /* From FAQ 8-12 */
6016 Str255 filePascal;
6017 CInfoPBRec myCPB;
6018 OSErr err;
6019
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006020 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006021
6022 myCPB.dirInfo.ioNamePtr = filePascal;
6023 myCPB.dirInfo.ioVRefNum = 0;
6024 myCPB.dirInfo.ioFDirIndex = 0;
6025 myCPB.dirInfo.ioDrDirID = 0;
6026
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006027 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006028
6029 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006030 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031
6032 /* TODO: Use an error code mechanism */
6033 return 0;
6034}
6035
6036/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006037 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038 */
6039
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006040char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041{
6042 /*
6043 * TODO: Add protection for 256 char max.
6044 */
6045
6046 CInfoPBRec theCPB;
6047 char_u fname[256];
6048 char_u *filenamePtr = fname;
6049 OSErr error;
6050 int folder = 1;
6051#ifdef USE_UNIXFILENAME
6052 SInt16 dfltVol_vRefNum;
6053 SInt32 dfltVol_dirID;
6054 FSRef refFile;
6055 OSStatus status;
6056 UInt32 pathSize = 256;
6057 char_u pathname[256];
6058 char_u *path = pathname;
6059#else
6060 Str255 directoryName;
6061 char_u temporary[255];
6062 char_u *temporaryPtr = temporary;
6063#endif
6064
6065#ifdef USE_UNIXFILENAME
6066 /* Get the default volume */
6067 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006068 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069
6070 if (error)
6071 return NULL;
6072#endif
6073
6074 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006075 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006076
6077 /* Get the info about the file specified in FSSpec */
6078 theCPB.dirInfo.ioFDirIndex = 0;
6079 theCPB.dirInfo.ioNamePtr = file.name;
6080 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006081 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006082 theCPB.dirInfo.ioDrDirID = file.parID;
6083
6084 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6085 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006086 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006087
6088 /* If we are called for a new file we expect fnfErr */
6089 if ((error) && (error != fnfErr))
6090 return NULL;
6091
6092 /* Check if it's a file or folder */
6093 /* default to file if file don't exist */
6094 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6095 folder = 0; /* It's not a folder */
6096 else
6097 folder = 1;
6098
6099#ifdef USE_UNIXFILENAME
6100 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006101 * The functions used here are available in Carbon, but do nothing on
6102 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 */
6104 if (error == fnfErr)
6105 {
6106 /* If the file to be saved does not already exist, it isn't possible
6107 to convert its FSSpec into an FSRef. But we can construct an
6108 FSSpec for the file's parent folder (since we have its volume and
6109 directory IDs), and since that folder does exist, we can convert
6110 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6111 and, finally, append the filename. */
6112 FSSpec dirSpec;
6113 FSRef dirRef;
6114 Str255 emptyFilename = "\p";
6115 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6116 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6117 if (error)
6118 return NULL;
6119
6120 error = FSpMakeFSRef(&dirSpec, &dirRef);
6121 if (error)
6122 return NULL;
6123
6124 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6125 if (status)
6126 return NULL;
6127
6128 STRCAT(path, "/");
6129 STRCAT(path, filenamePtr);
6130 }
6131 else
6132 {
6133 /* If the file to be saved already exists, we can get its full path
6134 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006135 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006136 if (error)
6137 return NULL;
6138
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006139 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 if (status)
6141 return NULL;
6142 }
6143
6144 /* Add a slash at the end if needed */
6145 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006146 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006147
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006148 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006149#else
6150 /* TODO: Get rid of all USE_UNIXFILENAME below */
6151 /* Set ioNamePtr, it's the same area which is always reused. */
6152 theCPB.dirInfo.ioNamePtr = directoryName;
6153
6154 /* Trick for first entry, set ioDrParID to the first value
6155 * we want for ioDrDirID*/
6156 theCPB.dirInfo.ioDrParID = file.parID;
6157 theCPB.dirInfo.ioDrDirID = file.parID;
6158
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006159 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160 do
6161 {
6162 theCPB.dirInfo.ioFDirIndex = -1;
6163 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6164 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006165 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006166 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6167
6168 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6169 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006170 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171
6172 if (error)
6173 return NULL;
6174
6175 /* Put the new directoryName in front of the current fname */
6176 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006177 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006178 STRCAT(filenamePtr, ":");
6179 STRCAT(filenamePtr, temporaryPtr);
6180 }
6181#if 1 /* def USE_UNIXFILENAME */
6182 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6183 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6184#else
6185 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6186#endif
6187
6188 /* Get the information about the volume on which the file reside */
6189 theCPB.dirInfo.ioFDirIndex = -1;
6190 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6191 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006192 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6194
6195 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6196 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006197 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198
6199 if (error)
6200 return NULL;
6201
6202 /* For MacOS Classic always add the volume name */
6203 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006204 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006205#ifdef USE_UNIXFILENAME
6206 if (file.vRefNum != dfltVol_vRefNum)
6207#endif
6208 {
6209 /* Add the volume name */
6210 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006211 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006212 STRCAT(filenamePtr, ":");
6213 STRCAT(filenamePtr, temporaryPtr);
6214
6215#ifdef USE_UNIXFILENAME
6216 STRCPY(temporaryPtr, filenamePtr);
6217 filenamePtr[0] = 0; /* NULL terminate the string */
6218 STRCAT(filenamePtr, "Volumes:");
6219 STRCAT(filenamePtr, temporaryPtr);
6220#endif
6221 }
6222
6223 /* Append final path separator if it's a folder */
6224 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006225 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226
6227 /* As we use Unix File Name for MacOS X convert it */
6228#ifdef USE_UNIXFILENAME
6229 /* Need to insert leading / */
6230 /* TODO: get the above code to use directly the / */
6231 STRCPY(&temporaryPtr[1], filenamePtr);
6232 temporaryPtr[0] = '/';
6233 STRCPY(filenamePtr, temporaryPtr);
6234 {
6235 char *p;
6236 for (p = fname; *p; p++)
6237 if (*p == ':')
6238 *p = '/';
6239 }
6240#endif
6241
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006242 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006243#endif
6244}
6245
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006246#if (defined(FEAT_MBYTE) && defined(USE_CARBONKEYHANDLER)) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006247/*
6248 * Input Method Control functions.
6249 */
6250
6251/*
6252 * Notify cursor position to IM.
6253 */
6254 void
6255im_set_position(int row, int col)
6256{
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006257# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006259 im_start_row = row;
6260 im_start_col = col;
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006261# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006262}
6263
6264static ScriptLanguageRecord gTSLWindow;
6265static ScriptLanguageRecord gTSLInsert;
6266static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6267
6268static Component gTSCWindow;
6269static Component gTSCInsert;
6270static Component gTSCDefault;
6271
6272static int im_initialized = 0;
6273
6274 static void
6275im_on_window_switch(int active)
6276{
6277 ScriptLanguageRecord *slptr = NULL;
6278 OSStatus err;
6279
6280 if (! gui.in_use)
6281 return;
6282
6283 if (im_initialized == 0)
6284 {
6285 im_initialized = 1;
6286
6287 /* save default TSM component (should be U.S.) to default */
6288 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6289 kKeyboardInputMethodClass);
6290 }
6291
6292 if (active == TRUE)
6293 {
6294 im_is_active = TRUE;
6295 ActivateTSMDocument(gTSMDocument);
6296 slptr = &gTSLWindow;
6297
6298 if (slptr)
6299 {
6300 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6301 kKeyboardInputMethodClass);
6302 if (err == noErr)
6303 err = SetTextServiceLanguage(slptr);
6304
6305 if (err == noErr)
6306 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6307 }
6308 }
6309 else
6310 {
6311 err = GetTextServiceLanguage(&gTSLWindow);
6312 if (err == noErr)
6313 slptr = &gTSLWindow;
6314
6315 if (slptr)
6316 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6317 kKeyboardInputMethodClass);
6318
6319 im_is_active = FALSE;
6320 DeactivateTSMDocument(gTSMDocument);
6321 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006322}
6323
6324/*
6325 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6326 */
6327 void
6328im_set_active(int active)
6329{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006330 ScriptLanguageRecord *slptr = NULL;
6331 OSStatus err;
6332
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006333 if (!gui.in_use)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006334 return;
6335
6336 if (im_initialized == 0)
6337 {
6338 im_initialized = 1;
6339
6340 /* save default TSM component (should be U.S.) to default */
6341 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6342 kKeyboardInputMethodClass);
6343 }
6344
6345 if (active == TRUE)
6346 {
6347 im_is_active = TRUE;
6348 ActivateTSMDocument(gTSMDocument);
6349 slptr = &gTSLInsert;
6350
6351 if (slptr)
6352 {
6353 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6354 kKeyboardInputMethodClass);
6355 if (err == noErr)
6356 err = SetTextServiceLanguage(slptr);
6357
6358 if (err == noErr)
6359 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6360 }
6361 }
6362 else
6363 {
6364 err = GetTextServiceLanguage(&gTSLInsert);
6365 if (err == noErr)
6366 slptr = &gTSLInsert;
6367
6368 if (slptr)
6369 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6370 kKeyboardInputMethodClass);
6371
6372 /* restore to default when switch to normal mode, so than we could
6373 * enter commands easier */
6374 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6375 kKeyboardInputMethodClass);
6376 SetTextServiceLanguage(&gTSLDefault);
6377
6378 im_is_active = FALSE;
6379 DeactivateTSMDocument(gTSMDocument);
6380 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006381}
6382
6383/*
6384 * Get IM status. When IM is on, return not 0. Else return 0.
6385 */
6386 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006387im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006388{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006389 if (! gui.in_use)
6390 return 0;
6391
6392 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006393}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006394
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006395#endif /* defined(FEAT_MBYTE) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006396
6397
6398
6399
6400#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6401// drawer implementation
6402static MenuRef contextMenu = NULL;
6403enum
6404{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006405 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006406};
6407
6408// the caller has to CFRelease() the returned string
6409 static CFStringRef
6410getTabLabel(tabpage_T *page)
6411{
6412 get_tabline_label(page, FALSE);
6413#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006414 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006415#else
6416 // TODO: check internal encoding?
6417 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6418 kCFStringEncodingMacRoman);
6419#endif
6420}
6421
6422
6423#define DRAWER_SIZE 150
6424#define DRAWER_INSET 16
6425
6426static ControlRef dataBrowser = NULL;
6427
6428// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006429// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006430// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006431// for a very short time. to prevent inconsistent state, we store the labels
6432// of the tabs, not pointers to the tabs (which are invalid for a short time).
6433static CFStringRef *tabLabels = NULL;
6434static int tabLabelsSize = 0;
6435
6436enum
6437{
6438 kTabsColumn = 'Tabs'
6439};
6440
6441 static int
6442getTabCount(void)
6443{
6444 tabpage_T *tp;
6445 int numTabs = 0;
6446
Bram Moolenaar29323592016-07-24 22:04:11 +02006447 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006448 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006449 return numTabs;
6450}
6451
6452// data browser item display callback
6453 static OSStatus
6454dbItemDataCallback(ControlRef browser,
6455 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006456 DataBrowserPropertyID property /* column id */,
6457 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006458 Boolean changeValue)
6459{
6460 OSStatus status = noErr;
6461
6462 // assert(property == kTabsColumn); // why is this violated??
6463
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006464 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006465 // In our case, it's always false.
6466 // (that is: if (changeValue) updateInternalData(); else return
6467 // internalData();
6468 if (!changeValue)
6469 {
6470 CFStringRef str;
6471
6472 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6473 str = tabLabels[itemID - 1];
6474 status = SetDataBrowserItemDataText(itemData, str);
6475 }
6476 else
6477 status = errDataBrowserPropertyNotSupported;
6478
6479 return status;
6480}
6481
6482// data browser action callback
6483 static void
6484dbItemNotificationCallback(ControlRef browser,
6485 DataBrowserItemID item,
6486 DataBrowserItemNotification message)
6487{
6488 switch (message)
6489 {
6490 case kDataBrowserItemSelected:
6491 send_tabline_event(item);
6492 break;
6493 }
6494}
6495
6496// callbacks needed for contextual menu:
6497 static void
6498dbGetContextualMenuCallback(ControlRef browser,
6499 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006500 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006501 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006502 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006503{
6504 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6505 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6506 *helpItemString = NULL;
6507
6508 *menu = contextMenu;
6509}
6510
6511 static void
6512dbSelectContextualMenuCallback(ControlRef browser,
6513 MenuRef menu,
6514 UInt32 selectionType,
6515 SInt16 menuID,
6516 MenuItemIndex menuItem)
6517{
6518 if (selectionType == kCMMenuItemSelected)
6519 {
6520 MenuCommand command;
6521 GetMenuItemCommandID(menu, menuItem, &command);
6522
6523 // get tab that was selected when the context menu appeared
6524 // (there is always one tab selected). TODO: check if the context menu
6525 // isn't opened on an item but on empty space (has to be possible some
6526 // way, the finder does it too ;-) )
6527 Handle items = NewHandle(0);
6528 if (items != NULL)
6529 {
6530 int numItems;
6531
6532 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6533 kDataBrowserItemIsSelected, items);
6534 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6535 if (numItems > 0)
6536 {
6537 int idx;
6538 DataBrowserItemID *itemsPtr;
6539
6540 HLock(items);
6541 itemsPtr = (DataBrowserItemID *)*items;
6542 idx = itemsPtr[0];
6543 HUnlock(items);
6544 send_tabline_menu_event(idx, command);
6545 }
6546 DisposeHandle(items);
6547 }
6548 }
6549}
6550
6551// focus callback of the data browser to always leave focus in vim
6552 static OSStatus
6553dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6554{
6555 assert(GetEventClass(event) == kEventClassControl
6556 && GetEventKind(event) == kEventControlSetFocusPart);
6557
6558 return paramErr;
6559}
6560
6561
6562// drawer callback to resize data browser to drawer size
6563 static OSStatus
6564drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6565{
6566 switch (GetEventKind(event))
6567 {
6568 case kEventWindowBoundsChanged: // move or resize
6569 {
6570 UInt32 attribs;
6571 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6572 NULL, sizeof(attribs), NULL, &attribs);
6573 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6574 {
6575 Rect r;
6576 GetWindowBounds(drawer, kWindowContentRgn, &r);
6577 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6578 SetControlBounds(dataBrowser, &r);
6579 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6580 kTabsColumn, r.right);
6581 }
6582 }
6583 break;
6584 }
6585
6586 return eventNotHandledErr;
6587}
6588
6589// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6590// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6591// blue highlights in the list view on these systems, though. Oh well.)
6592
6593
6594#import <mach-o/dyld.h>
6595
6596enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6597
6598 static OSStatus
6599myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6600 OptionBits inAttributesToSet,
6601 OptionBits inAttributesToClear)
6602{
6603 long osVersion;
6604 char *symbolName;
6605 NSSymbol symbol = NULL;
6606 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6607 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6608
6609 Gestalt(gestaltSystemVersion, &osVersion);
6610 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6611 return noErr;
6612
6613 // C name mangling...
6614 symbolName = "_DataBrowserChangeAttributes";
6615 if (!NSIsSymbolNameDefined(symbolName)
6616 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6617 return noErr;
6618
6619 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6620 if (dataBrowserChangeAttributes == NULL)
6621 return noErr; // well...
6622 return dataBrowserChangeAttributes(inDataBrowser,
6623 inAttributesToSet, inAttributesToClear);
6624}
6625
6626 static void
6627initialise_tabline(void)
6628{
6629 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6630 DataBrowserCallbacks dbCallbacks;
6631 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6632 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6633 DataBrowserListViewColumnDesc colDesc;
6634
6635 // drawers have to have compositing enabled
6636 CreateNewWindow(kDrawerWindowClass,
6637 kWindowStandardHandlerAttribute
6638 | kWindowCompositingAttribute
6639 | kWindowResizableAttribute
6640 | kWindowLiveResizeAttribute,
6641 &drawerRect, &drawer);
6642
6643 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6644 SetDrawerParent(drawer, gui.VimWindow);
6645 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6646
6647
6648 // create list view embedded in drawer
6649 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6650 &dataBrowser);
6651
6652 dbCallbacks.version = kDataBrowserLatestCallbacks;
6653 InitDataBrowserCallbacks(&dbCallbacks);
6654 dbCallbacks.u.v1.itemDataCallback =
6655 NewDataBrowserItemDataUPP(dbItemDataCallback);
6656 dbCallbacks.u.v1.itemNotificationCallback =
6657 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6658 dbCallbacks.u.v1.getContextualMenuCallback =
6659 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6660 dbCallbacks.u.v1.selectContextualMenuCallback =
6661 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6662
6663 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6664
6665 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6666 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6667 SetDataBrowserSelectionFlags(dataBrowser,
6668 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6669 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6670 kDataBrowserTableViewFillHilite);
6671 Boolean b = false;
6672 SetControlData(dataBrowser, kControlEntireControl,
6673 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6674
6675 // enable blue background in data browser (this is only in 10.4 and vim
6676 // has to support older osx versions as well, so we have to load this
6677 // function dynamically)
6678 myDataBrowserChangeAttributes(dataBrowser,
6679 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6680
6681 // install callback that keeps focus in vim and away from the data browser
6682 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6683 NULL, NULL);
6684
6685 // install callback that keeps data browser at the size of the drawer
6686 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6687 NULL, NULL);
6688
6689 // add "tabs" column to data browser
6690 colDesc.propertyDesc.propertyID = kTabsColumn;
6691 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6692
6693 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6694 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6695
6696 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6697 colDesc.headerBtnDesc.minimumWidth = 100;
6698 colDesc.headerBtnDesc.maximumWidth = 150;
6699 colDesc.headerBtnDesc.titleOffset = 0;
6700 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6701 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6702 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6703 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6704
6705 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6706
6707 // create tabline popup menu required by vim docs (see :he tabline-menu)
6708 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar7098ee52015-06-09 19:14:24 +02006709 if (first_tabpage->tp_next != NULL)
6710 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006711 TABLINE_MENU_CLOSE, NULL);
6712 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6713 TABLINE_MENU_NEW, NULL);
6714 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6715 TABLINE_MENU_OPEN, NULL);
6716}
6717
6718
6719/*
6720 * Show or hide the tabline.
6721 */
6722 void
6723gui_mch_show_tabline(int showit)
6724{
6725 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006726 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006727 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006728 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006729}
6730
6731/*
6732 * Return TRUE when tabline is displayed.
6733 */
6734 int
6735gui_mch_showing_tabline(void)
6736{
6737 WindowDrawerState state = GetDrawerState(drawer);
6738
6739 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6740}
6741
6742/*
6743 * Update the labels of the tabline.
6744 */
6745 void
6746gui_mch_update_tabline(void)
6747{
6748 tabpage_T *tp;
6749 int numTabs = getTabCount();
6750 int nr = 1;
6751 int curtabidx = 1;
6752
6753 // adjust data browser
6754 if (tabLabels != NULL)
6755 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006756 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006757
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006758 for (i = 0; i < tabLabelsSize; ++i)
6759 CFRelease(tabLabels[i]);
6760 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006761 }
6762 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6763 tabLabelsSize = numTabs;
6764
6765 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6766 {
6767 if (tp == curtab)
6768 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006769 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006770 }
6771
6772 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6773 kDataBrowserItemNoProperty);
6774 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6775 // can pass NULL for the id array
6776 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6777 kDataBrowserItemNoProperty);
6778
6779 DataBrowserItemID item = curtabidx;
6780 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6781}
6782
6783/*
6784 * Set the current tab to "nr". First tab is 1.
6785 */
6786 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006787gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006788{
6789 DataBrowserItemID item = nr;
6790 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6791
6792 // TODO: call something like this?: (or restore scroll position, or...)
6793 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6794 kDataBrowserRevealOnly);
6795}
6796
6797#endif // FEAT_GUI_TABLINE