blob: 0a8b0bcc533d7864e265289e7592d17b5e02312a [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
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
44/* Compile as CodeWarior External Editor */
45#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
636 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
637 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;
728 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
729 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
810 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
811 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
1071
1072#ifdef FEAT_VISUAL
1073 reset_VIsual();
1074#endif
1075
1076 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1077
1078 if (error)
1079 {
1080 /* TODO: empty fnames[] first */
1081 vim_free(fnames);
1082 return (error);
1083 }
1084
1085 if (starting > 0)
1086 {
1087 int i;
1088 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001089 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090
1091 /* these are the initial files dropped on the Vim icon */
1092 for (i = 0 ; i < numFiles; i++)
1093 {
1094 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1095 || (p = vim_strsave(fnames[i])) == NULL)
1096 mch_exit(2);
1097 else
1098 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001099 if (fnum == -1)
1100 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1101 }
1102
1103 /* If the file name was already in the buffer list we need to switch
1104 * to it. */
1105 if (curbuf->b_fnum != fnum)
1106 {
1107 char_u cmd[30];
1108
1109 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1110 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001112
1113 /* Change directory to the location of the first file. */
1114 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1115 shorten_fnames(TRUE);
1116
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 goto finished;
1118 }
1119
1120 /* Handle the drop, :edit to get to the file */
1121 handle_drop(numFiles, fnames, FALSE);
1122
1123 /* TODO: Handle the goto/select line more cleanly */
1124 if ((numFiles == 1) & (gotPosition))
1125 {
1126 if (thePosition.lineNum >= 0)
1127 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001128 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 /* oap->motion_type = MLINE;
1130 setpcmark();*/
1131 if (lnum < 1L)
1132 lnum = 1L;
1133 else if (lnum > curbuf->b_ml.ml_line_count)
1134 lnum = curbuf->b_ml.ml_line_count;
1135 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001136 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 /* beginline(BL_SOL | BL_FIX);*/
1138 }
1139 else
1140 goto_byte(thePosition.startRange + 1);
1141 }
1142
1143 /* Update the screen display */
1144 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001145#ifdef FEAT_VISUAL
1146 /* Select the text if possible */
1147 if (gotPosition)
1148 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001149 VIsual_active = TRUE;
1150 VIsual_select = FALSE;
1151 VIsual = curwin->w_cursor;
1152 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001153 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001154 VIsual_mode = 'v';
1155 goto_byte(thePosition.endRange);
1156 }
1157 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001158 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001159 VIsual_mode = 'V';
1160 VIsual.col = 0;
1161 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001162 }
1163#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 setcursor();
1165 out_flush();
1166
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001167 /* Fake mouse event to wake from stall */
1168 PostEvent(mouseUp, 0);
1169
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001170finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171 AEDisposeDesc(&theList); /* dispose what we allocated */
1172
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001173 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001174 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175}
1176
1177/*
1178 *
1179 */
1180
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001181 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001182Handle_aevt_oapp_AE(
1183 const AppleEvent *theAEvent,
1184 AppleEvent *theReply,
1185 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186{
1187 OSErr error = noErr;
1188
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001189 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001190 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191}
1192
1193/*
1194 *
1195 */
1196
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001197 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001198Handle_aevt_quit_AE(
1199 const AppleEvent *theAEvent,
1200 AppleEvent *theReply,
1201 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202{
1203 OSErr error = noErr;
1204
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001205 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001207 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208
1209 /* Need to fake a :confirm qa */
1210 do_cmdline_cmd((char_u *)"confirm qa");
1211
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001212 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213}
1214
1215/*
1216 *
1217 */
1218
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001219 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001220Handle_aevt_pdoc_AE(
1221 const AppleEvent *theAEvent,
1222 AppleEvent *theReply,
1223 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224{
1225 OSErr error = noErr;
1226
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001227 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001229 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001230}
1231
1232/*
1233 * Handling of unknown AppleEvent
1234 *
1235 * (Just get rid of all the parms)
1236 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001237 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001238Handle_unknown_AE(
1239 const AppleEvent *theAEvent,
1240 AppleEvent *theReply,
1241 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242{
1243 OSErr error = noErr;
1244
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001245 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001247 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248}
1249
1250
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251/*
1252 * Install the various AppleEvent Handlers
1253 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001254 OSErr
1255InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256{
1257 OSErr error;
1258
1259 /* install open application handler */
1260 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001261 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 if (error)
1263 {
1264 return error;
1265 }
1266
1267 /* install quit application handler */
1268 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001269 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001270 if (error)
1271 {
1272 return error;
1273 }
1274
1275 /* install open document handler */
1276 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001277 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001278 if (error)
1279 {
1280 return error;
1281 }
1282
1283 /* install print document handler */
1284 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001285 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286
1287/* Install Core Suite */
1288/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001289 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290
1291 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001292 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293
1294 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001295 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296
1297 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001298 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299
1300 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001301 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001304 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305
1306 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001307 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308
1309 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001310 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311
1312 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001313 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314
1315 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001316 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317
1318 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001319 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001320
1321 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001322 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323
1324 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001325 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326*/
1327
1328#ifdef FEAT_CW_EDITOR
1329 /*
1330 * Bind codewarrior support handlers
1331 */
1332 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001333 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334 if (error)
1335 {
1336 return error;
1337 }
1338 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001339 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340 if (error)
1341 {
1342 return error;
1343 }
1344 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001345 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001346 if (error)
1347 {
1348 return error;
1349 }
1350#endif
1351
1352 return error;
1353
1354}
1355#endif /* USE_AEVENT */
1356
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001357
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001358/*
1359 * Callback function, installed by InstallFontPanelHandler(), below,
1360 * to handle Font Panel events.
1361 */
1362 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001363FontPanelHandler(
1364 EventHandlerCallRef inHandlerCallRef,
1365 EventRef inEvent,
1366 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001367{
1368 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1369 {
1370 gFontPanelInfo.isPanelVisible = false;
1371 return noErr;
1372 }
1373
1374 if (GetEventKind(inEvent) == kEventFontSelection)
1375 {
1376 OSStatus status;
1377 FMFontFamily newFamily;
1378 FMFontSize newSize;
1379 FMFontStyle newStyle;
1380
1381 /* Retrieve the font family ID number. */
1382 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1383 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1384 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1385 &newFamily);
1386 if (status == noErr)
1387 gFontPanelInfo.family = newFamily;
1388
1389 /* Retrieve the font size. */
1390 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1391 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1392 if (status == noErr)
1393 gFontPanelInfo.size = newSize;
1394
1395 /* Retrieve the font style (bold, etc.). Currently unused. */
1396 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1397 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1398 if (status == noErr)
1399 gFontPanelInfo.style = newStyle;
1400 }
1401 return noErr;
1402}
1403
1404
1405 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001406InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001407{
1408 EventTypeSpec eventTypes[2];
1409 EventHandlerUPP handlerUPP;
1410 /* EventHandlerRef handlerRef; */
1411
1412 eventTypes[0].eventClass = kEventClassFont;
1413 eventTypes[0].eventKind = kEventFontSelection;
1414 eventTypes[1].eventClass = kEventClassFont;
1415 eventTypes[1].eventKind = kEventFontPanelClosed;
1416
1417 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1418
1419 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1420 /*userData=*/NULL, /*handlerRef=*/NULL);
1421}
1422
1423
1424/*
1425 * Fill the buffer pointed to by outName with the name and size
1426 * of the font currently selected in the Font Panel.
1427 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001429 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001430GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001431{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001432 Str255 buf;
1433 ByteCount fontNameLen = 0;
1434 ATSUFontID fid;
1435 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001436
1437 if (!outName)
1438 return;
1439
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001440 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1441 {
1442 /* Canonicalize localized font names */
1443 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1444 gFontPanelInfo.style, &fid, NULL) != noErr)
1445 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001446
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001447 /* Request font name with Mac encoding (otherwise we could
1448 * get an unwanted utf-16 name) */
1449 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1450 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001451 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001452 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001453
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001454 /* Only encode font size, because style (bold, italic, etc) is
1455 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001456 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001457 gFontPanelInfo.size/*,
1458 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1459 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1460 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1461
1462 if ((fontNameLen + STRLEN(styleString)) < 255)
1463 STRCPY(outName + fontNameLen, styleString);
1464 }
1465 else
1466 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001467 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001468 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001469}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001470
1471
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472/*
1473 * ------------------------------------------------------------
1474 * Unfiled yet
1475 * ------------------------------------------------------------
1476 */
1477
1478/*
1479 * gui_mac_get_menu_item_index
1480 *
1481 * Returns the index inside the menu wher
1482 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001483 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001484gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485{
1486 short index;
1487 short itemIndex = -1;
1488 vimmenu_T *pBrother;
1489
1490 /* Only menu without parent are the:
1491 * -menu in the menubar
1492 * -popup menu
1493 * -toolbar (guess)
1494 *
1495 * Which are not items anyway.
1496 */
1497 if (pMenu->parent)
1498 {
1499 /* Start from the Oldest Brother */
1500 pBrother = pMenu->parent->children;
1501 index = 1;
1502 while ((pBrother) && (itemIndex == -1))
1503 {
1504 if (pBrother == pMenu)
1505 itemIndex = index;
1506 index++;
1507 pBrother = pBrother->next;
1508 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001509 }
1510 return itemIndex;
1511}
1512
1513 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001514gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515{
1516 short index;
1517 vimmenu_T *pChildMenu;
1518 vimmenu_T *pElder = pMenu->parent;
1519
1520
1521 /* Only menu without parent are the:
1522 * -menu in the menubar
1523 * -popup menu
1524 * -toolbar (guess)
1525 *
1526 * Which are not items anyway.
1527 */
1528
1529 if ((pElder) && (pElder->submenu_id == menuID))
1530 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001531 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1532 pMenu = pMenu->next;
1533 }
1534 else
1535 {
1536 for (; pMenu != NULL; pMenu = pMenu->next)
1537 {
1538 if (pMenu->children != NULL)
1539 {
1540 pChildMenu = gui_mac_get_vim_menu
1541 (menuID, itemIndex, pMenu->children);
1542 if (pChildMenu)
1543 {
1544 pMenu = pChildMenu;
1545 break;
1546 }
1547 }
1548 }
1549 }
1550 return pMenu;
1551}
1552
1553/*
1554 * ------------------------------------------------------------
1555 * MacOS Feedback procedures
1556 * ------------------------------------------------------------
1557 */
1558 pascal
1559 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001560gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561{
1562 scrollbar_T *sb;
1563 int value, dragging;
1564 ControlHandle theControlToUse;
1565 int dont_scroll_save = dont_scroll;
1566
1567 theControlToUse = dragged_sb;
1568
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001569 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570
1571 if (sb == NULL)
1572 return;
1573
1574 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001575 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 dragging = (partCode != 0);
1577
1578 /* When "allow_scrollbar" is FALSE still need to remember the new
1579 * position, but don't actually scroll by setting "dont_scroll". */
1580 dont_scroll = !allow_scrollbar;
1581 gui_drag_scrollbar(sb, value, dragging);
1582 dont_scroll = dont_scroll_save;
1583}
1584
1585 pascal
1586 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001587gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588{
1589 /* TODO: have live support */
1590 scrollbar_T *sb, *sb_info;
1591 long data;
1592 long value;
1593 int page;
1594 int dragging = FALSE;
1595 int dont_scroll_save = dont_scroll;
1596
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001597 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001598
1599 if (sb == NULL)
1600 return;
1601
1602 if (sb->wp != NULL) /* Left or right scrollbar */
1603 {
1604 /*
1605 * Careful: need to get scrollbar info out of first (left) scrollbar
1606 * for window, but keep real scrollbar too because we must pass it to
1607 * gui_drag_scrollbar().
1608 */
1609 sb_info = &sb->wp->w_scrollbars[0];
1610
1611 if (sb_info->size > 5)
1612 page = sb_info->size - 2; /* use two lines of context */
1613 else
1614 page = sb_info->size;
1615 }
1616 else /* Bottom scrollbar */
1617 {
1618 sb_info = sb;
1619 page = W_WIDTH(curwin) - 5;
1620 }
1621
1622 switch (partCode)
1623 {
1624 case kControlUpButtonPart: data = -1; break;
1625 case kControlDownButtonPart: data = 1; break;
1626 case kControlPageDownPart: data = page; break;
1627 case kControlPageUpPart: data = -page; break;
1628 default: data = 0; break;
1629 }
1630
1631 value = sb_info->value + data;
1632/* if (value > sb_info->max)
1633 value = sb_info->max;
1634 else if (value < 0)
1635 value = 0;*/
1636
1637 /* When "allow_scrollbar" is FALSE still need to remember the new
1638 * position, but don't actually scroll by setting "dont_scroll". */
1639 dont_scroll = !allow_scrollbar;
1640 gui_drag_scrollbar(sb, value, dragging);
1641 dont_scroll = dont_scroll_save;
1642
1643 out_flush();
1644 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1645
1646/* if (sb_info->wp != NULL)
1647 {
1648 win_T *wp;
1649 int sb_num;
1650
1651 sb_num = 0;
1652 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1653 sb_num++;
1654
1655 if (wp != NULL)
1656 {
1657 current_scrollbar = sb_num;
1658 scrollbar_value = value;
1659 gui_do_scroll();
1660 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1661 }
1662 }*/
1663}
1664
1665/*
1666 * ------------------------------------------------------------
1667 * MacOS Click Handling procedures
1668 * ------------------------------------------------------------
1669 */
1670
1671
1672/*
1673 * Handle a click inside the window, it may happens in the
1674 * scrollbar or the contents.
1675 *
1676 * TODO: Add support for potential TOOLBAR
1677 */
1678 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001679gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680{
1681 Point thePoint;
1682 int_u vimModifiers;
1683 short thePortion;
1684 ControlHandle theControl;
1685 int vimMouseButton;
1686 short dblClick;
1687
1688 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001689 GlobalToLocal(&thePoint);
1690 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001692 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693
1694 if (theControl != NUL)
1695 {
1696 /* We hit a scollbar */
1697
1698 if (thePortion != kControlIndicatorPart)
1699 {
1700 dragged_sb = theControl;
1701 TrackControl(theControl, thePoint, gScrollAction);
1702 dragged_sb = NULL;
1703 }
1704 else
1705 {
1706 dragged_sb = theControl;
1707#if 1
1708 TrackControl(theControl, thePoint, gScrollDrag);
1709#else
1710 TrackControl(theControl, thePoint, NULL);
1711#endif
1712 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1713 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001714 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 dragged_sb = NULL;
1716 }
1717 }
1718 else
1719 {
1720 /* We are inside the contents */
1721
1722 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1723 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1724
1725 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1726 vimMouseButton = MOUSE_LEFT;
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001729 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001730 clickIsPopup = FALSE;
1731
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001732 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1733 {
1734 vimMouseButton = MOUSE_RIGHT;
1735 vimModifiers &= ~MOUSE_CTRL;
1736 clickIsPopup = TRUE;
1737 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738
1739 /* Is it a double click ? */
1740 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1741
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001742 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743 gui_send_mouse_event(vimMouseButton, thePoint.h,
1744 thePoint.v, dblClick, vimModifiers);
1745
1746 /* Create the rectangle around the cursor to detect
1747 * the mouse dragging
1748 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749#if 0
1750 /* TODO: Do we need to this even for the contextual menu?
1751 * It may be require for popup_setpos, but for popup?
1752 */
1753 if (vimMouseButton == MOUSE_LEFT)
1754#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001756 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 FILL_Y(Y_2_ROW(thePoint.v)),
1758 FILL_X(X_2_COL(thePoint.h)+1),
1759 FILL_Y(Y_2_ROW(thePoint.v)+1));
1760
1761 dragRectEnbl = TRUE;
1762 dragRectControl = kCreateRect;
1763 }
1764 }
1765}
1766
1767/*
1768 * Handle the click in the titlebar (to move the window)
1769 */
1770 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001771gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772{
1773 Rect movingLimits;
1774 Rect *movingLimitsPtr = &movingLimits;
1775
1776 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001777 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001778 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779}
1780
1781/*
1782 * Handle the click in the grow box
1783 */
1784 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001785gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786{
1787
1788 long newSize;
1789 unsigned short newWidth;
1790 unsigned short newHeight;
1791 Rect resizeLimits;
1792 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 Rect NewContentRect;
1794
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001795 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796
Bram Moolenaar720c7102007-05-10 18:07:50 +00001797 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 /* TODO: Should this come from Vim? */
1799 resizeLimits.top = 100;
1800 resizeLimits.left = 100;
1801
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1803 newWidth = NewContentRect.right - NewContentRect.left;
1804 newHeight = NewContentRect.bottom - NewContentRect.top;
1805 gui_resize_shell(newWidth, newHeight);
1806 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001807 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808}
1809
1810/*
1811 * Handle the click in the zoom box
1812 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001814gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815{
1816 Rect r;
1817 Point p;
1818 short thePart;
1819
1820 /* ideal width is current */
1821 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1822 if (gui.which_scrollbars[SBAR_LEFT])
1823 p.h += gui.scrollbar_width;
1824 if (gui.which_scrollbars[SBAR_RIGHT])
1825 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001826 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 p.v = 15 * 1024;
1828
1829 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1830 ? inZoomIn : inZoomOut;
1831
1832 if (!TrackBox(whichWindow, theEvent->where, thePart))
1833 return;
1834
1835 /* use returned width */
1836 p.h = r.right - r.left;
1837 /* adjust returned height */
1838 p.v = r.bottom - r.top - 2 * gui.border_offset;
1839 if (gui.which_scrollbars[SBAR_BOTTOM])
1840 p.v -= gui.scrollbar_height;
1841 p.v -= p.v % gui.char_height;
1842 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001843 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 p.v += gui.scrollbar_height;
1845
1846 ZoomWindowIdeal(whichWindow, thePart, &p);
1847
1848 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1849 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1850 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001851 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853
1854/*
1855 * ------------------------------------------------------------
1856 * MacOS Event Handling procedure
1857 * ------------------------------------------------------------
1858 */
1859
1860/*
1861 * Handle the Update Event
1862 */
1863
1864 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001865gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866{
1867 WindowPtr whichWindow;
1868 GrafPtr savePort;
1869 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 Rect *updateRectPtr;
1872 Rect rc;
1873 Rect growRect;
1874 RgnHandle saveRgn;
1875
1876
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 updateRgn = NewRgn();
1878 if (updateRgn == NULL)
1879 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880
1881 /* This could be done by the caller as we
1882 * don't require anything else out of the event
1883 */
1884 whichWindow = (WindowPtr) event->message;
1885
1886 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001887 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888
1889 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001890 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891
1892 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001893 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 /* Redraw the biggest rectangle covering the area
1895 * to be updated.
1896 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1898# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001899 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 * seem to work under MacOS X (Dany)
1901 */
1902 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1903# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001904
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001906 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001907
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001908 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909# if 0
1910 /* Code from original Carbon Port (using GetWindowRegion.
1911 * I believe the UpdateRgn is already in local (Dany)
1912 */
1913 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1914 GlobalToLocal(&botRight(updateRect));
1915# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 /* Update the content (i.e. the text) */
1917 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1918 updateRectPtr->right - updateRectPtr->left,
1919 updateRectPtr->bottom - updateRectPtr->top);
1920 /* Clear the border areas if needed */
1921 gui_mch_set_bg_color(gui.back_pixel);
1922 if (updateRectPtr->left < FILL_X(0))
1923 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001924 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1925 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
1927 if (updateRectPtr->top < FILL_Y(0))
1928 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001929 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1930 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 }
1932 if (updateRectPtr->right > FILL_X(Columns))
1933 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001934 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001936 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 }
1938 if (updateRectPtr->bottom > FILL_Y(Rows))
1939 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001942 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001944 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001945 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946
1947 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001948 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949
1950 /* Update the GrowBox */
1951 /* Taken from FAQ 33-27 */
1952 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001954 GetClip(saveRgn);
1955 ClipRect(&growRect);
1956 DrawGrowIcon(whichWindow);
1957 SetClip(saveRgn);
1958 DisposeRgn(saveRgn);
1959 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960
1961 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001962 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963}
1964
1965/*
1966 * Handle the activate/deactivate event
1967 * (apply to a window)
1968 */
1969 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001970gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971{
1972 WindowPtr whichWindow;
1973
1974 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001975 /* Dim scrollbars */
1976 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001977 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001978 ControlRef rootControl;
1979 GetRootControl(gui.VimWindow, &rootControl);
1980 if ((event->modifiers) & activeFlag)
1981 ActivateControl(rootControl);
1982 else
1983 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001985
1986 /* Activate */
1987 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988}
1989
1990
1991/*
1992 * Handle the suspend/resume event
1993 * (apply to the application)
1994 */
1995 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001996gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001997{
1998 /* The frontmost application just changed */
1999
2000 /* NOTE: the suspend may happen before the deactivate
2001 * seen on MacOS X
2002 */
2003
2004 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002005 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002006 */
2007 if (event->message & 1)
2008 /* Resume */
2009 gui_focus_change(TRUE);
2010 else
2011 /* Suspend */
2012 gui_focus_change(FALSE);
2013}
2014
2015/*
2016 * Handle the key
2017 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002018#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002019 static pascal OSStatus
2020gui_mac_handle_window_activate(
2021 EventHandlerCallRef nextHandler,
2022 EventRef theEvent,
2023 void *data)
2024{
2025 UInt32 eventClass = GetEventClass(theEvent);
2026 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002027
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002028 if (eventClass == kEventClassWindow)
2029 {
2030 switch (eventKind)
2031 {
2032 case kEventWindowActivated:
2033#if defined(USE_IM_CONTROL)
2034 im_on_window_switch(TRUE);
2035#endif
2036 return noErr;
2037
2038 case kEventWindowDeactivated:
2039#if defined(USE_IM_CONTROL)
2040 im_on_window_switch(FALSE);
2041#endif
2042 return noErr;
2043 }
2044 }
2045
2046 return eventNotHandledErr;
2047}
2048
2049 static pascal OSStatus
2050gui_mac_handle_text_input(
2051 EventHandlerCallRef nextHandler,
2052 EventRef theEvent,
2053 void *data)
2054{
2055 UInt32 eventClass = GetEventClass(theEvent);
2056 UInt32 eventKind = GetEventKind(theEvent);
2057
2058 if (eventClass != kEventClassTextInput)
2059 return eventNotHandledErr;
2060
2061 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2062 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2063 (kEventTextInputOffsetToPos != eventKind) &&
2064 (kEventTextInputPosToOffset != eventKind) &&
2065 (kEventTextInputGetSelectedText != eventKind))
2066 return eventNotHandledErr;
2067
2068 switch (eventKind)
2069 {
2070 case kEventTextInputUpdateActiveInputArea:
2071 return gui_mac_update_input_area(nextHandler, theEvent);
2072 case kEventTextInputUnicodeForKeyEvent:
2073 return gui_mac_unicode_key_event(nextHandler, theEvent);
2074
2075 case kEventTextInputOffsetToPos:
2076 case kEventTextInputPosToOffset:
2077 case kEventTextInputGetSelectedText:
2078 break;
2079 }
2080
2081 return eventNotHandledErr;
2082}
2083
2084 static pascal
2085OSStatus gui_mac_update_input_area(
2086 EventHandlerCallRef nextHandler,
2087 EventRef theEvent)
2088{
2089 return eventNotHandledErr;
2090}
2091
2092static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2093 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002094
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002095# define INLINE_KEY_BUFFER_SIZE 80
2096 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002097gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002098 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002099 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002100{
2101 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002102 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002103 UInt32 actualSize;
2104 UniChar *text;
2105 char_u result[INLINE_KEY_BUFFER_SIZE];
2106 short len = 0;
2107 UInt32 key_sym;
2108 char charcode;
2109 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002110 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002111 size_t encLen;
2112 char_u *to = NULL;
2113 Boolean isSpecial = FALSE;
2114 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002115 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002117 /* Mask the mouse (as per user setting) */
2118 if (p_mh)
2119 ObscureCursor();
2120
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002121 /* Don't use the keys when the dialog wants them. */
2122 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002123 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002124
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002125 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002126 typeUnicodeText, NULL, 0, &actualSize, NULL))
2127 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002128
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002129 text = (UniChar *)alloc(actualSize);
2130 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002131 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002132
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002134 typeUnicodeText, NULL, actualSize, NULL, text);
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(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002138 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
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, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002142 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
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, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002146 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002147 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002148
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002150 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002151 require_noerr(err, done);
2152
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002153#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002154 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002155 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002156#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002157
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002158 key_char = charcode;
2159 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002160
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002161 /* Find the special key (eg., for cursor keys) */
2162 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002163 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002164 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002165 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2166 if (special_keys[i].key_sym == key_sym)
2167 {
2168 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2169 special_keys[i].vim_code1);
2170 key_char = simplify_key(key_char,
2171 (int *)&vimModifiers);
2172 isSpecial = TRUE;
2173 break;
2174 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002175 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002176
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002177 /* Intercept CMD-. and CTRL-c */
2178 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002179 ((modifiers & cmdKey) && key_char == '.'))
2180 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002181
2182 if (!isSpecial)
2183 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002184 /* remove SHIFT for keys that are already shifted, e.g.,
2185 * '(' and '*' */
2186 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2187 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002188
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002189 /* remove CTRL from keys that already have it */
2190 if (key_char < 0x20)
2191 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002192
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002193 /* don't process unicode characters here */
2194 if (!IS_SPECIAL(key_char))
2195 {
2196 /* Following code to simplify and consolidate vimModifiers
2197 * taken liberally from gui_w48.c */
2198 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002199
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002200 /* Interpret META, include SHIFT, etc. */
2201 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2202 if (key_char == CSI)
2203 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002204
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002205 if (IS_SPECIAL(key_char))
2206 isSpecial = TRUE;
2207 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002208 }
2209
2210 if (vimModifiers)
2211 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002212 result[len++] = CSI;
2213 result[len++] = KS_MODIFIER;
2214 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002215 }
2216
2217 if (isSpecial && IS_SPECIAL(key_char))
2218 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002219 result[len++] = CSI;
2220 result[len++] = K_SECOND(key_char);
2221 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002222 }
2223 else
2224 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002225 encLen = actualSize;
2226 to = mac_utf16_to_enc(text, actualSize, &encLen);
2227 if (to)
2228 {
2229 /* This is basically add_to_input_buf_csi() */
2230 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2231 {
2232 result[len++] = to[i];
2233 if (to[i] == CSI)
2234 {
2235 result[len++] = KS_EXTRA;
2236 result[len++] = (int)KE_CSI;
2237 }
2238 }
2239 vim_free(to);
2240 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002241 }
2242
2243 add_to_input_buf(result, len);
2244 err = noErr;
2245
2246done:
2247 vim_free(text);
2248 if (err == noErr)
2249 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002250 /* Fake event to wake up WNE (required to get
2251 * key repeat working */
2252 PostEvent(keyUp, 0);
2253 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002254 }
2255
2256 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002257}
2258#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 void
2260gui_mac_doKeyEvent(EventRecord *theEvent)
2261{
2262 /* TODO: add support for COMMAND KEY */
2263 long menu;
2264 unsigned char string[20];
2265 short num, i;
2266 short len = 0;
2267 KeySym key_sym;
2268 int key_char;
2269 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002270 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271
2272 /* Mask the mouse (as per user setting) */
2273 if (p_mh)
2274 ObscureCursor();
2275
2276 /* Get the key code and it's ASCII representation */
2277 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2278 key_char = theEvent->message & charCodeMask;
2279 num = 1;
2280
2281 /* Intercept CTRL-C */
2282 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002283 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 if (key_char == Ctrl_C && ctrl_c_interrupts)
2285 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002286 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2287 && (key_char == '2' || key_char == '6'))
2288 {
2289 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2290 if (key_char == '2')
2291 key_char = Ctrl_AT;
2292 else
2293 key_char = Ctrl_HAT;
2294 theEvent->modifiers = 0;
2295 }
2296 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297
2298 /* Intercept CMD-. */
2299 if (theEvent->modifiers & cmdKey)
2300 if (key_char == '.')
2301 got_int = TRUE;
2302
2303 /* Handle command key as per menu */
2304 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2305 if (theEvent->modifiers & cmdKey)
2306 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2307 * Why the mouse button? */
2308 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2309 {
2310 menu = MenuKey(key_char);
2311 if (HiWord(menu))
2312 {
2313 gui_mac_handle_menu(menu);
2314 return;
2315 }
2316 }
2317
2318 /* Convert the modifiers */
2319 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2320
2321
2322 /* Handle special keys. */
2323#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002324 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2326#endif
2327 {
2328 /* Find the special key (for non-printable keyt_char) */
2329 if ((key_char < 0x20) || (key_char == 0x7f))
2330 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2331 if (special_keys[i].key_sym == key_sym)
2332 {
2333# if 0
2334 /* We currently don't have not so special key */
2335 if (special_keys[i].vim_code1 == NUL)
2336 key_char = special_keys[i].vim_code0;
2337 else
2338# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002339 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2340 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002341 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 break;
2343 }
2344 }
2345
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002346 /* For some keys the modifier is included in the char itself. */
2347 if (simplify || key_char == TAB || key_char == ' ')
2348 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349
2350 /* Add the modifier to the input bu if needed */
2351 /* Do not want SHIFT-A or CTRL-A with modifier */
2352 if (!IS_SPECIAL(key_char)
2353 && key_sym != vk_Space
2354 && key_sym != vk_Tab
2355 && key_sym != vk_Return
2356 && key_sym != vk_Enter
2357 && key_sym != vk_Esc)
2358 {
2359#if 1
2360 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if ((modifiers == MOD_MASK_SHIFT)
2362 || (modifiers == MOD_MASK_CTRL)
2363 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 modifiers = 0;
2365#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002366 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002368 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002370 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 modifiers = modifiers & ~MOD_MASK_SHIFT;
2372#endif
2373 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002374 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 string[len++] = CSI;
2377 string[len++] = KS_MODIFIER;
2378 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 }
2380
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002381 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002383 string[len++] = CSI;
2384 string[len++] = K_SECOND(key_char);
2385 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 }
2387 else
2388 {
2389#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002390 /* Convert characters when needed (e.g., from MacRoman to latin1).
2391 * This doesn't work for the NUL byte. */
2392 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 {
2394 char_u from[2], *to;
2395 int l;
2396
2397 from[0] = key_char;
2398 from[1] = NUL;
2399 l = 1;
2400 to = string_convert(&input_conv, from, &l);
2401 if (to != NULL)
2402 {
2403 for (i = 0; i < l && len < 19; i++)
2404 {
2405 if (to[i] == CSI)
2406 {
2407 string[len++] = KS_EXTRA;
2408 string[len++] = KE_CSI;
2409 }
2410 else
2411 string[len++] = to[i];
2412 }
2413 vim_free(to);
2414 }
2415 else
2416 string[len++] = key_char;
2417 }
2418 else
2419#endif
2420 string[len++] = key_char;
2421 }
2422
2423 if (len == 1 && string[0] == CSI)
2424 {
2425 /* Turn CSI into K_CSI. */
2426 string[ len++ ] = KS_EXTRA;
2427 string[ len++ ] = KE_CSI;
2428 }
2429
2430 add_to_input_buf(string, len);
2431}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002432#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433
2434/*
2435 * Handle MouseClick
2436 */
2437 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002438gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439{
2440 short thePart;
2441 WindowPtr whichWindow;
2442
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002443 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002445#ifdef FEAT_GUI_TABLINE
2446 /* prevent that the vim window size changes if it's activated by a
2447 click into the tab pane */
2448 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002449 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002450#endif
2451
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 switch (thePart)
2453 {
2454 case (inDesk):
2455 /* TODO: what to do? */
2456 break;
2457
2458 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002459 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 break;
2461
2462 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002463 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 break;
2465
2466 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002467 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 break;
2469
2470 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002471 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472 break;
2473
2474 case (inGoAway):
2475 if (TrackGoAway(whichWindow, theEvent->where))
2476 gui_shell_closed();
2477 break;
2478
2479 case (inZoomIn):
2480 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 break;
2483 }
2484}
2485
2486/*
2487 * Handle MouseMoved
2488 * [this event is a moving in and out of a region]
2489 */
2490 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002491gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492{
2493 Point thePoint;
2494 int_u vimModifiers;
2495
2496 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002497 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2499
2500 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002501 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2505 thePoint.v, FALSE, vimModifiers);
2506
2507 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002508 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 FILL_Y(Y_2_ROW(thePoint.v)),
2510 FILL_X(X_2_COL(thePoint.h)+1),
2511 FILL_Y(Y_2_ROW(thePoint.v)+1));
2512
2513 if (dragRectEnbl)
2514 dragRectControl = kCreateRect;
2515
2516}
2517
2518/*
2519 * Handle the mouse release
2520 */
2521 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002522gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523{
2524 Point thePoint;
2525 int_u vimModifiers;
2526
2527 /* TODO: Properly convert the Contextual menu mouse-up */
2528 /* Potential source of the double menu */
2529 lastMouseTick = theEvent->when;
2530 dragRectEnbl = FALSE;
2531 dragRectControl = kCreateEmpty;
2532 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002533 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534
2535 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 if (clickIsPopup)
2537 {
2538 vimModifiers &= ~MOUSE_CTRL;
2539 clickIsPopup = FALSE;
2540 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002541 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542}
2543
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 static pascal OSStatus
2545gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2546 void *data)
2547{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 Point point;
2549 Rect bounds;
2550 UInt32 mod;
2551 SInt32 delta;
2552 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002553 EventMouseWheelAxis axis;
2554
2555 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2556 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2557 && axis != kEventMouseWheelAxisY)
2558 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559
2560 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2561 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2562 goto bail;
2563 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2564 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2565 goto bail;
2566 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2567 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2568 goto bail;
2569
2570 vim_mod = 0;
2571 if (mod & shiftKey)
2572 vim_mod |= MOUSE_SHIFT;
2573 if (mod & controlKey)
2574 vim_mod |= MOUSE_CTRL;
2575 if (mod & optionKey)
2576 vim_mod |= MOUSE_ALT;
2577
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2579 {
2580 point.h -= bounds.left;
2581 point.v -= bounds.top;
2582 }
2583
2584 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2585 point.h, point.v, FALSE, vim_mod);
2586
Bram Moolenaarc236c162008-07-13 17:41:49 +00002587 /* post a bogus event to wake up WaitNextEvent */
2588 PostEvent(keyUp, 0);
2589
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 return noErr;
2591
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002592bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 /*
2594 * when we fail give any additional callback handler a chance to perform
2595 * it's actions
2596 */
2597 return CallNextEventHandler(nextHandler, theEvent);
2598}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599
Bram Moolenaare00289d2010-08-14 21:56:42 +02002600 void
2601gui_mch_mousehide(int hide)
2602{
2603 /* TODO */
2604}
2605
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606#if 0
2607
2608/*
2609 * This would be the normal way of invoking the contextual menu
2610 * but the Vim API doesn't seem to a support a request to get
2611 * the menu that we should display
2612 */
2613 void
2614gui_mac_handle_contextual_menu(event)
2615 EventRecord *event;
2616{
2617/*
2618 * Clone PopUp to use menu
2619 * Create a object descriptor for the current selection
2620 * Call the procedure
2621 */
2622
2623// Call to Handle Popup
2624 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2625
2626 if (status != noErr)
2627 return;
2628
2629 if (CntxType == kCMMenuItemSelected)
2630 {
2631 /* Handle the menu CntxMenuID, CntxMenuItem */
2632 /* The submenu can be handle directly by gui_mac_handle_menu */
2633 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002634 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 }
2636 else if (CntxMenuID == kCMShowHelpSelected)
2637 {
2638 /* Should come up with the help */
2639 }
2640
2641}
2642#endif
2643
2644/*
2645 * Handle menubar selection
2646 */
2647 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002648gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649{
2650 short menu = HiWord(menuChoice);
2651 short item = LoWord(menuChoice);
2652 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653
2654 if (menu == 256) /* TODO: use constant or gui.xyz */
2655 {
2656 if (item == 1)
2657 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 }
2659 else if (item != 0)
2660 {
2661 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2662
2663 if (theVimMenu)
2664 gui_menu_cb(theVimMenu);
2665 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002666 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667}
2668
2669/*
2670 * Dispatch the event to proper handler
2671 */
2672
2673 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002674gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675{
2676 OSErr error;
2677
2678 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002679 if (IsShowContextualMenuClick(event))
2680 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002682 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002684 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002686 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002687 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688
2689 /* Handle normal event */
2690 switch (event->what)
2691 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002692#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 case (keyDown):
2694 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002695 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002697#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002699 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 break;
2701
2702 case (mouseDown):
2703 gui_mac_doMouseDownEvent(event);
2704 break;
2705
2706 case (mouseUp):
2707 gui_mac_doMouseUpEvent(event);
2708 break;
2709
2710 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002711 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 break;
2713
2714 case (diskEvt):
2715 /* We don't need special handling for disk insertion */
2716 break;
2717
2718 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002719 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 break;
2721
2722 case (osEvt):
2723 switch ((event->message >> 24) & 0xFF)
2724 {
2725 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002726 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 break;
2728 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002729 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 break;
2731 }
2732 break;
2733
2734#ifdef USE_AEVENT
2735 case (kHighLevelEvent):
2736 /* Someone's talking to us, through AppleEvents */
2737 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2738 break;
2739#endif
2740 }
2741}
2742
2743/*
2744 * ------------------------------------------------------------
2745 * Unknown Stuff
2746 * ------------------------------------------------------------
2747 */
2748
2749
2750 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002751gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752{
2753 char_u c;
2754 char_u *p;
2755 char_u pFontName[256];
2756 Str255 systemFontname;
2757 short font_id;
2758 short size=9;
2759 GuiFont font;
2760#if 0
2761 char_u *fontNamePtr;
2762#endif
2763
2764 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2765 ;
2766
2767 c = *p;
2768 *p = 0;
2769
2770#if 1
2771 STRCPY(&pFontName[1], font_name);
2772 pFontName[0] = STRLEN(font_name);
2773 *p = c;
2774
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002775 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002776 char_u fontName[256];
2777 char_u *styleStart = vim_strchr(font_name, ':');
2778 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2779 vim_strncpy(fontName, font_name, fontNameLen);
2780
2781 ATSUFontID fontRef;
2782 FMFontStyle fontStyle;
2783 font_id = 0;
2784
2785 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2786 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2787 &fontRef) == noErr)
2788 {
2789 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2790 font_id = 0;
2791 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002792
2793 if (font_id == 0)
2794 {
2795 /*
2796 * Try again, this time replacing underscores in the font name
2797 * with spaces (:set guifont allows the two to be used
2798 * interchangeably; the Font Manager doesn't).
2799 */
2800 int i, changed = FALSE;
2801
2802 for (i = pFontName[0]; i > 0; --i)
2803 {
2804 if (pFontName[i] == '_')
2805 {
2806 pFontName[i] = ' ';
2807 changed = TRUE;
2808 }
2809 }
2810 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002811 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2812 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2813 kFontNoLanguageCode, &fontRef) == noErr)
2814 {
2815 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2816 font_id = 0;
2817 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002818 }
2819
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820#else
2821 /* name = C2Pascal_save(menu->dname); */
2822 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2823
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002824 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825#endif
2826
2827
2828 if (font_id == 0)
2829 {
2830 /* Oups, the system font was it the one the user want */
2831
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002832 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2833 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834 if (!EqualString(pFontName, systemFontname, false, false))
2835 return NOFONT;
2836 }
2837 if (*p == ':')
2838 {
2839 p++;
2840 /* Set the values found after ':' */
2841 while (*p)
2842 {
2843 switch (*p++)
2844 {
2845 case 'h':
2846 size = points_to_pixels(p, &p, TRUE);
2847 break;
2848 /*
2849 * TODO: Maybe accept width and styles
2850 */
2851 }
2852 while (*p == ':')
2853 p++;
2854 }
2855 }
2856
2857 if (size < 1)
2858 size = 1; /* Avoid having a size of 0 with system font */
2859
2860 font = (size << 16) + ((long) font_id & 0xFFFF);
2861
2862 return font;
2863}
2864
2865/*
2866 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002867 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 * ------------------------------------------------------------
2869 */
2870
2871/*
2872 * Parse the GUI related command-line arguments. Any arguments used are
2873 * deleted from argv, and *argc is decremented accordingly. This is called
2874 * when vim is started, whether or not the GUI has been started.
2875 */
2876 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002877gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878{
2879 /* TODO: Move most of this stuff toward gui_mch_init */
2880#ifdef USE_EXE_NAME
2881 FSSpec applDir;
2882# ifndef USE_FIND_BUNDLE_PATH
2883 short applVRefNum;
2884 long applDirID;
2885 Str255 volName;
2886# else
2887 ProcessSerialNumber psn;
2888 FSRef applFSRef;
2889# endif
2890#endif
2891
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892#if 0
2893 InitCursor();
2894
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
2897#ifdef USE_AEVENT
2898 (void) InstallAEHandlers();
2899#endif
2900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002901 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002903 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906
2907 DrawMenuBar();
2908
2909
2910#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002911 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002913 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914#endif
2915
2916
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 CreateNewWindow(kDocumentWindowClass,
2918 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002919 &windRect, &gui.VimWindow);
2920 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921
2922 gui.char_width = 7;
2923 gui.char_height = 11;
2924 gui.char_ascent = 6;
2925 gui.num_rows = 24;
2926 gui.num_cols = 80;
2927 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2928
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002929 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2930 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931
2932 dragRectEnbl = FALSE;
2933 dragRgn = NULL;
2934 dragRectControl = kCreateEmpty;
2935 cursorRgn = NewRgn();
2936#endif
2937#ifdef USE_EXE_NAME
2938# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002939 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002941 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942# else
2943 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2944 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 /* if (err != noErr) return err; */
2948
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002949 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 /* if (err != noErr) return err; */
2951
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002952 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953
2954 /* This technic return NIL when we disallow_gui */
2955# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002956 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958}
2959
2960#ifndef ALWAYS_USE_GUI
2961/*
2962 * Check if the GUI can be started. Called before gvimrc is sourced.
2963 * Return OK or FAIL.
2964 */
2965 int
2966gui_mch_init_check(void)
2967{
2968 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2969 * using the >console
2970 */
2971 if (disallow_gui) /* see main.c for reason to disallow */
2972 return FAIL;
2973 return OK;
2974}
2975#endif
2976
2977 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002978receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979{
2980 int x, y;
2981 int_u modifiers;
2982 char_u **fnames = NULL;
2983 int count;
2984 int i, j;
2985
2986 /* Get drop position, modifiers and count of items */
2987 {
2988 Point point;
2989 SInt16 mouseUpModifiers;
2990 UInt16 countItem;
2991
2992 GetDragMouse(theDrag, &point, NULL);
2993 GlobalToLocal(&point);
2994 x = point.h;
2995 y = point.v;
2996 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2997 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2998 CountDragItems(theDrag, &countItem);
2999 count = countItem;
3000 }
3001
3002 fnames = (char_u **)alloc(count * sizeof(char_u *));
3003 if (fnames == NULL)
3004 return dragNotAcceptedErr;
3005
3006 /* Get file names dropped */
3007 for (i = j = 0; i < count; ++i)
3008 {
3009 DragItemRef item;
3010 OSErr err;
3011 Size size;
3012 FlavorType type = flavorTypeHFS;
3013 HFSFlavor hfsFlavor;
3014
3015 fnames[i] = NULL;
3016 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3017 err = GetFlavorDataSize(theDrag, item, type, &size);
3018 if (err != noErr || size > sizeof(hfsFlavor))
3019 continue;
3020 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3021 if (err != noErr)
3022 continue;
3023 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3024 }
3025 count = j;
3026
3027 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003028
3029 /* Fake mouse event to wake from stall */
3030 PostEvent(mouseUp, 0);
3031
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 return noErr;
3033}
3034
3035/*
3036 * Initialise the GUI. Create all the windows, set up all the call-backs
3037 * etc.
3038 */
3039 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003040gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041{
3042 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003043 Rect windRect;
3044 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003046 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003047 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003048
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003049 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003050 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003051
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052#if 1
3053 InitCursor();
3054
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
3057#ifdef USE_AEVENT
3058 (void) InstallAEHandlers();
3059#endif
3060
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003061 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003063 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066
3067 DrawMenuBar();
3068
3069
3070#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003071 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003073 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074#endif
3075
3076 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003079 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3081 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003082 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083
3084 gui.char_width = 7;
3085 gui.char_height = 11;
3086 gui.char_ascent = 6;
3087 gui.num_rows = 24;
3088 gui.num_cols = 80;
3089 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3090
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003091 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3092 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003094 /* Install Carbon event callbacks. */
3095 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096
3097 dragRectEnbl = FALSE;
3098 dragRgn = NULL;
3099 dragRectControl = kCreateEmpty;
3100 cursorRgn = NewRgn();
3101#endif
3102 /* Display any pending error messages */
3103 display_errors();
3104
3105 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003106 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 gui.norm_pixel = 0x00000000;
3108 gui.back_pixel = 0x00FFFFFF;
3109
3110 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3111 * file). */
3112 set_normal_colors();
3113
3114 /*
3115 * Check that none of the colors are the same as the background color.
3116 * Then store the current values as the defaults.
3117 */
3118 gui_check_colors();
3119 gui.def_norm_pixel = gui.norm_pixel;
3120 gui.def_back_pixel = gui.back_pixel;
3121
3122 /* Get the colors for the highlight groups (gui_check_colors() might have
3123 * changed them) */
3124 highlight_gui_started();
3125
3126 /*
3127 * Setting the gui constants
3128 */
3129#ifdef FEAT_MENU
3130 gui.menu_height = 0;
3131#endif
3132 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3133 gui.border_offset = gui.border_width = 2;
3134
Bram Moolenaar720c7102007-05-10 18:07:50 +00003135 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 gui_mch_draw_string() below), enable it for all font sizes. */
3137 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 eventTypeSpec.eventClass = kEventClassMouse;
3140 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3141 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3142 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3143 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3144 {
3145 mouseWheelHandlerRef = NULL;
3146 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3147 mouseWheelHandlerUPP = NULL;
3148 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003150#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003151 InterfaceTypeList supportedServices = { kUnicodeDocument };
3152 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3153
3154 /* We don't support inline input yet, use input window by default */
3155 UseInputWindow(gTSMDocument, TRUE);
3156
3157 /* Should we activate the document by default? */
3158 // ActivateTSMDocument(gTSMDocument);
3159
3160 EventTypeSpec textEventTypes[] = {
3161 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3162 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3163 { kEventClassTextInput, kEventTextInputPosToOffset },
3164 { kEventClassTextInput, kEventTextInputOffsetToPos },
3165 };
3166
3167 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3168 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3169 NR_ELEMS(textEventTypes),
3170 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003171 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003172 DisposeEventHandlerUPP(keyEventHandlerUPP);
3173 keyEventHandlerUPP = NULL;
3174 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003175
3176 EventTypeSpec windowEventTypes[] = {
3177 { kEventClassWindow, kEventWindowActivated },
3178 { kEventClassWindow, kEventWindowDeactivated },
3179 };
3180
3181 /* Install window event handler to support TSMDocument activate and
3182 * deactivate */
3183 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3184 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3185 winEventHandlerUPP,
3186 NR_ELEMS(windowEventTypes),
3187 windowEventTypes, NULL, NULL))
3188 {
3189 DisposeEventHandlerUPP(winEventHandlerUPP);
3190 winEventHandlerUPP = NULL;
3191 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192#endif
3193
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003194/*
3195#ifdef FEAT_MBYTE
3196 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3197#endif
3198*/
3199
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003200#ifdef FEAT_GUI_TABLINE
3201 /*
3202 * Create the tabline
3203 */
3204 initialise_tabline();
3205#endif
3206
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 /* TODO: Load bitmap if using TOOLBAR */
3208 return OK;
3209}
3210
3211/*
3212 * Called when the foreground or background color has been changed.
3213 */
3214 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003215gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216{
3217 /* TODO:
3218 * This proc is called when Normal is set to a value
3219 * so what msut be done? I don't know
3220 */
3221}
3222
3223/*
3224 * Open the GUI window which was created by a call to gui_mch_init().
3225 */
3226 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003227gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228{
3229 ShowWindow(gui.VimWindow);
3230
3231 if (gui_win_x != -1 && gui_win_y != -1)
3232 gui_mch_set_winpos(gui_win_x, gui_win_y);
3233
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 /*
3235 * Make the GUI the foreground process (in case it was launched
3236 * from the Terminal or via :gui).
3237 */
3238 {
3239 ProcessSerialNumber psn;
3240 if (GetCurrentProcess(&psn) == noErr)
3241 SetFrontProcess(&psn);
3242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243
3244 return OK;
3245}
3246
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003247#ifdef USE_ATSUI_DRAWING
3248 static void
3249gui_mac_dispose_atsui_style(void)
3250{
3251 if (p_macatsui && gFontStyle)
3252 ATSUDisposeStyle(gFontStyle);
3253#ifdef FEAT_MBYTE
3254 if (p_macatsui && gWideFontStyle)
3255 ATSUDisposeStyle(gWideFontStyle);
3256#endif
3257}
3258#endif
3259
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 void
3261gui_mch_exit(int rc)
3262{
3263 /* TODO: find out all what is missing here? */
3264 DisposeRgn(cursorRgn);
3265
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003266#ifdef USE_CARBONKEYHANDLER
3267 if (keyEventHandlerUPP)
3268 DisposeEventHandlerUPP(keyEventHandlerUPP);
3269#endif
3270
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271 if (mouseWheelHandlerUPP != NULL)
3272 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003274#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003275 gui_mac_dispose_atsui_style();
3276#endif
3277
3278#ifdef USE_CARBONKEYHANDLER
3279 FixTSMDocument(gTSMDocument);
3280 DeactivateTSMDocument(gTSMDocument);
3281 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003282#endif
3283
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 /* Exit to shell? */
3285 exit(rc);
3286}
3287
3288/*
3289 * Get the position of the top left corner of the window.
3290 */
3291 int
3292gui_mch_get_winpos(int *x, int *y)
3293{
3294 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 Rect bounds;
3296 OSStatus status;
3297
3298 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003299 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300
3301 if (status != noErr)
3302 return FAIL;
3303 *x = bounds.left;
3304 *y = bounds.top;
3305 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 return FAIL;
3307}
3308
3309/*
3310 * Set the position of the top left corner of the window to the given
3311 * coordinates.
3312 */
3313 void
3314gui_mch_set_winpos(int x, int y)
3315{
3316 /* TODO: Should make sure the window is move within range
3317 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3318 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003319 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320}
3321
3322 void
3323gui_mch_set_shellsize(
3324 int width,
3325 int height,
3326 int min_width,
3327 int min_height,
3328 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003329 int base_height,
3330 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332 CGrafPtr VimPort;
3333 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334
3335 if (gui.which_scrollbars[SBAR_LEFT])
3336 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003337 VimPort = GetWindowPort(gui.VimWindow);
3338 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 }
3343 else
3344 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003345 VimPort = GetWindowPort(gui.VimWindow);
3346 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003348 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 }
3350
3351 SizeWindow(gui.VimWindow, width, height, TRUE);
3352
3353 gui_resize_shell(width, height);
3354}
3355
3356/*
3357 * Get the screen dimensions.
3358 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3359 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003360 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361 */
3362 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003363gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364{
3365 GDHandle dominantDevice = GetMainDevice();
3366 Rect screenRect = (**dominantDevice).gdRect;
3367
3368 *screen_w = screenRect.right - 10;
3369 *screen_h = screenRect.bottom - 40;
3370}
3371
3372
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003373/*
3374 * Open the Font Panel and wait for the user to select a font and
3375 * close the panel. Then fill the buffer pointed to by font_name with
3376 * the name and size of the selected font and return the font's handle,
3377 * or NOFONT in case of an error.
3378 */
3379 static GuiFont
3380gui_mac_select_font(char_u *font_name)
3381{
3382 GuiFont selected_font = NOFONT;
3383 OSStatus status;
3384 FontSelectionQDStyle curr_font;
3385
3386 /* Initialize the Font Panel with the current font. */
3387 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3388 curr_font.size = (gui.norm_font >> 16);
3389 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3390 curr_font.instance.fontStyle = 0;
3391 curr_font.hasColor = false;
3392 curr_font.version = 0; /* version number of the style structure */
3393 status = SetFontInfoForSelection(kFontSelectionQDType,
3394 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3395
3396 gFontPanelInfo.family = curr_font.instance.fontFamily;
3397 gFontPanelInfo.style = curr_font.instance.fontStyle;
3398 gFontPanelInfo.size = curr_font.size;
3399
3400 /* Pop up the Font Panel. */
3401 status = FPShowHideFontPanel();
3402 if (status == noErr)
3403 {
3404 /*
3405 * The Font Panel is modeless. We really need it to be modal,
3406 * so we spin in an event loop until the panel is closed.
3407 */
3408 gFontPanelInfo.isPanelVisible = true;
3409 while (gFontPanelInfo.isPanelVisible)
3410 {
3411 EventRecord e;
3412 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3413 }
3414
3415 GetFontPanelSelection(font_name);
3416 selected_font = gui_mac_find_font(font_name);
3417 }
3418 return selected_font;
3419}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003420
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003421#ifdef USE_ATSUI_DRAWING
3422 static void
3423gui_mac_create_atsui_style(void)
3424{
3425 if (p_macatsui && gFontStyle == NULL)
3426 {
3427 if (ATSUCreateStyle(&gFontStyle) != noErr)
3428 gFontStyle = NULL;
3429 }
3430#ifdef FEAT_MBYTE
3431 if (p_macatsui && gWideFontStyle == NULL)
3432 {
3433 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3434 gWideFontStyle = NULL;
3435 }
3436#endif
3437
3438 p_macatsui_last = p_macatsui;
3439}
3440#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441
3442/*
3443 * Initialise vim to use the font with the given name. Return FAIL if the font
3444 * could not be loaded, OK otherwise.
3445 */
3446 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003447gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448{
3449 /* TODO: Add support for bold italic underline proportional etc... */
3450 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003451 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 FontInfo font_info;
3453 short font_id;
3454 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003455 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003457#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003458 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003459#endif
3460
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 if (font_name == NULL)
3462 {
3463 /* First try to get the suggested font */
3464 GetFNum(suggestedFont, &font_id);
3465
3466 if (font_id == 0)
3467 {
3468 /* Then pickup the standard application font */
3469 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003470 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 else
3473 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3475 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003476 else if (STRCMP(font_name, "*") == 0)
3477 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003478 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003479
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003481 if (font == NOFONT)
3482 return FAIL;
3483
3484 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003485 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003486 if (new_p_guifont != NULL)
3487 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003488 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003489 vim_free(p_guifont);
3490 p_guifont = new_p_guifont;
3491 /* Replace spaces in the font name with underscores. */
3492 for ( ; *new_p_guifont; ++new_p_guifont)
3493 {
3494 if (*new_p_guifont == ' ')
3495 *new_p_guifont = '_';
3496 }
3497 }
3498 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 else
3500 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003501 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003502 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503
3504 if (font == NOFONT)
3505 return FAIL;
3506 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003507
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 gui.norm_font = font;
3509
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003510 hl_set_font_name(used_font_name);
3511
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003512 TextSize(font >> 16);
3513 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003515 GetFontInfo(&font_info);
3516
3517 gui.char_ascent = font_info.ascent;
3518 gui.char_width = CharWidth('_');
3519 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3520
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003521#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003522 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003523 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003524#endif
3525
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527}
3528
Bram Moolenaar02743632005-07-25 20:42:36 +00003529/*
3530 * Adjust gui.char_height (after 'linespace' was changed).
3531 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003533gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534{
3535 FontInfo font_info;
3536
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003537 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3539 gui.char_ascent = font_info.ascent + p_linespace / 2;
3540 return OK;
3541}
3542
3543/*
3544 * Get a font structure for highlighting.
3545 */
3546 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003547gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548{
3549 GuiFont font;
3550
3551 font = gui_mac_find_font(name);
3552
3553 if (font == NOFONT)
3554 {
3555 if (giveErrorIfMissing)
3556 EMSG2(_(e_font), name);
3557 return NOFONT;
3558 }
3559 /*
3560 * TODO : Accept only monospace
3561 */
3562
3563 return font;
3564}
3565
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003566#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003568 * Return the name of font "font" in allocated memory.
3569 * Don't know how to get the actual name, thus use the provided name.
3570 */
3571 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003572gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003573{
3574 if (name == NULL)
3575 return NULL;
3576 return vim_strsave(name);
3577}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003578#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003579
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003580#ifdef USE_ATSUI_DRAWING
3581 static void
3582gui_mac_set_font_attributes(GuiFont font)
3583{
3584 ATSUFontID fontID;
3585 Fixed fontSize;
3586 Fixed fontWidth;
3587
3588 fontID = font & 0xFFFF;
3589 fontSize = Long2Fix(font >> 16);
3590 fontWidth = Long2Fix(gui.char_width);
3591
3592 ATSUAttributeTag attribTags[] =
3593 {
3594 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3595 kATSUMaxATSUITagValue + 1
3596 };
3597
3598 ByteCount attribSizes[] =
3599 {
3600 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3601 sizeof(font)
3602 };
3603
3604 ATSUAttributeValuePtr attribValues[] =
3605 {
3606 &fontID, &fontSize, &fontWidth, &font
3607 };
3608
3609 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3610 {
3611 if (ATSUSetAttributes(gFontStyle,
3612 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3613 attribTags, attribSizes, attribValues) != noErr)
3614 {
3615# ifndef NDEBUG
3616 fprintf(stderr, "couldn't set font style\n");
3617# endif
3618 ATSUDisposeStyle(gFontStyle);
3619 gFontStyle = NULL;
3620 }
3621
3622#ifdef FEAT_MBYTE
3623 if (has_mbyte)
3624 {
3625 /* FIXME: we should use a more mbyte sensitive way to support
3626 * wide font drawing */
3627 fontWidth = Long2Fix(gui.char_width * 2);
3628
3629 if (ATSUSetAttributes(gWideFontStyle,
3630 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3631 attribTags, attribSizes, attribValues) != noErr)
3632 {
3633 ATSUDisposeStyle(gWideFontStyle);
3634 gWideFontStyle = NULL;
3635 }
3636 }
3637#endif
3638 }
3639}
3640#endif
3641
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003642/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 * Set the current text font.
3644 */
3645 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003646gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003648#ifdef USE_ATSUI_DRAWING
3649 GuiFont currFont;
3650 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003651
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003652 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003653 {
3654 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003655 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3656 sizeof(font), &currFont, &actualFontByteCount) == noErr
3657 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003658 {
3659 if (currFont == font)
3660 return;
3661 }
3662
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003663 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003664 }
3665
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003666 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003667 {
3668 /* Setup automatic font substitution. The user's guifontwide
3669 * is tried first, then the system tries other fonts. */
3670/*
3671 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3672 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3673 ATSUCreateFontFallbacks(&gFontFallbacks);
3674 ATSUSetObjFontFallbacks(gFontFallbacks, );
3675*/
3676 if (gui.wide_font)
3677 {
3678 ATSUFontID fallbackFonts;
3679 gIsFontFallbackSet = TRUE;
3680
3681 if (FMGetFontFromFontFamilyInstance(
3682 (gui.wide_font & 0xFFFF),
3683 0,
3684 &fallbackFonts,
3685 NULL) == noErr)
3686 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003687 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3688 &fallbackFonts,
3689 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003690 }
3691/*
3692 ATSUAttributeValuePtr fallbackValues[] = { };
3693*/
3694 }
3695 }
3696#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697 TextSize(font >> 16);
3698 TextFont(font & 0xFFFF);
3699}
3700
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701/*
3702 * If a font is not going to be used, free its structure.
3703 */
3704 void
3705gui_mch_free_font(font)
3706 GuiFont font;
3707{
3708 /*
3709 * Free font when "font" is not 0.
3710 * Nothing to do in the current implementation, since
3711 * nothing is allocated for each font used.
3712 */
3713}
3714
3715 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003716hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003717{
3718 if (isdigit(c))
3719 return c - '0';
3720 c = TOLOWER_ASC(c);
3721 if (c >= 'a' && c <= 'f')
3722 return c - 'a' + 10;
3723 return -1000;
3724}
3725
3726/*
3727 * Return the Pixel value (color) for the given color name. This routine was
3728 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3729 * Programmer's Guide.
3730 * Return INVALCOLOR when failed.
3731 */
3732 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003733gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734{
3735 /* TODO: Add support for the new named color of MacOS 8
3736 */
3737 RGBColor MacColor;
3738// guicolor_T color = 0;
3739
3740 typedef struct guicolor_tTable
3741 {
3742 char *name;
3743 guicolor_T color;
3744 } guicolor_tTable;
3745
3746 /*
3747 * The comment at the end of each line is the source
3748 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3749 */
3750 static guicolor_tTable table[] =
3751 {
3752 {"Black", RGB(0x00, 0x00, 0x00)},
3753 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3754 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3755 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3756 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3757 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3758 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003759 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3760 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3761 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3762 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3763 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3764 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3765 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3766 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3767 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3768 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3769 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3770 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3771 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3772 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3773 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3774 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003775 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3776 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 {"white", RGB(0xFF, 0xFF, 0xFF)},
3778 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3779 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3780 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3781 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3782 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3783 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3784 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3785 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3786 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3787 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3788 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3789 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3790 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3791 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3792 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3793 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3794 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3795 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003796 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3798 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3799 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3800 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3801 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3802 };
3803
3804 int r, g, b;
3805 int i;
3806
3807 if (name[0] == '#' && strlen((char *) name) == 7)
3808 {
3809 /* Name is in "#rrggbb" format */
3810 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3811 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3812 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3813 if (r < 0 || g < 0 || b < 0)
3814 return INVALCOLOR;
3815 return RGB(r, g, b);
3816 }
3817 else
3818 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003819 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003821 LMGetHiliteRGB(&MacColor);
3822 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 }
3824 /* Check if the name is one of the colors we know */
3825 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3826 if (STRICMP(name, table[i].name) == 0)
3827 return table[i].color;
3828 }
3829
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 /*
3831 * Last attempt. Look in the file "$VIM/rgb.txt".
3832 */
3833 {
3834#define LINE_LEN 100
3835 FILE *fd;
3836 char line[LINE_LEN];
3837 char_u *fname;
3838
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 if (fname == NULL)
3841 return INVALCOLOR;
3842
3843 fd = fopen((char *)fname, "rt");
3844 vim_free(fname);
3845 if (fd == NULL)
3846 return INVALCOLOR;
3847
3848 while (!feof(fd))
3849 {
3850 int len;
3851 int pos;
3852 char *color;
3853
3854 fgets(line, LINE_LEN, fd);
3855 len = strlen(line);
3856
3857 if (len <= 1 || line[len-1] != '\n')
3858 continue;
3859
3860 line[len-1] = '\0';
3861
3862 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3863 if (i != 3)
3864 continue;
3865
3866 color = line + pos;
3867
3868 if (STRICMP(color, name) == 0)
3869 {
3870 fclose(fd);
3871 return (guicolor_T) RGB(r, g, b);
3872 }
3873 }
3874 fclose(fd);
3875 }
3876
3877 return INVALCOLOR;
3878}
3879
3880/*
3881 * Set the current text foreground color.
3882 */
3883 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003884gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885{
3886 RGBColor TheColor;
3887
3888 TheColor.red = Red(color) * 0x0101;
3889 TheColor.green = Green(color) * 0x0101;
3890 TheColor.blue = Blue(color) * 0x0101;
3891
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003892 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893}
3894
3895/*
3896 * Set the current text background color.
3897 */
3898 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003899gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900{
3901 RGBColor TheColor;
3902
3903 TheColor.red = Red(color) * 0x0101;
3904 TheColor.green = Green(color) * 0x0101;
3905 TheColor.blue = Blue(color) * 0x0101;
3906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003907 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908}
3909
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003910RGBColor specialColor;
3911
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003912/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003913 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003914 */
3915 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003916gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003917{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003918 specialColor.red = Red(color) * 0x0101;
3919 specialColor.green = Green(color) * 0x0101;
3920 specialColor.blue = Blue(color) * 0x0101;
3921}
3922
3923/*
3924 * Draw undercurl at the bottom of the character cell.
3925 */
3926 static void
3927draw_undercurl(int flags, int row, int col, int cells)
3928{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003929 int x;
3930 int offset;
3931 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3932 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003933
3934 RGBForeColor(&specialColor);
3935
3936 offset = val[FILL_X(col) % 8];
3937 MoveTo(FILL_X(col), y - offset);
3938
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003939 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003940 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003941 offset = val[x % 8];
3942 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003943 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003944}
3945
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003946
3947 static void
3948draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950#ifdef FEAT_MBYTE
3951 char_u *tofree = NULL;
3952
3953 if (output_conv.vc_type != CONV_NONE)
3954 {
3955 tofree = string_convert(&output_conv, s, &len);
3956 if (tofree != NULL)
3957 s = tofree;
3958 }
3959#endif
3960
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 /*
3962 * On OS X, try using Quartz-style text antialiasing.
3963 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003964 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 {
3966 /* Quartz antialiasing is available only in OS 10.2 and later. */
3967 UInt32 qd_flags = (p_antialias ?
3968 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003969 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 }
3971
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003972 /*
3973 * When antialiasing we're using srcOr mode, we have to clear the block
3974 * before drawing the text.
3975 * Also needed when 'linespace' is non-zero to remove the cursor and
3976 * underlining.
3977 * But not when drawing transparently.
3978 * The following is like calling gui_mch_clear_block(row, col, row, col +
3979 * len - 1), but without setting the bg color to gui.back_pixel.
3980 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003981 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003982 && !(flags & DRAW_TRANSP))
3983 {
3984 Rect rc;
3985
3986 rc.left = FILL_X(col);
3987 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003988#ifdef FEAT_MBYTE
3989 /* Multibyte computation taken from gui_w32.c */
3990 if (has_mbyte)
3991 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003992 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003993 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003994 }
3995 else
3996#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003997 rc.right = FILL_X(col + len) + (col + len == Columns);
3998 rc.bottom = FILL_Y(row + 1);
3999 EraseRect(&rc);
4000 }
4001
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004002 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 {
4004 StyleParameter face;
4005
4006 face = normal;
4007 if (flags & DRAW_BOLD)
4008 face |= bold;
4009 if (flags & DRAW_UNDERL)
4010 face |= underline;
4011 TextFace(face);
4012
4013 /* Quartz antialiasing works only in srcOr transfer mode. */
4014 TextMode(srcOr);
4015
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 MoveTo(TEXT_X(col), TEXT_Y(row));
4017 DrawText((char*)s, 0, len);
4018 }
4019 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020 {
4021 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004022 TextMode(srcCopy);
4023 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024
4025 /* SelectFont(hdc, gui.currFont); */
4026
4027 if (flags & DRAW_TRANSP)
4028 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004029 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030 }
4031
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004032 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004033 DrawText((char *)s, 0, len);
4034
4035 if (flags & DRAW_BOLD)
4036 {
4037 TextMode(srcOr);
4038 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4039 DrawText((char *)s, 0, len);
4040 }
4041
4042 if (flags & DRAW_UNDERL)
4043 {
4044 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4045 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4046 }
4047 }
4048
4049 if (flags & DRAW_UNDERC)
4050 draw_undercurl(flags, row, col, len);
4051
4052#ifdef FEAT_MBYTE
4053 vim_free(tofree);
4054#endif
4055}
4056
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004057#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004058
4059 static void
4060draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4061{
4062 /* ATSUI requires utf-16 strings */
4063 UniCharCount utf16_len;
4064 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4065 utf16_len /= sizeof(UniChar);
4066
4067 /* - ATSUI automatically antialiases text (Someone)
4068 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004069#ifdef MAC_ATSUI_DEBUG
4070 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4071 row, col, len, len == 1 ? s[0] : ' ');
4072#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004073 /*
4074 * When antialiasing we're using srcOr mode, we have to clear the block
4075 * before drawing the text.
4076 * Also needed when 'linespace' is non-zero to remove the cursor and
4077 * underlining.
4078 * But not when drawing transparently.
4079 * The following is like calling gui_mch_clear_block(row, col, row, col +
4080 * len - 1), but without setting the bg color to gui.back_pixel.
4081 */
4082 if ((flags & DRAW_TRANSP) == 0)
4083 {
4084 Rect rc;
4085
4086 rc.left = FILL_X(col);
4087 rc.top = FILL_Y(row);
4088 /* Multibyte computation taken from gui_w32.c */
4089 if (has_mbyte)
4090 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004091 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02004092 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004093 }
4094 else
4095 rc.right = FILL_X(col + len) + (col + len == Columns);
4096
4097 rc.bottom = FILL_Y(row + 1);
4098 EraseRect(&rc);
4099 }
4100
4101 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004102 TextMode(srcCopy);
4103 TextFace(normal);
4104
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004105 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004106 if (flags & DRAW_TRANSP)
4107 {
4108 TextMode(srcOr);
4109 }
4110
4111 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004112
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004113 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004114 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004115 Boolean attValue = true;
4116 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4117 ByteCount attribSizes[] = { sizeof(Boolean) };
4118 ATSUAttributeValuePtr attribValues[] = { &attValue };
4119
4120 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4121 }
4122
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02004123 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
4124 : kATSStyleNoAntiAliasing;
4125 if (useAntialias != useAntialias_cached)
4126 {
4127 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
4128 ByteCount attribSizes[] = { sizeof(UInt32) };
4129 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4130
4131 if (gFontStyle)
4132 ATSUSetAttributes(gFontStyle, 1, attribTags,
4133 attribSizes, attribValues);
4134 if (gWideFontStyle)
4135 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4136 attribSizes, attribValues);
4137
4138 useAntialias_cached = useAntialias;
4139 }
4140
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004141#ifdef FEAT_MBYTE
4142 if (has_mbyte)
4143 {
4144 int n, width_in_cell, last_width_in_cell;
4145 UniCharArrayOffset offset = 0;
4146 UniCharCount yet_to_draw = 0;
4147 ATSUTextLayout textLayout;
4148 ATSUStyle textStyle;
4149
4150 last_width_in_cell = 1;
4151 ATSUCreateTextLayout(&textLayout);
4152 ATSUSetTextPointerLocation(textLayout, tofree,
4153 kATSUFromTextBeginning,
4154 kATSUToTextEnd, utf16_len);
4155 /*
4156 ATSUSetRunStyle(textLayout, gFontStyle,
4157 kATSUFromTextBeginning, kATSUToTextEnd); */
4158
4159 /* Compute the length in display cells. */
4160 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4161 {
4162 width_in_cell = (*mb_ptr2cells)(s + n);
4163
4164 /* probably we are switching from single byte character
4165 * to multibyte characters (which requires more than one
4166 * cell to draw) */
4167 if (width_in_cell != last_width_in_cell)
4168 {
4169#ifdef MAC_ATSUI_DEBUG
4170 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4171 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4172#endif
4173 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4174 : gFontStyle;
4175
4176 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4177 offset += yet_to_draw;
4178 yet_to_draw = 0;
4179 last_width_in_cell = width_in_cell;
4180 }
4181
4182 yet_to_draw++;
4183 }
4184
4185 if (yet_to_draw)
4186 {
4187#ifdef MAC_ATSUI_DEBUG
4188 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4189 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4190#endif
4191 /* finish the rest style */
4192 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4193 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4194 }
4195
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004196 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004197 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004198 kATSUFromTextBeginning, kATSUToTextEnd,
4199 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004200 ATSUDisposeTextLayout(textLayout);
4201 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004202 else
4203#endif
4204 {
4205 ATSUTextLayout textLayout;
4206
4207 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4208 kATSUFromTextBeginning, kATSUToTextEnd,
4209 utf16_len,
4210 (gFontStyle ? 1 : 0), &utf16_len,
4211 (gFontStyle ? &gFontStyle : NULL),
4212 &textLayout) == noErr)
4213 {
4214 ATSUSetTransientFontMatching(textLayout, TRUE);
4215
4216 ATSUDrawText(textLayout,
4217 kATSUFromTextBeginning, kATSUToTextEnd,
4218 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4219
4220 ATSUDisposeTextLayout(textLayout);
4221 }
4222 }
4223
4224 /* drawing is done, now reset bold to normal */
4225 if (gFontStyle && flags & DRAW_BOLD)
4226 {
4227 Boolean attValue = false;
4228
4229 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4230 ByteCount attribSizes[] = { sizeof(Boolean) };
4231 ATSUAttributeValuePtr attribValues[] = { &attValue };
4232
4233 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4234 attribValues);
4235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236 }
4237
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004238 if (flags & DRAW_UNDERC)
4239 draw_undercurl(flags, row, col, len);
4240
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004242}
4243#endif
4244
4245 void
4246gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4247{
4248#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004249 if (p_macatsui == 0 && p_macatsui_last != 0)
4250 /* switch from macatsui to nomacatsui */
4251 gui_mac_dispose_atsui_style();
4252 else if (p_macatsui != 0 && p_macatsui_last == 0)
4253 /* switch from nomacatsui to macatsui */
4254 gui_mac_create_atsui_style();
4255
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004256 if (p_macatsui)
4257 draw_string_ATSUI(row, col, s, len, flags);
4258 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004260 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261}
4262
4263/*
4264 * Return OK if the key with the termcap name "name" is supported.
4265 */
4266 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004267gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268{
4269 int i;
4270
4271 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4272 if (name[0] == special_keys[i].vim_code0 &&
4273 name[1] == special_keys[i].vim_code1)
4274 return OK;
4275 return FAIL;
4276}
4277
4278 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004279gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004281 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282}
4283
4284 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004285gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286{
4287 /* Do a visual beep by reversing the foreground and background colors */
4288 Rect rc;
4289
4290 /*
4291 * Note: InvertRect() excludes right and bottom of rectangle.
4292 */
4293 rc.left = 0;
4294 rc.top = 0;
4295 rc.right = gui.num_cols * gui.char_width;
4296 rc.bottom = gui.num_rows * gui.char_height;
4297 InvertRect(&rc);
4298
4299 ui_delay((long)msec, TRUE); /* wait for some msec */
4300
4301 InvertRect(&rc);
4302}
4303
4304/*
4305 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4306 */
4307 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004308gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309{
4310 Rect rc;
4311
4312 /*
4313 * Note: InvertRect() excludes right and bottom of rectangle.
4314 */
4315 rc.left = FILL_X(c);
4316 rc.top = FILL_Y(r);
4317 rc.right = rc.left + nc * gui.char_width;
4318 rc.bottom = rc.top + nr * gui.char_height;
4319 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320}
4321
4322/*
4323 * Iconify the GUI window.
4324 */
4325 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004326gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327{
4328 /* TODO: find out what could replace iconify
4329 * -window shade?
4330 * -hide application?
4331 */
4332}
4333
4334#if defined(FEAT_EVAL) || defined(PROTO)
4335/*
4336 * Bring the Vim window to the foreground.
4337 */
4338 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004339gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340{
4341 /* TODO */
4342}
4343#endif
4344
4345/*
4346 * Draw a cursor without focus.
4347 */
4348 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004349gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350{
4351 Rect rc;
4352
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 /*
4354 * Note: FrameRect() excludes right and bottom of rectangle.
4355 */
4356 rc.left = FILL_X(gui.col);
4357 rc.top = FILL_Y(gui.row);
4358 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004359#ifdef FEAT_MBYTE
4360 if (mb_lefthalve(gui.row, gui.col))
4361 rc.right += gui.char_width;
4362#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 rc.bottom = rc.top + gui.char_height;
4364
4365 gui_mch_set_fg_color(color);
4366
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004367 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368}
4369
4370/*
4371 * Draw part of a cursor, only w pixels wide, and h pixels high.
4372 */
4373 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004374gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375{
4376 Rect rc;
4377
4378#ifdef FEAT_RIGHTLEFT
4379 /* vertical line should be on the right of current point */
4380 if (CURSOR_BAR_RIGHT)
4381 rc.left = FILL_X(gui.col + 1) - w;
4382 else
4383#endif
4384 rc.left = FILL_X(gui.col);
4385 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4386 rc.right = rc.left + w;
4387 rc.bottom = rc.top + h;
4388
4389 gui_mch_set_fg_color(color);
4390
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004391 FrameRect(&rc);
4392// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393}
4394
4395
4396
4397/*
4398 * Catch up with any queued X events. This may put keyboard input into the
4399 * input buffer, call resize call-backs, trigger timers etc. If there is
4400 * nothing in the X event queue (& no timers pending), then we return
4401 * immediately.
4402 */
4403 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004404gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405{
4406 /* TODO: find what to do
4407 * maybe call gui_mch_wait_for_chars (0)
4408 * more like look at EventQueue then
4409 * call heart of gui_mch_wait_for_chars;
4410 *
4411 * if (eventther)
4412 * gui_mac_handle_event(&event);
4413 */
4414 EventRecord theEvent;
4415
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004416 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417 if (theEvent.what != nullEvent)
4418 gui_mch_wait_for_chars(0);
4419}
4420
4421/*
4422 * Simple wrapper to neglect more easily the time
4423 * spent inside WaitNextEvent while profiling.
4424 */
4425
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 pascal
4427 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004428WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429{
4430 if (((long) sleep) < -1)
4431 sleep = 32767;
4432 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4433}
4434
4435/*
4436 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4437 * from the keyboard.
4438 * wtime == -1 Wait forever.
4439 * wtime == 0 This should never happen.
4440 * wtime > 0 Wait wtime milliseconds for a character.
4441 * Returns OK if a character was found to be available within the given time,
4442 * or FAIL otherwise.
4443 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004444 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004445gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446{
4447 EventMask mask = (everyEvent);
4448 EventRecord event;
4449 long entryTick;
4450 long currentTick;
4451 long sleeppyTick;
4452
4453 /* If we are providing life feedback with the scrollbar,
4454 * we don't want to try to wait for an event, or else
4455 * there won't be any life feedback.
4456 */
4457 if (dragged_sb != NULL)
4458 return FAIL;
4459 /* TODO: Check if FAIL is the proper return code */
4460
4461 entryTick = TickCount();
4462
4463 allow_scrollbar = TRUE;
4464
4465 do
4466 {
4467/* if (dragRectControl == kCreateEmpty)
4468 {
4469 dragRgn = NULL;
4470 dragRectControl = kNothing;
4471 }
4472 else*/ if (dragRectControl == kCreateRect)
4473 {
4474 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004475 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476 dragRectControl = kNothing;
4477 }
4478 /*
4479 * Don't use gui_mch_update() because then we will spin-lock until a
4480 * char arrives, instead we use WaitNextEventWrp() to hang until an
4481 * event arrives. No need to check for input_buf_full because we are
4482 * returning as soon as it contains a single char.
4483 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004484 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004486 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 else
4488 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004489
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004490 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004492 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 if (input_available())
4494 {
4495 allow_scrollbar = FALSE;
4496 return OK;
4497 }
4498 }
4499 currentTick = TickCount();
4500 }
4501 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4502
4503 allow_scrollbar = FALSE;
4504 return FAIL;
4505}
4506
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507/*
4508 * Output routines.
4509 */
4510
4511/* Flush any output to the screen */
4512 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004513gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514{
4515 /* TODO: Is anything needed here? */
4516}
4517
4518/*
4519 * Clear a rectangular region of the screen from text pos (row1, col1) to
4520 * (row2, col2) inclusive.
4521 */
4522 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004523gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524{
4525 Rect rc;
4526
4527 /*
4528 * Clear one extra pixel at the far right, for when bold characters have
4529 * spilled over to the next column.
4530 */
4531 rc.left = FILL_X(col1);
4532 rc.top = FILL_Y(row1);
4533 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4534 rc.bottom = FILL_Y(row2 + 1);
4535
4536 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004537 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538}
4539
4540/*
4541 * Clear the whole text window.
4542 */
4543 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004544gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545{
4546 Rect rc;
4547
4548 rc.left = 0;
4549 rc.top = 0;
4550 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4551 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4552
4553 gui_mch_set_bg_color(gui.back_pixel);
4554 EraseRect(&rc);
4555/* gui_mch_set_fg_color(gui.norm_pixel);
4556 FrameRect(&rc);
4557*/
4558}
4559
4560/*
4561 * Delete the given number of lines from the given row, scrolling up any
4562 * text further down within the scroll region.
4563 */
4564 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004565gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566{
4567 Rect rc;
4568
4569 /* changed without checking! */
4570 rc.left = FILL_X(gui.scroll_region_left);
4571 rc.right = FILL_X(gui.scroll_region_right + 1);
4572 rc.top = FILL_Y(row);
4573 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4574
4575 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004576 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577
4578 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4579 gui.scroll_region_left,
4580 gui.scroll_region_bot, gui.scroll_region_right);
4581}
4582
4583/*
4584 * Insert the given number of lines before the given row, scrolling down any
4585 * following text within the scroll region.
4586 */
4587 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004588gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589{
4590 Rect rc;
4591
4592 rc.left = FILL_X(gui.scroll_region_left);
4593 rc.right = FILL_X(gui.scroll_region_right + 1);
4594 rc.top = FILL_Y(row);
4595 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4596
4597 gui_mch_set_bg_color(gui.back_pixel);
4598
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004599 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600
4601 /* Update gui.cursor_row if the cursor scrolled or copied over */
4602 if (gui.cursor_row >= gui.row
4603 && gui.cursor_col >= gui.scroll_region_left
4604 && gui.cursor_col <= gui.scroll_region_right)
4605 {
4606 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4607 gui.cursor_row += num_lines;
4608 else if (gui.cursor_row <= gui.scroll_region_bot)
4609 gui.cursor_is_valid = FALSE;
4610 }
4611
4612 gui_clear_block(row, gui.scroll_region_left,
4613 row + num_lines - 1, gui.scroll_region_right);
4614}
4615
4616 /*
4617 * TODO: add a vim format to the clipboard which remember
4618 * LINEWISE, CHARWISE, BLOCKWISE
4619 */
4620
4621 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004622clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623{
4624
4625 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004626 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 Size scrapSize;
4628 ScrapFlavorFlags scrapFlags;
4629 ScrapRef scrap = nil;
4630 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 int type;
4632 char *searchCR;
4633 char_u *tempclip;
4634
4635
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004636 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 if (error != noErr)
4638 return;
4639
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004640 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4641 if (error == noErr)
4642 {
4643 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4644 if (error == noErr && scrapSize > 1)
4645 flavor = 1;
4646 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004648 if (flavor == 0)
4649 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004650 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004651 if (error != noErr)
4652 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004654 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004655 if (error != noErr)
4656 return;
4657 }
4658
4659 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004661 /* In CARBON we don't need a Handle, a pointer is good */
4662 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004664 /* tempclip = lalloc(scrapSize+1, TRUE); */
4665 HLock(textOfClip);
4666 error = GetScrapFlavorData(scrap,
4667 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4668 &scrapSize, *textOfClip);
4669 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004671 if (flavor)
4672 type = **textOfClip;
4673 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004674 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004675
4676 tempclip = lalloc(scrapSize + 1, TRUE);
4677 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4678 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004680#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004681 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004682 /* Convert from utf-16 (clipboard) */
4683 size_t encLen = 0;
4684 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004685
4686 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004688 scrapSize = encLen;
4689 vim_free(tempclip);
4690 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004692 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004694
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004695 searchCR = (char *)tempclip;
4696 while (searchCR != NULL)
4697 {
4698 searchCR = strchr(searchCR, '\r');
4699 if (searchCR != NULL)
4700 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004702
4703 clip_yank_selection(type, tempclip, scrapSize, cbd);
4704
4705 vim_free(tempclip);
4706 HUnlock(textOfClip);
4707
4708 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709}
4710
4711 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004712clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713{
4714 /*
4715 * TODO: Really nothing to do?
4716 */
4717}
4718
4719 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004720clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721{
4722 return OK;
4723}
4724
4725/*
4726 * Send the current selection to the clipboard.
4727 */
4728 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004729clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730{
4731 Handle textOfClip;
4732 long scrapSize;
4733 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735
4736 char_u *str = NULL;
4737
4738 if (!cbd->owned)
4739 return;
4740
4741 clip_get_selection(cbd);
4742
4743 /*
4744 * Once we set the clipboard, lose ownership. If another application sets
4745 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004746 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747 cbd->owned = FALSE;
4748
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004749 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004751#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004752 size_t utf16_len = 0;
4753 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4754 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004756 scrapSize = utf16_len;
4757 vim_free(str);
4758 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 }
4760#endif
4761
4762 if (type >= 0)
4763 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004766 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767 HLock(textOfClip);
4768
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004769 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004770 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004771 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004772 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004773 scrapSize, *textOfClip + 1);
4774 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4775 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 HUnlock(textOfClip);
4777 DisposeHandle(textOfClip);
4778 }
4779
4780 vim_free(str);
4781}
4782
4783 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004784gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785{
4786 Rect VimBound;
4787
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004788/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004790
4791 if (gui.which_scrollbars[SBAR_LEFT])
4792 {
4793 VimBound.left = -gui.scrollbar_width + 1;
4794 }
4795 else
4796 {
4797 VimBound.left = 0;
4798 }
4799
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004802 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803}
4804
4805/*
4806 * Menu stuff.
4807 */
4808
4809 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004810gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811{
4812 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004813 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814 */
4815}
4816
4817 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004818gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819{
4820 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004821 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 */
4823}
4824
4825/*
4826 * Add a sub menu to the menu bar.
4827 */
4828 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004829gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830{
4831 /*
4832 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4833 * TODO: use menu->mnemonic and menu->actext
4834 * TODO: Try to reuse menu id
4835 * Carbon Help suggest to use only id between 1 and 235
4836 */
4837 static long next_avail_id = 128;
4838 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004839#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004840 CFStringRef name;
4841#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004843#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004844 short index;
4845 vimmenu_T *parent = menu->parent;
4846 vimmenu_T *brother = menu->next;
4847
4848 /* Cannot add a menu if ... */
4849 if ((parent != NULL && parent->submenu_id == 0))
4850 return;
4851
4852 /* menu ID greater than 1024 are reserved for ??? */
4853 if (next_avail_id == 1024)
4854 return;
4855
4856 /* My brother could be the PopUp, find my real brother */
4857 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4858 brother = brother->next;
4859
4860 /* Find where to insert the menu (for MenuBar) */
4861 if ((parent == NULL) && (brother != NULL))
4862 menu_after_me = brother->submenu_id;
4863
4864 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4865 if (!menu_is_menubar(menu->name))
4866 menu_after_me = hierMenu;
4867
4868 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004869#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004870 name = menu_title_removing_mnemonic(menu);
4871#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 if (name == NULL)
4875 return;
4876
4877 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 {
4879 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004880 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4881 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 */
4883 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004884#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004885 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4886 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4887#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004888 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004889#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890 next_avail_id++;
4891 }
4892
4893 if (parent == NULL)
4894 {
4895 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4896
4897 /* TODO: Verify if we could only Insert Menu if really part of the
4898 * menubar The Inserted menu are scanned or the Command-key combos
4899 */
4900
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004901 /* Insert the menu */
4902 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004903#if 1
4904 /* Vim should normally update it. TODO: verify */
4905 DrawMenuBar();
4906#endif
4907 }
4908 else
4909 {
4910 /* Adding as a submenu */
4911
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004912 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913
4914 /* Call InsertMenuItem followed by SetMenuItemText
4915 * to avoid special character recognition by InsertMenuItem
4916 */
4917 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004918#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004919 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4920#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004922#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4924 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4925 InsertMenu(menu->submenu_handle, hierMenu);
4926 }
4927
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004928#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004929 CFRelease(name);
4930#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004931 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004932#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933
4934#if 0
4935 /* Done by Vim later on */
4936 DrawMenuBar();
4937#endif
4938}
4939
4940/*
4941 * Add a menu item to a menu
4942 */
4943 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004944gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004946#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004947 CFStringRef name;
4948#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 vimmenu_T *parent = menu->parent;
4952 int menu_inserted;
4953
4954 /* Cannot add item, if the menu have not been created */
4955 if (parent->submenu_id == 0)
4956 return;
4957
4958 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4959 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4960
4961 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004962#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004963 name = menu_title_removing_mnemonic(menu);
4964#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004966#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967
4968 /* Where are just a menu item, so no handle, no id */
4969 menu->submenu_id = 0;
4970 menu->submenu_handle = NULL;
4971
Bram Moolenaar071d4272004-06-13 20:20:40 +00004972 menu_inserted = 0;
4973 if (menu->actext)
4974 {
4975 /* If the accelerator text for the menu item looks like it describes
4976 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4977 * item's command equivalent.
4978 */
4979 int key = 0;
4980 int modifiers = 0;
4981 char_u *p_actext;
4982
4983 p_actext = menu->actext;
Bram Moolenaardc5e2182008-12-24 12:06:26 +00004984 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985 if (*p_actext != 0)
4986 key = 0; /* error: trailing text */
4987 /* find_special_key() returns a keycode with as many of the
4988 * specified modifiers as appropriate already applied (e.g., for
4989 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4990 * as the only modifier). Since we want to display all of the
4991 * modifiers, we need to convert the keycode back to a printable
4992 * character plus modifiers.
4993 * TODO: Write an alternative find_special_key() that doesn't
4994 * apply modifiers.
4995 */
4996 if (key > 0 && key < 32)
4997 {
4998 /* Convert a control key to an uppercase letter. Note that
4999 * by this point it is no longer possible to distinguish
5000 * between, e.g., Ctrl-S and Ctrl-Shift-S.
5001 */
5002 modifiers |= MOD_MASK_CTRL;
5003 key += '@';
5004 }
5005 /* If the keycode is an uppercase letter, set the Shift modifier.
5006 * If it is a lowercase letter, don't set the modifier, but convert
5007 * the letter to uppercase for display in the menu.
5008 */
5009 else if (key >= 'A' && key <= 'Z')
5010 modifiers |= MOD_MASK_SHIFT;
5011 else if (key >= 'a' && key <= 'z')
5012 key += 'A' - 'a';
5013 /* Note: keycodes below 0x22 are reserved by Apple. */
5014 if (key >= 0x22 && vim_isprintc_strict(key))
5015 {
5016 int valid = 1;
5017 char_u mac_mods = kMenuNoModifiers;
5018 /* Convert Vim modifier codes to Menu Manager equivalents. */
5019 if (modifiers & MOD_MASK_SHIFT)
5020 mac_mods |= kMenuShiftModifier;
5021 if (modifiers & MOD_MASK_CTRL)
5022 mac_mods |= kMenuControlModifier;
5023 if (!(modifiers & MOD_MASK_CMD))
5024 mac_mods |= kMenuNoCommandModifier;
5025 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5026 valid = 0; /* TODO: will Alt someday map to Option? */
5027 if (valid)
5028 {
5029 char_u item_txt[10];
5030 /* Insert the menu item after idx, with its command key. */
5031 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5032 item_txt[3] = key;
5033 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5034 /* Set the modifier keys. */
5035 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5036 menu_inserted = 1;
5037 }
5038 }
5039 }
5040 /* Call InsertMenuItem followed by SetMenuItemText
5041 * to avoid special character recognition by InsertMenuItem
5042 */
5043 if (!menu_inserted)
5044 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5045 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005046#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005047 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5048#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005050#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051
5052#if 0
5053 /* Called by Vim */
5054 DrawMenuBar();
5055#endif
5056
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005057#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005058 CFRelease(name);
5059#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060 /* TODO: Can name be freed? */
5061 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005062#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063}
5064
5065 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005066gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067{
5068 /* no tearoff menus */
5069}
5070
5071/*
5072 * Destroy the machine specific menu widget.
5073 */
5074 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005075gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005077 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078
5079 if (index > 0)
5080 {
5081 if (menu->parent)
5082 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083 {
5084 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005085 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086
5087 /* Delete the Menu if it was a hierarchical Menu */
5088 if (menu->submenu_id != 0)
5089 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005090 DeleteMenu(menu->submenu_id);
5091 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092 }
5093 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094 }
5095#ifdef DEBUG_MAC_MENU
5096 else
5097 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005098 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099 }
5100#endif
5101 }
5102 else
5103 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005105 DeleteMenu(menu->submenu_id);
5106 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107 }
5108 }
5109 /* Shouldn't this be already done by Vim. TODO: Check */
5110 DrawMenuBar();
5111}
5112
5113/*
5114 * Make a menu either grey or not grey.
5115 */
5116 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005117gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118{
5119 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005120 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121/*
5122 index = menu->index;
5123*/
5124 if (grey)
5125 {
5126 if (menu->children)
5127 DisableMenuItem(menu->submenu_handle, index);
5128 if (menu->parent)
5129 if (menu->parent->submenu_handle)
5130 DisableMenuItem(menu->parent->submenu_handle, index);
5131 }
5132 else
5133 {
5134 if (menu->children)
5135 EnableMenuItem(menu->submenu_handle, index);
5136 if (menu->parent)
5137 if (menu->parent->submenu_handle)
5138 EnableMenuItem(menu->parent->submenu_handle, index);
5139 }
5140}
5141
5142/*
5143 * Make menu item hidden or not hidden
5144 */
5145 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005146gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147{
5148 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005149 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150}
5151
5152
5153/*
5154 * This is called after setting all the menus to grey/hidden or not.
5155 */
5156 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005157gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158{
5159 DrawMenuBar();
5160}
5161
5162
5163/*
5164 * Scrollbar stuff.
5165 */
5166
5167 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005168gui_mch_enable_scrollbar(
5169 scrollbar_T *sb,
5170 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171{
5172 if (flag)
5173 ShowControl(sb->id);
5174 else
5175 HideControl(sb->id);
5176
5177#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005178 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179#endif
5180}
5181
5182 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005183gui_mch_set_scrollbar_thumb(
5184 scrollbar_T *sb,
5185 long val,
5186 long size,
5187 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188{
5189 SetControl32BitMaximum (sb->id, max);
5190 SetControl32BitMinimum (sb->id, 0);
5191 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005192 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005194 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005195#endif
5196}
5197
5198 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005199gui_mch_set_scrollbar_pos(
5200 scrollbar_T *sb,
5201 int x,
5202 int y,
5203 int w,
5204 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205{
5206 gui_mch_set_bg_color(gui.back_pixel);
5207/* if (gui.which_scrollbars[SBAR_LEFT])
5208 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005209 MoveControl(sb->id, x-16, y);
5210 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 }
5212 else
5213 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005214 MoveControl(sb->id, x, y);
5215 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005216 }*/
5217 if (sb == &gui.bottom_sbar)
5218 h += 1;
5219 else
5220 w += 1;
5221
5222 if (gui.which_scrollbars[SBAR_LEFT])
5223 x -= 15;
5224
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005225 MoveControl(sb->id, x, y);
5226 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005228 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229#endif
5230}
5231
5232 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005233gui_mch_create_scrollbar(
5234 scrollbar_T *sb,
5235 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005236{
5237 Rect bounds;
5238
5239 bounds.top = -16;
5240 bounds.bottom = -10;
5241 bounds.right = -10;
5242 bounds.left = -16;
5243
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005244 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245 &bounds,
5246 "\pScrollBar",
5247 TRUE,
5248 0, /* current*/
5249 0, /* top */
5250 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005251 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252 (long) sb->ident);
5253#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005254 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255#endif
5256}
5257
5258 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005259gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260{
5261 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005262 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005264 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005265#endif
5266}
5267
5268
5269/*
5270 * Cursor blink functions.
5271 *
5272 * This is a simple state machine:
5273 * BLINK_NONE not blinking at all
5274 * BLINK_OFF blinking, cursor is not shown
5275 * BLINK_ON blinking, cursor is shown
5276 */
5277 void
5278gui_mch_set_blinking(long wait, long on, long off)
5279{
5280 /* TODO: TODO: TODO: TODO: */
5281/* blink_waittime = wait;
5282 blink_ontime = on;
5283 blink_offtime = off;*/
5284}
5285
5286/*
5287 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5288 */
5289 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005290gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291{
5292 gui_update_cursor(TRUE, FALSE);
5293 /* TODO: TODO: TODO: TODO: */
5294/* gui_w32_rm_blink_timer();
5295 if (blink_state == BLINK_OFF)
5296 gui_update_cursor(TRUE, FALSE);
5297 blink_state = BLINK_NONE;*/
5298}
5299
5300/*
5301 * Start the cursor blinking. If it was already blinking, this restarts the
5302 * waiting time and shows the cursor.
5303 */
5304 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005305gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005306{
5307 gui_update_cursor(TRUE, FALSE);
5308 /* TODO: TODO: TODO: TODO: */
5309/* gui_w32_rm_blink_timer(); */
5310
5311 /* Only switch blinking on if none of the times is zero */
5312/* if (blink_waittime && blink_ontime && blink_offtime)
5313 {
5314 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5315 (TIMERPROC)_OnBlinkTimer);
5316 blink_state = BLINK_ON;
5317 gui_update_cursor(TRUE, FALSE);
5318 }*/
5319}
5320
5321/*
5322 * Return the RGB value of a pixel as long.
5323 */
5324 long_u
5325gui_mch_get_rgb(guicolor_T pixel)
5326{
5327 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5328}
5329
5330
5331
5332#ifdef FEAT_BROWSE
5333/*
5334 * Pop open a file browser and return the file selected, in allocated memory,
5335 * or NULL if Cancel is hit.
5336 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5337 * title - Title message for the file browser dialog.
5338 * dflt - Default name of file.
5339 * ext - Default extension to be added to files without extensions.
5340 * initdir - directory in which to open the browser (NULL = current dir)
5341 * filter - Filter for matched files to choose from.
5342 * Has a format like this:
5343 * "C Files (*.c)\0*.c\0"
5344 * "All Files\0*.*\0\0"
5345 * If these two strings were concatenated, then a choice of two file
5346 * filters will be selectable to the user. Then only matching files will
5347 * be shown in the browser. If NULL, the default allows all files.
5348 *
5349 * *NOTE* - the filter string must be terminated with TWO nulls.
5350 */
5351 char_u *
5352gui_mch_browse(
5353 int saving,
5354 char_u *title,
5355 char_u *dflt,
5356 char_u *ext,
5357 char_u *initdir,
5358 char_u *filter)
5359{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005360 /* TODO: Add Ammon's safety checl (Dany) */
5361 NavReplyRecord reply;
5362 char_u *fname = NULL;
5363 char_u **fnames = NULL;
5364 long numFiles;
5365 NavDialogOptions navOptions;
5366 OSErr error;
5367
5368 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005369 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005370
5371
5372 /* TODO: If we get a :browse args, set the Multiple bit. */
5373 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5374 | kNavDontAutoTranslate
5375 | kNavDontAddTranslateItems
5376 /* | kNavAllowMultipleFiles */
5377 | kNavAllowStationery;
5378
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005379 (void) C2PascalString(title, &navOptions.message);
5380 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381 /* Could set clientName?
5382 * windowTitle? (there's no title bar?)
5383 */
5384
5385 if (saving)
5386 {
5387 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005388 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005389 if (!reply.validRecord)
5390 return NULL;
5391 }
5392 else
5393 {
5394 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5395 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5396 if (!reply.validRecord)
5397 return NULL;
5398 }
5399
5400 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5401
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005402 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005403
5404 if (fnames)
5405 {
5406 fname = fnames[0];
5407 vim_free(fnames);
5408 }
5409
5410 /* TODO: Shorten the file name if possible */
5411 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005412}
5413#endif /* FEAT_BROWSE */
5414
5415#ifdef FEAT_GUI_DIALOG
5416/*
5417 * Stuff for dialogues
5418 */
5419
5420/*
5421 * Create a dialogue dynamically from the parameter strings.
5422 * type = type of dialogue (question, alert, etc.)
5423 * title = dialogue title. may be NULL for default title.
5424 * message = text to display. Dialogue sizes to accommodate it.
5425 * buttons = '\n' separated list of button captions, default first.
5426 * dfltbutton = number of default button.
5427 *
5428 * This routine returns 1 if the first button is pressed,
5429 * 2 for the second, etc.
5430 *
5431 * 0 indicates Esc was pressed.
5432 * -1 for unexpected error
5433 *
5434 * If stubbing out this fn, return 1.
5435 */
5436
5437typedef struct
5438{
5439 short idx;
5440 short width; /* Size of the text in pixel */
5441 Rect box;
5442} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5443
5444#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5445
5446 static void
5447macMoveDialogItem(
5448 DialogRef theDialog,
5449 short itemNumber,
5450 short X,
5451 short Y,
5452 Rect *inBox)
5453{
5454#if 0 /* USE_CARBONIZED */
5455 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005456 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005457 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005458 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005459#else
5460 short itemType;
5461 Handle itemHandle;
5462 Rect localBox;
5463 Rect *itemBox = &localBox;
5464
5465 if (inBox != nil)
5466 itemBox = inBox;
5467
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005468 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5469 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5470 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471 /* To move a control (like a button) we need to call both
5472 * MoveControl and SetDialogItem. FAQ 6-18 */
5473 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005474 MoveControl((ControlRef) itemHandle, X, Y);
5475 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005476#endif
5477}
5478
5479 static void
5480macSizeDialogItem(
5481 DialogRef theDialog,
5482 short itemNumber,
5483 short width,
5484 short height)
5485{
5486 short itemType;
5487 Handle itemHandle;
5488 Rect itemBox;
5489
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005490 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005491
5492 /* When width or height is zero do not change it */
5493 if (width == 0)
5494 width = itemBox.right - itemBox.left;
5495 if (height == 0)
5496 height = itemBox.bottom - itemBox.top;
5497
5498#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005499 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005500#else
5501 /* Resize the bounding box */
5502 itemBox.right = itemBox.left + width;
5503 itemBox.bottom = itemBox.top + height;
5504
5505 /* To resize a control (like a button) we need to call both
5506 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5507 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005508 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005509
5510 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005511 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005512#endif
5513}
5514
5515 static void
5516macSetDialogItemText(
5517 DialogRef theDialog,
5518 short itemNumber,
5519 Str255 itemName)
5520{
5521 short itemType;
5522 Handle itemHandle;
5523 Rect itemBox;
5524
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005525 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005526
5527 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005528 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005529 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005530 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531}
5532
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005533
5534/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5535 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5536 * setting gDialogHotKeys to NULL disables any hotkey handling.
5537 */
5538 static pascal Boolean
5539DialogHotkeyFilterProc (
5540 DialogRef theDialog,
5541 EventRecord *event,
5542 DialogItemIndex *itemHit)
5543{
5544 char_u keyHit;
5545
5546 if (event->what == keyDown || event->what == autoKey)
5547 {
5548 keyHit = (event->message & charCodeMask);
5549
5550 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5551 {
5552#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5553 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5554#endif
5555 *itemHit = gDialogHotKeys[keyHit];
5556
5557 /* When handing off to StdFilterProc, pretend that the user
5558 * clicked the control manually. Note that this is also supposed
5559 * to cause the button to hilite briefly (to give some user
5560 * feedback), but this seems not to actually work (or it's too
5561 * fast to be seen).
5562 */
5563 event->what = kEventControlSimulateHit;
5564
5565 return true; /* we took care of it */
5566 }
5567
5568 /* Defer to the OS's standard behavior for this event.
5569 * This ensures that Enter will still activate the default button. */
5570 return StdFilterProc(theDialog, event, itemHit);
5571 }
5572 return false; /* Let ModalDialog deal with it */
5573}
5574
5575
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005576/* TODO: There have been some crashes with dialogs, check your inbox
5577 * (Jussi)
5578 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005579 int
5580gui_mch_dialog(
5581 int type,
5582 char_u *title,
5583 char_u *message,
5584 char_u *buttons,
5585 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005586 char_u *textfield,
5587 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588{
5589 Handle buttonDITL;
5590 Handle iconDITL;
5591 Handle inputDITL;
5592 Handle messageDITL;
5593 Handle itemHandle;
5594 Handle iconHandle;
5595 DialogPtr theDialog;
5596 char_u len;
5597 char_u PascalTitle[256]; /* place holder for the title */
5598 char_u name[256];
5599 GrafPtr oldPort;
5600 short itemHit;
5601 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005602 short hotKeys[256]; /* map of hotkey -> control ID */
5603 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604 Rect box;
5605 short button;
5606 short lastButton;
5607 short itemType;
5608 short useIcon;
5609 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005610 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005611 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612 short widestButton = 0;
5613 short dfltButtonEdge = 20; /* gut feeling */
5614 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5615 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5616 short maximumWidth = 400; /* gut feeling */
5617 short maxButtonWidth = 175; /* gut feeling */
5618
5619 short vertical;
5620 short dialogHeight;
5621 short messageLines = 3;
5622 FontInfo textFontInfo;
5623
5624 vgmDlgItm iconItm;
5625 vgmDlgItm messageItm;
5626 vgmDlgItm inputItm;
5627 vgmDlgItm buttonItm;
5628
5629 WindowRef theWindow;
5630
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005631 ModalFilterUPP dialogUPP;
5632
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633 /* Check 'v' flag in 'guioptions': vertical button placement. */
5634 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5635
5636 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005637 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638
5639 /* Get the WindowRef */
5640 theWindow = GetDialogWindow(theDialog);
5641
5642 /* Hide the window.
5643 * 1. to avoid seeing slow drawing
5644 * 2. to prevent a problem seen while moving dialog item
5645 * within a visible window. (non-Carbon MacOS 9)
5646 * Could be avoided by changing the resource.
5647 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005648 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005649
5650 /* Change the graphical port to the dialog,
5651 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005652 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005653 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005654
5655 /* Get the info about the default text,
5656 * used to calculate the height of the message
5657 * and of the text field */
5658 GetFontInfo(&textFontInfo);
5659
5660 /* Set the dialog title */
5661 if (title != NULL)
5662 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005663 (void) C2PascalString(title, &PascalTitle);
5664 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665 }
5666
5667 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005668 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669 buttonChar = buttons;
5670 button = 0;
5671
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005672 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005673 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005674
Bram Moolenaar071d4272004-06-13 20:20:40 +00005675 for (;*buttonChar != 0;)
5676 {
5677 /* Get the name of the button */
5678 button++;
5679 len = 0;
5680 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5681 {
5682 if (*buttonChar != DLG_HOTKEY_CHAR)
5683 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005684 else
5685 {
5686 aHotKey = (char_u)*(buttonChar+1);
5687 if (aHotKey >= 'A' && aHotKey <= 'Z')
5688 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5689 hotKeys[aHotKey] = button;
5690#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5691 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5692#endif
5693 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005694 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005695
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696 if (*buttonChar != 0)
5697 buttonChar++;
5698 name[0] = len;
5699
5700 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005701 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005702
5703 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005704 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705
5706 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708 /* Limite the size of any button to an acceptable value. */
5709 /* TODO: Should be based on the message width */
5710 if (width > maxButtonWidth)
5711 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005712 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005713
5714 totalButtonWidth += width;
5715
5716 if (width > widestButton)
5717 widestButton = width;
5718 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005719 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 lastButton = button;
5721
5722 /* Add the icon to the Dialog Box. */
5723 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005724 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005725 switch (type)
5726 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005727 case VIM_GENERIC:
5728 case VIM_INFO:
5729 case VIM_QUESTION: useIcon = kNoteIcon; break;
5730 case VIM_WARNING: useIcon = kCautionIcon; break;
5731 case VIM_ERROR: useIcon = kStopIcon; break;
5732 default: useIcon = kStopIcon;
5733 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005734 AppendDITL(theDialog, iconDITL, overlayDITL);
5735 ReleaseResource(iconDITL);
5736 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005738 iconHandle = GetIcon(useIcon);
5739 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740
5741 /* Add the message to the Dialog box. */
5742 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005743 messageDITL = GetResource('DITL', 132);
5744 AppendDITL(theDialog, messageDITL, overlayDITL);
5745 ReleaseResource(messageDITL);
5746 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5747 (void) C2PascalString(message, &name);
5748 SetDialogItemText(itemHandle, name);
5749 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005750
5751 /* Add the input box if needed */
5752 if (textfield != NULL)
5753 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005754 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005755 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005756 inputDITL = GetResource('DITL', 132);
5757 AppendDITL(theDialog, inputDITL, overlayDITL);
5758 ReleaseResource(inputDITL);
5759 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5760/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5761 (void) C2PascalString(textfield, &name);
5762 SetDialogItemText(itemHandle, name);
5763 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005764
5765 /* Hotkeys don't make sense if there's a text field */
5766 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005768 else
5769 /* Install hotkey table */
5770 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771
5772 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005773 SetDialogDefaultItem(theDialog, dfltbutton);
5774 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775
5776 /* Reposition element */
5777
5778 /* Check if we need to force vertical */
5779 if (totalButtonWidth > maximumWidth)
5780 vertical = TRUE;
5781
5782 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005783 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005784 iconItm.box.right = box.right;
5785 iconItm.box.bottom = box.bottom;
5786
5787 /* Place Message */
5788 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005789 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5790 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005791
5792 /* Place Input */
5793 if (textfield != NULL)
5794 {
5795 inputItm.box.left = messageItm.box.left;
5796 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005797 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5798 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799 /* Convert the static text into a text edit.
5800 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005801 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5802 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005803 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5804 }
5805
5806 /* Place Button */
5807 if (textfield != NULL)
5808 {
5809 buttonItm.box.left = inputItm.box.left;
5810 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5811 }
5812 else
5813 {
5814 buttonItm.box.left = messageItm.box.left;
5815 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5816 }
5817
5818 for (button=1; button <= lastButton; button++)
5819 {
5820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005821 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005822 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005823 if (vertical)
5824 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005825 macSizeDialogItem(theDialog, button, widestButton, 0);
5826 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005827 }
5828 /* Calculate position of next button */
5829 if (vertical)
5830 buttonItm.box.top = box.bottom + dfltElementSpacing;
5831 else
5832 buttonItm.box.left = box.right + dfltElementSpacing;
5833 }
5834
5835 /* Resize the dialog box */
5836 dialogHeight = box.bottom + dfltElementSpacing;
5837 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5838
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005840 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005841 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842
5843 /* Display it */
5844 ShowWindow(theWindow);
5845/* BringToFront(theWindow); */
5846 SelectWindow(theWindow);
5847
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005848/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005850 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005851 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852#endif
5853
Bram Moolenaard68071d2006-05-02 22:08:30 +00005854#ifdef USE_CARBONKEYHANDLER
5855 /* Avoid that we use key events for the main window. */
5856 dialog_busy = TRUE;
5857#endif
5858
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005859 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5860 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5861
Bram Moolenaar071d4272004-06-13 20:20:40 +00005862 /* Hang until one of the button is hit */
5863 do
5864 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005865 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005866 } while ((itemHit < 1) || (itemHit > lastButton));
5867
Bram Moolenaard68071d2006-05-02 22:08:30 +00005868#ifdef USE_CARBONKEYHANDLER
5869 dialog_busy = FALSE;
5870#endif
5871
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872 /* Copy back the text entered by the user into the param */
5873 if (textfield != NULL)
5874 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005875 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5876 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877#if IOSIZE < 256
5878 /* Truncate the name to IOSIZE if needed */
5879 if (name[0] > IOSIZE)
5880 name[0] = IOSIZE - 1;
5881#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005882 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 }
5884
5885 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005886 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005887
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005888 /* Free the modal filterProc */
5889 DisposeRoutineDescriptor(dialogUPP);
5890
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005892 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005893
5894 return itemHit;
5895/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005896 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005897 * SetDialogTimeout(): Auto click a button after timeout
5898 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5899 * MoveDialogItem(): Probably better than SetDialogItem
5900 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005901 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902 */
5903}
5904#endif /* FEAT_DIALOG_GUI */
5905
5906/*
5907 * Display the saved error message(s).
5908 */
5909#ifdef USE_MCH_ERRMSG
5910 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005911display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912{
5913 char *p;
5914 char_u pError[256];
5915
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005916 if (error_ga.ga_data == NULL)
5917 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005918
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005919 /* avoid putting up a message box with blanks only */
5920 for (p = (char *)error_ga.ga_data; *p; ++p)
5921 if (!isspace(*p))
5922 {
5923 if (STRLEN(p) > 255)
5924 pError[0] = 255;
5925 else
5926 pError[0] = STRLEN(p);
5927
5928 STRNCPY(&pError[1], p, pError[0]);
5929 ParamText(pError, nil, nil, nil);
5930 Alert(128, nil);
5931 break;
5932 /* TODO: handled message longer than 256 chars
5933 * use auto-sizeable alert
5934 * or dialog with scrollbars (TextEdit zone)
5935 */
5936 }
5937 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938}
5939#endif
5940
5941/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005942 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005944 void
5945gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946{
5947 Point where;
5948
5949 GetMouse(&where);
5950
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005951 *x = where.h;
5952 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953}
5954
5955 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005956gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005957{
5958 /* TODO */
5959#if 0
5960 /* From FAQ 3-11 */
5961
5962 CursorDevicePtr myMouse;
5963 Point where;
5964
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005965 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5966 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005967 {
5968 /* New way */
5969
5970 /*
5971 * Get first devoice with one button.
5972 * This will probably be the standad mouse
5973 * startat head of cursor dev list
5974 *
5975 */
5976
5977 myMouse = nil;
5978
5979 do
5980 {
5981 /* Get the next cursor device */
5982 CursorDeviceNextDevice(&myMouse);
5983 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005984 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005985
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005986 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987 }
5988 else
5989 {
5990 /* Old way */
5991 where.h = x;
5992 where.v = y;
5993
5994 *(Point *)RawMouse = where;
5995 *(Point *)MTemp = where;
5996 *(Ptr) CrsrNew = 0xFFFF;
5997 }
5998#endif
5999}
6000
6001 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006002gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006004/*
6005 * Clone PopUp to use menu
6006 * Create a object descriptor for the current selection
6007 * Call the procedure
6008 */
6009
6010 MenuHandle CntxMenu;
6011 Point where;
6012 OSStatus status;
6013 UInt32 CntxType;
6014 SInt16 CntxMenuID;
6015 UInt16 CntxMenuItem;
6016 Str255 HelpName = "";
6017 GrafPtr savePort;
6018
6019 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006020 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006021
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006022 GetMouse(&where);
6023 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024 CntxMenu = menu->submenu_handle;
6025
6026 /* TODO: Get the text selection from Vim */
6027
6028 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006029 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006030 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031
6032 if (status == noErr)
6033 {
6034 if (CntxType == kCMMenuItemSelected)
6035 {
6036 /* Handle the menu CntxMenuID, CntxMenuItem */
6037 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006038 /* But what about the current menu, is the menu changed by
6039 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006040 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041 }
6042 else if (CntxMenuID == kCMShowHelpSelected)
6043 {
6044 /* Should come up with the help */
6045 }
6046 }
6047
6048 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006049 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050}
6051
6052#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6053/* TODO: Is it need for MACOS_X? (Dany) */
6054 void
6055mch_post_buffer_write(buf_T *buf)
6056{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006057 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6058 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059}
6060#endif
6061
6062#ifdef FEAT_TITLE
6063/*
6064 * Set the window title and icon.
6065 * (The icon is not taken care of).
6066 */
6067 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006068gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069{
6070 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6071 * that 256. Even better get it to fit nicely in the titlebar.
6072 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006073#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006074 CFStringRef windowTitle;
6075 size_t windowTitleLen;
6076#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006078#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079
6080 if (title == NULL) /* nothing to do */
6081 return;
6082
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006083#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006084 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00006085 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006086
6087 if (windowTitle)
6088 {
6089 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6090 CFRelease(windowTitle);
6091 }
6092#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006093 pascalTitle = C2Pascal_save(title);
6094 if (pascalTitle != NULL)
6095 {
6096 SetWTitle(gui.VimWindow, pascalTitle);
6097 vim_free(pascalTitle);
6098 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006099#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100}
6101#endif
6102
6103/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006104 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00006105 */
6106
6107 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006108C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006109{
6110 char_u *PascalPtr = (char_u *) PascalString;
6111 int len;
6112 int i;
6113
6114 PascalPtr[0] = 0;
6115 if (CString == NULL)
6116 return 0;
6117
6118 len = STRLEN(CString);
6119 if (len > 255)
6120 len = 255;
6121
6122 for (i = 0; i < len; i++)
6123 PascalPtr[i+1] = CString[i];
6124
6125 PascalPtr[0] = len;
6126
6127 return 0;
6128}
6129
6130 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006131GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006132{
6133 /* From FAQ 8-12 */
6134 Str255 filePascal;
6135 CInfoPBRec myCPB;
6136 OSErr err;
6137
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006138 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139
6140 myCPB.dirInfo.ioNamePtr = filePascal;
6141 myCPB.dirInfo.ioVRefNum = 0;
6142 myCPB.dirInfo.ioFDirIndex = 0;
6143 myCPB.dirInfo.ioDrDirID = 0;
6144
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006145 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006146
6147 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006148 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006149
6150 /* TODO: Use an error code mechanism */
6151 return 0;
6152}
6153
6154/*
6155 * Convert a FSSpec to a fuill path
6156 */
6157
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006158char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006159{
6160 /*
6161 * TODO: Add protection for 256 char max.
6162 */
6163
6164 CInfoPBRec theCPB;
6165 char_u fname[256];
6166 char_u *filenamePtr = fname;
6167 OSErr error;
6168 int folder = 1;
6169#ifdef USE_UNIXFILENAME
6170 SInt16 dfltVol_vRefNum;
6171 SInt32 dfltVol_dirID;
6172 FSRef refFile;
6173 OSStatus status;
6174 UInt32 pathSize = 256;
6175 char_u pathname[256];
6176 char_u *path = pathname;
6177#else
6178 Str255 directoryName;
6179 char_u temporary[255];
6180 char_u *temporaryPtr = temporary;
6181#endif
6182
6183#ifdef USE_UNIXFILENAME
6184 /* Get the default volume */
6185 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006186 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187
6188 if (error)
6189 return NULL;
6190#endif
6191
6192 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006193 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194
6195 /* Get the info about the file specified in FSSpec */
6196 theCPB.dirInfo.ioFDirIndex = 0;
6197 theCPB.dirInfo.ioNamePtr = file.name;
6198 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006199 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200 theCPB.dirInfo.ioDrDirID = file.parID;
6201
6202 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6203 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006204 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006205
6206 /* If we are called for a new file we expect fnfErr */
6207 if ((error) && (error != fnfErr))
6208 return NULL;
6209
6210 /* Check if it's a file or folder */
6211 /* default to file if file don't exist */
6212 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6213 folder = 0; /* It's not a folder */
6214 else
6215 folder = 1;
6216
6217#ifdef USE_UNIXFILENAME
6218 /*
6219 * The function used here are available in Carbon, but
6220 * do nothing une MacOS 8 and 9
6221 */
6222 if (error == fnfErr)
6223 {
6224 /* If the file to be saved does not already exist, it isn't possible
6225 to convert its FSSpec into an FSRef. But we can construct an
6226 FSSpec for the file's parent folder (since we have its volume and
6227 directory IDs), and since that folder does exist, we can convert
6228 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6229 and, finally, append the filename. */
6230 FSSpec dirSpec;
6231 FSRef dirRef;
6232 Str255 emptyFilename = "\p";
6233 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6234 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6235 if (error)
6236 return NULL;
6237
6238 error = FSpMakeFSRef(&dirSpec, &dirRef);
6239 if (error)
6240 return NULL;
6241
6242 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6243 if (status)
6244 return NULL;
6245
6246 STRCAT(path, "/");
6247 STRCAT(path, filenamePtr);
6248 }
6249 else
6250 {
6251 /* If the file to be saved already exists, we can get its full path
6252 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006253 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254 if (error)
6255 return NULL;
6256
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006257 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258 if (status)
6259 return NULL;
6260 }
6261
6262 /* Add a slash at the end if needed */
6263 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006264 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006265
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006266 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006267#else
6268 /* TODO: Get rid of all USE_UNIXFILENAME below */
6269 /* Set ioNamePtr, it's the same area which is always reused. */
6270 theCPB.dirInfo.ioNamePtr = directoryName;
6271
6272 /* Trick for first entry, set ioDrParID to the first value
6273 * we want for ioDrDirID*/
6274 theCPB.dirInfo.ioDrParID = file.parID;
6275 theCPB.dirInfo.ioDrDirID = file.parID;
6276
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006277 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006278 do
6279 {
6280 theCPB.dirInfo.ioFDirIndex = -1;
6281 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6282 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006283 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6285
6286 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6287 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006288 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289
6290 if (error)
6291 return NULL;
6292
6293 /* Put the new directoryName in front of the current fname */
6294 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006295 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 STRCAT(filenamePtr, ":");
6297 STRCAT(filenamePtr, temporaryPtr);
6298 }
6299#if 1 /* def USE_UNIXFILENAME */
6300 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6301 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6302#else
6303 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6304#endif
6305
6306 /* Get the information about the volume on which the file reside */
6307 theCPB.dirInfo.ioFDirIndex = -1;
6308 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6309 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006310 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6312
6313 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6314 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006315 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316
6317 if (error)
6318 return NULL;
6319
6320 /* For MacOS Classic always add the volume name */
6321 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006322 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323#ifdef USE_UNIXFILENAME
6324 if (file.vRefNum != dfltVol_vRefNum)
6325#endif
6326 {
6327 /* Add the volume name */
6328 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006329 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006330 STRCAT(filenamePtr, ":");
6331 STRCAT(filenamePtr, temporaryPtr);
6332
6333#ifdef USE_UNIXFILENAME
6334 STRCPY(temporaryPtr, filenamePtr);
6335 filenamePtr[0] = 0; /* NULL terminate the string */
6336 STRCAT(filenamePtr, "Volumes:");
6337 STRCAT(filenamePtr, temporaryPtr);
6338#endif
6339 }
6340
6341 /* Append final path separator if it's a folder */
6342 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006343 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006344
6345 /* As we use Unix File Name for MacOS X convert it */
6346#ifdef USE_UNIXFILENAME
6347 /* Need to insert leading / */
6348 /* TODO: get the above code to use directly the / */
6349 STRCPY(&temporaryPtr[1], filenamePtr);
6350 temporaryPtr[0] = '/';
6351 STRCPY(filenamePtr, temporaryPtr);
6352 {
6353 char *p;
6354 for (p = fname; *p; p++)
6355 if (*p == ':')
6356 *p = '/';
6357 }
6358#endif
6359
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006360 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006361#endif
6362}
6363
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006364#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006365/*
6366 * Input Method Control functions.
6367 */
6368
6369/*
6370 * Notify cursor position to IM.
6371 */
6372 void
6373im_set_position(int row, int col)
6374{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006375#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006377 im_start_row = row;
6378 im_start_col = col;
6379#endif
6380}
6381
6382static ScriptLanguageRecord gTSLWindow;
6383static ScriptLanguageRecord gTSLInsert;
6384static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6385
6386static Component gTSCWindow;
6387static Component gTSCInsert;
6388static Component gTSCDefault;
6389
6390static int im_initialized = 0;
6391
6392 static void
6393im_on_window_switch(int active)
6394{
6395 ScriptLanguageRecord *slptr = NULL;
6396 OSStatus err;
6397
6398 if (! gui.in_use)
6399 return;
6400
6401 if (im_initialized == 0)
6402 {
6403 im_initialized = 1;
6404
6405 /* save default TSM component (should be U.S.) to default */
6406 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6407 kKeyboardInputMethodClass);
6408 }
6409
6410 if (active == TRUE)
6411 {
6412 im_is_active = TRUE;
6413 ActivateTSMDocument(gTSMDocument);
6414 slptr = &gTSLWindow;
6415
6416 if (slptr)
6417 {
6418 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6419 kKeyboardInputMethodClass);
6420 if (err == noErr)
6421 err = SetTextServiceLanguage(slptr);
6422
6423 if (err == noErr)
6424 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6425 }
6426 }
6427 else
6428 {
6429 err = GetTextServiceLanguage(&gTSLWindow);
6430 if (err == noErr)
6431 slptr = &gTSLWindow;
6432
6433 if (slptr)
6434 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6435 kKeyboardInputMethodClass);
6436
6437 im_is_active = FALSE;
6438 DeactivateTSMDocument(gTSMDocument);
6439 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006440}
6441
6442/*
6443 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6444 */
6445 void
6446im_set_active(int active)
6447{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006448 ScriptLanguageRecord *slptr = NULL;
6449 OSStatus err;
6450
6451 if (! gui.in_use)
6452 return;
6453
6454 if (im_initialized == 0)
6455 {
6456 im_initialized = 1;
6457
6458 /* save default TSM component (should be U.S.) to default */
6459 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6460 kKeyboardInputMethodClass);
6461 }
6462
6463 if (active == TRUE)
6464 {
6465 im_is_active = TRUE;
6466 ActivateTSMDocument(gTSMDocument);
6467 slptr = &gTSLInsert;
6468
6469 if (slptr)
6470 {
6471 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6472 kKeyboardInputMethodClass);
6473 if (err == noErr)
6474 err = SetTextServiceLanguage(slptr);
6475
6476 if (err == noErr)
6477 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6478 }
6479 }
6480 else
6481 {
6482 err = GetTextServiceLanguage(&gTSLInsert);
6483 if (err == noErr)
6484 slptr = &gTSLInsert;
6485
6486 if (slptr)
6487 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6488 kKeyboardInputMethodClass);
6489
6490 /* restore to default when switch to normal mode, so than we could
6491 * enter commands easier */
6492 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6493 kKeyboardInputMethodClass);
6494 SetTextServiceLanguage(&gTSLDefault);
6495
6496 im_is_active = FALSE;
6497 DeactivateTSMDocument(gTSMDocument);
6498 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006499}
6500
6501/*
6502 * Get IM status. When IM is on, return not 0. Else return 0.
6503 */
6504 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006505im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006507 if (! gui.in_use)
6508 return 0;
6509
6510 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006511}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006512
Bram Moolenaar071d4272004-06-13 20:20:40 +00006513#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006514
6515
6516
6517
6518#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6519// drawer implementation
6520static MenuRef contextMenu = NULL;
6521enum
6522{
6523 kTabContextMenuId = 42,
6524};
6525
6526// the caller has to CFRelease() the returned string
6527 static CFStringRef
6528getTabLabel(tabpage_T *page)
6529{
6530 get_tabline_label(page, FALSE);
6531#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006532 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006533#else
6534 // TODO: check internal encoding?
6535 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6536 kCFStringEncodingMacRoman);
6537#endif
6538}
6539
6540
6541#define DRAWER_SIZE 150
6542#define DRAWER_INSET 16
6543
6544static ControlRef dataBrowser = NULL;
6545
6546// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006547// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006548// and because of this, the tab labels and vims internal tabs are out of sync
6549// for a very short time. to prevent inconsistent state, we store the labels
6550// of the tabs, not pointers to the tabs (which are invalid for a short time).
6551static CFStringRef *tabLabels = NULL;
6552static int tabLabelsSize = 0;
6553
6554enum
6555{
6556 kTabsColumn = 'Tabs'
6557};
6558
6559 static int
6560getTabCount(void)
6561{
6562 tabpage_T *tp;
6563 int numTabs = 0;
6564
6565 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006566 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006567 return numTabs;
6568}
6569
6570// data browser item display callback
6571 static OSStatus
6572dbItemDataCallback(ControlRef browser,
6573 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006574 DataBrowserPropertyID property /* column id */,
6575 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006576 Boolean changeValue)
6577{
6578 OSStatus status = noErr;
6579
6580 // assert(property == kTabsColumn); // why is this violated??
6581
6582 // changeValue is true if we have a modifieable list and data was changed.
6583 // In our case, it's always false.
6584 // (that is: if (changeValue) updateInternalData(); else return
6585 // internalData();
6586 if (!changeValue)
6587 {
6588 CFStringRef str;
6589
6590 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6591 str = tabLabels[itemID - 1];
6592 status = SetDataBrowserItemDataText(itemData, str);
6593 }
6594 else
6595 status = errDataBrowserPropertyNotSupported;
6596
6597 return status;
6598}
6599
6600// data browser action callback
6601 static void
6602dbItemNotificationCallback(ControlRef browser,
6603 DataBrowserItemID item,
6604 DataBrowserItemNotification message)
6605{
6606 switch (message)
6607 {
6608 case kDataBrowserItemSelected:
6609 send_tabline_event(item);
6610 break;
6611 }
6612}
6613
6614// callbacks needed for contextual menu:
6615 static void
6616dbGetContextualMenuCallback(ControlRef browser,
6617 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006618 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006619 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006620 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006621{
6622 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6623 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6624 *helpItemString = NULL;
6625
6626 *menu = contextMenu;
6627}
6628
6629 static void
6630dbSelectContextualMenuCallback(ControlRef browser,
6631 MenuRef menu,
6632 UInt32 selectionType,
6633 SInt16 menuID,
6634 MenuItemIndex menuItem)
6635{
6636 if (selectionType == kCMMenuItemSelected)
6637 {
6638 MenuCommand command;
6639 GetMenuItemCommandID(menu, menuItem, &command);
6640
6641 // get tab that was selected when the context menu appeared
6642 // (there is always one tab selected). TODO: check if the context menu
6643 // isn't opened on an item but on empty space (has to be possible some
6644 // way, the finder does it too ;-) )
6645 Handle items = NewHandle(0);
6646 if (items != NULL)
6647 {
6648 int numItems;
6649
6650 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6651 kDataBrowserItemIsSelected, items);
6652 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6653 if (numItems > 0)
6654 {
6655 int idx;
6656 DataBrowserItemID *itemsPtr;
6657
6658 HLock(items);
6659 itemsPtr = (DataBrowserItemID *)*items;
6660 idx = itemsPtr[0];
6661 HUnlock(items);
6662 send_tabline_menu_event(idx, command);
6663 }
6664 DisposeHandle(items);
6665 }
6666 }
6667}
6668
6669// focus callback of the data browser to always leave focus in vim
6670 static OSStatus
6671dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6672{
6673 assert(GetEventClass(event) == kEventClassControl
6674 && GetEventKind(event) == kEventControlSetFocusPart);
6675
6676 return paramErr;
6677}
6678
6679
6680// drawer callback to resize data browser to drawer size
6681 static OSStatus
6682drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6683{
6684 switch (GetEventKind(event))
6685 {
6686 case kEventWindowBoundsChanged: // move or resize
6687 {
6688 UInt32 attribs;
6689 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6690 NULL, sizeof(attribs), NULL, &attribs);
6691 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6692 {
6693 Rect r;
6694 GetWindowBounds(drawer, kWindowContentRgn, &r);
6695 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6696 SetControlBounds(dataBrowser, &r);
6697 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6698 kTabsColumn, r.right);
6699 }
6700 }
6701 break;
6702 }
6703
6704 return eventNotHandledErr;
6705}
6706
6707// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6708// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6709// blue highlights in the list view on these systems, though. Oh well.)
6710
6711
6712#import <mach-o/dyld.h>
6713
6714enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6715
6716 static OSStatus
6717myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6718 OptionBits inAttributesToSet,
6719 OptionBits inAttributesToClear)
6720{
6721 long osVersion;
6722 char *symbolName;
6723 NSSymbol symbol = NULL;
6724 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6725 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6726
6727 Gestalt(gestaltSystemVersion, &osVersion);
6728 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6729 return noErr;
6730
6731 // C name mangling...
6732 symbolName = "_DataBrowserChangeAttributes";
6733 if (!NSIsSymbolNameDefined(symbolName)
6734 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6735 return noErr;
6736
6737 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6738 if (dataBrowserChangeAttributes == NULL)
6739 return noErr; // well...
6740 return dataBrowserChangeAttributes(inDataBrowser,
6741 inAttributesToSet, inAttributesToClear);
6742}
6743
6744 static void
6745initialise_tabline(void)
6746{
6747 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6748 DataBrowserCallbacks dbCallbacks;
6749 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6750 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6751 DataBrowserListViewColumnDesc colDesc;
6752
6753 // drawers have to have compositing enabled
6754 CreateNewWindow(kDrawerWindowClass,
6755 kWindowStandardHandlerAttribute
6756 | kWindowCompositingAttribute
6757 | kWindowResizableAttribute
6758 | kWindowLiveResizeAttribute,
6759 &drawerRect, &drawer);
6760
6761 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6762 SetDrawerParent(drawer, gui.VimWindow);
6763 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6764
6765
6766 // create list view embedded in drawer
6767 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6768 &dataBrowser);
6769
6770 dbCallbacks.version = kDataBrowserLatestCallbacks;
6771 InitDataBrowserCallbacks(&dbCallbacks);
6772 dbCallbacks.u.v1.itemDataCallback =
6773 NewDataBrowserItemDataUPP(dbItemDataCallback);
6774 dbCallbacks.u.v1.itemNotificationCallback =
6775 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6776 dbCallbacks.u.v1.getContextualMenuCallback =
6777 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6778 dbCallbacks.u.v1.selectContextualMenuCallback =
6779 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6780
6781 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6782
6783 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6784 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6785 SetDataBrowserSelectionFlags(dataBrowser,
6786 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6787 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6788 kDataBrowserTableViewFillHilite);
6789 Boolean b = false;
6790 SetControlData(dataBrowser, kControlEntireControl,
6791 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6792
6793 // enable blue background in data browser (this is only in 10.4 and vim
6794 // has to support older osx versions as well, so we have to load this
6795 // function dynamically)
6796 myDataBrowserChangeAttributes(dataBrowser,
6797 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6798
6799 // install callback that keeps focus in vim and away from the data browser
6800 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6801 NULL, NULL);
6802
6803 // install callback that keeps data browser at the size of the drawer
6804 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6805 NULL, NULL);
6806
6807 // add "tabs" column to data browser
6808 colDesc.propertyDesc.propertyID = kTabsColumn;
6809 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6810
6811 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6812 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6813
6814 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6815 colDesc.headerBtnDesc.minimumWidth = 100;
6816 colDesc.headerBtnDesc.maximumWidth = 150;
6817 colDesc.headerBtnDesc.titleOffset = 0;
6818 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6819 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6820 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6821 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6822
6823 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6824
6825 // create tabline popup menu required by vim docs (see :he tabline-menu)
6826 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6827 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6828 TABLINE_MENU_CLOSE, NULL);
6829 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6830 TABLINE_MENU_NEW, NULL);
6831 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6832 TABLINE_MENU_OPEN, NULL);
6833}
6834
6835
6836/*
6837 * Show or hide the tabline.
6838 */
6839 void
6840gui_mch_show_tabline(int showit)
6841{
6842 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006843 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006844 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006845 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006846}
6847
6848/*
6849 * Return TRUE when tabline is displayed.
6850 */
6851 int
6852gui_mch_showing_tabline(void)
6853{
6854 WindowDrawerState state = GetDrawerState(drawer);
6855
6856 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6857}
6858
6859/*
6860 * Update the labels of the tabline.
6861 */
6862 void
6863gui_mch_update_tabline(void)
6864{
6865 tabpage_T *tp;
6866 int numTabs = getTabCount();
6867 int nr = 1;
6868 int curtabidx = 1;
6869
6870 // adjust data browser
6871 if (tabLabels != NULL)
6872 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006873 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006874
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006875 for (i = 0; i < tabLabelsSize; ++i)
6876 CFRelease(tabLabels[i]);
6877 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006878 }
6879 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6880 tabLabelsSize = numTabs;
6881
6882 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6883 {
6884 if (tp == curtab)
6885 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006886 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006887 }
6888
6889 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6890 kDataBrowserItemNoProperty);
6891 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6892 // can pass NULL for the id array
6893 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6894 kDataBrowserItemNoProperty);
6895
6896 DataBrowserItemID item = curtabidx;
6897 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6898}
6899
6900/*
6901 * Set the current tab to "nr". First tab is 1.
6902 */
6903 void
6904gui_mch_set_curtab(nr)
6905 int nr;
6906{
6907 DataBrowserItemID item = nr;
6908 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6909
6910 // TODO: call something like this?: (or restore scroll position, or...)
6911 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6912 kDataBrowserRevealOnly);
6913}
6914
6915#endif // FEAT_GUI_TABLINE