blob: b3c6f1f5409e6558753922c92f91298d65ce544b [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);
487 name = mac_enc_to_cfstring(menu->dname, menuTitleLen);
488
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{
2546 EventRef bogusEvent;
2547 Point point;
2548 Rect bounds;
2549 UInt32 mod;
2550 SInt32 delta;
2551 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002552 EventMouseWheelAxis axis;
2553
2554 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2555 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2556 && axis != kEventMouseWheelAxisY)
2557 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558
2559 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2560 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2561 goto bail;
2562 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2563 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2564 goto bail;
2565 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2566 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2567 goto bail;
2568
2569 vim_mod = 0;
2570 if (mod & shiftKey)
2571 vim_mod |= MOUSE_SHIFT;
2572 if (mod & controlKey)
2573 vim_mod |= MOUSE_CTRL;
2574 if (mod & optionKey)
2575 vim_mod |= MOUSE_ALT;
2576
2577 /* post a bogus event to wake up WaitNextEvent */
2578 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2579 kEventAttributeNone, &bogusEvent))
2580 goto bail;
2581 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2582 kEventPriorityLow))
2583 goto bail;
2584
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002585 ReleaseEvent(bogusEvent);
2586
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2588 {
2589 point.h -= bounds.left;
2590 point.v -= bounds.top;
2591 }
2592
2593 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2594 point.h, point.v, FALSE, vim_mod);
2595
2596 return noErr;
2597
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002598bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 /*
2600 * when we fail give any additional callback handler a chance to perform
2601 * it's actions
2602 */
2603 return CallNextEventHandler(nextHandler, theEvent);
2604}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605
2606#if 0
2607
2608/*
2609 * This would be the normal way of invoking the contextual menu
2610 * but the Vim API doesn't seem to a support a request to get
2611 * the menu that we should display
2612 */
2613 void
2614gui_mac_handle_contextual_menu(event)
2615 EventRecord *event;
2616{
2617/*
2618 * Clone PopUp to use menu
2619 * Create a object descriptor for the current selection
2620 * Call the procedure
2621 */
2622
2623// Call to Handle Popup
2624 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2625
2626 if (status != noErr)
2627 return;
2628
2629 if (CntxType == kCMMenuItemSelected)
2630 {
2631 /* Handle the menu CntxMenuID, CntxMenuItem */
2632 /* The submenu can be handle directly by gui_mac_handle_menu */
2633 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002634 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 }
2636 else if (CntxMenuID == kCMShowHelpSelected)
2637 {
2638 /* Should come up with the help */
2639 }
2640
2641}
2642#endif
2643
2644/*
2645 * Handle menubar selection
2646 */
2647 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002648gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649{
2650 short menu = HiWord(menuChoice);
2651 short item = LoWord(menuChoice);
2652 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653
2654 if (menu == 256) /* TODO: use constant or gui.xyz */
2655 {
2656 if (item == 1)
2657 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 }
2659 else if (item != 0)
2660 {
2661 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2662
2663 if (theVimMenu)
2664 gui_menu_cb(theVimMenu);
2665 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002666 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667}
2668
2669/*
2670 * Dispatch the event to proper handler
2671 */
2672
2673 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002674gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675{
2676 OSErr error;
2677
2678 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002679 if (IsShowContextualMenuClick(event))
2680 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002682 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002684 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002686 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002687 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688
2689 /* Handle normal event */
2690 switch (event->what)
2691 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002692#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 case (keyDown):
2694 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002695 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002697#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002699 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 break;
2701
2702 case (mouseDown):
2703 gui_mac_doMouseDownEvent(event);
2704 break;
2705
2706 case (mouseUp):
2707 gui_mac_doMouseUpEvent(event);
2708 break;
2709
2710 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002711 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 break;
2713
2714 case (diskEvt):
2715 /* We don't need special handling for disk insertion */
2716 break;
2717
2718 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002719 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 break;
2721
2722 case (osEvt):
2723 switch ((event->message >> 24) & 0xFF)
2724 {
2725 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002726 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 break;
2728 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002729 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 break;
2731 }
2732 break;
2733
2734#ifdef USE_AEVENT
2735 case (kHighLevelEvent):
2736 /* Someone's talking to us, through AppleEvents */
2737 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2738 break;
2739#endif
2740 }
2741}
2742
2743/*
2744 * ------------------------------------------------------------
2745 * Unknown Stuff
2746 * ------------------------------------------------------------
2747 */
2748
2749
2750 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002751gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752{
2753 char_u c;
2754 char_u *p;
2755 char_u pFontName[256];
2756 Str255 systemFontname;
2757 short font_id;
2758 short size=9;
2759 GuiFont font;
2760#if 0
2761 char_u *fontNamePtr;
2762#endif
2763
2764 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2765 ;
2766
2767 c = *p;
2768 *p = 0;
2769
2770#if 1
2771 STRCPY(&pFontName[1], font_name);
2772 pFontName[0] = STRLEN(font_name);
2773 *p = c;
2774
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002775 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002776 char_u fontName[256];
2777 char_u *styleStart = vim_strchr(font_name, ':');
2778 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2779 vim_strncpy(fontName, font_name, fontNameLen);
2780
2781 ATSUFontID fontRef;
2782 FMFontStyle fontStyle;
2783 font_id = 0;
2784
2785 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2786 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2787 &fontRef) == noErr)
2788 {
2789 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2790 font_id = 0;
2791 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002792
2793 if (font_id == 0)
2794 {
2795 /*
2796 * Try again, this time replacing underscores in the font name
2797 * with spaces (:set guifont allows the two to be used
2798 * interchangeably; the Font Manager doesn't).
2799 */
2800 int i, changed = FALSE;
2801
2802 for (i = pFontName[0]; i > 0; --i)
2803 {
2804 if (pFontName[i] == '_')
2805 {
2806 pFontName[i] = ' ';
2807 changed = TRUE;
2808 }
2809 }
2810 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002811 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2812 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2813 kFontNoLanguageCode, &fontRef) == noErr)
2814 {
2815 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2816 font_id = 0;
2817 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002818 }
2819
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820#else
2821 /* name = C2Pascal_save(menu->dname); */
2822 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2823
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002824 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825#endif
2826
2827
2828 if (font_id == 0)
2829 {
2830 /* Oups, the system font was it the one the user want */
2831
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002832 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2833 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834 if (!EqualString(pFontName, systemFontname, false, false))
2835 return NOFONT;
2836 }
2837 if (*p == ':')
2838 {
2839 p++;
2840 /* Set the values found after ':' */
2841 while (*p)
2842 {
2843 switch (*p++)
2844 {
2845 case 'h':
2846 size = points_to_pixels(p, &p, TRUE);
2847 break;
2848 /*
2849 * TODO: Maybe accept width and styles
2850 */
2851 }
2852 while (*p == ':')
2853 p++;
2854 }
2855 }
2856
2857 if (size < 1)
2858 size = 1; /* Avoid having a size of 0 with system font */
2859
2860 font = (size << 16) + ((long) font_id & 0xFFFF);
2861
2862 return font;
2863}
2864
2865/*
2866 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002867 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 * ------------------------------------------------------------
2869 */
2870
2871/*
2872 * Parse the GUI related command-line arguments. Any arguments used are
2873 * deleted from argv, and *argc is decremented accordingly. This is called
2874 * when vim is started, whether or not the GUI has been started.
2875 */
2876 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002877gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878{
2879 /* TODO: Move most of this stuff toward gui_mch_init */
2880#ifdef USE_EXE_NAME
2881 FSSpec applDir;
2882# ifndef USE_FIND_BUNDLE_PATH
2883 short applVRefNum;
2884 long applDirID;
2885 Str255 volName;
2886# else
2887 ProcessSerialNumber psn;
2888 FSRef applFSRef;
2889# endif
2890#endif
2891
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892#if 0
2893 InitCursor();
2894
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896
2897#ifdef USE_AEVENT
2898 (void) InstallAEHandlers();
2899#endif
2900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002901 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002903 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002905 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002906
2907 DrawMenuBar();
2908
2909
2910#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002911 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002913 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914#endif
2915
2916
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 CreateNewWindow(kDocumentWindowClass,
2918 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002919 &windRect, &gui.VimWindow);
2920 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921
2922 gui.char_width = 7;
2923 gui.char_height = 11;
2924 gui.char_ascent = 6;
2925 gui.num_rows = 24;
2926 gui.num_cols = 80;
2927 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2928
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002929 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2930 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931
2932 dragRectEnbl = FALSE;
2933 dragRgn = NULL;
2934 dragRectControl = kCreateEmpty;
2935 cursorRgn = NewRgn();
2936#endif
2937#ifdef USE_EXE_NAME
2938# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002939 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002941 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942# else
2943 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2944 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 /* if (err != noErr) return err; */
2948
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002949 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 /* if (err != noErr) return err; */
2951
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002952 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953
2954 /* This technic return NIL when we disallow_gui */
2955# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002956 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958}
2959
2960#ifndef ALWAYS_USE_GUI
2961/*
2962 * Check if the GUI can be started. Called before gvimrc is sourced.
2963 * Return OK or FAIL.
2964 */
2965 int
2966gui_mch_init_check(void)
2967{
2968 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2969 * using the >console
2970 */
2971 if (disallow_gui) /* see main.c for reason to disallow */
2972 return FAIL;
2973 return OK;
2974}
2975#endif
2976
2977 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002978receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979{
2980 int x, y;
2981 int_u modifiers;
2982 char_u **fnames = NULL;
2983 int count;
2984 int i, j;
2985
2986 /* Get drop position, modifiers and count of items */
2987 {
2988 Point point;
2989 SInt16 mouseUpModifiers;
2990 UInt16 countItem;
2991
2992 GetDragMouse(theDrag, &point, NULL);
2993 GlobalToLocal(&point);
2994 x = point.h;
2995 y = point.v;
2996 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2997 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2998 CountDragItems(theDrag, &countItem);
2999 count = countItem;
3000 }
3001
3002 fnames = (char_u **)alloc(count * sizeof(char_u *));
3003 if (fnames == NULL)
3004 return dragNotAcceptedErr;
3005
3006 /* Get file names dropped */
3007 for (i = j = 0; i < count; ++i)
3008 {
3009 DragItemRef item;
3010 OSErr err;
3011 Size size;
3012 FlavorType type = flavorTypeHFS;
3013 HFSFlavor hfsFlavor;
3014
3015 fnames[i] = NULL;
3016 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3017 err = GetFlavorDataSize(theDrag, item, type, &size);
3018 if (err != noErr || size > sizeof(hfsFlavor))
3019 continue;
3020 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3021 if (err != noErr)
3022 continue;
3023 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3024 }
3025 count = j;
3026
3027 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003028
3029 /* Fake mouse event to wake from stall */
3030 PostEvent(mouseUp, 0);
3031
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032 return noErr;
3033}
3034
3035/*
3036 * Initialise the GUI. Create all the windows, set up all the call-backs
3037 * etc.
3038 */
3039 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003040gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041{
3042 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003043 Rect windRect;
3044 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003046 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003047 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003048
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003049 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003050 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003051
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052#if 1
3053 InitCursor();
3054
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056
3057#ifdef USE_AEVENT
3058 (void) InstallAEHandlers();
3059#endif
3060
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003061 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003063 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003065 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066
3067 DrawMenuBar();
3068
3069
3070#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003071 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003072#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003073 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074#endif
3075
3076 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003078 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003079 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3081 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003082 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083
3084 gui.char_width = 7;
3085 gui.char_height = 11;
3086 gui.char_ascent = 6;
3087 gui.num_rows = 24;
3088 gui.num_cols = 80;
3089 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3090
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003091 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3092 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003094 /* Install Carbon event callbacks. */
3095 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096
3097 dragRectEnbl = FALSE;
3098 dragRgn = NULL;
3099 dragRectControl = kCreateEmpty;
3100 cursorRgn = NewRgn();
3101#endif
3102 /* Display any pending error messages */
3103 display_errors();
3104
3105 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003106 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 gui.norm_pixel = 0x00000000;
3108 gui.back_pixel = 0x00FFFFFF;
3109
3110 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3111 * file). */
3112 set_normal_colors();
3113
3114 /*
3115 * Check that none of the colors are the same as the background color.
3116 * Then store the current values as the defaults.
3117 */
3118 gui_check_colors();
3119 gui.def_norm_pixel = gui.norm_pixel;
3120 gui.def_back_pixel = gui.back_pixel;
3121
3122 /* Get the colors for the highlight groups (gui_check_colors() might have
3123 * changed them) */
3124 highlight_gui_started();
3125
3126 /*
3127 * Setting the gui constants
3128 */
3129#ifdef FEAT_MENU
3130 gui.menu_height = 0;
3131#endif
3132 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3133 gui.border_offset = gui.border_width = 2;
3134
Bram Moolenaar720c7102007-05-10 18:07:50 +00003135 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 gui_mch_draw_string() below), enable it for all font sizes. */
3137 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 eventTypeSpec.eventClass = kEventClassMouse;
3140 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3141 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3142 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3143 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3144 {
3145 mouseWheelHandlerRef = NULL;
3146 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3147 mouseWheelHandlerUPP = NULL;
3148 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003150#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003151 InterfaceTypeList supportedServices = { kUnicodeDocument };
3152 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3153
3154 /* We don't support inline input yet, use input window by default */
3155 UseInputWindow(gTSMDocument, TRUE);
3156
3157 /* Should we activate the document by default? */
3158 // ActivateTSMDocument(gTSMDocument);
3159
3160 EventTypeSpec textEventTypes[] = {
3161 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3162 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3163 { kEventClassTextInput, kEventTextInputPosToOffset },
3164 { kEventClassTextInput, kEventTextInputOffsetToPos },
3165 };
3166
3167 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3168 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3169 NR_ELEMS(textEventTypes),
3170 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003171 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003172 DisposeEventHandlerUPP(keyEventHandlerUPP);
3173 keyEventHandlerUPP = NULL;
3174 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003175
3176 EventTypeSpec windowEventTypes[] = {
3177 { kEventClassWindow, kEventWindowActivated },
3178 { kEventClassWindow, kEventWindowDeactivated },
3179 };
3180
3181 /* Install window event handler to support TSMDocument activate and
3182 * deactivate */
3183 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3184 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3185 winEventHandlerUPP,
3186 NR_ELEMS(windowEventTypes),
3187 windowEventTypes, NULL, NULL))
3188 {
3189 DisposeEventHandlerUPP(winEventHandlerUPP);
3190 winEventHandlerUPP = NULL;
3191 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192#endif
3193
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003194/*
3195#ifdef FEAT_MBYTE
3196 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3197#endif
3198*/
3199
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003200#ifdef FEAT_GUI_TABLINE
3201 /*
3202 * Create the tabline
3203 */
3204 initialise_tabline();
3205#endif
3206
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 /* TODO: Load bitmap if using TOOLBAR */
3208 return OK;
3209}
3210
3211/*
3212 * Called when the foreground or background color has been changed.
3213 */
3214 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003215gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216{
3217 /* TODO:
3218 * This proc is called when Normal is set to a value
3219 * so what msut be done? I don't know
3220 */
3221}
3222
3223/*
3224 * Open the GUI window which was created by a call to gui_mch_init().
3225 */
3226 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003227gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228{
3229 ShowWindow(gui.VimWindow);
3230
3231 if (gui_win_x != -1 && gui_win_y != -1)
3232 gui_mch_set_winpos(gui_win_x, gui_win_y);
3233
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 /*
3235 * Make the GUI the foreground process (in case it was launched
3236 * from the Terminal or via :gui).
3237 */
3238 {
3239 ProcessSerialNumber psn;
3240 if (GetCurrentProcess(&psn) == noErr)
3241 SetFrontProcess(&psn);
3242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243
3244 return OK;
3245}
3246
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003247#ifdef USE_ATSUI_DRAWING
3248 static void
3249gui_mac_dispose_atsui_style(void)
3250{
3251 if (p_macatsui && gFontStyle)
3252 ATSUDisposeStyle(gFontStyle);
3253#ifdef FEAT_MBYTE
3254 if (p_macatsui && gWideFontStyle)
3255 ATSUDisposeStyle(gWideFontStyle);
3256#endif
3257}
3258#endif
3259
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 void
3261gui_mch_exit(int rc)
3262{
3263 /* TODO: find out all what is missing here? */
3264 DisposeRgn(cursorRgn);
3265
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003266#ifdef USE_CARBONKEYHANDLER
3267 if (keyEventHandlerUPP)
3268 DisposeEventHandlerUPP(keyEventHandlerUPP);
3269#endif
3270
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271 if (mouseWheelHandlerUPP != NULL)
3272 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003274#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003275 gui_mac_dispose_atsui_style();
3276#endif
3277
3278#ifdef USE_CARBONKEYHANDLER
3279 FixTSMDocument(gTSMDocument);
3280 DeactivateTSMDocument(gTSMDocument);
3281 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003282#endif
3283
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284 /* Exit to shell? */
3285 exit(rc);
3286}
3287
3288/*
3289 * Get the position of the top left corner of the window.
3290 */
3291 int
3292gui_mch_get_winpos(int *x, int *y)
3293{
3294 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 Rect bounds;
3296 OSStatus status;
3297
3298 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003299 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300
3301 if (status != noErr)
3302 return FAIL;
3303 *x = bounds.left;
3304 *y = bounds.top;
3305 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 return FAIL;
3307}
3308
3309/*
3310 * Set the position of the top left corner of the window to the given
3311 * coordinates.
3312 */
3313 void
3314gui_mch_set_winpos(int x, int y)
3315{
3316 /* TODO: Should make sure the window is move within range
3317 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3318 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003319 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320}
3321
3322 void
3323gui_mch_set_shellsize(
3324 int width,
3325 int height,
3326 int min_width,
3327 int min_height,
3328 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003329 int base_height,
3330 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332 CGrafPtr VimPort;
3333 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334
3335 if (gui.which_scrollbars[SBAR_LEFT])
3336 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003337 VimPort = GetWindowPort(gui.VimWindow);
3338 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 }
3343 else
3344 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003345 VimPort = GetWindowPort(gui.VimWindow);
3346 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003348 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 }
3350
3351 SizeWindow(gui.VimWindow, width, height, TRUE);
3352
3353 gui_resize_shell(width, height);
3354}
3355
3356/*
3357 * Get the screen dimensions.
3358 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3359 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003360 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361 */
3362 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003363gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003364{
3365 GDHandle dominantDevice = GetMainDevice();
3366 Rect screenRect = (**dominantDevice).gdRect;
3367
3368 *screen_w = screenRect.right - 10;
3369 *screen_h = screenRect.bottom - 40;
3370}
3371
3372
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003373/*
3374 * Open the Font Panel and wait for the user to select a font and
3375 * close the panel. Then fill the buffer pointed to by font_name with
3376 * the name and size of the selected font and return the font's handle,
3377 * or NOFONT in case of an error.
3378 */
3379 static GuiFont
3380gui_mac_select_font(char_u *font_name)
3381{
3382 GuiFont selected_font = NOFONT;
3383 OSStatus status;
3384 FontSelectionQDStyle curr_font;
3385
3386 /* Initialize the Font Panel with the current font. */
3387 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3388 curr_font.size = (gui.norm_font >> 16);
3389 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3390 curr_font.instance.fontStyle = 0;
3391 curr_font.hasColor = false;
3392 curr_font.version = 0; /* version number of the style structure */
3393 status = SetFontInfoForSelection(kFontSelectionQDType,
3394 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3395
3396 gFontPanelInfo.family = curr_font.instance.fontFamily;
3397 gFontPanelInfo.style = curr_font.instance.fontStyle;
3398 gFontPanelInfo.size = curr_font.size;
3399
3400 /* Pop up the Font Panel. */
3401 status = FPShowHideFontPanel();
3402 if (status == noErr)
3403 {
3404 /*
3405 * The Font Panel is modeless. We really need it to be modal,
3406 * so we spin in an event loop until the panel is closed.
3407 */
3408 gFontPanelInfo.isPanelVisible = true;
3409 while (gFontPanelInfo.isPanelVisible)
3410 {
3411 EventRecord e;
3412 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3413 }
3414
3415 GetFontPanelSelection(font_name);
3416 selected_font = gui_mac_find_font(font_name);
3417 }
3418 return selected_font;
3419}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003420
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003421#ifdef USE_ATSUI_DRAWING
3422 static void
3423gui_mac_create_atsui_style(void)
3424{
3425 if (p_macatsui && gFontStyle == NULL)
3426 {
3427 if (ATSUCreateStyle(&gFontStyle) != noErr)
3428 gFontStyle = NULL;
3429 }
3430#ifdef FEAT_MBYTE
3431 if (p_macatsui && gWideFontStyle == NULL)
3432 {
3433 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3434 gWideFontStyle = NULL;
3435 }
3436#endif
3437
3438 p_macatsui_last = p_macatsui;
3439}
3440#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441
3442/*
3443 * Initialise vim to use the font with the given name. Return FAIL if the font
3444 * could not be loaded, OK otherwise.
3445 */
3446 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003447gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448{
3449 /* TODO: Add support for bold italic underline proportional etc... */
3450 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003451 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 FontInfo font_info;
3453 short font_id;
3454 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003455 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003457#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003458 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003459#endif
3460
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 if (font_name == NULL)
3462 {
3463 /* First try to get the suggested font */
3464 GetFNum(suggestedFont, &font_id);
3465
3466 if (font_id == 0)
3467 {
3468 /* Then pickup the standard application font */
3469 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003470 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003472 else
3473 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003474 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3475 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003476 else if (STRCMP(font_name, "*") == 0)
3477 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003478 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003479
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003481 if (font == NOFONT)
3482 return FAIL;
3483
3484 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003485 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003486 if (new_p_guifont != NULL)
3487 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003488 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003489 vim_free(p_guifont);
3490 p_guifont = new_p_guifont;
3491 /* Replace spaces in the font name with underscores. */
3492 for ( ; *new_p_guifont; ++new_p_guifont)
3493 {
3494 if (*new_p_guifont == ' ')
3495 *new_p_guifont = '_';
3496 }
3497 }
3498 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 else
3500 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003501 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003502 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503
3504 if (font == NOFONT)
3505 return FAIL;
3506 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003507
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 gui.norm_font = font;
3509
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003510 hl_set_font_name(used_font_name);
3511
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003512 TextSize(font >> 16);
3513 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003515 GetFontInfo(&font_info);
3516
3517 gui.char_ascent = font_info.ascent;
3518 gui.char_width = CharWidth('_');
3519 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3520
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003521#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003522 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003523 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003524#endif
3525
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527}
3528
Bram Moolenaar02743632005-07-25 20:42:36 +00003529/*
3530 * Adjust gui.char_height (after 'linespace' was changed).
3531 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003533gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534{
3535 FontInfo font_info;
3536
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003537 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3539 gui.char_ascent = font_info.ascent + p_linespace / 2;
3540 return OK;
3541}
3542
3543/*
3544 * Get a font structure for highlighting.
3545 */
3546 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003547gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548{
3549 GuiFont font;
3550
3551 font = gui_mac_find_font(name);
3552
3553 if (font == NOFONT)
3554 {
3555 if (giveErrorIfMissing)
3556 EMSG2(_(e_font), name);
3557 return NOFONT;
3558 }
3559 /*
3560 * TODO : Accept only monospace
3561 */
3562
3563 return font;
3564}
3565
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003566#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003568 * Return the name of font "font" in allocated memory.
3569 * Don't know how to get the actual name, thus use the provided name.
3570 */
3571 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003572gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003573{
3574 if (name == NULL)
3575 return NULL;
3576 return vim_strsave(name);
3577}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003578#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003579
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003580#ifdef USE_ATSUI_DRAWING
3581 static void
3582gui_mac_set_font_attributes(GuiFont font)
3583{
3584 ATSUFontID fontID;
3585 Fixed fontSize;
3586 Fixed fontWidth;
3587
3588 fontID = font & 0xFFFF;
3589 fontSize = Long2Fix(font >> 16);
3590 fontWidth = Long2Fix(gui.char_width);
3591
3592 ATSUAttributeTag attribTags[] =
3593 {
3594 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3595 kATSUMaxATSUITagValue + 1
3596 };
3597
3598 ByteCount attribSizes[] =
3599 {
3600 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3601 sizeof(font)
3602 };
3603
3604 ATSUAttributeValuePtr attribValues[] =
3605 {
3606 &fontID, &fontSize, &fontWidth, &font
3607 };
3608
3609 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3610 {
3611 if (ATSUSetAttributes(gFontStyle,
3612 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3613 attribTags, attribSizes, attribValues) != noErr)
3614 {
3615# ifndef NDEBUG
3616 fprintf(stderr, "couldn't set font style\n");
3617# endif
3618 ATSUDisposeStyle(gFontStyle);
3619 gFontStyle = NULL;
3620 }
3621
3622#ifdef FEAT_MBYTE
3623 if (has_mbyte)
3624 {
3625 /* FIXME: we should use a more mbyte sensitive way to support
3626 * wide font drawing */
3627 fontWidth = Long2Fix(gui.char_width * 2);
3628
3629 if (ATSUSetAttributes(gWideFontStyle,
3630 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3631 attribTags, attribSizes, attribValues) != noErr)
3632 {
3633 ATSUDisposeStyle(gWideFontStyle);
3634 gWideFontStyle = NULL;
3635 }
3636 }
3637#endif
3638 }
3639}
3640#endif
3641
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003642/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003643 * Set the current text font.
3644 */
3645 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003646gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003648#ifdef USE_ATSUI_DRAWING
3649 GuiFont currFont;
3650 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003651
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003652 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003653 {
3654 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003655 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3656 sizeof(font), &currFont, &actualFontByteCount) == noErr
3657 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003658 {
3659 if (currFont == font)
3660 return;
3661 }
3662
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003663 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003664 }
3665
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003666 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003667 {
3668 /* Setup automatic font substitution. The user's guifontwide
3669 * is tried first, then the system tries other fonts. */
3670/*
3671 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3672 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3673 ATSUCreateFontFallbacks(&gFontFallbacks);
3674 ATSUSetObjFontFallbacks(gFontFallbacks, );
3675*/
3676 if (gui.wide_font)
3677 {
3678 ATSUFontID fallbackFonts;
3679 gIsFontFallbackSet = TRUE;
3680
3681 if (FMGetFontFromFontFamilyInstance(
3682 (gui.wide_font & 0xFFFF),
3683 0,
3684 &fallbackFonts,
3685 NULL) == noErr)
3686 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003687 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3688 &fallbackFonts,
3689 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003690 }
3691/*
3692 ATSUAttributeValuePtr fallbackValues[] = { };
3693*/
3694 }
3695 }
3696#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697 TextSize(font >> 16);
3698 TextFont(font & 0xFFFF);
3699}
3700
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701/*
3702 * If a font is not going to be used, free its structure.
3703 */
3704 void
3705gui_mch_free_font(font)
3706 GuiFont font;
3707{
3708 /*
3709 * Free font when "font" is not 0.
3710 * Nothing to do in the current implementation, since
3711 * nothing is allocated for each font used.
3712 */
3713}
3714
3715 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003716hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003717{
3718 if (isdigit(c))
3719 return c - '0';
3720 c = TOLOWER_ASC(c);
3721 if (c >= 'a' && c <= 'f')
3722 return c - 'a' + 10;
3723 return -1000;
3724}
3725
3726/*
3727 * Return the Pixel value (color) for the given color name. This routine was
3728 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3729 * Programmer's Guide.
3730 * Return INVALCOLOR when failed.
3731 */
3732 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003733gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734{
3735 /* TODO: Add support for the new named color of MacOS 8
3736 */
3737 RGBColor MacColor;
3738// guicolor_T color = 0;
3739
3740 typedef struct guicolor_tTable
3741 {
3742 char *name;
3743 guicolor_T color;
3744 } guicolor_tTable;
3745
3746 /*
3747 * The comment at the end of each line is the source
3748 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3749 */
3750 static guicolor_tTable table[] =
3751 {
3752 {"Black", RGB(0x00, 0x00, 0x00)},
3753 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3754 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3755 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3756 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3757 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3758 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003759 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3760 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3761 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3762 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3763 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3764 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3765 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3766 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3767 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3768 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3769 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3770 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3771 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3772 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3773 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3774 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003775 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3776 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 {"white", RGB(0xFF, 0xFF, 0xFF)},
3778 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3779 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3780 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3781 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3782 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3783 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3784 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3785 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3786 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3787 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3788 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3789 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3790 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3791 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3792 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3793 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3794 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3795 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003796 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3798 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3799 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3800 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3801 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3802 };
3803
3804 int r, g, b;
3805 int i;
3806
3807 if (name[0] == '#' && strlen((char *) name) == 7)
3808 {
3809 /* Name is in "#rrggbb" format */
3810 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3811 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3812 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3813 if (r < 0 || g < 0 || b < 0)
3814 return INVALCOLOR;
3815 return RGB(r, g, b);
3816 }
3817 else
3818 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003819 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003821 LMGetHiliteRGB(&MacColor);
3822 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 }
3824 /* Check if the name is one of the colors we know */
3825 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3826 if (STRICMP(name, table[i].name) == 0)
3827 return table[i].color;
3828 }
3829
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 /*
3831 * Last attempt. Look in the file "$VIM/rgb.txt".
3832 */
3833 {
3834#define LINE_LEN 100
3835 FILE *fd;
3836 char line[LINE_LEN];
3837 char_u *fname;
3838
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 if (fname == NULL)
3841 return INVALCOLOR;
3842
3843 fd = fopen((char *)fname, "rt");
3844 vim_free(fname);
3845 if (fd == NULL)
3846 return INVALCOLOR;
3847
3848 while (!feof(fd))
3849 {
3850 int len;
3851 int pos;
3852 char *color;
3853
3854 fgets(line, LINE_LEN, fd);
3855 len = strlen(line);
3856
3857 if (len <= 1 || line[len-1] != '\n')
3858 continue;
3859
3860 line[len-1] = '\0';
3861
3862 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3863 if (i != 3)
3864 continue;
3865
3866 color = line + pos;
3867
3868 if (STRICMP(color, name) == 0)
3869 {
3870 fclose(fd);
3871 return (guicolor_T) RGB(r, g, b);
3872 }
3873 }
3874 fclose(fd);
3875 }
3876
3877 return INVALCOLOR;
3878}
3879
3880/*
3881 * Set the current text foreground color.
3882 */
3883 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003884gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885{
3886 RGBColor TheColor;
3887
3888 TheColor.red = Red(color) * 0x0101;
3889 TheColor.green = Green(color) * 0x0101;
3890 TheColor.blue = Blue(color) * 0x0101;
3891
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003892 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893}
3894
3895/*
3896 * Set the current text background color.
3897 */
3898 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003899gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900{
3901 RGBColor TheColor;
3902
3903 TheColor.red = Red(color) * 0x0101;
3904 TheColor.green = Green(color) * 0x0101;
3905 TheColor.blue = Blue(color) * 0x0101;
3906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003907 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908}
3909
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003910RGBColor specialColor;
3911
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003912/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003913 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003914 */
3915 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003916gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003917{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003918 specialColor.red = Red(color) * 0x0101;
3919 specialColor.green = Green(color) * 0x0101;
3920 specialColor.blue = Blue(color) * 0x0101;
3921}
3922
3923/*
3924 * Draw undercurl at the bottom of the character cell.
3925 */
3926 static void
3927draw_undercurl(int flags, int row, int col, int cells)
3928{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003929 int x;
3930 int offset;
3931 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3932 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003933
3934 RGBForeColor(&specialColor);
3935
3936 offset = val[FILL_X(col) % 8];
3937 MoveTo(FILL_X(col), y - offset);
3938
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003939 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003940 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003941 offset = val[x % 8];
3942 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003943 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003944}
3945
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003946
3947 static void
3948draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950#ifdef FEAT_MBYTE
3951 char_u *tofree = NULL;
3952
3953 if (output_conv.vc_type != CONV_NONE)
3954 {
3955 tofree = string_convert(&output_conv, s, &len);
3956 if (tofree != NULL)
3957 s = tofree;
3958 }
3959#endif
3960
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 /*
3962 * On OS X, try using Quartz-style text antialiasing.
3963 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003964 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 {
3966 /* Quartz antialiasing is available only in OS 10.2 and later. */
3967 UInt32 qd_flags = (p_antialias ?
3968 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003969 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 }
3971
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003972 /*
3973 * When antialiasing we're using srcOr mode, we have to clear the block
3974 * before drawing the text.
3975 * Also needed when 'linespace' is non-zero to remove the cursor and
3976 * underlining.
3977 * But not when drawing transparently.
3978 * The following is like calling gui_mch_clear_block(row, col, row, col +
3979 * len - 1), but without setting the bg color to gui.back_pixel.
3980 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003981 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003982 && !(flags & DRAW_TRANSP))
3983 {
3984 Rect rc;
3985
3986 rc.left = FILL_X(col);
3987 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003988#ifdef FEAT_MBYTE
3989 /* Multibyte computation taken from gui_w32.c */
3990 if (has_mbyte)
3991 {
3992 int cell_len = 0;
3993 int n;
3994
3995 /* Compute the length in display cells. */
3996 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3997 cell_len += (*mb_ptr2cells)(s + n);
3998 rc.right = FILL_X(col + cell_len);
3999 }
4000 else
4001#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004002 rc.right = FILL_X(col + len) + (col + len == Columns);
4003 rc.bottom = FILL_Y(row + 1);
4004 EraseRect(&rc);
4005 }
4006
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004007 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 {
4009 StyleParameter face;
4010
4011 face = normal;
4012 if (flags & DRAW_BOLD)
4013 face |= bold;
4014 if (flags & DRAW_UNDERL)
4015 face |= underline;
4016 TextFace(face);
4017
4018 /* Quartz antialiasing works only in srcOr transfer mode. */
4019 TextMode(srcOr);
4020
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021 MoveTo(TEXT_X(col), TEXT_Y(row));
4022 DrawText((char*)s, 0, len);
4023 }
4024 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025 {
4026 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004027 TextMode(srcCopy);
4028 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029
4030 /* SelectFont(hdc, gui.currFont); */
4031
4032 if (flags & DRAW_TRANSP)
4033 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004034 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035 }
4036
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004037 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004038 DrawText((char *)s, 0, len);
4039
4040 if (flags & DRAW_BOLD)
4041 {
4042 TextMode(srcOr);
4043 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4044 DrawText((char *)s, 0, len);
4045 }
4046
4047 if (flags & DRAW_UNDERL)
4048 {
4049 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4050 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4051 }
4052 }
4053
4054 if (flags & DRAW_UNDERC)
4055 draw_undercurl(flags, row, col, len);
4056
4057#ifdef FEAT_MBYTE
4058 vim_free(tofree);
4059#endif
4060}
4061
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004062#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004063
4064 static void
4065draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4066{
4067 /* ATSUI requires utf-16 strings */
4068 UniCharCount utf16_len;
4069 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4070 utf16_len /= sizeof(UniChar);
4071
4072 /* - ATSUI automatically antialiases text (Someone)
4073 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004074#ifdef MAC_ATSUI_DEBUG
4075 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4076 row, col, len, len == 1 ? s[0] : ' ');
4077#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004078 /*
4079 * When antialiasing we're using srcOr mode, we have to clear the block
4080 * before drawing the text.
4081 * Also needed when 'linespace' is non-zero to remove the cursor and
4082 * underlining.
4083 * But not when drawing transparently.
4084 * The following is like calling gui_mch_clear_block(row, col, row, col +
4085 * len - 1), but without setting the bg color to gui.back_pixel.
4086 */
4087 if ((flags & DRAW_TRANSP) == 0)
4088 {
4089 Rect rc;
4090
4091 rc.left = FILL_X(col);
4092 rc.top = FILL_Y(row);
4093 /* Multibyte computation taken from gui_w32.c */
4094 if (has_mbyte)
4095 {
4096 int cell_len = 0;
4097 int n;
4098
4099 /* Compute the length in display cells. */
4100 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4101 cell_len += (*mb_ptr2cells)(s + n);
4102 rc.right = FILL_X(col + cell_len);
4103 }
4104 else
4105 rc.right = FILL_X(col + len) + (col + len == Columns);
4106
4107 rc.bottom = FILL_Y(row + 1);
4108 EraseRect(&rc);
4109 }
4110
4111 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004112 TextMode(srcCopy);
4113 TextFace(normal);
4114
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004115 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004116 if (flags & DRAW_TRANSP)
4117 {
4118 TextMode(srcOr);
4119 }
4120
4121 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004122
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004123 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004124 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004125 Boolean attValue = true;
4126 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4127 ByteCount attribSizes[] = { sizeof(Boolean) };
4128 ATSUAttributeValuePtr attribValues[] = { &attValue };
4129
4130 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4131 }
4132
4133#ifdef FEAT_MBYTE
4134 if (has_mbyte)
4135 {
4136 int n, width_in_cell, last_width_in_cell;
4137 UniCharArrayOffset offset = 0;
4138 UniCharCount yet_to_draw = 0;
4139 ATSUTextLayout textLayout;
4140 ATSUStyle textStyle;
4141
4142 last_width_in_cell = 1;
4143 ATSUCreateTextLayout(&textLayout);
4144 ATSUSetTextPointerLocation(textLayout, tofree,
4145 kATSUFromTextBeginning,
4146 kATSUToTextEnd, utf16_len);
4147 /*
4148 ATSUSetRunStyle(textLayout, gFontStyle,
4149 kATSUFromTextBeginning, kATSUToTextEnd); */
4150
4151 /* Compute the length in display cells. */
4152 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4153 {
4154 width_in_cell = (*mb_ptr2cells)(s + n);
4155
4156 /* probably we are switching from single byte character
4157 * to multibyte characters (which requires more than one
4158 * cell to draw) */
4159 if (width_in_cell != last_width_in_cell)
4160 {
4161#ifdef MAC_ATSUI_DEBUG
4162 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4163 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4164#endif
4165 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4166 : gFontStyle;
4167
4168 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4169 offset += yet_to_draw;
4170 yet_to_draw = 0;
4171 last_width_in_cell = width_in_cell;
4172 }
4173
4174 yet_to_draw++;
4175 }
4176
4177 if (yet_to_draw)
4178 {
4179#ifdef MAC_ATSUI_DEBUG
4180 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4181 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4182#endif
4183 /* finish the rest style */
4184 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4185 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4186 }
4187
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004188 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004189 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004190 kATSUFromTextBeginning, kATSUToTextEnd,
4191 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004192 ATSUDisposeTextLayout(textLayout);
4193 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004194 else
4195#endif
4196 {
4197 ATSUTextLayout textLayout;
4198
4199 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4200 kATSUFromTextBeginning, kATSUToTextEnd,
4201 utf16_len,
4202 (gFontStyle ? 1 : 0), &utf16_len,
4203 (gFontStyle ? &gFontStyle : NULL),
4204 &textLayout) == noErr)
4205 {
4206 ATSUSetTransientFontMatching(textLayout, TRUE);
4207
4208 ATSUDrawText(textLayout,
4209 kATSUFromTextBeginning, kATSUToTextEnd,
4210 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4211
4212 ATSUDisposeTextLayout(textLayout);
4213 }
4214 }
4215
4216 /* drawing is done, now reset bold to normal */
4217 if (gFontStyle && flags & DRAW_BOLD)
4218 {
4219 Boolean attValue = false;
4220
4221 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4222 ByteCount attribSizes[] = { sizeof(Boolean) };
4223 ATSUAttributeValuePtr attribValues[] = { &attValue };
4224
4225 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4226 attribValues);
4227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 }
4229
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004230 if (flags & DRAW_UNDERC)
4231 draw_undercurl(flags, row, col, len);
4232
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004234}
4235#endif
4236
4237 void
4238gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4239{
4240#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004241 if (p_macatsui == 0 && p_macatsui_last != 0)
4242 /* switch from macatsui to nomacatsui */
4243 gui_mac_dispose_atsui_style();
4244 else if (p_macatsui != 0 && p_macatsui_last == 0)
4245 /* switch from nomacatsui to macatsui */
4246 gui_mac_create_atsui_style();
4247
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004248 if (p_macatsui)
4249 draw_string_ATSUI(row, col, s, len, flags);
4250 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004252 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253}
4254
4255/*
4256 * Return OK if the key with the termcap name "name" is supported.
4257 */
4258 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004259gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260{
4261 int i;
4262
4263 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4264 if (name[0] == special_keys[i].vim_code0 &&
4265 name[1] == special_keys[i].vim_code1)
4266 return OK;
4267 return FAIL;
4268}
4269
4270 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004271gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004272{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004273 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274}
4275
4276 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004277gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278{
4279 /* Do a visual beep by reversing the foreground and background colors */
4280 Rect rc;
4281
4282 /*
4283 * Note: InvertRect() excludes right and bottom of rectangle.
4284 */
4285 rc.left = 0;
4286 rc.top = 0;
4287 rc.right = gui.num_cols * gui.char_width;
4288 rc.bottom = gui.num_rows * gui.char_height;
4289 InvertRect(&rc);
4290
4291 ui_delay((long)msec, TRUE); /* wait for some msec */
4292
4293 InvertRect(&rc);
4294}
4295
4296/*
4297 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4298 */
4299 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004300gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301{
4302 Rect rc;
4303
4304 /*
4305 * Note: InvertRect() excludes right and bottom of rectangle.
4306 */
4307 rc.left = FILL_X(c);
4308 rc.top = FILL_Y(r);
4309 rc.right = rc.left + nc * gui.char_width;
4310 rc.bottom = rc.top + nr * gui.char_height;
4311 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312}
4313
4314/*
4315 * Iconify the GUI window.
4316 */
4317 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004318gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319{
4320 /* TODO: find out what could replace iconify
4321 * -window shade?
4322 * -hide application?
4323 */
4324}
4325
4326#if defined(FEAT_EVAL) || defined(PROTO)
4327/*
4328 * Bring the Vim window to the foreground.
4329 */
4330 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004331gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332{
4333 /* TODO */
4334}
4335#endif
4336
4337/*
4338 * Draw a cursor without focus.
4339 */
4340 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004341gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342{
4343 Rect rc;
4344
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 /*
4346 * Note: FrameRect() excludes right and bottom of rectangle.
4347 */
4348 rc.left = FILL_X(gui.col);
4349 rc.top = FILL_Y(gui.row);
4350 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004351#ifdef FEAT_MBYTE
4352 if (mb_lefthalve(gui.row, gui.col))
4353 rc.right += gui.char_width;
4354#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355 rc.bottom = rc.top + gui.char_height;
4356
4357 gui_mch_set_fg_color(color);
4358
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004359 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360}
4361
4362/*
4363 * Draw part of a cursor, only w pixels wide, and h pixels high.
4364 */
4365 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004366gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367{
4368 Rect rc;
4369
4370#ifdef FEAT_RIGHTLEFT
4371 /* vertical line should be on the right of current point */
4372 if (CURSOR_BAR_RIGHT)
4373 rc.left = FILL_X(gui.col + 1) - w;
4374 else
4375#endif
4376 rc.left = FILL_X(gui.col);
4377 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4378 rc.right = rc.left + w;
4379 rc.bottom = rc.top + h;
4380
4381 gui_mch_set_fg_color(color);
4382
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004383 FrameRect(&rc);
4384// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385}
4386
4387
4388
4389/*
4390 * Catch up with any queued X events. This may put keyboard input into the
4391 * input buffer, call resize call-backs, trigger timers etc. If there is
4392 * nothing in the X event queue (& no timers pending), then we return
4393 * immediately.
4394 */
4395 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004396gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397{
4398 /* TODO: find what to do
4399 * maybe call gui_mch_wait_for_chars (0)
4400 * more like look at EventQueue then
4401 * call heart of gui_mch_wait_for_chars;
4402 *
4403 * if (eventther)
4404 * gui_mac_handle_event(&event);
4405 */
4406 EventRecord theEvent;
4407
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004408 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409 if (theEvent.what != nullEvent)
4410 gui_mch_wait_for_chars(0);
4411}
4412
4413/*
4414 * Simple wrapper to neglect more easily the time
4415 * spent inside WaitNextEvent while profiling.
4416 */
4417
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 pascal
4419 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004420WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004421{
4422 if (((long) sleep) < -1)
4423 sleep = 32767;
4424 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4425}
4426
4427/*
4428 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4429 * from the keyboard.
4430 * wtime == -1 Wait forever.
4431 * wtime == 0 This should never happen.
4432 * wtime > 0 Wait wtime milliseconds for a character.
4433 * Returns OK if a character was found to be available within the given time,
4434 * or FAIL otherwise.
4435 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004437gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438{
4439 EventMask mask = (everyEvent);
4440 EventRecord event;
4441 long entryTick;
4442 long currentTick;
4443 long sleeppyTick;
4444
4445 /* If we are providing life feedback with the scrollbar,
4446 * we don't want to try to wait for an event, or else
4447 * there won't be any life feedback.
4448 */
4449 if (dragged_sb != NULL)
4450 return FAIL;
4451 /* TODO: Check if FAIL is the proper return code */
4452
4453 entryTick = TickCount();
4454
4455 allow_scrollbar = TRUE;
4456
4457 do
4458 {
4459/* if (dragRectControl == kCreateEmpty)
4460 {
4461 dragRgn = NULL;
4462 dragRectControl = kNothing;
4463 }
4464 else*/ if (dragRectControl == kCreateRect)
4465 {
4466 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004467 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468 dragRectControl = kNothing;
4469 }
4470 /*
4471 * Don't use gui_mch_update() because then we will spin-lock until a
4472 * char arrives, instead we use WaitNextEventWrp() to hang until an
4473 * event arrives. No need to check for input_buf_full because we are
4474 * returning as soon as it contains a single char.
4475 */
4476 /* TODO: reduce wtime accordinly??? */
4477 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004478 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 else
4480 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004481
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004482 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004484 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 if (input_available())
4486 {
4487 allow_scrollbar = FALSE;
4488 return OK;
4489 }
4490 }
4491 currentTick = TickCount();
4492 }
4493 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4494
4495 allow_scrollbar = FALSE;
4496 return FAIL;
4497}
4498
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499/*
4500 * Output routines.
4501 */
4502
4503/* Flush any output to the screen */
4504 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004505gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506{
4507 /* TODO: Is anything needed here? */
4508}
4509
4510/*
4511 * Clear a rectangular region of the screen from text pos (row1, col1) to
4512 * (row2, col2) inclusive.
4513 */
4514 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004515gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516{
4517 Rect rc;
4518
4519 /*
4520 * Clear one extra pixel at the far right, for when bold characters have
4521 * spilled over to the next column.
4522 */
4523 rc.left = FILL_X(col1);
4524 rc.top = FILL_Y(row1);
4525 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4526 rc.bottom = FILL_Y(row2 + 1);
4527
4528 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004529 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530}
4531
4532/*
4533 * Clear the whole text window.
4534 */
4535 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004536gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537{
4538 Rect rc;
4539
4540 rc.left = 0;
4541 rc.top = 0;
4542 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4543 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4544
4545 gui_mch_set_bg_color(gui.back_pixel);
4546 EraseRect(&rc);
4547/* gui_mch_set_fg_color(gui.norm_pixel);
4548 FrameRect(&rc);
4549*/
4550}
4551
4552/*
4553 * Delete the given number of lines from the given row, scrolling up any
4554 * text further down within the scroll region.
4555 */
4556 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004557gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558{
4559 Rect rc;
4560
4561 /* changed without checking! */
4562 rc.left = FILL_X(gui.scroll_region_left);
4563 rc.right = FILL_X(gui.scroll_region_right + 1);
4564 rc.top = FILL_Y(row);
4565 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4566
4567 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004568 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569
4570 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4571 gui.scroll_region_left,
4572 gui.scroll_region_bot, gui.scroll_region_right);
4573}
4574
4575/*
4576 * Insert the given number of lines before the given row, scrolling down any
4577 * following text within the scroll region.
4578 */
4579 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004580gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581{
4582 Rect rc;
4583
4584 rc.left = FILL_X(gui.scroll_region_left);
4585 rc.right = FILL_X(gui.scroll_region_right + 1);
4586 rc.top = FILL_Y(row);
4587 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4588
4589 gui_mch_set_bg_color(gui.back_pixel);
4590
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004591 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592
4593 /* Update gui.cursor_row if the cursor scrolled or copied over */
4594 if (gui.cursor_row >= gui.row
4595 && gui.cursor_col >= gui.scroll_region_left
4596 && gui.cursor_col <= gui.scroll_region_right)
4597 {
4598 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4599 gui.cursor_row += num_lines;
4600 else if (gui.cursor_row <= gui.scroll_region_bot)
4601 gui.cursor_is_valid = FALSE;
4602 }
4603
4604 gui_clear_block(row, gui.scroll_region_left,
4605 row + num_lines - 1, gui.scroll_region_right);
4606}
4607
4608 /*
4609 * TODO: add a vim format to the clipboard which remember
4610 * LINEWISE, CHARWISE, BLOCKWISE
4611 */
4612
4613 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004614clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615{
4616
4617 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004618 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619 Size scrapSize;
4620 ScrapFlavorFlags scrapFlags;
4621 ScrapRef scrap = nil;
4622 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 int type;
4624 char *searchCR;
4625 char_u *tempclip;
4626
4627
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004628 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 if (error != noErr)
4630 return;
4631
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004632 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4633 if (error == noErr)
4634 {
4635 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4636 if (error == noErr && scrapSize > 1)
4637 flavor = 1;
4638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004639
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004640 if (flavor == 0)
4641 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004642 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004643 if (error != noErr)
4644 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004646 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004647 if (error != noErr)
4648 return;
4649 }
4650
4651 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004653 /* In CARBON we don't need a Handle, a pointer is good */
4654 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004656 /* tempclip = lalloc(scrapSize+1, TRUE); */
4657 HLock(textOfClip);
4658 error = GetScrapFlavorData(scrap,
4659 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4660 &scrapSize, *textOfClip);
4661 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004663 if (flavor)
4664 type = **textOfClip;
4665 else
4666 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4667
4668 tempclip = lalloc(scrapSize + 1, TRUE);
4669 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4670 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004672#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004673 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004674 /* Convert from utf-16 (clipboard) */
4675 size_t encLen = 0;
4676 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004677
4678 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004680 scrapSize = encLen;
4681 vim_free(tempclip);
4682 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004686
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004687 searchCR = (char *)tempclip;
4688 while (searchCR != NULL)
4689 {
4690 searchCR = strchr(searchCR, '\r');
4691 if (searchCR != NULL)
4692 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004694
4695 clip_yank_selection(type, tempclip, scrapSize, cbd);
4696
4697 vim_free(tempclip);
4698 HUnlock(textOfClip);
4699
4700 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701}
4702
4703 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004704clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705{
4706 /*
4707 * TODO: Really nothing to do?
4708 */
4709}
4710
4711 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004712clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713{
4714 return OK;
4715}
4716
4717/*
4718 * Send the current selection to the clipboard.
4719 */
4720 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004721clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722{
4723 Handle textOfClip;
4724 long scrapSize;
4725 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727
4728 char_u *str = NULL;
4729
4730 if (!cbd->owned)
4731 return;
4732
4733 clip_get_selection(cbd);
4734
4735 /*
4736 * Once we set the clipboard, lose ownership. If another application sets
4737 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 cbd->owned = FALSE;
4740
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004741 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004743#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004744 size_t utf16_len = 0;
4745 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4746 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004748 scrapSize = utf16_len;
4749 vim_free(str);
4750 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 }
4752#endif
4753
4754 if (type >= 0)
4755 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004758 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 HLock(textOfClip);
4760
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004761 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004762 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004763 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004764 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004765 scrapSize, *textOfClip + 1);
4766 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4767 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 HUnlock(textOfClip);
4769 DisposeHandle(textOfClip);
4770 }
4771
4772 vim_free(str);
4773}
4774
4775 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004776gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777{
4778 Rect VimBound;
4779
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004780/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782
4783 if (gui.which_scrollbars[SBAR_LEFT])
4784 {
4785 VimBound.left = -gui.scrollbar_width + 1;
4786 }
4787 else
4788 {
4789 VimBound.left = 0;
4790 }
4791
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004794 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795}
4796
4797/*
4798 * Menu stuff.
4799 */
4800
4801 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004802gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803{
4804 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004805 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806 */
4807}
4808
4809 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004810gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811{
4812 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004813 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814 */
4815}
4816
4817/*
4818 * Add a sub menu to the menu bar.
4819 */
4820 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004821gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822{
4823 /*
4824 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4825 * TODO: use menu->mnemonic and menu->actext
4826 * TODO: Try to reuse menu id
4827 * Carbon Help suggest to use only id between 1 and 235
4828 */
4829 static long next_avail_id = 128;
4830 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004831#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004832 CFStringRef name;
4833#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004834 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004835#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 short index;
4837 vimmenu_T *parent = menu->parent;
4838 vimmenu_T *brother = menu->next;
4839
4840 /* Cannot add a menu if ... */
4841 if ((parent != NULL && parent->submenu_id == 0))
4842 return;
4843
4844 /* menu ID greater than 1024 are reserved for ??? */
4845 if (next_avail_id == 1024)
4846 return;
4847
4848 /* My brother could be the PopUp, find my real brother */
4849 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4850 brother = brother->next;
4851
4852 /* Find where to insert the menu (for MenuBar) */
4853 if ((parent == NULL) && (brother != NULL))
4854 menu_after_me = brother->submenu_id;
4855
4856 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4857 if (!menu_is_menubar(menu->name))
4858 menu_after_me = hierMenu;
4859
4860 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004861#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004862 name = menu_title_removing_mnemonic(menu);
4863#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004864 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004865#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 if (name == NULL)
4867 return;
4868
4869 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 {
4871 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004872 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4873 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 */
4875 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004876#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004877 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4878 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4879#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004880 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004881#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 next_avail_id++;
4883 }
4884
4885 if (parent == NULL)
4886 {
4887 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4888
4889 /* TODO: Verify if we could only Insert Menu if really part of the
4890 * menubar The Inserted menu are scanned or the Command-key combos
4891 */
4892
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004893 /* Insert the menu */
4894 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004895#if 1
4896 /* Vim should normally update it. TODO: verify */
4897 DrawMenuBar();
4898#endif
4899 }
4900 else
4901 {
4902 /* Adding as a submenu */
4903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004904 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905
4906 /* Call InsertMenuItem followed by SetMenuItemText
4907 * to avoid special character recognition by InsertMenuItem
4908 */
4909 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004910#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004911 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4912#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004914#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4916 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4917 InsertMenu(menu->submenu_handle, hierMenu);
4918 }
4919
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004920#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004921 CFRelease(name);
4922#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004923 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004924#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925
4926#if 0
4927 /* Done by Vim later on */
4928 DrawMenuBar();
4929#endif
4930}
4931
4932/*
4933 * Add a menu item to a menu
4934 */
4935 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004936gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004938#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004939 CFStringRef name;
4940#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004942#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 vimmenu_T *parent = menu->parent;
4944 int menu_inserted;
4945
4946 /* Cannot add item, if the menu have not been created */
4947 if (parent->submenu_id == 0)
4948 return;
4949
4950 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4951 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4952
4953 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004954#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004955 name = menu_title_removing_mnemonic(menu);
4956#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004958#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004959
4960 /* Where are just a menu item, so no handle, no id */
4961 menu->submenu_id = 0;
4962 menu->submenu_handle = NULL;
4963
Bram Moolenaar071d4272004-06-13 20:20:40 +00004964 menu_inserted = 0;
4965 if (menu->actext)
4966 {
4967 /* If the accelerator text for the menu item looks like it describes
4968 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4969 * item's command equivalent.
4970 */
4971 int key = 0;
4972 int modifiers = 0;
4973 char_u *p_actext;
4974
4975 p_actext = menu->actext;
4976 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4977 if (*p_actext != 0)
4978 key = 0; /* error: trailing text */
4979 /* find_special_key() returns a keycode with as many of the
4980 * specified modifiers as appropriate already applied (e.g., for
4981 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4982 * as the only modifier). Since we want to display all of the
4983 * modifiers, we need to convert the keycode back to a printable
4984 * character plus modifiers.
4985 * TODO: Write an alternative find_special_key() that doesn't
4986 * apply modifiers.
4987 */
4988 if (key > 0 && key < 32)
4989 {
4990 /* Convert a control key to an uppercase letter. Note that
4991 * by this point it is no longer possible to distinguish
4992 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4993 */
4994 modifiers |= MOD_MASK_CTRL;
4995 key += '@';
4996 }
4997 /* If the keycode is an uppercase letter, set the Shift modifier.
4998 * If it is a lowercase letter, don't set the modifier, but convert
4999 * the letter to uppercase for display in the menu.
5000 */
5001 else if (key >= 'A' && key <= 'Z')
5002 modifiers |= MOD_MASK_SHIFT;
5003 else if (key >= 'a' && key <= 'z')
5004 key += 'A' - 'a';
5005 /* Note: keycodes below 0x22 are reserved by Apple. */
5006 if (key >= 0x22 && vim_isprintc_strict(key))
5007 {
5008 int valid = 1;
5009 char_u mac_mods = kMenuNoModifiers;
5010 /* Convert Vim modifier codes to Menu Manager equivalents. */
5011 if (modifiers & MOD_MASK_SHIFT)
5012 mac_mods |= kMenuShiftModifier;
5013 if (modifiers & MOD_MASK_CTRL)
5014 mac_mods |= kMenuControlModifier;
5015 if (!(modifiers & MOD_MASK_CMD))
5016 mac_mods |= kMenuNoCommandModifier;
5017 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5018 valid = 0; /* TODO: will Alt someday map to Option? */
5019 if (valid)
5020 {
5021 char_u item_txt[10];
5022 /* Insert the menu item after idx, with its command key. */
5023 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5024 item_txt[3] = key;
5025 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5026 /* Set the modifier keys. */
5027 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5028 menu_inserted = 1;
5029 }
5030 }
5031 }
5032 /* Call InsertMenuItem followed by SetMenuItemText
5033 * to avoid special character recognition by InsertMenuItem
5034 */
5035 if (!menu_inserted)
5036 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5037 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005038#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005039 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5040#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005042#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043
5044#if 0
5045 /* Called by Vim */
5046 DrawMenuBar();
5047#endif
5048
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005049#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005050 CFRelease(name);
5051#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 /* TODO: Can name be freed? */
5053 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005054#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055}
5056
5057 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005058gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005059{
5060 /* no tearoff menus */
5061}
5062
5063/*
5064 * Destroy the machine specific menu widget.
5065 */
5066 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005067gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005069 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005070
5071 if (index > 0)
5072 {
5073 if (menu->parent)
5074 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075 {
5076 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005077 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078
5079 /* Delete the Menu if it was a hierarchical Menu */
5080 if (menu->submenu_id != 0)
5081 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005082 DeleteMenu(menu->submenu_id);
5083 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 }
5085 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 }
5087#ifdef DEBUG_MAC_MENU
5088 else
5089 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005090 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091 }
5092#endif
5093 }
5094 else
5095 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005097 DeleteMenu(menu->submenu_id);
5098 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099 }
5100 }
5101 /* Shouldn't this be already done by Vim. TODO: Check */
5102 DrawMenuBar();
5103}
5104
5105/*
5106 * Make a menu either grey or not grey.
5107 */
5108 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005109gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110{
5111 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005112 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113/*
5114 index = menu->index;
5115*/
5116 if (grey)
5117 {
5118 if (menu->children)
5119 DisableMenuItem(menu->submenu_handle, index);
5120 if (menu->parent)
5121 if (menu->parent->submenu_handle)
5122 DisableMenuItem(menu->parent->submenu_handle, index);
5123 }
5124 else
5125 {
5126 if (menu->children)
5127 EnableMenuItem(menu->submenu_handle, index);
5128 if (menu->parent)
5129 if (menu->parent->submenu_handle)
5130 EnableMenuItem(menu->parent->submenu_handle, index);
5131 }
5132}
5133
5134/*
5135 * Make menu item hidden or not hidden
5136 */
5137 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005138gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139{
5140 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005141 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142}
5143
5144
5145/*
5146 * This is called after setting all the menus to grey/hidden or not.
5147 */
5148 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005149gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150{
5151 DrawMenuBar();
5152}
5153
5154
5155/*
5156 * Scrollbar stuff.
5157 */
5158
5159 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005160gui_mch_enable_scrollbar(
5161 scrollbar_T *sb,
5162 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005163{
5164 if (flag)
5165 ShowControl(sb->id);
5166 else
5167 HideControl(sb->id);
5168
5169#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005170 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171#endif
5172}
5173
5174 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005175gui_mch_set_scrollbar_thumb(
5176 scrollbar_T *sb,
5177 long val,
5178 long size,
5179 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005180{
5181 SetControl32BitMaximum (sb->id, max);
5182 SetControl32BitMinimum (sb->id, 0);
5183 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005184 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005185#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005186 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005187#endif
5188}
5189
5190 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005191gui_mch_set_scrollbar_pos(
5192 scrollbar_T *sb,
5193 int x,
5194 int y,
5195 int w,
5196 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005197{
5198 gui_mch_set_bg_color(gui.back_pixel);
5199/* if (gui.which_scrollbars[SBAR_LEFT])
5200 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005201 MoveControl(sb->id, x-16, y);
5202 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 }
5204 else
5205 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005206 MoveControl(sb->id, x, y);
5207 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208 }*/
5209 if (sb == &gui.bottom_sbar)
5210 h += 1;
5211 else
5212 w += 1;
5213
5214 if (gui.which_scrollbars[SBAR_LEFT])
5215 x -= 15;
5216
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005217 MoveControl(sb->id, x, y);
5218 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005220 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221#endif
5222}
5223
5224 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005225gui_mch_create_scrollbar(
5226 scrollbar_T *sb,
5227 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005228{
5229 Rect bounds;
5230
5231 bounds.top = -16;
5232 bounds.bottom = -10;
5233 bounds.right = -10;
5234 bounds.left = -16;
5235
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005236 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 &bounds,
5238 "\pScrollBar",
5239 TRUE,
5240 0, /* current*/
5241 0, /* top */
5242 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005244 (long) sb->ident);
5245#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005246 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247#endif
5248}
5249
5250 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005251gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252{
5253 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005254 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005256 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005257#endif
5258}
5259
5260
5261/*
5262 * Cursor blink functions.
5263 *
5264 * This is a simple state machine:
5265 * BLINK_NONE not blinking at all
5266 * BLINK_OFF blinking, cursor is not shown
5267 * BLINK_ON blinking, cursor is shown
5268 */
5269 void
5270gui_mch_set_blinking(long wait, long on, long off)
5271{
5272 /* TODO: TODO: TODO: TODO: */
5273/* blink_waittime = wait;
5274 blink_ontime = on;
5275 blink_offtime = off;*/
5276}
5277
5278/*
5279 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5280 */
5281 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005282gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283{
5284 gui_update_cursor(TRUE, FALSE);
5285 /* TODO: TODO: TODO: TODO: */
5286/* gui_w32_rm_blink_timer();
5287 if (blink_state == BLINK_OFF)
5288 gui_update_cursor(TRUE, FALSE);
5289 blink_state = BLINK_NONE;*/
5290}
5291
5292/*
5293 * Start the cursor blinking. If it was already blinking, this restarts the
5294 * waiting time and shows the cursor.
5295 */
5296 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005297gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005298{
5299 gui_update_cursor(TRUE, FALSE);
5300 /* TODO: TODO: TODO: TODO: */
5301/* gui_w32_rm_blink_timer(); */
5302
5303 /* Only switch blinking on if none of the times is zero */
5304/* if (blink_waittime && blink_ontime && blink_offtime)
5305 {
5306 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5307 (TIMERPROC)_OnBlinkTimer);
5308 blink_state = BLINK_ON;
5309 gui_update_cursor(TRUE, FALSE);
5310 }*/
5311}
5312
5313/*
5314 * Return the RGB value of a pixel as long.
5315 */
5316 long_u
5317gui_mch_get_rgb(guicolor_T pixel)
5318{
5319 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5320}
5321
5322
5323
5324#ifdef FEAT_BROWSE
5325/*
5326 * Pop open a file browser and return the file selected, in allocated memory,
5327 * or NULL if Cancel is hit.
5328 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5329 * title - Title message for the file browser dialog.
5330 * dflt - Default name of file.
5331 * ext - Default extension to be added to files without extensions.
5332 * initdir - directory in which to open the browser (NULL = current dir)
5333 * filter - Filter for matched files to choose from.
5334 * Has a format like this:
5335 * "C Files (*.c)\0*.c\0"
5336 * "All Files\0*.*\0\0"
5337 * If these two strings were concatenated, then a choice of two file
5338 * filters will be selectable to the user. Then only matching files will
5339 * be shown in the browser. If NULL, the default allows all files.
5340 *
5341 * *NOTE* - the filter string must be terminated with TWO nulls.
5342 */
5343 char_u *
5344gui_mch_browse(
5345 int saving,
5346 char_u *title,
5347 char_u *dflt,
5348 char_u *ext,
5349 char_u *initdir,
5350 char_u *filter)
5351{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005352 /* TODO: Add Ammon's safety checl (Dany) */
5353 NavReplyRecord reply;
5354 char_u *fname = NULL;
5355 char_u **fnames = NULL;
5356 long numFiles;
5357 NavDialogOptions navOptions;
5358 OSErr error;
5359
5360 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005361 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005362
5363
5364 /* TODO: If we get a :browse args, set the Multiple bit. */
5365 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5366 | kNavDontAutoTranslate
5367 | kNavDontAddTranslateItems
5368 /* | kNavAllowMultipleFiles */
5369 | kNavAllowStationery;
5370
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005371 (void) C2PascalString(title, &navOptions.message);
5372 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373 /* Could set clientName?
5374 * windowTitle? (there's no title bar?)
5375 */
5376
5377 if (saving)
5378 {
5379 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005380 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381 if (!reply.validRecord)
5382 return NULL;
5383 }
5384 else
5385 {
5386 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5387 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5388 if (!reply.validRecord)
5389 return NULL;
5390 }
5391
5392 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5393
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005394 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005395
5396 if (fnames)
5397 {
5398 fname = fnames[0];
5399 vim_free(fnames);
5400 }
5401
5402 /* TODO: Shorten the file name if possible */
5403 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005404}
5405#endif /* FEAT_BROWSE */
5406
5407#ifdef FEAT_GUI_DIALOG
5408/*
5409 * Stuff for dialogues
5410 */
5411
5412/*
5413 * Create a dialogue dynamically from the parameter strings.
5414 * type = type of dialogue (question, alert, etc.)
5415 * title = dialogue title. may be NULL for default title.
5416 * message = text to display. Dialogue sizes to accommodate it.
5417 * buttons = '\n' separated list of button captions, default first.
5418 * dfltbutton = number of default button.
5419 *
5420 * This routine returns 1 if the first button is pressed,
5421 * 2 for the second, etc.
5422 *
5423 * 0 indicates Esc was pressed.
5424 * -1 for unexpected error
5425 *
5426 * If stubbing out this fn, return 1.
5427 */
5428
5429typedef struct
5430{
5431 short idx;
5432 short width; /* Size of the text in pixel */
5433 Rect box;
5434} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5435
5436#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5437
5438 static void
5439macMoveDialogItem(
5440 DialogRef theDialog,
5441 short itemNumber,
5442 short X,
5443 short Y,
5444 Rect *inBox)
5445{
5446#if 0 /* USE_CARBONIZED */
5447 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005448 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005450 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451#else
5452 short itemType;
5453 Handle itemHandle;
5454 Rect localBox;
5455 Rect *itemBox = &localBox;
5456
5457 if (inBox != nil)
5458 itemBox = inBox;
5459
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005460 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5461 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5462 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 /* To move a control (like a button) we need to call both
5464 * MoveControl and SetDialogItem. FAQ 6-18 */
5465 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005466 MoveControl((ControlRef) itemHandle, X, Y);
5467 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468#endif
5469}
5470
5471 static void
5472macSizeDialogItem(
5473 DialogRef theDialog,
5474 short itemNumber,
5475 short width,
5476 short height)
5477{
5478 short itemType;
5479 Handle itemHandle;
5480 Rect itemBox;
5481
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005482 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483
5484 /* When width or height is zero do not change it */
5485 if (width == 0)
5486 width = itemBox.right - itemBox.left;
5487 if (height == 0)
5488 height = itemBox.bottom - itemBox.top;
5489
5490#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005491 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005492#else
5493 /* Resize the bounding box */
5494 itemBox.right = itemBox.left + width;
5495 itemBox.bottom = itemBox.top + height;
5496
5497 /* To resize a control (like a button) we need to call both
5498 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5499 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005500 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005501
5502 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005503 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504#endif
5505}
5506
5507 static void
5508macSetDialogItemText(
5509 DialogRef theDialog,
5510 short itemNumber,
5511 Str255 itemName)
5512{
5513 short itemType;
5514 Handle itemHandle;
5515 Rect itemBox;
5516
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005517 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518
5519 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005520 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005522 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523}
5524
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005525
5526/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5527 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5528 * setting gDialogHotKeys to NULL disables any hotkey handling.
5529 */
5530 static pascal Boolean
5531DialogHotkeyFilterProc (
5532 DialogRef theDialog,
5533 EventRecord *event,
5534 DialogItemIndex *itemHit)
5535{
5536 char_u keyHit;
5537
5538 if (event->what == keyDown || event->what == autoKey)
5539 {
5540 keyHit = (event->message & charCodeMask);
5541
5542 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5543 {
5544#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5545 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5546#endif
5547 *itemHit = gDialogHotKeys[keyHit];
5548
5549 /* When handing off to StdFilterProc, pretend that the user
5550 * clicked the control manually. Note that this is also supposed
5551 * to cause the button to hilite briefly (to give some user
5552 * feedback), but this seems not to actually work (or it's too
5553 * fast to be seen).
5554 */
5555 event->what = kEventControlSimulateHit;
5556
5557 return true; /* we took care of it */
5558 }
5559
5560 /* Defer to the OS's standard behavior for this event.
5561 * This ensures that Enter will still activate the default button. */
5562 return StdFilterProc(theDialog, event, itemHit);
5563 }
5564 return false; /* Let ModalDialog deal with it */
5565}
5566
5567
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005568/* TODO: There have been some crashes with dialogs, check your inbox
5569 * (Jussi)
5570 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005571 int
5572gui_mch_dialog(
5573 int type,
5574 char_u *title,
5575 char_u *message,
5576 char_u *buttons,
5577 int dfltbutton,
5578 char_u *textfield)
5579{
5580 Handle buttonDITL;
5581 Handle iconDITL;
5582 Handle inputDITL;
5583 Handle messageDITL;
5584 Handle itemHandle;
5585 Handle iconHandle;
5586 DialogPtr theDialog;
5587 char_u len;
5588 char_u PascalTitle[256]; /* place holder for the title */
5589 char_u name[256];
5590 GrafPtr oldPort;
5591 short itemHit;
5592 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005593 short hotKeys[256]; /* map of hotkey -> control ID */
5594 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595 Rect box;
5596 short button;
5597 short lastButton;
5598 short itemType;
5599 short useIcon;
5600 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005601 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005602 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005603 short widestButton = 0;
5604 short dfltButtonEdge = 20; /* gut feeling */
5605 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5606 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5607 short maximumWidth = 400; /* gut feeling */
5608 short maxButtonWidth = 175; /* gut feeling */
5609
5610 short vertical;
5611 short dialogHeight;
5612 short messageLines = 3;
5613 FontInfo textFontInfo;
5614
5615 vgmDlgItm iconItm;
5616 vgmDlgItm messageItm;
5617 vgmDlgItm inputItm;
5618 vgmDlgItm buttonItm;
5619
5620 WindowRef theWindow;
5621
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005622 ModalFilterUPP dialogUPP;
5623
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624 /* Check 'v' flag in 'guioptions': vertical button placement. */
5625 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5626
5627 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005628 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629
5630 /* Get the WindowRef */
5631 theWindow = GetDialogWindow(theDialog);
5632
5633 /* Hide the window.
5634 * 1. to avoid seeing slow drawing
5635 * 2. to prevent a problem seen while moving dialog item
5636 * within a visible window. (non-Carbon MacOS 9)
5637 * Could be avoided by changing the resource.
5638 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005639 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640
5641 /* Change the graphical port to the dialog,
5642 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005643 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005644 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645
5646 /* Get the info about the default text,
5647 * used to calculate the height of the message
5648 * and of the text field */
5649 GetFontInfo(&textFontInfo);
5650
5651 /* Set the dialog title */
5652 if (title != NULL)
5653 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005654 (void) C2PascalString(title, &PascalTitle);
5655 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005656 }
5657
5658 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005659 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 buttonChar = buttons;
5661 button = 0;
5662
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005663 /* initialize the hotkey mapping */
5664 memset(hotKeys, 0, sizeof(hotKeys));
5665
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666 for (;*buttonChar != 0;)
5667 {
5668 /* Get the name of the button */
5669 button++;
5670 len = 0;
5671 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5672 {
5673 if (*buttonChar != DLG_HOTKEY_CHAR)
5674 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005675 else
5676 {
5677 aHotKey = (char_u)*(buttonChar+1);
5678 if (aHotKey >= 'A' && aHotKey <= 'Z')
5679 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5680 hotKeys[aHotKey] = button;
5681#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5682 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5683#endif
5684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005686
Bram Moolenaar071d4272004-06-13 20:20:40 +00005687 if (*buttonChar != 0)
5688 buttonChar++;
5689 name[0] = len;
5690
5691 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005692 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005693
5694 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005695 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696
5697 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005698 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699 /* Limite the size of any button to an acceptable value. */
5700 /* TODO: Should be based on the message width */
5701 if (width > maxButtonWidth)
5702 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005703 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704
5705 totalButtonWidth += width;
5706
5707 if (width > widestButton)
5708 widestButton = width;
5709 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005710 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 lastButton = button;
5712
5713 /* Add the icon to the Dialog Box. */
5714 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005715 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005716 switch (type)
5717 {
5718 case VIM_GENERIC: useIcon = kNoteIcon;
5719 case VIM_ERROR: useIcon = kStopIcon;
5720 case VIM_WARNING: useIcon = kCautionIcon;
5721 case VIM_INFO: useIcon = kNoteIcon;
5722 case VIM_QUESTION: useIcon = kNoteIcon;
5723 default: useIcon = kStopIcon;
5724 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005725 AppendDITL(theDialog, iconDITL, overlayDITL);
5726 ReleaseResource(iconDITL);
5727 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005728 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005729 iconHandle = GetIcon(useIcon);
5730 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005731
5732 /* Add the message to the Dialog box. */
5733 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005734 messageDITL = GetResource('DITL', 132);
5735 AppendDITL(theDialog, messageDITL, overlayDITL);
5736 ReleaseResource(messageDITL);
5737 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5738 (void) C2PascalString(message, &name);
5739 SetDialogItemText(itemHandle, name);
5740 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005741
5742 /* Add the input box if needed */
5743 if (textfield != NULL)
5744 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005745 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005746 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005747 inputDITL = GetResource('DITL', 132);
5748 AppendDITL(theDialog, inputDITL, overlayDITL);
5749 ReleaseResource(inputDITL);
5750 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5751/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5752 (void) C2PascalString(textfield, &name);
5753 SetDialogItemText(itemHandle, name);
5754 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005755
5756 /* Hotkeys don't make sense if there's a text field */
5757 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005758 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005759 else
5760 /* Install hotkey table */
5761 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762
5763 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005764 SetDialogDefaultItem(theDialog, dfltbutton);
5765 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005766
5767 /* Reposition element */
5768
5769 /* Check if we need to force vertical */
5770 if (totalButtonWidth > maximumWidth)
5771 vertical = TRUE;
5772
5773 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005774 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775 iconItm.box.right = box.right;
5776 iconItm.box.bottom = box.bottom;
5777
5778 /* Place Message */
5779 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005780 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5781 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005782
5783 /* Place Input */
5784 if (textfield != NULL)
5785 {
5786 inputItm.box.left = messageItm.box.left;
5787 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005788 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5789 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005790 /* Convert the static text into a text edit.
5791 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005792 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5793 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5795 }
5796
5797 /* Place Button */
5798 if (textfield != NULL)
5799 {
5800 buttonItm.box.left = inputItm.box.left;
5801 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5802 }
5803 else
5804 {
5805 buttonItm.box.left = messageItm.box.left;
5806 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5807 }
5808
5809 for (button=1; button <= lastButton; button++)
5810 {
5811
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005812 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005813 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005814 if (vertical)
5815 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005816 macSizeDialogItem(theDialog, button, widestButton, 0);
5817 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005818 }
5819 /* Calculate position of next button */
5820 if (vertical)
5821 buttonItm.box.top = box.bottom + dfltElementSpacing;
5822 else
5823 buttonItm.box.left = box.right + dfltElementSpacing;
5824 }
5825
5826 /* Resize the dialog box */
5827 dialogHeight = box.bottom + dfltElementSpacing;
5828 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5829
Bram Moolenaar071d4272004-06-13 20:20:40 +00005830 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005831 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833
5834 /* Display it */
5835 ShowWindow(theWindow);
5836/* BringToFront(theWindow); */
5837 SelectWindow(theWindow);
5838
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005839/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005840#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005841 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005842 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843#endif
5844
Bram Moolenaard68071d2006-05-02 22:08:30 +00005845#ifdef USE_CARBONKEYHANDLER
5846 /* Avoid that we use key events for the main window. */
5847 dialog_busy = TRUE;
5848#endif
5849
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005850 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5851 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5852
Bram Moolenaar071d4272004-06-13 20:20:40 +00005853 /* Hang until one of the button is hit */
5854 do
5855 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005856 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857 } while ((itemHit < 1) || (itemHit > lastButton));
5858
Bram Moolenaard68071d2006-05-02 22:08:30 +00005859#ifdef USE_CARBONKEYHANDLER
5860 dialog_busy = FALSE;
5861#endif
5862
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863 /* Copy back the text entered by the user into the param */
5864 if (textfield != NULL)
5865 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005866 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5867 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868#if IOSIZE < 256
5869 /* Truncate the name to IOSIZE if needed */
5870 if (name[0] > IOSIZE)
5871 name[0] = IOSIZE - 1;
5872#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005873 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874 }
5875
5876 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005877 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005879 /* Free the modal filterProc */
5880 DisposeRoutineDescriptor(dialogUPP);
5881
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005883 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005884
5885 return itemHit;
5886/*
5887 * Usefull thing which could be used
5888 * SetDialogTimeout(): Auto click a button after timeout
5889 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5890 * MoveDialogItem(): Probably better than SetDialogItem
5891 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005892 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005893 */
5894}
5895#endif /* FEAT_DIALOG_GUI */
5896
5897/*
5898 * Display the saved error message(s).
5899 */
5900#ifdef USE_MCH_ERRMSG
5901 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005902display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903{
5904 char *p;
5905 char_u pError[256];
5906
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005907 if (error_ga.ga_data == NULL)
5908 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005909
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005910 /* avoid putting up a message box with blanks only */
5911 for (p = (char *)error_ga.ga_data; *p; ++p)
5912 if (!isspace(*p))
5913 {
5914 if (STRLEN(p) > 255)
5915 pError[0] = 255;
5916 else
5917 pError[0] = STRLEN(p);
5918
5919 STRNCPY(&pError[1], p, pError[0]);
5920 ParamText(pError, nil, nil, nil);
5921 Alert(128, nil);
5922 break;
5923 /* TODO: handled message longer than 256 chars
5924 * use auto-sizeable alert
5925 * or dialog with scrollbars (TextEdit zone)
5926 */
5927 }
5928 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929}
5930#endif
5931
5932/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005933 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005935 void
5936gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005937{
5938 Point where;
5939
5940 GetMouse(&where);
5941
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005942 *x = where.h;
5943 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944}
5945
5946 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005947gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948{
5949 /* TODO */
5950#if 0
5951 /* From FAQ 3-11 */
5952
5953 CursorDevicePtr myMouse;
5954 Point where;
5955
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005956 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5957 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005958 {
5959 /* New way */
5960
5961 /*
5962 * Get first devoice with one button.
5963 * This will probably be the standad mouse
5964 * startat head of cursor dev list
5965 *
5966 */
5967
5968 myMouse = nil;
5969
5970 do
5971 {
5972 /* Get the next cursor device */
5973 CursorDeviceNextDevice(&myMouse);
5974 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005975 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005976
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005977 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978 }
5979 else
5980 {
5981 /* Old way */
5982 where.h = x;
5983 where.v = y;
5984
5985 *(Point *)RawMouse = where;
5986 *(Point *)MTemp = where;
5987 *(Ptr) CrsrNew = 0xFFFF;
5988 }
5989#endif
5990}
5991
5992 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005993gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005995/*
5996 * Clone PopUp to use menu
5997 * Create a object descriptor for the current selection
5998 * Call the procedure
5999 */
6000
6001 MenuHandle CntxMenu;
6002 Point where;
6003 OSStatus status;
6004 UInt32 CntxType;
6005 SInt16 CntxMenuID;
6006 UInt16 CntxMenuItem;
6007 Str255 HelpName = "";
6008 GrafPtr savePort;
6009
6010 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006011 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006013 GetMouse(&where);
6014 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015 CntxMenu = menu->submenu_handle;
6016
6017 /* TODO: Get the text selection from Vim */
6018
6019 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006020 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006021 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022
6023 if (status == noErr)
6024 {
6025 if (CntxType == kCMMenuItemSelected)
6026 {
6027 /* Handle the menu CntxMenuID, CntxMenuItem */
6028 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006029 /* But what about the current menu, is the menu changed by
6030 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006031 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 }
6033 else if (CntxMenuID == kCMShowHelpSelected)
6034 {
6035 /* Should come up with the help */
6036 }
6037 }
6038
6039 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006040 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041}
6042
6043#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6044/* TODO: Is it need for MACOS_X? (Dany) */
6045 void
6046mch_post_buffer_write(buf_T *buf)
6047{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006048 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6049 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050}
6051#endif
6052
6053#ifdef FEAT_TITLE
6054/*
6055 * Set the window title and icon.
6056 * (The icon is not taken care of).
6057 */
6058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006059gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060{
6061 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6062 * that 256. Even better get it to fit nicely in the titlebar.
6063 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006064#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006065 CFStringRef windowTitle;
6066 size_t windowTitleLen;
6067#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006069#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006070
6071 if (title == NULL) /* nothing to do */
6072 return;
6073
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006074#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006075 windowTitleLen = STRLEN(title);
6076 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
6077
6078 if (windowTitle)
6079 {
6080 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6081 CFRelease(windowTitle);
6082 }
6083#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084 pascalTitle = C2Pascal_save(title);
6085 if (pascalTitle != NULL)
6086 {
6087 SetWTitle(gui.VimWindow, pascalTitle);
6088 vim_free(pascalTitle);
6089 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006090#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091}
6092#endif
6093
6094/*
6095 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6096 */
6097
6098 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006099C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100{
6101 char_u *PascalPtr = (char_u *) PascalString;
6102 int len;
6103 int i;
6104
6105 PascalPtr[0] = 0;
6106 if (CString == NULL)
6107 return 0;
6108
6109 len = STRLEN(CString);
6110 if (len > 255)
6111 len = 255;
6112
6113 for (i = 0; i < len; i++)
6114 PascalPtr[i+1] = CString[i];
6115
6116 PascalPtr[0] = len;
6117
6118 return 0;
6119}
6120
6121 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006122GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123{
6124 /* From FAQ 8-12 */
6125 Str255 filePascal;
6126 CInfoPBRec myCPB;
6127 OSErr err;
6128
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006129 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130
6131 myCPB.dirInfo.ioNamePtr = filePascal;
6132 myCPB.dirInfo.ioVRefNum = 0;
6133 myCPB.dirInfo.ioFDirIndex = 0;
6134 myCPB.dirInfo.ioDrDirID = 0;
6135
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006136 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137
6138 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006139 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140
6141 /* TODO: Use an error code mechanism */
6142 return 0;
6143}
6144
6145/*
6146 * Convert a FSSpec to a fuill path
6147 */
6148
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006149char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150{
6151 /*
6152 * TODO: Add protection for 256 char max.
6153 */
6154
6155 CInfoPBRec theCPB;
6156 char_u fname[256];
6157 char_u *filenamePtr = fname;
6158 OSErr error;
6159 int folder = 1;
6160#ifdef USE_UNIXFILENAME
6161 SInt16 dfltVol_vRefNum;
6162 SInt32 dfltVol_dirID;
6163 FSRef refFile;
6164 OSStatus status;
6165 UInt32 pathSize = 256;
6166 char_u pathname[256];
6167 char_u *path = pathname;
6168#else
6169 Str255 directoryName;
6170 char_u temporary[255];
6171 char_u *temporaryPtr = temporary;
6172#endif
6173
6174#ifdef USE_UNIXFILENAME
6175 /* Get the default volume */
6176 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006177 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006178
6179 if (error)
6180 return NULL;
6181#endif
6182
6183 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006184 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185
6186 /* Get the info about the file specified in FSSpec */
6187 theCPB.dirInfo.ioFDirIndex = 0;
6188 theCPB.dirInfo.ioNamePtr = file.name;
6189 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006190 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006191 theCPB.dirInfo.ioDrDirID = file.parID;
6192
6193 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6194 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006195 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196
6197 /* If we are called for a new file we expect fnfErr */
6198 if ((error) && (error != fnfErr))
6199 return NULL;
6200
6201 /* Check if it's a file or folder */
6202 /* default to file if file don't exist */
6203 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6204 folder = 0; /* It's not a folder */
6205 else
6206 folder = 1;
6207
6208#ifdef USE_UNIXFILENAME
6209 /*
6210 * The function used here are available in Carbon, but
6211 * do nothing une MacOS 8 and 9
6212 */
6213 if (error == fnfErr)
6214 {
6215 /* If the file to be saved does not already exist, it isn't possible
6216 to convert its FSSpec into an FSRef. But we can construct an
6217 FSSpec for the file's parent folder (since we have its volume and
6218 directory IDs), and since that folder does exist, we can convert
6219 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6220 and, finally, append the filename. */
6221 FSSpec dirSpec;
6222 FSRef dirRef;
6223 Str255 emptyFilename = "\p";
6224 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6225 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6226 if (error)
6227 return NULL;
6228
6229 error = FSpMakeFSRef(&dirSpec, &dirRef);
6230 if (error)
6231 return NULL;
6232
6233 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6234 if (status)
6235 return NULL;
6236
6237 STRCAT(path, "/");
6238 STRCAT(path, filenamePtr);
6239 }
6240 else
6241 {
6242 /* If the file to be saved already exists, we can get its full path
6243 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006244 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 if (error)
6246 return NULL;
6247
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006248 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 if (status)
6250 return NULL;
6251 }
6252
6253 /* Add a slash at the end if needed */
6254 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006255 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006257 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258#else
6259 /* TODO: Get rid of all USE_UNIXFILENAME below */
6260 /* Set ioNamePtr, it's the same area which is always reused. */
6261 theCPB.dirInfo.ioNamePtr = directoryName;
6262
6263 /* Trick for first entry, set ioDrParID to the first value
6264 * we want for ioDrDirID*/
6265 theCPB.dirInfo.ioDrParID = file.parID;
6266 theCPB.dirInfo.ioDrDirID = file.parID;
6267
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006268 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006269 do
6270 {
6271 theCPB.dirInfo.ioFDirIndex = -1;
6272 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6273 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006274 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6276
6277 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6278 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006279 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006280
6281 if (error)
6282 return NULL;
6283
6284 /* Put the new directoryName in front of the current fname */
6285 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006286 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287 STRCAT(filenamePtr, ":");
6288 STRCAT(filenamePtr, temporaryPtr);
6289 }
6290#if 1 /* def USE_UNIXFILENAME */
6291 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6292 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6293#else
6294 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6295#endif
6296
6297 /* Get the information about the volume on which the file reside */
6298 theCPB.dirInfo.ioFDirIndex = -1;
6299 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6300 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006301 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006302 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6303
6304 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6305 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006306 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006307
6308 if (error)
6309 return NULL;
6310
6311 /* For MacOS Classic always add the volume name */
6312 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006313 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006314#ifdef USE_UNIXFILENAME
6315 if (file.vRefNum != dfltVol_vRefNum)
6316#endif
6317 {
6318 /* Add the volume name */
6319 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006320 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006321 STRCAT(filenamePtr, ":");
6322 STRCAT(filenamePtr, temporaryPtr);
6323
6324#ifdef USE_UNIXFILENAME
6325 STRCPY(temporaryPtr, filenamePtr);
6326 filenamePtr[0] = 0; /* NULL terminate the string */
6327 STRCAT(filenamePtr, "Volumes:");
6328 STRCAT(filenamePtr, temporaryPtr);
6329#endif
6330 }
6331
6332 /* Append final path separator if it's a folder */
6333 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006334 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335
6336 /* As we use Unix File Name for MacOS X convert it */
6337#ifdef USE_UNIXFILENAME
6338 /* Need to insert leading / */
6339 /* TODO: get the above code to use directly the / */
6340 STRCPY(&temporaryPtr[1], filenamePtr);
6341 temporaryPtr[0] = '/';
6342 STRCPY(filenamePtr, temporaryPtr);
6343 {
6344 char *p;
6345 for (p = fname; *p; p++)
6346 if (*p == ':')
6347 *p = '/';
6348 }
6349#endif
6350
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006351 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006352#endif
6353}
6354
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006355#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356/*
6357 * Input Method Control functions.
6358 */
6359
6360/*
6361 * Notify cursor position to IM.
6362 */
6363 void
6364im_set_position(int row, int col)
6365{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006366#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006367 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006368 im_start_row = row;
6369 im_start_col = col;
6370#endif
6371}
6372
6373static ScriptLanguageRecord gTSLWindow;
6374static ScriptLanguageRecord gTSLInsert;
6375static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6376
6377static Component gTSCWindow;
6378static Component gTSCInsert;
6379static Component gTSCDefault;
6380
6381static int im_initialized = 0;
6382
6383 static void
6384im_on_window_switch(int active)
6385{
6386 ScriptLanguageRecord *slptr = NULL;
6387 OSStatus err;
6388
6389 if (! gui.in_use)
6390 return;
6391
6392 if (im_initialized == 0)
6393 {
6394 im_initialized = 1;
6395
6396 /* save default TSM component (should be U.S.) to default */
6397 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6398 kKeyboardInputMethodClass);
6399 }
6400
6401 if (active == TRUE)
6402 {
6403 im_is_active = TRUE;
6404 ActivateTSMDocument(gTSMDocument);
6405 slptr = &gTSLWindow;
6406
6407 if (slptr)
6408 {
6409 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6410 kKeyboardInputMethodClass);
6411 if (err == noErr)
6412 err = SetTextServiceLanguage(slptr);
6413
6414 if (err == noErr)
6415 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6416 }
6417 }
6418 else
6419 {
6420 err = GetTextServiceLanguage(&gTSLWindow);
6421 if (err == noErr)
6422 slptr = &gTSLWindow;
6423
6424 if (slptr)
6425 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6426 kKeyboardInputMethodClass);
6427
6428 im_is_active = FALSE;
6429 DeactivateTSMDocument(gTSMDocument);
6430 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431}
6432
6433/*
6434 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6435 */
6436 void
6437im_set_active(int active)
6438{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006439 ScriptLanguageRecord *slptr = NULL;
6440 OSStatus err;
6441
6442 if (! gui.in_use)
6443 return;
6444
6445 if (im_initialized == 0)
6446 {
6447 im_initialized = 1;
6448
6449 /* save default TSM component (should be U.S.) to default */
6450 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6451 kKeyboardInputMethodClass);
6452 }
6453
6454 if (active == TRUE)
6455 {
6456 im_is_active = TRUE;
6457 ActivateTSMDocument(gTSMDocument);
6458 slptr = &gTSLInsert;
6459
6460 if (slptr)
6461 {
6462 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6463 kKeyboardInputMethodClass);
6464 if (err == noErr)
6465 err = SetTextServiceLanguage(slptr);
6466
6467 if (err == noErr)
6468 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6469 }
6470 }
6471 else
6472 {
6473 err = GetTextServiceLanguage(&gTSLInsert);
6474 if (err == noErr)
6475 slptr = &gTSLInsert;
6476
6477 if (slptr)
6478 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6479 kKeyboardInputMethodClass);
6480
6481 /* restore to default when switch to normal mode, so than we could
6482 * enter commands easier */
6483 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6484 kKeyboardInputMethodClass);
6485 SetTextServiceLanguage(&gTSLDefault);
6486
6487 im_is_active = FALSE;
6488 DeactivateTSMDocument(gTSMDocument);
6489 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006490}
6491
6492/*
6493 * Get IM status. When IM is on, return not 0. Else return 0.
6494 */
6495 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006496im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006498 if (! gui.in_use)
6499 return 0;
6500
6501 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006503
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006505
6506
6507
6508
6509#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6510// drawer implementation
6511static MenuRef contextMenu = NULL;
6512enum
6513{
6514 kTabContextMenuId = 42,
6515};
6516
6517// the caller has to CFRelease() the returned string
6518 static CFStringRef
6519getTabLabel(tabpage_T *page)
6520{
6521 get_tabline_label(page, FALSE);
6522#ifdef MACOS_CONVERT
6523 return mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6524#else
6525 // TODO: check internal encoding?
6526 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6527 kCFStringEncodingMacRoman);
6528#endif
6529}
6530
6531
6532#define DRAWER_SIZE 150
6533#define DRAWER_INSET 16
6534
6535static ControlRef dataBrowser = NULL;
6536
6537// when the tabline is hidden, vim doesn't call update_tabline(). When
6538// the tabline is shown again, show_tabline() is called before upate_tabline(),
6539// and because of this, the tab labels and vims internal tabs are out of sync
6540// for a very short time. to prevent inconsistent state, we store the labels
6541// of the tabs, not pointers to the tabs (which are invalid for a short time).
6542static CFStringRef *tabLabels = NULL;
6543static int tabLabelsSize = 0;
6544
6545enum
6546{
6547 kTabsColumn = 'Tabs'
6548};
6549
6550 static int
6551getTabCount(void)
6552{
6553 tabpage_T *tp;
6554 int numTabs = 0;
6555
6556 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006557 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006558 return numTabs;
6559}
6560
6561// data browser item display callback
6562 static OSStatus
6563dbItemDataCallback(ControlRef browser,
6564 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006565 DataBrowserPropertyID property /* column id */,
6566 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006567 Boolean changeValue)
6568{
6569 OSStatus status = noErr;
6570
6571 // assert(property == kTabsColumn); // why is this violated??
6572
6573 // changeValue is true if we have a modifieable list and data was changed.
6574 // In our case, it's always false.
6575 // (that is: if (changeValue) updateInternalData(); else return
6576 // internalData();
6577 if (!changeValue)
6578 {
6579 CFStringRef str;
6580
6581 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6582 str = tabLabels[itemID - 1];
6583 status = SetDataBrowserItemDataText(itemData, str);
6584 }
6585 else
6586 status = errDataBrowserPropertyNotSupported;
6587
6588 return status;
6589}
6590
6591// data browser action callback
6592 static void
6593dbItemNotificationCallback(ControlRef browser,
6594 DataBrowserItemID item,
6595 DataBrowserItemNotification message)
6596{
6597 switch (message)
6598 {
6599 case kDataBrowserItemSelected:
6600 send_tabline_event(item);
6601 break;
6602 }
6603}
6604
6605// callbacks needed for contextual menu:
6606 static void
6607dbGetContextualMenuCallback(ControlRef browser,
6608 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006609 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006610 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006611 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006612{
6613 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6614 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6615 *helpItemString = NULL;
6616
6617 *menu = contextMenu;
6618}
6619
6620 static void
6621dbSelectContextualMenuCallback(ControlRef browser,
6622 MenuRef menu,
6623 UInt32 selectionType,
6624 SInt16 menuID,
6625 MenuItemIndex menuItem)
6626{
6627 if (selectionType == kCMMenuItemSelected)
6628 {
6629 MenuCommand command;
6630 GetMenuItemCommandID(menu, menuItem, &command);
6631
6632 // get tab that was selected when the context menu appeared
6633 // (there is always one tab selected). TODO: check if the context menu
6634 // isn't opened on an item but on empty space (has to be possible some
6635 // way, the finder does it too ;-) )
6636 Handle items = NewHandle(0);
6637 if (items != NULL)
6638 {
6639 int numItems;
6640
6641 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6642 kDataBrowserItemIsSelected, items);
6643 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6644 if (numItems > 0)
6645 {
6646 int idx;
6647 DataBrowserItemID *itemsPtr;
6648
6649 HLock(items);
6650 itemsPtr = (DataBrowserItemID *)*items;
6651 idx = itemsPtr[0];
6652 HUnlock(items);
6653 send_tabline_menu_event(idx, command);
6654 }
6655 DisposeHandle(items);
6656 }
6657 }
6658}
6659
6660// focus callback of the data browser to always leave focus in vim
6661 static OSStatus
6662dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6663{
6664 assert(GetEventClass(event) == kEventClassControl
6665 && GetEventKind(event) == kEventControlSetFocusPart);
6666
6667 return paramErr;
6668}
6669
6670
6671// drawer callback to resize data browser to drawer size
6672 static OSStatus
6673drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6674{
6675 switch (GetEventKind(event))
6676 {
6677 case kEventWindowBoundsChanged: // move or resize
6678 {
6679 UInt32 attribs;
6680 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6681 NULL, sizeof(attribs), NULL, &attribs);
6682 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6683 {
6684 Rect r;
6685 GetWindowBounds(drawer, kWindowContentRgn, &r);
6686 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6687 SetControlBounds(dataBrowser, &r);
6688 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6689 kTabsColumn, r.right);
6690 }
6691 }
6692 break;
6693 }
6694
6695 return eventNotHandledErr;
6696}
6697
6698// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6699// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6700// blue highlights in the list view on these systems, though. Oh well.)
6701
6702
6703#import <mach-o/dyld.h>
6704
6705enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6706
6707 static OSStatus
6708myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6709 OptionBits inAttributesToSet,
6710 OptionBits inAttributesToClear)
6711{
6712 long osVersion;
6713 char *symbolName;
6714 NSSymbol symbol = NULL;
6715 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6716 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6717
6718 Gestalt(gestaltSystemVersion, &osVersion);
6719 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6720 return noErr;
6721
6722 // C name mangling...
6723 symbolName = "_DataBrowserChangeAttributes";
6724 if (!NSIsSymbolNameDefined(symbolName)
6725 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6726 return noErr;
6727
6728 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6729 if (dataBrowserChangeAttributes == NULL)
6730 return noErr; // well...
6731 return dataBrowserChangeAttributes(inDataBrowser,
6732 inAttributesToSet, inAttributesToClear);
6733}
6734
6735 static void
6736initialise_tabline(void)
6737{
6738 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6739 DataBrowserCallbacks dbCallbacks;
6740 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6741 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6742 DataBrowserListViewColumnDesc colDesc;
6743
6744 // drawers have to have compositing enabled
6745 CreateNewWindow(kDrawerWindowClass,
6746 kWindowStandardHandlerAttribute
6747 | kWindowCompositingAttribute
6748 | kWindowResizableAttribute
6749 | kWindowLiveResizeAttribute,
6750 &drawerRect, &drawer);
6751
6752 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6753 SetDrawerParent(drawer, gui.VimWindow);
6754 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6755
6756
6757 // create list view embedded in drawer
6758 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6759 &dataBrowser);
6760
6761 dbCallbacks.version = kDataBrowserLatestCallbacks;
6762 InitDataBrowserCallbacks(&dbCallbacks);
6763 dbCallbacks.u.v1.itemDataCallback =
6764 NewDataBrowserItemDataUPP(dbItemDataCallback);
6765 dbCallbacks.u.v1.itemNotificationCallback =
6766 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6767 dbCallbacks.u.v1.getContextualMenuCallback =
6768 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6769 dbCallbacks.u.v1.selectContextualMenuCallback =
6770 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6771
6772 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6773
6774 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6775 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6776 SetDataBrowserSelectionFlags(dataBrowser,
6777 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6778 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6779 kDataBrowserTableViewFillHilite);
6780 Boolean b = false;
6781 SetControlData(dataBrowser, kControlEntireControl,
6782 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6783
6784 // enable blue background in data browser (this is only in 10.4 and vim
6785 // has to support older osx versions as well, so we have to load this
6786 // function dynamically)
6787 myDataBrowserChangeAttributes(dataBrowser,
6788 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6789
6790 // install callback that keeps focus in vim and away from the data browser
6791 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6792 NULL, NULL);
6793
6794 // install callback that keeps data browser at the size of the drawer
6795 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6796 NULL, NULL);
6797
6798 // add "tabs" column to data browser
6799 colDesc.propertyDesc.propertyID = kTabsColumn;
6800 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6801
6802 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6803 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6804
6805 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6806 colDesc.headerBtnDesc.minimumWidth = 100;
6807 colDesc.headerBtnDesc.maximumWidth = 150;
6808 colDesc.headerBtnDesc.titleOffset = 0;
6809 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6810 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6811 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6812 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6813
6814 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6815
6816 // create tabline popup menu required by vim docs (see :he tabline-menu)
6817 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6818 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6819 TABLINE_MENU_CLOSE, NULL);
6820 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6821 TABLINE_MENU_NEW, NULL);
6822 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6823 TABLINE_MENU_OPEN, NULL);
6824}
6825
6826
6827/*
6828 * Show or hide the tabline.
6829 */
6830 void
6831gui_mch_show_tabline(int showit)
6832{
6833 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006834 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006835 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006836 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006837}
6838
6839/*
6840 * Return TRUE when tabline is displayed.
6841 */
6842 int
6843gui_mch_showing_tabline(void)
6844{
6845 WindowDrawerState state = GetDrawerState(drawer);
6846
6847 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6848}
6849
6850/*
6851 * Update the labels of the tabline.
6852 */
6853 void
6854gui_mch_update_tabline(void)
6855{
6856 tabpage_T *tp;
6857 int numTabs = getTabCount();
6858 int nr = 1;
6859 int curtabidx = 1;
6860
6861 // adjust data browser
6862 if (tabLabels != NULL)
6863 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006864 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006865
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006866 for (i = 0; i < tabLabelsSize; ++i)
6867 CFRelease(tabLabels[i]);
6868 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006869 }
6870 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6871 tabLabelsSize = numTabs;
6872
6873 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6874 {
6875 if (tp == curtab)
6876 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006877 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006878 }
6879
6880 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6881 kDataBrowserItemNoProperty);
6882 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6883 // can pass NULL for the id array
6884 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6885 kDataBrowserItemNoProperty);
6886
6887 DataBrowserItemID item = curtabidx;
6888 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6889}
6890
6891/*
6892 * Set the current tab to "nr". First tab is 1.
6893 */
6894 void
6895gui_mch_set_curtab(nr)
6896 int nr;
6897{
6898 DataBrowserItemID item = nr;
6899 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6900
6901 // TODO: call something like this?: (or restore scroll position, or...)
6902 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6903 kDataBrowserRevealOnly);
6904}
6905
6906#endif // FEAT_GUI_TABLINE