blob: 77cd5cad2ba1ba53f911be2f01b11681c2e19ba6 [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
65static int im_start_row = 0;
66static int im_start_col = 0;
67#endif
68
69#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
70
71static TSMDocumentID gTSMDocument;
72
73static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000074static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000075static EventHandlerUPP winEventHandlerUPP = NULL;
76
77static pascal OSStatus gui_mac_handle_window_activate(
78 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
79
80static pascal OSStatus gui_mac_handle_text_input(
81 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
82
83static pascal OSStatus gui_mac_update_input_area(
84 EventHandlerCallRef nextHandler, EventRef theEvent);
85
86static pascal OSStatus gui_mac_unicode_key_event(
87 EventHandlerCallRef nextHandler, EventRef theEvent);
88
Bram Moolenaar26a60b42005-02-22 08:49:11 +000089#endif
90
Bram Moolenaar071d4272004-06-13 20:20:40 +000091
92/* Include some file. TODO: move into os_mac.h */
93#include <Menus.h>
94#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000095#include <Processes.h>
96#ifdef USE_AEVENT
97# include <AppleEvents.h>
98# include <AERegistry.h>
99#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
102# include <ControlDefinitions.h>
103# include <Navigation.h> /* Navigation only part of ?? */
104#endif
105
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000106/* Help Manager (balloon.h, HM prefixed functions) are not supported
107 * under Carbon (Jussi) */
108# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000110# include <MacHelp.h>
111# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112
113/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000114 * These seem to be rectangle options. Why are they not found in
115 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117#define kNothing 0
118#define kCreateEmpty 2 /*1*/
119#define kCreateRect 2
120#define kDestroy 3
121
122/*
123 * Dany: Don't like those...
124 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125#define topLeft(r) (((Point*)&(r))[0])
126#define botRight(r) (((Point*)&(r))[1])
127
128
129/* Time of last mouse click, to detect double-click */
130static long lastMouseTick = 0;
131
132/* ??? */
133static RgnHandle cursorRgn;
134static RgnHandle dragRgn;
135static Rect dragRect;
136static short dragRectEnbl;
137static short dragRectControl;
138
139/* This variable is set when waiting for an event, which is the only moment
140 * scrollbar dragging can be done directly. It's not allowed while commands
141 * are executed, because it may move the cursor and that may cause unexpected
142 * problems (e.g., while ":s" is working).
143 */
144static int allow_scrollbar = FALSE;
145
146/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148
149/* Feedback Action for Scrollbar */
150ControlActionUPP gScrollAction;
151ControlActionUPP gScrollDrag;
152
153/* Keeping track of which scrollbar is being dragged */
154static ControlHandle dragged_sb = NULL;
155
Bram Moolenaarc52da9d2008-03-20 13:39:37 +0000156/* Vector of char_u --> control index for hotkeys in dialogs */
157static short *gDialogHotKeys;
158
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000159static struct
160{
161 FMFontFamily family;
162 FMFontSize size;
163 FMFontStyle style;
164 Boolean isPanelVisible;
165} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000166
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000167#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000168# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000169int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000170ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000171# ifdef FEAT_MBYTE
172ATSUStyle gWideFontStyle;
173# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000174Boolean gIsFontFallbackSet;
175#endif
176
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177/* Colors Macros */
178#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
179#define Red(c) ((c & 0x00FF0000) >> 16)
180#define Green(c) ((c & 0x0000FF00) >> 8)
181#define Blue(c) ((c & 0x000000FF) >> 0)
182
183/* Key mapping */
184
185#define vk_Esc 0x35 /* -> 1B */
186
187#define vk_F1 0x7A /* -> 10 */
188#define vk_F2 0x78 /*0x63*/
189#define vk_F3 0x63 /*0x76*/
190#define vk_F4 0x76 /*0x60*/
191#define vk_F5 0x60 /*0x61*/
192#define vk_F6 0x61 /*0x62*/
193#define vk_F7 0x62 /*0x63*/ /*?*/
194#define vk_F8 0x64
195#define vk_F9 0x65
196#define vk_F10 0x6D
197#define vk_F11 0x67
198#define vk_F12 0x6F
199#define vk_F13 0x69
200#define vk_F14 0x6B
201#define vk_F15 0x71
202
203#define vk_Clr 0x47 /* -> 1B (ESC) */
204#define vk_Enter 0x4C /* -> 03 */
205
206#define vk_Space 0x31 /* -> 20 */
207#define vk_Tab 0x30 /* -> 09 */
208#define vk_Return 0x24 /* -> 0D */
209/* This is wrong for OSX, what is it for? */
210#define vk_Delete 0X08 /* -> 08 BackSpace */
211
212#define vk_Help 0x72 /* -> 05 */
213#define vk_Home 0x73 /* -> 01 */
214#define vk_PageUp 0x74 /* -> 0D */
215#define vk_FwdDelete 0x75 /* -> 7F */
216#define vk_End 0x77 /* -> 04 */
217#define vk_PageDown 0x79 /* -> 0C */
218
219#define vk_Up 0x7E /* -> 1E */
220#define vk_Down 0x7D /* -> 1F */
221#define vk_Left 0x7B /* -> 1C */
222#define vk_Right 0x7C /* -> 1D */
223
224#define vk_Undo vk_F1
225#define vk_Cut vk_F2
226#define vk_Copy vk_F3
227#define vk_Paste vk_F4
228#define vk_PrintScreen vk_F13
229#define vk_SCrollLock vk_F14
230#define vk_Pause vk_F15
231#define vk_NumLock vk_Clr
232#define vk_Insert vk_Help
233
234#define KeySym char
235
236static struct
237{
238 KeySym key_sym;
239 char_u vim_code0;
240 char_u vim_code1;
241} special_keys[] =
242{
243 {vk_Up, 'k', 'u'},
244 {vk_Down, 'k', 'd'},
245 {vk_Left, 'k', 'l'},
246 {vk_Right, 'k', 'r'},
247
248 {vk_F1, 'k', '1'},
249 {vk_F2, 'k', '2'},
250 {vk_F3, 'k', '3'},
251 {vk_F4, 'k', '4'},
252 {vk_F5, 'k', '5'},
253 {vk_F6, 'k', '6'},
254 {vk_F7, 'k', '7'},
255 {vk_F8, 'k', '8'},
256 {vk_F9, 'k', '9'},
257 {vk_F10, 'k', ';'},
258
259 {vk_F11, 'F', '1'},
260 {vk_F12, 'F', '2'},
261 {vk_F13, 'F', '3'},
262 {vk_F14, 'F', '4'},
263 {vk_F15, 'F', '5'},
264
265/* {XK_Help, '%', '1'}, */
266/* {XK_Undo, '&', '8'}, */
267/* {XK_BackSpace, 'k', 'b'}, */
268#ifndef MACOS_X
269 {vk_Delete, 'k', 'b'},
270#endif
271 {vk_Insert, 'k', 'I'},
272 {vk_FwdDelete, 'k', 'D'},
273 {vk_Home, 'k', 'h'},
274 {vk_End, '@', '7'},
275/* {XK_Prior, 'k', 'P'}, */
276/* {XK_Next, 'k', 'N'}, */
277/* {XK_Print, '%', '9'}, */
278
279 {vk_PageUp, 'k', 'P'},
280 {vk_PageDown, 'k', 'N'},
281
282 /* End of list marker: */
283 {(KeySym)0, 0, 0}
284};
285
286/*
287 * ------------------------------------------------------------
288 * Forward declaration (for those needed)
289 * ------------------------------------------------------------
290 */
291
292#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000293OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294#endif
295
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000296#ifdef FEAT_GUI_TABLINE
297static void initialise_tabline(void);
298static WindowRef drawer = NULL; // TODO: put into gui.h
299#endif
300
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000301#ifdef USE_ATSUI_DRAWING
302static void gui_mac_set_font_attributes(GuiFont font);
303static void gui_mac_dispose_atsui_style(void);
304#endif
305
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306/*
307 * ------------------------------------------------------------
308 * Conversion Utility
309 * ------------------------------------------------------------
310 */
311
312/*
313 * C2Pascal_save
314 *
315 * Allocate memory and convert the C-String passed in
316 * into a pascal string
317 *
318 */
319
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000320 char_u *
321C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322{
323 char_u *PascalString;
324 int len;
325
326 if (Cstring == NULL)
327 return NULL;
328
329 len = STRLEN(Cstring);
330
331 if (len > 255) /* Truncate if necessary */
332 len = 255;
333
334 PascalString = alloc(len + 1);
335 if (PascalString != NULL)
336 {
337 mch_memmove(PascalString + 1, Cstring, len);
338 PascalString[0] = len;
339 }
340
341 return PascalString;
342}
343
344/*
345 * C2Pascal_save_and_remove_backslash
346 *
347 * Allocate memory and convert the C-String passed in
348 * into a pascal string. Also remove the backslash at the same time
349 *
350 */
351
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000352 char_u *
353C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354{
355 char_u *PascalString;
356 int len;
357 char_u *p, *c;
358
359 len = STRLEN(Cstring);
360
361 if (len > 255) /* Truncate if necessary */
362 len = 255;
363
364 PascalString = alloc(len + 1);
365 if (PascalString != NULL)
366 {
367 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
368 {
369 if ((*c == '\\') && (c[1] != 0))
370 {
371 c++;
372 }
373 *p = *c;
374 p++;
375 len++;
376 }
377 PascalString[0] = len;
378 }
379
380 return PascalString;
381}
382
383/*
384 * Convert the modifiers of an Event into vim's modifiers (mouse)
385 */
386
387 int_u
388EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
389{
390 int_u vimModifiers = 0x00;
391
392 if (macModifiers & (shiftKey | rightShiftKey))
393 vimModifiers |= MOUSE_SHIFT;
394 if (macModifiers & (controlKey | rightControlKey))
395 vimModifiers |= MOUSE_CTRL;
396 if (macModifiers & (optionKey | rightOptionKey))
397 vimModifiers |= MOUSE_ALT;
398#if 0
399 /* Not yet supported */
400 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
401 vimModifiers |= MOUSE_CMD;
402#endif
403 return (vimModifiers);
404}
405
406/*
407 * Convert the modifiers of an Event into vim's modifiers (keys)
408 */
409
410 static int_u
411EventModifiers2VimModifiers(EventModifiers macModifiers)
412{
413 int_u vimModifiers = 0x00;
414
415 if (macModifiers & (shiftKey | rightShiftKey))
416 vimModifiers |= MOD_MASK_SHIFT;
417 if (macModifiers & (controlKey | rightControlKey))
418 vimModifiers |= MOD_MASK_CTRL;
419 if (macModifiers & (optionKey | rightOptionKey))
420 vimModifiers |= MOD_MASK_ALT;
421#ifdef USE_CMD_KEY
422 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
423 vimModifiers |= MOD_MASK_CMD;
424#endif
425 return (vimModifiers);
426}
427
428/* Convert a string representing a point size into pixels. The string should
429 * be a positive decimal number, with an optional decimal point (eg, "12", or
430 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
431 * character is stored in *end. The flag "vertical" says whether this
432 * calculation is for a vertical (height) size or a horizontal (width) one.
433 *
434 * From gui_w48.c
435 */
436 static int
437points_to_pixels(char_u *str, char_u **end, int vertical)
438{
439 int pixels;
440 int points = 0;
441 int divisor = 0;
442
443 while (*str)
444 {
445 if (*str == '.' && divisor == 0)
446 {
447 /* Start keeping a divisor, for later */
448 divisor = 1;
449 continue;
450 }
451
452 if (!isdigit(*str))
453 break;
454
455 points *= 10;
456 points += *str - '0';
457 divisor *= 10;
458
459 ++str;
460 }
461
462 if (divisor == 0)
463 divisor = 1;
464
465 pixels = points/divisor;
466 *end = str;
467 return pixels;
468}
469
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000470#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000471/*
472 * Deletes all traces of any Windows-style mnemonic text (including any
473 * parentheses) from a menu item and returns the cleaned menu item title.
474 * The caller is responsible for releasing the returned string.
475 */
476 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000477menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000478{
479 CFStringRef name;
480 size_t menuTitleLen;
481 CFIndex displayLen;
482 CFRange mnemonicStart;
483 CFRange mnemonicEnd;
484 CFMutableStringRef cleanedName;
485
486 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000487 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000488
489 if (name)
490 {
491 /* Simple mnemonic-removal algorithm, assumes single parenthesized
492 * mnemonic character towards the end of the menu text */
493 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
494 displayLen = CFStringGetLength(name);
495
496 if (mnemonicStart.location != kCFNotFound
497 && (mnemonicStart.location + 2) < displayLen
498 && CFStringGetCharacterAtIndex(name,
499 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
500 {
501 if (CFStringFindWithOptions(name, CFSTR(")"),
502 CFRangeMake(mnemonicStart.location + 1,
503 displayLen - mnemonicStart.location - 1),
504 kCFCompareBackwards, &mnemonicEnd) &&
505 (mnemonicStart.location + 2) == mnemonicEnd.location)
506 {
507 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
508 if (cleanedName)
509 {
510 CFStringDelete(cleanedName,
511 CFRangeMake(mnemonicStart.location,
512 mnemonicEnd.location + 1 -
513 mnemonicStart.location));
514
515 CFRelease(name);
516 name = cleanedName;
517 }
518 }
519 }
520 }
521
522 return name;
523}
524#endif
525
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526/*
527 * Convert a list of FSSpec aliases into a list of fullpathname
528 * character strings.
529 */
530
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000531 char_u **
532new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000533{
534 char_u **fnames = NULL;
535 OSErr newError;
536 long fileCount;
537 FSSpec fileToOpen;
538 long actualSize;
539 AEKeyword dummyKeyword;
540 DescType dummyType;
541
542 /* Get number of files in list */
543 *error = AECountItems(theList, numFiles);
544 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000545 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
547 /* Allocate the pointer list */
548 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
549
550 /* Empty out the list */
551 for (fileCount = 0; fileCount < *numFiles; fileCount++)
552 fnames[fileCount] = NULL;
553
554 /* Scan the list of FSSpec */
555 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
556 {
557 /* Get the alias for the nth file, convert to an FSSpec */
558 newError = AEGetNthPtr(theList, fileCount, typeFSS,
559 &dummyKeyword, &dummyType,
560 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
561 if (newError)
562 {
563 /* Caller is able to clean up */
564 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000565 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567
568 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000569 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 }
571
572 return (fnames);
573}
574
575/*
576 * ------------------------------------------------------------
577 * CodeWarrior External Editor Support
578 * ------------------------------------------------------------
579 */
580#ifdef FEAT_CW_EDITOR
581
582/*
583 * Handle the Window Search event from CodeWarrior
584 *
585 * Description
586 * -----------
587 *
588 * The IDE sends the Window Search AppleEvent to the editor when it
589 * needs to know whether a particular file is open in the editor.
590 *
591 * Event Reply
592 * -----------
593 *
594 * None. Put data in the location specified in the structure received.
595 *
596 * Remarks
597 * -------
598 *
599 * When the editor receives this event, determine whether the specified
600 * file is open. If it is, return the modification date/time for that file
601 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000602 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 *
604 */
605
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606typedef struct WindowSearch WindowSearch;
607struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
608{
609 FSSpec theFile; // identifies the file
610 long *theDate; // where to put the modification date/time
611};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000613 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000614Handle_KAHL_SRCH_AE(
615 const AppleEvent *theAEvent,
616 AppleEvent *theReply,
617 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618{
619 OSErr error = noErr;
620 buf_T *buf;
621 int foundFile = false;
622 DescType typeCode;
623 WindowSearch SearchData;
624 Size actualSize;
625
626 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
627 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000628 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000630 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000632 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633
634 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
635 if (buf->b_ml.ml_mfp != NULL
636 && SearchData.theFile.parID == buf->b_FSSpec.parID
637 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
638 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
639 {
640 foundFile = true;
641 break;
642 }
643
644 if (foundFile == false)
645 *SearchData.theDate = fnfErr;
646 else
647 *SearchData.theDate = buf->b_mtime;
648
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 return error;
650};
651
652/*
653 * Handle the Modified (from IDE to Editor) event from CodeWarrior
654 *
655 * Description
656 * -----------
657 *
658 * The IDE sends this event to the external editor when it wants to
659 * know which files that are open in the editor have been modified.
660 *
661 * Parameters None.
662 * ----------
663 *
664 * Event Reply
665 * -----------
666 * The reply for this event is:
667 *
668 * keyDirectObject typeAEList required
669 * each element in the list is a structure of typeChar
670 *
671 * Remarks
672 * -------
673 *
674 * When building the reply event, include one element in the list for
675 * each open file that has been modified.
676 *
677 */
678
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679typedef struct ModificationInfo ModificationInfo;
680struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
681{
682 FSSpec theFile; // identifies the file
683 long theDate; // the date/time the file was last modified
684 short saved; // set this to zero when replying, unused
685};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000687 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000688Handle_KAHL_MOD_AE(
689 const AppleEvent *theAEvent,
690 AppleEvent *theReply,
691 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692{
693 OSErr error = noErr;
694 AEDescList replyList;
695 long numFiles;
696 ModificationInfo theFile;
697 buf_T *buf;
698
699 theFile.saved = 0;
700
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000701 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000703 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
705 /* Send the reply */
706/* replyObject.descriptorType = typeNull;
707 replyObject.dataHandle = nil;*/
708
709/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
710 error = AECreateList(nil, 0, false, &replyList);
711 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000712 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713
714#if 0
715 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000717 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
718 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 * sizeof(DescType))
720 */
721
722 /* AEPutDesc */
723#endif
724
725 numFiles = 0;
726 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
727 if (buf->b_ml.ml_mfp != NULL)
728 {
729 /* Add this file to the list */
730 theFile.theFile = buf->b_FSSpec;
731 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000732/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
733 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 };
735
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736#if 0
737 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#endif
739
740 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000741 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 if (replyList.dataHandle)
744 AEDisposeDesc(&replyList);
745
746 return error;
747};
748
749/*
750 * Handle the Get Text event from CodeWarrior
751 *
752 * Description
753 * -----------
754 *
755 * The IDE sends the Get Text AppleEvent to the editor when it needs
756 * the source code from a file. For example, when the user issues a
757 * Check Syntax or Compile command, the compiler needs access to
758 * the source code contained in the file.
759 *
760 * Event Reply
761 * -----------
762 *
763 * None. Put data in locations specified in the structure received.
764 *
765 * Remarks
766 * -------
767 *
768 * When the editor receives this event, it must set the size of the handle
769 * in theText to fit the data in the file. It must then copy the entire
770 * contents of the specified file into the memory location specified in
771 * theText.
772 *
773 */
774
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775typedef struct CW_GetText CW_GetText;
776struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
777{
778 FSSpec theFile; /* identifies the file */
779 Handle theText; /* the location where you return the text (must be resized properly) */
780 long *unused; /* 0 (not used) */
781 long *theDate; /* where to put the modification date/time */
782};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000784 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000785Handle_KAHL_GTTX_AE(
786 const AppleEvent *theAEvent,
787 AppleEvent *theReply,
788 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789{
790 OSErr error = noErr;
791 buf_T *buf;
792 int foundFile = false;
793 DescType typeCode;
794 CW_GetText GetTextData;
795 Size actualSize;
796 char_u *line;
797 char_u *fullbuffer = NULL;
798 long linesize;
799 long lineStart;
800 long BufferSize;
801 long lineno;
802
803 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
804
805 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000806 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807
808 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
809 if (buf->b_ml.ml_mfp != NULL)
810 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
811 {
812 foundFile = true;
813 break;
814 }
815
816 if (foundFile)
817 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000818 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
820 {
821 /* Must use the right buffer */
822 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
823 linesize = STRLEN(line) + 1;
824 lineStart = BufferSize;
825 BufferSize += linesize;
826 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000827 SetHandleSize(GetTextData.theText, BufferSize);
828 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 break; /* Simple handling for now */
831 }
832 else
833 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000834 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 }
840 }
841 if (fullbuffer != NULL)
842 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000843 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 }
847 if (foundFile == false)
848 *GetTextData.theDate = fnfErr;
849 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000850/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 *GetTextData.theDate = buf->b_mtime;
852 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000854 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000856 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857}
858
859/*
860 *
861 */
862
863/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000864 pascal OSErr
865FindProcessBySignature(
866 const OSType targetType,
867 const OSType targetCreator,
868 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869{
870 OSErr anErr = noErr;
871 Boolean lookingForProcess = true;
872
873 ProcessInfoRec infoRec;
874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 infoRec.processName = nil;
877 infoRec.processAppSpec = nil;
878
879 psnPtr->lowLongOfPSN = kNoProcess;
880 psnPtr->highLongOfPSN = kNoProcess;
881
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000882 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 anErr = GetNextProcess(psnPtr);
885 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 else
888 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000889 anErr = GetProcessInformation(psnPtr, &infoRec);
890 if ((anErr == noErr)
891 && (infoRec.processType == targetType)
892 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 }
895 }
896
897 return anErr;
898}//end FindProcessBySignature
899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000900 void
901Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000903 OSErr anErr = noErr;
904 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
906 AppleEvent theReply = { typeNull, nil };
907 AESendMode sendMode;
908 AppleEvent theEvent = {typeNull, nil };
909 AEIdleUPP idleProcUPP = nil;
910 ModificationInfo ModData;
911
912
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000914 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
917 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000919 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 {
921 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
922 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
923 }
924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000925 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926
927 /* Add the parms */
928 ModData.theFile = buf->b_FSSpec;
929 ModData.theDate = buf->b_mtime;
930
931 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000932 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 sendMode = kAENoReply;
936 else
937 sendMode = kAEWaitReply;
938
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000939 if (anErr == noErr)
940 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
941 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000943/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000945 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 }
947}
948#endif /* FEAT_CW_EDITOR */
949
950/*
951 * ------------------------------------------------------------
952 * Apple Event Handling procedure
953 * ------------------------------------------------------------
954 */
955#ifdef USE_AEVENT
956
957/*
958 * Handle the Unused parms of an AppleEvent
959 */
960
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000961 OSErr
962HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963{
964 OSErr error;
965 long actualSize;
966 DescType dummyType;
967 AEKeyword missedKeyword;
968
969 /* Get the "missed keyword" attribute from the AppleEvent. */
970 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
971 typeKeyword, &dummyType,
972 (Ptr)&missedKeyword, sizeof(missedKeyword),
973 &actualSize);
974
975 /* If the descriptor isn't found, then we got the required parameters. */
976 if (error == errAEDescNotFound)
977 {
978 error = noErr;
979 }
980 else
981 {
982#if 0
983 /* Why is this removed? */
984 error = errAEEventNotHandled;
985#endif
986 }
987
988 return error;
989}
990
991
992/*
993 * Handle the ODoc AppleEvent
994 *
995 * Deals with all files dragged to the application icon.
996 *
997 */
998
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999typedef struct SelectionRange SelectionRange;
1000struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1001{
1002 short unused1; // 0 (not used)
1003 short lineNum; // line to select (<0 to specify range)
1004 long startRange; // start of selection range (if line < 0)
1005 long endRange; // end of selection range (if line < 0)
1006 long unused2; // 0 (not used)
1007 long theDate; // modification date/time
1008};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009
1010/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1011 itor the selection range. If lineNum is zero or greater, scroll the text
1012 to the specified line. If lineNum is less than zero, use the values in
1013 startRange and endRange to select the specified characters. Scroll
1014 the text to display the selection. If lineNum, startRange, and
1015 endRange are all negative, there is no selection range specified.
1016 */
1017
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001018 pascal OSErr
1019HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020{
1021 /*
1022 * TODO: Clean up the code with convert the AppleEvent into
1023 * a ":args"
1024 */
1025 OSErr error = noErr;
1026// OSErr firstError = noErr;
1027// short numErrors = 0;
1028 AEDesc theList;
1029 DescType typeCode;
1030 long numFiles;
1031 // long fileCount;
1032 char_u **fnames;
1033// char_u fname[256];
1034 Size actualSize;
1035 SelectionRange thePosition;
1036 short gotPosition = false;
1037 long lnum;
1038
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 /* the direct object parameter is the list of aliases to files (one or more) */
1040 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1041 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001042 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043
1044
1045 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1046 if (error == noErr)
1047 gotPosition = true;
1048 if (error == errAEDescNotFound)
1049 error = noErr;
1050 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001051 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053/*
1054 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1055
1056 if (^error) then
1057 {
1058 if (thePosition.lineNum >= 0)
1059 {
1060 // Goto this line
1061 }
1062 else
1063 {
1064 // Set the range char wise
1065 }
1066 }
1067 */
1068
1069
1070#ifdef FEAT_VISUAL
1071 reset_VIsual();
1072#endif
1073
1074 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1075
1076 if (error)
1077 {
1078 /* TODO: empty fnames[] first */
1079 vim_free(fnames);
1080 return (error);
1081 }
1082
1083 if (starting > 0)
1084 {
1085 int i;
1086 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001087 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088
1089 /* these are the initial files dropped on the Vim icon */
1090 for (i = 0 ; i < numFiles; i++)
1091 {
1092 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1093 || (p = vim_strsave(fnames[i])) == NULL)
1094 mch_exit(2);
1095 else
1096 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001097 if (fnum == -1)
1098 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1099 }
1100
1101 /* If the file name was already in the buffer list we need to switch
1102 * to it. */
1103 if (curbuf->b_fnum != fnum)
1104 {
1105 char_u cmd[30];
1106
1107 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1108 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001110
1111 /* Change directory to the location of the first file. */
1112 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1113 shorten_fnames(TRUE);
1114
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115 goto finished;
1116 }
1117
1118 /* Handle the drop, :edit to get to the file */
1119 handle_drop(numFiles, fnames, FALSE);
1120
1121 /* TODO: Handle the goto/select line more cleanly */
1122 if ((numFiles == 1) & (gotPosition))
1123 {
1124 if (thePosition.lineNum >= 0)
1125 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001126 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 /* oap->motion_type = MLINE;
1128 setpcmark();*/
1129 if (lnum < 1L)
1130 lnum = 1L;
1131 else if (lnum > curbuf->b_ml.ml_line_count)
1132 lnum = curbuf->b_ml.ml_line_count;
1133 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001134 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135 /* beginline(BL_SOL | BL_FIX);*/
1136 }
1137 else
1138 goto_byte(thePosition.startRange + 1);
1139 }
1140
1141 /* Update the screen display */
1142 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001143#ifdef FEAT_VISUAL
1144 /* Select the text if possible */
1145 if (gotPosition)
1146 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001147 VIsual_active = TRUE;
1148 VIsual_select = FALSE;
1149 VIsual = curwin->w_cursor;
1150 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001151 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001152 VIsual_mode = 'v';
1153 goto_byte(thePosition.endRange);
1154 }
1155 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001156 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001157 VIsual_mode = 'V';
1158 VIsual.col = 0;
1159 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001160 }
1161#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162 setcursor();
1163 out_flush();
1164
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001165 /* Fake mouse event to wake from stall */
1166 PostEvent(mouseUp, 0);
1167
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001168finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169 AEDisposeDesc(&theList); /* dispose what we allocated */
1170
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001171 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001172 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173}
1174
1175/*
1176 *
1177 */
1178
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001179 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001180Handle_aevt_oapp_AE(
1181 const AppleEvent *theAEvent,
1182 AppleEvent *theReply,
1183 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184{
1185 OSErr error = noErr;
1186
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001187 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001188 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189}
1190
1191/*
1192 *
1193 */
1194
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001195 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001196Handle_aevt_quit_AE(
1197 const AppleEvent *theAEvent,
1198 AppleEvent *theReply,
1199 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200{
1201 OSErr error = noErr;
1202
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001203 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001205 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206
1207 /* Need to fake a :confirm qa */
1208 do_cmdline_cmd((char_u *)"confirm qa");
1209
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001210 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211}
1212
1213/*
1214 *
1215 */
1216
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001217 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001218Handle_aevt_pdoc_AE(
1219 const AppleEvent *theAEvent,
1220 AppleEvent *theReply,
1221 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222{
1223 OSErr error = noErr;
1224
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001225 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001227 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228}
1229
1230/*
1231 * Handling of unknown AppleEvent
1232 *
1233 * (Just get rid of all the parms)
1234 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001235 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001236Handle_unknown_AE(
1237 const AppleEvent *theAEvent,
1238 AppleEvent *theReply,
1239 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240{
1241 OSErr error = noErr;
1242
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001243 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001245 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246}
1247
1248
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249/*
1250 * Install the various AppleEvent Handlers
1251 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001252 OSErr
1253InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254{
1255 OSErr error;
1256
1257 /* install open application handler */
1258 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001259 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 if (error)
1261 {
1262 return error;
1263 }
1264
1265 /* install quit application handler */
1266 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001267 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 if (error)
1269 {
1270 return error;
1271 }
1272
1273 /* install open document handler */
1274 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001275 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 if (error)
1277 {
1278 return error;
1279 }
1280
1281 /* install print document handler */
1282 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001283 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284
1285/* Install Core Suite */
1286/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001287 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288
1289 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001290 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291
1292 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001293 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294
1295 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001296 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297
1298 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001299 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300
1301 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001302 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303
1304 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001305 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306
1307 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001308 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309
1310 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001311 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312
1313 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001314 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315
1316 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001317 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318
1319 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001320 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321
1322 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001323 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001324*/
1325
1326#ifdef FEAT_CW_EDITOR
1327 /*
1328 * Bind codewarrior support handlers
1329 */
1330 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001331 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 if (error)
1333 {
1334 return error;
1335 }
1336 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001337 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001338 if (error)
1339 {
1340 return error;
1341 }
1342 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001343 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344 if (error)
1345 {
1346 return error;
1347 }
1348#endif
1349
1350 return error;
1351
1352}
1353#endif /* USE_AEVENT */
1354
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001355
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001356/*
1357 * Callback function, installed by InstallFontPanelHandler(), below,
1358 * to handle Font Panel events.
1359 */
1360 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001361FontPanelHandler(
1362 EventHandlerCallRef inHandlerCallRef,
1363 EventRef inEvent,
1364 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001365{
1366 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1367 {
1368 gFontPanelInfo.isPanelVisible = false;
1369 return noErr;
1370 }
1371
1372 if (GetEventKind(inEvent) == kEventFontSelection)
1373 {
1374 OSStatus status;
1375 FMFontFamily newFamily;
1376 FMFontSize newSize;
1377 FMFontStyle newStyle;
1378
1379 /* Retrieve the font family ID number. */
1380 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1381 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1382 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1383 &newFamily);
1384 if (status == noErr)
1385 gFontPanelInfo.family = newFamily;
1386
1387 /* Retrieve the font size. */
1388 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1389 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1390 if (status == noErr)
1391 gFontPanelInfo.size = newSize;
1392
1393 /* Retrieve the font style (bold, etc.). Currently unused. */
1394 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1395 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1396 if (status == noErr)
1397 gFontPanelInfo.style = newStyle;
1398 }
1399 return noErr;
1400}
1401
1402
1403 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001404InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001405{
1406 EventTypeSpec eventTypes[2];
1407 EventHandlerUPP handlerUPP;
1408 /* EventHandlerRef handlerRef; */
1409
1410 eventTypes[0].eventClass = kEventClassFont;
1411 eventTypes[0].eventKind = kEventFontSelection;
1412 eventTypes[1].eventClass = kEventClassFont;
1413 eventTypes[1].eventKind = kEventFontPanelClosed;
1414
1415 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1416
1417 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1418 /*userData=*/NULL, /*handlerRef=*/NULL);
1419}
1420
1421
1422/*
1423 * Fill the buffer pointed to by outName with the name and size
1424 * of the font currently selected in the Font Panel.
1425 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001426#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001427 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001428GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001429{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001430 Str255 buf;
1431 ByteCount fontNameLen = 0;
1432 ATSUFontID fid;
1433 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001434
1435 if (!outName)
1436 return;
1437
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001438 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1439 {
1440 /* Canonicalize localized font names */
1441 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1442 gFontPanelInfo.style, &fid, NULL) != noErr)
1443 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001444
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001445 /* Request font name with Mac encoding (otherwise we could
1446 * get an unwanted utf-16 name) */
1447 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1448 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001449 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001450 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001451
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001452 /* Only encode font size, because style (bold, italic, etc) is
1453 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001454 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001455 gFontPanelInfo.size/*,
1456 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1457 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1458 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1459
1460 if ((fontNameLen + STRLEN(styleString)) < 255)
1461 STRCPY(outName + fontNameLen, styleString);
1462 }
1463 else
1464 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001465 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001466 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001467}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001468
1469
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470/*
1471 * ------------------------------------------------------------
1472 * Unfiled yet
1473 * ------------------------------------------------------------
1474 */
1475
1476/*
1477 * gui_mac_get_menu_item_index
1478 *
1479 * Returns the index inside the menu wher
1480 */
1481 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001482gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001483{
1484 short index;
1485 short itemIndex = -1;
1486 vimmenu_T *pBrother;
1487
1488 /* Only menu without parent are the:
1489 * -menu in the menubar
1490 * -popup menu
1491 * -toolbar (guess)
1492 *
1493 * Which are not items anyway.
1494 */
1495 if (pMenu->parent)
1496 {
1497 /* Start from the Oldest Brother */
1498 pBrother = pMenu->parent->children;
1499 index = 1;
1500 while ((pBrother) && (itemIndex == -1))
1501 {
1502 if (pBrother == pMenu)
1503 itemIndex = index;
1504 index++;
1505 pBrother = pBrother->next;
1506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 }
1508 return itemIndex;
1509}
1510
1511 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001512gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001513{
1514 short index;
1515 vimmenu_T *pChildMenu;
1516 vimmenu_T *pElder = pMenu->parent;
1517
1518
1519 /* Only menu without parent are the:
1520 * -menu in the menubar
1521 * -popup menu
1522 * -toolbar (guess)
1523 *
1524 * Which are not items anyway.
1525 */
1526
1527 if ((pElder) && (pElder->submenu_id == menuID))
1528 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1530 pMenu = pMenu->next;
1531 }
1532 else
1533 {
1534 for (; pMenu != NULL; pMenu = pMenu->next)
1535 {
1536 if (pMenu->children != NULL)
1537 {
1538 pChildMenu = gui_mac_get_vim_menu
1539 (menuID, itemIndex, pMenu->children);
1540 if (pChildMenu)
1541 {
1542 pMenu = pChildMenu;
1543 break;
1544 }
1545 }
1546 }
1547 }
1548 return pMenu;
1549}
1550
1551/*
1552 * ------------------------------------------------------------
1553 * MacOS Feedback procedures
1554 * ------------------------------------------------------------
1555 */
1556 pascal
1557 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001558gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559{
1560 scrollbar_T *sb;
1561 int value, dragging;
1562 ControlHandle theControlToUse;
1563 int dont_scroll_save = dont_scroll;
1564
1565 theControlToUse = dragged_sb;
1566
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001567 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568
1569 if (sb == NULL)
1570 return;
1571
1572 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001573 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574 dragging = (partCode != 0);
1575
1576 /* When "allow_scrollbar" is FALSE still need to remember the new
1577 * position, but don't actually scroll by setting "dont_scroll". */
1578 dont_scroll = !allow_scrollbar;
1579 gui_drag_scrollbar(sb, value, dragging);
1580 dont_scroll = dont_scroll_save;
1581}
1582
1583 pascal
1584 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001585gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586{
1587 /* TODO: have live support */
1588 scrollbar_T *sb, *sb_info;
1589 long data;
1590 long value;
1591 int page;
1592 int dragging = FALSE;
1593 int dont_scroll_save = dont_scroll;
1594
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001595 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596
1597 if (sb == NULL)
1598 return;
1599
1600 if (sb->wp != NULL) /* Left or right scrollbar */
1601 {
1602 /*
1603 * Careful: need to get scrollbar info out of first (left) scrollbar
1604 * for window, but keep real scrollbar too because we must pass it to
1605 * gui_drag_scrollbar().
1606 */
1607 sb_info = &sb->wp->w_scrollbars[0];
1608
1609 if (sb_info->size > 5)
1610 page = sb_info->size - 2; /* use two lines of context */
1611 else
1612 page = sb_info->size;
1613 }
1614 else /* Bottom scrollbar */
1615 {
1616 sb_info = sb;
1617 page = W_WIDTH(curwin) - 5;
1618 }
1619
1620 switch (partCode)
1621 {
1622 case kControlUpButtonPart: data = -1; break;
1623 case kControlDownButtonPart: data = 1; break;
1624 case kControlPageDownPart: data = page; break;
1625 case kControlPageUpPart: data = -page; break;
1626 default: data = 0; break;
1627 }
1628
1629 value = sb_info->value + data;
1630/* if (value > sb_info->max)
1631 value = sb_info->max;
1632 else if (value < 0)
1633 value = 0;*/
1634
1635 /* When "allow_scrollbar" is FALSE still need to remember the new
1636 * position, but don't actually scroll by setting "dont_scroll". */
1637 dont_scroll = !allow_scrollbar;
1638 gui_drag_scrollbar(sb, value, dragging);
1639 dont_scroll = dont_scroll_save;
1640
1641 out_flush();
1642 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1643
1644/* if (sb_info->wp != NULL)
1645 {
1646 win_T *wp;
1647 int sb_num;
1648
1649 sb_num = 0;
1650 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1651 sb_num++;
1652
1653 if (wp != NULL)
1654 {
1655 current_scrollbar = sb_num;
1656 scrollbar_value = value;
1657 gui_do_scroll();
1658 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1659 }
1660 }*/
1661}
1662
1663/*
1664 * ------------------------------------------------------------
1665 * MacOS Click Handling procedures
1666 * ------------------------------------------------------------
1667 */
1668
1669
1670/*
1671 * Handle a click inside the window, it may happens in the
1672 * scrollbar or the contents.
1673 *
1674 * TODO: Add support for potential TOOLBAR
1675 */
1676 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001677gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678{
1679 Point thePoint;
1680 int_u vimModifiers;
1681 short thePortion;
1682 ControlHandle theControl;
1683 int vimMouseButton;
1684 short dblClick;
1685
1686 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001687 GlobalToLocal(&thePoint);
1688 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001690 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691
1692 if (theControl != NUL)
1693 {
1694 /* We hit a scollbar */
1695
1696 if (thePortion != kControlIndicatorPart)
1697 {
1698 dragged_sb = theControl;
1699 TrackControl(theControl, thePoint, gScrollAction);
1700 dragged_sb = NULL;
1701 }
1702 else
1703 {
1704 dragged_sb = theControl;
1705#if 1
1706 TrackControl(theControl, thePoint, gScrollDrag);
1707#else
1708 TrackControl(theControl, thePoint, NULL);
1709#endif
1710 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1711 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001712 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713 dragged_sb = NULL;
1714 }
1715 }
1716 else
1717 {
1718 /* We are inside the contents */
1719
1720 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1721 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1722
1723 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1724 vimMouseButton = MOUSE_LEFT;
1725
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001727 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728 clickIsPopup = FALSE;
1729
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001730 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1731 {
1732 vimMouseButton = MOUSE_RIGHT;
1733 vimModifiers &= ~MOUSE_CTRL;
1734 clickIsPopup = TRUE;
1735 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736
1737 /* Is it a double click ? */
1738 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1739
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001740 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 gui_send_mouse_event(vimMouseButton, thePoint.h,
1742 thePoint.v, dblClick, vimModifiers);
1743
1744 /* Create the rectangle around the cursor to detect
1745 * the mouse dragging
1746 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747#if 0
1748 /* TODO: Do we need to this even for the contextual menu?
1749 * It may be require for popup_setpos, but for popup?
1750 */
1751 if (vimMouseButton == MOUSE_LEFT)
1752#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001754 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 FILL_Y(Y_2_ROW(thePoint.v)),
1756 FILL_X(X_2_COL(thePoint.h)+1),
1757 FILL_Y(Y_2_ROW(thePoint.v)+1));
1758
1759 dragRectEnbl = TRUE;
1760 dragRectControl = kCreateRect;
1761 }
1762 }
1763}
1764
1765/*
1766 * Handle the click in the titlebar (to move the window)
1767 */
1768 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001769gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770{
1771 Rect movingLimits;
1772 Rect *movingLimitsPtr = &movingLimits;
1773
1774 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001775 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001776 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777}
1778
1779/*
1780 * Handle the click in the grow box
1781 */
1782 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001783gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784{
1785
1786 long newSize;
1787 unsigned short newWidth;
1788 unsigned short newHeight;
1789 Rect resizeLimits;
1790 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 Rect NewContentRect;
1792
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001793 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794
Bram Moolenaar720c7102007-05-10 18:07:50 +00001795 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 /* TODO: Should this come from Vim? */
1797 resizeLimits.top = 100;
1798 resizeLimits.left = 100;
1799
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1801 newWidth = NewContentRect.right - NewContentRect.left;
1802 newHeight = NewContentRect.bottom - NewContentRect.top;
1803 gui_resize_shell(newWidth, newHeight);
1804 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001805 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806}
1807
1808/*
1809 * Handle the click in the zoom box
1810 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001812gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813{
1814 Rect r;
1815 Point p;
1816 short thePart;
1817
1818 /* ideal width is current */
1819 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1820 if (gui.which_scrollbars[SBAR_LEFT])
1821 p.h += gui.scrollbar_width;
1822 if (gui.which_scrollbars[SBAR_RIGHT])
1823 p.h += gui.scrollbar_width;
1824 /* ideal height is as heigh as we can get */
1825 p.v = 15 * 1024;
1826
1827 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1828 ? inZoomIn : inZoomOut;
1829
1830 if (!TrackBox(whichWindow, theEvent->where, thePart))
1831 return;
1832
1833 /* use returned width */
1834 p.h = r.right - r.left;
1835 /* adjust returned height */
1836 p.v = r.bottom - r.top - 2 * gui.border_offset;
1837 if (gui.which_scrollbars[SBAR_BOTTOM])
1838 p.v -= gui.scrollbar_height;
1839 p.v -= p.v % gui.char_height;
1840 p.v += 2 * gui.border_width;
1841 if (gui.which_scrollbars[SBAR_BOTTOM]);
1842 p.v += gui.scrollbar_height;
1843
1844 ZoomWindowIdeal(whichWindow, thePart, &p);
1845
1846 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1847 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1848 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001849 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851
1852/*
1853 * ------------------------------------------------------------
1854 * MacOS Event Handling procedure
1855 * ------------------------------------------------------------
1856 */
1857
1858/*
1859 * Handle the Update Event
1860 */
1861
1862 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001863gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864{
1865 WindowPtr whichWindow;
1866 GrafPtr savePort;
1867 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 Rect *updateRectPtr;
1870 Rect rc;
1871 Rect growRect;
1872 RgnHandle saveRgn;
1873
1874
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 updateRgn = NewRgn();
1876 if (updateRgn == NULL)
1877 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878
1879 /* This could be done by the caller as we
1880 * don't require anything else out of the event
1881 */
1882 whichWindow = (WindowPtr) event->message;
1883
1884 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001885 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001888 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889
1890 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001891 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 /* Redraw the biggest rectangle covering the area
1893 * to be updated.
1894 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1896# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001897 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 * seem to work under MacOS X (Dany)
1899 */
1900 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1901# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001902
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001904 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001905
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001906 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907# if 0
1908 /* Code from original Carbon Port (using GetWindowRegion.
1909 * I believe the UpdateRgn is already in local (Dany)
1910 */
1911 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1912 GlobalToLocal(&botRight(updateRect));
1913# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 /* Update the content (i.e. the text) */
1915 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1916 updateRectPtr->right - updateRectPtr->left,
1917 updateRectPtr->bottom - updateRectPtr->top);
1918 /* Clear the border areas if needed */
1919 gui_mch_set_bg_color(gui.back_pixel);
1920 if (updateRectPtr->left < FILL_X(0))
1921 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001922 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1923 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 }
1925 if (updateRectPtr->top < FILL_Y(0))
1926 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001927 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1928 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 }
1930 if (updateRectPtr->right > FILL_X(Columns))
1931 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001932 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001934 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 }
1936 if (updateRectPtr->bottom > FILL_Y(Rows))
1937 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001938 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001942 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
1945 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001946 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947
1948 /* Update the GrowBox */
1949 /* Taken from FAQ 33-27 */
1950 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001952 GetClip(saveRgn);
1953 ClipRect(&growRect);
1954 DrawGrowIcon(whichWindow);
1955 SetClip(saveRgn);
1956 DisposeRgn(saveRgn);
1957 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958
1959 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001960 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961}
1962
1963/*
1964 * Handle the activate/deactivate event
1965 * (apply to a window)
1966 */
1967 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001968gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969{
1970 WindowPtr whichWindow;
1971
1972 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001973 /* Dim scrollbars */
1974 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001976 ControlRef rootControl;
1977 GetRootControl(gui.VimWindow, &rootControl);
1978 if ((event->modifiers) & activeFlag)
1979 ActivateControl(rootControl);
1980 else
1981 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001983
1984 /* Activate */
1985 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986}
1987
1988
1989/*
1990 * Handle the suspend/resume event
1991 * (apply to the application)
1992 */
1993 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001994gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995{
1996 /* The frontmost application just changed */
1997
1998 /* NOTE: the suspend may happen before the deactivate
1999 * seen on MacOS X
2000 */
2001
2002 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002003 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 */
2005 if (event->message & 1)
2006 /* Resume */
2007 gui_focus_change(TRUE);
2008 else
2009 /* Suspend */
2010 gui_focus_change(FALSE);
2011}
2012
2013/*
2014 * Handle the key
2015 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002016#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002017 static pascal OSStatus
2018gui_mac_handle_window_activate(
2019 EventHandlerCallRef nextHandler,
2020 EventRef theEvent,
2021 void *data)
2022{
2023 UInt32 eventClass = GetEventClass(theEvent);
2024 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002025
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002026 if (eventClass == kEventClassWindow)
2027 {
2028 switch (eventKind)
2029 {
2030 case kEventWindowActivated:
2031#if defined(USE_IM_CONTROL)
2032 im_on_window_switch(TRUE);
2033#endif
2034 return noErr;
2035
2036 case kEventWindowDeactivated:
2037#if defined(USE_IM_CONTROL)
2038 im_on_window_switch(FALSE);
2039#endif
2040 return noErr;
2041 }
2042 }
2043
2044 return eventNotHandledErr;
2045}
2046
2047 static pascal OSStatus
2048gui_mac_handle_text_input(
2049 EventHandlerCallRef nextHandler,
2050 EventRef theEvent,
2051 void *data)
2052{
2053 UInt32 eventClass = GetEventClass(theEvent);
2054 UInt32 eventKind = GetEventKind(theEvent);
2055
2056 if (eventClass != kEventClassTextInput)
2057 return eventNotHandledErr;
2058
2059 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2060 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2061 (kEventTextInputOffsetToPos != eventKind) &&
2062 (kEventTextInputPosToOffset != eventKind) &&
2063 (kEventTextInputGetSelectedText != eventKind))
2064 return eventNotHandledErr;
2065
2066 switch (eventKind)
2067 {
2068 case kEventTextInputUpdateActiveInputArea:
2069 return gui_mac_update_input_area(nextHandler, theEvent);
2070 case kEventTextInputUnicodeForKeyEvent:
2071 return gui_mac_unicode_key_event(nextHandler, theEvent);
2072
2073 case kEventTextInputOffsetToPos:
2074 case kEventTextInputPosToOffset:
2075 case kEventTextInputGetSelectedText:
2076 break;
2077 }
2078
2079 return eventNotHandledErr;
2080}
2081
2082 static pascal
2083OSStatus gui_mac_update_input_area(
2084 EventHandlerCallRef nextHandler,
2085 EventRef theEvent)
2086{
2087 return eventNotHandledErr;
2088}
2089
2090static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2091 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002092
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002093# define INLINE_KEY_BUFFER_SIZE 80
2094 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002095gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002096 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002097 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002098{
2099 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002100 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002101 UInt32 actualSize;
2102 UniChar *text;
2103 char_u result[INLINE_KEY_BUFFER_SIZE];
2104 short len = 0;
2105 UInt32 key_sym;
2106 char charcode;
2107 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002108 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002109 size_t encLen;
2110 char_u *to = NULL;
2111 Boolean isSpecial = FALSE;
2112 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002113 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002115 /* Mask the mouse (as per user setting) */
2116 if (p_mh)
2117 ObscureCursor();
2118
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002119 /* Don't use the keys when the dialog wants them. */
2120 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002122
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002123 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002124 typeUnicodeText, NULL, 0, &actualSize, NULL))
2125 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002126
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002127 text = (UniChar *)alloc(actualSize);
2128 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002130
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002131 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002132 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002134
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002135 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002136 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002137 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002138
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002139 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002140 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002141 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002142
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002144 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002146
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002147 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002148 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 require_noerr(err, done);
2150
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002152 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002153 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002154#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002156 key_char = charcode;
2157 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002158
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002159 /* Find the special key (eg., for cursor keys) */
2160 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002161 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002162 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002163 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2164 if (special_keys[i].key_sym == key_sym)
2165 {
2166 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2167 special_keys[i].vim_code1);
2168 key_char = simplify_key(key_char,
2169 (int *)&vimModifiers);
2170 isSpecial = TRUE;
2171 break;
2172 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002173 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002174
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002175 /* Intercept CMD-. and CTRL-c */
2176 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002177 ((modifiers & cmdKey) && key_char == '.'))
2178 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002179
2180 if (!isSpecial)
2181 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002182 /* remove SHIFT for keys that are already shifted, e.g.,
2183 * '(' and '*' */
2184 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2185 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002186
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002187 /* remove CTRL from keys that already have it */
2188 if (key_char < 0x20)
2189 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002190
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002191 /* don't process unicode characters here */
2192 if (!IS_SPECIAL(key_char))
2193 {
2194 /* Following code to simplify and consolidate vimModifiers
2195 * taken liberally from gui_w48.c */
2196 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002197
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002198 /* Interpret META, include SHIFT, etc. */
2199 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2200 if (key_char == CSI)
2201 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002202
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002203 if (IS_SPECIAL(key_char))
2204 isSpecial = TRUE;
2205 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002206 }
2207
2208 if (vimModifiers)
2209 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002210 result[len++] = CSI;
2211 result[len++] = KS_MODIFIER;
2212 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002213 }
2214
2215 if (isSpecial && IS_SPECIAL(key_char))
2216 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002217 result[len++] = CSI;
2218 result[len++] = K_SECOND(key_char);
2219 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002220 }
2221 else
2222 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002223 encLen = actualSize;
2224 to = mac_utf16_to_enc(text, actualSize, &encLen);
2225 if (to)
2226 {
2227 /* This is basically add_to_input_buf_csi() */
2228 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2229 {
2230 result[len++] = to[i];
2231 if (to[i] == CSI)
2232 {
2233 result[len++] = KS_EXTRA;
2234 result[len++] = (int)KE_CSI;
2235 }
2236 }
2237 vim_free(to);
2238 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002239 }
2240
2241 add_to_input_buf(result, len);
2242 err = noErr;
2243
2244done:
2245 vim_free(text);
2246 if (err == noErr)
2247 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002248 /* Fake event to wake up WNE (required to get
2249 * key repeat working */
2250 PostEvent(keyUp, 0);
2251 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002252 }
2253
2254 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002255}
2256#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 void
2258gui_mac_doKeyEvent(EventRecord *theEvent)
2259{
2260 /* TODO: add support for COMMAND KEY */
2261 long menu;
2262 unsigned char string[20];
2263 short num, i;
2264 short len = 0;
2265 KeySym key_sym;
2266 int key_char;
2267 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002268 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269
2270 /* Mask the mouse (as per user setting) */
2271 if (p_mh)
2272 ObscureCursor();
2273
2274 /* Get the key code and it's ASCII representation */
2275 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2276 key_char = theEvent->message & charCodeMask;
2277 num = 1;
2278
2279 /* Intercept CTRL-C */
2280 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002281 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 if (key_char == Ctrl_C && ctrl_c_interrupts)
2283 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002284 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2285 && (key_char == '2' || key_char == '6'))
2286 {
2287 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2288 if (key_char == '2')
2289 key_char = Ctrl_AT;
2290 else
2291 key_char = Ctrl_HAT;
2292 theEvent->modifiers = 0;
2293 }
2294 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295
2296 /* Intercept CMD-. */
2297 if (theEvent->modifiers & cmdKey)
2298 if (key_char == '.')
2299 got_int = TRUE;
2300
2301 /* Handle command key as per menu */
2302 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2303 if (theEvent->modifiers & cmdKey)
2304 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2305 * Why the mouse button? */
2306 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2307 {
2308 menu = MenuKey(key_char);
2309 if (HiWord(menu))
2310 {
2311 gui_mac_handle_menu(menu);
2312 return;
2313 }
2314 }
2315
2316 /* Convert the modifiers */
2317 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2318
2319
2320 /* Handle special keys. */
2321#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002322 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2324#endif
2325 {
2326 /* Find the special key (for non-printable keyt_char) */
2327 if ((key_char < 0x20) || (key_char == 0x7f))
2328 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2329 if (special_keys[i].key_sym == key_sym)
2330 {
2331# if 0
2332 /* We currently don't have not so special key */
2333 if (special_keys[i].vim_code1 == NUL)
2334 key_char = special_keys[i].vim_code0;
2335 else
2336# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002337 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2338 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002339 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 break;
2341 }
2342 }
2343
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002344 /* For some keys the modifier is included in the char itself. */
2345 if (simplify || key_char == TAB || key_char == ' ')
2346 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347
2348 /* Add the modifier to the input bu if needed */
2349 /* Do not want SHIFT-A or CTRL-A with modifier */
2350 if (!IS_SPECIAL(key_char)
2351 && key_sym != vk_Space
2352 && key_sym != vk_Tab
2353 && key_sym != vk_Return
2354 && key_sym != vk_Enter
2355 && key_sym != vk_Esc)
2356 {
2357#if 1
2358 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002359 if ((modifiers == MOD_MASK_SHIFT)
2360 || (modifiers == MOD_MASK_CTRL)
2361 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 modifiers = 0;
2363#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002364 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002366 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002368 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 modifiers = modifiers & ~MOD_MASK_SHIFT;
2370#endif
2371 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002374 string[len++] = CSI;
2375 string[len++] = KS_MODIFIER;
2376 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 }
2378
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002379 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002381 string[len++] = CSI;
2382 string[len++] = K_SECOND(key_char);
2383 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 }
2385 else
2386 {
2387#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002388 /* Convert characters when needed (e.g., from MacRoman to latin1).
2389 * This doesn't work for the NUL byte. */
2390 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 {
2392 char_u from[2], *to;
2393 int l;
2394
2395 from[0] = key_char;
2396 from[1] = NUL;
2397 l = 1;
2398 to = string_convert(&input_conv, from, &l);
2399 if (to != NULL)
2400 {
2401 for (i = 0; i < l && len < 19; i++)
2402 {
2403 if (to[i] == CSI)
2404 {
2405 string[len++] = KS_EXTRA;
2406 string[len++] = KE_CSI;
2407 }
2408 else
2409 string[len++] = to[i];
2410 }
2411 vim_free(to);
2412 }
2413 else
2414 string[len++] = key_char;
2415 }
2416 else
2417#endif
2418 string[len++] = key_char;
2419 }
2420
2421 if (len == 1 && string[0] == CSI)
2422 {
2423 /* Turn CSI into K_CSI. */
2424 string[ len++ ] = KS_EXTRA;
2425 string[ len++ ] = KE_CSI;
2426 }
2427
2428 add_to_input_buf(string, len);
2429}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002430#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431
2432/*
2433 * Handle MouseClick
2434 */
2435 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002436gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437{
2438 short thePart;
2439 WindowPtr whichWindow;
2440
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002441 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002443#ifdef FEAT_GUI_TABLINE
2444 /* prevent that the vim window size changes if it's activated by a
2445 click into the tab pane */
2446 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002447 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002448#endif
2449
Bram Moolenaar071d4272004-06-13 20:20:40 +00002450 switch (thePart)
2451 {
2452 case (inDesk):
2453 /* TODO: what to do? */
2454 break;
2455
2456 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002457 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002458 break;
2459
2460 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002461 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 break;
2463
2464 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002465 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 break;
2467
2468 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002469 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 break;
2471
2472 case (inGoAway):
2473 if (TrackGoAway(whichWindow, theEvent->where))
2474 gui_shell_closed();
2475 break;
2476
2477 case (inZoomIn):
2478 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 break;
2481 }
2482}
2483
2484/*
2485 * Handle MouseMoved
2486 * [this event is a moving in and out of a region]
2487 */
2488 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002489gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490{
2491 Point thePoint;
2492 int_u vimModifiers;
2493
2494 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002495 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2497
2498 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002499 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2503 thePoint.v, FALSE, vimModifiers);
2504
2505 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002506 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 FILL_Y(Y_2_ROW(thePoint.v)),
2508 FILL_X(X_2_COL(thePoint.h)+1),
2509 FILL_Y(Y_2_ROW(thePoint.v)+1));
2510
2511 if (dragRectEnbl)
2512 dragRectControl = kCreateRect;
2513
2514}
2515
2516/*
2517 * Handle the mouse release
2518 */
2519 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002520gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002521{
2522 Point thePoint;
2523 int_u vimModifiers;
2524
2525 /* TODO: Properly convert the Contextual menu mouse-up */
2526 /* Potential source of the double menu */
2527 lastMouseTick = theEvent->when;
2528 dragRectEnbl = FALSE;
2529 dragRectControl = kCreateEmpty;
2530 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002531 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532
2533 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 if (clickIsPopup)
2535 {
2536 vimModifiers &= ~MOUSE_CTRL;
2537 clickIsPopup = FALSE;
2538 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002539 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540}
2541
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 static pascal OSStatus
2543gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2544 void *data)
2545{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 Point point;
2547 Rect bounds;
2548 UInt32 mod;
2549 SInt32 delta;
2550 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002551 EventMouseWheelAxis axis;
2552
2553 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2554 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2555 && axis != kEventMouseWheelAxisY)
2556 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557
2558 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2559 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2560 goto bail;
2561 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2562 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2563 goto bail;
2564 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2565 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2566 goto bail;
2567
2568 vim_mod = 0;
2569 if (mod & shiftKey)
2570 vim_mod |= MOUSE_SHIFT;
2571 if (mod & controlKey)
2572 vim_mod |= MOUSE_CTRL;
2573 if (mod & optionKey)
2574 vim_mod |= MOUSE_ALT;
2575
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2577 {
2578 point.h -= bounds.left;
2579 point.v -= bounds.top;
2580 }
2581
2582 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2583 point.h, point.v, FALSE, vim_mod);
2584
Bram Moolenaarc236c162008-07-13 17:41:49 +00002585 /* post a bogus event to wake up WaitNextEvent */
2586 PostEvent(keyUp, 0);
2587
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 return noErr;
2589
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002590bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 /*
2592 * when we fail give any additional callback handler a chance to perform
2593 * it's actions
2594 */
2595 return CallNextEventHandler(nextHandler, theEvent);
2596}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597
2598#if 0
2599
2600/*
2601 * This would be the normal way of invoking the contextual menu
2602 * but the Vim API doesn't seem to a support a request to get
2603 * the menu that we should display
2604 */
2605 void
2606gui_mac_handle_contextual_menu(event)
2607 EventRecord *event;
2608{
2609/*
2610 * Clone PopUp to use menu
2611 * Create a object descriptor for the current selection
2612 * Call the procedure
2613 */
2614
2615// Call to Handle Popup
2616 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2617
2618 if (status != noErr)
2619 return;
2620
2621 if (CntxType == kCMMenuItemSelected)
2622 {
2623 /* Handle the menu CntxMenuID, CntxMenuItem */
2624 /* The submenu can be handle directly by gui_mac_handle_menu */
2625 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002626 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627 }
2628 else if (CntxMenuID == kCMShowHelpSelected)
2629 {
2630 /* Should come up with the help */
2631 }
2632
2633}
2634#endif
2635
2636/*
2637 * Handle menubar selection
2638 */
2639 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002640gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641{
2642 short menu = HiWord(menuChoice);
2643 short item = LoWord(menuChoice);
2644 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645
2646 if (menu == 256) /* TODO: use constant or gui.xyz */
2647 {
2648 if (item == 1)
2649 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 }
2651 else if (item != 0)
2652 {
2653 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2654
2655 if (theVimMenu)
2656 gui_menu_cb(theVimMenu);
2657 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002658 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659}
2660
2661/*
2662 * Dispatch the event to proper handler
2663 */
2664
2665 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002666gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667{
2668 OSErr error;
2669
2670 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002671 if (IsShowContextualMenuClick(event))
2672 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002674 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002676 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002678 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002679 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680
2681 /* Handle normal event */
2682 switch (event->what)
2683 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002684#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 case (keyDown):
2686 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002687 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002689#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002691 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 break;
2693
2694 case (mouseDown):
2695 gui_mac_doMouseDownEvent(event);
2696 break;
2697
2698 case (mouseUp):
2699 gui_mac_doMouseUpEvent(event);
2700 break;
2701
2702 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002703 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 break;
2705
2706 case (diskEvt):
2707 /* We don't need special handling for disk insertion */
2708 break;
2709
2710 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002711 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 break;
2713
2714 case (osEvt):
2715 switch ((event->message >> 24) & 0xFF)
2716 {
2717 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002718 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719 break;
2720 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002721 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 break;
2723 }
2724 break;
2725
2726#ifdef USE_AEVENT
2727 case (kHighLevelEvent):
2728 /* Someone's talking to us, through AppleEvents */
2729 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2730 break;
2731#endif
2732 }
2733}
2734
2735/*
2736 * ------------------------------------------------------------
2737 * Unknown Stuff
2738 * ------------------------------------------------------------
2739 */
2740
2741
2742 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002743gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744{
2745 char_u c;
2746 char_u *p;
2747 char_u pFontName[256];
2748 Str255 systemFontname;
2749 short font_id;
2750 short size=9;
2751 GuiFont font;
2752#if 0
2753 char_u *fontNamePtr;
2754#endif
2755
2756 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2757 ;
2758
2759 c = *p;
2760 *p = 0;
2761
2762#if 1
2763 STRCPY(&pFontName[1], font_name);
2764 pFontName[0] = STRLEN(font_name);
2765 *p = c;
2766
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002767 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002768 char_u fontName[256];
2769 char_u *styleStart = vim_strchr(font_name, ':');
2770 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2771 vim_strncpy(fontName, font_name, fontNameLen);
2772
2773 ATSUFontID fontRef;
2774 FMFontStyle fontStyle;
2775 font_id = 0;
2776
2777 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2778 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2779 &fontRef) == noErr)
2780 {
2781 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2782 font_id = 0;
2783 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002784
2785 if (font_id == 0)
2786 {
2787 /*
2788 * Try again, this time replacing underscores in the font name
2789 * with spaces (:set guifont allows the two to be used
2790 * interchangeably; the Font Manager doesn't).
2791 */
2792 int i, changed = FALSE;
2793
2794 for (i = pFontName[0]; i > 0; --i)
2795 {
2796 if (pFontName[i] == '_')
2797 {
2798 pFontName[i] = ' ';
2799 changed = TRUE;
2800 }
2801 }
2802 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002803 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2804 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2805 kFontNoLanguageCode, &fontRef) == noErr)
2806 {
2807 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2808 font_id = 0;
2809 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002810 }
2811
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812#else
2813 /* name = C2Pascal_save(menu->dname); */
2814 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2815
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002816 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817#endif
2818
2819
2820 if (font_id == 0)
2821 {
2822 /* Oups, the system font was it the one the user want */
2823
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002824 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2825 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 if (!EqualString(pFontName, systemFontname, false, false))
2827 return NOFONT;
2828 }
2829 if (*p == ':')
2830 {
2831 p++;
2832 /* Set the values found after ':' */
2833 while (*p)
2834 {
2835 switch (*p++)
2836 {
2837 case 'h':
2838 size = points_to_pixels(p, &p, TRUE);
2839 break;
2840 /*
2841 * TODO: Maybe accept width and styles
2842 */
2843 }
2844 while (*p == ':')
2845 p++;
2846 }
2847 }
2848
2849 if (size < 1)
2850 size = 1; /* Avoid having a size of 0 with system font */
2851
2852 font = (size << 16) + ((long) font_id & 0xFFFF);
2853
2854 return font;
2855}
2856
2857/*
2858 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002859 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 * ------------------------------------------------------------
2861 */
2862
2863/*
2864 * Parse the GUI related command-line arguments. Any arguments used are
2865 * deleted from argv, and *argc is decremented accordingly. This is called
2866 * when vim is started, whether or not the GUI has been started.
2867 */
2868 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002869gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870{
2871 /* TODO: Move most of this stuff toward gui_mch_init */
2872#ifdef USE_EXE_NAME
2873 FSSpec applDir;
2874# ifndef USE_FIND_BUNDLE_PATH
2875 short applVRefNum;
2876 long applDirID;
2877 Str255 volName;
2878# else
2879 ProcessSerialNumber psn;
2880 FSRef applFSRef;
2881# endif
2882#endif
2883
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884#if 0
2885 InitCursor();
2886
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888
2889#ifdef USE_AEVENT
2890 (void) InstallAEHandlers();
2891#endif
2892
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002893 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002895 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002897 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
2899 DrawMenuBar();
2900
2901
2902#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002903 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906#endif
2907
2908
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909 CreateNewWindow(kDocumentWindowClass,
2910 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002911 &windRect, &gui.VimWindow);
2912 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913
2914 gui.char_width = 7;
2915 gui.char_height = 11;
2916 gui.char_ascent = 6;
2917 gui.num_rows = 24;
2918 gui.num_cols = 80;
2919 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2920
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002921 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2922 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923
2924 dragRectEnbl = FALSE;
2925 dragRgn = NULL;
2926 dragRectControl = kCreateEmpty;
2927 cursorRgn = NewRgn();
2928#endif
2929#ifdef USE_EXE_NAME
2930# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002931 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002933 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934# else
2935 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2936 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002938 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 /* if (err != noErr) return err; */
2940
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002941 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 /* if (err != noErr) return err; */
2943
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002944 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945
2946 /* This technic return NIL when we disallow_gui */
2947# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002948 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950}
2951
2952#ifndef ALWAYS_USE_GUI
2953/*
2954 * Check if the GUI can be started. Called before gvimrc is sourced.
2955 * Return OK or FAIL.
2956 */
2957 int
2958gui_mch_init_check(void)
2959{
2960 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2961 * using the >console
2962 */
2963 if (disallow_gui) /* see main.c for reason to disallow */
2964 return FAIL;
2965 return OK;
2966}
2967#endif
2968
2969 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002970receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971{
2972 int x, y;
2973 int_u modifiers;
2974 char_u **fnames = NULL;
2975 int count;
2976 int i, j;
2977
2978 /* Get drop position, modifiers and count of items */
2979 {
2980 Point point;
2981 SInt16 mouseUpModifiers;
2982 UInt16 countItem;
2983
2984 GetDragMouse(theDrag, &point, NULL);
2985 GlobalToLocal(&point);
2986 x = point.h;
2987 y = point.v;
2988 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2989 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2990 CountDragItems(theDrag, &countItem);
2991 count = countItem;
2992 }
2993
2994 fnames = (char_u **)alloc(count * sizeof(char_u *));
2995 if (fnames == NULL)
2996 return dragNotAcceptedErr;
2997
2998 /* Get file names dropped */
2999 for (i = j = 0; i < count; ++i)
3000 {
3001 DragItemRef item;
3002 OSErr err;
3003 Size size;
3004 FlavorType type = flavorTypeHFS;
3005 HFSFlavor hfsFlavor;
3006
3007 fnames[i] = NULL;
3008 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3009 err = GetFlavorDataSize(theDrag, item, type, &size);
3010 if (err != noErr || size > sizeof(hfsFlavor))
3011 continue;
3012 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3013 if (err != noErr)
3014 continue;
3015 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3016 }
3017 count = j;
3018
3019 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003020
3021 /* Fake mouse event to wake from stall */
3022 PostEvent(mouseUp, 0);
3023
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024 return noErr;
3025}
3026
3027/*
3028 * Initialise the GUI. Create all the windows, set up all the call-backs
3029 * etc.
3030 */
3031 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003032gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033{
3034 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003035 Rect windRect;
3036 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003038 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003039 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003040
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003041 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003042 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003043
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044#if 1
3045 InitCursor();
3046
Bram Moolenaar071d4272004-06-13 20:20:40 +00003047 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048
3049#ifdef USE_AEVENT
3050 (void) InstallAEHandlers();
3051#endif
3052
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003053 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003055 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003057 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058
3059 DrawMenuBar();
3060
3061
3062#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003063 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066#endif
3067
3068 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003071 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3073 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003074 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075
3076 gui.char_width = 7;
3077 gui.char_height = 11;
3078 gui.char_ascent = 6;
3079 gui.num_rows = 24;
3080 gui.num_cols = 80;
3081 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3082
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003083 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3084 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003086 /* Install Carbon event callbacks. */
3087 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088
3089 dragRectEnbl = FALSE;
3090 dragRgn = NULL;
3091 dragRectControl = kCreateEmpty;
3092 cursorRgn = NewRgn();
3093#endif
3094 /* Display any pending error messages */
3095 display_errors();
3096
3097 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003098 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 gui.norm_pixel = 0x00000000;
3100 gui.back_pixel = 0x00FFFFFF;
3101
3102 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3103 * file). */
3104 set_normal_colors();
3105
3106 /*
3107 * Check that none of the colors are the same as the background color.
3108 * Then store the current values as the defaults.
3109 */
3110 gui_check_colors();
3111 gui.def_norm_pixel = gui.norm_pixel;
3112 gui.def_back_pixel = gui.back_pixel;
3113
3114 /* Get the colors for the highlight groups (gui_check_colors() might have
3115 * changed them) */
3116 highlight_gui_started();
3117
3118 /*
3119 * Setting the gui constants
3120 */
3121#ifdef FEAT_MENU
3122 gui.menu_height = 0;
3123#endif
3124 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3125 gui.border_offset = gui.border_width = 2;
3126
Bram Moolenaar720c7102007-05-10 18:07:50 +00003127 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 gui_mch_draw_string() below), enable it for all font sizes. */
3129 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 eventTypeSpec.eventClass = kEventClassMouse;
3132 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3133 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3134 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3135 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3136 {
3137 mouseWheelHandlerRef = NULL;
3138 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3139 mouseWheelHandlerUPP = NULL;
3140 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003142#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003143 InterfaceTypeList supportedServices = { kUnicodeDocument };
3144 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3145
3146 /* We don't support inline input yet, use input window by default */
3147 UseInputWindow(gTSMDocument, TRUE);
3148
3149 /* Should we activate the document by default? */
3150 // ActivateTSMDocument(gTSMDocument);
3151
3152 EventTypeSpec textEventTypes[] = {
3153 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3154 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3155 { kEventClassTextInput, kEventTextInputPosToOffset },
3156 { kEventClassTextInput, kEventTextInputOffsetToPos },
3157 };
3158
3159 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3160 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3161 NR_ELEMS(textEventTypes),
3162 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003163 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003164 DisposeEventHandlerUPP(keyEventHandlerUPP);
3165 keyEventHandlerUPP = NULL;
3166 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003167
3168 EventTypeSpec windowEventTypes[] = {
3169 { kEventClassWindow, kEventWindowActivated },
3170 { kEventClassWindow, kEventWindowDeactivated },
3171 };
3172
3173 /* Install window event handler to support TSMDocument activate and
3174 * deactivate */
3175 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3176 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3177 winEventHandlerUPP,
3178 NR_ELEMS(windowEventTypes),
3179 windowEventTypes, NULL, NULL))
3180 {
3181 DisposeEventHandlerUPP(winEventHandlerUPP);
3182 winEventHandlerUPP = NULL;
3183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184#endif
3185
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003186/*
3187#ifdef FEAT_MBYTE
3188 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3189#endif
3190*/
3191
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003192#ifdef FEAT_GUI_TABLINE
3193 /*
3194 * Create the tabline
3195 */
3196 initialise_tabline();
3197#endif
3198
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 /* TODO: Load bitmap if using TOOLBAR */
3200 return OK;
3201}
3202
3203/*
3204 * Called when the foreground or background color has been changed.
3205 */
3206 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003207gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208{
3209 /* TODO:
3210 * This proc is called when Normal is set to a value
3211 * so what msut be done? I don't know
3212 */
3213}
3214
3215/*
3216 * Open the GUI window which was created by a call to gui_mch_init().
3217 */
3218 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003219gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220{
3221 ShowWindow(gui.VimWindow);
3222
3223 if (gui_win_x != -1 && gui_win_y != -1)
3224 gui_mch_set_winpos(gui_win_x, gui_win_y);
3225
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 /*
3227 * Make the GUI the foreground process (in case it was launched
3228 * from the Terminal or via :gui).
3229 */
3230 {
3231 ProcessSerialNumber psn;
3232 if (GetCurrentProcess(&psn) == noErr)
3233 SetFrontProcess(&psn);
3234 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235
3236 return OK;
3237}
3238
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003239#ifdef USE_ATSUI_DRAWING
3240 static void
3241gui_mac_dispose_atsui_style(void)
3242{
3243 if (p_macatsui && gFontStyle)
3244 ATSUDisposeStyle(gFontStyle);
3245#ifdef FEAT_MBYTE
3246 if (p_macatsui && gWideFontStyle)
3247 ATSUDisposeStyle(gWideFontStyle);
3248#endif
3249}
3250#endif
3251
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252 void
3253gui_mch_exit(int rc)
3254{
3255 /* TODO: find out all what is missing here? */
3256 DisposeRgn(cursorRgn);
3257
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003258#ifdef USE_CARBONKEYHANDLER
3259 if (keyEventHandlerUPP)
3260 DisposeEventHandlerUPP(keyEventHandlerUPP);
3261#endif
3262
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 if (mouseWheelHandlerUPP != NULL)
3264 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003266#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003267 gui_mac_dispose_atsui_style();
3268#endif
3269
3270#ifdef USE_CARBONKEYHANDLER
3271 FixTSMDocument(gTSMDocument);
3272 DeactivateTSMDocument(gTSMDocument);
3273 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003274#endif
3275
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276 /* Exit to shell? */
3277 exit(rc);
3278}
3279
3280/*
3281 * Get the position of the top left corner of the window.
3282 */
3283 int
3284gui_mch_get_winpos(int *x, int *y)
3285{
3286 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 Rect bounds;
3288 OSStatus status;
3289
3290 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003291 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292
3293 if (status != noErr)
3294 return FAIL;
3295 *x = bounds.left;
3296 *y = bounds.top;
3297 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 return FAIL;
3299}
3300
3301/*
3302 * Set the position of the top left corner of the window to the given
3303 * coordinates.
3304 */
3305 void
3306gui_mch_set_winpos(int x, int y)
3307{
3308 /* TODO: Should make sure the window is move within range
3309 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3310 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003311 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003312}
3313
3314 void
3315gui_mch_set_shellsize(
3316 int width,
3317 int height,
3318 int min_width,
3319 int min_height,
3320 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003321 int base_height,
3322 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 CGrafPtr VimPort;
3325 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326
3327 if (gui.which_scrollbars[SBAR_LEFT])
3328 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003329 VimPort = GetWindowPort(gui.VimWindow);
3330 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003332 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 }
3335 else
3336 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003337 VimPort = GetWindowPort(gui.VimWindow);
3338 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 }
3342
3343 SizeWindow(gui.VimWindow, width, height, TRUE);
3344
3345 gui_resize_shell(width, height);
3346}
3347
3348/*
3349 * Get the screen dimensions.
3350 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3351 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003352 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353 */
3354 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003355gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356{
3357 GDHandle dominantDevice = GetMainDevice();
3358 Rect screenRect = (**dominantDevice).gdRect;
3359
3360 *screen_w = screenRect.right - 10;
3361 *screen_h = screenRect.bottom - 40;
3362}
3363
3364
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003365/*
3366 * Open the Font Panel and wait for the user to select a font and
3367 * close the panel. Then fill the buffer pointed to by font_name with
3368 * the name and size of the selected font and return the font's handle,
3369 * or NOFONT in case of an error.
3370 */
3371 static GuiFont
3372gui_mac_select_font(char_u *font_name)
3373{
3374 GuiFont selected_font = NOFONT;
3375 OSStatus status;
3376 FontSelectionQDStyle curr_font;
3377
3378 /* Initialize the Font Panel with the current font. */
3379 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3380 curr_font.size = (gui.norm_font >> 16);
3381 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3382 curr_font.instance.fontStyle = 0;
3383 curr_font.hasColor = false;
3384 curr_font.version = 0; /* version number of the style structure */
3385 status = SetFontInfoForSelection(kFontSelectionQDType,
3386 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3387
3388 gFontPanelInfo.family = curr_font.instance.fontFamily;
3389 gFontPanelInfo.style = curr_font.instance.fontStyle;
3390 gFontPanelInfo.size = curr_font.size;
3391
3392 /* Pop up the Font Panel. */
3393 status = FPShowHideFontPanel();
3394 if (status == noErr)
3395 {
3396 /*
3397 * The Font Panel is modeless. We really need it to be modal,
3398 * so we spin in an event loop until the panel is closed.
3399 */
3400 gFontPanelInfo.isPanelVisible = true;
3401 while (gFontPanelInfo.isPanelVisible)
3402 {
3403 EventRecord e;
3404 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3405 }
3406
3407 GetFontPanelSelection(font_name);
3408 selected_font = gui_mac_find_font(font_name);
3409 }
3410 return selected_font;
3411}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003412
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003413#ifdef USE_ATSUI_DRAWING
3414 static void
3415gui_mac_create_atsui_style(void)
3416{
3417 if (p_macatsui && gFontStyle == NULL)
3418 {
3419 if (ATSUCreateStyle(&gFontStyle) != noErr)
3420 gFontStyle = NULL;
3421 }
3422#ifdef FEAT_MBYTE
3423 if (p_macatsui && gWideFontStyle == NULL)
3424 {
3425 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3426 gWideFontStyle = NULL;
3427 }
3428#endif
3429
3430 p_macatsui_last = p_macatsui;
3431}
3432#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433
3434/*
3435 * Initialise vim to use the font with the given name. Return FAIL if the font
3436 * could not be loaded, OK otherwise.
3437 */
3438 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003439gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440{
3441 /* TODO: Add support for bold italic underline proportional etc... */
3442 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003443 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444 FontInfo font_info;
3445 short font_id;
3446 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003447 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003449#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003450 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003451#endif
3452
Bram Moolenaar071d4272004-06-13 20:20:40 +00003453 if (font_name == NULL)
3454 {
3455 /* First try to get the suggested font */
3456 GetFNum(suggestedFont, &font_id);
3457
3458 if (font_id == 0)
3459 {
3460 /* Then pickup the standard application font */
3461 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003462 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003464 else
3465 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3467 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003468 else if (STRCMP(font_name, "*") == 0)
3469 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003470 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003471
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003473 if (font == NOFONT)
3474 return FAIL;
3475
3476 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003477 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003478 if (new_p_guifont != NULL)
3479 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003481 vim_free(p_guifont);
3482 p_guifont = new_p_guifont;
3483 /* Replace spaces in the font name with underscores. */
3484 for ( ; *new_p_guifont; ++new_p_guifont)
3485 {
3486 if (*new_p_guifont == ' ')
3487 *new_p_guifont = '_';
3488 }
3489 }
3490 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491 else
3492 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003493 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003494 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495
3496 if (font == NOFONT)
3497 return FAIL;
3498 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003499
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 gui.norm_font = font;
3501
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003502 hl_set_font_name(used_font_name);
3503
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003504 TextSize(font >> 16);
3505 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003506
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003507 GetFontInfo(&font_info);
3508
3509 gui.char_ascent = font_info.ascent;
3510 gui.char_width = CharWidth('_');
3511 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3512
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003513#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003514 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003515 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003516#endif
3517
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519}
3520
Bram Moolenaar02743632005-07-25 20:42:36 +00003521/*
3522 * Adjust gui.char_height (after 'linespace' was changed).
3523 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003525gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526{
3527 FontInfo font_info;
3528
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003529 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3531 gui.char_ascent = font_info.ascent + p_linespace / 2;
3532 return OK;
3533}
3534
3535/*
3536 * Get a font structure for highlighting.
3537 */
3538 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003539gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540{
3541 GuiFont font;
3542
3543 font = gui_mac_find_font(name);
3544
3545 if (font == NOFONT)
3546 {
3547 if (giveErrorIfMissing)
3548 EMSG2(_(e_font), name);
3549 return NOFONT;
3550 }
3551 /*
3552 * TODO : Accept only monospace
3553 */
3554
3555 return font;
3556}
3557
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003558#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003560 * Return the name of font "font" in allocated memory.
3561 * Don't know how to get the actual name, thus use the provided name.
3562 */
3563 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003564gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003565{
3566 if (name == NULL)
3567 return NULL;
3568 return vim_strsave(name);
3569}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003570#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003571
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003572#ifdef USE_ATSUI_DRAWING
3573 static void
3574gui_mac_set_font_attributes(GuiFont font)
3575{
3576 ATSUFontID fontID;
3577 Fixed fontSize;
3578 Fixed fontWidth;
3579
3580 fontID = font & 0xFFFF;
3581 fontSize = Long2Fix(font >> 16);
3582 fontWidth = Long2Fix(gui.char_width);
3583
3584 ATSUAttributeTag attribTags[] =
3585 {
3586 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3587 kATSUMaxATSUITagValue + 1
3588 };
3589
3590 ByteCount attribSizes[] =
3591 {
3592 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3593 sizeof(font)
3594 };
3595
3596 ATSUAttributeValuePtr attribValues[] =
3597 {
3598 &fontID, &fontSize, &fontWidth, &font
3599 };
3600
3601 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3602 {
3603 if (ATSUSetAttributes(gFontStyle,
3604 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3605 attribTags, attribSizes, attribValues) != noErr)
3606 {
3607# ifndef NDEBUG
3608 fprintf(stderr, "couldn't set font style\n");
3609# endif
3610 ATSUDisposeStyle(gFontStyle);
3611 gFontStyle = NULL;
3612 }
3613
3614#ifdef FEAT_MBYTE
3615 if (has_mbyte)
3616 {
3617 /* FIXME: we should use a more mbyte sensitive way to support
3618 * wide font drawing */
3619 fontWidth = Long2Fix(gui.char_width * 2);
3620
3621 if (ATSUSetAttributes(gWideFontStyle,
3622 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3623 attribTags, attribSizes, attribValues) != noErr)
3624 {
3625 ATSUDisposeStyle(gWideFontStyle);
3626 gWideFontStyle = NULL;
3627 }
3628 }
3629#endif
3630 }
3631}
3632#endif
3633
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003634/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 * Set the current text font.
3636 */
3637 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003638gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003640#ifdef USE_ATSUI_DRAWING
3641 GuiFont currFont;
3642 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003643
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003644 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003645 {
3646 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003647 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3648 sizeof(font), &currFont, &actualFontByteCount) == noErr
3649 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003650 {
3651 if (currFont == font)
3652 return;
3653 }
3654
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003655 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003656 }
3657
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003658 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003659 {
3660 /* Setup automatic font substitution. The user's guifontwide
3661 * is tried first, then the system tries other fonts. */
3662/*
3663 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3664 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3665 ATSUCreateFontFallbacks(&gFontFallbacks);
3666 ATSUSetObjFontFallbacks(gFontFallbacks, );
3667*/
3668 if (gui.wide_font)
3669 {
3670 ATSUFontID fallbackFonts;
3671 gIsFontFallbackSet = TRUE;
3672
3673 if (FMGetFontFromFontFamilyInstance(
3674 (gui.wide_font & 0xFFFF),
3675 0,
3676 &fallbackFonts,
3677 NULL) == noErr)
3678 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003679 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3680 &fallbackFonts,
3681 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003682 }
3683/*
3684 ATSUAttributeValuePtr fallbackValues[] = { };
3685*/
3686 }
3687 }
3688#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 TextSize(font >> 16);
3690 TextFont(font & 0xFFFF);
3691}
3692
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693/*
3694 * If a font is not going to be used, free its structure.
3695 */
3696 void
3697gui_mch_free_font(font)
3698 GuiFont font;
3699{
3700 /*
3701 * Free font when "font" is not 0.
3702 * Nothing to do in the current implementation, since
3703 * nothing is allocated for each font used.
3704 */
3705}
3706
3707 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003708hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709{
3710 if (isdigit(c))
3711 return c - '0';
3712 c = TOLOWER_ASC(c);
3713 if (c >= 'a' && c <= 'f')
3714 return c - 'a' + 10;
3715 return -1000;
3716}
3717
3718/*
3719 * Return the Pixel value (color) for the given color name. This routine was
3720 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3721 * Programmer's Guide.
3722 * Return INVALCOLOR when failed.
3723 */
3724 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003725gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726{
3727 /* TODO: Add support for the new named color of MacOS 8
3728 */
3729 RGBColor MacColor;
3730// guicolor_T color = 0;
3731
3732 typedef struct guicolor_tTable
3733 {
3734 char *name;
3735 guicolor_T color;
3736 } guicolor_tTable;
3737
3738 /*
3739 * The comment at the end of each line is the source
3740 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3741 */
3742 static guicolor_tTable table[] =
3743 {
3744 {"Black", RGB(0x00, 0x00, 0x00)},
3745 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3746 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3747 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3748 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3749 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3750 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003751 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3752 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3753 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3754 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3755 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3756 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3757 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3758 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3759 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3760 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3761 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3762 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3763 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3764 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3765 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3766 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003767 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3768 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 {"white", RGB(0xFF, 0xFF, 0xFF)},
3770 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3771 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3772 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3773 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3774 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3775 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3776 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3777 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3778 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3779 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3780 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3781 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3782 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3783 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3784 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3785 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3786 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3787 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003788 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3790 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3791 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3792 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3793 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3794 };
3795
3796 int r, g, b;
3797 int i;
3798
3799 if (name[0] == '#' && strlen((char *) name) == 7)
3800 {
3801 /* Name is in "#rrggbb" format */
3802 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3803 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3804 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3805 if (r < 0 || g < 0 || b < 0)
3806 return INVALCOLOR;
3807 return RGB(r, g, b);
3808 }
3809 else
3810 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003811 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003813 LMGetHiliteRGB(&MacColor);
3814 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 }
3816 /* Check if the name is one of the colors we know */
3817 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3818 if (STRICMP(name, table[i].name) == 0)
3819 return table[i].color;
3820 }
3821
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 /*
3823 * Last attempt. Look in the file "$VIM/rgb.txt".
3824 */
3825 {
3826#define LINE_LEN 100
3827 FILE *fd;
3828 char line[LINE_LEN];
3829 char_u *fname;
3830
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 if (fname == NULL)
3833 return INVALCOLOR;
3834
3835 fd = fopen((char *)fname, "rt");
3836 vim_free(fname);
3837 if (fd == NULL)
3838 return INVALCOLOR;
3839
3840 while (!feof(fd))
3841 {
3842 int len;
3843 int pos;
3844 char *color;
3845
3846 fgets(line, LINE_LEN, fd);
3847 len = strlen(line);
3848
3849 if (len <= 1 || line[len-1] != '\n')
3850 continue;
3851
3852 line[len-1] = '\0';
3853
3854 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3855 if (i != 3)
3856 continue;
3857
3858 color = line + pos;
3859
3860 if (STRICMP(color, name) == 0)
3861 {
3862 fclose(fd);
3863 return (guicolor_T) RGB(r, g, b);
3864 }
3865 }
3866 fclose(fd);
3867 }
3868
3869 return INVALCOLOR;
3870}
3871
3872/*
3873 * Set the current text foreground color.
3874 */
3875 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003876gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877{
3878 RGBColor TheColor;
3879
3880 TheColor.red = Red(color) * 0x0101;
3881 TheColor.green = Green(color) * 0x0101;
3882 TheColor.blue = Blue(color) * 0x0101;
3883
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003884 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885}
3886
3887/*
3888 * Set the current text background color.
3889 */
3890 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003891gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892{
3893 RGBColor TheColor;
3894
3895 TheColor.red = Red(color) * 0x0101;
3896 TheColor.green = Green(color) * 0x0101;
3897 TheColor.blue = Blue(color) * 0x0101;
3898
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003899 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900}
3901
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003902RGBColor specialColor;
3903
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003904/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003905 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003906 */
3907 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003908gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003909{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003910 specialColor.red = Red(color) * 0x0101;
3911 specialColor.green = Green(color) * 0x0101;
3912 specialColor.blue = Blue(color) * 0x0101;
3913}
3914
3915/*
3916 * Draw undercurl at the bottom of the character cell.
3917 */
3918 static void
3919draw_undercurl(int flags, int row, int col, int cells)
3920{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003921 int x;
3922 int offset;
3923 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3924 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003925
3926 RGBForeColor(&specialColor);
3927
3928 offset = val[FILL_X(col) % 8];
3929 MoveTo(FILL_X(col), y - offset);
3930
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003931 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003932 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003933 offset = val[x % 8];
3934 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003935 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003936}
3937
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003938
3939 static void
3940draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003941{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942#ifdef FEAT_MBYTE
3943 char_u *tofree = NULL;
3944
3945 if (output_conv.vc_type != CONV_NONE)
3946 {
3947 tofree = string_convert(&output_conv, s, &len);
3948 if (tofree != NULL)
3949 s = tofree;
3950 }
3951#endif
3952
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953 /*
3954 * On OS X, try using Quartz-style text antialiasing.
3955 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003956 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957 {
3958 /* Quartz antialiasing is available only in OS 10.2 and later. */
3959 UInt32 qd_flags = (p_antialias ?
3960 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003961 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 }
3963
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003964 /*
3965 * When antialiasing we're using srcOr mode, we have to clear the block
3966 * before drawing the text.
3967 * Also needed when 'linespace' is non-zero to remove the cursor and
3968 * underlining.
3969 * But not when drawing transparently.
3970 * The following is like calling gui_mch_clear_block(row, col, row, col +
3971 * len - 1), but without setting the bg color to gui.back_pixel.
3972 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003973 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003974 && !(flags & DRAW_TRANSP))
3975 {
3976 Rect rc;
3977
3978 rc.left = FILL_X(col);
3979 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003980#ifdef FEAT_MBYTE
3981 /* Multibyte computation taken from gui_w32.c */
3982 if (has_mbyte)
3983 {
3984 int cell_len = 0;
3985 int n;
3986
3987 /* Compute the length in display cells. */
3988 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3989 cell_len += (*mb_ptr2cells)(s + n);
3990 rc.right = FILL_X(col + cell_len);
3991 }
3992 else
3993#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003994 rc.right = FILL_X(col + len) + (col + len == Columns);
3995 rc.bottom = FILL_Y(row + 1);
3996 EraseRect(&rc);
3997 }
3998
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003999 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 {
4001 StyleParameter face;
4002
4003 face = normal;
4004 if (flags & DRAW_BOLD)
4005 face |= bold;
4006 if (flags & DRAW_UNDERL)
4007 face |= underline;
4008 TextFace(face);
4009
4010 /* Quartz antialiasing works only in srcOr transfer mode. */
4011 TextMode(srcOr);
4012
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 MoveTo(TEXT_X(col), TEXT_Y(row));
4014 DrawText((char*)s, 0, len);
4015 }
4016 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 {
4018 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004019 TextMode(srcCopy);
4020 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021
4022 /* SelectFont(hdc, gui.currFont); */
4023
4024 if (flags & DRAW_TRANSP)
4025 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004026 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 }
4028
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004029 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004030 DrawText((char *)s, 0, len);
4031
4032 if (flags & DRAW_BOLD)
4033 {
4034 TextMode(srcOr);
4035 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4036 DrawText((char *)s, 0, len);
4037 }
4038
4039 if (flags & DRAW_UNDERL)
4040 {
4041 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4042 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4043 }
4044 }
4045
4046 if (flags & DRAW_UNDERC)
4047 draw_undercurl(flags, row, col, len);
4048
4049#ifdef FEAT_MBYTE
4050 vim_free(tofree);
4051#endif
4052}
4053
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004054#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004055
4056 static void
4057draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4058{
4059 /* ATSUI requires utf-16 strings */
4060 UniCharCount utf16_len;
4061 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4062 utf16_len /= sizeof(UniChar);
4063
4064 /* - ATSUI automatically antialiases text (Someone)
4065 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004066#ifdef MAC_ATSUI_DEBUG
4067 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4068 row, col, len, len == 1 ? s[0] : ' ');
4069#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004070 /*
4071 * When antialiasing we're using srcOr mode, we have to clear the block
4072 * before drawing the text.
4073 * Also needed when 'linespace' is non-zero to remove the cursor and
4074 * underlining.
4075 * But not when drawing transparently.
4076 * The following is like calling gui_mch_clear_block(row, col, row, col +
4077 * len - 1), but without setting the bg color to gui.back_pixel.
4078 */
4079 if ((flags & DRAW_TRANSP) == 0)
4080 {
4081 Rect rc;
4082
4083 rc.left = FILL_X(col);
4084 rc.top = FILL_Y(row);
4085 /* Multibyte computation taken from gui_w32.c */
4086 if (has_mbyte)
4087 {
4088 int cell_len = 0;
4089 int n;
4090
4091 /* Compute the length in display cells. */
4092 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4093 cell_len += (*mb_ptr2cells)(s + n);
4094 rc.right = FILL_X(col + cell_len);
4095 }
4096 else
4097 rc.right = FILL_X(col + len) + (col + len == Columns);
4098
4099 rc.bottom = FILL_Y(row + 1);
4100 EraseRect(&rc);
4101 }
4102
4103 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004104 TextMode(srcCopy);
4105 TextFace(normal);
4106
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004107 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004108 if (flags & DRAW_TRANSP)
4109 {
4110 TextMode(srcOr);
4111 }
4112
4113 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004114
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004115 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004116 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004117 Boolean attValue = true;
4118 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4119 ByteCount attribSizes[] = { sizeof(Boolean) };
4120 ATSUAttributeValuePtr attribValues[] = { &attValue };
4121
4122 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4123 }
4124
4125#ifdef FEAT_MBYTE
4126 if (has_mbyte)
4127 {
4128 int n, width_in_cell, last_width_in_cell;
4129 UniCharArrayOffset offset = 0;
4130 UniCharCount yet_to_draw = 0;
4131 ATSUTextLayout textLayout;
4132 ATSUStyle textStyle;
4133
4134 last_width_in_cell = 1;
4135 ATSUCreateTextLayout(&textLayout);
4136 ATSUSetTextPointerLocation(textLayout, tofree,
4137 kATSUFromTextBeginning,
4138 kATSUToTextEnd, utf16_len);
4139 /*
4140 ATSUSetRunStyle(textLayout, gFontStyle,
4141 kATSUFromTextBeginning, kATSUToTextEnd); */
4142
4143 /* Compute the length in display cells. */
4144 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4145 {
4146 width_in_cell = (*mb_ptr2cells)(s + n);
4147
4148 /* probably we are switching from single byte character
4149 * to multibyte characters (which requires more than one
4150 * cell to draw) */
4151 if (width_in_cell != last_width_in_cell)
4152 {
4153#ifdef MAC_ATSUI_DEBUG
4154 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4155 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4156#endif
4157 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4158 : gFontStyle;
4159
4160 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4161 offset += yet_to_draw;
4162 yet_to_draw = 0;
4163 last_width_in_cell = width_in_cell;
4164 }
4165
4166 yet_to_draw++;
4167 }
4168
4169 if (yet_to_draw)
4170 {
4171#ifdef MAC_ATSUI_DEBUG
4172 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4173 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4174#endif
4175 /* finish the rest style */
4176 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4177 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4178 }
4179
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004180 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004181 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004182 kATSUFromTextBeginning, kATSUToTextEnd,
4183 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004184 ATSUDisposeTextLayout(textLayout);
4185 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004186 else
4187#endif
4188 {
4189 ATSUTextLayout textLayout;
4190
4191 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4192 kATSUFromTextBeginning, kATSUToTextEnd,
4193 utf16_len,
4194 (gFontStyle ? 1 : 0), &utf16_len,
4195 (gFontStyle ? &gFontStyle : NULL),
4196 &textLayout) == noErr)
4197 {
4198 ATSUSetTransientFontMatching(textLayout, TRUE);
4199
4200 ATSUDrawText(textLayout,
4201 kATSUFromTextBeginning, kATSUToTextEnd,
4202 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4203
4204 ATSUDisposeTextLayout(textLayout);
4205 }
4206 }
4207
4208 /* drawing is done, now reset bold to normal */
4209 if (gFontStyle && flags & DRAW_BOLD)
4210 {
4211 Boolean attValue = false;
4212
4213 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4214 ByteCount attribSizes[] = { sizeof(Boolean) };
4215 ATSUAttributeValuePtr attribValues[] = { &attValue };
4216
4217 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4218 attribValues);
4219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 }
4221
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004222 if (flags & DRAW_UNDERC)
4223 draw_undercurl(flags, row, col, len);
4224
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004226}
4227#endif
4228
4229 void
4230gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4231{
4232#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004233 if (p_macatsui == 0 && p_macatsui_last != 0)
4234 /* switch from macatsui to nomacatsui */
4235 gui_mac_dispose_atsui_style();
4236 else if (p_macatsui != 0 && p_macatsui_last == 0)
4237 /* switch from nomacatsui to macatsui */
4238 gui_mac_create_atsui_style();
4239
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004240 if (p_macatsui)
4241 draw_string_ATSUI(row, col, s, len, flags);
4242 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004244 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245}
4246
4247/*
4248 * Return OK if the key with the termcap name "name" is supported.
4249 */
4250 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004251gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252{
4253 int i;
4254
4255 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4256 if (name[0] == special_keys[i].vim_code0 &&
4257 name[1] == special_keys[i].vim_code1)
4258 return OK;
4259 return FAIL;
4260}
4261
4262 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004263gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004265 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266}
4267
4268 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004269gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270{
4271 /* Do a visual beep by reversing the foreground and background colors */
4272 Rect rc;
4273
4274 /*
4275 * Note: InvertRect() excludes right and bottom of rectangle.
4276 */
4277 rc.left = 0;
4278 rc.top = 0;
4279 rc.right = gui.num_cols * gui.char_width;
4280 rc.bottom = gui.num_rows * gui.char_height;
4281 InvertRect(&rc);
4282
4283 ui_delay((long)msec, TRUE); /* wait for some msec */
4284
4285 InvertRect(&rc);
4286}
4287
4288/*
4289 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4290 */
4291 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004292gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004293{
4294 Rect rc;
4295
4296 /*
4297 * Note: InvertRect() excludes right and bottom of rectangle.
4298 */
4299 rc.left = FILL_X(c);
4300 rc.top = FILL_Y(r);
4301 rc.right = rc.left + nc * gui.char_width;
4302 rc.bottom = rc.top + nr * gui.char_height;
4303 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304}
4305
4306/*
4307 * Iconify the GUI window.
4308 */
4309 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004310gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311{
4312 /* TODO: find out what could replace iconify
4313 * -window shade?
4314 * -hide application?
4315 */
4316}
4317
4318#if defined(FEAT_EVAL) || defined(PROTO)
4319/*
4320 * Bring the Vim window to the foreground.
4321 */
4322 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004323gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324{
4325 /* TODO */
4326}
4327#endif
4328
4329/*
4330 * Draw a cursor without focus.
4331 */
4332 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004333gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334{
4335 Rect rc;
4336
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337 /*
4338 * Note: FrameRect() excludes right and bottom of rectangle.
4339 */
4340 rc.left = FILL_X(gui.col);
4341 rc.top = FILL_Y(gui.row);
4342 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004343#ifdef FEAT_MBYTE
4344 if (mb_lefthalve(gui.row, gui.col))
4345 rc.right += gui.char_width;
4346#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347 rc.bottom = rc.top + gui.char_height;
4348
4349 gui_mch_set_fg_color(color);
4350
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004351 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352}
4353
4354/*
4355 * Draw part of a cursor, only w pixels wide, and h pixels high.
4356 */
4357 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004358gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359{
4360 Rect rc;
4361
4362#ifdef FEAT_RIGHTLEFT
4363 /* vertical line should be on the right of current point */
4364 if (CURSOR_BAR_RIGHT)
4365 rc.left = FILL_X(gui.col + 1) - w;
4366 else
4367#endif
4368 rc.left = FILL_X(gui.col);
4369 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4370 rc.right = rc.left + w;
4371 rc.bottom = rc.top + h;
4372
4373 gui_mch_set_fg_color(color);
4374
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004375 FrameRect(&rc);
4376// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377}
4378
4379
4380
4381/*
4382 * Catch up with any queued X events. This may put keyboard input into the
4383 * input buffer, call resize call-backs, trigger timers etc. If there is
4384 * nothing in the X event queue (& no timers pending), then we return
4385 * immediately.
4386 */
4387 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004388gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389{
4390 /* TODO: find what to do
4391 * maybe call gui_mch_wait_for_chars (0)
4392 * more like look at EventQueue then
4393 * call heart of gui_mch_wait_for_chars;
4394 *
4395 * if (eventther)
4396 * gui_mac_handle_event(&event);
4397 */
4398 EventRecord theEvent;
4399
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004400 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 if (theEvent.what != nullEvent)
4402 gui_mch_wait_for_chars(0);
4403}
4404
4405/*
4406 * Simple wrapper to neglect more easily the time
4407 * spent inside WaitNextEvent while profiling.
4408 */
4409
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 pascal
4411 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004412WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413{
4414 if (((long) sleep) < -1)
4415 sleep = 32767;
4416 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4417}
4418
4419/*
4420 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4421 * from the keyboard.
4422 * wtime == -1 Wait forever.
4423 * wtime == 0 This should never happen.
4424 * wtime > 0 Wait wtime milliseconds for a character.
4425 * Returns OK if a character was found to be available within the given time,
4426 * or FAIL otherwise.
4427 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004428 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004429gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430{
4431 EventMask mask = (everyEvent);
4432 EventRecord event;
4433 long entryTick;
4434 long currentTick;
4435 long sleeppyTick;
4436
4437 /* If we are providing life feedback with the scrollbar,
4438 * we don't want to try to wait for an event, or else
4439 * there won't be any life feedback.
4440 */
4441 if (dragged_sb != NULL)
4442 return FAIL;
4443 /* TODO: Check if FAIL is the proper return code */
4444
4445 entryTick = TickCount();
4446
4447 allow_scrollbar = TRUE;
4448
4449 do
4450 {
4451/* if (dragRectControl == kCreateEmpty)
4452 {
4453 dragRgn = NULL;
4454 dragRectControl = kNothing;
4455 }
4456 else*/ if (dragRectControl == kCreateRect)
4457 {
4458 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004459 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460 dragRectControl = kNothing;
4461 }
4462 /*
4463 * Don't use gui_mch_update() because then we will spin-lock until a
4464 * char arrives, instead we use WaitNextEventWrp() to hang until an
4465 * event arrives. No need to check for input_buf_full because we are
4466 * returning as soon as it contains a single char.
4467 */
4468 /* TODO: reduce wtime accordinly??? */
4469 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004470 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 else
4472 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004473
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004474 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004476 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 if (input_available())
4478 {
4479 allow_scrollbar = FALSE;
4480 return OK;
4481 }
4482 }
4483 currentTick = TickCount();
4484 }
4485 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4486
4487 allow_scrollbar = FALSE;
4488 return FAIL;
4489}
4490
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491/*
4492 * Output routines.
4493 */
4494
4495/* Flush any output to the screen */
4496 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004497gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498{
4499 /* TODO: Is anything needed here? */
4500}
4501
4502/*
4503 * Clear a rectangular region of the screen from text pos (row1, col1) to
4504 * (row2, col2) inclusive.
4505 */
4506 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004507gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508{
4509 Rect rc;
4510
4511 /*
4512 * Clear one extra pixel at the far right, for when bold characters have
4513 * spilled over to the next column.
4514 */
4515 rc.left = FILL_X(col1);
4516 rc.top = FILL_Y(row1);
4517 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4518 rc.bottom = FILL_Y(row2 + 1);
4519
4520 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004521 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522}
4523
4524/*
4525 * Clear the whole text window.
4526 */
4527 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004528gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529{
4530 Rect rc;
4531
4532 rc.left = 0;
4533 rc.top = 0;
4534 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4535 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4536
4537 gui_mch_set_bg_color(gui.back_pixel);
4538 EraseRect(&rc);
4539/* gui_mch_set_fg_color(gui.norm_pixel);
4540 FrameRect(&rc);
4541*/
4542}
4543
4544/*
4545 * Delete the given number of lines from the given row, scrolling up any
4546 * text further down within the scroll region.
4547 */
4548 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004549gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550{
4551 Rect rc;
4552
4553 /* changed without checking! */
4554 rc.left = FILL_X(gui.scroll_region_left);
4555 rc.right = FILL_X(gui.scroll_region_right + 1);
4556 rc.top = FILL_Y(row);
4557 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4558
4559 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004560 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561
4562 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4563 gui.scroll_region_left,
4564 gui.scroll_region_bot, gui.scroll_region_right);
4565}
4566
4567/*
4568 * Insert the given number of lines before the given row, scrolling down any
4569 * following text within the scroll region.
4570 */
4571 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004572gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573{
4574 Rect rc;
4575
4576 rc.left = FILL_X(gui.scroll_region_left);
4577 rc.right = FILL_X(gui.scroll_region_right + 1);
4578 rc.top = FILL_Y(row);
4579 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4580
4581 gui_mch_set_bg_color(gui.back_pixel);
4582
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004583 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584
4585 /* Update gui.cursor_row if the cursor scrolled or copied over */
4586 if (gui.cursor_row >= gui.row
4587 && gui.cursor_col >= gui.scroll_region_left
4588 && gui.cursor_col <= gui.scroll_region_right)
4589 {
4590 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4591 gui.cursor_row += num_lines;
4592 else if (gui.cursor_row <= gui.scroll_region_bot)
4593 gui.cursor_is_valid = FALSE;
4594 }
4595
4596 gui_clear_block(row, gui.scroll_region_left,
4597 row + num_lines - 1, gui.scroll_region_right);
4598}
4599
4600 /*
4601 * TODO: add a vim format to the clipboard which remember
4602 * LINEWISE, CHARWISE, BLOCKWISE
4603 */
4604
4605 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004606clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607{
4608
4609 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004610 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 Size scrapSize;
4612 ScrapFlavorFlags scrapFlags;
4613 ScrapRef scrap = nil;
4614 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 int type;
4616 char *searchCR;
4617 char_u *tempclip;
4618
4619
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004620 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621 if (error != noErr)
4622 return;
4623
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004624 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4625 if (error == noErr)
4626 {
4627 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4628 if (error == noErr && scrapSize > 1)
4629 flavor = 1;
4630 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004632 if (flavor == 0)
4633 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004634 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004635 if (error != noErr)
4636 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004638 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004639 if (error != noErr)
4640 return;
4641 }
4642
4643 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004645 /* In CARBON we don't need a Handle, a pointer is good */
4646 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004648 /* tempclip = lalloc(scrapSize+1, TRUE); */
4649 HLock(textOfClip);
4650 error = GetScrapFlavorData(scrap,
4651 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4652 &scrapSize, *textOfClip);
4653 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004655 if (flavor)
4656 type = **textOfClip;
4657 else
4658 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4659
4660 tempclip = lalloc(scrapSize + 1, TRUE);
4661 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4662 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004664#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004665 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004666 /* Convert from utf-16 (clipboard) */
4667 size_t encLen = 0;
4668 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004669
4670 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004672 scrapSize = encLen;
4673 vim_free(tempclip);
4674 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004676 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004678
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004679 searchCR = (char *)tempclip;
4680 while (searchCR != NULL)
4681 {
4682 searchCR = strchr(searchCR, '\r');
4683 if (searchCR != NULL)
4684 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004686
4687 clip_yank_selection(type, tempclip, scrapSize, cbd);
4688
4689 vim_free(tempclip);
4690 HUnlock(textOfClip);
4691
4692 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693}
4694
4695 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004696clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697{
4698 /*
4699 * TODO: Really nothing to do?
4700 */
4701}
4702
4703 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004704clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705{
4706 return OK;
4707}
4708
4709/*
4710 * Send the current selection to the clipboard.
4711 */
4712 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004713clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714{
4715 Handle textOfClip;
4716 long scrapSize;
4717 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719
4720 char_u *str = NULL;
4721
4722 if (!cbd->owned)
4723 return;
4724
4725 clip_get_selection(cbd);
4726
4727 /*
4728 * Once we set the clipboard, lose ownership. If another application sets
4729 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 cbd->owned = FALSE;
4732
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004733 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004735#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004736 size_t utf16_len = 0;
4737 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4738 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004740 scrapSize = utf16_len;
4741 vim_free(str);
4742 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743 }
4744#endif
4745
4746 if (type >= 0)
4747 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004750 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 HLock(textOfClip);
4752
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004753 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004754 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004755 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004756 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004757 scrapSize, *textOfClip + 1);
4758 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4759 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 HUnlock(textOfClip);
4761 DisposeHandle(textOfClip);
4762 }
4763
4764 vim_free(str);
4765}
4766
4767 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004768gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769{
4770 Rect VimBound;
4771
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004772/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774
4775 if (gui.which_scrollbars[SBAR_LEFT])
4776 {
4777 VimBound.left = -gui.scrollbar_width + 1;
4778 }
4779 else
4780 {
4781 VimBound.left = 0;
4782 }
4783
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004786 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787}
4788
4789/*
4790 * Menu stuff.
4791 */
4792
4793 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004794gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795{
4796 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004797 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798 */
4799}
4800
4801 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004802gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803{
4804 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004805 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806 */
4807}
4808
4809/*
4810 * Add a sub menu to the menu bar.
4811 */
4812 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004813gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814{
4815 /*
4816 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4817 * TODO: use menu->mnemonic and menu->actext
4818 * TODO: Try to reuse menu id
4819 * Carbon Help suggest to use only id between 1 and 235
4820 */
4821 static long next_avail_id = 128;
4822 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004823#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004824 CFStringRef name;
4825#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004827#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 short index;
4829 vimmenu_T *parent = menu->parent;
4830 vimmenu_T *brother = menu->next;
4831
4832 /* Cannot add a menu if ... */
4833 if ((parent != NULL && parent->submenu_id == 0))
4834 return;
4835
4836 /* menu ID greater than 1024 are reserved for ??? */
4837 if (next_avail_id == 1024)
4838 return;
4839
4840 /* My brother could be the PopUp, find my real brother */
4841 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4842 brother = brother->next;
4843
4844 /* Find where to insert the menu (for MenuBar) */
4845 if ((parent == NULL) && (brother != NULL))
4846 menu_after_me = brother->submenu_id;
4847
4848 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4849 if (!menu_is_menubar(menu->name))
4850 menu_after_me = hierMenu;
4851
4852 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004853#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004854 name = menu_title_removing_mnemonic(menu);
4855#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004857#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858 if (name == NULL)
4859 return;
4860
4861 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 {
4863 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004864 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4865 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 */
4867 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004868#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004869 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4870 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4871#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004872 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004873#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 next_avail_id++;
4875 }
4876
4877 if (parent == NULL)
4878 {
4879 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4880
4881 /* TODO: Verify if we could only Insert Menu if really part of the
4882 * menubar The Inserted menu are scanned or the Command-key combos
4883 */
4884
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004885 /* Insert the menu */
4886 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887#if 1
4888 /* Vim should normally update it. TODO: verify */
4889 DrawMenuBar();
4890#endif
4891 }
4892 else
4893 {
4894 /* Adding as a submenu */
4895
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004896 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897
4898 /* Call InsertMenuItem followed by SetMenuItemText
4899 * to avoid special character recognition by InsertMenuItem
4900 */
4901 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004902#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004903 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4904#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004906#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4908 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4909 InsertMenu(menu->submenu_handle, hierMenu);
4910 }
4911
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004912#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004913 CFRelease(name);
4914#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004915 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004916#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004917
4918#if 0
4919 /* Done by Vim later on */
4920 DrawMenuBar();
4921#endif
4922}
4923
4924/*
4925 * Add a menu item to a menu
4926 */
4927 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004928gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004929{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004930#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004931 CFStringRef name;
4932#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004934#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004935 vimmenu_T *parent = menu->parent;
4936 int menu_inserted;
4937
4938 /* Cannot add item, if the menu have not been created */
4939 if (parent->submenu_id == 0)
4940 return;
4941
4942 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4943 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4944
4945 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004946#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004947 name = menu_title_removing_mnemonic(menu);
4948#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951
4952 /* Where are just a menu item, so no handle, no id */
4953 menu->submenu_id = 0;
4954 menu->submenu_handle = NULL;
4955
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956 menu_inserted = 0;
4957 if (menu->actext)
4958 {
4959 /* If the accelerator text for the menu item looks like it describes
4960 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4961 * item's command equivalent.
4962 */
4963 int key = 0;
4964 int modifiers = 0;
4965 char_u *p_actext;
4966
4967 p_actext = menu->actext;
4968 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4969 if (*p_actext != 0)
4970 key = 0; /* error: trailing text */
4971 /* find_special_key() returns a keycode with as many of the
4972 * specified modifiers as appropriate already applied (e.g., for
4973 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4974 * as the only modifier). Since we want to display all of the
4975 * modifiers, we need to convert the keycode back to a printable
4976 * character plus modifiers.
4977 * TODO: Write an alternative find_special_key() that doesn't
4978 * apply modifiers.
4979 */
4980 if (key > 0 && key < 32)
4981 {
4982 /* Convert a control key to an uppercase letter. Note that
4983 * by this point it is no longer possible to distinguish
4984 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4985 */
4986 modifiers |= MOD_MASK_CTRL;
4987 key += '@';
4988 }
4989 /* If the keycode is an uppercase letter, set the Shift modifier.
4990 * If it is a lowercase letter, don't set the modifier, but convert
4991 * the letter to uppercase for display in the menu.
4992 */
4993 else if (key >= 'A' && key <= 'Z')
4994 modifiers |= MOD_MASK_SHIFT;
4995 else if (key >= 'a' && key <= 'z')
4996 key += 'A' - 'a';
4997 /* Note: keycodes below 0x22 are reserved by Apple. */
4998 if (key >= 0x22 && vim_isprintc_strict(key))
4999 {
5000 int valid = 1;
5001 char_u mac_mods = kMenuNoModifiers;
5002 /* Convert Vim modifier codes to Menu Manager equivalents. */
5003 if (modifiers & MOD_MASK_SHIFT)
5004 mac_mods |= kMenuShiftModifier;
5005 if (modifiers & MOD_MASK_CTRL)
5006 mac_mods |= kMenuControlModifier;
5007 if (!(modifiers & MOD_MASK_CMD))
5008 mac_mods |= kMenuNoCommandModifier;
5009 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5010 valid = 0; /* TODO: will Alt someday map to Option? */
5011 if (valid)
5012 {
5013 char_u item_txt[10];
5014 /* Insert the menu item after idx, with its command key. */
5015 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5016 item_txt[3] = key;
5017 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5018 /* Set the modifier keys. */
5019 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5020 menu_inserted = 1;
5021 }
5022 }
5023 }
5024 /* Call InsertMenuItem followed by SetMenuItemText
5025 * to avoid special character recognition by InsertMenuItem
5026 */
5027 if (!menu_inserted)
5028 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5029 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005030#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005031 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5032#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005034#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035
5036#if 0
5037 /* Called by Vim */
5038 DrawMenuBar();
5039#endif
5040
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005041#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005042 CFRelease(name);
5043#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044 /* TODO: Can name be freed? */
5045 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005046#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047}
5048
5049 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005050gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051{
5052 /* no tearoff menus */
5053}
5054
5055/*
5056 * Destroy the machine specific menu widget.
5057 */
5058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005059gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005061 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062
5063 if (index > 0)
5064 {
5065 if (menu->parent)
5066 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067 {
5068 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005069 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005070
5071 /* Delete the Menu if it was a hierarchical Menu */
5072 if (menu->submenu_id != 0)
5073 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005074 DeleteMenu(menu->submenu_id);
5075 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076 }
5077 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078 }
5079#ifdef DEBUG_MAC_MENU
5080 else
5081 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005082 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083 }
5084#endif
5085 }
5086 else
5087 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005089 DeleteMenu(menu->submenu_id);
5090 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091 }
5092 }
5093 /* Shouldn't this be already done by Vim. TODO: Check */
5094 DrawMenuBar();
5095}
5096
5097/*
5098 * Make a menu either grey or not grey.
5099 */
5100 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005101gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102{
5103 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005104 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005105/*
5106 index = menu->index;
5107*/
5108 if (grey)
5109 {
5110 if (menu->children)
5111 DisableMenuItem(menu->submenu_handle, index);
5112 if (menu->parent)
5113 if (menu->parent->submenu_handle)
5114 DisableMenuItem(menu->parent->submenu_handle, index);
5115 }
5116 else
5117 {
5118 if (menu->children)
5119 EnableMenuItem(menu->submenu_handle, index);
5120 if (menu->parent)
5121 if (menu->parent->submenu_handle)
5122 EnableMenuItem(menu->parent->submenu_handle, index);
5123 }
5124}
5125
5126/*
5127 * Make menu item hidden or not hidden
5128 */
5129 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005130gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005131{
5132 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005133 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134}
5135
5136
5137/*
5138 * This is called after setting all the menus to grey/hidden or not.
5139 */
5140 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005141gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142{
5143 DrawMenuBar();
5144}
5145
5146
5147/*
5148 * Scrollbar stuff.
5149 */
5150
5151 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005152gui_mch_enable_scrollbar(
5153 scrollbar_T *sb,
5154 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155{
5156 if (flag)
5157 ShowControl(sb->id);
5158 else
5159 HideControl(sb->id);
5160
5161#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005162 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005163#endif
5164}
5165
5166 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005167gui_mch_set_scrollbar_thumb(
5168 scrollbar_T *sb,
5169 long val,
5170 long size,
5171 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172{
5173 SetControl32BitMaximum (sb->id, max);
5174 SetControl32BitMinimum (sb->id, 0);
5175 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005176 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005178 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179#endif
5180}
5181
5182 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005183gui_mch_set_scrollbar_pos(
5184 scrollbar_T *sb,
5185 int x,
5186 int y,
5187 int w,
5188 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189{
5190 gui_mch_set_bg_color(gui.back_pixel);
5191/* if (gui.which_scrollbars[SBAR_LEFT])
5192 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005193 MoveControl(sb->id, x-16, y);
5194 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005195 }
5196 else
5197 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005198 MoveControl(sb->id, x, y);
5199 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 }*/
5201 if (sb == &gui.bottom_sbar)
5202 h += 1;
5203 else
5204 w += 1;
5205
5206 if (gui.which_scrollbars[SBAR_LEFT])
5207 x -= 15;
5208
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005209 MoveControl(sb->id, x, y);
5210 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005212 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005213#endif
5214}
5215
5216 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005217gui_mch_create_scrollbar(
5218 scrollbar_T *sb,
5219 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220{
5221 Rect bounds;
5222
5223 bounds.top = -16;
5224 bounds.bottom = -10;
5225 bounds.right = -10;
5226 bounds.left = -16;
5227
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005228 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 &bounds,
5230 "\pScrollBar",
5231 TRUE,
5232 0, /* current*/
5233 0, /* top */
5234 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005236 (long) sb->ident);
5237#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005238 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239#endif
5240}
5241
5242 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005243gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005244{
5245 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005246 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005248 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249#endif
5250}
5251
5252
5253/*
5254 * Cursor blink functions.
5255 *
5256 * This is a simple state machine:
5257 * BLINK_NONE not blinking at all
5258 * BLINK_OFF blinking, cursor is not shown
5259 * BLINK_ON blinking, cursor is shown
5260 */
5261 void
5262gui_mch_set_blinking(long wait, long on, long off)
5263{
5264 /* TODO: TODO: TODO: TODO: */
5265/* blink_waittime = wait;
5266 blink_ontime = on;
5267 blink_offtime = off;*/
5268}
5269
5270/*
5271 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5272 */
5273 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005274gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275{
5276 gui_update_cursor(TRUE, FALSE);
5277 /* TODO: TODO: TODO: TODO: */
5278/* gui_w32_rm_blink_timer();
5279 if (blink_state == BLINK_OFF)
5280 gui_update_cursor(TRUE, FALSE);
5281 blink_state = BLINK_NONE;*/
5282}
5283
5284/*
5285 * Start the cursor blinking. If it was already blinking, this restarts the
5286 * waiting time and shows the cursor.
5287 */
5288 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005289gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290{
5291 gui_update_cursor(TRUE, FALSE);
5292 /* TODO: TODO: TODO: TODO: */
5293/* gui_w32_rm_blink_timer(); */
5294
5295 /* Only switch blinking on if none of the times is zero */
5296/* if (blink_waittime && blink_ontime && blink_offtime)
5297 {
5298 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5299 (TIMERPROC)_OnBlinkTimer);
5300 blink_state = BLINK_ON;
5301 gui_update_cursor(TRUE, FALSE);
5302 }*/
5303}
5304
5305/*
5306 * Return the RGB value of a pixel as long.
5307 */
5308 long_u
5309gui_mch_get_rgb(guicolor_T pixel)
5310{
5311 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5312}
5313
5314
5315
5316#ifdef FEAT_BROWSE
5317/*
5318 * Pop open a file browser and return the file selected, in allocated memory,
5319 * or NULL if Cancel is hit.
5320 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5321 * title - Title message for the file browser dialog.
5322 * dflt - Default name of file.
5323 * ext - Default extension to be added to files without extensions.
5324 * initdir - directory in which to open the browser (NULL = current dir)
5325 * filter - Filter for matched files to choose from.
5326 * Has a format like this:
5327 * "C Files (*.c)\0*.c\0"
5328 * "All Files\0*.*\0\0"
5329 * If these two strings were concatenated, then a choice of two file
5330 * filters will be selectable to the user. Then only matching files will
5331 * be shown in the browser. If NULL, the default allows all files.
5332 *
5333 * *NOTE* - the filter string must be terminated with TWO nulls.
5334 */
5335 char_u *
5336gui_mch_browse(
5337 int saving,
5338 char_u *title,
5339 char_u *dflt,
5340 char_u *ext,
5341 char_u *initdir,
5342 char_u *filter)
5343{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344 /* TODO: Add Ammon's safety checl (Dany) */
5345 NavReplyRecord reply;
5346 char_u *fname = NULL;
5347 char_u **fnames = NULL;
5348 long numFiles;
5349 NavDialogOptions navOptions;
5350 OSErr error;
5351
5352 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005353 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005354
5355
5356 /* TODO: If we get a :browse args, set the Multiple bit. */
5357 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5358 | kNavDontAutoTranslate
5359 | kNavDontAddTranslateItems
5360 /* | kNavAllowMultipleFiles */
5361 | kNavAllowStationery;
5362
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005363 (void) C2PascalString(title, &navOptions.message);
5364 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365 /* Could set clientName?
5366 * windowTitle? (there's no title bar?)
5367 */
5368
5369 if (saving)
5370 {
5371 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005372 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373 if (!reply.validRecord)
5374 return NULL;
5375 }
5376 else
5377 {
5378 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5379 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5380 if (!reply.validRecord)
5381 return NULL;
5382 }
5383
5384 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5385
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005386 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005387
5388 if (fnames)
5389 {
5390 fname = fnames[0];
5391 vim_free(fnames);
5392 }
5393
5394 /* TODO: Shorten the file name if possible */
5395 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005396}
5397#endif /* FEAT_BROWSE */
5398
5399#ifdef FEAT_GUI_DIALOG
5400/*
5401 * Stuff for dialogues
5402 */
5403
5404/*
5405 * Create a dialogue dynamically from the parameter strings.
5406 * type = type of dialogue (question, alert, etc.)
5407 * title = dialogue title. may be NULL for default title.
5408 * message = text to display. Dialogue sizes to accommodate it.
5409 * buttons = '\n' separated list of button captions, default first.
5410 * dfltbutton = number of default button.
5411 *
5412 * This routine returns 1 if the first button is pressed,
5413 * 2 for the second, etc.
5414 *
5415 * 0 indicates Esc was pressed.
5416 * -1 for unexpected error
5417 *
5418 * If stubbing out this fn, return 1.
5419 */
5420
5421typedef struct
5422{
5423 short idx;
5424 short width; /* Size of the text in pixel */
5425 Rect box;
5426} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5427
5428#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5429
5430 static void
5431macMoveDialogItem(
5432 DialogRef theDialog,
5433 short itemNumber,
5434 short X,
5435 short Y,
5436 Rect *inBox)
5437{
5438#if 0 /* USE_CARBONIZED */
5439 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005440 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005442 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005443#else
5444 short itemType;
5445 Handle itemHandle;
5446 Rect localBox;
5447 Rect *itemBox = &localBox;
5448
5449 if (inBox != nil)
5450 itemBox = inBox;
5451
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005452 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5453 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5454 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005455 /* To move a control (like a button) we need to call both
5456 * MoveControl and SetDialogItem. FAQ 6-18 */
5457 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005458 MoveControl((ControlRef) itemHandle, X, Y);
5459 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005460#endif
5461}
5462
5463 static void
5464macSizeDialogItem(
5465 DialogRef theDialog,
5466 short itemNumber,
5467 short width,
5468 short height)
5469{
5470 short itemType;
5471 Handle itemHandle;
5472 Rect itemBox;
5473
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005474 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005475
5476 /* When width or height is zero do not change it */
5477 if (width == 0)
5478 width = itemBox.right - itemBox.left;
5479 if (height == 0)
5480 height = itemBox.bottom - itemBox.top;
5481
5482#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005483 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484#else
5485 /* Resize the bounding box */
5486 itemBox.right = itemBox.left + width;
5487 itemBox.bottom = itemBox.top + height;
5488
5489 /* To resize a control (like a button) we need to call both
5490 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5491 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005492 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005493
5494 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005495 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005496#endif
5497}
5498
5499 static void
5500macSetDialogItemText(
5501 DialogRef theDialog,
5502 short itemNumber,
5503 Str255 itemName)
5504{
5505 short itemType;
5506 Handle itemHandle;
5507 Rect itemBox;
5508
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005509 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510
5511 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005512 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005513 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005514 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515}
5516
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005517
5518/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5519 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5520 * setting gDialogHotKeys to NULL disables any hotkey handling.
5521 */
5522 static pascal Boolean
5523DialogHotkeyFilterProc (
5524 DialogRef theDialog,
5525 EventRecord *event,
5526 DialogItemIndex *itemHit)
5527{
5528 char_u keyHit;
5529
5530 if (event->what == keyDown || event->what == autoKey)
5531 {
5532 keyHit = (event->message & charCodeMask);
5533
5534 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5535 {
5536#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5537 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5538#endif
5539 *itemHit = gDialogHotKeys[keyHit];
5540
5541 /* When handing off to StdFilterProc, pretend that the user
5542 * clicked the control manually. Note that this is also supposed
5543 * to cause the button to hilite briefly (to give some user
5544 * feedback), but this seems not to actually work (or it's too
5545 * fast to be seen).
5546 */
5547 event->what = kEventControlSimulateHit;
5548
5549 return true; /* we took care of it */
5550 }
5551
5552 /* Defer to the OS's standard behavior for this event.
5553 * This ensures that Enter will still activate the default button. */
5554 return StdFilterProc(theDialog, event, itemHit);
5555 }
5556 return false; /* Let ModalDialog deal with it */
5557}
5558
5559
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005560/* TODO: There have been some crashes with dialogs, check your inbox
5561 * (Jussi)
5562 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563 int
5564gui_mch_dialog(
5565 int type,
5566 char_u *title,
5567 char_u *message,
5568 char_u *buttons,
5569 int dfltbutton,
5570 char_u *textfield)
5571{
5572 Handle buttonDITL;
5573 Handle iconDITL;
5574 Handle inputDITL;
5575 Handle messageDITL;
5576 Handle itemHandle;
5577 Handle iconHandle;
5578 DialogPtr theDialog;
5579 char_u len;
5580 char_u PascalTitle[256]; /* place holder for the title */
5581 char_u name[256];
5582 GrafPtr oldPort;
5583 short itemHit;
5584 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005585 short hotKeys[256]; /* map of hotkey -> control ID */
5586 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587 Rect box;
5588 short button;
5589 short lastButton;
5590 short itemType;
5591 short useIcon;
5592 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005593 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005594 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595 short widestButton = 0;
5596 short dfltButtonEdge = 20; /* gut feeling */
5597 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5598 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5599 short maximumWidth = 400; /* gut feeling */
5600 short maxButtonWidth = 175; /* gut feeling */
5601
5602 short vertical;
5603 short dialogHeight;
5604 short messageLines = 3;
5605 FontInfo textFontInfo;
5606
5607 vgmDlgItm iconItm;
5608 vgmDlgItm messageItm;
5609 vgmDlgItm inputItm;
5610 vgmDlgItm buttonItm;
5611
5612 WindowRef theWindow;
5613
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005614 ModalFilterUPP dialogUPP;
5615
Bram Moolenaar071d4272004-06-13 20:20:40 +00005616 /* Check 'v' flag in 'guioptions': vertical button placement. */
5617 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5618
5619 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005620 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621
5622 /* Get the WindowRef */
5623 theWindow = GetDialogWindow(theDialog);
5624
5625 /* Hide the window.
5626 * 1. to avoid seeing slow drawing
5627 * 2. to prevent a problem seen while moving dialog item
5628 * within a visible window. (non-Carbon MacOS 9)
5629 * Could be avoided by changing the resource.
5630 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005631 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005632
5633 /* Change the graphical port to the dialog,
5634 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005635 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005636 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637
5638 /* Get the info about the default text,
5639 * used to calculate the height of the message
5640 * and of the text field */
5641 GetFontInfo(&textFontInfo);
5642
5643 /* Set the dialog title */
5644 if (title != NULL)
5645 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005646 (void) C2PascalString(title, &PascalTitle);
5647 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005648 }
5649
5650 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005651 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 buttonChar = buttons;
5653 button = 0;
5654
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005655 /* initialize the hotkey mapping */
5656 memset(hotKeys, 0, sizeof(hotKeys));
5657
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658 for (;*buttonChar != 0;)
5659 {
5660 /* Get the name of the button */
5661 button++;
5662 len = 0;
5663 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5664 {
5665 if (*buttonChar != DLG_HOTKEY_CHAR)
5666 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005667 else
5668 {
5669 aHotKey = (char_u)*(buttonChar+1);
5670 if (aHotKey >= 'A' && aHotKey <= 'Z')
5671 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5672 hotKeys[aHotKey] = button;
5673#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5674 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5675#endif
5676 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005677 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005678
Bram Moolenaar071d4272004-06-13 20:20:40 +00005679 if (*buttonChar != 0)
5680 buttonChar++;
5681 name[0] = len;
5682
5683 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005684 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685
5686 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005687 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688
5689 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005690 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 /* Limite the size of any button to an acceptable value. */
5692 /* TODO: Should be based on the message width */
5693 if (width > maxButtonWidth)
5694 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005695 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696
5697 totalButtonWidth += width;
5698
5699 if (width > widestButton)
5700 widestButton = width;
5701 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005702 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005703 lastButton = button;
5704
5705 /* Add the icon to the Dialog Box. */
5706 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708 switch (type)
5709 {
5710 case VIM_GENERIC: useIcon = kNoteIcon;
5711 case VIM_ERROR: useIcon = kStopIcon;
5712 case VIM_WARNING: useIcon = kCautionIcon;
5713 case VIM_INFO: useIcon = kNoteIcon;
5714 case VIM_QUESTION: useIcon = kNoteIcon;
5715 default: useIcon = kStopIcon;
5716 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005717 AppendDITL(theDialog, iconDITL, overlayDITL);
5718 ReleaseResource(iconDITL);
5719 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005721 iconHandle = GetIcon(useIcon);
5722 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005723
5724 /* Add the message to the Dialog box. */
5725 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005726 messageDITL = GetResource('DITL', 132);
5727 AppendDITL(theDialog, messageDITL, overlayDITL);
5728 ReleaseResource(messageDITL);
5729 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5730 (void) C2PascalString(message, &name);
5731 SetDialogItemText(itemHandle, name);
5732 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733
5734 /* Add the input box if needed */
5735 if (textfield != NULL)
5736 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005737 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005738 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005739 inputDITL = GetResource('DITL', 132);
5740 AppendDITL(theDialog, inputDITL, overlayDITL);
5741 ReleaseResource(inputDITL);
5742 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5743/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5744 (void) C2PascalString(textfield, &name);
5745 SetDialogItemText(itemHandle, name);
5746 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005747
5748 /* Hotkeys don't make sense if there's a text field */
5749 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005750 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005751 else
5752 /* Install hotkey table */
5753 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754
5755 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005756 SetDialogDefaultItem(theDialog, dfltbutton);
5757 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005758
5759 /* Reposition element */
5760
5761 /* Check if we need to force vertical */
5762 if (totalButtonWidth > maximumWidth)
5763 vertical = TRUE;
5764
5765 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005766 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767 iconItm.box.right = box.right;
5768 iconItm.box.bottom = box.bottom;
5769
5770 /* Place Message */
5771 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005772 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5773 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005774
5775 /* Place Input */
5776 if (textfield != NULL)
5777 {
5778 inputItm.box.left = messageItm.box.left;
5779 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005780 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5781 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005782 /* Convert the static text into a text edit.
5783 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005784 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5785 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5787 }
5788
5789 /* Place Button */
5790 if (textfield != NULL)
5791 {
5792 buttonItm.box.left = inputItm.box.left;
5793 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5794 }
5795 else
5796 {
5797 buttonItm.box.left = messageItm.box.left;
5798 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5799 }
5800
5801 for (button=1; button <= lastButton; button++)
5802 {
5803
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005804 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005805 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005806 if (vertical)
5807 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005808 macSizeDialogItem(theDialog, button, widestButton, 0);
5809 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005810 }
5811 /* Calculate position of next button */
5812 if (vertical)
5813 buttonItm.box.top = box.bottom + dfltElementSpacing;
5814 else
5815 buttonItm.box.left = box.right + dfltElementSpacing;
5816 }
5817
5818 /* Resize the dialog box */
5819 dialogHeight = box.bottom + dfltElementSpacing;
5820 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5821
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005823 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005824 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825
5826 /* Display it */
5827 ShowWindow(theWindow);
5828/* BringToFront(theWindow); */
5829 SelectWindow(theWindow);
5830
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005831/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005833 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005834 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835#endif
5836
Bram Moolenaard68071d2006-05-02 22:08:30 +00005837#ifdef USE_CARBONKEYHANDLER
5838 /* Avoid that we use key events for the main window. */
5839 dialog_busy = TRUE;
5840#endif
5841
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005842 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5843 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5844
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845 /* Hang until one of the button is hit */
5846 do
5847 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005848 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849 } while ((itemHit < 1) || (itemHit > lastButton));
5850
Bram Moolenaard68071d2006-05-02 22:08:30 +00005851#ifdef USE_CARBONKEYHANDLER
5852 dialog_busy = FALSE;
5853#endif
5854
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855 /* Copy back the text entered by the user into the param */
5856 if (textfield != NULL)
5857 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005858 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5859 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860#if IOSIZE < 256
5861 /* Truncate the name to IOSIZE if needed */
5862 if (name[0] > IOSIZE)
5863 name[0] = IOSIZE - 1;
5864#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005865 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005866 }
5867
5868 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005869 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005871 /* Free the modal filterProc */
5872 DisposeRoutineDescriptor(dialogUPP);
5873
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005875 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005876
5877 return itemHit;
5878/*
5879 * Usefull thing which could be used
5880 * SetDialogTimeout(): Auto click a button after timeout
5881 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5882 * MoveDialogItem(): Probably better than SetDialogItem
5883 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005884 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885 */
5886}
5887#endif /* FEAT_DIALOG_GUI */
5888
5889/*
5890 * Display the saved error message(s).
5891 */
5892#ifdef USE_MCH_ERRMSG
5893 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005894display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895{
5896 char *p;
5897 char_u pError[256];
5898
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005899 if (error_ga.ga_data == NULL)
5900 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005902 /* avoid putting up a message box with blanks only */
5903 for (p = (char *)error_ga.ga_data; *p; ++p)
5904 if (!isspace(*p))
5905 {
5906 if (STRLEN(p) > 255)
5907 pError[0] = 255;
5908 else
5909 pError[0] = STRLEN(p);
5910
5911 STRNCPY(&pError[1], p, pError[0]);
5912 ParamText(pError, nil, nil, nil);
5913 Alert(128, nil);
5914 break;
5915 /* TODO: handled message longer than 256 chars
5916 * use auto-sizeable alert
5917 * or dialog with scrollbars (TextEdit zone)
5918 */
5919 }
5920 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005921}
5922#endif
5923
5924/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005925 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005926 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005927 void
5928gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929{
5930 Point where;
5931
5932 GetMouse(&where);
5933
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005934 *x = where.h;
5935 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936}
5937
5938 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005939gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005940{
5941 /* TODO */
5942#if 0
5943 /* From FAQ 3-11 */
5944
5945 CursorDevicePtr myMouse;
5946 Point where;
5947
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005948 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5949 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005950 {
5951 /* New way */
5952
5953 /*
5954 * Get first devoice with one button.
5955 * This will probably be the standad mouse
5956 * startat head of cursor dev list
5957 *
5958 */
5959
5960 myMouse = nil;
5961
5962 do
5963 {
5964 /* Get the next cursor device */
5965 CursorDeviceNextDevice(&myMouse);
5966 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005967 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005968
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005969 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005970 }
5971 else
5972 {
5973 /* Old way */
5974 where.h = x;
5975 where.v = y;
5976
5977 *(Point *)RawMouse = where;
5978 *(Point *)MTemp = where;
5979 *(Ptr) CrsrNew = 0xFFFF;
5980 }
5981#endif
5982}
5983
5984 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005985gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005986{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987/*
5988 * Clone PopUp to use menu
5989 * Create a object descriptor for the current selection
5990 * Call the procedure
5991 */
5992
5993 MenuHandle CntxMenu;
5994 Point where;
5995 OSStatus status;
5996 UInt32 CntxType;
5997 SInt16 CntxMenuID;
5998 UInt16 CntxMenuItem;
5999 Str255 HelpName = "";
6000 GrafPtr savePort;
6001
6002 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006003 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006004
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006005 GetMouse(&where);
6006 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006007 CntxMenu = menu->submenu_handle;
6008
6009 /* TODO: Get the text selection from Vim */
6010
6011 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006012 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006013 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014
6015 if (status == noErr)
6016 {
6017 if (CntxType == kCMMenuItemSelected)
6018 {
6019 /* Handle the menu CntxMenuID, CntxMenuItem */
6020 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006021 /* But what about the current menu, is the menu changed by
6022 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006023 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024 }
6025 else if (CntxMenuID == kCMShowHelpSelected)
6026 {
6027 /* Should come up with the help */
6028 }
6029 }
6030
6031 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006032 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033}
6034
6035#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6036/* TODO: Is it need for MACOS_X? (Dany) */
6037 void
6038mch_post_buffer_write(buf_T *buf)
6039{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006040 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6041 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006042}
6043#endif
6044
6045#ifdef FEAT_TITLE
6046/*
6047 * Set the window title and icon.
6048 * (The icon is not taken care of).
6049 */
6050 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006051gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006052{
6053 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6054 * that 256. Even better get it to fit nicely in the titlebar.
6055 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006056#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006057 CFStringRef windowTitle;
6058 size_t windowTitleLen;
6059#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006061#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062
6063 if (title == NULL) /* nothing to do */
6064 return;
6065
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006066#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006067 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00006068 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006069
6070 if (windowTitle)
6071 {
6072 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6073 CFRelease(windowTitle);
6074 }
6075#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006076 pascalTitle = C2Pascal_save(title);
6077 if (pascalTitle != NULL)
6078 {
6079 SetWTitle(gui.VimWindow, pascalTitle);
6080 vim_free(pascalTitle);
6081 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006082#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083}
6084#endif
6085
6086/*
6087 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6088 */
6089
6090 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006091C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092{
6093 char_u *PascalPtr = (char_u *) PascalString;
6094 int len;
6095 int i;
6096
6097 PascalPtr[0] = 0;
6098 if (CString == NULL)
6099 return 0;
6100
6101 len = STRLEN(CString);
6102 if (len > 255)
6103 len = 255;
6104
6105 for (i = 0; i < len; i++)
6106 PascalPtr[i+1] = CString[i];
6107
6108 PascalPtr[0] = len;
6109
6110 return 0;
6111}
6112
6113 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006114GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006115{
6116 /* From FAQ 8-12 */
6117 Str255 filePascal;
6118 CInfoPBRec myCPB;
6119 OSErr err;
6120
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006121 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122
6123 myCPB.dirInfo.ioNamePtr = filePascal;
6124 myCPB.dirInfo.ioVRefNum = 0;
6125 myCPB.dirInfo.ioFDirIndex = 0;
6126 myCPB.dirInfo.ioDrDirID = 0;
6127
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006128 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006129
6130 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006131 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006132
6133 /* TODO: Use an error code mechanism */
6134 return 0;
6135}
6136
6137/*
6138 * Convert a FSSpec to a fuill path
6139 */
6140
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006141char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006142{
6143 /*
6144 * TODO: Add protection for 256 char max.
6145 */
6146
6147 CInfoPBRec theCPB;
6148 char_u fname[256];
6149 char_u *filenamePtr = fname;
6150 OSErr error;
6151 int folder = 1;
6152#ifdef USE_UNIXFILENAME
6153 SInt16 dfltVol_vRefNum;
6154 SInt32 dfltVol_dirID;
6155 FSRef refFile;
6156 OSStatus status;
6157 UInt32 pathSize = 256;
6158 char_u pathname[256];
6159 char_u *path = pathname;
6160#else
6161 Str255 directoryName;
6162 char_u temporary[255];
6163 char_u *temporaryPtr = temporary;
6164#endif
6165
6166#ifdef USE_UNIXFILENAME
6167 /* Get the default volume */
6168 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006169 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006170
6171 if (error)
6172 return NULL;
6173#endif
6174
6175 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006176 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006177
6178 /* Get the info about the file specified in FSSpec */
6179 theCPB.dirInfo.ioFDirIndex = 0;
6180 theCPB.dirInfo.ioNamePtr = file.name;
6181 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006182 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006183 theCPB.dirInfo.ioDrDirID = file.parID;
6184
6185 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6186 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006187 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188
6189 /* If we are called for a new file we expect fnfErr */
6190 if ((error) && (error != fnfErr))
6191 return NULL;
6192
6193 /* Check if it's a file or folder */
6194 /* default to file if file don't exist */
6195 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6196 folder = 0; /* It's not a folder */
6197 else
6198 folder = 1;
6199
6200#ifdef USE_UNIXFILENAME
6201 /*
6202 * The function used here are available in Carbon, but
6203 * do nothing une MacOS 8 and 9
6204 */
6205 if (error == fnfErr)
6206 {
6207 /* If the file to be saved does not already exist, it isn't possible
6208 to convert its FSSpec into an FSRef. But we can construct an
6209 FSSpec for the file's parent folder (since we have its volume and
6210 directory IDs), and since that folder does exist, we can convert
6211 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6212 and, finally, append the filename. */
6213 FSSpec dirSpec;
6214 FSRef dirRef;
6215 Str255 emptyFilename = "\p";
6216 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6217 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6218 if (error)
6219 return NULL;
6220
6221 error = FSpMakeFSRef(&dirSpec, &dirRef);
6222 if (error)
6223 return NULL;
6224
6225 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6226 if (status)
6227 return NULL;
6228
6229 STRCAT(path, "/");
6230 STRCAT(path, filenamePtr);
6231 }
6232 else
6233 {
6234 /* If the file to be saved already exists, we can get its full path
6235 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006236 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237 if (error)
6238 return NULL;
6239
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006240 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006241 if (status)
6242 return NULL;
6243 }
6244
6245 /* Add a slash at the end if needed */
6246 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006247 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006249 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006250#else
6251 /* TODO: Get rid of all USE_UNIXFILENAME below */
6252 /* Set ioNamePtr, it's the same area which is always reused. */
6253 theCPB.dirInfo.ioNamePtr = directoryName;
6254
6255 /* Trick for first entry, set ioDrParID to the first value
6256 * we want for ioDrDirID*/
6257 theCPB.dirInfo.ioDrParID = file.parID;
6258 theCPB.dirInfo.ioDrDirID = file.parID;
6259
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006260 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006261 do
6262 {
6263 theCPB.dirInfo.ioFDirIndex = -1;
6264 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6265 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006266 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006267 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6268
6269 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6270 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006271 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272
6273 if (error)
6274 return NULL;
6275
6276 /* Put the new directoryName in front of the current fname */
6277 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006278 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006279 STRCAT(filenamePtr, ":");
6280 STRCAT(filenamePtr, temporaryPtr);
6281 }
6282#if 1 /* def USE_UNIXFILENAME */
6283 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6284 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6285#else
6286 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6287#endif
6288
6289 /* Get the information about the volume on which the file reside */
6290 theCPB.dirInfo.ioFDirIndex = -1;
6291 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6292 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006293 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6295
6296 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6297 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006298 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299
6300 if (error)
6301 return NULL;
6302
6303 /* For MacOS Classic always add the volume name */
6304 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006305 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306#ifdef USE_UNIXFILENAME
6307 if (file.vRefNum != dfltVol_vRefNum)
6308#endif
6309 {
6310 /* Add the volume name */
6311 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006312 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006313 STRCAT(filenamePtr, ":");
6314 STRCAT(filenamePtr, temporaryPtr);
6315
6316#ifdef USE_UNIXFILENAME
6317 STRCPY(temporaryPtr, filenamePtr);
6318 filenamePtr[0] = 0; /* NULL terminate the string */
6319 STRCAT(filenamePtr, "Volumes:");
6320 STRCAT(filenamePtr, temporaryPtr);
6321#endif
6322 }
6323
6324 /* Append final path separator if it's a folder */
6325 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006326 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006327
6328 /* As we use Unix File Name for MacOS X convert it */
6329#ifdef USE_UNIXFILENAME
6330 /* Need to insert leading / */
6331 /* TODO: get the above code to use directly the / */
6332 STRCPY(&temporaryPtr[1], filenamePtr);
6333 temporaryPtr[0] = '/';
6334 STRCPY(filenamePtr, temporaryPtr);
6335 {
6336 char *p;
6337 for (p = fname; *p; p++)
6338 if (*p == ':')
6339 *p = '/';
6340 }
6341#endif
6342
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006343 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006344#endif
6345}
6346
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006347#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006348/*
6349 * Input Method Control functions.
6350 */
6351
6352/*
6353 * Notify cursor position to IM.
6354 */
6355 void
6356im_set_position(int row, int col)
6357{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006358#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006359 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006360 im_start_row = row;
6361 im_start_col = col;
6362#endif
6363}
6364
6365static ScriptLanguageRecord gTSLWindow;
6366static ScriptLanguageRecord gTSLInsert;
6367static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6368
6369static Component gTSCWindow;
6370static Component gTSCInsert;
6371static Component gTSCDefault;
6372
6373static int im_initialized = 0;
6374
6375 static void
6376im_on_window_switch(int active)
6377{
6378 ScriptLanguageRecord *slptr = NULL;
6379 OSStatus err;
6380
6381 if (! gui.in_use)
6382 return;
6383
6384 if (im_initialized == 0)
6385 {
6386 im_initialized = 1;
6387
6388 /* save default TSM component (should be U.S.) to default */
6389 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6390 kKeyboardInputMethodClass);
6391 }
6392
6393 if (active == TRUE)
6394 {
6395 im_is_active = TRUE;
6396 ActivateTSMDocument(gTSMDocument);
6397 slptr = &gTSLWindow;
6398
6399 if (slptr)
6400 {
6401 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6402 kKeyboardInputMethodClass);
6403 if (err == noErr)
6404 err = SetTextServiceLanguage(slptr);
6405
6406 if (err == noErr)
6407 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6408 }
6409 }
6410 else
6411 {
6412 err = GetTextServiceLanguage(&gTSLWindow);
6413 if (err == noErr)
6414 slptr = &gTSLWindow;
6415
6416 if (slptr)
6417 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6418 kKeyboardInputMethodClass);
6419
6420 im_is_active = FALSE;
6421 DeactivateTSMDocument(gTSMDocument);
6422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423}
6424
6425/*
6426 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6427 */
6428 void
6429im_set_active(int active)
6430{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006431 ScriptLanguageRecord *slptr = NULL;
6432 OSStatus err;
6433
6434 if (! gui.in_use)
6435 return;
6436
6437 if (im_initialized == 0)
6438 {
6439 im_initialized = 1;
6440
6441 /* save default TSM component (should be U.S.) to default */
6442 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6443 kKeyboardInputMethodClass);
6444 }
6445
6446 if (active == TRUE)
6447 {
6448 im_is_active = TRUE;
6449 ActivateTSMDocument(gTSMDocument);
6450 slptr = &gTSLInsert;
6451
6452 if (slptr)
6453 {
6454 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6455 kKeyboardInputMethodClass);
6456 if (err == noErr)
6457 err = SetTextServiceLanguage(slptr);
6458
6459 if (err == noErr)
6460 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6461 }
6462 }
6463 else
6464 {
6465 err = GetTextServiceLanguage(&gTSLInsert);
6466 if (err == noErr)
6467 slptr = &gTSLInsert;
6468
6469 if (slptr)
6470 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6471 kKeyboardInputMethodClass);
6472
6473 /* restore to default when switch to normal mode, so than we could
6474 * enter commands easier */
6475 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6476 kKeyboardInputMethodClass);
6477 SetTextServiceLanguage(&gTSLDefault);
6478
6479 im_is_active = FALSE;
6480 DeactivateTSMDocument(gTSMDocument);
6481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006482}
6483
6484/*
6485 * Get IM status. When IM is on, return not 0. Else return 0.
6486 */
6487 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006488im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006490 if (! gui.in_use)
6491 return 0;
6492
6493 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006494}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006495
Bram Moolenaar071d4272004-06-13 20:20:40 +00006496#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006497
6498
6499
6500
6501#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6502// drawer implementation
6503static MenuRef contextMenu = NULL;
6504enum
6505{
6506 kTabContextMenuId = 42,
6507};
6508
6509// the caller has to CFRelease() the returned string
6510 static CFStringRef
6511getTabLabel(tabpage_T *page)
6512{
6513 get_tabline_label(page, FALSE);
6514#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006515 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006516#else
6517 // TODO: check internal encoding?
6518 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6519 kCFStringEncodingMacRoman);
6520#endif
6521}
6522
6523
6524#define DRAWER_SIZE 150
6525#define DRAWER_INSET 16
6526
6527static ControlRef dataBrowser = NULL;
6528
6529// when the tabline is hidden, vim doesn't call update_tabline(). When
6530// the tabline is shown again, show_tabline() is called before upate_tabline(),
6531// and because of this, the tab labels and vims internal tabs are out of sync
6532// for a very short time. to prevent inconsistent state, we store the labels
6533// of the tabs, not pointers to the tabs (which are invalid for a short time).
6534static CFStringRef *tabLabels = NULL;
6535static int tabLabelsSize = 0;
6536
6537enum
6538{
6539 kTabsColumn = 'Tabs'
6540};
6541
6542 static int
6543getTabCount(void)
6544{
6545 tabpage_T *tp;
6546 int numTabs = 0;
6547
6548 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006549 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006550 return numTabs;
6551}
6552
6553// data browser item display callback
6554 static OSStatus
6555dbItemDataCallback(ControlRef browser,
6556 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006557 DataBrowserPropertyID property /* column id */,
6558 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006559 Boolean changeValue)
6560{
6561 OSStatus status = noErr;
6562
6563 // assert(property == kTabsColumn); // why is this violated??
6564
6565 // changeValue is true if we have a modifieable list and data was changed.
6566 // In our case, it's always false.
6567 // (that is: if (changeValue) updateInternalData(); else return
6568 // internalData();
6569 if (!changeValue)
6570 {
6571 CFStringRef str;
6572
6573 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6574 str = tabLabels[itemID - 1];
6575 status = SetDataBrowserItemDataText(itemData, str);
6576 }
6577 else
6578 status = errDataBrowserPropertyNotSupported;
6579
6580 return status;
6581}
6582
6583// data browser action callback
6584 static void
6585dbItemNotificationCallback(ControlRef browser,
6586 DataBrowserItemID item,
6587 DataBrowserItemNotification message)
6588{
6589 switch (message)
6590 {
6591 case kDataBrowserItemSelected:
6592 send_tabline_event(item);
6593 break;
6594 }
6595}
6596
6597// callbacks needed for contextual menu:
6598 static void
6599dbGetContextualMenuCallback(ControlRef browser,
6600 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006601 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006602 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006603 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006604{
6605 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6606 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6607 *helpItemString = NULL;
6608
6609 *menu = contextMenu;
6610}
6611
6612 static void
6613dbSelectContextualMenuCallback(ControlRef browser,
6614 MenuRef menu,
6615 UInt32 selectionType,
6616 SInt16 menuID,
6617 MenuItemIndex menuItem)
6618{
6619 if (selectionType == kCMMenuItemSelected)
6620 {
6621 MenuCommand command;
6622 GetMenuItemCommandID(menu, menuItem, &command);
6623
6624 // get tab that was selected when the context menu appeared
6625 // (there is always one tab selected). TODO: check if the context menu
6626 // isn't opened on an item but on empty space (has to be possible some
6627 // way, the finder does it too ;-) )
6628 Handle items = NewHandle(0);
6629 if (items != NULL)
6630 {
6631 int numItems;
6632
6633 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6634 kDataBrowserItemIsSelected, items);
6635 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6636 if (numItems > 0)
6637 {
6638 int idx;
6639 DataBrowserItemID *itemsPtr;
6640
6641 HLock(items);
6642 itemsPtr = (DataBrowserItemID *)*items;
6643 idx = itemsPtr[0];
6644 HUnlock(items);
6645 send_tabline_menu_event(idx, command);
6646 }
6647 DisposeHandle(items);
6648 }
6649 }
6650}
6651
6652// focus callback of the data browser to always leave focus in vim
6653 static OSStatus
6654dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6655{
6656 assert(GetEventClass(event) == kEventClassControl
6657 && GetEventKind(event) == kEventControlSetFocusPart);
6658
6659 return paramErr;
6660}
6661
6662
6663// drawer callback to resize data browser to drawer size
6664 static OSStatus
6665drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6666{
6667 switch (GetEventKind(event))
6668 {
6669 case kEventWindowBoundsChanged: // move or resize
6670 {
6671 UInt32 attribs;
6672 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6673 NULL, sizeof(attribs), NULL, &attribs);
6674 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6675 {
6676 Rect r;
6677 GetWindowBounds(drawer, kWindowContentRgn, &r);
6678 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6679 SetControlBounds(dataBrowser, &r);
6680 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6681 kTabsColumn, r.right);
6682 }
6683 }
6684 break;
6685 }
6686
6687 return eventNotHandledErr;
6688}
6689
6690// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6691// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6692// blue highlights in the list view on these systems, though. Oh well.)
6693
6694
6695#import <mach-o/dyld.h>
6696
6697enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6698
6699 static OSStatus
6700myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6701 OptionBits inAttributesToSet,
6702 OptionBits inAttributesToClear)
6703{
6704 long osVersion;
6705 char *symbolName;
6706 NSSymbol symbol = NULL;
6707 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6708 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6709
6710 Gestalt(gestaltSystemVersion, &osVersion);
6711 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6712 return noErr;
6713
6714 // C name mangling...
6715 symbolName = "_DataBrowserChangeAttributes";
6716 if (!NSIsSymbolNameDefined(symbolName)
6717 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6718 return noErr;
6719
6720 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6721 if (dataBrowserChangeAttributes == NULL)
6722 return noErr; // well...
6723 return dataBrowserChangeAttributes(inDataBrowser,
6724 inAttributesToSet, inAttributesToClear);
6725}
6726
6727 static void
6728initialise_tabline(void)
6729{
6730 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6731 DataBrowserCallbacks dbCallbacks;
6732 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6733 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6734 DataBrowserListViewColumnDesc colDesc;
6735
6736 // drawers have to have compositing enabled
6737 CreateNewWindow(kDrawerWindowClass,
6738 kWindowStandardHandlerAttribute
6739 | kWindowCompositingAttribute
6740 | kWindowResizableAttribute
6741 | kWindowLiveResizeAttribute,
6742 &drawerRect, &drawer);
6743
6744 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6745 SetDrawerParent(drawer, gui.VimWindow);
6746 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6747
6748
6749 // create list view embedded in drawer
6750 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6751 &dataBrowser);
6752
6753 dbCallbacks.version = kDataBrowserLatestCallbacks;
6754 InitDataBrowserCallbacks(&dbCallbacks);
6755 dbCallbacks.u.v1.itemDataCallback =
6756 NewDataBrowserItemDataUPP(dbItemDataCallback);
6757 dbCallbacks.u.v1.itemNotificationCallback =
6758 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6759 dbCallbacks.u.v1.getContextualMenuCallback =
6760 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6761 dbCallbacks.u.v1.selectContextualMenuCallback =
6762 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6763
6764 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6765
6766 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6767 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6768 SetDataBrowserSelectionFlags(dataBrowser,
6769 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6770 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6771 kDataBrowserTableViewFillHilite);
6772 Boolean b = false;
6773 SetControlData(dataBrowser, kControlEntireControl,
6774 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6775
6776 // enable blue background in data browser (this is only in 10.4 and vim
6777 // has to support older osx versions as well, so we have to load this
6778 // function dynamically)
6779 myDataBrowserChangeAttributes(dataBrowser,
6780 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6781
6782 // install callback that keeps focus in vim and away from the data browser
6783 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6784 NULL, NULL);
6785
6786 // install callback that keeps data browser at the size of the drawer
6787 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6788 NULL, NULL);
6789
6790 // add "tabs" column to data browser
6791 colDesc.propertyDesc.propertyID = kTabsColumn;
6792 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6793
6794 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6795 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6796
6797 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6798 colDesc.headerBtnDesc.minimumWidth = 100;
6799 colDesc.headerBtnDesc.maximumWidth = 150;
6800 colDesc.headerBtnDesc.titleOffset = 0;
6801 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6802 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6803 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6804 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6805
6806 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6807
6808 // create tabline popup menu required by vim docs (see :he tabline-menu)
6809 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6810 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6811 TABLINE_MENU_CLOSE, NULL);
6812 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6813 TABLINE_MENU_NEW, NULL);
6814 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6815 TABLINE_MENU_OPEN, NULL);
6816}
6817
6818
6819/*
6820 * Show or hide the tabline.
6821 */
6822 void
6823gui_mch_show_tabline(int showit)
6824{
6825 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006826 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006827 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006828 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006829}
6830
6831/*
6832 * Return TRUE when tabline is displayed.
6833 */
6834 int
6835gui_mch_showing_tabline(void)
6836{
6837 WindowDrawerState state = GetDrawerState(drawer);
6838
6839 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6840}
6841
6842/*
6843 * Update the labels of the tabline.
6844 */
6845 void
6846gui_mch_update_tabline(void)
6847{
6848 tabpage_T *tp;
6849 int numTabs = getTabCount();
6850 int nr = 1;
6851 int curtabidx = 1;
6852
6853 // adjust data browser
6854 if (tabLabels != NULL)
6855 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006856 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006857
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006858 for (i = 0; i < tabLabelsSize; ++i)
6859 CFRelease(tabLabels[i]);
6860 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006861 }
6862 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6863 tabLabelsSize = numTabs;
6864
6865 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6866 {
6867 if (tp == curtab)
6868 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006869 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006870 }
6871
6872 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6873 kDataBrowserItemNoProperty);
6874 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6875 // can pass NULL for the id array
6876 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6877 kDataBrowserItemNoProperty);
6878
6879 DataBrowserItemID item = curtabidx;
6880 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6881}
6882
6883/*
6884 * Set the current tab to "nr". First tab is 1.
6885 */
6886 void
6887gui_mch_set_curtab(nr)
6888 int nr;
6889{
6890 DataBrowserItemID item = nr;
6891 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6892
6893 // TODO: call something like this?: (or restore scroll position, or...)
6894 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6895 kDataBrowserRevealOnly);
6896}
6897
6898#endif // FEAT_GUI_TABLINE