blob: 2f0f7f865713e1192f0b337ed3e364f36920407b [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 */
1483 short /* Shoulde 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;
1826 /* ideal height is as heigh as we can get */
1827 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;
1843 if (gui.which_scrollbars[SBAR_BOTTOM]);
1844 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
2600#if 0
2601
2602/*
2603 * This would be the normal way of invoking the contextual menu
2604 * but the Vim API doesn't seem to a support a request to get
2605 * the menu that we should display
2606 */
2607 void
2608gui_mac_handle_contextual_menu(event)
2609 EventRecord *event;
2610{
2611/*
2612 * Clone PopUp to use menu
2613 * Create a object descriptor for the current selection
2614 * Call the procedure
2615 */
2616
2617// Call to Handle Popup
2618 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2619
2620 if (status != noErr)
2621 return;
2622
2623 if (CntxType == kCMMenuItemSelected)
2624 {
2625 /* Handle the menu CntxMenuID, CntxMenuItem */
2626 /* The submenu can be handle directly by gui_mac_handle_menu */
2627 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002628 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629 }
2630 else if (CntxMenuID == kCMShowHelpSelected)
2631 {
2632 /* Should come up with the help */
2633 }
2634
2635}
2636#endif
2637
2638/*
2639 * Handle menubar selection
2640 */
2641 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002642gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643{
2644 short menu = HiWord(menuChoice);
2645 short item = LoWord(menuChoice);
2646 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647
2648 if (menu == 256) /* TODO: use constant or gui.xyz */
2649 {
2650 if (item == 1)
2651 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 }
2653 else if (item != 0)
2654 {
2655 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2656
2657 if (theVimMenu)
2658 gui_menu_cb(theVimMenu);
2659 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002660 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661}
2662
2663/*
2664 * Dispatch the event to proper handler
2665 */
2666
2667 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002668gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669{
2670 OSErr error;
2671
2672 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002673 if (IsShowContextualMenuClick(event))
2674 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002676 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002678 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002680 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002681 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682
2683 /* Handle normal event */
2684 switch (event->what)
2685 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002686#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 case (keyDown):
2688 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002689 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002691#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002693 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 break;
2695
2696 case (mouseDown):
2697 gui_mac_doMouseDownEvent(event);
2698 break;
2699
2700 case (mouseUp):
2701 gui_mac_doMouseUpEvent(event);
2702 break;
2703
2704 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002705 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 break;
2707
2708 case (diskEvt):
2709 /* We don't need special handling for disk insertion */
2710 break;
2711
2712 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002713 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 break;
2715
2716 case (osEvt):
2717 switch ((event->message >> 24) & 0xFF)
2718 {
2719 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002720 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 break;
2722 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002723 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 break;
2725 }
2726 break;
2727
2728#ifdef USE_AEVENT
2729 case (kHighLevelEvent):
2730 /* Someone's talking to us, through AppleEvents */
2731 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2732 break;
2733#endif
2734 }
2735}
2736
2737/*
2738 * ------------------------------------------------------------
2739 * Unknown Stuff
2740 * ------------------------------------------------------------
2741 */
2742
2743
2744 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002745gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746{
2747 char_u c;
2748 char_u *p;
2749 char_u pFontName[256];
2750 Str255 systemFontname;
2751 short font_id;
2752 short size=9;
2753 GuiFont font;
2754#if 0
2755 char_u *fontNamePtr;
2756#endif
2757
2758 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2759 ;
2760
2761 c = *p;
2762 *p = 0;
2763
2764#if 1
2765 STRCPY(&pFontName[1], font_name);
2766 pFontName[0] = STRLEN(font_name);
2767 *p = c;
2768
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002769 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002770 char_u fontName[256];
2771 char_u *styleStart = vim_strchr(font_name, ':');
2772 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2773 vim_strncpy(fontName, font_name, fontNameLen);
2774
2775 ATSUFontID fontRef;
2776 FMFontStyle fontStyle;
2777 font_id = 0;
2778
2779 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2780 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2781 &fontRef) == noErr)
2782 {
2783 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2784 font_id = 0;
2785 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002786
2787 if (font_id == 0)
2788 {
2789 /*
2790 * Try again, this time replacing underscores in the font name
2791 * with spaces (:set guifont allows the two to be used
2792 * interchangeably; the Font Manager doesn't).
2793 */
2794 int i, changed = FALSE;
2795
2796 for (i = pFontName[0]; i > 0; --i)
2797 {
2798 if (pFontName[i] == '_')
2799 {
2800 pFontName[i] = ' ';
2801 changed = TRUE;
2802 }
2803 }
2804 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002805 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2806 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2807 kFontNoLanguageCode, &fontRef) == noErr)
2808 {
2809 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2810 font_id = 0;
2811 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002812 }
2813
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814#else
2815 /* name = C2Pascal_save(menu->dname); */
2816 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2817
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002818 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819#endif
2820
2821
2822 if (font_id == 0)
2823 {
2824 /* Oups, the system font was it the one the user want */
2825
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002826 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2827 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 if (!EqualString(pFontName, systemFontname, false, false))
2829 return NOFONT;
2830 }
2831 if (*p == ':')
2832 {
2833 p++;
2834 /* Set the values found after ':' */
2835 while (*p)
2836 {
2837 switch (*p++)
2838 {
2839 case 'h':
2840 size = points_to_pixels(p, &p, TRUE);
2841 break;
2842 /*
2843 * TODO: Maybe accept width and styles
2844 */
2845 }
2846 while (*p == ':')
2847 p++;
2848 }
2849 }
2850
2851 if (size < 1)
2852 size = 1; /* Avoid having a size of 0 with system font */
2853
2854 font = (size << 16) + ((long) font_id & 0xFFFF);
2855
2856 return font;
2857}
2858
2859/*
2860 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002861 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 * ------------------------------------------------------------
2863 */
2864
2865/*
2866 * Parse the GUI related command-line arguments. Any arguments used are
2867 * deleted from argv, and *argc is decremented accordingly. This is called
2868 * when vim is started, whether or not the GUI has been started.
2869 */
2870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002871gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872{
2873 /* TODO: Move most of this stuff toward gui_mch_init */
2874#ifdef USE_EXE_NAME
2875 FSSpec applDir;
2876# ifndef USE_FIND_BUNDLE_PATH
2877 short applVRefNum;
2878 long applDirID;
2879 Str255 volName;
2880# else
2881 ProcessSerialNumber psn;
2882 FSRef applFSRef;
2883# endif
2884#endif
2885
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886#if 0
2887 InitCursor();
2888
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890
2891#ifdef USE_AEVENT
2892 (void) InstallAEHandlers();
2893#endif
2894
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002895 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002897 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002899 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
2901 DrawMenuBar();
2902
2903
2904#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002907 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908#endif
2909
2910
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911 CreateNewWindow(kDocumentWindowClass,
2912 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002913 &windRect, &gui.VimWindow);
2914 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915
2916 gui.char_width = 7;
2917 gui.char_height = 11;
2918 gui.char_ascent = 6;
2919 gui.num_rows = 24;
2920 gui.num_cols = 80;
2921 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2922
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002923 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2924 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925
2926 dragRectEnbl = FALSE;
2927 dragRgn = NULL;
2928 dragRectControl = kCreateEmpty;
2929 cursorRgn = NewRgn();
2930#endif
2931#ifdef USE_EXE_NAME
2932# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002933 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002935 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936# else
2937 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2938 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002940 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 /* if (err != noErr) return err; */
2942
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002943 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 /* if (err != noErr) return err; */
2945
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947
2948 /* This technic return NIL when we disallow_gui */
2949# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002950 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952}
2953
2954#ifndef ALWAYS_USE_GUI
2955/*
2956 * Check if the GUI can be started. Called before gvimrc is sourced.
2957 * Return OK or FAIL.
2958 */
2959 int
2960gui_mch_init_check(void)
2961{
2962 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2963 * using the >console
2964 */
2965 if (disallow_gui) /* see main.c for reason to disallow */
2966 return FAIL;
2967 return OK;
2968}
2969#endif
2970
2971 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002972receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973{
2974 int x, y;
2975 int_u modifiers;
2976 char_u **fnames = NULL;
2977 int count;
2978 int i, j;
2979
2980 /* Get drop position, modifiers and count of items */
2981 {
2982 Point point;
2983 SInt16 mouseUpModifiers;
2984 UInt16 countItem;
2985
2986 GetDragMouse(theDrag, &point, NULL);
2987 GlobalToLocal(&point);
2988 x = point.h;
2989 y = point.v;
2990 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2991 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2992 CountDragItems(theDrag, &countItem);
2993 count = countItem;
2994 }
2995
2996 fnames = (char_u **)alloc(count * sizeof(char_u *));
2997 if (fnames == NULL)
2998 return dragNotAcceptedErr;
2999
3000 /* Get file names dropped */
3001 for (i = j = 0; i < count; ++i)
3002 {
3003 DragItemRef item;
3004 OSErr err;
3005 Size size;
3006 FlavorType type = flavorTypeHFS;
3007 HFSFlavor hfsFlavor;
3008
3009 fnames[i] = NULL;
3010 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3011 err = GetFlavorDataSize(theDrag, item, type, &size);
3012 if (err != noErr || size > sizeof(hfsFlavor))
3013 continue;
3014 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3015 if (err != noErr)
3016 continue;
3017 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3018 }
3019 count = j;
3020
3021 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003022
3023 /* Fake mouse event to wake from stall */
3024 PostEvent(mouseUp, 0);
3025
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 return noErr;
3027}
3028
3029/*
3030 * Initialise the GUI. Create all the windows, set up all the call-backs
3031 * etc.
3032 */
3033 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003034gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035{
3036 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003037 Rect windRect;
3038 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003040 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003041 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003042
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003043 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003044 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003045
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046#if 1
3047 InitCursor();
3048
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050
3051#ifdef USE_AEVENT
3052 (void) InstallAEHandlers();
3053#endif
3054
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003055 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003057 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003059 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060
3061 DrawMenuBar();
3062
3063
3064#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003067 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068#endif
3069
3070 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003073 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3075 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003076 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077
3078 gui.char_width = 7;
3079 gui.char_height = 11;
3080 gui.char_ascent = 6;
3081 gui.num_rows = 24;
3082 gui.num_cols = 80;
3083 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3084
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003085 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3086 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003088 /* Install Carbon event callbacks. */
3089 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090
3091 dragRectEnbl = FALSE;
3092 dragRgn = NULL;
3093 dragRectControl = kCreateEmpty;
3094 cursorRgn = NewRgn();
3095#endif
3096 /* Display any pending error messages */
3097 display_errors();
3098
3099 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003100 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 gui.norm_pixel = 0x00000000;
3102 gui.back_pixel = 0x00FFFFFF;
3103
3104 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3105 * file). */
3106 set_normal_colors();
3107
3108 /*
3109 * Check that none of the colors are the same as the background color.
3110 * Then store the current values as the defaults.
3111 */
3112 gui_check_colors();
3113 gui.def_norm_pixel = gui.norm_pixel;
3114 gui.def_back_pixel = gui.back_pixel;
3115
3116 /* Get the colors for the highlight groups (gui_check_colors() might have
3117 * changed them) */
3118 highlight_gui_started();
3119
3120 /*
3121 * Setting the gui constants
3122 */
3123#ifdef FEAT_MENU
3124 gui.menu_height = 0;
3125#endif
3126 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3127 gui.border_offset = gui.border_width = 2;
3128
Bram Moolenaar720c7102007-05-10 18:07:50 +00003129 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130 gui_mch_draw_string() below), enable it for all font sizes. */
3131 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 eventTypeSpec.eventClass = kEventClassMouse;
3134 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3135 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3136 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3137 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3138 {
3139 mouseWheelHandlerRef = NULL;
3140 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3141 mouseWheelHandlerUPP = NULL;
3142 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003144#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003145 InterfaceTypeList supportedServices = { kUnicodeDocument };
3146 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3147
3148 /* We don't support inline input yet, use input window by default */
3149 UseInputWindow(gTSMDocument, TRUE);
3150
3151 /* Should we activate the document by default? */
3152 // ActivateTSMDocument(gTSMDocument);
3153
3154 EventTypeSpec textEventTypes[] = {
3155 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3156 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3157 { kEventClassTextInput, kEventTextInputPosToOffset },
3158 { kEventClassTextInput, kEventTextInputOffsetToPos },
3159 };
3160
3161 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3162 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3163 NR_ELEMS(textEventTypes),
3164 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003165 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003166 DisposeEventHandlerUPP(keyEventHandlerUPP);
3167 keyEventHandlerUPP = NULL;
3168 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003169
3170 EventTypeSpec windowEventTypes[] = {
3171 { kEventClassWindow, kEventWindowActivated },
3172 { kEventClassWindow, kEventWindowDeactivated },
3173 };
3174
3175 /* Install window event handler to support TSMDocument activate and
3176 * deactivate */
3177 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3178 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3179 winEventHandlerUPP,
3180 NR_ELEMS(windowEventTypes),
3181 windowEventTypes, NULL, NULL))
3182 {
3183 DisposeEventHandlerUPP(winEventHandlerUPP);
3184 winEventHandlerUPP = NULL;
3185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186#endif
3187
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003188/*
3189#ifdef FEAT_MBYTE
3190 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3191#endif
3192*/
3193
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003194#ifdef FEAT_GUI_TABLINE
3195 /*
3196 * Create the tabline
3197 */
3198 initialise_tabline();
3199#endif
3200
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201 /* TODO: Load bitmap if using TOOLBAR */
3202 return OK;
3203}
3204
3205/*
3206 * Called when the foreground or background color has been changed.
3207 */
3208 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003209gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210{
3211 /* TODO:
3212 * This proc is called when Normal is set to a value
3213 * so what msut be done? I don't know
3214 */
3215}
3216
3217/*
3218 * Open the GUI window which was created by a call to gui_mch_init().
3219 */
3220 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003221gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222{
3223 ShowWindow(gui.VimWindow);
3224
3225 if (gui_win_x != -1 && gui_win_y != -1)
3226 gui_mch_set_winpos(gui_win_x, gui_win_y);
3227
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 /*
3229 * Make the GUI the foreground process (in case it was launched
3230 * from the Terminal or via :gui).
3231 */
3232 {
3233 ProcessSerialNumber psn;
3234 if (GetCurrentProcess(&psn) == noErr)
3235 SetFrontProcess(&psn);
3236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237
3238 return OK;
3239}
3240
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003241#ifdef USE_ATSUI_DRAWING
3242 static void
3243gui_mac_dispose_atsui_style(void)
3244{
3245 if (p_macatsui && gFontStyle)
3246 ATSUDisposeStyle(gFontStyle);
3247#ifdef FEAT_MBYTE
3248 if (p_macatsui && gWideFontStyle)
3249 ATSUDisposeStyle(gWideFontStyle);
3250#endif
3251}
3252#endif
3253
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 void
3255gui_mch_exit(int rc)
3256{
3257 /* TODO: find out all what is missing here? */
3258 DisposeRgn(cursorRgn);
3259
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003260#ifdef USE_CARBONKEYHANDLER
3261 if (keyEventHandlerUPP)
3262 DisposeEventHandlerUPP(keyEventHandlerUPP);
3263#endif
3264
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 if (mouseWheelHandlerUPP != NULL)
3266 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003268#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003269 gui_mac_dispose_atsui_style();
3270#endif
3271
3272#ifdef USE_CARBONKEYHANDLER
3273 FixTSMDocument(gTSMDocument);
3274 DeactivateTSMDocument(gTSMDocument);
3275 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003276#endif
3277
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 /* Exit to shell? */
3279 exit(rc);
3280}
3281
3282/*
3283 * Get the position of the top left corner of the window.
3284 */
3285 int
3286gui_mch_get_winpos(int *x, int *y)
3287{
3288 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 Rect bounds;
3290 OSStatus status;
3291
3292 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003293 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294
3295 if (status != noErr)
3296 return FAIL;
3297 *x = bounds.left;
3298 *y = bounds.top;
3299 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 return FAIL;
3301}
3302
3303/*
3304 * Set the position of the top left corner of the window to the given
3305 * coordinates.
3306 */
3307 void
3308gui_mch_set_winpos(int x, int y)
3309{
3310 /* TODO: Should make sure the window is move within range
3311 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3312 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003313 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314}
3315
3316 void
3317gui_mch_set_shellsize(
3318 int width,
3319 int height,
3320 int min_width,
3321 int min_height,
3322 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003323 int base_height,
3324 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 CGrafPtr VimPort;
3327 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328
3329 if (gui.which_scrollbars[SBAR_LEFT])
3330 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003331 VimPort = GetWindowPort(gui.VimWindow);
3332 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003334 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 }
3337 else
3338 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003339 VimPort = GetWindowPort(gui.VimWindow);
3340 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003342 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 }
3344
3345 SizeWindow(gui.VimWindow, width, height, TRUE);
3346
3347 gui_resize_shell(width, height);
3348}
3349
3350/*
3351 * Get the screen dimensions.
3352 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3353 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003354 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 */
3356 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003357gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358{
3359 GDHandle dominantDevice = GetMainDevice();
3360 Rect screenRect = (**dominantDevice).gdRect;
3361
3362 *screen_w = screenRect.right - 10;
3363 *screen_h = screenRect.bottom - 40;
3364}
3365
3366
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003367/*
3368 * Open the Font Panel and wait for the user to select a font and
3369 * close the panel. Then fill the buffer pointed to by font_name with
3370 * the name and size of the selected font and return the font's handle,
3371 * or NOFONT in case of an error.
3372 */
3373 static GuiFont
3374gui_mac_select_font(char_u *font_name)
3375{
3376 GuiFont selected_font = NOFONT;
3377 OSStatus status;
3378 FontSelectionQDStyle curr_font;
3379
3380 /* Initialize the Font Panel with the current font. */
3381 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3382 curr_font.size = (gui.norm_font >> 16);
3383 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3384 curr_font.instance.fontStyle = 0;
3385 curr_font.hasColor = false;
3386 curr_font.version = 0; /* version number of the style structure */
3387 status = SetFontInfoForSelection(kFontSelectionQDType,
3388 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3389
3390 gFontPanelInfo.family = curr_font.instance.fontFamily;
3391 gFontPanelInfo.style = curr_font.instance.fontStyle;
3392 gFontPanelInfo.size = curr_font.size;
3393
3394 /* Pop up the Font Panel. */
3395 status = FPShowHideFontPanel();
3396 if (status == noErr)
3397 {
3398 /*
3399 * The Font Panel is modeless. We really need it to be modal,
3400 * so we spin in an event loop until the panel is closed.
3401 */
3402 gFontPanelInfo.isPanelVisible = true;
3403 while (gFontPanelInfo.isPanelVisible)
3404 {
3405 EventRecord e;
3406 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3407 }
3408
3409 GetFontPanelSelection(font_name);
3410 selected_font = gui_mac_find_font(font_name);
3411 }
3412 return selected_font;
3413}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003414
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003415#ifdef USE_ATSUI_DRAWING
3416 static void
3417gui_mac_create_atsui_style(void)
3418{
3419 if (p_macatsui && gFontStyle == NULL)
3420 {
3421 if (ATSUCreateStyle(&gFontStyle) != noErr)
3422 gFontStyle = NULL;
3423 }
3424#ifdef FEAT_MBYTE
3425 if (p_macatsui && gWideFontStyle == NULL)
3426 {
3427 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3428 gWideFontStyle = NULL;
3429 }
3430#endif
3431
3432 p_macatsui_last = p_macatsui;
3433}
3434#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435
3436/*
3437 * Initialise vim to use the font with the given name. Return FAIL if the font
3438 * could not be loaded, OK otherwise.
3439 */
3440 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003441gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442{
3443 /* TODO: Add support for bold italic underline proportional etc... */
3444 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003445 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 FontInfo font_info;
3447 short font_id;
3448 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003449 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003450
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003451#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003452 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003453#endif
3454
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455 if (font_name == NULL)
3456 {
3457 /* First try to get the suggested font */
3458 GetFNum(suggestedFont, &font_id);
3459
3460 if (font_id == 0)
3461 {
3462 /* Then pickup the standard application font */
3463 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003464 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003466 else
3467 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3469 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003470 else if (STRCMP(font_name, "*") == 0)
3471 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003473
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003474 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003475 if (font == NOFONT)
3476 return FAIL;
3477
3478 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003479 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003480 if (new_p_guifont != NULL)
3481 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003482 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003483 vim_free(p_guifont);
3484 p_guifont = new_p_guifont;
3485 /* Replace spaces in the font name with underscores. */
3486 for ( ; *new_p_guifont; ++new_p_guifont)
3487 {
3488 if (*new_p_guifont == ' ')
3489 *new_p_guifont = '_';
3490 }
3491 }
3492 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 else
3494 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003495 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003496 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497
3498 if (font == NOFONT)
3499 return FAIL;
3500 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003501
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 gui.norm_font = font;
3503
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003504 hl_set_font_name(used_font_name);
3505
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003506 TextSize(font >> 16);
3507 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003509 GetFontInfo(&font_info);
3510
3511 gui.char_ascent = font_info.ascent;
3512 gui.char_width = CharWidth('_');
3513 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3514
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003515#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003516 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003517 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003518#endif
3519
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521}
3522
Bram Moolenaar02743632005-07-25 20:42:36 +00003523/*
3524 * Adjust gui.char_height (after 'linespace' was changed).
3525 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003527gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528{
3529 FontInfo font_info;
3530
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003531 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3533 gui.char_ascent = font_info.ascent + p_linespace / 2;
3534 return OK;
3535}
3536
3537/*
3538 * Get a font structure for highlighting.
3539 */
3540 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003541gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542{
3543 GuiFont font;
3544
3545 font = gui_mac_find_font(name);
3546
3547 if (font == NOFONT)
3548 {
3549 if (giveErrorIfMissing)
3550 EMSG2(_(e_font), name);
3551 return NOFONT;
3552 }
3553 /*
3554 * TODO : Accept only monospace
3555 */
3556
3557 return font;
3558}
3559
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003560#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003562 * Return the name of font "font" in allocated memory.
3563 * Don't know how to get the actual name, thus use the provided name.
3564 */
3565 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003566gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003567{
3568 if (name == NULL)
3569 return NULL;
3570 return vim_strsave(name);
3571}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003572#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003573
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003574#ifdef USE_ATSUI_DRAWING
3575 static void
3576gui_mac_set_font_attributes(GuiFont font)
3577{
3578 ATSUFontID fontID;
3579 Fixed fontSize;
3580 Fixed fontWidth;
3581
3582 fontID = font & 0xFFFF;
3583 fontSize = Long2Fix(font >> 16);
3584 fontWidth = Long2Fix(gui.char_width);
3585
3586 ATSUAttributeTag attribTags[] =
3587 {
3588 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3589 kATSUMaxATSUITagValue + 1
3590 };
3591
3592 ByteCount attribSizes[] =
3593 {
3594 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3595 sizeof(font)
3596 };
3597
3598 ATSUAttributeValuePtr attribValues[] =
3599 {
3600 &fontID, &fontSize, &fontWidth, &font
3601 };
3602
3603 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3604 {
3605 if (ATSUSetAttributes(gFontStyle,
3606 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3607 attribTags, attribSizes, attribValues) != noErr)
3608 {
3609# ifndef NDEBUG
3610 fprintf(stderr, "couldn't set font style\n");
3611# endif
3612 ATSUDisposeStyle(gFontStyle);
3613 gFontStyle = NULL;
3614 }
3615
3616#ifdef FEAT_MBYTE
3617 if (has_mbyte)
3618 {
3619 /* FIXME: we should use a more mbyte sensitive way to support
3620 * wide font drawing */
3621 fontWidth = Long2Fix(gui.char_width * 2);
3622
3623 if (ATSUSetAttributes(gWideFontStyle,
3624 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3625 attribTags, attribSizes, attribValues) != noErr)
3626 {
3627 ATSUDisposeStyle(gWideFontStyle);
3628 gWideFontStyle = NULL;
3629 }
3630 }
3631#endif
3632 }
3633}
3634#endif
3635
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003636/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 * Set the current text font.
3638 */
3639 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003640gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003641{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003642#ifdef USE_ATSUI_DRAWING
3643 GuiFont currFont;
3644 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003645
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003646 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003647 {
3648 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003649 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3650 sizeof(font), &currFont, &actualFontByteCount) == noErr
3651 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003652 {
3653 if (currFont == font)
3654 return;
3655 }
3656
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003657 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003658 }
3659
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003660 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003661 {
3662 /* Setup automatic font substitution. The user's guifontwide
3663 * is tried first, then the system tries other fonts. */
3664/*
3665 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3666 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3667 ATSUCreateFontFallbacks(&gFontFallbacks);
3668 ATSUSetObjFontFallbacks(gFontFallbacks, );
3669*/
3670 if (gui.wide_font)
3671 {
3672 ATSUFontID fallbackFonts;
3673 gIsFontFallbackSet = TRUE;
3674
3675 if (FMGetFontFromFontFamilyInstance(
3676 (gui.wide_font & 0xFFFF),
3677 0,
3678 &fallbackFonts,
3679 NULL) == noErr)
3680 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003681 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3682 &fallbackFonts,
3683 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003684 }
3685/*
3686 ATSUAttributeValuePtr fallbackValues[] = { };
3687*/
3688 }
3689 }
3690#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691 TextSize(font >> 16);
3692 TextFont(font & 0xFFFF);
3693}
3694
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695/*
3696 * If a font is not going to be used, free its structure.
3697 */
3698 void
3699gui_mch_free_font(font)
3700 GuiFont font;
3701{
3702 /*
3703 * Free font when "font" is not 0.
3704 * Nothing to do in the current implementation, since
3705 * nothing is allocated for each font used.
3706 */
3707}
3708
3709 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003710hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711{
3712 if (isdigit(c))
3713 return c - '0';
3714 c = TOLOWER_ASC(c);
3715 if (c >= 'a' && c <= 'f')
3716 return c - 'a' + 10;
3717 return -1000;
3718}
3719
3720/*
3721 * Return the Pixel value (color) for the given color name. This routine was
3722 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3723 * Programmer's Guide.
3724 * Return INVALCOLOR when failed.
3725 */
3726 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003727gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728{
3729 /* TODO: Add support for the new named color of MacOS 8
3730 */
3731 RGBColor MacColor;
3732// guicolor_T color = 0;
3733
3734 typedef struct guicolor_tTable
3735 {
3736 char *name;
3737 guicolor_T color;
3738 } guicolor_tTable;
3739
3740 /*
3741 * The comment at the end of each line is the source
3742 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3743 */
3744 static guicolor_tTable table[] =
3745 {
3746 {"Black", RGB(0x00, 0x00, 0x00)},
3747 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3748 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3749 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3750 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3751 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3752 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003753 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3754 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3755 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3756 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3757 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3758 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3759 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3760 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3761 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3762 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3763 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3764 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3765 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3766 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3767 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3768 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003769 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3770 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 {"white", RGB(0xFF, 0xFF, 0xFF)},
3772 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3773 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3774 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3775 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3776 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3777 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3778 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3779 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3780 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3781 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3782 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3783 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3784 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3785 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3786 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3787 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3788 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3789 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003790 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3792 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3793 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3794 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3795 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3796 };
3797
3798 int r, g, b;
3799 int i;
3800
3801 if (name[0] == '#' && strlen((char *) name) == 7)
3802 {
3803 /* Name is in "#rrggbb" format */
3804 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3805 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3806 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3807 if (r < 0 || g < 0 || b < 0)
3808 return INVALCOLOR;
3809 return RGB(r, g, b);
3810 }
3811 else
3812 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003813 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003815 LMGetHiliteRGB(&MacColor);
3816 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 }
3818 /* Check if the name is one of the colors we know */
3819 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3820 if (STRICMP(name, table[i].name) == 0)
3821 return table[i].color;
3822 }
3823
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 /*
3825 * Last attempt. Look in the file "$VIM/rgb.txt".
3826 */
3827 {
3828#define LINE_LEN 100
3829 FILE *fd;
3830 char line[LINE_LEN];
3831 char_u *fname;
3832
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 if (fname == NULL)
3835 return INVALCOLOR;
3836
3837 fd = fopen((char *)fname, "rt");
3838 vim_free(fname);
3839 if (fd == NULL)
3840 return INVALCOLOR;
3841
3842 while (!feof(fd))
3843 {
3844 int len;
3845 int pos;
3846 char *color;
3847
3848 fgets(line, LINE_LEN, fd);
3849 len = strlen(line);
3850
3851 if (len <= 1 || line[len-1] != '\n')
3852 continue;
3853
3854 line[len-1] = '\0';
3855
3856 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3857 if (i != 3)
3858 continue;
3859
3860 color = line + pos;
3861
3862 if (STRICMP(color, name) == 0)
3863 {
3864 fclose(fd);
3865 return (guicolor_T) RGB(r, g, b);
3866 }
3867 }
3868 fclose(fd);
3869 }
3870
3871 return INVALCOLOR;
3872}
3873
3874/*
3875 * Set the current text foreground color.
3876 */
3877 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003878gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879{
3880 RGBColor TheColor;
3881
3882 TheColor.red = Red(color) * 0x0101;
3883 TheColor.green = Green(color) * 0x0101;
3884 TheColor.blue = Blue(color) * 0x0101;
3885
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003886 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887}
3888
3889/*
3890 * Set the current text background color.
3891 */
3892 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003893gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894{
3895 RGBColor TheColor;
3896
3897 TheColor.red = Red(color) * 0x0101;
3898 TheColor.green = Green(color) * 0x0101;
3899 TheColor.blue = Blue(color) * 0x0101;
3900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003901 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902}
3903
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003904RGBColor specialColor;
3905
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003906/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003907 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003908 */
3909 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003910gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003911{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003912 specialColor.red = Red(color) * 0x0101;
3913 specialColor.green = Green(color) * 0x0101;
3914 specialColor.blue = Blue(color) * 0x0101;
3915}
3916
3917/*
3918 * Draw undercurl at the bottom of the character cell.
3919 */
3920 static void
3921draw_undercurl(int flags, int row, int col, int cells)
3922{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003923 int x;
3924 int offset;
3925 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3926 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003927
3928 RGBForeColor(&specialColor);
3929
3930 offset = val[FILL_X(col) % 8];
3931 MoveTo(FILL_X(col), y - offset);
3932
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003933 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003934 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003935 offset = val[x % 8];
3936 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003937 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003938}
3939
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003940
3941 static void
3942draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944#ifdef FEAT_MBYTE
3945 char_u *tofree = NULL;
3946
3947 if (output_conv.vc_type != CONV_NONE)
3948 {
3949 tofree = string_convert(&output_conv, s, &len);
3950 if (tofree != NULL)
3951 s = tofree;
3952 }
3953#endif
3954
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 /*
3956 * On OS X, try using Quartz-style text antialiasing.
3957 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003958 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 {
3960 /* Quartz antialiasing is available only in OS 10.2 and later. */
3961 UInt32 qd_flags = (p_antialias ?
3962 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003963 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964 }
3965
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003966 /*
3967 * When antialiasing we're using srcOr mode, we have to clear the block
3968 * before drawing the text.
3969 * Also needed when 'linespace' is non-zero to remove the cursor and
3970 * underlining.
3971 * But not when drawing transparently.
3972 * The following is like calling gui_mch_clear_block(row, col, row, col +
3973 * len - 1), but without setting the bg color to gui.back_pixel.
3974 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003975 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003976 && !(flags & DRAW_TRANSP))
3977 {
3978 Rect rc;
3979
3980 rc.left = FILL_X(col);
3981 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003982#ifdef FEAT_MBYTE
3983 /* Multibyte computation taken from gui_w32.c */
3984 if (has_mbyte)
3985 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003986 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003987 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003988 }
3989 else
3990#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003991 rc.right = FILL_X(col + len) + (col + len == Columns);
3992 rc.bottom = FILL_Y(row + 1);
3993 EraseRect(&rc);
3994 }
3995
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003996 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 {
3998 StyleParameter face;
3999
4000 face = normal;
4001 if (flags & DRAW_BOLD)
4002 face |= bold;
4003 if (flags & DRAW_UNDERL)
4004 face |= underline;
4005 TextFace(face);
4006
4007 /* Quartz antialiasing works only in srcOr transfer mode. */
4008 TextMode(srcOr);
4009
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010 MoveTo(TEXT_X(col), TEXT_Y(row));
4011 DrawText((char*)s, 0, len);
4012 }
4013 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 {
4015 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004016 TextMode(srcCopy);
4017 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018
4019 /* SelectFont(hdc, gui.currFont); */
4020
4021 if (flags & DRAW_TRANSP)
4022 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004023 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 }
4025
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004026 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004027 DrawText((char *)s, 0, len);
4028
4029 if (flags & DRAW_BOLD)
4030 {
4031 TextMode(srcOr);
4032 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4033 DrawText((char *)s, 0, len);
4034 }
4035
4036 if (flags & DRAW_UNDERL)
4037 {
4038 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4039 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4040 }
4041 }
4042
4043 if (flags & DRAW_UNDERC)
4044 draw_undercurl(flags, row, col, len);
4045
4046#ifdef FEAT_MBYTE
4047 vim_free(tofree);
4048#endif
4049}
4050
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004051#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004052
4053 static void
4054draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4055{
4056 /* ATSUI requires utf-16 strings */
4057 UniCharCount utf16_len;
4058 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4059 utf16_len /= sizeof(UniChar);
4060
4061 /* - ATSUI automatically antialiases text (Someone)
4062 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004063#ifdef MAC_ATSUI_DEBUG
4064 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4065 row, col, len, len == 1 ? s[0] : ' ');
4066#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004067 /*
4068 * When antialiasing we're using srcOr mode, we have to clear the block
4069 * before drawing the text.
4070 * Also needed when 'linespace' is non-zero to remove the cursor and
4071 * underlining.
4072 * But not when drawing transparently.
4073 * The following is like calling gui_mch_clear_block(row, col, row, col +
4074 * len - 1), but without setting the bg color to gui.back_pixel.
4075 */
4076 if ((flags & DRAW_TRANSP) == 0)
4077 {
4078 Rect rc;
4079
4080 rc.left = FILL_X(col);
4081 rc.top = FILL_Y(row);
4082 /* Multibyte computation taken from gui_w32.c */
4083 if (has_mbyte)
4084 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004085 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02004086 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004087 }
4088 else
4089 rc.right = FILL_X(col + len) + (col + len == Columns);
4090
4091 rc.bottom = FILL_Y(row + 1);
4092 EraseRect(&rc);
4093 }
4094
4095 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004096 TextMode(srcCopy);
4097 TextFace(normal);
4098
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004099 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004100 if (flags & DRAW_TRANSP)
4101 {
4102 TextMode(srcOr);
4103 }
4104
4105 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004106
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004107 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004108 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004109 Boolean attValue = true;
4110 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4111 ByteCount attribSizes[] = { sizeof(Boolean) };
4112 ATSUAttributeValuePtr attribValues[] = { &attValue };
4113
4114 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4115 }
4116
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02004117 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
4118 : kATSStyleNoAntiAliasing;
4119 if (useAntialias != useAntialias_cached)
4120 {
4121 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
4122 ByteCount attribSizes[] = { sizeof(UInt32) };
4123 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4124
4125 if (gFontStyle)
4126 ATSUSetAttributes(gFontStyle, 1, attribTags,
4127 attribSizes, attribValues);
4128 if (gWideFontStyle)
4129 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4130 attribSizes, attribValues);
4131
4132 useAntialias_cached = useAntialias;
4133 }
4134
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004135#ifdef FEAT_MBYTE
4136 if (has_mbyte)
4137 {
4138 int n, width_in_cell, last_width_in_cell;
4139 UniCharArrayOffset offset = 0;
4140 UniCharCount yet_to_draw = 0;
4141 ATSUTextLayout textLayout;
4142 ATSUStyle textStyle;
4143
4144 last_width_in_cell = 1;
4145 ATSUCreateTextLayout(&textLayout);
4146 ATSUSetTextPointerLocation(textLayout, tofree,
4147 kATSUFromTextBeginning,
4148 kATSUToTextEnd, utf16_len);
4149 /*
4150 ATSUSetRunStyle(textLayout, gFontStyle,
4151 kATSUFromTextBeginning, kATSUToTextEnd); */
4152
4153 /* Compute the length in display cells. */
4154 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4155 {
4156 width_in_cell = (*mb_ptr2cells)(s + n);
4157
4158 /* probably we are switching from single byte character
4159 * to multibyte characters (which requires more than one
4160 * cell to draw) */
4161 if (width_in_cell != last_width_in_cell)
4162 {
4163#ifdef MAC_ATSUI_DEBUG
4164 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4165 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4166#endif
4167 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4168 : gFontStyle;
4169
4170 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4171 offset += yet_to_draw;
4172 yet_to_draw = 0;
4173 last_width_in_cell = width_in_cell;
4174 }
4175
4176 yet_to_draw++;
4177 }
4178
4179 if (yet_to_draw)
4180 {
4181#ifdef MAC_ATSUI_DEBUG
4182 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4183 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4184#endif
4185 /* finish the rest style */
4186 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4187 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4188 }
4189
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004190 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004191 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004192 kATSUFromTextBeginning, kATSUToTextEnd,
4193 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004194 ATSUDisposeTextLayout(textLayout);
4195 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004196 else
4197#endif
4198 {
4199 ATSUTextLayout textLayout;
4200
4201 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4202 kATSUFromTextBeginning, kATSUToTextEnd,
4203 utf16_len,
4204 (gFontStyle ? 1 : 0), &utf16_len,
4205 (gFontStyle ? &gFontStyle : NULL),
4206 &textLayout) == noErr)
4207 {
4208 ATSUSetTransientFontMatching(textLayout, TRUE);
4209
4210 ATSUDrawText(textLayout,
4211 kATSUFromTextBeginning, kATSUToTextEnd,
4212 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4213
4214 ATSUDisposeTextLayout(textLayout);
4215 }
4216 }
4217
4218 /* drawing is done, now reset bold to normal */
4219 if (gFontStyle && flags & DRAW_BOLD)
4220 {
4221 Boolean attValue = false;
4222
4223 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4224 ByteCount attribSizes[] = { sizeof(Boolean) };
4225 ATSUAttributeValuePtr attribValues[] = { &attValue };
4226
4227 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4228 attribValues);
4229 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004230 }
4231
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004232 if (flags & DRAW_UNDERC)
4233 draw_undercurl(flags, row, col, len);
4234
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004236}
4237#endif
4238
4239 void
4240gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4241{
4242#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004243 if (p_macatsui == 0 && p_macatsui_last != 0)
4244 /* switch from macatsui to nomacatsui */
4245 gui_mac_dispose_atsui_style();
4246 else if (p_macatsui != 0 && p_macatsui_last == 0)
4247 /* switch from nomacatsui to macatsui */
4248 gui_mac_create_atsui_style();
4249
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004250 if (p_macatsui)
4251 draw_string_ATSUI(row, col, s, len, flags);
4252 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004254 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255}
4256
4257/*
4258 * Return OK if the key with the termcap name "name" is supported.
4259 */
4260 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004261gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262{
4263 int i;
4264
4265 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4266 if (name[0] == special_keys[i].vim_code0 &&
4267 name[1] == special_keys[i].vim_code1)
4268 return OK;
4269 return FAIL;
4270}
4271
4272 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004273gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004275 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276}
4277
4278 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004279gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280{
4281 /* Do a visual beep by reversing the foreground and background colors */
4282 Rect rc;
4283
4284 /*
4285 * Note: InvertRect() excludes right and bottom of rectangle.
4286 */
4287 rc.left = 0;
4288 rc.top = 0;
4289 rc.right = gui.num_cols * gui.char_width;
4290 rc.bottom = gui.num_rows * gui.char_height;
4291 InvertRect(&rc);
4292
4293 ui_delay((long)msec, TRUE); /* wait for some msec */
4294
4295 InvertRect(&rc);
4296}
4297
4298/*
4299 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4300 */
4301 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004302gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303{
4304 Rect rc;
4305
4306 /*
4307 * Note: InvertRect() excludes right and bottom of rectangle.
4308 */
4309 rc.left = FILL_X(c);
4310 rc.top = FILL_Y(r);
4311 rc.right = rc.left + nc * gui.char_width;
4312 rc.bottom = rc.top + nr * gui.char_height;
4313 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314}
4315
4316/*
4317 * Iconify the GUI window.
4318 */
4319 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004320gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321{
4322 /* TODO: find out what could replace iconify
4323 * -window shade?
4324 * -hide application?
4325 */
4326}
4327
4328#if defined(FEAT_EVAL) || defined(PROTO)
4329/*
4330 * Bring the Vim window to the foreground.
4331 */
4332 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004333gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334{
4335 /* TODO */
4336}
4337#endif
4338
4339/*
4340 * Draw a cursor without focus.
4341 */
4342 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004343gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344{
4345 Rect rc;
4346
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347 /*
4348 * Note: FrameRect() excludes right and bottom of rectangle.
4349 */
4350 rc.left = FILL_X(gui.col);
4351 rc.top = FILL_Y(gui.row);
4352 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004353#ifdef FEAT_MBYTE
4354 if (mb_lefthalve(gui.row, gui.col))
4355 rc.right += gui.char_width;
4356#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 rc.bottom = rc.top + gui.char_height;
4358
4359 gui_mch_set_fg_color(color);
4360
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004361 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362}
4363
4364/*
4365 * Draw part of a cursor, only w pixels wide, and h pixels high.
4366 */
4367 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004368gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369{
4370 Rect rc;
4371
4372#ifdef FEAT_RIGHTLEFT
4373 /* vertical line should be on the right of current point */
4374 if (CURSOR_BAR_RIGHT)
4375 rc.left = FILL_X(gui.col + 1) - w;
4376 else
4377#endif
4378 rc.left = FILL_X(gui.col);
4379 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4380 rc.right = rc.left + w;
4381 rc.bottom = rc.top + h;
4382
4383 gui_mch_set_fg_color(color);
4384
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004385 FrameRect(&rc);
4386// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387}
4388
4389
4390
4391/*
4392 * Catch up with any queued X events. This may put keyboard input into the
4393 * input buffer, call resize call-backs, trigger timers etc. If there is
4394 * nothing in the X event queue (& no timers pending), then we return
4395 * immediately.
4396 */
4397 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004398gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399{
4400 /* TODO: find what to do
4401 * maybe call gui_mch_wait_for_chars (0)
4402 * more like look at EventQueue then
4403 * call heart of gui_mch_wait_for_chars;
4404 *
4405 * if (eventther)
4406 * gui_mac_handle_event(&event);
4407 */
4408 EventRecord theEvent;
4409
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004410 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411 if (theEvent.what != nullEvent)
4412 gui_mch_wait_for_chars(0);
4413}
4414
4415/*
4416 * Simple wrapper to neglect more easily the time
4417 * spent inside WaitNextEvent while profiling.
4418 */
4419
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420 pascal
4421 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004422WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423{
4424 if (((long) sleep) < -1)
4425 sleep = 32767;
4426 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4427}
4428
4429/*
4430 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4431 * from the keyboard.
4432 * wtime == -1 Wait forever.
4433 * wtime == 0 This should never happen.
4434 * wtime > 0 Wait wtime milliseconds for a character.
4435 * Returns OK if a character was found to be available within the given time,
4436 * or FAIL otherwise.
4437 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004439gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440{
4441 EventMask mask = (everyEvent);
4442 EventRecord event;
4443 long entryTick;
4444 long currentTick;
4445 long sleeppyTick;
4446
4447 /* If we are providing life feedback with the scrollbar,
4448 * we don't want to try to wait for an event, or else
4449 * there won't be any life feedback.
4450 */
4451 if (dragged_sb != NULL)
4452 return FAIL;
4453 /* TODO: Check if FAIL is the proper return code */
4454
4455 entryTick = TickCount();
4456
4457 allow_scrollbar = TRUE;
4458
4459 do
4460 {
4461/* if (dragRectControl == kCreateEmpty)
4462 {
4463 dragRgn = NULL;
4464 dragRectControl = kNothing;
4465 }
4466 else*/ if (dragRectControl == kCreateRect)
4467 {
4468 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004469 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 dragRectControl = kNothing;
4471 }
4472 /*
4473 * Don't use gui_mch_update() because then we will spin-lock until a
4474 * char arrives, instead we use WaitNextEventWrp() to hang until an
4475 * event arrives. No need to check for input_buf_full because we are
4476 * returning as soon as it contains a single char.
4477 */
4478 /* TODO: reduce wtime accordinly??? */
4479 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004480 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 else
4482 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004483
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004484 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004486 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 if (input_available())
4488 {
4489 allow_scrollbar = FALSE;
4490 return OK;
4491 }
4492 }
4493 currentTick = TickCount();
4494 }
4495 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4496
4497 allow_scrollbar = FALSE;
4498 return FAIL;
4499}
4500
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501/*
4502 * Output routines.
4503 */
4504
4505/* Flush any output to the screen */
4506 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004507gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508{
4509 /* TODO: Is anything needed here? */
4510}
4511
4512/*
4513 * Clear a rectangular region of the screen from text pos (row1, col1) to
4514 * (row2, col2) inclusive.
4515 */
4516 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004517gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518{
4519 Rect rc;
4520
4521 /*
4522 * Clear one extra pixel at the far right, for when bold characters have
4523 * spilled over to the next column.
4524 */
4525 rc.left = FILL_X(col1);
4526 rc.top = FILL_Y(row1);
4527 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4528 rc.bottom = FILL_Y(row2 + 1);
4529
4530 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004531 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532}
4533
4534/*
4535 * Clear the whole text window.
4536 */
4537 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004538gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539{
4540 Rect rc;
4541
4542 rc.left = 0;
4543 rc.top = 0;
4544 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4545 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4546
4547 gui_mch_set_bg_color(gui.back_pixel);
4548 EraseRect(&rc);
4549/* gui_mch_set_fg_color(gui.norm_pixel);
4550 FrameRect(&rc);
4551*/
4552}
4553
4554/*
4555 * Delete the given number of lines from the given row, scrolling up any
4556 * text further down within the scroll region.
4557 */
4558 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004559gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560{
4561 Rect rc;
4562
4563 /* changed without checking! */
4564 rc.left = FILL_X(gui.scroll_region_left);
4565 rc.right = FILL_X(gui.scroll_region_right + 1);
4566 rc.top = FILL_Y(row);
4567 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4568
4569 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004570 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571
4572 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4573 gui.scroll_region_left,
4574 gui.scroll_region_bot, gui.scroll_region_right);
4575}
4576
4577/*
4578 * Insert the given number of lines before the given row, scrolling down any
4579 * following text within the scroll region.
4580 */
4581 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004582gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583{
4584 Rect rc;
4585
4586 rc.left = FILL_X(gui.scroll_region_left);
4587 rc.right = FILL_X(gui.scroll_region_right + 1);
4588 rc.top = FILL_Y(row);
4589 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4590
4591 gui_mch_set_bg_color(gui.back_pixel);
4592
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004593 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
4595 /* Update gui.cursor_row if the cursor scrolled or copied over */
4596 if (gui.cursor_row >= gui.row
4597 && gui.cursor_col >= gui.scroll_region_left
4598 && gui.cursor_col <= gui.scroll_region_right)
4599 {
4600 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4601 gui.cursor_row += num_lines;
4602 else if (gui.cursor_row <= gui.scroll_region_bot)
4603 gui.cursor_is_valid = FALSE;
4604 }
4605
4606 gui_clear_block(row, gui.scroll_region_left,
4607 row + num_lines - 1, gui.scroll_region_right);
4608}
4609
4610 /*
4611 * TODO: add a vim format to the clipboard which remember
4612 * LINEWISE, CHARWISE, BLOCKWISE
4613 */
4614
4615 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004616clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617{
4618
4619 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004620 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621 Size scrapSize;
4622 ScrapFlavorFlags scrapFlags;
4623 ScrapRef scrap = nil;
4624 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625 int type;
4626 char *searchCR;
4627 char_u *tempclip;
4628
4629
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004630 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 if (error != noErr)
4632 return;
4633
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004634 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4635 if (error == noErr)
4636 {
4637 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4638 if (error == noErr && scrapSize > 1)
4639 flavor = 1;
4640 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004642 if (flavor == 0)
4643 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004644 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004645 if (error != noErr)
4646 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004648 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004649 if (error != noErr)
4650 return;
4651 }
4652
4653 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004655 /* In CARBON we don't need a Handle, a pointer is good */
4656 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004658 /* tempclip = lalloc(scrapSize+1, TRUE); */
4659 HLock(textOfClip);
4660 error = GetScrapFlavorData(scrap,
4661 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4662 &scrapSize, *textOfClip);
4663 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004665 if (flavor)
4666 type = **textOfClip;
4667 else
4668 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4669
4670 tempclip = lalloc(scrapSize + 1, TRUE);
4671 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4672 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004674#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004675 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004676 /* Convert from utf-16 (clipboard) */
4677 size_t encLen = 0;
4678 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004679
4680 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004682 scrapSize = encLen;
4683 vim_free(tempclip);
4684 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004686 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004688
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004689 searchCR = (char *)tempclip;
4690 while (searchCR != NULL)
4691 {
4692 searchCR = strchr(searchCR, '\r');
4693 if (searchCR != NULL)
4694 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004696
4697 clip_yank_selection(type, tempclip, scrapSize, cbd);
4698
4699 vim_free(tempclip);
4700 HUnlock(textOfClip);
4701
4702 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703}
4704
4705 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004706clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004707{
4708 /*
4709 * TODO: Really nothing to do?
4710 */
4711}
4712
4713 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004714clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715{
4716 return OK;
4717}
4718
4719/*
4720 * Send the current selection to the clipboard.
4721 */
4722 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004723clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724{
4725 Handle textOfClip;
4726 long scrapSize;
4727 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729
4730 char_u *str = NULL;
4731
4732 if (!cbd->owned)
4733 return;
4734
4735 clip_get_selection(cbd);
4736
4737 /*
4738 * Once we set the clipboard, lose ownership. If another application sets
4739 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741 cbd->owned = FALSE;
4742
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004743 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004745#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004746 size_t utf16_len = 0;
4747 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4748 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004750 scrapSize = utf16_len;
4751 vim_free(str);
4752 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753 }
4754#endif
4755
4756 if (type >= 0)
4757 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004760 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761 HLock(textOfClip);
4762
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004763 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004764 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004765 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004766 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004767 scrapSize, *textOfClip + 1);
4768 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4769 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 HUnlock(textOfClip);
4771 DisposeHandle(textOfClip);
4772 }
4773
4774 vim_free(str);
4775}
4776
4777 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004778gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779{
4780 Rect VimBound;
4781
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004782/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784
4785 if (gui.which_scrollbars[SBAR_LEFT])
4786 {
4787 VimBound.left = -gui.scrollbar_width + 1;
4788 }
4789 else
4790 {
4791 VimBound.left = 0;
4792 }
4793
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004796 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797}
4798
4799/*
4800 * Menu stuff.
4801 */
4802
4803 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004804gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805{
4806 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004807 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 */
4809}
4810
4811 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004812gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813{
4814 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004815 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816 */
4817}
4818
4819/*
4820 * Add a sub menu to the menu bar.
4821 */
4822 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004823gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824{
4825 /*
4826 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4827 * TODO: use menu->mnemonic and menu->actext
4828 * TODO: Try to reuse menu id
4829 * Carbon Help suggest to use only id between 1 and 235
4830 */
4831 static long next_avail_id = 128;
4832 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004833#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004834 CFStringRef name;
4835#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004837#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 short index;
4839 vimmenu_T *parent = menu->parent;
4840 vimmenu_T *brother = menu->next;
4841
4842 /* Cannot add a menu if ... */
4843 if ((parent != NULL && parent->submenu_id == 0))
4844 return;
4845
4846 /* menu ID greater than 1024 are reserved for ??? */
4847 if (next_avail_id == 1024)
4848 return;
4849
4850 /* My brother could be the PopUp, find my real brother */
4851 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4852 brother = brother->next;
4853
4854 /* Find where to insert the menu (for MenuBar) */
4855 if ((parent == NULL) && (brother != NULL))
4856 menu_after_me = brother->submenu_id;
4857
4858 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4859 if (!menu_is_menubar(menu->name))
4860 menu_after_me = hierMenu;
4861
4862 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004863#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004864 name = menu_title_removing_mnemonic(menu);
4865#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004867#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 if (name == NULL)
4869 return;
4870
4871 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 {
4873 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004874 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4875 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 */
4877 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004878#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004879 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4880 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4881#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004882 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004883#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004884 next_avail_id++;
4885 }
4886
4887 if (parent == NULL)
4888 {
4889 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4890
4891 /* TODO: Verify if we could only Insert Menu if really part of the
4892 * menubar The Inserted menu are scanned or the Command-key combos
4893 */
4894
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004895 /* Insert the menu */
4896 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897#if 1
4898 /* Vim should normally update it. TODO: verify */
4899 DrawMenuBar();
4900#endif
4901 }
4902 else
4903 {
4904 /* Adding as a submenu */
4905
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004906 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907
4908 /* Call InsertMenuItem followed by SetMenuItemText
4909 * to avoid special character recognition by InsertMenuItem
4910 */
4911 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004912#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004913 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4914#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004916#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004917 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4918 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4919 InsertMenu(menu->submenu_handle, hierMenu);
4920 }
4921
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004922#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004923 CFRelease(name);
4924#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004925 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004926#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927
4928#if 0
4929 /* Done by Vim later on */
4930 DrawMenuBar();
4931#endif
4932}
4933
4934/*
4935 * Add a menu item to a menu
4936 */
4937 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004938gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004940#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004941 CFStringRef name;
4942#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004944#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945 vimmenu_T *parent = menu->parent;
4946 int menu_inserted;
4947
4948 /* Cannot add item, if the menu have not been created */
4949 if (parent->submenu_id == 0)
4950 return;
4951
4952 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4953 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4954
4955 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004956#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004957 name = menu_title_removing_mnemonic(menu);
4958#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004959 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004960#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004961
4962 /* Where are just a menu item, so no handle, no id */
4963 menu->submenu_id = 0;
4964 menu->submenu_handle = NULL;
4965
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 menu_inserted = 0;
4967 if (menu->actext)
4968 {
4969 /* If the accelerator text for the menu item looks like it describes
4970 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4971 * item's command equivalent.
4972 */
4973 int key = 0;
4974 int modifiers = 0;
4975 char_u *p_actext;
4976
4977 p_actext = menu->actext;
Bram Moolenaardc5e2182008-12-24 12:06:26 +00004978 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979 if (*p_actext != 0)
4980 key = 0; /* error: trailing text */
4981 /* find_special_key() returns a keycode with as many of the
4982 * specified modifiers as appropriate already applied (e.g., for
4983 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4984 * as the only modifier). Since we want to display all of the
4985 * modifiers, we need to convert the keycode back to a printable
4986 * character plus modifiers.
4987 * TODO: Write an alternative find_special_key() that doesn't
4988 * apply modifiers.
4989 */
4990 if (key > 0 && key < 32)
4991 {
4992 /* Convert a control key to an uppercase letter. Note that
4993 * by this point it is no longer possible to distinguish
4994 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4995 */
4996 modifiers |= MOD_MASK_CTRL;
4997 key += '@';
4998 }
4999 /* If the keycode is an uppercase letter, set the Shift modifier.
5000 * If it is a lowercase letter, don't set the modifier, but convert
5001 * the letter to uppercase for display in the menu.
5002 */
5003 else if (key >= 'A' && key <= 'Z')
5004 modifiers |= MOD_MASK_SHIFT;
5005 else if (key >= 'a' && key <= 'z')
5006 key += 'A' - 'a';
5007 /* Note: keycodes below 0x22 are reserved by Apple. */
5008 if (key >= 0x22 && vim_isprintc_strict(key))
5009 {
5010 int valid = 1;
5011 char_u mac_mods = kMenuNoModifiers;
5012 /* Convert Vim modifier codes to Menu Manager equivalents. */
5013 if (modifiers & MOD_MASK_SHIFT)
5014 mac_mods |= kMenuShiftModifier;
5015 if (modifiers & MOD_MASK_CTRL)
5016 mac_mods |= kMenuControlModifier;
5017 if (!(modifiers & MOD_MASK_CMD))
5018 mac_mods |= kMenuNoCommandModifier;
5019 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5020 valid = 0; /* TODO: will Alt someday map to Option? */
5021 if (valid)
5022 {
5023 char_u item_txt[10];
5024 /* Insert the menu item after idx, with its command key. */
5025 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5026 item_txt[3] = key;
5027 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5028 /* Set the modifier keys. */
5029 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5030 menu_inserted = 1;
5031 }
5032 }
5033 }
5034 /* Call InsertMenuItem followed by SetMenuItemText
5035 * to avoid special character recognition by InsertMenuItem
5036 */
5037 if (!menu_inserted)
5038 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5039 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005040#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005041 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5042#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005044#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005045
5046#if 0
5047 /* Called by Vim */
5048 DrawMenuBar();
5049#endif
5050
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005051#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005052 CFRelease(name);
5053#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 /* TODO: Can name be freed? */
5055 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005056#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057}
5058
5059 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005060gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005061{
5062 /* no tearoff menus */
5063}
5064
5065/*
5066 * Destroy the machine specific menu widget.
5067 */
5068 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005069gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005070{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005071 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005072
5073 if (index > 0)
5074 {
5075 if (menu->parent)
5076 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005077 {
5078 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005079 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080
5081 /* Delete the Menu if it was a hierarchical Menu */
5082 if (menu->submenu_id != 0)
5083 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005084 DeleteMenu(menu->submenu_id);
5085 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 }
5087 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088 }
5089#ifdef DEBUG_MAC_MENU
5090 else
5091 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005092 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 }
5094#endif
5095 }
5096 else
5097 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005099 DeleteMenu(menu->submenu_id);
5100 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 }
5102 }
5103 /* Shouldn't this be already done by Vim. TODO: Check */
5104 DrawMenuBar();
5105}
5106
5107/*
5108 * Make a menu either grey or not grey.
5109 */
5110 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005111gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112{
5113 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005114 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115/*
5116 index = menu->index;
5117*/
5118 if (grey)
5119 {
5120 if (menu->children)
5121 DisableMenuItem(menu->submenu_handle, index);
5122 if (menu->parent)
5123 if (menu->parent->submenu_handle)
5124 DisableMenuItem(menu->parent->submenu_handle, index);
5125 }
5126 else
5127 {
5128 if (menu->children)
5129 EnableMenuItem(menu->submenu_handle, index);
5130 if (menu->parent)
5131 if (menu->parent->submenu_handle)
5132 EnableMenuItem(menu->parent->submenu_handle, index);
5133 }
5134}
5135
5136/*
5137 * Make menu item hidden or not hidden
5138 */
5139 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005140gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141{
5142 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005143 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005144}
5145
5146
5147/*
5148 * This is called after setting all the menus to grey/hidden or not.
5149 */
5150 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005151gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005152{
5153 DrawMenuBar();
5154}
5155
5156
5157/*
5158 * Scrollbar stuff.
5159 */
5160
5161 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005162gui_mch_enable_scrollbar(
5163 scrollbar_T *sb,
5164 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005165{
5166 if (flag)
5167 ShowControl(sb->id);
5168 else
5169 HideControl(sb->id);
5170
5171#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005172 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173#endif
5174}
5175
5176 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005177gui_mch_set_scrollbar_thumb(
5178 scrollbar_T *sb,
5179 long val,
5180 long size,
5181 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182{
5183 SetControl32BitMaximum (sb->id, max);
5184 SetControl32BitMinimum (sb->id, 0);
5185 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005186 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005187#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005188 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189#endif
5190}
5191
5192 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005193gui_mch_set_scrollbar_pos(
5194 scrollbar_T *sb,
5195 int x,
5196 int y,
5197 int w,
5198 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199{
5200 gui_mch_set_bg_color(gui.back_pixel);
5201/* if (gui.which_scrollbars[SBAR_LEFT])
5202 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005203 MoveControl(sb->id, x-16, y);
5204 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 }
5206 else
5207 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005208 MoveControl(sb->id, x, y);
5209 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005210 }*/
5211 if (sb == &gui.bottom_sbar)
5212 h += 1;
5213 else
5214 w += 1;
5215
5216 if (gui.which_scrollbars[SBAR_LEFT])
5217 x -= 15;
5218
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005219 MoveControl(sb->id, x, y);
5220 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005222 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223#endif
5224}
5225
5226 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005227gui_mch_create_scrollbar(
5228 scrollbar_T *sb,
5229 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230{
5231 Rect bounds;
5232
5233 bounds.top = -16;
5234 bounds.bottom = -10;
5235 bounds.right = -10;
5236 bounds.left = -16;
5237
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005238 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 &bounds,
5240 "\pScrollBar",
5241 TRUE,
5242 0, /* current*/
5243 0, /* top */
5244 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246 (long) sb->ident);
5247#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005248 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249#endif
5250}
5251
5252 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005253gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254{
5255 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005256 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005257#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005258 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005259#endif
5260}
5261
5262
5263/*
5264 * Cursor blink functions.
5265 *
5266 * This is a simple state machine:
5267 * BLINK_NONE not blinking at all
5268 * BLINK_OFF blinking, cursor is not shown
5269 * BLINK_ON blinking, cursor is shown
5270 */
5271 void
5272gui_mch_set_blinking(long wait, long on, long off)
5273{
5274 /* TODO: TODO: TODO: TODO: */
5275/* blink_waittime = wait;
5276 blink_ontime = on;
5277 blink_offtime = off;*/
5278}
5279
5280/*
5281 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5282 */
5283 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005284gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285{
5286 gui_update_cursor(TRUE, FALSE);
5287 /* TODO: TODO: TODO: TODO: */
5288/* gui_w32_rm_blink_timer();
5289 if (blink_state == BLINK_OFF)
5290 gui_update_cursor(TRUE, FALSE);
5291 blink_state = BLINK_NONE;*/
5292}
5293
5294/*
5295 * Start the cursor blinking. If it was already blinking, this restarts the
5296 * waiting time and shows the cursor.
5297 */
5298 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005299gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300{
5301 gui_update_cursor(TRUE, FALSE);
5302 /* TODO: TODO: TODO: TODO: */
5303/* gui_w32_rm_blink_timer(); */
5304
5305 /* Only switch blinking on if none of the times is zero */
5306/* if (blink_waittime && blink_ontime && blink_offtime)
5307 {
5308 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5309 (TIMERPROC)_OnBlinkTimer);
5310 blink_state = BLINK_ON;
5311 gui_update_cursor(TRUE, FALSE);
5312 }*/
5313}
5314
5315/*
5316 * Return the RGB value of a pixel as long.
5317 */
5318 long_u
5319gui_mch_get_rgb(guicolor_T pixel)
5320{
5321 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5322}
5323
5324
5325
5326#ifdef FEAT_BROWSE
5327/*
5328 * Pop open a file browser and return the file selected, in allocated memory,
5329 * or NULL if Cancel is hit.
5330 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5331 * title - Title message for the file browser dialog.
5332 * dflt - Default name of file.
5333 * ext - Default extension to be added to files without extensions.
5334 * initdir - directory in which to open the browser (NULL = current dir)
5335 * filter - Filter for matched files to choose from.
5336 * Has a format like this:
5337 * "C Files (*.c)\0*.c\0"
5338 * "All Files\0*.*\0\0"
5339 * If these two strings were concatenated, then a choice of two file
5340 * filters will be selectable to the user. Then only matching files will
5341 * be shown in the browser. If NULL, the default allows all files.
5342 *
5343 * *NOTE* - the filter string must be terminated with TWO nulls.
5344 */
5345 char_u *
5346gui_mch_browse(
5347 int saving,
5348 char_u *title,
5349 char_u *dflt,
5350 char_u *ext,
5351 char_u *initdir,
5352 char_u *filter)
5353{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005354 /* TODO: Add Ammon's safety checl (Dany) */
5355 NavReplyRecord reply;
5356 char_u *fname = NULL;
5357 char_u **fnames = NULL;
5358 long numFiles;
5359 NavDialogOptions navOptions;
5360 OSErr error;
5361
5362 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005363 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005364
5365
5366 /* TODO: If we get a :browse args, set the Multiple bit. */
5367 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5368 | kNavDontAutoTranslate
5369 | kNavDontAddTranslateItems
5370 /* | kNavAllowMultipleFiles */
5371 | kNavAllowStationery;
5372
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005373 (void) C2PascalString(title, &navOptions.message);
5374 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375 /* Could set clientName?
5376 * windowTitle? (there's no title bar?)
5377 */
5378
5379 if (saving)
5380 {
5381 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005382 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005383 if (!reply.validRecord)
5384 return NULL;
5385 }
5386 else
5387 {
5388 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5389 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5390 if (!reply.validRecord)
5391 return NULL;
5392 }
5393
5394 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5395
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005396 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397
5398 if (fnames)
5399 {
5400 fname = fnames[0];
5401 vim_free(fnames);
5402 }
5403
5404 /* TODO: Shorten the file name if possible */
5405 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005406}
5407#endif /* FEAT_BROWSE */
5408
5409#ifdef FEAT_GUI_DIALOG
5410/*
5411 * Stuff for dialogues
5412 */
5413
5414/*
5415 * Create a dialogue dynamically from the parameter strings.
5416 * type = type of dialogue (question, alert, etc.)
5417 * title = dialogue title. may be NULL for default title.
5418 * message = text to display. Dialogue sizes to accommodate it.
5419 * buttons = '\n' separated list of button captions, default first.
5420 * dfltbutton = number of default button.
5421 *
5422 * This routine returns 1 if the first button is pressed,
5423 * 2 for the second, etc.
5424 *
5425 * 0 indicates Esc was pressed.
5426 * -1 for unexpected error
5427 *
5428 * If stubbing out this fn, return 1.
5429 */
5430
5431typedef struct
5432{
5433 short idx;
5434 short width; /* Size of the text in pixel */
5435 Rect box;
5436} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5437
5438#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5439
5440 static void
5441macMoveDialogItem(
5442 DialogRef theDialog,
5443 short itemNumber,
5444 short X,
5445 short Y,
5446 Rect *inBox)
5447{
5448#if 0 /* USE_CARBONIZED */
5449 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005450 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005452 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005453#else
5454 short itemType;
5455 Handle itemHandle;
5456 Rect localBox;
5457 Rect *itemBox = &localBox;
5458
5459 if (inBox != nil)
5460 itemBox = inBox;
5461
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005462 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5463 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5464 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 /* To move a control (like a button) we need to call both
5466 * MoveControl and SetDialogItem. FAQ 6-18 */
5467 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005468 MoveControl((ControlRef) itemHandle, X, Y);
5469 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470#endif
5471}
5472
5473 static void
5474macSizeDialogItem(
5475 DialogRef theDialog,
5476 short itemNumber,
5477 short width,
5478 short height)
5479{
5480 short itemType;
5481 Handle itemHandle;
5482 Rect itemBox;
5483
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005484 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005485
5486 /* When width or height is zero do not change it */
5487 if (width == 0)
5488 width = itemBox.right - itemBox.left;
5489 if (height == 0)
5490 height = itemBox.bottom - itemBox.top;
5491
5492#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005493 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005494#else
5495 /* Resize the bounding box */
5496 itemBox.right = itemBox.left + width;
5497 itemBox.bottom = itemBox.top + height;
5498
5499 /* To resize a control (like a button) we need to call both
5500 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5501 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005502 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503
5504 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005505 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005506#endif
5507}
5508
5509 static void
5510macSetDialogItemText(
5511 DialogRef theDialog,
5512 short itemNumber,
5513 Str255 itemName)
5514{
5515 short itemType;
5516 Handle itemHandle;
5517 Rect itemBox;
5518
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005519 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520
5521 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005522 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005524 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005525}
5526
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005527
5528/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5529 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5530 * setting gDialogHotKeys to NULL disables any hotkey handling.
5531 */
5532 static pascal Boolean
5533DialogHotkeyFilterProc (
5534 DialogRef theDialog,
5535 EventRecord *event,
5536 DialogItemIndex *itemHit)
5537{
5538 char_u keyHit;
5539
5540 if (event->what == keyDown || event->what == autoKey)
5541 {
5542 keyHit = (event->message & charCodeMask);
5543
5544 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5545 {
5546#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5547 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5548#endif
5549 *itemHit = gDialogHotKeys[keyHit];
5550
5551 /* When handing off to StdFilterProc, pretend that the user
5552 * clicked the control manually. Note that this is also supposed
5553 * to cause the button to hilite briefly (to give some user
5554 * feedback), but this seems not to actually work (or it's too
5555 * fast to be seen).
5556 */
5557 event->what = kEventControlSimulateHit;
5558
5559 return true; /* we took care of it */
5560 }
5561
5562 /* Defer to the OS's standard behavior for this event.
5563 * This ensures that Enter will still activate the default button. */
5564 return StdFilterProc(theDialog, event, itemHit);
5565 }
5566 return false; /* Let ModalDialog deal with it */
5567}
5568
5569
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005570/* TODO: There have been some crashes with dialogs, check your inbox
5571 * (Jussi)
5572 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573 int
5574gui_mch_dialog(
5575 int type,
5576 char_u *title,
5577 char_u *message,
5578 char_u *buttons,
5579 int dfltbutton,
5580 char_u *textfield)
5581{
5582 Handle buttonDITL;
5583 Handle iconDITL;
5584 Handle inputDITL;
5585 Handle messageDITL;
5586 Handle itemHandle;
5587 Handle iconHandle;
5588 DialogPtr theDialog;
5589 char_u len;
5590 char_u PascalTitle[256]; /* place holder for the title */
5591 char_u name[256];
5592 GrafPtr oldPort;
5593 short itemHit;
5594 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005595 short hotKeys[256]; /* map of hotkey -> control ID */
5596 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005597 Rect box;
5598 short button;
5599 short lastButton;
5600 short itemType;
5601 short useIcon;
5602 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005603 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005604 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605 short widestButton = 0;
5606 short dfltButtonEdge = 20; /* gut feeling */
5607 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5608 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5609 short maximumWidth = 400; /* gut feeling */
5610 short maxButtonWidth = 175; /* gut feeling */
5611
5612 short vertical;
5613 short dialogHeight;
5614 short messageLines = 3;
5615 FontInfo textFontInfo;
5616
5617 vgmDlgItm iconItm;
5618 vgmDlgItm messageItm;
5619 vgmDlgItm inputItm;
5620 vgmDlgItm buttonItm;
5621
5622 WindowRef theWindow;
5623
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005624 ModalFilterUPP dialogUPP;
5625
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626 /* Check 'v' flag in 'guioptions': vertical button placement. */
5627 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5628
5629 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005630 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005631
5632 /* Get the WindowRef */
5633 theWindow = GetDialogWindow(theDialog);
5634
5635 /* Hide the window.
5636 * 1. to avoid seeing slow drawing
5637 * 2. to prevent a problem seen while moving dialog item
5638 * within a visible window. (non-Carbon MacOS 9)
5639 * Could be avoided by changing the resource.
5640 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005641 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005642
5643 /* Change the graphical port to the dialog,
5644 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005645 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005646 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647
5648 /* Get the info about the default text,
5649 * used to calculate the height of the message
5650 * and of the text field */
5651 GetFontInfo(&textFontInfo);
5652
5653 /* Set the dialog title */
5654 if (title != NULL)
5655 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005656 (void) C2PascalString(title, &PascalTitle);
5657 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658 }
5659
5660 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005661 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005662 buttonChar = buttons;
5663 button = 0;
5664
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005665 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005666 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005667
Bram Moolenaar071d4272004-06-13 20:20:40 +00005668 for (;*buttonChar != 0;)
5669 {
5670 /* Get the name of the button */
5671 button++;
5672 len = 0;
5673 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5674 {
5675 if (*buttonChar != DLG_HOTKEY_CHAR)
5676 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005677 else
5678 {
5679 aHotKey = (char_u)*(buttonChar+1);
5680 if (aHotKey >= 'A' && aHotKey <= 'Z')
5681 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5682 hotKeys[aHotKey] = button;
5683#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5684 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5685#endif
5686 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005687 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005688
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689 if (*buttonChar != 0)
5690 buttonChar++;
5691 name[0] = len;
5692
5693 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005694 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695
5696 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005697 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005698
5699 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005700 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701 /* Limite the size of any button to an acceptable value. */
5702 /* TODO: Should be based on the message width */
5703 if (width > maxButtonWidth)
5704 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005705 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706
5707 totalButtonWidth += width;
5708
5709 if (width > widestButton)
5710 widestButton = width;
5711 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005712 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005713 lastButton = button;
5714
5715 /* Add the icon to the Dialog Box. */
5716 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005717 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005718 switch (type)
5719 {
5720 case VIM_GENERIC: useIcon = kNoteIcon;
5721 case VIM_ERROR: useIcon = kStopIcon;
5722 case VIM_WARNING: useIcon = kCautionIcon;
5723 case VIM_INFO: useIcon = kNoteIcon;
5724 case VIM_QUESTION: useIcon = kNoteIcon;
5725 default: useIcon = kStopIcon;
5726 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005727 AppendDITL(theDialog, iconDITL, overlayDITL);
5728 ReleaseResource(iconDITL);
5729 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005730 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005731 iconHandle = GetIcon(useIcon);
5732 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733
5734 /* Add the message to the Dialog box. */
5735 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005736 messageDITL = GetResource('DITL', 132);
5737 AppendDITL(theDialog, messageDITL, overlayDITL);
5738 ReleaseResource(messageDITL);
5739 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5740 (void) C2PascalString(message, &name);
5741 SetDialogItemText(itemHandle, name);
5742 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005743
5744 /* Add the input box if needed */
5745 if (textfield != NULL)
5746 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005747 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005748 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005749 inputDITL = GetResource('DITL', 132);
5750 AppendDITL(theDialog, inputDITL, overlayDITL);
5751 ReleaseResource(inputDITL);
5752 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5753/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5754 (void) C2PascalString(textfield, &name);
5755 SetDialogItemText(itemHandle, name);
5756 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005757
5758 /* Hotkeys don't make sense if there's a text field */
5759 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005761 else
5762 /* Install hotkey table */
5763 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005764
5765 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005766 SetDialogDefaultItem(theDialog, dfltbutton);
5767 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768
5769 /* Reposition element */
5770
5771 /* Check if we need to force vertical */
5772 if (totalButtonWidth > maximumWidth)
5773 vertical = TRUE;
5774
5775 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005776 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005777 iconItm.box.right = box.right;
5778 iconItm.box.bottom = box.bottom;
5779
5780 /* Place Message */
5781 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005782 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5783 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005784
5785 /* Place Input */
5786 if (textfield != NULL)
5787 {
5788 inputItm.box.left = messageItm.box.left;
5789 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005790 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5791 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792 /* Convert the static text into a text edit.
5793 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005794 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5795 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005796 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5797 }
5798
5799 /* Place Button */
5800 if (textfield != NULL)
5801 {
5802 buttonItm.box.left = inputItm.box.left;
5803 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5804 }
5805 else
5806 {
5807 buttonItm.box.left = messageItm.box.left;
5808 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5809 }
5810
5811 for (button=1; button <= lastButton; button++)
5812 {
5813
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005814 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005815 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816 if (vertical)
5817 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005818 macSizeDialogItem(theDialog, button, widestButton, 0);
5819 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005820 }
5821 /* Calculate position of next button */
5822 if (vertical)
5823 buttonItm.box.top = box.bottom + dfltElementSpacing;
5824 else
5825 buttonItm.box.left = box.right + dfltElementSpacing;
5826 }
5827
5828 /* Resize the dialog box */
5829 dialogHeight = box.bottom + dfltElementSpacing;
5830 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5831
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005833 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005834 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835
5836 /* Display it */
5837 ShowWindow(theWindow);
5838/* BringToFront(theWindow); */
5839 SelectWindow(theWindow);
5840
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005841/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005843 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005844 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845#endif
5846
Bram Moolenaard68071d2006-05-02 22:08:30 +00005847#ifdef USE_CARBONKEYHANDLER
5848 /* Avoid that we use key events for the main window. */
5849 dialog_busy = TRUE;
5850#endif
5851
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005852 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5853 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5854
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855 /* Hang until one of the button is hit */
5856 do
5857 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005858 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005859 } while ((itemHit < 1) || (itemHit > lastButton));
5860
Bram Moolenaard68071d2006-05-02 22:08:30 +00005861#ifdef USE_CARBONKEYHANDLER
5862 dialog_busy = FALSE;
5863#endif
5864
Bram Moolenaar071d4272004-06-13 20:20:40 +00005865 /* Copy back the text entered by the user into the param */
5866 if (textfield != NULL)
5867 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005868 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5869 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870#if IOSIZE < 256
5871 /* Truncate the name to IOSIZE if needed */
5872 if (name[0] > IOSIZE)
5873 name[0] = IOSIZE - 1;
5874#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005875 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005876 }
5877
5878 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005879 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005881 /* Free the modal filterProc */
5882 DisposeRoutineDescriptor(dialogUPP);
5883
Bram Moolenaar071d4272004-06-13 20:20:40 +00005884 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005885 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886
5887 return itemHit;
5888/*
5889 * Usefull thing which could be used
5890 * SetDialogTimeout(): Auto click a button after timeout
5891 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5892 * MoveDialogItem(): Probably better than SetDialogItem
5893 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005894 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895 */
5896}
5897#endif /* FEAT_DIALOG_GUI */
5898
5899/*
5900 * Display the saved error message(s).
5901 */
5902#ifdef USE_MCH_ERRMSG
5903 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005904display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005905{
5906 char *p;
5907 char_u pError[256];
5908
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005909 if (error_ga.ga_data == NULL)
5910 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005912 /* avoid putting up a message box with blanks only */
5913 for (p = (char *)error_ga.ga_data; *p; ++p)
5914 if (!isspace(*p))
5915 {
5916 if (STRLEN(p) > 255)
5917 pError[0] = 255;
5918 else
5919 pError[0] = STRLEN(p);
5920
5921 STRNCPY(&pError[1], p, pError[0]);
5922 ParamText(pError, nil, nil, nil);
5923 Alert(128, nil);
5924 break;
5925 /* TODO: handled message longer than 256 chars
5926 * use auto-sizeable alert
5927 * or dialog with scrollbars (TextEdit zone)
5928 */
5929 }
5930 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005931}
5932#endif
5933
5934/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005935 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005937 void
5938gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005939{
5940 Point where;
5941
5942 GetMouse(&where);
5943
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005944 *x = where.h;
5945 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946}
5947
5948 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005949gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950{
5951 /* TODO */
5952#if 0
5953 /* From FAQ 3-11 */
5954
5955 CursorDevicePtr myMouse;
5956 Point where;
5957
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005958 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5959 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005960 {
5961 /* New way */
5962
5963 /*
5964 * Get first devoice with one button.
5965 * This will probably be the standad mouse
5966 * startat head of cursor dev list
5967 *
5968 */
5969
5970 myMouse = nil;
5971
5972 do
5973 {
5974 /* Get the next cursor device */
5975 CursorDeviceNextDevice(&myMouse);
5976 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005977 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005979 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980 }
5981 else
5982 {
5983 /* Old way */
5984 where.h = x;
5985 where.v = y;
5986
5987 *(Point *)RawMouse = where;
5988 *(Point *)MTemp = where;
5989 *(Ptr) CrsrNew = 0xFFFF;
5990 }
5991#endif
5992}
5993
5994 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005995gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005996{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997/*
5998 * Clone PopUp to use menu
5999 * Create a object descriptor for the current selection
6000 * Call the procedure
6001 */
6002
6003 MenuHandle CntxMenu;
6004 Point where;
6005 OSStatus status;
6006 UInt32 CntxType;
6007 SInt16 CntxMenuID;
6008 UInt16 CntxMenuItem;
6009 Str255 HelpName = "";
6010 GrafPtr savePort;
6011
6012 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006013 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006015 GetMouse(&where);
6016 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017 CntxMenu = menu->submenu_handle;
6018
6019 /* TODO: Get the text selection from Vim */
6020
6021 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006022 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006023 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024
6025 if (status == noErr)
6026 {
6027 if (CntxType == kCMMenuItemSelected)
6028 {
6029 /* Handle the menu CntxMenuID, CntxMenuItem */
6030 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006031 /* But what about the current menu, is the menu changed by
6032 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006033 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006034 }
6035 else if (CntxMenuID == kCMShowHelpSelected)
6036 {
6037 /* Should come up with the help */
6038 }
6039 }
6040
6041 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006042 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006043}
6044
6045#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6046/* TODO: Is it need for MACOS_X? (Dany) */
6047 void
6048mch_post_buffer_write(buf_T *buf)
6049{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006050 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6051 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006052}
6053#endif
6054
6055#ifdef FEAT_TITLE
6056/*
6057 * Set the window title and icon.
6058 * (The icon is not taken care of).
6059 */
6060 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006061gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062{
6063 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6064 * that 256. Even better get it to fit nicely in the titlebar.
6065 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006066#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006067 CFStringRef windowTitle;
6068 size_t windowTitleLen;
6069#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006070 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006071#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072
6073 if (title == NULL) /* nothing to do */
6074 return;
6075
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006076#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006077 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00006078 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006079
6080 if (windowTitle)
6081 {
6082 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6083 CFRelease(windowTitle);
6084 }
6085#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006086 pascalTitle = C2Pascal_save(title);
6087 if (pascalTitle != NULL)
6088 {
6089 SetWTitle(gui.VimWindow, pascalTitle);
6090 vim_free(pascalTitle);
6091 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006092#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006093}
6094#endif
6095
6096/*
6097 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6098 */
6099
6100 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006101C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102{
6103 char_u *PascalPtr = (char_u *) PascalString;
6104 int len;
6105 int i;
6106
6107 PascalPtr[0] = 0;
6108 if (CString == NULL)
6109 return 0;
6110
6111 len = STRLEN(CString);
6112 if (len > 255)
6113 len = 255;
6114
6115 for (i = 0; i < len; i++)
6116 PascalPtr[i+1] = CString[i];
6117
6118 PascalPtr[0] = len;
6119
6120 return 0;
6121}
6122
6123 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006124GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125{
6126 /* From FAQ 8-12 */
6127 Str255 filePascal;
6128 CInfoPBRec myCPB;
6129 OSErr err;
6130
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006131 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006132
6133 myCPB.dirInfo.ioNamePtr = filePascal;
6134 myCPB.dirInfo.ioVRefNum = 0;
6135 myCPB.dirInfo.ioFDirIndex = 0;
6136 myCPB.dirInfo.ioDrDirID = 0;
6137
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006138 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139
6140 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006141 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006142
6143 /* TODO: Use an error code mechanism */
6144 return 0;
6145}
6146
6147/*
6148 * Convert a FSSpec to a fuill path
6149 */
6150
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006151char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006152{
6153 /*
6154 * TODO: Add protection for 256 char max.
6155 */
6156
6157 CInfoPBRec theCPB;
6158 char_u fname[256];
6159 char_u *filenamePtr = fname;
6160 OSErr error;
6161 int folder = 1;
6162#ifdef USE_UNIXFILENAME
6163 SInt16 dfltVol_vRefNum;
6164 SInt32 dfltVol_dirID;
6165 FSRef refFile;
6166 OSStatus status;
6167 UInt32 pathSize = 256;
6168 char_u pathname[256];
6169 char_u *path = pathname;
6170#else
6171 Str255 directoryName;
6172 char_u temporary[255];
6173 char_u *temporaryPtr = temporary;
6174#endif
6175
6176#ifdef USE_UNIXFILENAME
6177 /* Get the default volume */
6178 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006179 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180
6181 if (error)
6182 return NULL;
6183#endif
6184
6185 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006186 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187
6188 /* Get the info about the file specified in FSSpec */
6189 theCPB.dirInfo.ioFDirIndex = 0;
6190 theCPB.dirInfo.ioNamePtr = file.name;
6191 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006192 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 theCPB.dirInfo.ioDrDirID = file.parID;
6194
6195 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6196 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006197 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198
6199 /* If we are called for a new file we expect fnfErr */
6200 if ((error) && (error != fnfErr))
6201 return NULL;
6202
6203 /* Check if it's a file or folder */
6204 /* default to file if file don't exist */
6205 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6206 folder = 0; /* It's not a folder */
6207 else
6208 folder = 1;
6209
6210#ifdef USE_UNIXFILENAME
6211 /*
6212 * The function used here are available in Carbon, but
6213 * do nothing une MacOS 8 and 9
6214 */
6215 if (error == fnfErr)
6216 {
6217 /* If the file to be saved does not already exist, it isn't possible
6218 to convert its FSSpec into an FSRef. But we can construct an
6219 FSSpec for the file's parent folder (since we have its volume and
6220 directory IDs), and since that folder does exist, we can convert
6221 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6222 and, finally, append the filename. */
6223 FSSpec dirSpec;
6224 FSRef dirRef;
6225 Str255 emptyFilename = "\p";
6226 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6227 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6228 if (error)
6229 return NULL;
6230
6231 error = FSpMakeFSRef(&dirSpec, &dirRef);
6232 if (error)
6233 return NULL;
6234
6235 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6236 if (status)
6237 return NULL;
6238
6239 STRCAT(path, "/");
6240 STRCAT(path, filenamePtr);
6241 }
6242 else
6243 {
6244 /* If the file to be saved already exists, we can get its full path
6245 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006246 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006247 if (error)
6248 return NULL;
6249
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006250 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251 if (status)
6252 return NULL;
6253 }
6254
6255 /* Add a slash at the end if needed */
6256 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006257 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006259 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006260#else
6261 /* TODO: Get rid of all USE_UNIXFILENAME below */
6262 /* Set ioNamePtr, it's the same area which is always reused. */
6263 theCPB.dirInfo.ioNamePtr = directoryName;
6264
6265 /* Trick for first entry, set ioDrParID to the first value
6266 * we want for ioDrDirID*/
6267 theCPB.dirInfo.ioDrParID = file.parID;
6268 theCPB.dirInfo.ioDrDirID = file.parID;
6269
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006270 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271 do
6272 {
6273 theCPB.dirInfo.ioFDirIndex = -1;
6274 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6275 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006276 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6278
6279 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6280 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006281 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006282
6283 if (error)
6284 return NULL;
6285
6286 /* Put the new directoryName in front of the current fname */
6287 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006288 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289 STRCAT(filenamePtr, ":");
6290 STRCAT(filenamePtr, temporaryPtr);
6291 }
6292#if 1 /* def USE_UNIXFILENAME */
6293 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6294 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6295#else
6296 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6297#endif
6298
6299 /* Get the information about the volume on which the file reside */
6300 theCPB.dirInfo.ioFDirIndex = -1;
6301 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6302 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006303 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006304 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6305
6306 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6307 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006308 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309
6310 if (error)
6311 return NULL;
6312
6313 /* For MacOS Classic always add the volume name */
6314 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006315 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316#ifdef USE_UNIXFILENAME
6317 if (file.vRefNum != dfltVol_vRefNum)
6318#endif
6319 {
6320 /* Add the volume name */
6321 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006322 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323 STRCAT(filenamePtr, ":");
6324 STRCAT(filenamePtr, temporaryPtr);
6325
6326#ifdef USE_UNIXFILENAME
6327 STRCPY(temporaryPtr, filenamePtr);
6328 filenamePtr[0] = 0; /* NULL terminate the string */
6329 STRCAT(filenamePtr, "Volumes:");
6330 STRCAT(filenamePtr, temporaryPtr);
6331#endif
6332 }
6333
6334 /* Append final path separator if it's a folder */
6335 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006336 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006337
6338 /* As we use Unix File Name for MacOS X convert it */
6339#ifdef USE_UNIXFILENAME
6340 /* Need to insert leading / */
6341 /* TODO: get the above code to use directly the / */
6342 STRCPY(&temporaryPtr[1], filenamePtr);
6343 temporaryPtr[0] = '/';
6344 STRCPY(filenamePtr, temporaryPtr);
6345 {
6346 char *p;
6347 for (p = fname; *p; p++)
6348 if (*p == ':')
6349 *p = '/';
6350 }
6351#endif
6352
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006353 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006354#endif
6355}
6356
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006357#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006358/*
6359 * Input Method Control functions.
6360 */
6361
6362/*
6363 * Notify cursor position to IM.
6364 */
6365 void
6366im_set_position(int row, int col)
6367{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006368#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006369 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006370 im_start_row = row;
6371 im_start_col = col;
6372#endif
6373}
6374
6375static ScriptLanguageRecord gTSLWindow;
6376static ScriptLanguageRecord gTSLInsert;
6377static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6378
6379static Component gTSCWindow;
6380static Component gTSCInsert;
6381static Component gTSCDefault;
6382
6383static int im_initialized = 0;
6384
6385 static void
6386im_on_window_switch(int active)
6387{
6388 ScriptLanguageRecord *slptr = NULL;
6389 OSStatus err;
6390
6391 if (! gui.in_use)
6392 return;
6393
6394 if (im_initialized == 0)
6395 {
6396 im_initialized = 1;
6397
6398 /* save default TSM component (should be U.S.) to default */
6399 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6400 kKeyboardInputMethodClass);
6401 }
6402
6403 if (active == TRUE)
6404 {
6405 im_is_active = TRUE;
6406 ActivateTSMDocument(gTSMDocument);
6407 slptr = &gTSLWindow;
6408
6409 if (slptr)
6410 {
6411 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6412 kKeyboardInputMethodClass);
6413 if (err == noErr)
6414 err = SetTextServiceLanguage(slptr);
6415
6416 if (err == noErr)
6417 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6418 }
6419 }
6420 else
6421 {
6422 err = GetTextServiceLanguage(&gTSLWindow);
6423 if (err == noErr)
6424 slptr = &gTSLWindow;
6425
6426 if (slptr)
6427 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6428 kKeyboardInputMethodClass);
6429
6430 im_is_active = FALSE;
6431 DeactivateTSMDocument(gTSMDocument);
6432 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433}
6434
6435/*
6436 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6437 */
6438 void
6439im_set_active(int active)
6440{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006441 ScriptLanguageRecord *slptr = NULL;
6442 OSStatus err;
6443
6444 if (! gui.in_use)
6445 return;
6446
6447 if (im_initialized == 0)
6448 {
6449 im_initialized = 1;
6450
6451 /* save default TSM component (should be U.S.) to default */
6452 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6453 kKeyboardInputMethodClass);
6454 }
6455
6456 if (active == TRUE)
6457 {
6458 im_is_active = TRUE;
6459 ActivateTSMDocument(gTSMDocument);
6460 slptr = &gTSLInsert;
6461
6462 if (slptr)
6463 {
6464 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6465 kKeyboardInputMethodClass);
6466 if (err == noErr)
6467 err = SetTextServiceLanguage(slptr);
6468
6469 if (err == noErr)
6470 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6471 }
6472 }
6473 else
6474 {
6475 err = GetTextServiceLanguage(&gTSLInsert);
6476 if (err == noErr)
6477 slptr = &gTSLInsert;
6478
6479 if (slptr)
6480 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6481 kKeyboardInputMethodClass);
6482
6483 /* restore to default when switch to normal mode, so than we could
6484 * enter commands easier */
6485 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6486 kKeyboardInputMethodClass);
6487 SetTextServiceLanguage(&gTSLDefault);
6488
6489 im_is_active = FALSE;
6490 DeactivateTSMDocument(gTSMDocument);
6491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006492}
6493
6494/*
6495 * Get IM status. When IM is on, return not 0. Else return 0.
6496 */
6497 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006498im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006499{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006500 if (! gui.in_use)
6501 return 0;
6502
6503 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006505
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006507
6508
6509
6510
6511#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6512// drawer implementation
6513static MenuRef contextMenu = NULL;
6514enum
6515{
6516 kTabContextMenuId = 42,
6517};
6518
6519// the caller has to CFRelease() the returned string
6520 static CFStringRef
6521getTabLabel(tabpage_T *page)
6522{
6523 get_tabline_label(page, FALSE);
6524#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006525 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006526#else
6527 // TODO: check internal encoding?
6528 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6529 kCFStringEncodingMacRoman);
6530#endif
6531}
6532
6533
6534#define DRAWER_SIZE 150
6535#define DRAWER_INSET 16
6536
6537static ControlRef dataBrowser = NULL;
6538
6539// when the tabline is hidden, vim doesn't call update_tabline(). When
6540// the tabline is shown again, show_tabline() is called before upate_tabline(),
6541// and because of this, the tab labels and vims internal tabs are out of sync
6542// for a very short time. to prevent inconsistent state, we store the labels
6543// of the tabs, not pointers to the tabs (which are invalid for a short time).
6544static CFStringRef *tabLabels = NULL;
6545static int tabLabelsSize = 0;
6546
6547enum
6548{
6549 kTabsColumn = 'Tabs'
6550};
6551
6552 static int
6553getTabCount(void)
6554{
6555 tabpage_T *tp;
6556 int numTabs = 0;
6557
6558 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006559 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006560 return numTabs;
6561}
6562
6563// data browser item display callback
6564 static OSStatus
6565dbItemDataCallback(ControlRef browser,
6566 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006567 DataBrowserPropertyID property /* column id */,
6568 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006569 Boolean changeValue)
6570{
6571 OSStatus status = noErr;
6572
6573 // assert(property == kTabsColumn); // why is this violated??
6574
6575 // changeValue is true if we have a modifieable list and data was changed.
6576 // In our case, it's always false.
6577 // (that is: if (changeValue) updateInternalData(); else return
6578 // internalData();
6579 if (!changeValue)
6580 {
6581 CFStringRef str;
6582
6583 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6584 str = tabLabels[itemID - 1];
6585 status = SetDataBrowserItemDataText(itemData, str);
6586 }
6587 else
6588 status = errDataBrowserPropertyNotSupported;
6589
6590 return status;
6591}
6592
6593// data browser action callback
6594 static void
6595dbItemNotificationCallback(ControlRef browser,
6596 DataBrowserItemID item,
6597 DataBrowserItemNotification message)
6598{
6599 switch (message)
6600 {
6601 case kDataBrowserItemSelected:
6602 send_tabline_event(item);
6603 break;
6604 }
6605}
6606
6607// callbacks needed for contextual menu:
6608 static void
6609dbGetContextualMenuCallback(ControlRef browser,
6610 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006611 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006612 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006613 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006614{
6615 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6616 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6617 *helpItemString = NULL;
6618
6619 *menu = contextMenu;
6620}
6621
6622 static void
6623dbSelectContextualMenuCallback(ControlRef browser,
6624 MenuRef menu,
6625 UInt32 selectionType,
6626 SInt16 menuID,
6627 MenuItemIndex menuItem)
6628{
6629 if (selectionType == kCMMenuItemSelected)
6630 {
6631 MenuCommand command;
6632 GetMenuItemCommandID(menu, menuItem, &command);
6633
6634 // get tab that was selected when the context menu appeared
6635 // (there is always one tab selected). TODO: check if the context menu
6636 // isn't opened on an item but on empty space (has to be possible some
6637 // way, the finder does it too ;-) )
6638 Handle items = NewHandle(0);
6639 if (items != NULL)
6640 {
6641 int numItems;
6642
6643 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6644 kDataBrowserItemIsSelected, items);
6645 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6646 if (numItems > 0)
6647 {
6648 int idx;
6649 DataBrowserItemID *itemsPtr;
6650
6651 HLock(items);
6652 itemsPtr = (DataBrowserItemID *)*items;
6653 idx = itemsPtr[0];
6654 HUnlock(items);
6655 send_tabline_menu_event(idx, command);
6656 }
6657 DisposeHandle(items);
6658 }
6659 }
6660}
6661
6662// focus callback of the data browser to always leave focus in vim
6663 static OSStatus
6664dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6665{
6666 assert(GetEventClass(event) == kEventClassControl
6667 && GetEventKind(event) == kEventControlSetFocusPart);
6668
6669 return paramErr;
6670}
6671
6672
6673// drawer callback to resize data browser to drawer size
6674 static OSStatus
6675drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6676{
6677 switch (GetEventKind(event))
6678 {
6679 case kEventWindowBoundsChanged: // move or resize
6680 {
6681 UInt32 attribs;
6682 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6683 NULL, sizeof(attribs), NULL, &attribs);
6684 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6685 {
6686 Rect r;
6687 GetWindowBounds(drawer, kWindowContentRgn, &r);
6688 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6689 SetControlBounds(dataBrowser, &r);
6690 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6691 kTabsColumn, r.right);
6692 }
6693 }
6694 break;
6695 }
6696
6697 return eventNotHandledErr;
6698}
6699
6700// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6701// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6702// blue highlights in the list view on these systems, though. Oh well.)
6703
6704
6705#import <mach-o/dyld.h>
6706
6707enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6708
6709 static OSStatus
6710myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6711 OptionBits inAttributesToSet,
6712 OptionBits inAttributesToClear)
6713{
6714 long osVersion;
6715 char *symbolName;
6716 NSSymbol symbol = NULL;
6717 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6718 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6719
6720 Gestalt(gestaltSystemVersion, &osVersion);
6721 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6722 return noErr;
6723
6724 // C name mangling...
6725 symbolName = "_DataBrowserChangeAttributes";
6726 if (!NSIsSymbolNameDefined(symbolName)
6727 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6728 return noErr;
6729
6730 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6731 if (dataBrowserChangeAttributes == NULL)
6732 return noErr; // well...
6733 return dataBrowserChangeAttributes(inDataBrowser,
6734 inAttributesToSet, inAttributesToClear);
6735}
6736
6737 static void
6738initialise_tabline(void)
6739{
6740 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6741 DataBrowserCallbacks dbCallbacks;
6742 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6743 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6744 DataBrowserListViewColumnDesc colDesc;
6745
6746 // drawers have to have compositing enabled
6747 CreateNewWindow(kDrawerWindowClass,
6748 kWindowStandardHandlerAttribute
6749 | kWindowCompositingAttribute
6750 | kWindowResizableAttribute
6751 | kWindowLiveResizeAttribute,
6752 &drawerRect, &drawer);
6753
6754 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6755 SetDrawerParent(drawer, gui.VimWindow);
6756 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6757
6758
6759 // create list view embedded in drawer
6760 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6761 &dataBrowser);
6762
6763 dbCallbacks.version = kDataBrowserLatestCallbacks;
6764 InitDataBrowserCallbacks(&dbCallbacks);
6765 dbCallbacks.u.v1.itemDataCallback =
6766 NewDataBrowserItemDataUPP(dbItemDataCallback);
6767 dbCallbacks.u.v1.itemNotificationCallback =
6768 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6769 dbCallbacks.u.v1.getContextualMenuCallback =
6770 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6771 dbCallbacks.u.v1.selectContextualMenuCallback =
6772 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6773
6774 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6775
6776 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6777 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6778 SetDataBrowserSelectionFlags(dataBrowser,
6779 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6780 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6781 kDataBrowserTableViewFillHilite);
6782 Boolean b = false;
6783 SetControlData(dataBrowser, kControlEntireControl,
6784 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6785
6786 // enable blue background in data browser (this is only in 10.4 and vim
6787 // has to support older osx versions as well, so we have to load this
6788 // function dynamically)
6789 myDataBrowserChangeAttributes(dataBrowser,
6790 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6791
6792 // install callback that keeps focus in vim and away from the data browser
6793 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6794 NULL, NULL);
6795
6796 // install callback that keeps data browser at the size of the drawer
6797 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6798 NULL, NULL);
6799
6800 // add "tabs" column to data browser
6801 colDesc.propertyDesc.propertyID = kTabsColumn;
6802 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6803
6804 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6805 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6806
6807 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6808 colDesc.headerBtnDesc.minimumWidth = 100;
6809 colDesc.headerBtnDesc.maximumWidth = 150;
6810 colDesc.headerBtnDesc.titleOffset = 0;
6811 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6812 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6813 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6814 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6815
6816 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6817
6818 // create tabline popup menu required by vim docs (see :he tabline-menu)
6819 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6820 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6821 TABLINE_MENU_CLOSE, NULL);
6822 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6823 TABLINE_MENU_NEW, NULL);
6824 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6825 TABLINE_MENU_OPEN, NULL);
6826}
6827
6828
6829/*
6830 * Show or hide the tabline.
6831 */
6832 void
6833gui_mch_show_tabline(int showit)
6834{
6835 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006836 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006837 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006838 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006839}
6840
6841/*
6842 * Return TRUE when tabline is displayed.
6843 */
6844 int
6845gui_mch_showing_tabline(void)
6846{
6847 WindowDrawerState state = GetDrawerState(drawer);
6848
6849 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6850}
6851
6852/*
6853 * Update the labels of the tabline.
6854 */
6855 void
6856gui_mch_update_tabline(void)
6857{
6858 tabpage_T *tp;
6859 int numTabs = getTabCount();
6860 int nr = 1;
6861 int curtabidx = 1;
6862
6863 // adjust data browser
6864 if (tabLabels != NULL)
6865 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006866 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006867
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006868 for (i = 0; i < tabLabelsSize; ++i)
6869 CFRelease(tabLabels[i]);
6870 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006871 }
6872 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6873 tabLabelsSize = numTabs;
6874
6875 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6876 {
6877 if (tp == curtab)
6878 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006879 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006880 }
6881
6882 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6883 kDataBrowserItemNoProperty);
6884 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6885 // can pass NULL for the id array
6886 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6887 kDataBrowserItemNoProperty);
6888
6889 DataBrowserItemID item = curtabidx;
6890 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6891}
6892
6893/*
6894 * Set the current tab to "nr". First tab is 1.
6895 */
6896 void
6897gui_mch_set_curtab(nr)
6898 int nr;
6899{
6900 DataBrowserItemID item = nr;
6901 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6902
6903 // TODO: call something like this?: (or restore scroll position, or...)
6904 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6905 kDataBrowserRevealOnly);
6906}
6907
6908#endif // FEAT_GUI_TABLINE