blob: d2279ece5a42f39365e7f5ee94b4838df56a88cb [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
1010/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1011 itor the selection range. If lineNum is zero or greater, scroll the text
1012 to the specified line. If lineNum is less than zero, use the values in
1013 startRange and endRange to select the specified characters. Scroll
1014 the text to display the selection. If lineNum, startRange, and
1015 endRange are all negative, there is no selection range specified.
1016 */
1017
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001018 pascal OSErr
1019HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020{
1021 /*
1022 * TODO: Clean up the code with convert the AppleEvent into
1023 * a ":args"
1024 */
1025 OSErr error = noErr;
1026// OSErr firstError = noErr;
1027// short numErrors = 0;
1028 AEDesc theList;
1029 DescType typeCode;
1030 long numFiles;
1031 // long fileCount;
1032 char_u **fnames;
1033// char_u fname[256];
1034 Size actualSize;
1035 SelectionRange thePosition;
1036 short gotPosition = false;
1037 long lnum;
1038
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 /* the direct object parameter is the list of aliases to files (one or more) */
1040 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1041 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001042 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043
1044
1045 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1046 if (error == noErr)
1047 gotPosition = true;
1048 if (error == errAEDescNotFound)
1049 error = noErr;
1050 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001051 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053/*
1054 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1055
1056 if (^error) then
1057 {
1058 if (thePosition.lineNum >= 0)
1059 {
1060 // Goto this line
1061 }
1062 else
1063 {
1064 // Set the range char wise
1065 }
1066 }
1067 */
1068
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1071
1072 if (error)
1073 {
1074 /* TODO: empty fnames[] first */
1075 vim_free(fnames);
1076 return (error);
1077 }
1078
1079 if (starting > 0)
1080 {
1081 int i;
1082 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001083 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084
1085 /* these are the initial files dropped on the Vim icon */
1086 for (i = 0 ; i < numFiles; i++)
1087 {
1088 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1089 || (p = vim_strsave(fnames[i])) == NULL)
1090 mch_exit(2);
1091 else
1092 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001093 if (fnum == -1)
1094 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1095 }
1096
1097 /* If the file name was already in the buffer list we need to switch
1098 * to it. */
1099 if (curbuf->b_fnum != fnum)
1100 {
1101 char_u cmd[30];
1102
1103 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1104 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001106
1107 /* Change directory to the location of the first file. */
Bram Moolenaarb7407d32018-02-03 17:36:27 +01001108 if (GARGCOUNT > 0
1109 && vim_chdirfile(alist_name(&GARGLIST[0]), "drop") == OK)
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001110 shorten_fnames(TRUE);
1111
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 goto finished;
1113 }
1114
1115 /* Handle the drop, :edit to get to the file */
1116 handle_drop(numFiles, fnames, FALSE);
1117
1118 /* TODO: Handle the goto/select line more cleanly */
1119 if ((numFiles == 1) & (gotPosition))
1120 {
1121 if (thePosition.lineNum >= 0)
1122 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001123 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 /* oap->motion_type = MLINE;
1125 setpcmark();*/
1126 if (lnum < 1L)
1127 lnum = 1L;
1128 else if (lnum > curbuf->b_ml.ml_line_count)
1129 lnum = curbuf->b_ml.ml_line_count;
1130 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001131 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 /* beginline(BL_SOL | BL_FIX);*/
1133 }
1134 else
1135 goto_byte(thePosition.startRange + 1);
1136 }
1137
1138 /* Update the screen display */
1139 update_screen(NOT_VALID);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001140
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001141 /* Select the text if possible */
1142 if (gotPosition)
1143 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001144 VIsual_active = TRUE;
1145 VIsual_select = FALSE;
1146 VIsual = curwin->w_cursor;
1147 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001148 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001149 VIsual_mode = 'v';
1150 goto_byte(thePosition.endRange);
1151 }
1152 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001153 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001154 VIsual_mode = 'V';
1155 VIsual.col = 0;
1156 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001157 }
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001158
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 setcursor();
1160 out_flush();
1161
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001162 /* Fake mouse event to wake from stall */
1163 PostEvent(mouseUp, 0);
1164
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001165finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001166 AEDisposeDesc(&theList); /* dispose what we allocated */
1167
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001168 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001169 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170}
1171
1172/*
1173 *
1174 */
1175
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001176 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001177Handle_aevt_oapp_AE(
1178 const AppleEvent *theAEvent,
1179 AppleEvent *theReply,
1180 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181{
1182 OSErr error = noErr;
1183
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001184 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001185 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186}
1187
1188/*
1189 *
1190 */
1191
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001192 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001193Handle_aevt_quit_AE(
1194 const AppleEvent *theAEvent,
1195 AppleEvent *theReply,
1196 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197{
1198 OSErr error = noErr;
1199
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001200 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001202 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203
1204 /* Need to fake a :confirm qa */
1205 do_cmdline_cmd((char_u *)"confirm qa");
1206
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001207 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208}
1209
1210/*
1211 *
1212 */
1213
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001214 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001215Handle_aevt_pdoc_AE(
1216 const AppleEvent *theAEvent,
1217 AppleEvent *theReply,
1218 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219{
1220 OSErr error = noErr;
1221
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001222 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001224 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225}
1226
1227/*
1228 * Handling of unknown AppleEvent
1229 *
1230 * (Just get rid of all the parms)
1231 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001232 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001233Handle_unknown_AE(
1234 const AppleEvent *theAEvent,
1235 AppleEvent *theReply,
1236 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237{
1238 OSErr error = noErr;
1239
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001240 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001242 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243}
1244
1245
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246/*
1247 * Install the various AppleEvent Handlers
1248 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001249 OSErr
1250InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251{
1252 OSErr error;
1253
1254 /* install open application handler */
1255 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001256 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 if (error)
1258 {
1259 return error;
1260 }
1261
1262 /* install quit application handler */
1263 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001264 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 if (error)
1266 {
1267 return error;
1268 }
1269
1270 /* install open document handler */
1271 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001272 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273 if (error)
1274 {
1275 return error;
1276 }
1277
1278 /* install print document handler */
1279 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001280 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281
1282/* Install Core Suite */
1283/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001284 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285
1286 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001287 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288
1289 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001290 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291
1292 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001293 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294
1295 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001296 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297
1298 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001299 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300
1301 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001302 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303
1304 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001305 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306
1307 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001308 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309
1310 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001311 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312
1313 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001314 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315
1316 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001317 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318
1319 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001320 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321*/
1322
1323#ifdef FEAT_CW_EDITOR
1324 /*
1325 * Bind codewarrior support handlers
1326 */
1327 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001328 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329 if (error)
1330 {
1331 return error;
1332 }
1333 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001334 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001335 if (error)
1336 {
1337 return error;
1338 }
1339 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001340 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 if (error)
1342 {
1343 return error;
1344 }
1345#endif
1346
1347 return error;
1348
1349}
1350#endif /* USE_AEVENT */
1351
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001352
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001353/*
1354 * Callback function, installed by InstallFontPanelHandler(), below,
1355 * to handle Font Panel events.
1356 */
1357 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001358FontPanelHandler(
1359 EventHandlerCallRef inHandlerCallRef,
1360 EventRef inEvent,
1361 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001362{
1363 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1364 {
1365 gFontPanelInfo.isPanelVisible = false;
1366 return noErr;
1367 }
1368
1369 if (GetEventKind(inEvent) == kEventFontSelection)
1370 {
1371 OSStatus status;
1372 FMFontFamily newFamily;
1373 FMFontSize newSize;
1374 FMFontStyle newStyle;
1375
1376 /* Retrieve the font family ID number. */
1377 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1378 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1379 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1380 &newFamily);
1381 if (status == noErr)
1382 gFontPanelInfo.family = newFamily;
1383
1384 /* Retrieve the font size. */
1385 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1386 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1387 if (status == noErr)
1388 gFontPanelInfo.size = newSize;
1389
1390 /* Retrieve the font style (bold, etc.). Currently unused. */
1391 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1392 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1393 if (status == noErr)
1394 gFontPanelInfo.style = newStyle;
1395 }
1396 return noErr;
1397}
1398
1399
1400 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001401InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001402{
1403 EventTypeSpec eventTypes[2];
1404 EventHandlerUPP handlerUPP;
1405 /* EventHandlerRef handlerRef; */
1406
1407 eventTypes[0].eventClass = kEventClassFont;
1408 eventTypes[0].eventKind = kEventFontSelection;
1409 eventTypes[1].eventClass = kEventClassFont;
1410 eventTypes[1].eventKind = kEventFontPanelClosed;
1411
1412 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1413
1414 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1415 /*userData=*/NULL, /*handlerRef=*/NULL);
1416}
1417
1418
1419/*
1420 * Fill the buffer pointed to by outName with the name and size
1421 * of the font currently selected in the Font Panel.
1422 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001424 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001425GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001426{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001427 Str255 buf;
1428 ByteCount fontNameLen = 0;
1429 ATSUFontID fid;
1430 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001431
1432 if (!outName)
1433 return;
1434
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001435 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1436 {
1437 /* Canonicalize localized font names */
1438 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1439 gFontPanelInfo.style, &fid, NULL) != noErr)
1440 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001441
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001442 /* Request font name with Mac encoding (otherwise we could
1443 * get an unwanted utf-16 name) */
1444 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1445 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001446 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001447 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001448
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001449 /* Only encode font size, because style (bold, italic, etc) is
1450 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001451 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001452 gFontPanelInfo.size/*,
1453 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1454 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1455 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1456
1457 if ((fontNameLen + STRLEN(styleString)) < 255)
1458 STRCPY(outName + fontNameLen, styleString);
1459 }
1460 else
1461 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001462 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001463 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001464}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001465
1466
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467/*
1468 * ------------------------------------------------------------
1469 * Unfiled yet
1470 * ------------------------------------------------------------
1471 */
1472
1473/*
1474 * gui_mac_get_menu_item_index
1475 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001476 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001477 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001478 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001479gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480{
1481 short index;
1482 short itemIndex = -1;
1483 vimmenu_T *pBrother;
1484
1485 /* Only menu without parent are the:
1486 * -menu in the menubar
1487 * -popup menu
1488 * -toolbar (guess)
1489 *
1490 * Which are not items anyway.
1491 */
1492 if (pMenu->parent)
1493 {
1494 /* Start from the Oldest Brother */
1495 pBrother = pMenu->parent->children;
1496 index = 1;
1497 while ((pBrother) && (itemIndex == -1))
1498 {
1499 if (pBrother == pMenu)
1500 itemIndex = index;
1501 index++;
1502 pBrother = pBrother->next;
1503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 }
1505 return itemIndex;
1506}
1507
1508 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001509gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510{
1511 short index;
1512 vimmenu_T *pChildMenu;
1513 vimmenu_T *pElder = pMenu->parent;
1514
1515
1516 /* Only menu without parent are the:
1517 * -menu in the menubar
1518 * -popup menu
1519 * -toolbar (guess)
1520 *
1521 * Which are not items anyway.
1522 */
1523
1524 if ((pElder) && (pElder->submenu_id == menuID))
1525 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1527 pMenu = pMenu->next;
1528 }
1529 else
1530 {
1531 for (; pMenu != NULL; pMenu = pMenu->next)
1532 {
1533 if (pMenu->children != NULL)
1534 {
1535 pChildMenu = gui_mac_get_vim_menu
1536 (menuID, itemIndex, pMenu->children);
1537 if (pChildMenu)
1538 {
1539 pMenu = pChildMenu;
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 return pMenu;
1546}
1547
1548/*
1549 * ------------------------------------------------------------
1550 * MacOS Feedback procedures
1551 * ------------------------------------------------------------
1552 */
1553 pascal
1554 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001555gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556{
1557 scrollbar_T *sb;
1558 int value, dragging;
1559 ControlHandle theControlToUse;
1560 int dont_scroll_save = dont_scroll;
1561
1562 theControlToUse = dragged_sb;
1563
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001564 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565
1566 if (sb == NULL)
1567 return;
1568
1569 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001570 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 dragging = (partCode != 0);
1572
1573 /* When "allow_scrollbar" is FALSE still need to remember the new
1574 * position, but don't actually scroll by setting "dont_scroll". */
1575 dont_scroll = !allow_scrollbar;
1576 gui_drag_scrollbar(sb, value, dragging);
1577 dont_scroll = dont_scroll_save;
1578}
1579
1580 pascal
1581 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001582gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583{
1584 /* TODO: have live support */
1585 scrollbar_T *sb, *sb_info;
1586 long data;
1587 long value;
1588 int page;
1589 int dragging = FALSE;
1590 int dont_scroll_save = dont_scroll;
1591
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001592 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 if (sb == NULL)
1595 return;
1596
1597 if (sb->wp != NULL) /* Left or right scrollbar */
1598 {
1599 /*
1600 * Careful: need to get scrollbar info out of first (left) scrollbar
1601 * for window, but keep real scrollbar too because we must pass it to
1602 * gui_drag_scrollbar().
1603 */
1604 sb_info = &sb->wp->w_scrollbars[0];
1605
1606 if (sb_info->size > 5)
1607 page = sb_info->size - 2; /* use two lines of context */
1608 else
1609 page = sb_info->size;
1610 }
1611 else /* Bottom scrollbar */
1612 {
1613 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001614 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 }
1616
1617 switch (partCode)
1618 {
1619 case kControlUpButtonPart: data = -1; break;
1620 case kControlDownButtonPart: data = 1; break;
1621 case kControlPageDownPart: data = page; break;
1622 case kControlPageUpPart: data = -page; break;
1623 default: data = 0; break;
1624 }
1625
1626 value = sb_info->value + data;
1627/* if (value > sb_info->max)
1628 value = sb_info->max;
1629 else if (value < 0)
1630 value = 0;*/
1631
1632 /* When "allow_scrollbar" is FALSE still need to remember the new
1633 * position, but don't actually scroll by setting "dont_scroll". */
1634 dont_scroll = !allow_scrollbar;
1635 gui_drag_scrollbar(sb, value, dragging);
1636 dont_scroll = dont_scroll_save;
1637
1638 out_flush();
1639 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1640
1641/* if (sb_info->wp != NULL)
1642 {
1643 win_T *wp;
1644 int sb_num;
1645
1646 sb_num = 0;
1647 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1648 sb_num++;
1649
1650 if (wp != NULL)
1651 {
1652 current_scrollbar = sb_num;
1653 scrollbar_value = value;
1654 gui_do_scroll();
1655 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1656 }
1657 }*/
1658}
1659
1660/*
1661 * ------------------------------------------------------------
1662 * MacOS Click Handling procedures
1663 * ------------------------------------------------------------
1664 */
1665
1666
1667/*
1668 * Handle a click inside the window, it may happens in the
1669 * scrollbar or the contents.
1670 *
1671 * TODO: Add support for potential TOOLBAR
1672 */
1673 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001674gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675{
1676 Point thePoint;
1677 int_u vimModifiers;
1678 short thePortion;
1679 ControlHandle theControl;
1680 int vimMouseButton;
1681 short dblClick;
1682
1683 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001684 GlobalToLocal(&thePoint);
1685 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001687 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688
1689 if (theControl != NUL)
1690 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001691 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692
1693 if (thePortion != kControlIndicatorPart)
1694 {
1695 dragged_sb = theControl;
1696 TrackControl(theControl, thePoint, gScrollAction);
1697 dragged_sb = NULL;
1698 }
1699 else
1700 {
1701 dragged_sb = theControl;
1702#if 1
1703 TrackControl(theControl, thePoint, gScrollDrag);
1704#else
1705 TrackControl(theControl, thePoint, NULL);
1706#endif
1707 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1708 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001709 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 dragged_sb = NULL;
1711 }
1712 }
1713 else
1714 {
1715 /* We are inside the contents */
1716
1717 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1718 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1719
1720 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1721 vimMouseButton = MOUSE_LEFT;
1722
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001724 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 clickIsPopup = FALSE;
1726
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001727 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1728 {
1729 vimMouseButton = MOUSE_RIGHT;
1730 vimModifiers &= ~MOUSE_CTRL;
1731 clickIsPopup = TRUE;
1732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733
1734 /* Is it a double click ? */
1735 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1736
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001737 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 gui_send_mouse_event(vimMouseButton, thePoint.h,
1739 thePoint.v, dblClick, vimModifiers);
1740
1741 /* Create the rectangle around the cursor to detect
1742 * the mouse dragging
1743 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744#if 0
1745 /* TODO: Do we need to this even for the contextual menu?
1746 * It may be require for popup_setpos, but for popup?
1747 */
1748 if (vimMouseButton == MOUSE_LEFT)
1749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001751 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 FILL_Y(Y_2_ROW(thePoint.v)),
1753 FILL_X(X_2_COL(thePoint.h)+1),
1754 FILL_Y(Y_2_ROW(thePoint.v)+1));
1755
1756 dragRectEnbl = TRUE;
1757 dragRectControl = kCreateRect;
1758 }
1759 }
1760}
1761
1762/*
1763 * Handle the click in the titlebar (to move the window)
1764 */
1765 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001766gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767{
1768 Rect movingLimits;
1769 Rect *movingLimitsPtr = &movingLimits;
1770
1771 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001772 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001773 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774}
1775
1776/*
1777 * Handle the click in the grow box
1778 */
1779 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001780gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781{
1782
1783 long newSize;
1784 unsigned short newWidth;
1785 unsigned short newHeight;
1786 Rect resizeLimits;
1787 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 Rect NewContentRect;
1789
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001790 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791
Bram Moolenaar720c7102007-05-10 18:07:50 +00001792 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 /* TODO: Should this come from Vim? */
1794 resizeLimits.top = 100;
1795 resizeLimits.left = 100;
1796
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1798 newWidth = NewContentRect.right - NewContentRect.left;
1799 newHeight = NewContentRect.bottom - NewContentRect.top;
1800 gui_resize_shell(newWidth, newHeight);
1801 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001802 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803}
1804
1805/*
1806 * Handle the click in the zoom box
1807 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001809gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810{
1811 Rect r;
1812 Point p;
1813 short thePart;
1814
1815 /* ideal width is current */
1816 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1817 if (gui.which_scrollbars[SBAR_LEFT])
1818 p.h += gui.scrollbar_width;
1819 if (gui.which_scrollbars[SBAR_RIGHT])
1820 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001821 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 p.v = 15 * 1024;
1823
1824 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1825 ? inZoomIn : inZoomOut;
1826
1827 if (!TrackBox(whichWindow, theEvent->where, thePart))
1828 return;
1829
1830 /* use returned width */
1831 p.h = r.right - r.left;
1832 /* adjust returned height */
1833 p.v = r.bottom - r.top - 2 * gui.border_offset;
1834 if (gui.which_scrollbars[SBAR_BOTTOM])
1835 p.v -= gui.scrollbar_height;
1836 p.v -= p.v % gui.char_height;
1837 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001838 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 p.v += gui.scrollbar_height;
1840
1841 ZoomWindowIdeal(whichWindow, thePart, &p);
1842
1843 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1844 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1845 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001846 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849/*
1850 * ------------------------------------------------------------
1851 * MacOS Event Handling procedure
1852 * ------------------------------------------------------------
1853 */
1854
1855/*
1856 * Handle the Update Event
1857 */
1858
1859 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001860gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861{
1862 WindowPtr whichWindow;
1863 GrafPtr savePort;
1864 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 Rect *updateRectPtr;
1867 Rect rc;
1868 Rect growRect;
1869 RgnHandle saveRgn;
1870
1871
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 updateRgn = NewRgn();
1873 if (updateRgn == NULL)
1874 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875
1876 /* This could be done by the caller as we
1877 * don't require anything else out of the event
1878 */
1879 whichWindow = (WindowPtr) event->message;
1880
1881 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001882 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883
1884 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001885 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001888 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 /* Redraw the biggest rectangle covering the area
1890 * to be updated.
1891 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1893# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001894 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 * seem to work under MacOS X (Dany)
1896 */
1897 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1898# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001899
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001902
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001903 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904# if 0
1905 /* Code from original Carbon Port (using GetWindowRegion.
1906 * I believe the UpdateRgn is already in local (Dany)
1907 */
1908 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1909 GlobalToLocal(&botRight(updateRect));
1910# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 /* Update the content (i.e. the text) */
1912 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1913 updateRectPtr->right - updateRectPtr->left,
1914 updateRectPtr->bottom - updateRectPtr->top);
1915 /* Clear the border areas if needed */
1916 gui_mch_set_bg_color(gui.back_pixel);
1917 if (updateRectPtr->left < FILL_X(0))
1918 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001919 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1920 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
1922 if (updateRectPtr->top < FILL_Y(0))
1923 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001924 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1925 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
1927 if (updateRectPtr->right > FILL_X(Columns))
1928 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001929 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001931 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 if (updateRectPtr->bottom > FILL_Y(Rows))
1934 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001937 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941
1942 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
1945 /* Update the GrowBox */
1946 /* Taken from FAQ 33-27 */
1947 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001949 GetClip(saveRgn);
1950 ClipRect(&growRect);
1951 DrawGrowIcon(whichWindow);
1952 SetClip(saveRgn);
1953 DisposeRgn(saveRgn);
1954 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955
1956 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001957 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958}
1959
1960/*
1961 * Handle the activate/deactivate event
1962 * (apply to a window)
1963 */
1964 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001965gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966{
1967 WindowPtr whichWindow;
1968
1969 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001970 /* Dim scrollbars */
1971 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001973 ControlRef rootControl;
1974 GetRootControl(gui.VimWindow, &rootControl);
1975 if ((event->modifiers) & activeFlag)
1976 ActivateControl(rootControl);
1977 else
1978 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001980
1981 /* Activate */
1982 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983}
1984
1985
1986/*
1987 * Handle the suspend/resume event
1988 * (apply to the application)
1989 */
1990 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001991gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992{
1993 /* The frontmost application just changed */
1994
1995 /* NOTE: the suspend may happen before the deactivate
1996 * seen on MacOS X
1997 */
1998
1999 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002000 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001 */
2002 if (event->message & 1)
2003 /* Resume */
2004 gui_focus_change(TRUE);
2005 else
2006 /* Suspend */
2007 gui_focus_change(FALSE);
2008}
2009
2010/*
2011 * Handle the key
2012 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002013#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002014 static pascal OSStatus
2015gui_mac_handle_window_activate(
2016 EventHandlerCallRef nextHandler,
2017 EventRef theEvent,
2018 void *data)
2019{
2020 UInt32 eventClass = GetEventClass(theEvent);
2021 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002022
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002023 if (eventClass == kEventClassWindow)
2024 {
2025 switch (eventKind)
2026 {
2027 case kEventWindowActivated:
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002028# if defined(FEAT_MBYTE)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002029 im_on_window_switch(TRUE);
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002030# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002031 return noErr;
2032
2033 case kEventWindowDeactivated:
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002034# if defined(FEAT_MBYTE)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002035 im_on_window_switch(FALSE);
Bram Moolenaar819edbe2017-11-25 17:14:33 +01002036# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002037 return noErr;
2038 }
2039 }
2040
2041 return eventNotHandledErr;
2042}
2043
2044 static pascal OSStatus
2045gui_mac_handle_text_input(
2046 EventHandlerCallRef nextHandler,
2047 EventRef theEvent,
2048 void *data)
2049{
2050 UInt32 eventClass = GetEventClass(theEvent);
2051 UInt32 eventKind = GetEventKind(theEvent);
2052
2053 if (eventClass != kEventClassTextInput)
2054 return eventNotHandledErr;
2055
2056 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2057 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2058 (kEventTextInputOffsetToPos != eventKind) &&
2059 (kEventTextInputPosToOffset != eventKind) &&
2060 (kEventTextInputGetSelectedText != eventKind))
2061 return eventNotHandledErr;
2062
2063 switch (eventKind)
2064 {
2065 case kEventTextInputUpdateActiveInputArea:
2066 return gui_mac_update_input_area(nextHandler, theEvent);
2067 case kEventTextInputUnicodeForKeyEvent:
2068 return gui_mac_unicode_key_event(nextHandler, theEvent);
2069
2070 case kEventTextInputOffsetToPos:
2071 case kEventTextInputPosToOffset:
2072 case kEventTextInputGetSelectedText:
2073 break;
2074 }
2075
2076 return eventNotHandledErr;
2077}
2078
2079 static pascal
2080OSStatus gui_mac_update_input_area(
2081 EventHandlerCallRef nextHandler,
2082 EventRef theEvent)
2083{
2084 return eventNotHandledErr;
2085}
2086
2087static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2088 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002089
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002090# define INLINE_KEY_BUFFER_SIZE 80
2091 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002092gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002093 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002094 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002095{
2096 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002097 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002098 UInt32 actualSize;
2099 UniChar *text;
2100 char_u result[INLINE_KEY_BUFFER_SIZE];
2101 short len = 0;
2102 UInt32 key_sym;
2103 char charcode;
2104 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002105 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002106 size_t encLen;
2107 char_u *to = NULL;
2108 Boolean isSpecial = FALSE;
2109 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002110 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002112 /* Mask the mouse (as per user setting) */
2113 if (p_mh)
2114 ObscureCursor();
2115
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 /* Don't use the keys when the dialog wants them. */
2117 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002118 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 typeUnicodeText, NULL, 0, &actualSize, NULL))
2122 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 text = (UniChar *)alloc(actualSize);
2125 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002126 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002127
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002128 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002130 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002131
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002132 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002133 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002134 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002135
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002136 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002138 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002139
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002140 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002141 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002142 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002143
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002144 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002145 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002146 require_noerr(err, done);
2147
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002148#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002150 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002153 key_char = charcode;
2154 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002156 /* Find the special key (eg., for cursor keys) */
2157 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002158 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002159 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002160 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2161 if (special_keys[i].key_sym == key_sym)
2162 {
2163 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2164 special_keys[i].vim_code1);
2165 key_char = simplify_key(key_char,
2166 (int *)&vimModifiers);
2167 isSpecial = TRUE;
2168 break;
2169 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002170 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002171
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002172 /* Intercept CMD-. and CTRL-c */
2173 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002174 ((modifiers & cmdKey) && key_char == '.'))
2175 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002176
2177 if (!isSpecial)
2178 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002179 /* remove SHIFT for keys that are already shifted, e.g.,
2180 * '(' and '*' */
2181 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2182 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002183
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002184 /* remove CTRL from keys that already have it */
2185 if (key_char < 0x20)
2186 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002187
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002188 /* don't process unicode characters here */
2189 if (!IS_SPECIAL(key_char))
2190 {
2191 /* Following code to simplify and consolidate vimModifiers
2192 * taken liberally from gui_w48.c */
2193 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002194
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002195 /* Interpret META, include SHIFT, etc. */
2196 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2197 if (key_char == CSI)
2198 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002199
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002200 if (IS_SPECIAL(key_char))
2201 isSpecial = TRUE;
2202 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002203 }
2204
2205 if (vimModifiers)
2206 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002207 result[len++] = CSI;
2208 result[len++] = KS_MODIFIER;
2209 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002210 }
2211
2212 if (isSpecial && IS_SPECIAL(key_char))
2213 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002214 result[len++] = CSI;
2215 result[len++] = K_SECOND(key_char);
2216 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002217 }
2218 else
2219 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002220 encLen = actualSize;
2221 to = mac_utf16_to_enc(text, actualSize, &encLen);
2222 if (to)
2223 {
2224 /* This is basically add_to_input_buf_csi() */
2225 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2226 {
2227 result[len++] = to[i];
2228 if (to[i] == CSI)
2229 {
2230 result[len++] = KS_EXTRA;
2231 result[len++] = (int)KE_CSI;
2232 }
2233 }
2234 vim_free(to);
2235 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002236 }
2237
2238 add_to_input_buf(result, len);
2239 err = noErr;
2240
2241done:
2242 vim_free(text);
2243 if (err == noErr)
2244 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002245 /* Fake event to wake up WNE (required to get
2246 * key repeat working */
2247 PostEvent(keyUp, 0);
2248 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002249 }
2250
2251 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002252}
2253#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 void
2255gui_mac_doKeyEvent(EventRecord *theEvent)
2256{
2257 /* TODO: add support for COMMAND KEY */
2258 long menu;
2259 unsigned char string[20];
2260 short num, i;
2261 short len = 0;
2262 KeySym key_sym;
2263 int key_char;
2264 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002265 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266
2267 /* Mask the mouse (as per user setting) */
2268 if (p_mh)
2269 ObscureCursor();
2270
2271 /* Get the key code and it's ASCII representation */
2272 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2273 key_char = theEvent->message & charCodeMask;
2274 num = 1;
2275
2276 /* Intercept CTRL-C */
2277 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002278 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 if (key_char == Ctrl_C && ctrl_c_interrupts)
2280 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002281 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2282 && (key_char == '2' || key_char == '6'))
2283 {
2284 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2285 if (key_char == '2')
2286 key_char = Ctrl_AT;
2287 else
2288 key_char = Ctrl_HAT;
2289 theEvent->modifiers = 0;
2290 }
2291 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292
2293 /* Intercept CMD-. */
2294 if (theEvent->modifiers & cmdKey)
2295 if (key_char == '.')
2296 got_int = TRUE;
2297
2298 /* Handle command key as per menu */
2299 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2300 if (theEvent->modifiers & cmdKey)
2301 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2302 * Why the mouse button? */
2303 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2304 {
2305 menu = MenuKey(key_char);
2306 if (HiWord(menu))
2307 {
2308 gui_mac_handle_menu(menu);
2309 return;
2310 }
2311 }
2312
2313 /* Convert the modifiers */
2314 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2315
2316
2317 /* Handle special keys. */
2318#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002319 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2321#endif
2322 {
2323 /* Find the special key (for non-printable keyt_char) */
2324 if ((key_char < 0x20) || (key_char == 0x7f))
2325 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2326 if (special_keys[i].key_sym == key_sym)
2327 {
2328# if 0
2329 /* We currently don't have not so special key */
2330 if (special_keys[i].vim_code1 == NUL)
2331 key_char = special_keys[i].vim_code0;
2332 else
2333# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002334 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2335 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002336 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 break;
2338 }
2339 }
2340
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002341 /* For some keys the modifier is included in the char itself. */
2342 if (simplify || key_char == TAB || key_char == ' ')
2343 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344
2345 /* Add the modifier to the input bu if needed */
2346 /* Do not want SHIFT-A or CTRL-A with modifier */
2347 if (!IS_SPECIAL(key_char)
2348 && key_sym != vk_Space
2349 && key_sym != vk_Tab
2350 && key_sym != vk_Return
2351 && key_sym != vk_Enter
2352 && key_sym != vk_Esc)
2353 {
2354#if 1
2355 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002356 if ((modifiers == MOD_MASK_SHIFT)
2357 || (modifiers == MOD_MASK_CTRL)
2358 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 modifiers = 0;
2360#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002363 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002365 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 modifiers = modifiers & ~MOD_MASK_SHIFT;
2367#endif
2368 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002369 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002371 string[len++] = CSI;
2372 string[len++] = KS_MODIFIER;
2373 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 }
2375
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002378 string[len++] = CSI;
2379 string[len++] = K_SECOND(key_char);
2380 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 }
2382 else
2383 {
2384#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002385 /* Convert characters when needed (e.g., from MacRoman to latin1).
2386 * This doesn't work for the NUL byte. */
2387 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 {
2389 char_u from[2], *to;
2390 int l;
2391
2392 from[0] = key_char;
2393 from[1] = NUL;
2394 l = 1;
2395 to = string_convert(&input_conv, from, &l);
2396 if (to != NULL)
2397 {
2398 for (i = 0; i < l && len < 19; i++)
2399 {
2400 if (to[i] == CSI)
2401 {
2402 string[len++] = KS_EXTRA;
2403 string[len++] = KE_CSI;
2404 }
2405 else
2406 string[len++] = to[i];
2407 }
2408 vim_free(to);
2409 }
2410 else
2411 string[len++] = key_char;
2412 }
2413 else
2414#endif
2415 string[len++] = key_char;
2416 }
2417
2418 if (len == 1 && string[0] == CSI)
2419 {
2420 /* Turn CSI into K_CSI. */
2421 string[ len++ ] = KS_EXTRA;
2422 string[ len++ ] = KE_CSI;
2423 }
2424
2425 add_to_input_buf(string, len);
2426}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002427#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428
2429/*
2430 * Handle MouseClick
2431 */
2432 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002433gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434{
2435 short thePart;
2436 WindowPtr whichWindow;
2437
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002438 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002440#ifdef FEAT_GUI_TABLINE
2441 /* prevent that the vim window size changes if it's activated by a
2442 click into the tab pane */
2443 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002444 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002445#endif
2446
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 switch (thePart)
2448 {
2449 case (inDesk):
2450 /* TODO: what to do? */
2451 break;
2452
2453 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002454 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455 break;
2456
2457 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002458 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 break;
2460
2461 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002462 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 break;
2464
2465 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002466 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 break;
2468
2469 case (inGoAway):
2470 if (TrackGoAway(whichWindow, theEvent->where))
2471 gui_shell_closed();
2472 break;
2473
2474 case (inZoomIn):
2475 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 break;
2478 }
2479}
2480
2481/*
2482 * Handle MouseMoved
2483 * [this event is a moving in and out of a region]
2484 */
2485 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002486gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487{
2488 Point thePoint;
2489 int_u vimModifiers;
2490
2491 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002492 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2494
2495 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002496 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2500 thePoint.v, FALSE, vimModifiers);
2501
2502 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002503 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 FILL_Y(Y_2_ROW(thePoint.v)),
2505 FILL_X(X_2_COL(thePoint.h)+1),
2506 FILL_Y(Y_2_ROW(thePoint.v)+1));
2507
2508 if (dragRectEnbl)
2509 dragRectControl = kCreateRect;
2510
2511}
2512
2513/*
2514 * Handle the mouse release
2515 */
2516 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002517gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518{
2519 Point thePoint;
2520 int_u vimModifiers;
2521
2522 /* TODO: Properly convert the Contextual menu mouse-up */
2523 /* Potential source of the double menu */
2524 lastMouseTick = theEvent->when;
2525 dragRectEnbl = FALSE;
2526 dragRectControl = kCreateEmpty;
2527 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002528 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529
2530 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 if (clickIsPopup)
2532 {
2533 vimModifiers &= ~MOUSE_CTRL;
2534 clickIsPopup = FALSE;
2535 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002536 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537}
2538
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 static pascal OSStatus
2540gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2541 void *data)
2542{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 Point point;
2544 Rect bounds;
2545 UInt32 mod;
2546 SInt32 delta;
2547 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002548 EventMouseWheelAxis axis;
2549
2550 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2551 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2552 && axis != kEventMouseWheelAxisY)
2553 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554
2555 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2556 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2557 goto bail;
2558 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2559 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2560 goto bail;
2561 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2562 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2563 goto bail;
2564
2565 vim_mod = 0;
2566 if (mod & shiftKey)
2567 vim_mod |= MOUSE_SHIFT;
2568 if (mod & controlKey)
2569 vim_mod |= MOUSE_CTRL;
2570 if (mod & optionKey)
2571 vim_mod |= MOUSE_ALT;
2572
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2574 {
2575 point.h -= bounds.left;
2576 point.v -= bounds.top;
2577 }
2578
2579 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2580 point.h, point.v, FALSE, vim_mod);
2581
Bram Moolenaarc236c162008-07-13 17:41:49 +00002582 /* post a bogus event to wake up WaitNextEvent */
2583 PostEvent(keyUp, 0);
2584
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 return noErr;
2586
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002587bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 /*
2589 * when we fail give any additional callback handler a chance to perform
2590 * it's actions
2591 */
2592 return CallNextEventHandler(nextHandler, theEvent);
2593}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594
Bram Moolenaare00289d2010-08-14 21:56:42 +02002595 void
2596gui_mch_mousehide(int hide)
2597{
2598 /* TODO */
2599}
2600
Bram Moolenaar071d4272004-06-13 20:20:40 +00002601#if 0
2602
2603/*
2604 * This would be the normal way of invoking the contextual menu
2605 * but the Vim API doesn't seem to a support a request to get
2606 * the menu that we should display
2607 */
2608 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002609gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610{
2611/*
2612 * Clone PopUp to use menu
2613 * Create a object descriptor for the current selection
2614 * Call the procedure
2615 */
2616
2617// Call to Handle Popup
2618 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2619
2620 if (status != noErr)
2621 return;
2622
2623 if (CntxType == kCMMenuItemSelected)
2624 {
2625 /* Handle the menu CntxMenuID, CntxMenuItem */
2626 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002627 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002628 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629 }
2630 else if (CntxMenuID == kCMShowHelpSelected)
2631 {
2632 /* Should come up with the help */
2633 }
2634
2635}
2636#endif
2637
2638/*
2639 * Handle menubar selection
2640 */
2641 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002642gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643{
2644 short menu = HiWord(menuChoice);
2645 short item = LoWord(menuChoice);
2646 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647
2648 if (menu == 256) /* TODO: use constant or gui.xyz */
2649 {
2650 if (item == 1)
2651 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 }
2653 else if (item != 0)
2654 {
2655 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2656
2657 if (theVimMenu)
2658 gui_menu_cb(theVimMenu);
2659 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002660 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661}
2662
2663/*
2664 * Dispatch the event to proper handler
2665 */
2666
2667 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002668gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669{
2670 OSErr error;
2671
2672 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002673 if (IsShowContextualMenuClick(event))
2674 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002676 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002678 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002680 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002681 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682
2683 /* Handle normal event */
2684 switch (event->what)
2685 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002686#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 case (keyDown):
2688 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002689 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002691#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002693 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 break;
2695
2696 case (mouseDown):
2697 gui_mac_doMouseDownEvent(event);
2698 break;
2699
2700 case (mouseUp):
2701 gui_mac_doMouseUpEvent(event);
2702 break;
2703
2704 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002705 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 break;
2707
2708 case (diskEvt):
2709 /* We don't need special handling for disk insertion */
2710 break;
2711
2712 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002713 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 break;
2715
2716 case (osEvt):
2717 switch ((event->message >> 24) & 0xFF)
2718 {
2719 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002720 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 break;
2722 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002723 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 break;
2725 }
2726 break;
2727
2728#ifdef USE_AEVENT
2729 case (kHighLevelEvent):
2730 /* Someone's talking to us, through AppleEvents */
2731 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2732 break;
2733#endif
2734 }
2735}
2736
2737/*
2738 * ------------------------------------------------------------
2739 * Unknown Stuff
2740 * ------------------------------------------------------------
2741 */
2742
2743
2744 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002745gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746{
2747 char_u c;
2748 char_u *p;
2749 char_u pFontName[256];
2750 Str255 systemFontname;
2751 short font_id;
2752 short size=9;
2753 GuiFont font;
2754#if 0
2755 char_u *fontNamePtr;
2756#endif
2757
2758 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2759 ;
2760
2761 c = *p;
2762 *p = 0;
2763
2764#if 1
2765 STRCPY(&pFontName[1], font_name);
2766 pFontName[0] = STRLEN(font_name);
2767 *p = c;
2768
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002769 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002770 char_u fontName[256];
2771 char_u *styleStart = vim_strchr(font_name, ':');
2772 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2773 vim_strncpy(fontName, font_name, fontNameLen);
2774
2775 ATSUFontID fontRef;
2776 FMFontStyle fontStyle;
2777 font_id = 0;
2778
2779 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2780 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2781 &fontRef) == noErr)
2782 {
2783 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2784 font_id = 0;
2785 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002786
2787 if (font_id == 0)
2788 {
2789 /*
2790 * Try again, this time replacing underscores in the font name
2791 * with spaces (:set guifont allows the two to be used
2792 * interchangeably; the Font Manager doesn't).
2793 */
2794 int i, changed = FALSE;
2795
2796 for (i = pFontName[0]; i > 0; --i)
2797 {
2798 if (pFontName[i] == '_')
2799 {
2800 pFontName[i] = ' ';
2801 changed = TRUE;
2802 }
2803 }
2804 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002805 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2806 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2807 kFontNoLanguageCode, &fontRef) == noErr)
2808 {
2809 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2810 font_id = 0;
2811 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002812 }
2813
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814#else
2815 /* name = C2Pascal_save(menu->dname); */
2816 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2817
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002818 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819#endif
2820
2821
2822 if (font_id == 0)
2823 {
2824 /* Oups, the system font was it the one the user want */
2825
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002826 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2827 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 if (!EqualString(pFontName, systemFontname, false, false))
2829 return NOFONT;
2830 }
2831 if (*p == ':')
2832 {
2833 p++;
2834 /* Set the values found after ':' */
2835 while (*p)
2836 {
2837 switch (*p++)
2838 {
2839 case 'h':
2840 size = points_to_pixels(p, &p, TRUE);
2841 break;
2842 /*
2843 * TODO: Maybe accept width and styles
2844 */
2845 }
2846 while (*p == ':')
2847 p++;
2848 }
2849 }
2850
2851 if (size < 1)
2852 size = 1; /* Avoid having a size of 0 with system font */
2853
2854 font = (size << 16) + ((long) font_id & 0xFFFF);
2855
2856 return font;
2857}
2858
2859/*
2860 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002861 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 * ------------------------------------------------------------
2863 */
2864
2865/*
2866 * Parse the GUI related command-line arguments. Any arguments used are
2867 * deleted from argv, and *argc is decremented accordingly. This is called
2868 * when vim is started, whether or not the GUI has been started.
2869 */
2870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002871gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872{
2873 /* TODO: Move most of this stuff toward gui_mch_init */
2874#ifdef USE_EXE_NAME
2875 FSSpec applDir;
2876# ifndef USE_FIND_BUNDLE_PATH
2877 short applVRefNum;
2878 long applDirID;
2879 Str255 volName;
2880# else
2881 ProcessSerialNumber psn;
2882 FSRef applFSRef;
2883# endif
2884#endif
2885
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886#if 0
2887 InitCursor();
2888
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890
2891#ifdef USE_AEVENT
2892 (void) InstallAEHandlers();
2893#endif
2894
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002895 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002897 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002899 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
2901 DrawMenuBar();
2902
2903
2904#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002907 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908#endif
2909
2910
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911 CreateNewWindow(kDocumentWindowClass,
2912 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002913 &windRect, &gui.VimWindow);
2914 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915
2916 gui.char_width = 7;
2917 gui.char_height = 11;
2918 gui.char_ascent = 6;
2919 gui.num_rows = 24;
2920 gui.num_cols = 80;
2921 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2922
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002923 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2924 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925
2926 dragRectEnbl = FALSE;
2927 dragRgn = NULL;
2928 dragRectControl = kCreateEmpty;
2929 cursorRgn = NewRgn();
2930#endif
2931#ifdef USE_EXE_NAME
2932# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002933 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002935 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936# else
2937 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2938 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002940 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 /* if (err != noErr) return err; */
2942
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002943 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 /* if (err != noErr) return err; */
2945
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947
2948 /* This technic return NIL when we disallow_gui */
2949# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002950 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952}
2953
2954#ifndef ALWAYS_USE_GUI
2955/*
2956 * Check if the GUI can be started. Called before gvimrc is sourced.
2957 * Return OK or FAIL.
2958 */
2959 int
2960gui_mch_init_check(void)
2961{
2962 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2963 * using the >console
2964 */
2965 if (disallow_gui) /* see main.c for reason to disallow */
2966 return FAIL;
2967 return OK;
2968}
2969#endif
2970
2971 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002972receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973{
2974 int x, y;
2975 int_u modifiers;
2976 char_u **fnames = NULL;
2977 int count;
2978 int i, j;
2979
2980 /* Get drop position, modifiers and count of items */
2981 {
2982 Point point;
2983 SInt16 mouseUpModifiers;
2984 UInt16 countItem;
2985
2986 GetDragMouse(theDrag, &point, NULL);
2987 GlobalToLocal(&point);
2988 x = point.h;
2989 y = point.v;
2990 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2991 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2992 CountDragItems(theDrag, &countItem);
2993 count = countItem;
2994 }
2995
2996 fnames = (char_u **)alloc(count * sizeof(char_u *));
2997 if (fnames == NULL)
2998 return dragNotAcceptedErr;
2999
3000 /* Get file names dropped */
3001 for (i = j = 0; i < count; ++i)
3002 {
3003 DragItemRef item;
3004 OSErr err;
3005 Size size;
3006 FlavorType type = flavorTypeHFS;
3007 HFSFlavor hfsFlavor;
3008
3009 fnames[i] = NULL;
3010 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3011 err = GetFlavorDataSize(theDrag, item, type, &size);
3012 if (err != noErr || size > sizeof(hfsFlavor))
3013 continue;
3014 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3015 if (err != noErr)
3016 continue;
3017 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3018 }
3019 count = j;
3020
3021 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003022
3023 /* Fake mouse event to wake from stall */
3024 PostEvent(mouseUp, 0);
3025
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 return noErr;
3027}
3028
3029/*
3030 * Initialise the GUI. Create all the windows, set up all the call-backs
3031 * etc.
3032 */
3033 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003034gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035{
3036 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003037 Rect windRect;
3038 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003040 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003041 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003042
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003043 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003044 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003045
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046#if 1
3047 InitCursor();
3048
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050
3051#ifdef USE_AEVENT
3052 (void) InstallAEHandlers();
3053#endif
3054
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003055 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003057 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003059 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060
3061 DrawMenuBar();
3062
3063
3064#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003067 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068#endif
3069
3070 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003073 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3075 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003076 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077
3078 gui.char_width = 7;
3079 gui.char_height = 11;
3080 gui.char_ascent = 6;
3081 gui.num_rows = 24;
3082 gui.num_cols = 80;
3083 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3084
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003085 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3086 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003088 /* Install Carbon event callbacks. */
3089 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090
3091 dragRectEnbl = FALSE;
3092 dragRgn = NULL;
3093 dragRectControl = kCreateEmpty;
3094 cursorRgn = NewRgn();
3095#endif
3096 /* Display any pending error messages */
3097 display_errors();
3098
3099 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003100 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 gui.norm_pixel = 0x00000000;
3102 gui.back_pixel = 0x00FFFFFF;
3103
3104 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3105 * file). */
3106 set_normal_colors();
3107
3108 /*
3109 * Check that none of the colors are the same as the background color.
3110 * Then store the current values as the defaults.
3111 */
3112 gui_check_colors();
3113 gui.def_norm_pixel = gui.norm_pixel;
3114 gui.def_back_pixel = gui.back_pixel;
3115
3116 /* Get the colors for the highlight groups (gui_check_colors() might have
3117 * changed them) */
3118 highlight_gui_started();
3119
3120 /*
3121 * Setting the gui constants
3122 */
3123#ifdef FEAT_MENU
3124 gui.menu_height = 0;
3125#endif
3126 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3127 gui.border_offset = gui.border_width = 2;
3128
Bram Moolenaar720c7102007-05-10 18:07:50 +00003129 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 gui_mch_draw_string() below), enable it for all font sizes. */
3131 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 eventTypeSpec.eventClass = kEventClassMouse;
3134 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3135 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3136 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3137 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3138 {
3139 mouseWheelHandlerRef = NULL;
3140 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3141 mouseWheelHandlerUPP = NULL;
3142 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003144#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003145 InterfaceTypeList supportedServices = { kUnicodeDocument };
3146 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3147
3148 /* We don't support inline input yet, use input window by default */
3149 UseInputWindow(gTSMDocument, TRUE);
3150
3151 /* Should we activate the document by default? */
3152 // ActivateTSMDocument(gTSMDocument);
3153
3154 EventTypeSpec textEventTypes[] = {
3155 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3156 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3157 { kEventClassTextInput, kEventTextInputPosToOffset },
3158 { kEventClassTextInput, kEventTextInputOffsetToPos },
3159 };
3160
3161 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3162 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3163 NR_ELEMS(textEventTypes),
3164 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003165 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003166 DisposeEventHandlerUPP(keyEventHandlerUPP);
3167 keyEventHandlerUPP = NULL;
3168 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003169
3170 EventTypeSpec windowEventTypes[] = {
3171 { kEventClassWindow, kEventWindowActivated },
3172 { kEventClassWindow, kEventWindowDeactivated },
3173 };
3174
3175 /* Install window event handler to support TSMDocument activate and
3176 * deactivate */
3177 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3178 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3179 winEventHandlerUPP,
3180 NR_ELEMS(windowEventTypes),
3181 windowEventTypes, NULL, NULL))
3182 {
3183 DisposeEventHandlerUPP(winEventHandlerUPP);
3184 winEventHandlerUPP = NULL;
3185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186#endif
3187
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003188/*
3189#ifdef FEAT_MBYTE
3190 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3191#endif
3192*/
3193
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003194#ifdef FEAT_GUI_TABLINE
3195 /*
3196 * Create the tabline
3197 */
3198 initialise_tabline();
3199#endif
3200
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201 /* TODO: Load bitmap if using TOOLBAR */
3202 return OK;
3203}
3204
3205/*
3206 * Called when the foreground or background color has been changed.
3207 */
3208 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003209gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210{
3211 /* TODO:
3212 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003213 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 */
3215}
3216
3217/*
3218 * Open the GUI window which was created by a call to gui_mch_init().
3219 */
3220 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003221gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222{
3223 ShowWindow(gui.VimWindow);
3224
3225 if (gui_win_x != -1 && gui_win_y != -1)
3226 gui_mch_set_winpos(gui_win_x, gui_win_y);
3227
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 /*
3229 * Make the GUI the foreground process (in case it was launched
3230 * from the Terminal or via :gui).
3231 */
3232 {
3233 ProcessSerialNumber psn;
3234 if (GetCurrentProcess(&psn) == noErr)
3235 SetFrontProcess(&psn);
3236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237
3238 return OK;
3239}
3240
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003241#ifdef USE_ATSUI_DRAWING
3242 static void
3243gui_mac_dispose_atsui_style(void)
3244{
3245 if (p_macatsui && gFontStyle)
3246 ATSUDisposeStyle(gFontStyle);
3247#ifdef FEAT_MBYTE
3248 if (p_macatsui && gWideFontStyle)
3249 ATSUDisposeStyle(gWideFontStyle);
3250#endif
3251}
3252#endif
3253
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 void
3255gui_mch_exit(int rc)
3256{
3257 /* TODO: find out all what is missing here? */
3258 DisposeRgn(cursorRgn);
3259
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003260#ifdef USE_CARBONKEYHANDLER
3261 if (keyEventHandlerUPP)
3262 DisposeEventHandlerUPP(keyEventHandlerUPP);
3263#endif
3264
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 if (mouseWheelHandlerUPP != NULL)
3266 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003268#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003269 gui_mac_dispose_atsui_style();
3270#endif
3271
3272#ifdef USE_CARBONKEYHANDLER
3273 FixTSMDocument(gTSMDocument);
3274 DeactivateTSMDocument(gTSMDocument);
3275 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003276#endif
3277
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 /* Exit to shell? */
3279 exit(rc);
3280}
3281
3282/*
3283 * Get the position of the top left corner of the window.
3284 */
3285 int
3286gui_mch_get_winpos(int *x, int *y)
3287{
3288 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 Rect bounds;
3290 OSStatus status;
3291
3292 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003293 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294
3295 if (status != noErr)
3296 return FAIL;
3297 *x = bounds.left;
3298 *y = bounds.top;
3299 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300}
3301
3302/*
3303 * Set the position of the top left corner of the window to the given
3304 * coordinates.
3305 */
3306 void
3307gui_mch_set_winpos(int x, int y)
3308{
3309 /* TODO: Should make sure the window is move within range
3310 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3311 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003312 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313}
3314
3315 void
3316gui_mch_set_shellsize(
3317 int width,
3318 int height,
3319 int min_width,
3320 int min_height,
3321 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003322 int base_height,
3323 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 CGrafPtr VimPort;
3326 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327
3328 if (gui.which_scrollbars[SBAR_LEFT])
3329 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003330 VimPort = GetWindowPort(gui.VimWindow);
3331 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003333 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 }
3336 else
3337 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003338 VimPort = GetWindowPort(gui.VimWindow);
3339 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003341 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 }
3343
3344 SizeWindow(gui.VimWindow, width, height, TRUE);
3345
3346 gui_resize_shell(width, height);
3347}
3348
3349/*
3350 * Get the screen dimensions.
3351 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3352 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003353 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 */
3355 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003356gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357{
3358 GDHandle dominantDevice = GetMainDevice();
3359 Rect screenRect = (**dominantDevice).gdRect;
3360
3361 *screen_w = screenRect.right - 10;
3362 *screen_h = screenRect.bottom - 40;
3363}
3364
3365
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003366/*
3367 * Open the Font Panel and wait for the user to select a font and
3368 * close the panel. Then fill the buffer pointed to by font_name with
3369 * the name and size of the selected font and return the font's handle,
3370 * or NOFONT in case of an error.
3371 */
3372 static GuiFont
3373gui_mac_select_font(char_u *font_name)
3374{
3375 GuiFont selected_font = NOFONT;
3376 OSStatus status;
3377 FontSelectionQDStyle curr_font;
3378
3379 /* Initialize the Font Panel with the current font. */
3380 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3381 curr_font.size = (gui.norm_font >> 16);
3382 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3383 curr_font.instance.fontStyle = 0;
3384 curr_font.hasColor = false;
3385 curr_font.version = 0; /* version number of the style structure */
3386 status = SetFontInfoForSelection(kFontSelectionQDType,
3387 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3388
3389 gFontPanelInfo.family = curr_font.instance.fontFamily;
3390 gFontPanelInfo.style = curr_font.instance.fontStyle;
3391 gFontPanelInfo.size = curr_font.size;
3392
3393 /* Pop up the Font Panel. */
3394 status = FPShowHideFontPanel();
3395 if (status == noErr)
3396 {
3397 /*
3398 * The Font Panel is modeless. We really need it to be modal,
3399 * so we spin in an event loop until the panel is closed.
3400 */
3401 gFontPanelInfo.isPanelVisible = true;
3402 while (gFontPanelInfo.isPanelVisible)
3403 {
3404 EventRecord e;
3405 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3406 }
3407
3408 GetFontPanelSelection(font_name);
3409 selected_font = gui_mac_find_font(font_name);
3410 }
3411 return selected_font;
3412}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003413
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003414#ifdef USE_ATSUI_DRAWING
3415 static void
3416gui_mac_create_atsui_style(void)
3417{
3418 if (p_macatsui && gFontStyle == NULL)
3419 {
3420 if (ATSUCreateStyle(&gFontStyle) != noErr)
3421 gFontStyle = NULL;
3422 }
3423#ifdef FEAT_MBYTE
3424 if (p_macatsui && gWideFontStyle == NULL)
3425 {
3426 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3427 gWideFontStyle = NULL;
3428 }
3429#endif
3430
3431 p_macatsui_last = p_macatsui;
3432}
3433#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434
3435/*
3436 * Initialise vim to use the font with the given name. Return FAIL if the font
3437 * could not be loaded, OK otherwise.
3438 */
3439 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003440gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441{
3442 /* TODO: Add support for bold italic underline proportional etc... */
3443 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003444 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 FontInfo font_info;
3446 short font_id;
3447 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003448 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003450#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003451 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003452#endif
3453
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 if (font_name == NULL)
3455 {
3456 /* First try to get the suggested font */
3457 GetFNum(suggestedFont, &font_id);
3458
3459 if (font_id == 0)
3460 {
3461 /* Then pickup the standard application font */
3462 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003463 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003465 else
3466 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3468 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003469 else if (STRCMP(font_name, "*") == 0)
3470 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003471 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003472
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003473 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003474 if (font == NOFONT)
3475 return FAIL;
3476
3477 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003478 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003479 if (new_p_guifont != NULL)
3480 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003481 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003482 vim_free(p_guifont);
3483 p_guifont = new_p_guifont;
3484 /* Replace spaces in the font name with underscores. */
3485 for ( ; *new_p_guifont; ++new_p_guifont)
3486 {
3487 if (*new_p_guifont == ' ')
3488 *new_p_guifont = '_';
3489 }
3490 }
3491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 else
3493 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003494 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003495 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496
3497 if (font == NOFONT)
3498 return FAIL;
3499 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003500
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501 gui.norm_font = font;
3502
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003503 hl_set_font_name(used_font_name);
3504
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003505 TextSize(font >> 16);
3506 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003508 GetFontInfo(&font_info);
3509
3510 gui.char_ascent = font_info.ascent;
3511 gui.char_width = CharWidth('_');
3512 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3513
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003514#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003515 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003516 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003517#endif
3518
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520}
3521
Bram Moolenaar02743632005-07-25 20:42:36 +00003522/*
3523 * Adjust gui.char_height (after 'linespace' was changed).
3524 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003526gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527{
3528 FontInfo font_info;
3529
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003530 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3532 gui.char_ascent = font_info.ascent + p_linespace / 2;
3533 return OK;
3534}
3535
3536/*
3537 * Get a font structure for highlighting.
3538 */
3539 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003540gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541{
3542 GuiFont font;
3543
3544 font = gui_mac_find_font(name);
3545
3546 if (font == NOFONT)
3547 {
3548 if (giveErrorIfMissing)
3549 EMSG2(_(e_font), name);
3550 return NOFONT;
3551 }
3552 /*
3553 * TODO : Accept only monospace
3554 */
3555
3556 return font;
3557}
3558
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003559#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003561 * Return the name of font "font" in allocated memory.
3562 * Don't know how to get the actual name, thus use the provided name.
3563 */
3564 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003565gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003566{
3567 if (name == NULL)
3568 return NULL;
3569 return vim_strsave(name);
3570}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003571#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003572
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003573#ifdef USE_ATSUI_DRAWING
3574 static void
3575gui_mac_set_font_attributes(GuiFont font)
3576{
3577 ATSUFontID fontID;
3578 Fixed fontSize;
3579 Fixed fontWidth;
3580
3581 fontID = font & 0xFFFF;
3582 fontSize = Long2Fix(font >> 16);
3583 fontWidth = Long2Fix(gui.char_width);
3584
3585 ATSUAttributeTag attribTags[] =
3586 {
3587 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3588 kATSUMaxATSUITagValue + 1
3589 };
3590
3591 ByteCount attribSizes[] =
3592 {
3593 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3594 sizeof(font)
3595 };
3596
3597 ATSUAttributeValuePtr attribValues[] =
3598 {
3599 &fontID, &fontSize, &fontWidth, &font
3600 };
3601
3602 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3603 {
3604 if (ATSUSetAttributes(gFontStyle,
3605 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3606 attribTags, attribSizes, attribValues) != noErr)
3607 {
3608# ifndef NDEBUG
3609 fprintf(stderr, "couldn't set font style\n");
3610# endif
3611 ATSUDisposeStyle(gFontStyle);
3612 gFontStyle = NULL;
3613 }
3614
3615#ifdef FEAT_MBYTE
3616 if (has_mbyte)
3617 {
3618 /* FIXME: we should use a more mbyte sensitive way to support
3619 * wide font drawing */
3620 fontWidth = Long2Fix(gui.char_width * 2);
3621
3622 if (ATSUSetAttributes(gWideFontStyle,
3623 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3624 attribTags, attribSizes, attribValues) != noErr)
3625 {
3626 ATSUDisposeStyle(gWideFontStyle);
3627 gWideFontStyle = NULL;
3628 }
3629 }
3630#endif
3631 }
3632}
3633#endif
3634
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003635/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636 * Set the current text font.
3637 */
3638 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003639gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003641#ifdef USE_ATSUI_DRAWING
3642 GuiFont currFont;
3643 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003644
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003645 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003646 {
3647 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003648 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3649 sizeof(font), &currFont, &actualFontByteCount) == noErr
3650 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003651 {
3652 if (currFont == font)
3653 return;
3654 }
3655
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003656 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003657 }
3658
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003659 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003660 {
3661 /* Setup automatic font substitution. The user's guifontwide
3662 * is tried first, then the system tries other fonts. */
3663/*
3664 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3665 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3666 ATSUCreateFontFallbacks(&gFontFallbacks);
3667 ATSUSetObjFontFallbacks(gFontFallbacks, );
3668*/
3669 if (gui.wide_font)
3670 {
3671 ATSUFontID fallbackFonts;
3672 gIsFontFallbackSet = TRUE;
3673
3674 if (FMGetFontFromFontFamilyInstance(
3675 (gui.wide_font & 0xFFFF),
3676 0,
3677 &fallbackFonts,
3678 NULL) == noErr)
3679 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003680 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3681 &fallbackFonts,
3682 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003683 }
3684/*
3685 ATSUAttributeValuePtr fallbackValues[] = { };
3686*/
3687 }
3688 }
3689#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 TextSize(font >> 16);
3691 TextFont(font & 0xFFFF);
3692}
3693
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694/*
3695 * If a font is not going to be used, free its structure.
3696 */
3697 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003698gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699{
3700 /*
3701 * Free font when "font" is not 0.
3702 * Nothing to do in the current implementation, since
3703 * nothing is allocated for each font used.
3704 */
3705}
3706
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707/*
3708 * Return the Pixel value (color) for the given color name. This routine was
3709 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3710 * Programmer's Guide.
3711 * Return INVALCOLOR when failed.
3712 */
3713 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003714gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715{
3716 /* TODO: Add support for the new named color of MacOS 8
3717 */
3718 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719
Bram Moolenaarab302212016-04-26 20:59:29 +02003720 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003722 LMGetHiliteRGB(&MacColor);
3723 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003725 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726}
3727
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003728 guicolor_T
3729gui_mch_get_rgb_color(int r, int g, int b)
3730{
3731 return gui_get_rgb_color_cmn(r, g, b);
3732}
3733
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734/*
3735 * Set the current text foreground color.
3736 */
3737 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003738gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739{
3740 RGBColor TheColor;
3741
3742 TheColor.red = Red(color) * 0x0101;
3743 TheColor.green = Green(color) * 0x0101;
3744 TheColor.blue = Blue(color) * 0x0101;
3745
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003746 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747}
3748
3749/*
3750 * Set the current text background color.
3751 */
3752 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003753gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754{
3755 RGBColor TheColor;
3756
3757 TheColor.red = Red(color) * 0x0101;
3758 TheColor.green = Green(color) * 0x0101;
3759 TheColor.blue = Blue(color) * 0x0101;
3760
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003761 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762}
3763
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003764RGBColor specialColor;
3765
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003766/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003767 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003768 */
3769 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003770gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003771{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003772 specialColor.red = Red(color) * 0x0101;
3773 specialColor.green = Green(color) * 0x0101;
3774 specialColor.blue = Blue(color) * 0x0101;
3775}
3776
3777/*
3778 * Draw undercurl at the bottom of the character cell.
3779 */
3780 static void
3781draw_undercurl(int flags, int row, int col, int cells)
3782{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003783 int x;
3784 int offset;
3785 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3786 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003787
3788 RGBForeColor(&specialColor);
3789
3790 offset = val[FILL_X(col) % 8];
3791 MoveTo(FILL_X(col), y - offset);
3792
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003793 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003794 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003795 offset = val[x % 8];
3796 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003797 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003798}
3799
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003800
3801 static void
3802draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804#ifdef FEAT_MBYTE
3805 char_u *tofree = NULL;
3806
3807 if (output_conv.vc_type != CONV_NONE)
3808 {
3809 tofree = string_convert(&output_conv, s, &len);
3810 if (tofree != NULL)
3811 s = tofree;
3812 }
3813#endif
3814
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 /*
3816 * On OS X, try using Quartz-style text antialiasing.
3817 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003818 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 {
3820 /* Quartz antialiasing is available only in OS 10.2 and later. */
3821 UInt32 qd_flags = (p_antialias ?
3822 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003823 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 }
3825
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003826 /*
3827 * When antialiasing we're using srcOr mode, we have to clear the block
3828 * before drawing the text.
3829 * Also needed when 'linespace' is non-zero to remove the cursor and
3830 * underlining.
3831 * But not when drawing transparently.
3832 * The following is like calling gui_mch_clear_block(row, col, row, col +
3833 * len - 1), but without setting the bg color to gui.back_pixel.
3834 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003835 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003836 && !(flags & DRAW_TRANSP))
3837 {
3838 Rect rc;
3839
3840 rc.left = FILL_X(col);
3841 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003842#ifdef FEAT_MBYTE
3843 /* Multibyte computation taken from gui_w32.c */
3844 if (has_mbyte)
3845 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003846 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003847 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003848 }
3849 else
3850#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003851 rc.right = FILL_X(col + len) + (col + len == Columns);
3852 rc.bottom = FILL_Y(row + 1);
3853 EraseRect(&rc);
3854 }
3855
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003856 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857 {
3858 StyleParameter face;
3859
3860 face = normal;
3861 if (flags & DRAW_BOLD)
3862 face |= bold;
3863 if (flags & DRAW_UNDERL)
3864 face |= underline;
3865 TextFace(face);
3866
3867 /* Quartz antialiasing works only in srcOr transfer mode. */
3868 TextMode(srcOr);
3869
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870 MoveTo(TEXT_X(col), TEXT_Y(row));
3871 DrawText((char*)s, 0, len);
3872 }
3873 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 {
3875 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003876 TextMode(srcCopy);
3877 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878
3879 /* SelectFont(hdc, gui.currFont); */
3880
3881 if (flags & DRAW_TRANSP)
3882 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003883 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 }
3885
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003886 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003887 DrawText((char *)s, 0, len);
3888
3889 if (flags & DRAW_BOLD)
3890 {
3891 TextMode(srcOr);
3892 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3893 DrawText((char *)s, 0, len);
3894 }
3895
3896 if (flags & DRAW_UNDERL)
3897 {
3898 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3899 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3900 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003901 if (flags & DRAW_STRIKE)
3902 {
3903 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3904 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3905 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003906 }
3907
3908 if (flags & DRAW_UNDERC)
3909 draw_undercurl(flags, row, col, len);
3910
3911#ifdef FEAT_MBYTE
3912 vim_free(tofree);
3913#endif
3914}
3915
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003916#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003917
3918 static void
3919draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3920{
3921 /* ATSUI requires utf-16 strings */
3922 UniCharCount utf16_len;
3923 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3924 utf16_len /= sizeof(UniChar);
3925
3926 /* - ATSUI automatically antialiases text (Someone)
3927 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003928#ifdef MAC_ATSUI_DEBUG
3929 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3930 row, col, len, len == 1 ? s[0] : ' ');
3931#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003932 /*
3933 * When antialiasing we're using srcOr mode, we have to clear the block
3934 * before drawing the text.
3935 * Also needed when 'linespace' is non-zero to remove the cursor and
3936 * underlining.
3937 * But not when drawing transparently.
3938 * The following is like calling gui_mch_clear_block(row, col, row, col +
3939 * len - 1), but without setting the bg color to gui.back_pixel.
3940 */
3941 if ((flags & DRAW_TRANSP) == 0)
3942 {
3943 Rect rc;
3944
3945 rc.left = FILL_X(col);
3946 rc.top = FILL_Y(row);
3947 /* Multibyte computation taken from gui_w32.c */
3948 if (has_mbyte)
3949 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003950 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003951 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003952 }
3953 else
3954 rc.right = FILL_X(col + len) + (col + len == Columns);
3955
3956 rc.bottom = FILL_Y(row + 1);
3957 EraseRect(&rc);
3958 }
3959
3960 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003961 TextMode(srcCopy);
3962 TextFace(normal);
3963
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003964 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003965 if (flags & DRAW_TRANSP)
3966 {
3967 TextMode(srcOr);
3968 }
3969
3970 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003971
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003972 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003973 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003974 Boolean attValue = true;
3975 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3976 ByteCount attribSizes[] = { sizeof(Boolean) };
3977 ATSUAttributeValuePtr attribValues[] = { &attValue };
3978
3979 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3980 }
3981
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003982 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3983 : kATSStyleNoAntiAliasing;
3984 if (useAntialias != useAntialias_cached)
3985 {
3986 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3987 ByteCount attribSizes[] = { sizeof(UInt32) };
3988 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3989
3990 if (gFontStyle)
3991 ATSUSetAttributes(gFontStyle, 1, attribTags,
3992 attribSizes, attribValues);
3993 if (gWideFontStyle)
3994 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3995 attribSizes, attribValues);
3996
3997 useAntialias_cached = useAntialias;
3998 }
3999
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004000#ifdef FEAT_MBYTE
4001 if (has_mbyte)
4002 {
4003 int n, width_in_cell, last_width_in_cell;
4004 UniCharArrayOffset offset = 0;
4005 UniCharCount yet_to_draw = 0;
4006 ATSUTextLayout textLayout;
4007 ATSUStyle textStyle;
4008
4009 last_width_in_cell = 1;
4010 ATSUCreateTextLayout(&textLayout);
4011 ATSUSetTextPointerLocation(textLayout, tofree,
4012 kATSUFromTextBeginning,
4013 kATSUToTextEnd, utf16_len);
4014 /*
4015 ATSUSetRunStyle(textLayout, gFontStyle,
4016 kATSUFromTextBeginning, kATSUToTextEnd); */
4017
4018 /* Compute the length in display cells. */
4019 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4020 {
4021 width_in_cell = (*mb_ptr2cells)(s + n);
4022
4023 /* probably we are switching from single byte character
4024 * to multibyte characters (which requires more than one
4025 * cell to draw) */
4026 if (width_in_cell != last_width_in_cell)
4027 {
4028#ifdef MAC_ATSUI_DEBUG
4029 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4030 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4031#endif
4032 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4033 : gFontStyle;
4034
4035 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4036 offset += yet_to_draw;
4037 yet_to_draw = 0;
4038 last_width_in_cell = width_in_cell;
4039 }
4040
4041 yet_to_draw++;
4042 }
4043
4044 if (yet_to_draw)
4045 {
4046#ifdef MAC_ATSUI_DEBUG
4047 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4048 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4049#endif
4050 /* finish the rest style */
4051 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4052 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4053 }
4054
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004055 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004056 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004057 kATSUFromTextBeginning, kATSUToTextEnd,
4058 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004059 ATSUDisposeTextLayout(textLayout);
4060 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004061 else
4062#endif
4063 {
4064 ATSUTextLayout textLayout;
4065
4066 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4067 kATSUFromTextBeginning, kATSUToTextEnd,
4068 utf16_len,
4069 (gFontStyle ? 1 : 0), &utf16_len,
4070 (gFontStyle ? &gFontStyle : NULL),
4071 &textLayout) == noErr)
4072 {
4073 ATSUSetTransientFontMatching(textLayout, TRUE);
4074
4075 ATSUDrawText(textLayout,
4076 kATSUFromTextBeginning, kATSUToTextEnd,
4077 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4078
4079 ATSUDisposeTextLayout(textLayout);
4080 }
4081 }
4082
4083 /* drawing is done, now reset bold to normal */
4084 if (gFontStyle && flags & DRAW_BOLD)
4085 {
4086 Boolean attValue = false;
4087
4088 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4089 ByteCount attribSizes[] = { sizeof(Boolean) };
4090 ATSUAttributeValuePtr attribValues[] = { &attValue };
4091
4092 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4093 attribValues);
4094 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095 }
4096
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004097 if (flags & DRAW_UNDERC)
4098 draw_undercurl(flags, row, col, len);
4099
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004101}
4102#endif
4103
4104 void
4105gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4106{
4107#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004108 if (p_macatsui == 0 && p_macatsui_last != 0)
4109 /* switch from macatsui to nomacatsui */
4110 gui_mac_dispose_atsui_style();
4111 else if (p_macatsui != 0 && p_macatsui_last == 0)
4112 /* switch from nomacatsui to macatsui */
4113 gui_mac_create_atsui_style();
4114
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004115 if (p_macatsui)
4116 draw_string_ATSUI(row, col, s, len, flags);
4117 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004119 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120}
4121
4122/*
4123 * Return OK if the key with the termcap name "name" is supported.
4124 */
4125 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004126gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127{
4128 int i;
4129
4130 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4131 if (name[0] == special_keys[i].vim_code0 &&
4132 name[1] == special_keys[i].vim_code1)
4133 return OK;
4134 return FAIL;
4135}
4136
4137 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004138gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004140 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141}
4142
4143 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004144gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145{
4146 /* Do a visual beep by reversing the foreground and background colors */
4147 Rect rc;
4148
4149 /*
4150 * Note: InvertRect() excludes right and bottom of rectangle.
4151 */
4152 rc.left = 0;
4153 rc.top = 0;
4154 rc.right = gui.num_cols * gui.char_width;
4155 rc.bottom = gui.num_rows * gui.char_height;
4156 InvertRect(&rc);
4157
4158 ui_delay((long)msec, TRUE); /* wait for some msec */
4159
4160 InvertRect(&rc);
4161}
4162
4163/*
4164 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4165 */
4166 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004167gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168{
4169 Rect rc;
4170
4171 /*
4172 * Note: InvertRect() excludes right and bottom of rectangle.
4173 */
4174 rc.left = FILL_X(c);
4175 rc.top = FILL_Y(r);
4176 rc.right = rc.left + nc * gui.char_width;
4177 rc.bottom = rc.top + nr * gui.char_height;
4178 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179}
4180
4181/*
4182 * Iconify the GUI window.
4183 */
4184 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004185gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186{
4187 /* TODO: find out what could replace iconify
4188 * -window shade?
4189 * -hide application?
4190 */
4191}
4192
4193#if defined(FEAT_EVAL) || defined(PROTO)
4194/*
4195 * Bring the Vim window to the foreground.
4196 */
4197 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004198gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199{
4200 /* TODO */
4201}
4202#endif
4203
4204/*
4205 * Draw a cursor without focus.
4206 */
4207 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004208gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209{
4210 Rect rc;
4211
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212 /*
4213 * Note: FrameRect() excludes right and bottom of rectangle.
4214 */
4215 rc.left = FILL_X(gui.col);
4216 rc.top = FILL_Y(gui.row);
4217 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004218#ifdef FEAT_MBYTE
4219 if (mb_lefthalve(gui.row, gui.col))
4220 rc.right += gui.char_width;
4221#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 rc.bottom = rc.top + gui.char_height;
4223
4224 gui_mch_set_fg_color(color);
4225
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004226 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227}
4228
4229/*
4230 * Draw part of a cursor, only w pixels wide, and h pixels high.
4231 */
4232 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004233gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234{
4235 Rect rc;
4236
4237#ifdef FEAT_RIGHTLEFT
4238 /* vertical line should be on the right of current point */
4239 if (CURSOR_BAR_RIGHT)
4240 rc.left = FILL_X(gui.col + 1) - w;
4241 else
4242#endif
4243 rc.left = FILL_X(gui.col);
4244 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4245 rc.right = rc.left + w;
4246 rc.bottom = rc.top + h;
4247
4248 gui_mch_set_fg_color(color);
4249
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004250 FrameRect(&rc);
4251// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252}
4253
4254
4255
4256/*
4257 * Catch up with any queued X events. This may put keyboard input into the
4258 * input buffer, call resize call-backs, trigger timers etc. If there is
4259 * nothing in the X event queue (& no timers pending), then we return
4260 * immediately.
4261 */
4262 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004263gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264{
4265 /* TODO: find what to do
4266 * maybe call gui_mch_wait_for_chars (0)
4267 * more like look at EventQueue then
4268 * call heart of gui_mch_wait_for_chars;
4269 *
4270 * if (eventther)
4271 * gui_mac_handle_event(&event);
4272 */
4273 EventRecord theEvent;
4274
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004275 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 if (theEvent.what != nullEvent)
4277 gui_mch_wait_for_chars(0);
4278}
4279
4280/*
4281 * Simple wrapper to neglect more easily the time
4282 * spent inside WaitNextEvent while profiling.
4283 */
4284
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 pascal
4286 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004287WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288{
4289 if (((long) sleep) < -1)
4290 sleep = 32767;
4291 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4292}
4293
4294/*
4295 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4296 * from the keyboard.
4297 * wtime == -1 Wait forever.
4298 * wtime == 0 This should never happen.
4299 * wtime > 0 Wait wtime milliseconds for a character.
4300 * Returns OK if a character was found to be available within the given time,
4301 * or FAIL otherwise.
4302 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004304gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305{
4306 EventMask mask = (everyEvent);
4307 EventRecord event;
4308 long entryTick;
4309 long currentTick;
4310 long sleeppyTick;
4311
4312 /* If we are providing life feedback with the scrollbar,
4313 * we don't want to try to wait for an event, or else
4314 * there won't be any life feedback.
4315 */
4316 if (dragged_sb != NULL)
4317 return FAIL;
4318 /* TODO: Check if FAIL is the proper return code */
4319
4320 entryTick = TickCount();
4321
4322 allow_scrollbar = TRUE;
4323
4324 do
4325 {
4326/* if (dragRectControl == kCreateEmpty)
4327 {
4328 dragRgn = NULL;
4329 dragRectControl = kNothing;
4330 }
4331 else*/ if (dragRectControl == kCreateRect)
4332 {
4333 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004334 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 dragRectControl = kNothing;
4336 }
4337 /*
4338 * Don't use gui_mch_update() because then we will spin-lock until a
4339 * char arrives, instead we use WaitNextEventWrp() to hang until an
4340 * event arrives. No need to check for input_buf_full because we are
4341 * returning as soon as it contains a single char.
4342 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004343 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004345 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 else
4347 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004348
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004349 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004351 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352 if (input_available())
4353 {
4354 allow_scrollbar = FALSE;
4355 return OK;
4356 }
4357 }
4358 currentTick = TickCount();
4359 }
4360 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4361
4362 allow_scrollbar = FALSE;
4363 return FAIL;
4364}
4365
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366/*
4367 * Output routines.
4368 */
4369
4370/* Flush any output to the screen */
4371 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004372gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373{
4374 /* TODO: Is anything needed here? */
4375}
4376
4377/*
4378 * Clear a rectangular region of the screen from text pos (row1, col1) to
4379 * (row2, col2) inclusive.
4380 */
4381 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004382gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383{
4384 Rect rc;
4385
4386 /*
4387 * Clear one extra pixel at the far right, for when bold characters have
4388 * spilled over to the next column.
4389 */
4390 rc.left = FILL_X(col1);
4391 rc.top = FILL_Y(row1);
4392 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4393 rc.bottom = FILL_Y(row2 + 1);
4394
4395 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004396 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397}
4398
4399/*
4400 * Clear the whole text window.
4401 */
4402 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004403gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404{
4405 Rect rc;
4406
4407 rc.left = 0;
4408 rc.top = 0;
4409 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4410 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4411
4412 gui_mch_set_bg_color(gui.back_pixel);
4413 EraseRect(&rc);
4414/* gui_mch_set_fg_color(gui.norm_pixel);
4415 FrameRect(&rc);
4416*/
4417}
4418
4419/*
4420 * Delete the given number of lines from the given row, scrolling up any
4421 * text further down within the scroll region.
4422 */
4423 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004424gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425{
4426 Rect rc;
4427
4428 /* changed without checking! */
4429 rc.left = FILL_X(gui.scroll_region_left);
4430 rc.right = FILL_X(gui.scroll_region_right + 1);
4431 rc.top = FILL_Y(row);
4432 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4433
4434 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004435 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436
4437 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4438 gui.scroll_region_left,
4439 gui.scroll_region_bot, gui.scroll_region_right);
4440}
4441
4442/*
4443 * Insert the given number of lines before the given row, scrolling down any
4444 * following text within the scroll region.
4445 */
4446 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004447gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448{
4449 Rect rc;
4450
4451 rc.left = FILL_X(gui.scroll_region_left);
4452 rc.right = FILL_X(gui.scroll_region_right + 1);
4453 rc.top = FILL_Y(row);
4454 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4455
4456 gui_mch_set_bg_color(gui.back_pixel);
4457
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004458 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459
4460 /* Update gui.cursor_row if the cursor scrolled or copied over */
4461 if (gui.cursor_row >= gui.row
4462 && gui.cursor_col >= gui.scroll_region_left
4463 && gui.cursor_col <= gui.scroll_region_right)
4464 {
4465 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4466 gui.cursor_row += num_lines;
4467 else if (gui.cursor_row <= gui.scroll_region_bot)
4468 gui.cursor_is_valid = FALSE;
4469 }
4470
4471 gui_clear_block(row, gui.scroll_region_left,
4472 row + num_lines - 1, gui.scroll_region_right);
4473}
4474
4475 /*
4476 * TODO: add a vim format to the clipboard which remember
4477 * LINEWISE, CHARWISE, BLOCKWISE
4478 */
4479
4480 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004481clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482{
4483
4484 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004485 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 Size scrapSize;
4487 ScrapFlavorFlags scrapFlags;
4488 ScrapRef scrap = nil;
4489 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004490 int type;
4491 char *searchCR;
4492 char_u *tempclip;
4493
4494
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004495 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 if (error != noErr)
4497 return;
4498
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004499 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4500 if (error == noErr)
4501 {
4502 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4503 if (error == noErr && scrapSize > 1)
4504 flavor = 1;
4505 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004507 if (flavor == 0)
4508 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004509 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004510 if (error != noErr)
4511 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004512
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004513 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004514 if (error != noErr)
4515 return;
4516 }
4517
4518 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004520 /* In CARBON we don't need a Handle, a pointer is good */
4521 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004523 /* tempclip = lalloc(scrapSize+1, TRUE); */
4524 HLock(textOfClip);
4525 error = GetScrapFlavorData(scrap,
4526 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4527 &scrapSize, *textOfClip);
4528 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004530 if (flavor)
4531 type = **textOfClip;
4532 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004533 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004534
4535 tempclip = lalloc(scrapSize + 1, TRUE);
4536 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4537 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004539#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004540 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004541 /* Convert from utf-16 (clipboard) */
4542 size_t encLen = 0;
4543 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004544
4545 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004547 scrapSize = encLen;
4548 vim_free(tempclip);
4549 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004551 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004553
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004554 searchCR = (char *)tempclip;
4555 while (searchCR != NULL)
4556 {
4557 searchCR = strchr(searchCR, '\r');
4558 if (searchCR != NULL)
4559 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004561
4562 clip_yank_selection(type, tempclip, scrapSize, cbd);
4563
4564 vim_free(tempclip);
4565 HUnlock(textOfClip);
4566
4567 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568}
4569
4570 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004571clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572{
4573 /*
4574 * TODO: Really nothing to do?
4575 */
4576}
4577
4578 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004579clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580{
4581 return OK;
4582}
4583
4584/*
4585 * Send the current selection to the clipboard.
4586 */
4587 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004588clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589{
4590 Handle textOfClip;
4591 long scrapSize;
4592 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
4595 char_u *str = NULL;
4596
4597 if (!cbd->owned)
4598 return;
4599
4600 clip_get_selection(cbd);
4601
4602 /*
4603 * Once we set the clipboard, lose ownership. If another application sets
4604 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 cbd->owned = FALSE;
4607
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004608 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004610#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004611 size_t utf16_len = 0;
4612 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4613 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004615 scrapSize = utf16_len;
4616 vim_free(str);
4617 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 }
4619#endif
4620
4621 if (type >= 0)
4622 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004625 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 HLock(textOfClip);
4627
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004628 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004629 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004630 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004631 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004632 scrapSize, *textOfClip + 1);
4633 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4634 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635 HUnlock(textOfClip);
4636 DisposeHandle(textOfClip);
4637 }
4638
4639 vim_free(str);
4640}
4641
4642 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004643gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644{
4645 Rect VimBound;
4646
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004647/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649
4650 if (gui.which_scrollbars[SBAR_LEFT])
4651 {
4652 VimBound.left = -gui.scrollbar_width + 1;
4653 }
4654 else
4655 {
4656 VimBound.left = 0;
4657 }
4658
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004661 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662}
4663
4664/*
4665 * Menu stuff.
4666 */
4667
4668 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004669gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670{
4671 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004672 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673 */
4674}
4675
4676 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004677gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678{
4679 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004680 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681 */
4682}
4683
4684/*
4685 * Add a sub menu to the menu bar.
4686 */
4687 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004688gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689{
4690 /*
4691 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4692 * TODO: use menu->mnemonic and menu->actext
4693 * TODO: Try to reuse menu id
4694 * Carbon Help suggest to use only id between 1 and 235
4695 */
4696 static long next_avail_id = 128;
4697 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004698#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004699 CFStringRef name;
4700#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 short index;
4704 vimmenu_T *parent = menu->parent;
4705 vimmenu_T *brother = menu->next;
4706
4707 /* Cannot add a menu if ... */
4708 if ((parent != NULL && parent->submenu_id == 0))
4709 return;
4710
4711 /* menu ID greater than 1024 are reserved for ??? */
4712 if (next_avail_id == 1024)
4713 return;
4714
4715 /* My brother could be the PopUp, find my real brother */
4716 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4717 brother = brother->next;
4718
4719 /* Find where to insert the menu (for MenuBar) */
4720 if ((parent == NULL) && (brother != NULL))
4721 menu_after_me = brother->submenu_id;
4722
4723 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4724 if (!menu_is_menubar(menu->name))
4725 menu_after_me = hierMenu;
4726
4727 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004728#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004729 name = menu_title_removing_mnemonic(menu);
4730#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004732#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733 if (name == NULL)
4734 return;
4735
4736 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737 {
4738 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004739 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4740 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741 */
4742 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004743#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004744 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4745 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4746#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004747 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004748#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749 next_avail_id++;
4750 }
4751
4752 if (parent == NULL)
4753 {
4754 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4755
4756 /* TODO: Verify if we could only Insert Menu if really part of the
4757 * menubar The Inserted menu are scanned or the Command-key combos
4758 */
4759
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004760 /* Insert the menu */
4761 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762#if 1
4763 /* Vim should normally update it. TODO: verify */
4764 DrawMenuBar();
4765#endif
4766 }
4767 else
4768 {
4769 /* Adding as a submenu */
4770
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004771 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772
4773 /* Call InsertMenuItem followed by SetMenuItemText
4774 * to avoid special character recognition by InsertMenuItem
4775 */
4776 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004777#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004778 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4779#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004781#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4783 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4784 InsertMenu(menu->submenu_handle, hierMenu);
4785 }
4786
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004787#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004788 CFRelease(name);
4789#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004790 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792
4793#if 0
4794 /* Done by Vim later on */
4795 DrawMenuBar();
4796#endif
4797}
4798
4799/*
4800 * Add a menu item to a menu
4801 */
4802 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004803gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004805#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004806 CFStringRef name;
4807#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004809#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 vimmenu_T *parent = menu->parent;
4811 int menu_inserted;
4812
4813 /* Cannot add item, if the menu have not been created */
4814 if (parent->submenu_id == 0)
4815 return;
4816
4817 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4818 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4819
4820 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004821#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004822 name = menu_title_removing_mnemonic(menu);
4823#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004825#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826
4827 /* Where are just a menu item, so no handle, no id */
4828 menu->submenu_id = 0;
4829 menu->submenu_handle = NULL;
4830
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831 menu_inserted = 0;
4832 if (menu->actext)
4833 {
4834 /* If the accelerator text for the menu item looks like it describes
4835 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4836 * item's command equivalent.
4837 */
4838 int key = 0;
4839 int modifiers = 0;
4840 char_u *p_actext;
4841
4842 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004843 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004844 if (*p_actext != 0)
4845 key = 0; /* error: trailing text */
4846 /* find_special_key() returns a keycode with as many of the
4847 * specified modifiers as appropriate already applied (e.g., for
4848 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4849 * as the only modifier). Since we want to display all of the
4850 * modifiers, we need to convert the keycode back to a printable
4851 * character plus modifiers.
4852 * TODO: Write an alternative find_special_key() that doesn't
4853 * apply modifiers.
4854 */
4855 if (key > 0 && key < 32)
4856 {
4857 /* Convert a control key to an uppercase letter. Note that
4858 * by this point it is no longer possible to distinguish
4859 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4860 */
4861 modifiers |= MOD_MASK_CTRL;
4862 key += '@';
4863 }
4864 /* If the keycode is an uppercase letter, set the Shift modifier.
4865 * If it is a lowercase letter, don't set the modifier, but convert
4866 * the letter to uppercase for display in the menu.
4867 */
4868 else if (key >= 'A' && key <= 'Z')
4869 modifiers |= MOD_MASK_SHIFT;
4870 else if (key >= 'a' && key <= 'z')
4871 key += 'A' - 'a';
4872 /* Note: keycodes below 0x22 are reserved by Apple. */
4873 if (key >= 0x22 && vim_isprintc_strict(key))
4874 {
4875 int valid = 1;
4876 char_u mac_mods = kMenuNoModifiers;
4877 /* Convert Vim modifier codes to Menu Manager equivalents. */
4878 if (modifiers & MOD_MASK_SHIFT)
4879 mac_mods |= kMenuShiftModifier;
4880 if (modifiers & MOD_MASK_CTRL)
4881 mac_mods |= kMenuControlModifier;
4882 if (!(modifiers & MOD_MASK_CMD))
4883 mac_mods |= kMenuNoCommandModifier;
4884 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4885 valid = 0; /* TODO: will Alt someday map to Option? */
4886 if (valid)
4887 {
4888 char_u item_txt[10];
4889 /* Insert the menu item after idx, with its command key. */
4890 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4891 item_txt[3] = key;
4892 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4893 /* Set the modifier keys. */
4894 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4895 menu_inserted = 1;
4896 }
4897 }
4898 }
4899 /* Call InsertMenuItem followed by SetMenuItemText
4900 * to avoid special character recognition by InsertMenuItem
4901 */
4902 if (!menu_inserted)
4903 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4904 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004905#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004906 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4907#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004909#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910
4911#if 0
4912 /* Called by Vim */
4913 DrawMenuBar();
4914#endif
4915
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004916#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004917 CFRelease(name);
4918#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919 /* TODO: Can name be freed? */
4920 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004921#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922}
4923
4924 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004925gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926{
4927 /* no tearoff menus */
4928}
4929
4930/*
4931 * Destroy the machine specific menu widget.
4932 */
4933 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004934gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004935{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004936 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937
4938 if (index > 0)
4939 {
4940 if (menu->parent)
4941 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942 {
4943 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004944 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945
4946 /* Delete the Menu if it was a hierarchical Menu */
4947 if (menu->submenu_id != 0)
4948 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004949 DeleteMenu(menu->submenu_id);
4950 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 }
4952 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953 }
4954#ifdef DEBUG_MAC_MENU
4955 else
4956 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004957 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004958 }
4959#endif
4960 }
4961 else
4962 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004963 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004964 DeleteMenu(menu->submenu_id);
4965 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 }
4967 }
4968 /* Shouldn't this be already done by Vim. TODO: Check */
4969 DrawMenuBar();
4970}
4971
4972/*
4973 * Make a menu either grey or not grey.
4974 */
4975 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004976gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977{
4978 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004979 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980/*
4981 index = menu->index;
4982*/
4983 if (grey)
4984 {
4985 if (menu->children)
4986 DisableMenuItem(menu->submenu_handle, index);
4987 if (menu->parent)
4988 if (menu->parent->submenu_handle)
4989 DisableMenuItem(menu->parent->submenu_handle, index);
4990 }
4991 else
4992 {
4993 if (menu->children)
4994 EnableMenuItem(menu->submenu_handle, index);
4995 if (menu->parent)
4996 if (menu->parent->submenu_handle)
4997 EnableMenuItem(menu->parent->submenu_handle, index);
4998 }
4999}
5000
5001/*
5002 * Make menu item hidden or not hidden
5003 */
5004 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005005gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005006{
5007 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005008 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009}
5010
5011
5012/*
5013 * This is called after setting all the menus to grey/hidden or not.
5014 */
5015 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005016gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017{
5018 DrawMenuBar();
5019}
5020
5021
5022/*
5023 * Scrollbar stuff.
5024 */
5025
5026 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005027gui_mch_enable_scrollbar(
5028 scrollbar_T *sb,
5029 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005030{
5031 if (flag)
5032 ShowControl(sb->id);
5033 else
5034 HideControl(sb->id);
5035
5036#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005037 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038#endif
5039}
5040
5041 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005042gui_mch_set_scrollbar_thumb(
5043 scrollbar_T *sb,
5044 long val,
5045 long size,
5046 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047{
5048 SetControl32BitMaximum (sb->id, max);
5049 SetControl32BitMinimum (sb->id, 0);
5050 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005051 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02005053 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054#endif
5055}
5056
5057 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005058gui_mch_set_scrollbar_pos(
5059 scrollbar_T *sb,
5060 int x,
5061 int y,
5062 int w,
5063 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064{
5065 gui_mch_set_bg_color(gui.back_pixel);
5066/* if (gui.which_scrollbars[SBAR_LEFT])
5067 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005068 MoveControl(sb->id, x-16, y);
5069 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005070 }
5071 else
5072 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005073 MoveControl(sb->id, x, y);
5074 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075 }*/
5076 if (sb == &gui.bottom_sbar)
5077 h += 1;
5078 else
5079 w += 1;
5080
5081 if (gui.which_scrollbars[SBAR_LEFT])
5082 x -= 15;
5083
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005084 MoveControl(sb->id, x, y);
5085 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005087 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088#endif
5089}
5090
5091 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005092gui_mch_create_scrollbar(
5093 scrollbar_T *sb,
5094 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095{
5096 Rect bounds;
5097
5098 bounds.top = -16;
5099 bounds.bottom = -10;
5100 bounds.right = -10;
5101 bounds.left = -16;
5102
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005103 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 &bounds,
5105 "\pScrollBar",
5106 TRUE,
5107 0, /* current*/
5108 0, /* top */
5109 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 (long) sb->ident);
5112#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005113 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114#endif
5115}
5116
5117 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005118gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119{
5120 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005121 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005123 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124#endif
5125}
5126
Bram Moolenaar703a8042016-06-04 16:24:32 +02005127 int
5128gui_mch_is_blinking(void)
5129{
5130 return FALSE;
5131}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005133 int
5134gui_mch_is_blink_off(void)
5135{
5136 return FALSE;
5137}
5138
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139/*
5140 * Cursor blink functions.
5141 *
5142 * This is a simple state machine:
5143 * BLINK_NONE not blinking at all
5144 * BLINK_OFF blinking, cursor is not shown
5145 * BLINK_ON blinking, cursor is shown
5146 */
5147 void
5148gui_mch_set_blinking(long wait, long on, long off)
5149{
5150 /* TODO: TODO: TODO: TODO: */
5151/* blink_waittime = wait;
5152 blink_ontime = on;
5153 blink_offtime = off;*/
5154}
5155
5156/*
5157 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5158 */
5159 void
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005160gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161{
Bram Moolenaar1dd45fb2018-01-31 21:10:01 +01005162 if (may_call_gui_update_cursor)
5163 gui_update_cursor(TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005164 /* TODO: TODO: TODO: TODO: */
5165/* gui_w32_rm_blink_timer();
5166 if (blink_state == BLINK_OFF)
5167 gui_update_cursor(TRUE, FALSE);
5168 blink_state = BLINK_NONE;*/
5169}
5170
5171/*
5172 * Start the cursor blinking. If it was already blinking, this restarts the
5173 * waiting time and shows the cursor.
5174 */
5175 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005176gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177{
5178 gui_update_cursor(TRUE, FALSE);
5179 /* TODO: TODO: TODO: TODO: */
5180/* gui_w32_rm_blink_timer(); */
5181
5182 /* Only switch blinking on if none of the times is zero */
5183/* if (blink_waittime && blink_ontime && blink_offtime)
5184 {
5185 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5186 (TIMERPROC)_OnBlinkTimer);
5187 blink_state = BLINK_ON;
5188 gui_update_cursor(TRUE, FALSE);
5189 }*/
5190}
5191
5192/*
5193 * Return the RGB value of a pixel as long.
5194 */
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005195 guicolor_T
Bram Moolenaar071d4272004-06-13 20:20:40 +00005196gui_mch_get_rgb(guicolor_T pixel)
5197{
Bram Moolenaar1b58cdd2016-08-22 23:04:33 +02005198 return (guicolor_T)((Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199}
5200
5201
5202
5203#ifdef FEAT_BROWSE
5204/*
5205 * Pop open a file browser and return the file selected, in allocated memory,
5206 * or NULL if Cancel is hit.
5207 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5208 * title - Title message for the file browser dialog.
5209 * dflt - Default name of file.
5210 * ext - Default extension to be added to files without extensions.
5211 * initdir - directory in which to open the browser (NULL = current dir)
5212 * filter - Filter for matched files to choose from.
5213 * Has a format like this:
5214 * "C Files (*.c)\0*.c\0"
5215 * "All Files\0*.*\0\0"
5216 * If these two strings were concatenated, then a choice of two file
5217 * filters will be selectable to the user. Then only matching files will
5218 * be shown in the browser. If NULL, the default allows all files.
5219 *
5220 * *NOTE* - the filter string must be terminated with TWO nulls.
5221 */
5222 char_u *
5223gui_mch_browse(
5224 int saving,
5225 char_u *title,
5226 char_u *dflt,
5227 char_u *ext,
5228 char_u *initdir,
5229 char_u *filter)
5230{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005231 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232 NavReplyRecord reply;
5233 char_u *fname = NULL;
5234 char_u **fnames = NULL;
5235 long numFiles;
5236 NavDialogOptions navOptions;
5237 OSErr error;
5238
5239 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005240 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005241
5242
5243 /* TODO: If we get a :browse args, set the Multiple bit. */
5244 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5245 | kNavDontAutoTranslate
5246 | kNavDontAddTranslateItems
5247 /* | kNavAllowMultipleFiles */
5248 | kNavAllowStationery;
5249
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005250 (void) C2PascalString(title, &navOptions.message);
5251 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 /* Could set clientName?
5253 * windowTitle? (there's no title bar?)
5254 */
5255
5256 if (saving)
5257 {
5258 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005259 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260 if (!reply.validRecord)
5261 return NULL;
5262 }
5263 else
5264 {
5265 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5266 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5267 if (!reply.validRecord)
5268 return NULL;
5269 }
5270
5271 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5272
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005273 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274
5275 if (fnames)
5276 {
5277 fname = fnames[0];
5278 vim_free(fnames);
5279 }
5280
5281 /* TODO: Shorten the file name if possible */
5282 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283}
5284#endif /* FEAT_BROWSE */
5285
5286#ifdef FEAT_GUI_DIALOG
5287/*
5288 * Stuff for dialogues
5289 */
5290
5291/*
5292 * Create a dialogue dynamically from the parameter strings.
5293 * type = type of dialogue (question, alert, etc.)
5294 * title = dialogue title. may be NULL for default title.
5295 * message = text to display. Dialogue sizes to accommodate it.
5296 * buttons = '\n' separated list of button captions, default first.
5297 * dfltbutton = number of default button.
5298 *
5299 * This routine returns 1 if the first button is pressed,
5300 * 2 for the second, etc.
5301 *
5302 * 0 indicates Esc was pressed.
5303 * -1 for unexpected error
5304 *
5305 * If stubbing out this fn, return 1.
5306 */
5307
5308typedef struct
5309{
5310 short idx;
5311 short width; /* Size of the text in pixel */
5312 Rect box;
5313} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5314
5315#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5316
5317 static void
5318macMoveDialogItem(
5319 DialogRef theDialog,
5320 short itemNumber,
5321 short X,
5322 short Y,
5323 Rect *inBox)
5324{
5325#if 0 /* USE_CARBONIZED */
5326 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005327 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005329 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330#else
5331 short itemType;
5332 Handle itemHandle;
5333 Rect localBox;
5334 Rect *itemBox = &localBox;
5335
5336 if (inBox != nil)
5337 itemBox = inBox;
5338
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005339 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5340 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5341 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005342 /* To move a control (like a button) we need to call both
5343 * MoveControl and SetDialogItem. FAQ 6-18 */
5344 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005345 MoveControl((ControlRef) itemHandle, X, Y);
5346 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005347#endif
5348}
5349
5350 static void
5351macSizeDialogItem(
5352 DialogRef theDialog,
5353 short itemNumber,
5354 short width,
5355 short height)
5356{
5357 short itemType;
5358 Handle itemHandle;
5359 Rect itemBox;
5360
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005361 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005362
5363 /* When width or height is zero do not change it */
5364 if (width == 0)
5365 width = itemBox.right - itemBox.left;
5366 if (height == 0)
5367 height = itemBox.bottom - itemBox.top;
5368
5369#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005370 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371#else
5372 /* Resize the bounding box */
5373 itemBox.right = itemBox.left + width;
5374 itemBox.bottom = itemBox.top + height;
5375
5376 /* To resize a control (like a button) we need to call both
5377 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5378 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005379 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005380
5381 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005382 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005383#endif
5384}
5385
5386 static void
5387macSetDialogItemText(
5388 DialogRef theDialog,
5389 short itemNumber,
5390 Str255 itemName)
5391{
5392 short itemType;
5393 Handle itemHandle;
5394 Rect itemBox;
5395
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005396 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397
5398 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005399 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005401 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005402}
5403
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005404
5405/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5406 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5407 * setting gDialogHotKeys to NULL disables any hotkey handling.
5408 */
5409 static pascal Boolean
5410DialogHotkeyFilterProc (
5411 DialogRef theDialog,
5412 EventRecord *event,
5413 DialogItemIndex *itemHit)
5414{
5415 char_u keyHit;
5416
5417 if (event->what == keyDown || event->what == autoKey)
5418 {
5419 keyHit = (event->message & charCodeMask);
5420
5421 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5422 {
5423#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5424 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5425#endif
5426 *itemHit = gDialogHotKeys[keyHit];
5427
5428 /* When handing off to StdFilterProc, pretend that the user
5429 * clicked the control manually. Note that this is also supposed
5430 * to cause the button to hilite briefly (to give some user
5431 * feedback), but this seems not to actually work (or it's too
5432 * fast to be seen).
5433 */
5434 event->what = kEventControlSimulateHit;
5435
5436 return true; /* we took care of it */
5437 }
5438
5439 /* Defer to the OS's standard behavior for this event.
5440 * This ensures that Enter will still activate the default button. */
5441 return StdFilterProc(theDialog, event, itemHit);
5442 }
5443 return false; /* Let ModalDialog deal with it */
5444}
5445
5446
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005447/* TODO: There have been some crashes with dialogs, check your inbox
5448 * (Jussi)
5449 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450 int
5451gui_mch_dialog(
5452 int type,
5453 char_u *title,
5454 char_u *message,
5455 char_u *buttons,
5456 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005457 char_u *textfield,
5458 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005459{
5460 Handle buttonDITL;
5461 Handle iconDITL;
5462 Handle inputDITL;
5463 Handle messageDITL;
5464 Handle itemHandle;
5465 Handle iconHandle;
5466 DialogPtr theDialog;
5467 char_u len;
5468 char_u PascalTitle[256]; /* place holder for the title */
5469 char_u name[256];
5470 GrafPtr oldPort;
5471 short itemHit;
5472 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005473 short hotKeys[256]; /* map of hotkey -> control ID */
5474 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005475 Rect box;
5476 short button;
5477 short lastButton;
5478 short itemType;
5479 short useIcon;
5480 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005481 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005482 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 short widestButton = 0;
5484 short dfltButtonEdge = 20; /* gut feeling */
5485 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5486 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5487 short maximumWidth = 400; /* gut feeling */
5488 short maxButtonWidth = 175; /* gut feeling */
5489
5490 short vertical;
5491 short dialogHeight;
5492 short messageLines = 3;
5493 FontInfo textFontInfo;
5494
5495 vgmDlgItm iconItm;
5496 vgmDlgItm messageItm;
5497 vgmDlgItm inputItm;
5498 vgmDlgItm buttonItm;
5499
5500 WindowRef theWindow;
5501
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005502 ModalFilterUPP dialogUPP;
5503
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504 /* Check 'v' flag in 'guioptions': vertical button placement. */
5505 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5506
5507 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005508 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005509
5510 /* Get the WindowRef */
5511 theWindow = GetDialogWindow(theDialog);
5512
5513 /* Hide the window.
5514 * 1. to avoid seeing slow drawing
5515 * 2. to prevent a problem seen while moving dialog item
5516 * within a visible window. (non-Carbon MacOS 9)
5517 * Could be avoided by changing the resource.
5518 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005519 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520
5521 /* Change the graphical port to the dialog,
5522 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005523 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005524 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005525
5526 /* Get the info about the default text,
5527 * used to calculate the height of the message
5528 * and of the text field */
5529 GetFontInfo(&textFontInfo);
5530
5531 /* Set the dialog title */
5532 if (title != NULL)
5533 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005534 (void) C2PascalString(title, &PascalTitle);
5535 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005536 }
5537
5538 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005539 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005540 buttonChar = buttons;
5541 button = 0;
5542
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005543 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005544 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005545
Bram Moolenaar071d4272004-06-13 20:20:40 +00005546 for (;*buttonChar != 0;)
5547 {
5548 /* Get the name of the button */
5549 button++;
5550 len = 0;
5551 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5552 {
5553 if (*buttonChar != DLG_HOTKEY_CHAR)
5554 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005555 else
5556 {
5557 aHotKey = (char_u)*(buttonChar+1);
5558 if (aHotKey >= 'A' && aHotKey <= 'Z')
5559 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5560 hotKeys[aHotKey] = button;
5561#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5562 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5563#endif
5564 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005565 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005566
Bram Moolenaar071d4272004-06-13 20:20:40 +00005567 if (*buttonChar != 0)
5568 buttonChar++;
5569 name[0] = len;
5570
5571 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005572 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573
5574 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005575 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576
5577 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005578 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005579 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005580 /* TODO: Should be based on the message width */
5581 if (width > maxButtonWidth)
5582 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005583 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005584
5585 totalButtonWidth += width;
5586
5587 if (width > widestButton)
5588 widestButton = width;
5589 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005590 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005591 lastButton = button;
5592
5593 /* Add the icon to the Dialog Box. */
5594 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005595 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596 switch (type)
5597 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005598 case VIM_GENERIC:
5599 case VIM_INFO:
5600 case VIM_QUESTION: useIcon = kNoteIcon; break;
5601 case VIM_WARNING: useIcon = kCautionIcon; break;
5602 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005603 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005604 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005605 AppendDITL(theDialog, iconDITL, overlayDITL);
5606 ReleaseResource(iconDITL);
5607 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005609 iconHandle = GetIcon(useIcon);
5610 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005611
5612 /* Add the message to the Dialog box. */
5613 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005614 messageDITL = GetResource('DITL', 132);
5615 AppendDITL(theDialog, messageDITL, overlayDITL);
5616 ReleaseResource(messageDITL);
5617 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5618 (void) C2PascalString(message, &name);
5619 SetDialogItemText(itemHandle, name);
5620 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621
5622 /* Add the input box if needed */
5623 if (textfield != NULL)
5624 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005625 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005627 inputDITL = GetResource('DITL', 132);
5628 AppendDITL(theDialog, inputDITL, overlayDITL);
5629 ReleaseResource(inputDITL);
5630 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5631/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5632 (void) C2PascalString(textfield, &name);
5633 SetDialogItemText(itemHandle, name);
5634 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005635
5636 /* Hotkeys don't make sense if there's a text field */
5637 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005639 else
5640 /* Install hotkey table */
5641 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005642
5643 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005644 SetDialogDefaultItem(theDialog, dfltbutton);
5645 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005646
5647 /* Reposition element */
5648
5649 /* Check if we need to force vertical */
5650 if (totalButtonWidth > maximumWidth)
5651 vertical = TRUE;
5652
5653 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005654 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005655 iconItm.box.right = box.right;
5656 iconItm.box.bottom = box.bottom;
5657
5658 /* Place Message */
5659 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005660 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5661 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005662
5663 /* Place Input */
5664 if (textfield != NULL)
5665 {
5666 inputItm.box.left = messageItm.box.left;
5667 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005668 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5669 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 /* Convert the static text into a text edit.
5671 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005672 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5673 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005674 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5675 }
5676
5677 /* Place Button */
5678 if (textfield != NULL)
5679 {
5680 buttonItm.box.left = inputItm.box.left;
5681 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5682 }
5683 else
5684 {
5685 buttonItm.box.left = messageItm.box.left;
5686 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5687 }
5688
5689 for (button=1; button <= lastButton; button++)
5690 {
5691
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005692 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005693 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005694 if (vertical)
5695 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005696 macSizeDialogItem(theDialog, button, widestButton, 0);
5697 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005698 }
5699 /* Calculate position of next button */
5700 if (vertical)
5701 buttonItm.box.top = box.bottom + dfltElementSpacing;
5702 else
5703 buttonItm.box.left = box.right + dfltElementSpacing;
5704 }
5705
5706 /* Resize the dialog box */
5707 dialogHeight = box.bottom + dfltElementSpacing;
5708 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5709
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005711 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005712 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005713
5714 /* Display it */
5715 ShowWindow(theWindow);
5716/* BringToFront(theWindow); */
5717 SelectWindow(theWindow);
5718
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005719/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005721 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005722 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005723#endif
5724
Bram Moolenaard68071d2006-05-02 22:08:30 +00005725#ifdef USE_CARBONKEYHANDLER
5726 /* Avoid that we use key events for the main window. */
5727 dialog_busy = TRUE;
5728#endif
5729
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005730 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5731 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5732
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733 /* Hang until one of the button is hit */
5734 do
5735 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005736 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737 } while ((itemHit < 1) || (itemHit > lastButton));
5738
Bram Moolenaard68071d2006-05-02 22:08:30 +00005739#ifdef USE_CARBONKEYHANDLER
5740 dialog_busy = FALSE;
5741#endif
5742
Bram Moolenaar071d4272004-06-13 20:20:40 +00005743 /* Copy back the text entered by the user into the param */
5744 if (textfield != NULL)
5745 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005746 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5747 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005748#if IOSIZE < 256
5749 /* Truncate the name to IOSIZE if needed */
5750 if (name[0] > IOSIZE)
5751 name[0] = IOSIZE - 1;
5752#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005753 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754 }
5755
5756 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005757 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005758
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005759 /* Free the modal filterProc */
5760 DisposeRoutineDescriptor(dialogUPP);
5761
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005762 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005763 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005764
5765 return itemHit;
5766/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005767 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 * SetDialogTimeout(): Auto click a button after timeout
5769 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5770 * MoveDialogItem(): Probably better than SetDialogItem
5771 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005772 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773 */
5774}
5775#endif /* FEAT_DIALOG_GUI */
5776
5777/*
5778 * Display the saved error message(s).
5779 */
5780#ifdef USE_MCH_ERRMSG
5781 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005782display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783{
5784 char *p;
5785 char_u pError[256];
5786
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005787 if (error_ga.ga_data == NULL)
5788 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005789
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005790 /* avoid putting up a message box with blanks only */
5791 for (p = (char *)error_ga.ga_data; *p; ++p)
5792 if (!isspace(*p))
5793 {
5794 if (STRLEN(p) > 255)
5795 pError[0] = 255;
5796 else
5797 pError[0] = STRLEN(p);
5798
5799 STRNCPY(&pError[1], p, pError[0]);
5800 ParamText(pError, nil, nil, nil);
5801 Alert(128, nil);
5802 break;
5803 /* TODO: handled message longer than 256 chars
5804 * use auto-sizeable alert
5805 * or dialog with scrollbars (TextEdit zone)
5806 */
5807 }
5808 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809}
5810#endif
5811
5812/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005813 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005814 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005815 void
5816gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005817{
5818 Point where;
5819
5820 GetMouse(&where);
5821
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005822 *x = where.h;
5823 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005824}
5825
5826 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005827gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005828{
5829 /* TODO */
5830#if 0
5831 /* From FAQ 3-11 */
5832
5833 CursorDevicePtr myMouse;
5834 Point where;
5835
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005836 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5837 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005838 {
5839 /* New way */
5840
5841 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005842 * Get first device with one button.
5843 * This will probably be the standard mouse
5844 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845 *
5846 */
5847
5848 myMouse = nil;
5849
5850 do
5851 {
5852 /* Get the next cursor device */
5853 CursorDeviceNextDevice(&myMouse);
5854 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005855 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005857 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005858 }
5859 else
5860 {
5861 /* Old way */
5862 where.h = x;
5863 where.v = y;
5864
5865 *(Point *)RawMouse = where;
5866 *(Point *)MTemp = where;
5867 *(Ptr) CrsrNew = 0xFFFF;
5868 }
5869#endif
5870}
5871
5872 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005873gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005875/*
5876 * Clone PopUp to use menu
5877 * Create a object descriptor for the current selection
5878 * Call the procedure
5879 */
5880
5881 MenuHandle CntxMenu;
5882 Point where;
5883 OSStatus status;
5884 UInt32 CntxType;
5885 SInt16 CntxMenuID;
5886 UInt16 CntxMenuItem;
5887 Str255 HelpName = "";
5888 GrafPtr savePort;
5889
5890 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005891 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005893 GetMouse(&where);
5894 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895 CntxMenu = menu->submenu_handle;
5896
5897 /* TODO: Get the text selection from Vim */
5898
5899 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005900 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005901 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902
5903 if (status == noErr)
5904 {
5905 if (CntxType == kCMMenuItemSelected)
5906 {
5907 /* Handle the menu CntxMenuID, CntxMenuItem */
5908 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005909 /* But what about the current menu, is the menu changed by
5910 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005911 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912 }
5913 else if (CntxMenuID == kCMShowHelpSelected)
5914 {
5915 /* Should come up with the help */
5916 }
5917 }
5918
5919 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005920 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005921}
5922
5923#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5924/* TODO: Is it need for MACOS_X? (Dany) */
5925 void
5926mch_post_buffer_write(buf_T *buf)
5927{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005928 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5929 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930}
5931#endif
5932
5933#ifdef FEAT_TITLE
5934/*
5935 * Set the window title and icon.
5936 * (The icon is not taken care of).
5937 */
5938 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005939gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005940{
5941 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5942 * that 256. Even better get it to fit nicely in the titlebar.
5943 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005944#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005945 CFStringRef windowTitle;
5946 size_t windowTitleLen;
5947#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005949#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950
5951 if (title == NULL) /* nothing to do */
5952 return;
5953
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005954#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005955 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00005956 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005957
5958 if (windowTitle)
5959 {
5960 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5961 CFRelease(windowTitle);
5962 }
5963#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964 pascalTitle = C2Pascal_save(title);
5965 if (pascalTitle != NULL)
5966 {
5967 SetWTitle(gui.VimWindow, pascalTitle);
5968 vim_free(pascalTitle);
5969 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005970#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005971}
5972#endif
5973
5974/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005975 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00005976 */
5977
5978 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005979C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980{
5981 char_u *PascalPtr = (char_u *) PascalString;
5982 int len;
5983 int i;
5984
5985 PascalPtr[0] = 0;
5986 if (CString == NULL)
5987 return 0;
5988
5989 len = STRLEN(CString);
5990 if (len > 255)
5991 len = 255;
5992
5993 for (i = 0; i < len; i++)
5994 PascalPtr[i+1] = CString[i];
5995
5996 PascalPtr[0] = len;
5997
5998 return 0;
5999}
6000
6001 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006002GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003{
6004 /* From FAQ 8-12 */
6005 Str255 filePascal;
6006 CInfoPBRec myCPB;
6007 OSErr err;
6008
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006009 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006010
6011 myCPB.dirInfo.ioNamePtr = filePascal;
6012 myCPB.dirInfo.ioVRefNum = 0;
6013 myCPB.dirInfo.ioFDirIndex = 0;
6014 myCPB.dirInfo.ioDrDirID = 0;
6015
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006016 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017
6018 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006019 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020
6021 /* TODO: Use an error code mechanism */
6022 return 0;
6023}
6024
6025/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006026 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00006027 */
6028
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006029char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006030{
6031 /*
6032 * TODO: Add protection for 256 char max.
6033 */
6034
6035 CInfoPBRec theCPB;
6036 char_u fname[256];
6037 char_u *filenamePtr = fname;
6038 OSErr error;
6039 int folder = 1;
6040#ifdef USE_UNIXFILENAME
6041 SInt16 dfltVol_vRefNum;
6042 SInt32 dfltVol_dirID;
6043 FSRef refFile;
6044 OSStatus status;
6045 UInt32 pathSize = 256;
6046 char_u pathname[256];
6047 char_u *path = pathname;
6048#else
6049 Str255 directoryName;
6050 char_u temporary[255];
6051 char_u *temporaryPtr = temporary;
6052#endif
6053
6054#ifdef USE_UNIXFILENAME
6055 /* Get the default volume */
6056 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006057 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006058
6059 if (error)
6060 return NULL;
6061#endif
6062
6063 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006064 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006065
6066 /* Get the info about the file specified in FSSpec */
6067 theCPB.dirInfo.ioFDirIndex = 0;
6068 theCPB.dirInfo.ioNamePtr = file.name;
6069 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006070 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006071 theCPB.dirInfo.ioDrDirID = file.parID;
6072
6073 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6074 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006075 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006076
6077 /* If we are called for a new file we expect fnfErr */
6078 if ((error) && (error != fnfErr))
6079 return NULL;
6080
6081 /* Check if it's a file or folder */
6082 /* default to file if file don't exist */
6083 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6084 folder = 0; /* It's not a folder */
6085 else
6086 folder = 1;
6087
6088#ifdef USE_UNIXFILENAME
6089 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006090 * The functions used here are available in Carbon, but do nothing on
6091 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 */
6093 if (error == fnfErr)
6094 {
6095 /* If the file to be saved does not already exist, it isn't possible
6096 to convert its FSSpec into an FSRef. But we can construct an
6097 FSSpec for the file's parent folder (since we have its volume and
6098 directory IDs), and since that folder does exist, we can convert
6099 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6100 and, finally, append the filename. */
6101 FSSpec dirSpec;
6102 FSRef dirRef;
6103 Str255 emptyFilename = "\p";
6104 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6105 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6106 if (error)
6107 return NULL;
6108
6109 error = FSpMakeFSRef(&dirSpec, &dirRef);
6110 if (error)
6111 return NULL;
6112
6113 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6114 if (status)
6115 return NULL;
6116
6117 STRCAT(path, "/");
6118 STRCAT(path, filenamePtr);
6119 }
6120 else
6121 {
6122 /* If the file to be saved already exists, we can get its full path
6123 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006124 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 if (error)
6126 return NULL;
6127
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006128 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006129 if (status)
6130 return NULL;
6131 }
6132
6133 /* Add a slash at the end if needed */
6134 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006135 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006136
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006137 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006138#else
6139 /* TODO: Get rid of all USE_UNIXFILENAME below */
6140 /* Set ioNamePtr, it's the same area which is always reused. */
6141 theCPB.dirInfo.ioNamePtr = directoryName;
6142
6143 /* Trick for first entry, set ioDrParID to the first value
6144 * we want for ioDrDirID*/
6145 theCPB.dirInfo.ioDrParID = file.parID;
6146 theCPB.dirInfo.ioDrDirID = file.parID;
6147
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006148 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006149 do
6150 {
6151 theCPB.dirInfo.ioFDirIndex = -1;
6152 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6153 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006154 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006155 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6156
6157 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6158 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006159 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160
6161 if (error)
6162 return NULL;
6163
6164 /* Put the new directoryName in front of the current fname */
6165 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006166 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006167 STRCAT(filenamePtr, ":");
6168 STRCAT(filenamePtr, temporaryPtr);
6169 }
6170#if 1 /* def USE_UNIXFILENAME */
6171 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6172 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6173#else
6174 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6175#endif
6176
6177 /* Get the information about the volume on which the file reside */
6178 theCPB.dirInfo.ioFDirIndex = -1;
6179 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6180 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006181 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006182 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6183
6184 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6185 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006186 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187
6188 if (error)
6189 return NULL;
6190
6191 /* For MacOS Classic always add the volume name */
6192 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006193 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194#ifdef USE_UNIXFILENAME
6195 if (file.vRefNum != dfltVol_vRefNum)
6196#endif
6197 {
6198 /* Add the volume name */
6199 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006200 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006201 STRCAT(filenamePtr, ":");
6202 STRCAT(filenamePtr, temporaryPtr);
6203
6204#ifdef USE_UNIXFILENAME
6205 STRCPY(temporaryPtr, filenamePtr);
6206 filenamePtr[0] = 0; /* NULL terminate the string */
6207 STRCAT(filenamePtr, "Volumes:");
6208 STRCAT(filenamePtr, temporaryPtr);
6209#endif
6210 }
6211
6212 /* Append final path separator if it's a folder */
6213 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006214 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006215
6216 /* As we use Unix File Name for MacOS X convert it */
6217#ifdef USE_UNIXFILENAME
6218 /* Need to insert leading / */
6219 /* TODO: get the above code to use directly the / */
6220 STRCPY(&temporaryPtr[1], filenamePtr);
6221 temporaryPtr[0] = '/';
6222 STRCPY(filenamePtr, temporaryPtr);
6223 {
6224 char *p;
6225 for (p = fname; *p; p++)
6226 if (*p == ':')
6227 *p = '/';
6228 }
6229#endif
6230
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006231 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006232#endif
6233}
6234
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006235#if (defined(FEAT_MBYTE) && defined(USE_CARBONKEYHANDLER)) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006236/*
6237 * Input Method Control functions.
6238 */
6239
6240/*
6241 * Notify cursor position to IM.
6242 */
6243 void
6244im_set_position(int row, int col)
6245{
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006246# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006247 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006248 im_start_row = row;
6249 im_start_col = col;
Bram Moolenaar259f26a2018-05-15 22:25:40 +02006250# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006251}
6252
6253static ScriptLanguageRecord gTSLWindow;
6254static ScriptLanguageRecord gTSLInsert;
6255static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6256
6257static Component gTSCWindow;
6258static Component gTSCInsert;
6259static Component gTSCDefault;
6260
6261static int im_initialized = 0;
6262
6263 static void
6264im_on_window_switch(int active)
6265{
6266 ScriptLanguageRecord *slptr = NULL;
6267 OSStatus err;
6268
6269 if (! gui.in_use)
6270 return;
6271
6272 if (im_initialized == 0)
6273 {
6274 im_initialized = 1;
6275
6276 /* save default TSM component (should be U.S.) to default */
6277 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6278 kKeyboardInputMethodClass);
6279 }
6280
6281 if (active == TRUE)
6282 {
6283 im_is_active = TRUE;
6284 ActivateTSMDocument(gTSMDocument);
6285 slptr = &gTSLWindow;
6286
6287 if (slptr)
6288 {
6289 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6290 kKeyboardInputMethodClass);
6291 if (err == noErr)
6292 err = SetTextServiceLanguage(slptr);
6293
6294 if (err == noErr)
6295 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6296 }
6297 }
6298 else
6299 {
6300 err = GetTextServiceLanguage(&gTSLWindow);
6301 if (err == noErr)
6302 slptr = &gTSLWindow;
6303
6304 if (slptr)
6305 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6306 kKeyboardInputMethodClass);
6307
6308 im_is_active = FALSE;
6309 DeactivateTSMDocument(gTSMDocument);
6310 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311}
6312
6313/*
6314 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6315 */
6316 void
6317im_set_active(int active)
6318{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006319 ScriptLanguageRecord *slptr = NULL;
6320 OSStatus err;
6321
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006322 if (!gui.in_use)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006323 return;
6324
6325 if (im_initialized == 0)
6326 {
6327 im_initialized = 1;
6328
6329 /* save default TSM component (should be U.S.) to default */
6330 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6331 kKeyboardInputMethodClass);
6332 }
6333
6334 if (active == TRUE)
6335 {
6336 im_is_active = TRUE;
6337 ActivateTSMDocument(gTSMDocument);
6338 slptr = &gTSLInsert;
6339
6340 if (slptr)
6341 {
6342 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6343 kKeyboardInputMethodClass);
6344 if (err == noErr)
6345 err = SetTextServiceLanguage(slptr);
6346
6347 if (err == noErr)
6348 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6349 }
6350 }
6351 else
6352 {
6353 err = GetTextServiceLanguage(&gTSLInsert);
6354 if (err == noErr)
6355 slptr = &gTSLInsert;
6356
6357 if (slptr)
6358 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6359 kKeyboardInputMethodClass);
6360
6361 /* restore to default when switch to normal mode, so than we could
6362 * enter commands easier */
6363 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6364 kKeyboardInputMethodClass);
6365 SetTextServiceLanguage(&gTSLDefault);
6366
6367 im_is_active = FALSE;
6368 DeactivateTSMDocument(gTSMDocument);
6369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006370}
6371
6372/*
6373 * Get IM status. When IM is on, return not 0. Else return 0.
6374 */
6375 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006376im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006377{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006378 if (! gui.in_use)
6379 return 0;
6380
6381 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006382}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006383
Bram Moolenaar819edbe2017-11-25 17:14:33 +01006384#endif /* defined(FEAT_MBYTE) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006385
6386
6387
6388
6389#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6390// drawer implementation
6391static MenuRef contextMenu = NULL;
6392enum
6393{
Bram Moolenaar43acbce2016-02-27 15:21:32 +01006394 kTabContextMenuId = 42
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006395};
6396
6397// the caller has to CFRelease() the returned string
6398 static CFStringRef
6399getTabLabel(tabpage_T *page)
6400{
6401 get_tabline_label(page, FALSE);
6402#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006403 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006404#else
6405 // TODO: check internal encoding?
6406 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6407 kCFStringEncodingMacRoman);
6408#endif
6409}
6410
6411
6412#define DRAWER_SIZE 150
6413#define DRAWER_INSET 16
6414
6415static ControlRef dataBrowser = NULL;
6416
6417// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006418// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006419// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006420// for a very short time. to prevent inconsistent state, we store the labels
6421// of the tabs, not pointers to the tabs (which are invalid for a short time).
6422static CFStringRef *tabLabels = NULL;
6423static int tabLabelsSize = 0;
6424
6425enum
6426{
6427 kTabsColumn = 'Tabs'
6428};
6429
6430 static int
6431getTabCount(void)
6432{
6433 tabpage_T *tp;
6434 int numTabs = 0;
6435
Bram Moolenaar29323592016-07-24 22:04:11 +02006436 FOR_ALL_TABPAGES(tp)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006437 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006438 return numTabs;
6439}
6440
6441// data browser item display callback
6442 static OSStatus
6443dbItemDataCallback(ControlRef browser,
6444 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006445 DataBrowserPropertyID property /* column id */,
6446 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006447 Boolean changeValue)
6448{
6449 OSStatus status = noErr;
6450
6451 // assert(property == kTabsColumn); // why is this violated??
6452
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006453 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006454 // In our case, it's always false.
6455 // (that is: if (changeValue) updateInternalData(); else return
6456 // internalData();
6457 if (!changeValue)
6458 {
6459 CFStringRef str;
6460
6461 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6462 str = tabLabels[itemID - 1];
6463 status = SetDataBrowserItemDataText(itemData, str);
6464 }
6465 else
6466 status = errDataBrowserPropertyNotSupported;
6467
6468 return status;
6469}
6470
6471// data browser action callback
6472 static void
6473dbItemNotificationCallback(ControlRef browser,
6474 DataBrowserItemID item,
6475 DataBrowserItemNotification message)
6476{
6477 switch (message)
6478 {
6479 case kDataBrowserItemSelected:
6480 send_tabline_event(item);
6481 break;
6482 }
6483}
6484
6485// callbacks needed for contextual menu:
6486 static void
6487dbGetContextualMenuCallback(ControlRef browser,
6488 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006489 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006490 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006491 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006492{
6493 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6494 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6495 *helpItemString = NULL;
6496
6497 *menu = contextMenu;
6498}
6499
6500 static void
6501dbSelectContextualMenuCallback(ControlRef browser,
6502 MenuRef menu,
6503 UInt32 selectionType,
6504 SInt16 menuID,
6505 MenuItemIndex menuItem)
6506{
6507 if (selectionType == kCMMenuItemSelected)
6508 {
6509 MenuCommand command;
6510 GetMenuItemCommandID(menu, menuItem, &command);
6511
6512 // get tab that was selected when the context menu appeared
6513 // (there is always one tab selected). TODO: check if the context menu
6514 // isn't opened on an item but on empty space (has to be possible some
6515 // way, the finder does it too ;-) )
6516 Handle items = NewHandle(0);
6517 if (items != NULL)
6518 {
6519 int numItems;
6520
6521 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6522 kDataBrowserItemIsSelected, items);
6523 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6524 if (numItems > 0)
6525 {
6526 int idx;
6527 DataBrowserItemID *itemsPtr;
6528
6529 HLock(items);
6530 itemsPtr = (DataBrowserItemID *)*items;
6531 idx = itemsPtr[0];
6532 HUnlock(items);
6533 send_tabline_menu_event(idx, command);
6534 }
6535 DisposeHandle(items);
6536 }
6537 }
6538}
6539
6540// focus callback of the data browser to always leave focus in vim
6541 static OSStatus
6542dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6543{
6544 assert(GetEventClass(event) == kEventClassControl
6545 && GetEventKind(event) == kEventControlSetFocusPart);
6546
6547 return paramErr;
6548}
6549
6550
6551// drawer callback to resize data browser to drawer size
6552 static OSStatus
6553drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6554{
6555 switch (GetEventKind(event))
6556 {
6557 case kEventWindowBoundsChanged: // move or resize
6558 {
6559 UInt32 attribs;
6560 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6561 NULL, sizeof(attribs), NULL, &attribs);
6562 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6563 {
6564 Rect r;
6565 GetWindowBounds(drawer, kWindowContentRgn, &r);
6566 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6567 SetControlBounds(dataBrowser, &r);
6568 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6569 kTabsColumn, r.right);
6570 }
6571 }
6572 break;
6573 }
6574
6575 return eventNotHandledErr;
6576}
6577
6578// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6579// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6580// blue highlights in the list view on these systems, though. Oh well.)
6581
6582
6583#import <mach-o/dyld.h>
6584
6585enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6586
6587 static OSStatus
6588myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6589 OptionBits inAttributesToSet,
6590 OptionBits inAttributesToClear)
6591{
6592 long osVersion;
6593 char *symbolName;
6594 NSSymbol symbol = NULL;
6595 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6596 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6597
6598 Gestalt(gestaltSystemVersion, &osVersion);
6599 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6600 return noErr;
6601
6602 // C name mangling...
6603 symbolName = "_DataBrowserChangeAttributes";
6604 if (!NSIsSymbolNameDefined(symbolName)
6605 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6606 return noErr;
6607
6608 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6609 if (dataBrowserChangeAttributes == NULL)
6610 return noErr; // well...
6611 return dataBrowserChangeAttributes(inDataBrowser,
6612 inAttributesToSet, inAttributesToClear);
6613}
6614
6615 static void
6616initialise_tabline(void)
6617{
6618 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6619 DataBrowserCallbacks dbCallbacks;
6620 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6621 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6622 DataBrowserListViewColumnDesc colDesc;
6623
6624 // drawers have to have compositing enabled
6625 CreateNewWindow(kDrawerWindowClass,
6626 kWindowStandardHandlerAttribute
6627 | kWindowCompositingAttribute
6628 | kWindowResizableAttribute
6629 | kWindowLiveResizeAttribute,
6630 &drawerRect, &drawer);
6631
6632 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6633 SetDrawerParent(drawer, gui.VimWindow);
6634 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6635
6636
6637 // create list view embedded in drawer
6638 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6639 &dataBrowser);
6640
6641 dbCallbacks.version = kDataBrowserLatestCallbacks;
6642 InitDataBrowserCallbacks(&dbCallbacks);
6643 dbCallbacks.u.v1.itemDataCallback =
6644 NewDataBrowserItemDataUPP(dbItemDataCallback);
6645 dbCallbacks.u.v1.itemNotificationCallback =
6646 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6647 dbCallbacks.u.v1.getContextualMenuCallback =
6648 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6649 dbCallbacks.u.v1.selectContextualMenuCallback =
6650 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6651
6652 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6653
6654 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6655 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6656 SetDataBrowserSelectionFlags(dataBrowser,
6657 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6658 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6659 kDataBrowserTableViewFillHilite);
6660 Boolean b = false;
6661 SetControlData(dataBrowser, kControlEntireControl,
6662 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6663
6664 // enable blue background in data browser (this is only in 10.4 and vim
6665 // has to support older osx versions as well, so we have to load this
6666 // function dynamically)
6667 myDataBrowserChangeAttributes(dataBrowser,
6668 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6669
6670 // install callback that keeps focus in vim and away from the data browser
6671 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6672 NULL, NULL);
6673
6674 // install callback that keeps data browser at the size of the drawer
6675 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6676 NULL, NULL);
6677
6678 // add "tabs" column to data browser
6679 colDesc.propertyDesc.propertyID = kTabsColumn;
6680 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6681
6682 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6683 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6684
6685 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6686 colDesc.headerBtnDesc.minimumWidth = 100;
6687 colDesc.headerBtnDesc.maximumWidth = 150;
6688 colDesc.headerBtnDesc.titleOffset = 0;
6689 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6690 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6691 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6692 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6693
6694 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6695
6696 // create tabline popup menu required by vim docs (see :he tabline-menu)
6697 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar7098ee52015-06-09 19:14:24 +02006698 if (first_tabpage->tp_next != NULL)
6699 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006700 TABLINE_MENU_CLOSE, NULL);
6701 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6702 TABLINE_MENU_NEW, NULL);
6703 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6704 TABLINE_MENU_OPEN, NULL);
6705}
6706
6707
6708/*
6709 * Show or hide the tabline.
6710 */
6711 void
6712gui_mch_show_tabline(int showit)
6713{
6714 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006715 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006716 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006717 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006718}
6719
6720/*
6721 * Return TRUE when tabline is displayed.
6722 */
6723 int
6724gui_mch_showing_tabline(void)
6725{
6726 WindowDrawerState state = GetDrawerState(drawer);
6727
6728 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6729}
6730
6731/*
6732 * Update the labels of the tabline.
6733 */
6734 void
6735gui_mch_update_tabline(void)
6736{
6737 tabpage_T *tp;
6738 int numTabs = getTabCount();
6739 int nr = 1;
6740 int curtabidx = 1;
6741
6742 // adjust data browser
6743 if (tabLabels != NULL)
6744 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006745 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006746
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006747 for (i = 0; i < tabLabelsSize; ++i)
6748 CFRelease(tabLabels[i]);
6749 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006750 }
6751 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6752 tabLabelsSize = numTabs;
6753
6754 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6755 {
6756 if (tp == curtab)
6757 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006758 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006759 }
6760
6761 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6762 kDataBrowserItemNoProperty);
6763 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6764 // can pass NULL for the id array
6765 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6766 kDataBrowserItemNoProperty);
6767
6768 DataBrowserItemID item = curtabidx;
6769 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6770}
6771
6772/*
6773 * Set the current tab to "nr". First tab is 1.
6774 */
6775 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01006776gui_mch_set_curtab(int nr)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006777{
6778 DataBrowserItemID item = nr;
6779 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6780
6781 // TODO: call something like this?: (or restore scroll position, or...)
6782 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6783 kDataBrowserRevealOnly);
6784}
6785
6786#endif // FEAT_GUI_TABLINE