blob: bbb0857a0cdefa4b4e93ff3d7d73366a6b6c2421 [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;
64#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;
68#endif
69
70#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
71
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'}, */
270#ifndef MACOS_X
271 {vk_Delete, 'k', 'b'},
272#endif
273 {vk_Insert, 'k', 'I'},
274 {vk_FwdDelete, 'k', 'D'},
275 {vk_Home, 'k', 'h'},
276 {vk_End, '@', '7'},
277/* {XK_Prior, 'k', 'P'}, */
278/* {XK_Next, 'k', 'N'}, */
279/* {XK_Print, '%', '9'}, */
280
281 {vk_PageUp, 'k', 'P'},
282 {vk_PageDown, 'k', 'N'},
283
284 /* End of list marker: */
285 {(KeySym)0, 0, 0}
286};
287
288/*
289 * ------------------------------------------------------------
290 * Forward declaration (for those needed)
291 * ------------------------------------------------------------
292 */
293
294#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000295OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296#endif
297
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000298#ifdef FEAT_GUI_TABLINE
299static void initialise_tabline(void);
300static WindowRef drawer = NULL; // TODO: put into gui.h
301#endif
302
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000303#ifdef USE_ATSUI_DRAWING
304static void gui_mac_set_font_attributes(GuiFont font);
305static void gui_mac_dispose_atsui_style(void);
306#endif
307
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308/*
309 * ------------------------------------------------------------
310 * Conversion Utility
311 * ------------------------------------------------------------
312 */
313
314/*
315 * C2Pascal_save
316 *
317 * Allocate memory and convert the C-String passed in
318 * into a pascal string
319 *
320 */
321
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000322 char_u *
323C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324{
325 char_u *PascalString;
326 int len;
327
328 if (Cstring == NULL)
329 return NULL;
330
331 len = STRLEN(Cstring);
332
333 if (len > 255) /* Truncate if necessary */
334 len = 255;
335
336 PascalString = alloc(len + 1);
337 if (PascalString != NULL)
338 {
339 mch_memmove(PascalString + 1, Cstring, len);
340 PascalString[0] = len;
341 }
342
343 return PascalString;
344}
345
346/*
347 * C2Pascal_save_and_remove_backslash
348 *
349 * Allocate memory and convert the C-String passed in
350 * into a pascal string. Also remove the backslash at the same time
351 *
352 */
353
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000354 char_u *
355C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356{
357 char_u *PascalString;
358 int len;
359 char_u *p, *c;
360
361 len = STRLEN(Cstring);
362
363 if (len > 255) /* Truncate if necessary */
364 len = 255;
365
366 PascalString = alloc(len + 1);
367 if (PascalString != NULL)
368 {
369 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
370 {
371 if ((*c == '\\') && (c[1] != 0))
372 {
373 c++;
374 }
375 *p = *c;
376 p++;
377 len++;
378 }
379 PascalString[0] = len;
380 }
381
382 return PascalString;
383}
384
385/*
386 * Convert the modifiers of an Event into vim's modifiers (mouse)
387 */
388
389 int_u
390EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
391{
392 int_u vimModifiers = 0x00;
393
394 if (macModifiers & (shiftKey | rightShiftKey))
395 vimModifiers |= MOUSE_SHIFT;
396 if (macModifiers & (controlKey | rightControlKey))
397 vimModifiers |= MOUSE_CTRL;
398 if (macModifiers & (optionKey | rightOptionKey))
399 vimModifiers |= MOUSE_ALT;
400#if 0
401 /* Not yet supported */
402 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
403 vimModifiers |= MOUSE_CMD;
404#endif
405 return (vimModifiers);
406}
407
408/*
409 * Convert the modifiers of an Event into vim's modifiers (keys)
410 */
411
412 static int_u
413EventModifiers2VimModifiers(EventModifiers macModifiers)
414{
415 int_u vimModifiers = 0x00;
416
417 if (macModifiers & (shiftKey | rightShiftKey))
418 vimModifiers |= MOD_MASK_SHIFT;
419 if (macModifiers & (controlKey | rightControlKey))
420 vimModifiers |= MOD_MASK_CTRL;
421 if (macModifiers & (optionKey | rightOptionKey))
422 vimModifiers |= MOD_MASK_ALT;
423#ifdef USE_CMD_KEY
424 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
425 vimModifiers |= MOD_MASK_CMD;
426#endif
427 return (vimModifiers);
428}
429
430/* Convert a string representing a point size into pixels. The string should
431 * be a positive decimal number, with an optional decimal point (eg, "12", or
432 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
433 * character is stored in *end. The flag "vertical" says whether this
434 * calculation is for a vertical (height) size or a horizontal (width) one.
435 *
436 * From gui_w48.c
437 */
438 static int
439points_to_pixels(char_u *str, char_u **end, int vertical)
440{
441 int pixels;
442 int points = 0;
443 int divisor = 0;
444
445 while (*str)
446 {
447 if (*str == '.' && divisor == 0)
448 {
449 /* Start keeping a divisor, for later */
450 divisor = 1;
451 continue;
452 }
453
454 if (!isdigit(*str))
455 break;
456
457 points *= 10;
458 points += *str - '0';
459 divisor *= 10;
460
461 ++str;
462 }
463
464 if (divisor == 0)
465 divisor = 1;
466
467 pixels = points/divisor;
468 *end = str;
469 return pixels;
470}
471
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000472#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000473/*
474 * Deletes all traces of any Windows-style mnemonic text (including any
475 * parentheses) from a menu item and returns the cleaned menu item title.
476 * The caller is responsible for releasing the returned string.
477 */
478 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000479menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000480{
481 CFStringRef name;
482 size_t menuTitleLen;
483 CFIndex displayLen;
484 CFRange mnemonicStart;
485 CFRange mnemonicEnd;
486 CFMutableStringRef cleanedName;
487
488 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000489 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000490
491 if (name)
492 {
493 /* Simple mnemonic-removal algorithm, assumes single parenthesized
494 * mnemonic character towards the end of the menu text */
495 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
496 displayLen = CFStringGetLength(name);
497
498 if (mnemonicStart.location != kCFNotFound
499 && (mnemonicStart.location + 2) < displayLen
500 && CFStringGetCharacterAtIndex(name,
501 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
502 {
503 if (CFStringFindWithOptions(name, CFSTR(")"),
504 CFRangeMake(mnemonicStart.location + 1,
505 displayLen - mnemonicStart.location - 1),
506 kCFCompareBackwards, &mnemonicEnd) &&
507 (mnemonicStart.location + 2) == mnemonicEnd.location)
508 {
509 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
510 if (cleanedName)
511 {
512 CFStringDelete(cleanedName,
513 CFRangeMake(mnemonicStart.location,
514 mnemonicEnd.location + 1 -
515 mnemonicStart.location));
516
517 CFRelease(name);
518 name = cleanedName;
519 }
520 }
521 }
522 }
523
524 return name;
525}
526#endif
527
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528/*
529 * Convert a list of FSSpec aliases into a list of fullpathname
530 * character strings.
531 */
532
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000533 char_u **
534new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535{
536 char_u **fnames = NULL;
537 OSErr newError;
538 long fileCount;
539 FSSpec fileToOpen;
540 long actualSize;
541 AEKeyword dummyKeyword;
542 DescType dummyType;
543
544 /* Get number of files in list */
545 *error = AECountItems(theList, numFiles);
546 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000547 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548
549 /* Allocate the pointer list */
550 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
551
552 /* Empty out the list */
553 for (fileCount = 0; fileCount < *numFiles; fileCount++)
554 fnames[fileCount] = NULL;
555
556 /* Scan the list of FSSpec */
557 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
558 {
559 /* Get the alias for the nth file, convert to an FSSpec */
560 newError = AEGetNthPtr(theList, fileCount, typeFSS,
561 &dummyKeyword, &dummyType,
562 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
563 if (newError)
564 {
565 /* Caller is able to clean up */
566 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000567 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 }
569
570 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000571 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 }
573
574 return (fnames);
575}
576
577/*
578 * ------------------------------------------------------------
579 * CodeWarrior External Editor Support
580 * ------------------------------------------------------------
581 */
582#ifdef FEAT_CW_EDITOR
583
584/*
585 * Handle the Window Search event from CodeWarrior
586 *
587 * Description
588 * -----------
589 *
590 * The IDE sends the Window Search AppleEvent to the editor when it
591 * needs to know whether a particular file is open in the editor.
592 *
593 * Event Reply
594 * -----------
595 *
596 * None. Put data in the location specified in the structure received.
597 *
598 * Remarks
599 * -------
600 *
601 * When the editor receives this event, determine whether the specified
602 * file is open. If it is, return the modification date/time for that file
603 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000604 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 *
606 */
607
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608typedef struct WindowSearch WindowSearch;
609struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
610{
611 FSSpec theFile; // identifies the file
612 long *theDate; // where to put the modification date/time
613};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000615 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000616Handle_KAHL_SRCH_AE(
617 const AppleEvent *theAEvent,
618 AppleEvent *theReply,
619 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620{
621 OSErr error = noErr;
622 buf_T *buf;
623 int foundFile = false;
624 DescType typeCode;
625 WindowSearch SearchData;
626 Size actualSize;
627
628 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
629 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000630 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000632 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000634 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635
Bram Moolenaar29323592016-07-24 22:04:11 +0200636 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 if (buf->b_ml.ml_mfp != NULL
638 && SearchData.theFile.parID == buf->b_FSSpec.parID
639 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
640 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
641 {
642 foundFile = true;
643 break;
644 }
645
646 if (foundFile == false)
647 *SearchData.theDate = fnfErr;
648 else
649 *SearchData.theDate = buf->b_mtime;
650
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 return error;
652};
653
654/*
655 * Handle the Modified (from IDE to Editor) event from CodeWarrior
656 *
657 * Description
658 * -----------
659 *
660 * The IDE sends this event to the external editor when it wants to
661 * know which files that are open in the editor have been modified.
662 *
663 * Parameters None.
664 * ----------
665 *
666 * Event Reply
667 * -----------
668 * The reply for this event is:
669 *
670 * keyDirectObject typeAEList required
671 * each element in the list is a structure of typeChar
672 *
673 * Remarks
674 * -------
675 *
676 * When building the reply event, include one element in the list for
677 * each open file that has been modified.
678 *
679 */
680
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681typedef struct ModificationInfo ModificationInfo;
682struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
683{
684 FSSpec theFile; // identifies the file
685 long theDate; // the date/time the file was last modified
686 short saved; // set this to zero when replying, unused
687};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000688
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000689 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000690Handle_KAHL_MOD_AE(
691 const AppleEvent *theAEvent,
692 AppleEvent *theReply,
693 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694{
695 OSErr error = noErr;
696 AEDescList replyList;
697 long numFiles;
698 ModificationInfo theFile;
699 buf_T *buf;
700
701 theFile.saved = 0;
702
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000703 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000705 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706
707 /* Send the reply */
708/* replyObject.descriptorType = typeNull;
709 replyObject.dataHandle = nil;*/
710
711/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
712 error = AECreateList(nil, 0, false, &replyList);
713 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000714 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715
716#if 0
717 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000719 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
720 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 * sizeof(DescType))
722 */
723
724 /* AEPutDesc */
725#endif
726
727 numFiles = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +0200728 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729 if (buf->b_ml.ml_mfp != NULL)
730 {
731 /* Add this file to the list */
732 theFile.theFile = buf->b_FSSpec;
733 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000734/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
735 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 };
737
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#if 0
739 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740#endif
741
742 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000743 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 if (replyList.dataHandle)
746 AEDisposeDesc(&replyList);
747
748 return error;
749};
750
751/*
752 * Handle the Get Text event from CodeWarrior
753 *
754 * Description
755 * -----------
756 *
757 * The IDE sends the Get Text AppleEvent to the editor when it needs
758 * the source code from a file. For example, when the user issues a
759 * Check Syntax or Compile command, the compiler needs access to
760 * the source code contained in the file.
761 *
762 * Event Reply
763 * -----------
764 *
765 * None. Put data in locations specified in the structure received.
766 *
767 * Remarks
768 * -------
769 *
770 * When the editor receives this event, it must set the size of the handle
771 * in theText to fit the data in the file. It must then copy the entire
772 * contents of the specified file into the memory location specified in
773 * theText.
774 *
775 */
776
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777typedef struct CW_GetText CW_GetText;
778struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
779{
780 FSSpec theFile; /* identifies the file */
781 Handle theText; /* the location where you return the text (must be resized properly) */
782 long *unused; /* 0 (not used) */
783 long *theDate; /* where to put the modification date/time */
784};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000786 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000787Handle_KAHL_GTTX_AE(
788 const AppleEvent *theAEvent,
789 AppleEvent *theReply,
790 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791{
792 OSErr error = noErr;
793 buf_T *buf;
794 int foundFile = false;
795 DescType typeCode;
796 CW_GetText GetTextData;
797 Size actualSize;
798 char_u *line;
799 char_u *fullbuffer = NULL;
800 long linesize;
801 long lineStart;
802 long BufferSize;
803 long lineno;
804
805 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
806
807 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000808 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809
Bram Moolenaar29323592016-07-24 22:04:11 +0200810 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 if (buf->b_ml.ml_mfp != NULL)
812 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
813 {
814 foundFile = true;
815 break;
816 }
817
818 if (foundFile)
819 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000820 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
822 {
823 /* Must use the right buffer */
824 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
825 linesize = STRLEN(line) + 1;
826 lineStart = BufferSize;
827 BufferSize += linesize;
828 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000829 SetHandleSize(GetTextData.theText, BufferSize);
830 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 break; /* Simple handling for now */
833 }
834 else
835 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000840 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 }
842 }
843 if (fullbuffer != NULL)
844 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000847 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 }
849 if (foundFile == false)
850 *GetTextData.theDate = fnfErr;
851 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000852/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 *GetTextData.theDate = buf->b_mtime;
854 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000856 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000858 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859}
860
861/*
862 *
863 */
864
865/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000866 pascal OSErr
867FindProcessBySignature(
868 const OSType targetType,
869 const OSType targetCreator,
870 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871{
872 OSErr anErr = noErr;
873 Boolean lookingForProcess = true;
874
875 ProcessInfoRec infoRec;
876
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000877 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 infoRec.processName = nil;
879 infoRec.processAppSpec = nil;
880
881 psnPtr->lowLongOfPSN = kNoProcess;
882 psnPtr->highLongOfPSN = kNoProcess;
883
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000886 anErr = GetNextProcess(psnPtr);
887 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 else
890 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000891 anErr = GetProcessInformation(psnPtr, &infoRec);
892 if ((anErr == noErr)
893 && (infoRec.processType == targetType)
894 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 }
897 }
898
899 return anErr;
900}//end FindProcessBySignature
901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000902 void
903Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000905 OSErr anErr = noErr;
906 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
908 AppleEvent theReply = { typeNull, nil };
909 AESendMode sendMode;
910 AppleEvent theEvent = {typeNull, nil };
911 AEIdleUPP idleProcUPP = nil;
912 ModificationInfo ModData;
913
914
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000915 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000918 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
919 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000921 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 {
923 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
924 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
925 }
926
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000927 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928
929 /* Add the parms */
930 ModData.theFile = buf->b_FSSpec;
931 ModData.theDate = buf->b_mtime;
932
933 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000936 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 sendMode = kAENoReply;
938 else
939 sendMode = kAEWaitReply;
940
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000941 if (anErr == noErr)
942 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
943 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000945/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000947 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948 }
949}
950#endif /* FEAT_CW_EDITOR */
951
952/*
953 * ------------------------------------------------------------
954 * Apple Event Handling procedure
955 * ------------------------------------------------------------
956 */
957#ifdef USE_AEVENT
958
959/*
960 * Handle the Unused parms of an AppleEvent
961 */
962
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000963 OSErr
964HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965{
966 OSErr error;
967 long actualSize;
968 DescType dummyType;
969 AEKeyword missedKeyword;
970
971 /* Get the "missed keyword" attribute from the AppleEvent. */
972 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
973 typeKeyword, &dummyType,
974 (Ptr)&missedKeyword, sizeof(missedKeyword),
975 &actualSize);
976
977 /* If the descriptor isn't found, then we got the required parameters. */
978 if (error == errAEDescNotFound)
979 {
980 error = noErr;
981 }
982 else
983 {
984#if 0
985 /* Why is this removed? */
986 error = errAEEventNotHandled;
987#endif
988 }
989
990 return error;
991}
992
993
994/*
995 * Handle the ODoc AppleEvent
996 *
997 * Deals with all files dragged to the application icon.
998 *
999 */
1000
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001typedef struct SelectionRange SelectionRange;
1002struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1003{
1004 short unused1; // 0 (not used)
1005 short lineNum; // line to select (<0 to specify range)
1006 long startRange; // start of selection range (if line < 0)
1007 long endRange; // end of selection range (if line < 0)
1008 long unused2; // 0 (not used)
1009 long theDate; // modification date/time
1010};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011
1012/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1013 itor the selection range. If lineNum is zero or greater, scroll the text
1014 to the specified line. If lineNum is less than zero, use the values in
1015 startRange and endRange to select the specified characters. Scroll
1016 the text to display the selection. If lineNum, startRange, and
1017 endRange are all negative, there is no selection range specified.
1018 */
1019
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001020 pascal OSErr
1021HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022{
1023 /*
1024 * TODO: Clean up the code with convert the AppleEvent into
1025 * a ":args"
1026 */
1027 OSErr error = noErr;
1028// OSErr firstError = noErr;
1029// short numErrors = 0;
1030 AEDesc theList;
1031 DescType typeCode;
1032 long numFiles;
1033 // long fileCount;
1034 char_u **fnames;
1035// char_u fname[256];
1036 Size actualSize;
1037 SelectionRange thePosition;
1038 short gotPosition = false;
1039 long lnum;
1040
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041 /* the direct object parameter is the list of aliases to files (one or more) */
1042 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1043 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001044 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045
1046
1047 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1048 if (error == noErr)
1049 gotPosition = true;
1050 if (error == errAEDescNotFound)
1051 error = noErr;
1052 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001053 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055/*
1056 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1057
1058 if (^error) then
1059 {
1060 if (thePosition.lineNum >= 0)
1061 {
1062 // Goto this line
1063 }
1064 else
1065 {
1066 // Set the range char wise
1067 }
1068 }
1069 */
1070
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1073
1074 if (error)
1075 {
1076 /* TODO: empty fnames[] first */
1077 vim_free(fnames);
1078 return (error);
1079 }
1080
1081 if (starting > 0)
1082 {
1083 int i;
1084 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001085 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086
1087 /* these are the initial files dropped on the Vim icon */
1088 for (i = 0 ; i < numFiles; i++)
1089 {
1090 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1091 || (p = vim_strsave(fnames[i])) == NULL)
1092 mch_exit(2);
1093 else
1094 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001095 if (fnum == -1)
1096 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1097 }
1098
1099 /* If the file name was already in the buffer list we need to switch
1100 * to it. */
1101 if (curbuf->b_fnum != fnum)
1102 {
1103 char_u cmd[30];
1104
1105 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1106 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001108
1109 /* Change directory to the location of the first file. */
1110 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1111 shorten_fnames(TRUE);
1112
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113 goto finished;
1114 }
1115
1116 /* Handle the drop, :edit to get to the file */
1117 handle_drop(numFiles, fnames, FALSE);
1118
1119 /* TODO: Handle the goto/select line more cleanly */
1120 if ((numFiles == 1) & (gotPosition))
1121 {
1122 if (thePosition.lineNum >= 0)
1123 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001124 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 /* oap->motion_type = MLINE;
1126 setpcmark();*/
1127 if (lnum < 1L)
1128 lnum = 1L;
1129 else if (lnum > curbuf->b_ml.ml_line_count)
1130 lnum = curbuf->b_ml.ml_line_count;
1131 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001132 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 /* beginline(BL_SOL | BL_FIX);*/
1134 }
1135 else
1136 goto_byte(thePosition.startRange + 1);
1137 }
1138
1139 /* Update the screen display */
1140 update_screen(NOT_VALID);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001141
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001142 /* Select the text if possible */
1143 if (gotPosition)
1144 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001145 VIsual_active = TRUE;
1146 VIsual_select = FALSE;
1147 VIsual = curwin->w_cursor;
1148 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001149 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001150 VIsual_mode = 'v';
1151 goto_byte(thePosition.endRange);
1152 }
1153 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001154 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001155 VIsual_mode = 'V';
1156 VIsual.col = 0;
1157 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001158 }
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001159
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 setcursor();
1161 out_flush();
1162
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001163 /* Fake mouse event to wake from stall */
1164 PostEvent(mouseUp, 0);
1165
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001166finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 AEDisposeDesc(&theList); /* dispose what we allocated */
1168
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001169 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001170 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171}
1172
1173/*
1174 *
1175 */
1176
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001177 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001178Handle_aevt_oapp_AE(
1179 const AppleEvent *theAEvent,
1180 AppleEvent *theReply,
1181 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182{
1183 OSErr error = noErr;
1184
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001185 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001186 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187}
1188
1189/*
1190 *
1191 */
1192
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001193 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001194Handle_aevt_quit_AE(
1195 const AppleEvent *theAEvent,
1196 AppleEvent *theReply,
1197 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198{
1199 OSErr error = noErr;
1200
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001201 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001203 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204
1205 /* Need to fake a :confirm qa */
1206 do_cmdline_cmd((char_u *)"confirm qa");
1207
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001208 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209}
1210
1211/*
1212 *
1213 */
1214
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001215 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001216Handle_aevt_pdoc_AE(
1217 const AppleEvent *theAEvent,
1218 AppleEvent *theReply,
1219 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220{
1221 OSErr error = noErr;
1222
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001223 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001225 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226}
1227
1228/*
1229 * Handling of unknown AppleEvent
1230 *
1231 * (Just get rid of all the parms)
1232 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001233 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001234Handle_unknown_AE(
1235 const AppleEvent *theAEvent,
1236 AppleEvent *theReply,
1237 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238{
1239 OSErr error = noErr;
1240
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001241 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001243 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244}
1245
1246
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247/*
1248 * Install the various AppleEvent Handlers
1249 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001250 OSErr
1251InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252{
1253 OSErr error;
1254
1255 /* install open application handler */
1256 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001257 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 if (error)
1259 {
1260 return error;
1261 }
1262
1263 /* install quit application handler */
1264 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001265 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 if (error)
1267 {
1268 return error;
1269 }
1270
1271 /* install open document handler */
1272 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001273 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274 if (error)
1275 {
1276 return error;
1277 }
1278
1279 /* install print document handler */
1280 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001281 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282
1283/* Install Core Suite */
1284/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001285 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286
1287 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001288 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289
1290 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001291 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292
1293 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001294 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295
1296 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001297 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298
1299 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001300 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
1302 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001303 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304
1305 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001306 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
1308 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001309 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310
1311 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001312 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313
1314 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001315 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316
1317 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001318 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319
1320 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001321 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322*/
1323
1324#ifdef FEAT_CW_EDITOR
1325 /*
1326 * Bind codewarrior support handlers
1327 */
1328 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001329 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330 if (error)
1331 {
1332 return error;
1333 }
1334 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001335 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 if (error)
1337 {
1338 return error;
1339 }
1340 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001341 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 if (error)
1343 {
1344 return error;
1345 }
1346#endif
1347
1348 return error;
1349
1350}
1351#endif /* USE_AEVENT */
1352
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001353
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001354/*
1355 * Callback function, installed by InstallFontPanelHandler(), below,
1356 * to handle Font Panel events.
1357 */
1358 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001359FontPanelHandler(
1360 EventHandlerCallRef inHandlerCallRef,
1361 EventRef inEvent,
1362 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001363{
1364 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1365 {
1366 gFontPanelInfo.isPanelVisible = false;
1367 return noErr;
1368 }
1369
1370 if (GetEventKind(inEvent) == kEventFontSelection)
1371 {
1372 OSStatus status;
1373 FMFontFamily newFamily;
1374 FMFontSize newSize;
1375 FMFontStyle newStyle;
1376
1377 /* Retrieve the font family ID number. */
1378 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1379 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1380 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1381 &newFamily);
1382 if (status == noErr)
1383 gFontPanelInfo.family = newFamily;
1384
1385 /* Retrieve the font size. */
1386 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1387 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1388 if (status == noErr)
1389 gFontPanelInfo.size = newSize;
1390
1391 /* Retrieve the font style (bold, etc.). Currently unused. */
1392 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1393 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1394 if (status == noErr)
1395 gFontPanelInfo.style = newStyle;
1396 }
1397 return noErr;
1398}
1399
1400
1401 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001402InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001403{
1404 EventTypeSpec eventTypes[2];
1405 EventHandlerUPP handlerUPP;
1406 /* EventHandlerRef handlerRef; */
1407
1408 eventTypes[0].eventClass = kEventClassFont;
1409 eventTypes[0].eventKind = kEventFontSelection;
1410 eventTypes[1].eventClass = kEventClassFont;
1411 eventTypes[1].eventKind = kEventFontPanelClosed;
1412
1413 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1414
1415 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1416 /*userData=*/NULL, /*handlerRef=*/NULL);
1417}
1418
1419
1420/*
1421 * Fill the buffer pointed to by outName with the name and size
1422 * of the font currently selected in the Font Panel.
1423 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001424#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001425 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001426GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001427{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428 Str255 buf;
1429 ByteCount fontNameLen = 0;
1430 ATSUFontID fid;
1431 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001432
1433 if (!outName)
1434 return;
1435
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001436 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1437 {
1438 /* Canonicalize localized font names */
1439 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1440 gFontPanelInfo.style, &fid, NULL) != noErr)
1441 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001442
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001443 /* Request font name with Mac encoding (otherwise we could
1444 * get an unwanted utf-16 name) */
1445 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1446 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001447 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001448 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001449
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001450 /* Only encode font size, because style (bold, italic, etc) is
1451 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001452 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001453 gFontPanelInfo.size/*,
1454 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1455 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1456 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1457
1458 if ((fontNameLen + STRLEN(styleString)) < 255)
1459 STRCPY(outName + fontNameLen, styleString);
1460 }
1461 else
1462 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001463 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001464 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001465}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001466
1467
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468/*
1469 * ------------------------------------------------------------
1470 * Unfiled yet
1471 * ------------------------------------------------------------
1472 */
1473
1474/*
1475 * gui_mac_get_menu_item_index
1476 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001477 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001479 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001480gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481{
1482 short index;
1483 short itemIndex = -1;
1484 vimmenu_T *pBrother;
1485
1486 /* Only menu without parent are the:
1487 * -menu in the menubar
1488 * -popup menu
1489 * -toolbar (guess)
1490 *
1491 * Which are not items anyway.
1492 */
1493 if (pMenu->parent)
1494 {
1495 /* Start from the Oldest Brother */
1496 pBrother = pMenu->parent->children;
1497 index = 1;
1498 while ((pBrother) && (itemIndex == -1))
1499 {
1500 if (pBrother == pMenu)
1501 itemIndex = index;
1502 index++;
1503 pBrother = pBrother->next;
1504 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 }
1506 return itemIndex;
1507}
1508
1509 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001510gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511{
1512 short index;
1513 vimmenu_T *pChildMenu;
1514 vimmenu_T *pElder = pMenu->parent;
1515
1516
1517 /* Only menu without parent are the:
1518 * -menu in the menubar
1519 * -popup menu
1520 * -toolbar (guess)
1521 *
1522 * Which are not items anyway.
1523 */
1524
1525 if ((pElder) && (pElder->submenu_id == menuID))
1526 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1528 pMenu = pMenu->next;
1529 }
1530 else
1531 {
1532 for (; pMenu != NULL; pMenu = pMenu->next)
1533 {
1534 if (pMenu->children != NULL)
1535 {
1536 pChildMenu = gui_mac_get_vim_menu
1537 (menuID, itemIndex, pMenu->children);
1538 if (pChildMenu)
1539 {
1540 pMenu = pChildMenu;
1541 break;
1542 }
1543 }
1544 }
1545 }
1546 return pMenu;
1547}
1548
1549/*
1550 * ------------------------------------------------------------
1551 * MacOS Feedback procedures
1552 * ------------------------------------------------------------
1553 */
1554 pascal
1555 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001556gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557{
1558 scrollbar_T *sb;
1559 int value, dragging;
1560 ControlHandle theControlToUse;
1561 int dont_scroll_save = dont_scroll;
1562
1563 theControlToUse = dragged_sb;
1564
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001565 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566
1567 if (sb == NULL)
1568 return;
1569
1570 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001571 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572 dragging = (partCode != 0);
1573
1574 /* When "allow_scrollbar" is FALSE still need to remember the new
1575 * position, but don't actually scroll by setting "dont_scroll". */
1576 dont_scroll = !allow_scrollbar;
1577 gui_drag_scrollbar(sb, value, dragging);
1578 dont_scroll = dont_scroll_save;
1579}
1580
1581 pascal
1582 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001583gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001584{
1585 /* TODO: have live support */
1586 scrollbar_T *sb, *sb_info;
1587 long data;
1588 long value;
1589 int page;
1590 int dragging = FALSE;
1591 int dont_scroll_save = dont_scroll;
1592
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001593 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594
1595 if (sb == NULL)
1596 return;
1597
1598 if (sb->wp != NULL) /* Left or right scrollbar */
1599 {
1600 /*
1601 * Careful: need to get scrollbar info out of first (left) scrollbar
1602 * for window, but keep real scrollbar too because we must pass it to
1603 * gui_drag_scrollbar().
1604 */
1605 sb_info = &sb->wp->w_scrollbars[0];
1606
1607 if (sb_info->size > 5)
1608 page = sb_info->size - 2; /* use two lines of context */
1609 else
1610 page = sb_info->size;
1611 }
1612 else /* Bottom scrollbar */
1613 {
1614 sb_info = sb;
Bram Moolenaar02631462017-09-22 15:20:32 +02001615 page = curwin->w_width - 5;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 }
1617
1618 switch (partCode)
1619 {
1620 case kControlUpButtonPart: data = -1; break;
1621 case kControlDownButtonPart: data = 1; break;
1622 case kControlPageDownPart: data = page; break;
1623 case kControlPageUpPart: data = -page; break;
1624 default: data = 0; break;
1625 }
1626
1627 value = sb_info->value + data;
1628/* if (value > sb_info->max)
1629 value = sb_info->max;
1630 else if (value < 0)
1631 value = 0;*/
1632
1633 /* When "allow_scrollbar" is FALSE still need to remember the new
1634 * position, but don't actually scroll by setting "dont_scroll". */
1635 dont_scroll = !allow_scrollbar;
1636 gui_drag_scrollbar(sb, value, dragging);
1637 dont_scroll = dont_scroll_save;
1638
1639 out_flush();
1640 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1641
1642/* if (sb_info->wp != NULL)
1643 {
1644 win_T *wp;
1645 int sb_num;
1646
1647 sb_num = 0;
1648 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1649 sb_num++;
1650
1651 if (wp != NULL)
1652 {
1653 current_scrollbar = sb_num;
1654 scrollbar_value = value;
1655 gui_do_scroll();
1656 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1657 }
1658 }*/
1659}
1660
1661/*
1662 * ------------------------------------------------------------
1663 * MacOS Click Handling procedures
1664 * ------------------------------------------------------------
1665 */
1666
1667
1668/*
1669 * Handle a click inside the window, it may happens in the
1670 * scrollbar or the contents.
1671 *
1672 * TODO: Add support for potential TOOLBAR
1673 */
1674 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001675gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676{
1677 Point thePoint;
1678 int_u vimModifiers;
1679 short thePortion;
1680 ControlHandle theControl;
1681 int vimMouseButton;
1682 short dblClick;
1683
1684 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001685 GlobalToLocal(&thePoint);
1686 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001688 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689
1690 if (theControl != NUL)
1691 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001692 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693
1694 if (thePortion != kControlIndicatorPart)
1695 {
1696 dragged_sb = theControl;
1697 TrackControl(theControl, thePoint, gScrollAction);
1698 dragged_sb = NULL;
1699 }
1700 else
1701 {
1702 dragged_sb = theControl;
1703#if 1
1704 TrackControl(theControl, thePoint, gScrollDrag);
1705#else
1706 TrackControl(theControl, thePoint, NULL);
1707#endif
1708 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1709 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001710 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 dragged_sb = NULL;
1712 }
1713 }
1714 else
1715 {
1716 /* We are inside the contents */
1717
1718 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1719 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1720
1721 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1722 vimMouseButton = MOUSE_LEFT;
1723
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001725 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 clickIsPopup = FALSE;
1727
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001728 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1729 {
1730 vimMouseButton = MOUSE_RIGHT;
1731 vimModifiers &= ~MOUSE_CTRL;
1732 clickIsPopup = TRUE;
1733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734
1735 /* Is it a double click ? */
1736 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1737
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001738 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 gui_send_mouse_event(vimMouseButton, thePoint.h,
1740 thePoint.v, dblClick, vimModifiers);
1741
1742 /* Create the rectangle around the cursor to detect
1743 * the mouse dragging
1744 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745#if 0
1746 /* TODO: Do we need to this even for the contextual menu?
1747 * It may be require for popup_setpos, but for popup?
1748 */
1749 if (vimMouseButton == MOUSE_LEFT)
1750#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001752 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753 FILL_Y(Y_2_ROW(thePoint.v)),
1754 FILL_X(X_2_COL(thePoint.h)+1),
1755 FILL_Y(Y_2_ROW(thePoint.v)+1));
1756
1757 dragRectEnbl = TRUE;
1758 dragRectControl = kCreateRect;
1759 }
1760 }
1761}
1762
1763/*
1764 * Handle the click in the titlebar (to move the window)
1765 */
1766 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001767gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768{
1769 Rect movingLimits;
1770 Rect *movingLimitsPtr = &movingLimits;
1771
1772 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001773 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001774 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775}
1776
1777/*
1778 * Handle the click in the grow box
1779 */
1780 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001781gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782{
1783
1784 long newSize;
1785 unsigned short newWidth;
1786 unsigned short newHeight;
1787 Rect resizeLimits;
1788 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 Rect NewContentRect;
1790
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001791 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792
Bram Moolenaar720c7102007-05-10 18:07:50 +00001793 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 /* TODO: Should this come from Vim? */
1795 resizeLimits.top = 100;
1796 resizeLimits.left = 100;
1797
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1799 newWidth = NewContentRect.right - NewContentRect.left;
1800 newHeight = NewContentRect.bottom - NewContentRect.top;
1801 gui_resize_shell(newWidth, newHeight);
1802 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001803 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804}
1805
1806/*
1807 * Handle the click in the zoom box
1808 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001810gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811{
1812 Rect r;
1813 Point p;
1814 short thePart;
1815
1816 /* ideal width is current */
1817 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1818 if (gui.which_scrollbars[SBAR_LEFT])
1819 p.h += gui.scrollbar_width;
1820 if (gui.which_scrollbars[SBAR_RIGHT])
1821 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001822 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 p.v = 15 * 1024;
1824
1825 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1826 ? inZoomIn : inZoomOut;
1827
1828 if (!TrackBox(whichWindow, theEvent->where, thePart))
1829 return;
1830
1831 /* use returned width */
1832 p.h = r.right - r.left;
1833 /* adjust returned height */
1834 p.v = r.bottom - r.top - 2 * gui.border_offset;
1835 if (gui.which_scrollbars[SBAR_BOTTOM])
1836 p.v -= gui.scrollbar_height;
1837 p.v -= p.v % gui.char_height;
1838 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001839 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840 p.v += gui.scrollbar_height;
1841
1842 ZoomWindowIdeal(whichWindow, thePart, &p);
1843
1844 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1845 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1846 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001847 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849
1850/*
1851 * ------------------------------------------------------------
1852 * MacOS Event Handling procedure
1853 * ------------------------------------------------------------
1854 */
1855
1856/*
1857 * Handle the Update Event
1858 */
1859
1860 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001861gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862{
1863 WindowPtr whichWindow;
1864 GrafPtr savePort;
1865 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001867 Rect *updateRectPtr;
1868 Rect rc;
1869 Rect growRect;
1870 RgnHandle saveRgn;
1871
1872
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 updateRgn = NewRgn();
1874 if (updateRgn == NULL)
1875 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 /* This could be done by the caller as we
1878 * don't require anything else out of the event
1879 */
1880 whichWindow = (WindowPtr) event->message;
1881
1882 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001883 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884
1885 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001886 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887
1888 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 /* Redraw the biggest rectangle covering the area
1891 * to be updated.
1892 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1894# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001895 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 * seem to work under MacOS X (Dany)
1897 */
1898 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1899# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001900
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001902 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001904 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905# if 0
1906 /* Code from original Carbon Port (using GetWindowRegion.
1907 * I believe the UpdateRgn is already in local (Dany)
1908 */
1909 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1910 GlobalToLocal(&botRight(updateRect));
1911# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 /* Update the content (i.e. the text) */
1913 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1914 updateRectPtr->right - updateRectPtr->left,
1915 updateRectPtr->bottom - updateRectPtr->top);
1916 /* Clear the border areas if needed */
1917 gui_mch_set_bg_color(gui.back_pixel);
1918 if (updateRectPtr->left < FILL_X(0))
1919 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001920 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1921 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 }
1923 if (updateRectPtr->top < FILL_Y(0))
1924 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001925 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1926 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927 }
1928 if (updateRectPtr->right > FILL_X(Columns))
1929 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001930 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001932 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 }
1934 if (updateRectPtr->bottom > FILL_Y(Rows))
1935 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001936 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001938 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001941 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942
1943 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001944 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 /* Update the GrowBox */
1947 /* Taken from FAQ 33-27 */
1948 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001950 GetClip(saveRgn);
1951 ClipRect(&growRect);
1952 DrawGrowIcon(whichWindow);
1953 SetClip(saveRgn);
1954 DisposeRgn(saveRgn);
1955 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956
1957 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001958 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959}
1960
1961/*
1962 * Handle the activate/deactivate event
1963 * (apply to a window)
1964 */
1965 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001966gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967{
1968 WindowPtr whichWindow;
1969
1970 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001971 /* Dim scrollbars */
1972 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001974 ControlRef rootControl;
1975 GetRootControl(gui.VimWindow, &rootControl);
1976 if ((event->modifiers) & activeFlag)
1977 ActivateControl(rootControl);
1978 else
1979 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001981
1982 /* Activate */
1983 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984}
1985
1986
1987/*
1988 * Handle the suspend/resume event
1989 * (apply to the application)
1990 */
1991 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001992gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993{
1994 /* The frontmost application just changed */
1995
1996 /* NOTE: the suspend may happen before the deactivate
1997 * seen on MacOS X
1998 */
1999
2000 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002001 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 */
2003 if (event->message & 1)
2004 /* Resume */
2005 gui_focus_change(TRUE);
2006 else
2007 /* Suspend */
2008 gui_focus_change(FALSE);
2009}
2010
2011/*
2012 * Handle the key
2013 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002014#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002015 static pascal OSStatus
2016gui_mac_handle_window_activate(
2017 EventHandlerCallRef nextHandler,
2018 EventRef theEvent,
2019 void *data)
2020{
2021 UInt32 eventClass = GetEventClass(theEvent);
2022 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002023
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002024 if (eventClass == kEventClassWindow)
2025 {
2026 switch (eventKind)
2027 {
2028 case kEventWindowActivated:
2029#if defined(USE_IM_CONTROL)
2030 im_on_window_switch(TRUE);
2031#endif
2032 return noErr;
2033
2034 case kEventWindowDeactivated:
2035#if defined(USE_IM_CONTROL)
2036 im_on_window_switch(FALSE);
2037#endif
2038 return noErr;
2039 }
2040 }
2041
2042 return eventNotHandledErr;
2043}
2044
2045 static pascal OSStatus
2046gui_mac_handle_text_input(
2047 EventHandlerCallRef nextHandler,
2048 EventRef theEvent,
2049 void *data)
2050{
2051 UInt32 eventClass = GetEventClass(theEvent);
2052 UInt32 eventKind = GetEventKind(theEvent);
2053
2054 if (eventClass != kEventClassTextInput)
2055 return eventNotHandledErr;
2056
2057 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2058 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2059 (kEventTextInputOffsetToPos != eventKind) &&
2060 (kEventTextInputPosToOffset != eventKind) &&
2061 (kEventTextInputGetSelectedText != eventKind))
2062 return eventNotHandledErr;
2063
2064 switch (eventKind)
2065 {
2066 case kEventTextInputUpdateActiveInputArea:
2067 return gui_mac_update_input_area(nextHandler, theEvent);
2068 case kEventTextInputUnicodeForKeyEvent:
2069 return gui_mac_unicode_key_event(nextHandler, theEvent);
2070
2071 case kEventTextInputOffsetToPos:
2072 case kEventTextInputPosToOffset:
2073 case kEventTextInputGetSelectedText:
2074 break;
2075 }
2076
2077 return eventNotHandledErr;
2078}
2079
2080 static pascal
2081OSStatus gui_mac_update_input_area(
2082 EventHandlerCallRef nextHandler,
2083 EventRef theEvent)
2084{
2085 return eventNotHandledErr;
2086}
2087
2088static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2089 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002090
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002091# define INLINE_KEY_BUFFER_SIZE 80
2092 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002093gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002094 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002095 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002096{
2097 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002098 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002099 UInt32 actualSize;
2100 UniChar *text;
2101 char_u result[INLINE_KEY_BUFFER_SIZE];
2102 short len = 0;
2103 UInt32 key_sym;
2104 char charcode;
2105 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002106 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002107 size_t encLen;
2108 char_u *to = NULL;
2109 Boolean isSpecial = FALSE;
2110 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002111 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002113 /* Mask the mouse (as per user setting) */
2114 if (p_mh)
2115 ObscureCursor();
2116
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002117 /* Don't use the keys when the dialog wants them. */
2118 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002119 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002120
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002121 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002122 typeUnicodeText, NULL, 0, &actualSize, NULL))
2123 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002124
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002125 text = (UniChar *)alloc(actualSize);
2126 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002127 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002128
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002129 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002130 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002131 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002132
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002134 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002135 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002136
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002137 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002138 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002139 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002140
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002141 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002142 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002144
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002146 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002147 require_noerr(err, done);
2148
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002149#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002150 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002151 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002153
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002154 key_char = charcode;
2155 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002156
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002157 /* Find the special key (eg., for cursor keys) */
2158 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002159 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002160 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002161 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2162 if (special_keys[i].key_sym == key_sym)
2163 {
2164 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2165 special_keys[i].vim_code1);
2166 key_char = simplify_key(key_char,
2167 (int *)&vimModifiers);
2168 isSpecial = TRUE;
2169 break;
2170 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002171 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002172
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002173 /* Intercept CMD-. and CTRL-c */
2174 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002175 ((modifiers & cmdKey) && key_char == '.'))
2176 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002177
2178 if (!isSpecial)
2179 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002180 /* remove SHIFT for keys that are already shifted, e.g.,
2181 * '(' and '*' */
2182 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2183 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002184
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002185 /* remove CTRL from keys that already have it */
2186 if (key_char < 0x20)
2187 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002188
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002189 /* don't process unicode characters here */
2190 if (!IS_SPECIAL(key_char))
2191 {
2192 /* Following code to simplify and consolidate vimModifiers
2193 * taken liberally from gui_w48.c */
2194 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002195
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002196 /* Interpret META, include SHIFT, etc. */
2197 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2198 if (key_char == CSI)
2199 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002200
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002201 if (IS_SPECIAL(key_char))
2202 isSpecial = TRUE;
2203 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002204 }
2205
2206 if (vimModifiers)
2207 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002208 result[len++] = CSI;
2209 result[len++] = KS_MODIFIER;
2210 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002211 }
2212
2213 if (isSpecial && IS_SPECIAL(key_char))
2214 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002215 result[len++] = CSI;
2216 result[len++] = K_SECOND(key_char);
2217 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002218 }
2219 else
2220 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002221 encLen = actualSize;
2222 to = mac_utf16_to_enc(text, actualSize, &encLen);
2223 if (to)
2224 {
2225 /* This is basically add_to_input_buf_csi() */
2226 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2227 {
2228 result[len++] = to[i];
2229 if (to[i] == CSI)
2230 {
2231 result[len++] = KS_EXTRA;
2232 result[len++] = (int)KE_CSI;
2233 }
2234 }
2235 vim_free(to);
2236 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002237 }
2238
2239 add_to_input_buf(result, len);
2240 err = noErr;
2241
2242done:
2243 vim_free(text);
2244 if (err == noErr)
2245 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002246 /* Fake event to wake up WNE (required to get
2247 * key repeat working */
2248 PostEvent(keyUp, 0);
2249 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002250 }
2251
2252 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002253}
2254#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 void
2256gui_mac_doKeyEvent(EventRecord *theEvent)
2257{
2258 /* TODO: add support for COMMAND KEY */
2259 long menu;
2260 unsigned char string[20];
2261 short num, i;
2262 short len = 0;
2263 KeySym key_sym;
2264 int key_char;
2265 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002266 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267
2268 /* Mask the mouse (as per user setting) */
2269 if (p_mh)
2270 ObscureCursor();
2271
2272 /* Get the key code and it's ASCII representation */
2273 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2274 key_char = theEvent->message & charCodeMask;
2275 num = 1;
2276
2277 /* Intercept CTRL-C */
2278 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002279 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280 if (key_char == Ctrl_C && ctrl_c_interrupts)
2281 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002282 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2283 && (key_char == '2' || key_char == '6'))
2284 {
2285 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2286 if (key_char == '2')
2287 key_char = Ctrl_AT;
2288 else
2289 key_char = Ctrl_HAT;
2290 theEvent->modifiers = 0;
2291 }
2292 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293
2294 /* Intercept CMD-. */
2295 if (theEvent->modifiers & cmdKey)
2296 if (key_char == '.')
2297 got_int = TRUE;
2298
2299 /* Handle command key as per menu */
2300 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2301 if (theEvent->modifiers & cmdKey)
2302 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2303 * Why the mouse button? */
2304 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2305 {
2306 menu = MenuKey(key_char);
2307 if (HiWord(menu))
2308 {
2309 gui_mac_handle_menu(menu);
2310 return;
2311 }
2312 }
2313
2314 /* Convert the modifiers */
2315 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2316
2317
2318 /* Handle special keys. */
2319#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002320 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2322#endif
2323 {
2324 /* Find the special key (for non-printable keyt_char) */
2325 if ((key_char < 0x20) || (key_char == 0x7f))
2326 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2327 if (special_keys[i].key_sym == key_sym)
2328 {
2329# if 0
2330 /* We currently don't have not so special key */
2331 if (special_keys[i].vim_code1 == NUL)
2332 key_char = special_keys[i].vim_code0;
2333 else
2334# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002335 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2336 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002337 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338 break;
2339 }
2340 }
2341
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002342 /* For some keys the modifier is included in the char itself. */
2343 if (simplify || key_char == TAB || key_char == ' ')
2344 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345
2346 /* Add the modifier to the input bu if needed */
2347 /* Do not want SHIFT-A or CTRL-A with modifier */
2348 if (!IS_SPECIAL(key_char)
2349 && key_sym != vk_Space
2350 && key_sym != vk_Tab
2351 && key_sym != vk_Return
2352 && key_sym != vk_Enter
2353 && key_sym != vk_Esc)
2354 {
2355#if 1
2356 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002357 if ((modifiers == MOD_MASK_SHIFT)
2358 || (modifiers == MOD_MASK_CTRL)
2359 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 modifiers = 0;
2361#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002362 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002364 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002366 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 modifiers = modifiers & ~MOD_MASK_SHIFT;
2368#endif
2369 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002370 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 string[len++] = CSI;
2373 string[len++] = KS_MODIFIER;
2374 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 }
2376
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002377 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002379 string[len++] = CSI;
2380 string[len++] = K_SECOND(key_char);
2381 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 }
2383 else
2384 {
2385#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002386 /* Convert characters when needed (e.g., from MacRoman to latin1).
2387 * This doesn't work for the NUL byte. */
2388 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 {
2390 char_u from[2], *to;
2391 int l;
2392
2393 from[0] = key_char;
2394 from[1] = NUL;
2395 l = 1;
2396 to = string_convert(&input_conv, from, &l);
2397 if (to != NULL)
2398 {
2399 for (i = 0; i < l && len < 19; i++)
2400 {
2401 if (to[i] == CSI)
2402 {
2403 string[len++] = KS_EXTRA;
2404 string[len++] = KE_CSI;
2405 }
2406 else
2407 string[len++] = to[i];
2408 }
2409 vim_free(to);
2410 }
2411 else
2412 string[len++] = key_char;
2413 }
2414 else
2415#endif
2416 string[len++] = key_char;
2417 }
2418
2419 if (len == 1 && string[0] == CSI)
2420 {
2421 /* Turn CSI into K_CSI. */
2422 string[ len++ ] = KS_EXTRA;
2423 string[ len++ ] = KE_CSI;
2424 }
2425
2426 add_to_input_buf(string, len);
2427}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002428#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429
2430/*
2431 * Handle MouseClick
2432 */
2433 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002434gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435{
2436 short thePart;
2437 WindowPtr whichWindow;
2438
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002439 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002441#ifdef FEAT_GUI_TABLINE
2442 /* prevent that the vim window size changes if it's activated by a
2443 click into the tab pane */
2444 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002445 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002446#endif
2447
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 switch (thePart)
2449 {
2450 case (inDesk):
2451 /* TODO: what to do? */
2452 break;
2453
2454 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002455 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 break;
2457
2458 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002459 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 break;
2461
2462 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002463 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 break;
2465
2466 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002467 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 break;
2469
2470 case (inGoAway):
2471 if (TrackGoAway(whichWindow, theEvent->where))
2472 gui_shell_closed();
2473 break;
2474
2475 case (inZoomIn):
2476 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 break;
2479 }
2480}
2481
2482/*
2483 * Handle MouseMoved
2484 * [this event is a moving in and out of a region]
2485 */
2486 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002487gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488{
2489 Point thePoint;
2490 int_u vimModifiers;
2491
2492 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002493 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2495
2496 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002497 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2501 thePoint.v, FALSE, vimModifiers);
2502
2503 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002504 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505 FILL_Y(Y_2_ROW(thePoint.v)),
2506 FILL_X(X_2_COL(thePoint.h)+1),
2507 FILL_Y(Y_2_ROW(thePoint.v)+1));
2508
2509 if (dragRectEnbl)
2510 dragRectControl = kCreateRect;
2511
2512}
2513
2514/*
2515 * Handle the mouse release
2516 */
2517 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002518gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519{
2520 Point thePoint;
2521 int_u vimModifiers;
2522
2523 /* TODO: Properly convert the Contextual menu mouse-up */
2524 /* Potential source of the double menu */
2525 lastMouseTick = theEvent->when;
2526 dragRectEnbl = FALSE;
2527 dragRectControl = kCreateEmpty;
2528 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002529 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530
2531 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 if (clickIsPopup)
2533 {
2534 vimModifiers &= ~MOUSE_CTRL;
2535 clickIsPopup = FALSE;
2536 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002537 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538}
2539
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 static pascal OSStatus
2541gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2542 void *data)
2543{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 Point point;
2545 Rect bounds;
2546 UInt32 mod;
2547 SInt32 delta;
2548 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002549 EventMouseWheelAxis axis;
2550
2551 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2552 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2553 && axis != kEventMouseWheelAxisY)
2554 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555
2556 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2557 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2558 goto bail;
2559 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2560 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2561 goto bail;
2562 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2563 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2564 goto bail;
2565
2566 vim_mod = 0;
2567 if (mod & shiftKey)
2568 vim_mod |= MOUSE_SHIFT;
2569 if (mod & controlKey)
2570 vim_mod |= MOUSE_CTRL;
2571 if (mod & optionKey)
2572 vim_mod |= MOUSE_ALT;
2573
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2575 {
2576 point.h -= bounds.left;
2577 point.v -= bounds.top;
2578 }
2579
2580 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2581 point.h, point.v, FALSE, vim_mod);
2582
Bram Moolenaarc236c162008-07-13 17:41:49 +00002583 /* post a bogus event to wake up WaitNextEvent */
2584 PostEvent(keyUp, 0);
2585
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 return noErr;
2587
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002588bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 /*
2590 * when we fail give any additional callback handler a chance to perform
2591 * it's actions
2592 */
2593 return CallNextEventHandler(nextHandler, theEvent);
2594}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595
Bram Moolenaare00289d2010-08-14 21:56:42 +02002596 void
2597gui_mch_mousehide(int hide)
2598{
2599 /* TODO */
2600}
2601
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602#if 0
2603
2604/*
2605 * This would be the normal way of invoking the contextual menu
2606 * but the Vim API doesn't seem to a support a request to get
2607 * the menu that we should display
2608 */
2609 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002610gui_mac_handle_contextual_menu(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611{
2612/*
2613 * Clone PopUp to use menu
2614 * Create a object descriptor for the current selection
2615 * Call the procedure
2616 */
2617
2618// Call to Handle Popup
2619 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2620
2621 if (status != noErr)
2622 return;
2623
2624 if (CntxType == kCMMenuItemSelected)
2625 {
2626 /* Handle the menu CntxMenuID, CntxMenuItem */
2627 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002628 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002629 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630 }
2631 else if (CntxMenuID == kCMShowHelpSelected)
2632 {
2633 /* Should come up with the help */
2634 }
2635
2636}
2637#endif
2638
2639/*
2640 * Handle menubar selection
2641 */
2642 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002643gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644{
2645 short menu = HiWord(menuChoice);
2646 short item = LoWord(menuChoice);
2647 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648
2649 if (menu == 256) /* TODO: use constant or gui.xyz */
2650 {
2651 if (item == 1)
2652 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 }
2654 else if (item != 0)
2655 {
2656 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2657
2658 if (theVimMenu)
2659 gui_menu_cb(theVimMenu);
2660 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002661 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662}
2663
2664/*
2665 * Dispatch the event to proper handler
2666 */
2667
2668 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002669gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670{
2671 OSErr error;
2672
2673 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002674 if (IsShowContextualMenuClick(event))
2675 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002677 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002679 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002681 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002682 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683
2684 /* Handle normal event */
2685 switch (event->what)
2686 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002687#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 case (keyDown):
2689 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002690 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002692#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002694 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 break;
2696
2697 case (mouseDown):
2698 gui_mac_doMouseDownEvent(event);
2699 break;
2700
2701 case (mouseUp):
2702 gui_mac_doMouseUpEvent(event);
2703 break;
2704
2705 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002706 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 break;
2708
2709 case (diskEvt):
2710 /* We don't need special handling for disk insertion */
2711 break;
2712
2713 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002714 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 break;
2716
2717 case (osEvt):
2718 switch ((event->message >> 24) & 0xFF)
2719 {
2720 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002721 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 break;
2723 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002724 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 break;
2726 }
2727 break;
2728
2729#ifdef USE_AEVENT
2730 case (kHighLevelEvent):
2731 /* Someone's talking to us, through AppleEvents */
2732 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2733 break;
2734#endif
2735 }
2736}
2737
2738/*
2739 * ------------------------------------------------------------
2740 * Unknown Stuff
2741 * ------------------------------------------------------------
2742 */
2743
2744
2745 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002746gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747{
2748 char_u c;
2749 char_u *p;
2750 char_u pFontName[256];
2751 Str255 systemFontname;
2752 short font_id;
2753 short size=9;
2754 GuiFont font;
2755#if 0
2756 char_u *fontNamePtr;
2757#endif
2758
2759 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2760 ;
2761
2762 c = *p;
2763 *p = 0;
2764
2765#if 1
2766 STRCPY(&pFontName[1], font_name);
2767 pFontName[0] = STRLEN(font_name);
2768 *p = c;
2769
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002770 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002771 char_u fontName[256];
2772 char_u *styleStart = vim_strchr(font_name, ':');
2773 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2774 vim_strncpy(fontName, font_name, fontNameLen);
2775
2776 ATSUFontID fontRef;
2777 FMFontStyle fontStyle;
2778 font_id = 0;
2779
2780 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2781 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2782 &fontRef) == noErr)
2783 {
2784 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2785 font_id = 0;
2786 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002787
2788 if (font_id == 0)
2789 {
2790 /*
2791 * Try again, this time replacing underscores in the font name
2792 * with spaces (:set guifont allows the two to be used
2793 * interchangeably; the Font Manager doesn't).
2794 */
2795 int i, changed = FALSE;
2796
2797 for (i = pFontName[0]; i > 0; --i)
2798 {
2799 if (pFontName[i] == '_')
2800 {
2801 pFontName[i] = ' ';
2802 changed = TRUE;
2803 }
2804 }
2805 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002806 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2807 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2808 kFontNoLanguageCode, &fontRef) == noErr)
2809 {
2810 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2811 font_id = 0;
2812 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002813 }
2814
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815#else
2816 /* name = C2Pascal_save(menu->dname); */
2817 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2818
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002819 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820#endif
2821
2822
2823 if (font_id == 0)
2824 {
2825 /* Oups, the system font was it the one the user want */
2826
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002827 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2828 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829 if (!EqualString(pFontName, systemFontname, false, false))
2830 return NOFONT;
2831 }
2832 if (*p == ':')
2833 {
2834 p++;
2835 /* Set the values found after ':' */
2836 while (*p)
2837 {
2838 switch (*p++)
2839 {
2840 case 'h':
2841 size = points_to_pixels(p, &p, TRUE);
2842 break;
2843 /*
2844 * TODO: Maybe accept width and styles
2845 */
2846 }
2847 while (*p == ':')
2848 p++;
2849 }
2850 }
2851
2852 if (size < 1)
2853 size = 1; /* Avoid having a size of 0 with system font */
2854
2855 font = (size << 16) + ((long) font_id & 0xFFFF);
2856
2857 return font;
2858}
2859
2860/*
2861 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002862 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 * ------------------------------------------------------------
2864 */
2865
2866/*
2867 * Parse the GUI related command-line arguments. Any arguments used are
2868 * deleted from argv, and *argc is decremented accordingly. This is called
2869 * when vim is started, whether or not the GUI has been started.
2870 */
2871 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002872gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873{
2874 /* TODO: Move most of this stuff toward gui_mch_init */
2875#ifdef USE_EXE_NAME
2876 FSSpec applDir;
2877# ifndef USE_FIND_BUNDLE_PATH
2878 short applVRefNum;
2879 long applDirID;
2880 Str255 volName;
2881# else
2882 ProcessSerialNumber psn;
2883 FSRef applFSRef;
2884# endif
2885#endif
2886
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887#if 0
2888 InitCursor();
2889
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891
2892#ifdef USE_AEVENT
2893 (void) InstallAEHandlers();
2894#endif
2895
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002896 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002898 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002900 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901
2902 DrawMenuBar();
2903
2904
2905#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002906 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002908 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909#endif
2910
2911
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 CreateNewWindow(kDocumentWindowClass,
2913 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002914 &windRect, &gui.VimWindow);
2915 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916
2917 gui.char_width = 7;
2918 gui.char_height = 11;
2919 gui.char_ascent = 6;
2920 gui.num_rows = 24;
2921 gui.num_cols = 80;
2922 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2923
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002924 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2925 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926
2927 dragRectEnbl = FALSE;
2928 dragRgn = NULL;
2929 dragRectControl = kCreateEmpty;
2930 cursorRgn = NewRgn();
2931#endif
2932#ifdef USE_EXE_NAME
2933# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002934 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002936 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937# else
2938 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2939 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002941 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 /* if (err != noErr) return err; */
2943
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002944 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 /* if (err != noErr) return err; */
2946
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002947 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948
2949 /* This technic return NIL when we disallow_gui */
2950# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002951 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953}
2954
2955#ifndef ALWAYS_USE_GUI
2956/*
2957 * Check if the GUI can be started. Called before gvimrc is sourced.
2958 * Return OK or FAIL.
2959 */
2960 int
2961gui_mch_init_check(void)
2962{
2963 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2964 * using the >console
2965 */
2966 if (disallow_gui) /* see main.c for reason to disallow */
2967 return FAIL;
2968 return OK;
2969}
2970#endif
2971
2972 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002973receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974{
2975 int x, y;
2976 int_u modifiers;
2977 char_u **fnames = NULL;
2978 int count;
2979 int i, j;
2980
2981 /* Get drop position, modifiers and count of items */
2982 {
2983 Point point;
2984 SInt16 mouseUpModifiers;
2985 UInt16 countItem;
2986
2987 GetDragMouse(theDrag, &point, NULL);
2988 GlobalToLocal(&point);
2989 x = point.h;
2990 y = point.v;
2991 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2992 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2993 CountDragItems(theDrag, &countItem);
2994 count = countItem;
2995 }
2996
2997 fnames = (char_u **)alloc(count * sizeof(char_u *));
2998 if (fnames == NULL)
2999 return dragNotAcceptedErr;
3000
3001 /* Get file names dropped */
3002 for (i = j = 0; i < count; ++i)
3003 {
3004 DragItemRef item;
3005 OSErr err;
3006 Size size;
3007 FlavorType type = flavorTypeHFS;
3008 HFSFlavor hfsFlavor;
3009
3010 fnames[i] = NULL;
3011 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3012 err = GetFlavorDataSize(theDrag, item, type, &size);
3013 if (err != noErr || size > sizeof(hfsFlavor))
3014 continue;
3015 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3016 if (err != noErr)
3017 continue;
3018 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3019 }
3020 count = j;
3021
3022 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003023
3024 /* Fake mouse event to wake from stall */
3025 PostEvent(mouseUp, 0);
3026
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027 return noErr;
3028}
3029
3030/*
3031 * Initialise the GUI. Create all the windows, set up all the call-backs
3032 * etc.
3033 */
3034 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003035gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036{
3037 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003038 Rect windRect;
3039 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003041 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003042 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003043
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003044 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003045 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003046
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047#if 1
3048 InitCursor();
3049
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051
3052#ifdef USE_AEVENT
3053 (void) InstallAEHandlers();
3054#endif
3055
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003056 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003058 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003060 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061
3062 DrawMenuBar();
3063
3064
3065#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003066 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003068 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069#endif
3070
3071 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003074 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3076 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003077 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078
3079 gui.char_width = 7;
3080 gui.char_height = 11;
3081 gui.char_ascent = 6;
3082 gui.num_rows = 24;
3083 gui.num_cols = 80;
3084 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3085
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003086 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3087 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003089 /* Install Carbon event callbacks. */
3090 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091
3092 dragRectEnbl = FALSE;
3093 dragRgn = NULL;
3094 dragRectControl = kCreateEmpty;
3095 cursorRgn = NewRgn();
3096#endif
3097 /* Display any pending error messages */
3098 display_errors();
3099
3100 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003101 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 gui.norm_pixel = 0x00000000;
3103 gui.back_pixel = 0x00FFFFFF;
3104
3105 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3106 * file). */
3107 set_normal_colors();
3108
3109 /*
3110 * Check that none of the colors are the same as the background color.
3111 * Then store the current values as the defaults.
3112 */
3113 gui_check_colors();
3114 gui.def_norm_pixel = gui.norm_pixel;
3115 gui.def_back_pixel = gui.back_pixel;
3116
3117 /* Get the colors for the highlight groups (gui_check_colors() might have
3118 * changed them) */
3119 highlight_gui_started();
3120
3121 /*
3122 * Setting the gui constants
3123 */
3124#ifdef FEAT_MENU
3125 gui.menu_height = 0;
3126#endif
3127 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3128 gui.border_offset = gui.border_width = 2;
3129
Bram Moolenaar720c7102007-05-10 18:07:50 +00003130 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 gui_mch_draw_string() below), enable it for all font sizes. */
3132 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 eventTypeSpec.eventClass = kEventClassMouse;
3135 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3136 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3137 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3138 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3139 {
3140 mouseWheelHandlerRef = NULL;
3141 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3142 mouseWheelHandlerUPP = NULL;
3143 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003145#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003146 InterfaceTypeList supportedServices = { kUnicodeDocument };
3147 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3148
3149 /* We don't support inline input yet, use input window by default */
3150 UseInputWindow(gTSMDocument, TRUE);
3151
3152 /* Should we activate the document by default? */
3153 // ActivateTSMDocument(gTSMDocument);
3154
3155 EventTypeSpec textEventTypes[] = {
3156 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3157 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3158 { kEventClassTextInput, kEventTextInputPosToOffset },
3159 { kEventClassTextInput, kEventTextInputOffsetToPos },
3160 };
3161
3162 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3163 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3164 NR_ELEMS(textEventTypes),
3165 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003166 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003167 DisposeEventHandlerUPP(keyEventHandlerUPP);
3168 keyEventHandlerUPP = NULL;
3169 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003170
3171 EventTypeSpec windowEventTypes[] = {
3172 { kEventClassWindow, kEventWindowActivated },
3173 { kEventClassWindow, kEventWindowDeactivated },
3174 };
3175
3176 /* Install window event handler to support TSMDocument activate and
3177 * deactivate */
3178 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3179 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3180 winEventHandlerUPP,
3181 NR_ELEMS(windowEventTypes),
3182 windowEventTypes, NULL, NULL))
3183 {
3184 DisposeEventHandlerUPP(winEventHandlerUPP);
3185 winEventHandlerUPP = NULL;
3186 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187#endif
3188
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003189/*
3190#ifdef FEAT_MBYTE
3191 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3192#endif
3193*/
3194
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003195#ifdef FEAT_GUI_TABLINE
3196 /*
3197 * Create the tabline
3198 */
3199 initialise_tabline();
3200#endif
3201
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 /* TODO: Load bitmap if using TOOLBAR */
3203 return OK;
3204}
3205
3206/*
3207 * Called when the foreground or background color has been changed.
3208 */
3209 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003210gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003211{
3212 /* TODO:
3213 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003214 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215 */
3216}
3217
3218/*
3219 * Open the GUI window which was created by a call to gui_mch_init().
3220 */
3221 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003222gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223{
3224 ShowWindow(gui.VimWindow);
3225
3226 if (gui_win_x != -1 && gui_win_y != -1)
3227 gui_mch_set_winpos(gui_win_x, gui_win_y);
3228
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 /*
3230 * Make the GUI the foreground process (in case it was launched
3231 * from the Terminal or via :gui).
3232 */
3233 {
3234 ProcessSerialNumber psn;
3235 if (GetCurrentProcess(&psn) == noErr)
3236 SetFrontProcess(&psn);
3237 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238
3239 return OK;
3240}
3241
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003242#ifdef USE_ATSUI_DRAWING
3243 static void
3244gui_mac_dispose_atsui_style(void)
3245{
3246 if (p_macatsui && gFontStyle)
3247 ATSUDisposeStyle(gFontStyle);
3248#ifdef FEAT_MBYTE
3249 if (p_macatsui && gWideFontStyle)
3250 ATSUDisposeStyle(gWideFontStyle);
3251#endif
3252}
3253#endif
3254
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 void
3256gui_mch_exit(int rc)
3257{
3258 /* TODO: find out all what is missing here? */
3259 DisposeRgn(cursorRgn);
3260
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003261#ifdef USE_CARBONKEYHANDLER
3262 if (keyEventHandlerUPP)
3263 DisposeEventHandlerUPP(keyEventHandlerUPP);
3264#endif
3265
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 if (mouseWheelHandlerUPP != NULL)
3267 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003269#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003270 gui_mac_dispose_atsui_style();
3271#endif
3272
3273#ifdef USE_CARBONKEYHANDLER
3274 FixTSMDocument(gTSMDocument);
3275 DeactivateTSMDocument(gTSMDocument);
3276 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003277#endif
3278
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 /* Exit to shell? */
3280 exit(rc);
3281}
3282
3283/*
3284 * Get the position of the top left corner of the window.
3285 */
3286 int
3287gui_mch_get_winpos(int *x, int *y)
3288{
3289 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 Rect bounds;
3291 OSStatus status;
3292
3293 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003294 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295
3296 if (status != noErr)
3297 return FAIL;
3298 *x = bounds.left;
3299 *y = bounds.top;
3300 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301}
3302
3303/*
3304 * Set the position of the top left corner of the window to the given
3305 * coordinates.
3306 */
3307 void
3308gui_mch_set_winpos(int x, int y)
3309{
3310 /* TODO: Should make sure the window is move within range
3311 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3312 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003313 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314}
3315
3316 void
3317gui_mch_set_shellsize(
3318 int width,
3319 int height,
3320 int min_width,
3321 int min_height,
3322 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003323 int base_height,
3324 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 CGrafPtr VimPort;
3327 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328
3329 if (gui.which_scrollbars[SBAR_LEFT])
3330 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003331 VimPort = GetWindowPort(gui.VimWindow);
3332 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003334 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 }
3337 else
3338 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003339 VimPort = GetWindowPort(gui.VimWindow);
3340 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003342 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 }
3344
3345 SizeWindow(gui.VimWindow, width, height, TRUE);
3346
3347 gui_resize_shell(width, height);
3348}
3349
3350/*
3351 * Get the screen dimensions.
3352 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3353 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003354 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 */
3356 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003357gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358{
3359 GDHandle dominantDevice = GetMainDevice();
3360 Rect screenRect = (**dominantDevice).gdRect;
3361
3362 *screen_w = screenRect.right - 10;
3363 *screen_h = screenRect.bottom - 40;
3364}
3365
3366
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003367/*
3368 * Open the Font Panel and wait for the user to select a font and
3369 * close the panel. Then fill the buffer pointed to by font_name with
3370 * the name and size of the selected font and return the font's handle,
3371 * or NOFONT in case of an error.
3372 */
3373 static GuiFont
3374gui_mac_select_font(char_u *font_name)
3375{
3376 GuiFont selected_font = NOFONT;
3377 OSStatus status;
3378 FontSelectionQDStyle curr_font;
3379
3380 /* Initialize the Font Panel with the current font. */
3381 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3382 curr_font.size = (gui.norm_font >> 16);
3383 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3384 curr_font.instance.fontStyle = 0;
3385 curr_font.hasColor = false;
3386 curr_font.version = 0; /* version number of the style structure */
3387 status = SetFontInfoForSelection(kFontSelectionQDType,
3388 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3389
3390 gFontPanelInfo.family = curr_font.instance.fontFamily;
3391 gFontPanelInfo.style = curr_font.instance.fontStyle;
3392 gFontPanelInfo.size = curr_font.size;
3393
3394 /* Pop up the Font Panel. */
3395 status = FPShowHideFontPanel();
3396 if (status == noErr)
3397 {
3398 /*
3399 * The Font Panel is modeless. We really need it to be modal,
3400 * so we spin in an event loop until the panel is closed.
3401 */
3402 gFontPanelInfo.isPanelVisible = true;
3403 while (gFontPanelInfo.isPanelVisible)
3404 {
3405 EventRecord e;
3406 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3407 }
3408
3409 GetFontPanelSelection(font_name);
3410 selected_font = gui_mac_find_font(font_name);
3411 }
3412 return selected_font;
3413}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003414
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003415#ifdef USE_ATSUI_DRAWING
3416 static void
3417gui_mac_create_atsui_style(void)
3418{
3419 if (p_macatsui && gFontStyle == NULL)
3420 {
3421 if (ATSUCreateStyle(&gFontStyle) != noErr)
3422 gFontStyle = NULL;
3423 }
3424#ifdef FEAT_MBYTE
3425 if (p_macatsui && gWideFontStyle == NULL)
3426 {
3427 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3428 gWideFontStyle = NULL;
3429 }
3430#endif
3431
3432 p_macatsui_last = p_macatsui;
3433}
3434#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435
3436/*
3437 * Initialise vim to use the font with the given name. Return FAIL if the font
3438 * could not be loaded, OK otherwise.
3439 */
3440 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003441gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442{
3443 /* TODO: Add support for bold italic underline proportional etc... */
3444 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003445 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 FontInfo font_info;
3447 short font_id;
3448 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003449 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003451#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003452 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003453#endif
3454
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455 if (font_name == NULL)
3456 {
3457 /* First try to get the suggested font */
3458 GetFNum(suggestedFont, &font_id);
3459
3460 if (font_id == 0)
3461 {
3462 /* Then pickup the standard application font */
3463 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003464 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003466 else
3467 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3469 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003470 else if (STRCMP(font_name, "*") == 0)
3471 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003473
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003474 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003475 if (font == NOFONT)
3476 return FAIL;
3477
3478 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003479 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003480 if (new_p_guifont != NULL)
3481 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003482 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003483 vim_free(p_guifont);
3484 p_guifont = new_p_guifont;
3485 /* Replace spaces in the font name with underscores. */
3486 for ( ; *new_p_guifont; ++new_p_guifont)
3487 {
3488 if (*new_p_guifont == ' ')
3489 *new_p_guifont = '_';
3490 }
3491 }
3492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 else
3494 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003495 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003496 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497
3498 if (font == NOFONT)
3499 return FAIL;
3500 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003501
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 gui.norm_font = font;
3503
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003504 hl_set_font_name(used_font_name);
3505
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003506 TextSize(font >> 16);
3507 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003509 GetFontInfo(&font_info);
3510
3511 gui.char_ascent = font_info.ascent;
3512 gui.char_width = CharWidth('_');
3513 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3514
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003515#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003516 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003517 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003518#endif
3519
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521}
3522
Bram Moolenaar02743632005-07-25 20:42:36 +00003523/*
3524 * Adjust gui.char_height (after 'linespace' was changed).
3525 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003527gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528{
3529 FontInfo font_info;
3530
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003531 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3533 gui.char_ascent = font_info.ascent + p_linespace / 2;
3534 return OK;
3535}
3536
3537/*
3538 * Get a font structure for highlighting.
3539 */
3540 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003541gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542{
3543 GuiFont font;
3544
3545 font = gui_mac_find_font(name);
3546
3547 if (font == NOFONT)
3548 {
3549 if (giveErrorIfMissing)
3550 EMSG2(_(e_font), name);
3551 return NOFONT;
3552 }
3553 /*
3554 * TODO : Accept only monospace
3555 */
3556
3557 return font;
3558}
3559
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003560#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003562 * Return the name of font "font" in allocated memory.
3563 * Don't know how to get the actual name, thus use the provided name.
3564 */
3565 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003566gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003567{
3568 if (name == NULL)
3569 return NULL;
3570 return vim_strsave(name);
3571}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003572#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003573
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003574#ifdef USE_ATSUI_DRAWING
3575 static void
3576gui_mac_set_font_attributes(GuiFont font)
3577{
3578 ATSUFontID fontID;
3579 Fixed fontSize;
3580 Fixed fontWidth;
3581
3582 fontID = font & 0xFFFF;
3583 fontSize = Long2Fix(font >> 16);
3584 fontWidth = Long2Fix(gui.char_width);
3585
3586 ATSUAttributeTag attribTags[] =
3587 {
3588 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3589 kATSUMaxATSUITagValue + 1
3590 };
3591
3592 ByteCount attribSizes[] =
3593 {
3594 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3595 sizeof(font)
3596 };
3597
3598 ATSUAttributeValuePtr attribValues[] =
3599 {
3600 &fontID, &fontSize, &fontWidth, &font
3601 };
3602
3603 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3604 {
3605 if (ATSUSetAttributes(gFontStyle,
3606 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3607 attribTags, attribSizes, attribValues) != noErr)
3608 {
3609# ifndef NDEBUG
3610 fprintf(stderr, "couldn't set font style\n");
3611# endif
3612 ATSUDisposeStyle(gFontStyle);
3613 gFontStyle = NULL;
3614 }
3615
3616#ifdef FEAT_MBYTE
3617 if (has_mbyte)
3618 {
3619 /* FIXME: we should use a more mbyte sensitive way to support
3620 * wide font drawing */
3621 fontWidth = Long2Fix(gui.char_width * 2);
3622
3623 if (ATSUSetAttributes(gWideFontStyle,
3624 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3625 attribTags, attribSizes, attribValues) != noErr)
3626 {
3627 ATSUDisposeStyle(gWideFontStyle);
3628 gWideFontStyle = NULL;
3629 }
3630 }
3631#endif
3632 }
3633}
3634#endif
3635
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003636/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 * Set the current text font.
3638 */
3639 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003640gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003642#ifdef USE_ATSUI_DRAWING
3643 GuiFont currFont;
3644 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003645
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003646 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003647 {
3648 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003649 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3650 sizeof(font), &currFont, &actualFontByteCount) == noErr
3651 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003652 {
3653 if (currFont == font)
3654 return;
3655 }
3656
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003657 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003658 }
3659
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003660 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003661 {
3662 /* Setup automatic font substitution. The user's guifontwide
3663 * is tried first, then the system tries other fonts. */
3664/*
3665 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3666 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3667 ATSUCreateFontFallbacks(&gFontFallbacks);
3668 ATSUSetObjFontFallbacks(gFontFallbacks, );
3669*/
3670 if (gui.wide_font)
3671 {
3672 ATSUFontID fallbackFonts;
3673 gIsFontFallbackSet = TRUE;
3674
3675 if (FMGetFontFromFontFamilyInstance(
3676 (gui.wide_font & 0xFFFF),
3677 0,
3678 &fallbackFonts,
3679 NULL) == noErr)
3680 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003681 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3682 &fallbackFonts,
3683 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003684 }
3685/*
3686 ATSUAttributeValuePtr fallbackValues[] = { };
3687*/
3688 }
3689 }
3690#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691 TextSize(font >> 16);
3692 TextFont(font & 0xFFFF);
3693}
3694
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695/*
3696 * If a font is not going to be used, free its structure.
3697 */
3698 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003699gui_mch_free_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700{
3701 /*
3702 * Free font when "font" is not 0.
3703 * Nothing to do in the current implementation, since
3704 * nothing is allocated for each font used.
3705 */
3706}
3707
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708/*
3709 * Return the Pixel value (color) for the given color name. This routine was
3710 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3711 * Programmer's Guide.
3712 * Return INVALCOLOR when failed.
3713 */
3714 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003715gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716{
3717 /* TODO: Add support for the new named color of MacOS 8
3718 */
3719 RGBColor MacColor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720
Bram Moolenaarab302212016-04-26 20:59:29 +02003721 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 {
Bram Moolenaarab302212016-04-26 20:59:29 +02003723 LMGetHiliteRGB(&MacColor);
3724 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 }
Bram Moolenaarab302212016-04-26 20:59:29 +02003726 return gui_get_color_cmn(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727}
3728
Bram Moolenaar26af85d2017-07-23 16:45:10 +02003729 guicolor_T
3730gui_mch_get_rgb_color(int r, int g, int b)
3731{
3732 return gui_get_rgb_color_cmn(r, g, b);
3733}
3734
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735/*
3736 * Set the current text foreground color.
3737 */
3738 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003739gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740{
3741 RGBColor TheColor;
3742
3743 TheColor.red = Red(color) * 0x0101;
3744 TheColor.green = Green(color) * 0x0101;
3745 TheColor.blue = Blue(color) * 0x0101;
3746
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003747 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748}
3749
3750/*
3751 * Set the current text background color.
3752 */
3753 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003754gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755{
3756 RGBColor TheColor;
3757
3758 TheColor.red = Red(color) * 0x0101;
3759 TheColor.green = Green(color) * 0x0101;
3760 TheColor.blue = Blue(color) * 0x0101;
3761
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003762 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763}
3764
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003765RGBColor specialColor;
3766
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003767/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003768 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003769 */
3770 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003771gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003772{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003773 specialColor.red = Red(color) * 0x0101;
3774 specialColor.green = Green(color) * 0x0101;
3775 specialColor.blue = Blue(color) * 0x0101;
3776}
3777
3778/*
3779 * Draw undercurl at the bottom of the character cell.
3780 */
3781 static void
3782draw_undercurl(int flags, int row, int col, int cells)
3783{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003784 int x;
3785 int offset;
3786 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3787 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003788
3789 RGBForeColor(&specialColor);
3790
3791 offset = val[FILL_X(col) % 8];
3792 MoveTo(FILL_X(col), y - offset);
3793
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003794 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003795 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003796 offset = val[x % 8];
3797 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003798 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003799}
3800
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003801
3802 static void
3803draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805#ifdef FEAT_MBYTE
3806 char_u *tofree = NULL;
3807
3808 if (output_conv.vc_type != CONV_NONE)
3809 {
3810 tofree = string_convert(&output_conv, s, &len);
3811 if (tofree != NULL)
3812 s = tofree;
3813 }
3814#endif
3815
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816 /*
3817 * On OS X, try using Quartz-style text antialiasing.
3818 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003819 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 {
3821 /* Quartz antialiasing is available only in OS 10.2 and later. */
3822 UInt32 qd_flags = (p_antialias ?
3823 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003824 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 }
3826
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003827 /*
3828 * When antialiasing we're using srcOr mode, we have to clear the block
3829 * before drawing the text.
3830 * Also needed when 'linespace' is non-zero to remove the cursor and
3831 * underlining.
3832 * But not when drawing transparently.
3833 * The following is like calling gui_mch_clear_block(row, col, row, col +
3834 * len - 1), but without setting the bg color to gui.back_pixel.
3835 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003836 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003837 && !(flags & DRAW_TRANSP))
3838 {
3839 Rect rc;
3840
3841 rc.left = FILL_X(col);
3842 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003843#ifdef FEAT_MBYTE
3844 /* Multibyte computation taken from gui_w32.c */
3845 if (has_mbyte)
3846 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003847 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003848 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003849 }
3850 else
3851#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003852 rc.right = FILL_X(col + len) + (col + len == Columns);
3853 rc.bottom = FILL_Y(row + 1);
3854 EraseRect(&rc);
3855 }
3856
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003857 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 {
3859 StyleParameter face;
3860
3861 face = normal;
3862 if (flags & DRAW_BOLD)
3863 face |= bold;
3864 if (flags & DRAW_UNDERL)
3865 face |= underline;
3866 TextFace(face);
3867
3868 /* Quartz antialiasing works only in srcOr transfer mode. */
3869 TextMode(srcOr);
3870
Bram Moolenaar071d4272004-06-13 20:20:40 +00003871 MoveTo(TEXT_X(col), TEXT_Y(row));
3872 DrawText((char*)s, 0, len);
3873 }
3874 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 {
3876 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003877 TextMode(srcCopy);
3878 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879
3880 /* SelectFont(hdc, gui.currFont); */
3881
3882 if (flags & DRAW_TRANSP)
3883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003884 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 }
3886
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003887 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003888 DrawText((char *)s, 0, len);
3889
3890 if (flags & DRAW_BOLD)
3891 {
3892 TextMode(srcOr);
3893 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3894 DrawText((char *)s, 0, len);
3895 }
3896
3897 if (flags & DRAW_UNDERL)
3898 {
3899 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3900 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3901 }
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02003902 if (flags & DRAW_STRIKE)
3903 {
3904 MoveTo(FILL_X(col), FILL_Y(row + 1) - gui.char_height/2);
3905 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - gui.char_height/2);
3906 }
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003907 }
3908
3909 if (flags & DRAW_UNDERC)
3910 draw_undercurl(flags, row, col, len);
3911
3912#ifdef FEAT_MBYTE
3913 vim_free(tofree);
3914#endif
3915}
3916
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003917#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003918
3919 static void
3920draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3921{
3922 /* ATSUI requires utf-16 strings */
3923 UniCharCount utf16_len;
3924 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3925 utf16_len /= sizeof(UniChar);
3926
3927 /* - ATSUI automatically antialiases text (Someone)
3928 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003929#ifdef MAC_ATSUI_DEBUG
3930 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
3931 row, col, len, len == 1 ? s[0] : ' ');
3932#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003933 /*
3934 * When antialiasing we're using srcOr mode, we have to clear the block
3935 * before drawing the text.
3936 * Also needed when 'linespace' is non-zero to remove the cursor and
3937 * underlining.
3938 * But not when drawing transparently.
3939 * The following is like calling gui_mch_clear_block(row, col, row, col +
3940 * len - 1), but without setting the bg color to gui.back_pixel.
3941 */
3942 if ((flags & DRAW_TRANSP) == 0)
3943 {
3944 Rect rc;
3945
3946 rc.left = FILL_X(col);
3947 rc.top = FILL_Y(row);
3948 /* Multibyte computation taken from gui_w32.c */
3949 if (has_mbyte)
3950 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003951 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003952 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003953 }
3954 else
3955 rc.right = FILL_X(col + len) + (col + len == Columns);
3956
3957 rc.bottom = FILL_Y(row + 1);
3958 EraseRect(&rc);
3959 }
3960
3961 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003962 TextMode(srcCopy);
3963 TextFace(normal);
3964
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003965 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003966 if (flags & DRAW_TRANSP)
3967 {
3968 TextMode(srcOr);
3969 }
3970
3971 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003972
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003973 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003974 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003975 Boolean attValue = true;
3976 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
3977 ByteCount attribSizes[] = { sizeof(Boolean) };
3978 ATSUAttributeValuePtr attribValues[] = { &attValue };
3979
3980 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
3981 }
3982
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02003983 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
3984 : kATSStyleNoAntiAliasing;
3985 if (useAntialias != useAntialias_cached)
3986 {
3987 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
3988 ByteCount attribSizes[] = { sizeof(UInt32) };
3989 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
3990
3991 if (gFontStyle)
3992 ATSUSetAttributes(gFontStyle, 1, attribTags,
3993 attribSizes, attribValues);
3994 if (gWideFontStyle)
3995 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
3996 attribSizes, attribValues);
3997
3998 useAntialias_cached = useAntialias;
3999 }
4000
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004001#ifdef FEAT_MBYTE
4002 if (has_mbyte)
4003 {
4004 int n, width_in_cell, last_width_in_cell;
4005 UniCharArrayOffset offset = 0;
4006 UniCharCount yet_to_draw = 0;
4007 ATSUTextLayout textLayout;
4008 ATSUStyle textStyle;
4009
4010 last_width_in_cell = 1;
4011 ATSUCreateTextLayout(&textLayout);
4012 ATSUSetTextPointerLocation(textLayout, tofree,
4013 kATSUFromTextBeginning,
4014 kATSUToTextEnd, utf16_len);
4015 /*
4016 ATSUSetRunStyle(textLayout, gFontStyle,
4017 kATSUFromTextBeginning, kATSUToTextEnd); */
4018
4019 /* Compute the length in display cells. */
4020 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4021 {
4022 width_in_cell = (*mb_ptr2cells)(s + n);
4023
4024 /* probably we are switching from single byte character
4025 * to multibyte characters (which requires more than one
4026 * cell to draw) */
4027 if (width_in_cell != last_width_in_cell)
4028 {
4029#ifdef MAC_ATSUI_DEBUG
4030 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4031 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4032#endif
4033 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4034 : gFontStyle;
4035
4036 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4037 offset += yet_to_draw;
4038 yet_to_draw = 0;
4039 last_width_in_cell = width_in_cell;
4040 }
4041
4042 yet_to_draw++;
4043 }
4044
4045 if (yet_to_draw)
4046 {
4047#ifdef MAC_ATSUI_DEBUG
4048 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4049 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4050#endif
4051 /* finish the rest style */
4052 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4053 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4054 }
4055
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004056 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004057 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004058 kATSUFromTextBeginning, kATSUToTextEnd,
4059 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004060 ATSUDisposeTextLayout(textLayout);
4061 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004062 else
4063#endif
4064 {
4065 ATSUTextLayout textLayout;
4066
4067 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4068 kATSUFromTextBeginning, kATSUToTextEnd,
4069 utf16_len,
4070 (gFontStyle ? 1 : 0), &utf16_len,
4071 (gFontStyle ? &gFontStyle : NULL),
4072 &textLayout) == noErr)
4073 {
4074 ATSUSetTransientFontMatching(textLayout, TRUE);
4075
4076 ATSUDrawText(textLayout,
4077 kATSUFromTextBeginning, kATSUToTextEnd,
4078 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4079
4080 ATSUDisposeTextLayout(textLayout);
4081 }
4082 }
4083
4084 /* drawing is done, now reset bold to normal */
4085 if (gFontStyle && flags & DRAW_BOLD)
4086 {
4087 Boolean attValue = false;
4088
4089 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4090 ByteCount attribSizes[] = { sizeof(Boolean) };
4091 ATSUAttributeValuePtr attribValues[] = { &attValue };
4092
4093 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4094 attribValues);
4095 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 }
4097
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004098 if (flags & DRAW_UNDERC)
4099 draw_undercurl(flags, row, col, len);
4100
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004102}
4103#endif
4104
4105 void
4106gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4107{
4108#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004109 if (p_macatsui == 0 && p_macatsui_last != 0)
4110 /* switch from macatsui to nomacatsui */
4111 gui_mac_dispose_atsui_style();
4112 else if (p_macatsui != 0 && p_macatsui_last == 0)
4113 /* switch from nomacatsui to macatsui */
4114 gui_mac_create_atsui_style();
4115
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004116 if (p_macatsui)
4117 draw_string_ATSUI(row, col, s, len, flags);
4118 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004120 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121}
4122
4123/*
4124 * Return OK if the key with the termcap name "name" is supported.
4125 */
4126 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004127gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128{
4129 int i;
4130
4131 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4132 if (name[0] == special_keys[i].vim_code0 &&
4133 name[1] == special_keys[i].vim_code1)
4134 return OK;
4135 return FAIL;
4136}
4137
4138 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004139gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004141 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142}
4143
4144 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004145gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146{
4147 /* Do a visual beep by reversing the foreground and background colors */
4148 Rect rc;
4149
4150 /*
4151 * Note: InvertRect() excludes right and bottom of rectangle.
4152 */
4153 rc.left = 0;
4154 rc.top = 0;
4155 rc.right = gui.num_cols * gui.char_width;
4156 rc.bottom = gui.num_rows * gui.char_height;
4157 InvertRect(&rc);
4158
4159 ui_delay((long)msec, TRUE); /* wait for some msec */
4160
4161 InvertRect(&rc);
4162}
4163
4164/*
4165 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4166 */
4167 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004168gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169{
4170 Rect rc;
4171
4172 /*
4173 * Note: InvertRect() excludes right and bottom of rectangle.
4174 */
4175 rc.left = FILL_X(c);
4176 rc.top = FILL_Y(r);
4177 rc.right = rc.left + nc * gui.char_width;
4178 rc.bottom = rc.top + nr * gui.char_height;
4179 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180}
4181
4182/*
4183 * Iconify the GUI window.
4184 */
4185 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004186gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187{
4188 /* TODO: find out what could replace iconify
4189 * -window shade?
4190 * -hide application?
4191 */
4192}
4193
4194#if defined(FEAT_EVAL) || defined(PROTO)
4195/*
4196 * Bring the Vim window to the foreground.
4197 */
4198 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004199gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200{
4201 /* TODO */
4202}
4203#endif
4204
4205/*
4206 * Draw a cursor without focus.
4207 */
4208 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004209gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210{
4211 Rect rc;
4212
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 /*
4214 * Note: FrameRect() excludes right and bottom of rectangle.
4215 */
4216 rc.left = FILL_X(gui.col);
4217 rc.top = FILL_Y(gui.row);
4218 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004219#ifdef FEAT_MBYTE
4220 if (mb_lefthalve(gui.row, gui.col))
4221 rc.right += gui.char_width;
4222#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 rc.bottom = rc.top + gui.char_height;
4224
4225 gui_mch_set_fg_color(color);
4226
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004227 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228}
4229
4230/*
4231 * Draw part of a cursor, only w pixels wide, and h pixels high.
4232 */
4233 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004234gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235{
4236 Rect rc;
4237
4238#ifdef FEAT_RIGHTLEFT
4239 /* vertical line should be on the right of current point */
4240 if (CURSOR_BAR_RIGHT)
4241 rc.left = FILL_X(gui.col + 1) - w;
4242 else
4243#endif
4244 rc.left = FILL_X(gui.col);
4245 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4246 rc.right = rc.left + w;
4247 rc.bottom = rc.top + h;
4248
4249 gui_mch_set_fg_color(color);
4250
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004251 FrameRect(&rc);
4252// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253}
4254
4255
4256
4257/*
4258 * Catch up with any queued X events. This may put keyboard input into the
4259 * input buffer, call resize call-backs, trigger timers etc. If there is
4260 * nothing in the X event queue (& no timers pending), then we return
4261 * immediately.
4262 */
4263 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004264gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265{
4266 /* TODO: find what to do
4267 * maybe call gui_mch_wait_for_chars (0)
4268 * more like look at EventQueue then
4269 * call heart of gui_mch_wait_for_chars;
4270 *
4271 * if (eventther)
4272 * gui_mac_handle_event(&event);
4273 */
4274 EventRecord theEvent;
4275
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004276 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277 if (theEvent.what != nullEvent)
4278 gui_mch_wait_for_chars(0);
4279}
4280
4281/*
4282 * Simple wrapper to neglect more easily the time
4283 * spent inside WaitNextEvent while profiling.
4284 */
4285
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 pascal
4287 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004288WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289{
4290 if (((long) sleep) < -1)
4291 sleep = 32767;
4292 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4293}
4294
4295/*
4296 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4297 * from the keyboard.
4298 * wtime == -1 Wait forever.
4299 * wtime == 0 This should never happen.
4300 * wtime > 0 Wait wtime milliseconds for a character.
4301 * Returns OK if a character was found to be available within the given time,
4302 * or FAIL otherwise.
4303 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004305gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306{
4307 EventMask mask = (everyEvent);
4308 EventRecord event;
4309 long entryTick;
4310 long currentTick;
4311 long sleeppyTick;
4312
4313 /* If we are providing life feedback with the scrollbar,
4314 * we don't want to try to wait for an event, or else
4315 * there won't be any life feedback.
4316 */
4317 if (dragged_sb != NULL)
4318 return FAIL;
4319 /* TODO: Check if FAIL is the proper return code */
4320
4321 entryTick = TickCount();
4322
4323 allow_scrollbar = TRUE;
4324
4325 do
4326 {
4327/* if (dragRectControl == kCreateEmpty)
4328 {
4329 dragRgn = NULL;
4330 dragRectControl = kNothing;
4331 }
4332 else*/ if (dragRectControl == kCreateRect)
4333 {
4334 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004335 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336 dragRectControl = kNothing;
4337 }
4338 /*
4339 * Don't use gui_mch_update() because then we will spin-lock until a
4340 * char arrives, instead we use WaitNextEventWrp() to hang until an
4341 * event arrives. No need to check for input_buf_full because we are
4342 * returning as soon as it contains a single char.
4343 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004344 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004346 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347 else
4348 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004349
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004350 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004352 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 if (input_available())
4354 {
4355 allow_scrollbar = FALSE;
4356 return OK;
4357 }
4358 }
4359 currentTick = TickCount();
4360 }
4361 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4362
4363 allow_scrollbar = FALSE;
4364 return FAIL;
4365}
4366
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367/*
4368 * Output routines.
4369 */
4370
4371/* Flush any output to the screen */
4372 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004373gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374{
4375 /* TODO: Is anything needed here? */
4376}
4377
4378/*
4379 * Clear a rectangular region of the screen from text pos (row1, col1) to
4380 * (row2, col2) inclusive.
4381 */
4382 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004383gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384{
4385 Rect rc;
4386
4387 /*
4388 * Clear one extra pixel at the far right, for when bold characters have
4389 * spilled over to the next column.
4390 */
4391 rc.left = FILL_X(col1);
4392 rc.top = FILL_Y(row1);
4393 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4394 rc.bottom = FILL_Y(row2 + 1);
4395
4396 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004397 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398}
4399
4400/*
4401 * Clear the whole text window.
4402 */
4403 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004404gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405{
4406 Rect rc;
4407
4408 rc.left = 0;
4409 rc.top = 0;
4410 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4411 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4412
4413 gui_mch_set_bg_color(gui.back_pixel);
4414 EraseRect(&rc);
4415/* gui_mch_set_fg_color(gui.norm_pixel);
4416 FrameRect(&rc);
4417*/
4418}
4419
4420/*
4421 * Delete the given number of lines from the given row, scrolling up any
4422 * text further down within the scroll region.
4423 */
4424 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004425gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426{
4427 Rect rc;
4428
4429 /* changed without checking! */
4430 rc.left = FILL_X(gui.scroll_region_left);
4431 rc.right = FILL_X(gui.scroll_region_right + 1);
4432 rc.top = FILL_Y(row);
4433 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4434
4435 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004436 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437
4438 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4439 gui.scroll_region_left,
4440 gui.scroll_region_bot, gui.scroll_region_right);
4441}
4442
4443/*
4444 * Insert the given number of lines before the given row, scrolling down any
4445 * following text within the scroll region.
4446 */
4447 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004448gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449{
4450 Rect rc;
4451
4452 rc.left = FILL_X(gui.scroll_region_left);
4453 rc.right = FILL_X(gui.scroll_region_right + 1);
4454 rc.top = FILL_Y(row);
4455 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4456
4457 gui_mch_set_bg_color(gui.back_pixel);
4458
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004459 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460
4461 /* Update gui.cursor_row if the cursor scrolled or copied over */
4462 if (gui.cursor_row >= gui.row
4463 && gui.cursor_col >= gui.scroll_region_left
4464 && gui.cursor_col <= gui.scroll_region_right)
4465 {
4466 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4467 gui.cursor_row += num_lines;
4468 else if (gui.cursor_row <= gui.scroll_region_bot)
4469 gui.cursor_is_valid = FALSE;
4470 }
4471
4472 gui_clear_block(row, gui.scroll_region_left,
4473 row + num_lines - 1, gui.scroll_region_right);
4474}
4475
4476 /*
4477 * TODO: add a vim format to the clipboard which remember
4478 * LINEWISE, CHARWISE, BLOCKWISE
4479 */
4480
4481 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004482clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483{
4484
4485 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004486 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 Size scrapSize;
4488 ScrapFlavorFlags scrapFlags;
4489 ScrapRef scrap = nil;
4490 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 int type;
4492 char *searchCR;
4493 char_u *tempclip;
4494
4495
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004496 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 if (error != noErr)
4498 return;
4499
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004500 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4501 if (error == noErr)
4502 {
4503 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4504 if (error == noErr && scrapSize > 1)
4505 flavor = 1;
4506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004508 if (flavor == 0)
4509 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004510 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004511 if (error != noErr)
4512 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004514 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004515 if (error != noErr)
4516 return;
4517 }
4518
4519 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004521 /* In CARBON we don't need a Handle, a pointer is good */
4522 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004524 /* tempclip = lalloc(scrapSize+1, TRUE); */
4525 HLock(textOfClip);
4526 error = GetScrapFlavorData(scrap,
4527 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4528 &scrapSize, *textOfClip);
4529 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004531 if (flavor)
4532 type = **textOfClip;
4533 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004534 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004535
4536 tempclip = lalloc(scrapSize + 1, TRUE);
4537 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4538 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004540#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004541 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004542 /* Convert from utf-16 (clipboard) */
4543 size_t encLen = 0;
4544 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004545
4546 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004548 scrapSize = encLen;
4549 vim_free(tempclip);
4550 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004554
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004555 searchCR = (char *)tempclip;
4556 while (searchCR != NULL)
4557 {
4558 searchCR = strchr(searchCR, '\r');
4559 if (searchCR != NULL)
4560 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004562
4563 clip_yank_selection(type, tempclip, scrapSize, cbd);
4564
4565 vim_free(tempclip);
4566 HUnlock(textOfClip);
4567
4568 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569}
4570
4571 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004572clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573{
4574 /*
4575 * TODO: Really nothing to do?
4576 */
4577}
4578
4579 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004580clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581{
4582 return OK;
4583}
4584
4585/*
4586 * Send the current selection to the clipboard.
4587 */
4588 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004589clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590{
4591 Handle textOfClip;
4592 long scrapSize;
4593 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004595
4596 char_u *str = NULL;
4597
4598 if (!cbd->owned)
4599 return;
4600
4601 clip_get_selection(cbd);
4602
4603 /*
4604 * Once we set the clipboard, lose ownership. If another application sets
4605 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 cbd->owned = FALSE;
4608
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004609 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004611#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004612 size_t utf16_len = 0;
4613 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4614 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004616 scrapSize = utf16_len;
4617 vim_free(str);
4618 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 }
4620#endif
4621
4622 if (type >= 0)
4623 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004626 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 HLock(textOfClip);
4628
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004629 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004630 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004631 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004632 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004633 scrapSize, *textOfClip + 1);
4634 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4635 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 HUnlock(textOfClip);
4637 DisposeHandle(textOfClip);
4638 }
4639
4640 vim_free(str);
4641}
4642
4643 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004644gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645{
4646 Rect VimBound;
4647
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004648/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650
4651 if (gui.which_scrollbars[SBAR_LEFT])
4652 {
4653 VimBound.left = -gui.scrollbar_width + 1;
4654 }
4655 else
4656 {
4657 VimBound.left = 0;
4658 }
4659
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004662 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663}
4664
4665/*
4666 * Menu stuff.
4667 */
4668
4669 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004670gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671{
4672 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004673 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674 */
4675}
4676
4677 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004678gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679{
4680 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004681 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 */
4683}
4684
4685/*
4686 * Add a sub menu to the menu bar.
4687 */
4688 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004689gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690{
4691 /*
4692 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4693 * TODO: use menu->mnemonic and menu->actext
4694 * TODO: Try to reuse menu id
4695 * Carbon Help suggest to use only id between 1 and 235
4696 */
4697 static long next_avail_id = 128;
4698 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004699#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004700 CFStringRef name;
4701#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004703#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704 short index;
4705 vimmenu_T *parent = menu->parent;
4706 vimmenu_T *brother = menu->next;
4707
4708 /* Cannot add a menu if ... */
4709 if ((parent != NULL && parent->submenu_id == 0))
4710 return;
4711
4712 /* menu ID greater than 1024 are reserved for ??? */
4713 if (next_avail_id == 1024)
4714 return;
4715
4716 /* My brother could be the PopUp, find my real brother */
4717 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4718 brother = brother->next;
4719
4720 /* Find where to insert the menu (for MenuBar) */
4721 if ((parent == NULL) && (brother != NULL))
4722 menu_after_me = brother->submenu_id;
4723
4724 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4725 if (!menu_is_menubar(menu->name))
4726 menu_after_me = hierMenu;
4727
4728 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004729#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004730 name = menu_title_removing_mnemonic(menu);
4731#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004733#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734 if (name == NULL)
4735 return;
4736
4737 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738 {
4739 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004740 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4741 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 */
4743 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004744#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004745 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4746 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4747#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004748 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 next_avail_id++;
4751 }
4752
4753 if (parent == NULL)
4754 {
4755 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4756
4757 /* TODO: Verify if we could only Insert Menu if really part of the
4758 * menubar The Inserted menu are scanned or the Command-key combos
4759 */
4760
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004761 /* Insert the menu */
4762 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763#if 1
4764 /* Vim should normally update it. TODO: verify */
4765 DrawMenuBar();
4766#endif
4767 }
4768 else
4769 {
4770 /* Adding as a submenu */
4771
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004772 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773
4774 /* Call InsertMenuItem followed by SetMenuItemText
4775 * to avoid special character recognition by InsertMenuItem
4776 */
4777 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004778#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004779 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4780#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004782#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4784 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4785 InsertMenu(menu->submenu_handle, hierMenu);
4786 }
4787
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004788#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004789 CFRelease(name);
4790#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004791 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004792#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793
4794#if 0
4795 /* Done by Vim later on */
4796 DrawMenuBar();
4797#endif
4798}
4799
4800/*
4801 * Add a menu item to a menu
4802 */
4803 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004804gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004806#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004807 CFStringRef name;
4808#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004810#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 vimmenu_T *parent = menu->parent;
4812 int menu_inserted;
4813
4814 /* Cannot add item, if the menu have not been created */
4815 if (parent->submenu_id == 0)
4816 return;
4817
4818 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4819 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4820
4821 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004822#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004823 name = menu_title_removing_mnemonic(menu);
4824#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004826#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827
4828 /* Where are just a menu item, so no handle, no id */
4829 menu->submenu_id = 0;
4830 menu->submenu_handle = NULL;
4831
Bram Moolenaar071d4272004-06-13 20:20:40 +00004832 menu_inserted = 0;
4833 if (menu->actext)
4834 {
4835 /* If the accelerator text for the menu item looks like it describes
4836 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4837 * item's command equivalent.
4838 */
4839 int key = 0;
4840 int modifiers = 0;
4841 char_u *p_actext;
4842
4843 p_actext = menu->actext;
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +02004844 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004845 if (*p_actext != 0)
4846 key = 0; /* error: trailing text */
4847 /* find_special_key() returns a keycode with as many of the
4848 * specified modifiers as appropriate already applied (e.g., for
4849 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4850 * as the only modifier). Since we want to display all of the
4851 * modifiers, we need to convert the keycode back to a printable
4852 * character plus modifiers.
4853 * TODO: Write an alternative find_special_key() that doesn't
4854 * apply modifiers.
4855 */
4856 if (key > 0 && key < 32)
4857 {
4858 /* Convert a control key to an uppercase letter. Note that
4859 * by this point it is no longer possible to distinguish
4860 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4861 */
4862 modifiers |= MOD_MASK_CTRL;
4863 key += '@';
4864 }
4865 /* If the keycode is an uppercase letter, set the Shift modifier.
4866 * If it is a lowercase letter, don't set the modifier, but convert
4867 * the letter to uppercase for display in the menu.
4868 */
4869 else if (key >= 'A' && key <= 'Z')
4870 modifiers |= MOD_MASK_SHIFT;
4871 else if (key >= 'a' && key <= 'z')
4872 key += 'A' - 'a';
4873 /* Note: keycodes below 0x22 are reserved by Apple. */
4874 if (key >= 0x22 && vim_isprintc_strict(key))
4875 {
4876 int valid = 1;
4877 char_u mac_mods = kMenuNoModifiers;
4878 /* Convert Vim modifier codes to Menu Manager equivalents. */
4879 if (modifiers & MOD_MASK_SHIFT)
4880 mac_mods |= kMenuShiftModifier;
4881 if (modifiers & MOD_MASK_CTRL)
4882 mac_mods |= kMenuControlModifier;
4883 if (!(modifiers & MOD_MASK_CMD))
4884 mac_mods |= kMenuNoCommandModifier;
4885 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4886 valid = 0; /* TODO: will Alt someday map to Option? */
4887 if (valid)
4888 {
4889 char_u item_txt[10];
4890 /* Insert the menu item after idx, with its command key. */
4891 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4892 item_txt[3] = key;
4893 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4894 /* Set the modifier keys. */
4895 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4896 menu_inserted = 1;
4897 }
4898 }
4899 }
4900 /* Call InsertMenuItem followed by SetMenuItemText
4901 * to avoid special character recognition by InsertMenuItem
4902 */
4903 if (!menu_inserted)
4904 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4905 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004906#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004907 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4908#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004910#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911
4912#if 0
4913 /* Called by Vim */
4914 DrawMenuBar();
4915#endif
4916
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004917#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004918 CFRelease(name);
4919#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920 /* TODO: Can name be freed? */
4921 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004922#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923}
4924
4925 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004926gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927{
4928 /* no tearoff menus */
4929}
4930
4931/*
4932 * Destroy the machine specific menu widget.
4933 */
4934 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004935gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004937 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004938
4939 if (index > 0)
4940 {
4941 if (menu->parent)
4942 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 {
4944 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004945 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946
4947 /* Delete the Menu if it was a hierarchical Menu */
4948 if (menu->submenu_id != 0)
4949 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004950 DeleteMenu(menu->submenu_id);
4951 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 }
4953 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004954 }
4955#ifdef DEBUG_MAC_MENU
4956 else
4957 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004958 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004959 }
4960#endif
4961 }
4962 else
4963 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004964 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004965 DeleteMenu(menu->submenu_id);
4966 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 }
4968 }
4969 /* Shouldn't this be already done by Vim. TODO: Check */
4970 DrawMenuBar();
4971}
4972
4973/*
4974 * Make a menu either grey or not grey.
4975 */
4976 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004977gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978{
4979 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004980 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981/*
4982 index = menu->index;
4983*/
4984 if (grey)
4985 {
4986 if (menu->children)
4987 DisableMenuItem(menu->submenu_handle, index);
4988 if (menu->parent)
4989 if (menu->parent->submenu_handle)
4990 DisableMenuItem(menu->parent->submenu_handle, index);
4991 }
4992 else
4993 {
4994 if (menu->children)
4995 EnableMenuItem(menu->submenu_handle, index);
4996 if (menu->parent)
4997 if (menu->parent->submenu_handle)
4998 EnableMenuItem(menu->parent->submenu_handle, index);
4999 }
5000}
5001
5002/*
5003 * Make menu item hidden or not hidden
5004 */
5005 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005006gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007{
5008 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005009 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010}
5011
5012
5013/*
5014 * This is called after setting all the menus to grey/hidden or not.
5015 */
5016 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005017gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018{
5019 DrawMenuBar();
5020}
5021
5022
5023/*
5024 * Scrollbar stuff.
5025 */
5026
5027 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005028gui_mch_enable_scrollbar(
5029 scrollbar_T *sb,
5030 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005031{
5032 if (flag)
5033 ShowControl(sb->id);
5034 else
5035 HideControl(sb->id);
5036
5037#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005038 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039#endif
5040}
5041
5042 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005043gui_mch_set_scrollbar_thumb(
5044 scrollbar_T *sb,
5045 long val,
5046 long size,
5047 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048{
5049 SetControl32BitMaximum (sb->id, max);
5050 SetControl32BitMinimum (sb->id, 0);
5051 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005052 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053#ifdef DEBUG_MAC_SB
Bram Moolenaarea034592016-06-02 22:27:08 +02005054 printf("thumb_sb (%x) %lx, %lx,%lx\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055#endif
5056}
5057
5058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005059gui_mch_set_scrollbar_pos(
5060 scrollbar_T *sb,
5061 int x,
5062 int y,
5063 int w,
5064 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065{
5066 gui_mch_set_bg_color(gui.back_pixel);
5067/* if (gui.which_scrollbars[SBAR_LEFT])
5068 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005069 MoveControl(sb->id, x-16, y);
5070 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 }
5072 else
5073 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005074 MoveControl(sb->id, x, y);
5075 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076 }*/
5077 if (sb == &gui.bottom_sbar)
5078 h += 1;
5079 else
5080 w += 1;
5081
5082 if (gui.which_scrollbars[SBAR_LEFT])
5083 x -= 15;
5084
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005085 MoveControl(sb->id, x, y);
5086 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005088 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089#endif
5090}
5091
5092 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005093gui_mch_create_scrollbar(
5094 scrollbar_T *sb,
5095 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096{
5097 Rect bounds;
5098
5099 bounds.top = -16;
5100 bounds.bottom = -10;
5101 bounds.right = -10;
5102 bounds.left = -16;
5103
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005104 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005105 &bounds,
5106 "\pScrollBar",
5107 TRUE,
5108 0, /* current*/
5109 0, /* top */
5110 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112 (long) sb->ident);
5113#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005114 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115#endif
5116}
5117
5118 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005119gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120{
5121 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005122 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005123#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005124 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125#endif
5126}
5127
Bram Moolenaar703a8042016-06-04 16:24:32 +02005128 int
5129gui_mch_is_blinking(void)
5130{
5131 return FALSE;
5132}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133
Bram Moolenaar9d5d3c92016-07-07 16:43:02 +02005134 int
5135gui_mch_is_blink_off(void)
5136{
5137 return FALSE;
5138}
5139
Bram Moolenaar071d4272004-06-13 20:20:40 +00005140/*
5141 * Cursor blink functions.
5142 *
5143 * This is a simple state machine:
5144 * BLINK_NONE not blinking at all
5145 * BLINK_OFF blinking, cursor is not shown
5146 * BLINK_ON blinking, cursor is shown
5147 */
5148 void
5149gui_mch_set_blinking(long wait, long on, long off)
5150{
5151 /* TODO: TODO: TODO: TODO: */
5152/* blink_waittime = wait;
5153 blink_ontime = on;
5154 blink_offtime = off;*/
5155}
5156
5157/*
5158 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5159 */
5160 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005161gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162{
5163 gui_update_cursor(TRUE, FALSE);
5164 /* 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 Moolenaar1b60e502008-03-12 13:40:54 +00006235#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
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 Moolenaar1b60e502008-03-12 13:40:54 +00006246#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;
6250#endif
6251}
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
6322 if (! gui.in_use)
6323 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 Moolenaar071d4272004-06-13 20:20:40 +00006384#endif /* defined(USE_IM_CONTROL) || 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