blob: 8f90e43037a6c02feeae66938fc8af3c4556391c [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 Moolenaar26a60b42005-02-22 08:49:11 +000062static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +000063#endif
64
Bram Moolenaar071d4272004-06-13 20:20:40 +000065
66/* Include some file. TODO: move into os_mac.h */
67#include <Menus.h>
68#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000069#include <Processes.h>
70#ifdef USE_AEVENT
71# include <AppleEvents.h>
72# include <AERegistry.h>
73#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000074# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000075#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
76# include <ControlDefinitions.h>
77# include <Navigation.h> /* Navigation only part of ?? */
78#endif
79
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000080/* Help Manager (balloon.h, HM prefixed functions) are not supported
81 * under Carbon (Jussi) */
82# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +000083/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000084# include <MacHelp.h>
85# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000086
87/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000088 * These seem to be rectangle options. Why are they not found in
89 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +000090 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000091#define kNothing 0
92#define kCreateEmpty 2 /*1*/
93#define kCreateRect 2
94#define kDestroy 3
95
96/*
97 * Dany: Don't like those...
98 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000099#define topLeft(r) (((Point*)&(r))[0])
100#define botRight(r) (((Point*)&(r))[1])
101
102
103/* Time of last mouse click, to detect double-click */
104static long lastMouseTick = 0;
105
106/* ??? */
107static RgnHandle cursorRgn;
108static RgnHandle dragRgn;
109static Rect dragRect;
110static short dragRectEnbl;
111static short dragRectControl;
112
113/* This variable is set when waiting for an event, which is the only moment
114 * scrollbar dragging can be done directly. It's not allowed while commands
115 * are executed, because it may move the cursor and that may cause unexpected
116 * problems (e.g., while ":s" is working).
117 */
118static int allow_scrollbar = FALSE;
119
120/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122
123/* Feedback Action for Scrollbar */
124ControlActionUPP gScrollAction;
125ControlActionUPP gScrollDrag;
126
127/* Keeping track of which scrollbar is being dragged */
128static ControlHandle dragged_sb = NULL;
129
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000130static struct
131{
132 FMFontFamily family;
133 FMFontSize size;
134 FMFontStyle style;
135 Boolean isPanelVisible;
136} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000137
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000138#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000139# define USE_ATSUI_DRAWING
140ATSUStyle gFontStyle;
141Boolean gIsFontFallbackSet;
142#endif
143
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144/* Colors Macros */
145#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
146#define Red(c) ((c & 0x00FF0000) >> 16)
147#define Green(c) ((c & 0x0000FF00) >> 8)
148#define Blue(c) ((c & 0x000000FF) >> 0)
149
150/* Key mapping */
151
152#define vk_Esc 0x35 /* -> 1B */
153
154#define vk_F1 0x7A /* -> 10 */
155#define vk_F2 0x78 /*0x63*/
156#define vk_F3 0x63 /*0x76*/
157#define vk_F4 0x76 /*0x60*/
158#define vk_F5 0x60 /*0x61*/
159#define vk_F6 0x61 /*0x62*/
160#define vk_F7 0x62 /*0x63*/ /*?*/
161#define vk_F8 0x64
162#define vk_F9 0x65
163#define vk_F10 0x6D
164#define vk_F11 0x67
165#define vk_F12 0x6F
166#define vk_F13 0x69
167#define vk_F14 0x6B
168#define vk_F15 0x71
169
170#define vk_Clr 0x47 /* -> 1B (ESC) */
171#define vk_Enter 0x4C /* -> 03 */
172
173#define vk_Space 0x31 /* -> 20 */
174#define vk_Tab 0x30 /* -> 09 */
175#define vk_Return 0x24 /* -> 0D */
176/* This is wrong for OSX, what is it for? */
177#define vk_Delete 0X08 /* -> 08 BackSpace */
178
179#define vk_Help 0x72 /* -> 05 */
180#define vk_Home 0x73 /* -> 01 */
181#define vk_PageUp 0x74 /* -> 0D */
182#define vk_FwdDelete 0x75 /* -> 7F */
183#define vk_End 0x77 /* -> 04 */
184#define vk_PageDown 0x79 /* -> 0C */
185
186#define vk_Up 0x7E /* -> 1E */
187#define vk_Down 0x7D /* -> 1F */
188#define vk_Left 0x7B /* -> 1C */
189#define vk_Right 0x7C /* -> 1D */
190
191#define vk_Undo vk_F1
192#define vk_Cut vk_F2
193#define vk_Copy vk_F3
194#define vk_Paste vk_F4
195#define vk_PrintScreen vk_F13
196#define vk_SCrollLock vk_F14
197#define vk_Pause vk_F15
198#define vk_NumLock vk_Clr
199#define vk_Insert vk_Help
200
201#define KeySym char
202
203static struct
204{
205 KeySym key_sym;
206 char_u vim_code0;
207 char_u vim_code1;
208} special_keys[] =
209{
210 {vk_Up, 'k', 'u'},
211 {vk_Down, 'k', 'd'},
212 {vk_Left, 'k', 'l'},
213 {vk_Right, 'k', 'r'},
214
215 {vk_F1, 'k', '1'},
216 {vk_F2, 'k', '2'},
217 {vk_F3, 'k', '3'},
218 {vk_F4, 'k', '4'},
219 {vk_F5, 'k', '5'},
220 {vk_F6, 'k', '6'},
221 {vk_F7, 'k', '7'},
222 {vk_F8, 'k', '8'},
223 {vk_F9, 'k', '9'},
224 {vk_F10, 'k', ';'},
225
226 {vk_F11, 'F', '1'},
227 {vk_F12, 'F', '2'},
228 {vk_F13, 'F', '3'},
229 {vk_F14, 'F', '4'},
230 {vk_F15, 'F', '5'},
231
232/* {XK_Help, '%', '1'}, */
233/* {XK_Undo, '&', '8'}, */
234/* {XK_BackSpace, 'k', 'b'}, */
235#ifndef MACOS_X
236 {vk_Delete, 'k', 'b'},
237#endif
238 {vk_Insert, 'k', 'I'},
239 {vk_FwdDelete, 'k', 'D'},
240 {vk_Home, 'k', 'h'},
241 {vk_End, '@', '7'},
242/* {XK_Prior, 'k', 'P'}, */
243/* {XK_Next, 'k', 'N'}, */
244/* {XK_Print, '%', '9'}, */
245
246 {vk_PageUp, 'k', 'P'},
247 {vk_PageDown, 'k', 'N'},
248
249 /* End of list marker: */
250 {(KeySym)0, 0, 0}
251};
252
253/*
254 * ------------------------------------------------------------
255 * Forward declaration (for those needed)
256 * ------------------------------------------------------------
257 */
258
259#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000260OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261#endif
262
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000263#ifdef FEAT_GUI_TABLINE
264static void initialise_tabline(void);
265static WindowRef drawer = NULL; // TODO: put into gui.h
266#endif
267
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268/*
269 * ------------------------------------------------------------
270 * Conversion Utility
271 * ------------------------------------------------------------
272 */
273
274/*
275 * C2Pascal_save
276 *
277 * Allocate memory and convert the C-String passed in
278 * into a pascal string
279 *
280 */
281
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000282 char_u *
283C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284{
285 char_u *PascalString;
286 int len;
287
288 if (Cstring == NULL)
289 return NULL;
290
291 len = STRLEN(Cstring);
292
293 if (len > 255) /* Truncate if necessary */
294 len = 255;
295
296 PascalString = alloc(len + 1);
297 if (PascalString != NULL)
298 {
299 mch_memmove(PascalString + 1, Cstring, len);
300 PascalString[0] = len;
301 }
302
303 return PascalString;
304}
305
306/*
307 * C2Pascal_save_and_remove_backslash
308 *
309 * Allocate memory and convert the C-String passed in
310 * into a pascal string. Also remove the backslash at the same time
311 *
312 */
313
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000314 char_u *
315C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316{
317 char_u *PascalString;
318 int len;
319 char_u *p, *c;
320
321 len = STRLEN(Cstring);
322
323 if (len > 255) /* Truncate if necessary */
324 len = 255;
325
326 PascalString = alloc(len + 1);
327 if (PascalString != NULL)
328 {
329 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
330 {
331 if ((*c == '\\') && (c[1] != 0))
332 {
333 c++;
334 }
335 *p = *c;
336 p++;
337 len++;
338 }
339 PascalString[0] = len;
340 }
341
342 return PascalString;
343}
344
345/*
346 * Convert the modifiers of an Event into vim's modifiers (mouse)
347 */
348
349 int_u
350EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
351{
352 int_u vimModifiers = 0x00;
353
354 if (macModifiers & (shiftKey | rightShiftKey))
355 vimModifiers |= MOUSE_SHIFT;
356 if (macModifiers & (controlKey | rightControlKey))
357 vimModifiers |= MOUSE_CTRL;
358 if (macModifiers & (optionKey | rightOptionKey))
359 vimModifiers |= MOUSE_ALT;
360#if 0
361 /* Not yet supported */
362 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
363 vimModifiers |= MOUSE_CMD;
364#endif
365 return (vimModifiers);
366}
367
368/*
369 * Convert the modifiers of an Event into vim's modifiers (keys)
370 */
371
372 static int_u
373EventModifiers2VimModifiers(EventModifiers macModifiers)
374{
375 int_u vimModifiers = 0x00;
376
377 if (macModifiers & (shiftKey | rightShiftKey))
378 vimModifiers |= MOD_MASK_SHIFT;
379 if (macModifiers & (controlKey | rightControlKey))
380 vimModifiers |= MOD_MASK_CTRL;
381 if (macModifiers & (optionKey | rightOptionKey))
382 vimModifiers |= MOD_MASK_ALT;
383#ifdef USE_CMD_KEY
384 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
385 vimModifiers |= MOD_MASK_CMD;
386#endif
387 return (vimModifiers);
388}
389
390/* Convert a string representing a point size into pixels. The string should
391 * be a positive decimal number, with an optional decimal point (eg, "12", or
392 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
393 * character is stored in *end. The flag "vertical" says whether this
394 * calculation is for a vertical (height) size or a horizontal (width) one.
395 *
396 * From gui_w48.c
397 */
398 static int
399points_to_pixels(char_u *str, char_u **end, int vertical)
400{
401 int pixels;
402 int points = 0;
403 int divisor = 0;
404
405 while (*str)
406 {
407 if (*str == '.' && divisor == 0)
408 {
409 /* Start keeping a divisor, for later */
410 divisor = 1;
411 continue;
412 }
413
414 if (!isdigit(*str))
415 break;
416
417 points *= 10;
418 points += *str - '0';
419 divisor *= 10;
420
421 ++str;
422 }
423
424 if (divisor == 0)
425 divisor = 1;
426
427 pixels = points/divisor;
428 *end = str;
429 return pixels;
430}
431
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000432#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000433/*
434 * Deletes all traces of any Windows-style mnemonic text (including any
435 * parentheses) from a menu item and returns the cleaned menu item title.
436 * The caller is responsible for releasing the returned string.
437 */
438 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000439menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000440{
441 CFStringRef name;
442 size_t menuTitleLen;
443 CFIndex displayLen;
444 CFRange mnemonicStart;
445 CFRange mnemonicEnd;
446 CFMutableStringRef cleanedName;
447
448 menuTitleLen = STRLEN(menu->dname);
449 name = mac_enc_to_cfstring(menu->dname, menuTitleLen);
450
451 if (name)
452 {
453 /* Simple mnemonic-removal algorithm, assumes single parenthesized
454 * mnemonic character towards the end of the menu text */
455 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
456 displayLen = CFStringGetLength(name);
457
458 if (mnemonicStart.location != kCFNotFound
459 && (mnemonicStart.location + 2) < displayLen
460 && CFStringGetCharacterAtIndex(name,
461 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
462 {
463 if (CFStringFindWithOptions(name, CFSTR(")"),
464 CFRangeMake(mnemonicStart.location + 1,
465 displayLen - mnemonicStart.location - 1),
466 kCFCompareBackwards, &mnemonicEnd) &&
467 (mnemonicStart.location + 2) == mnemonicEnd.location)
468 {
469 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
470 if (cleanedName)
471 {
472 CFStringDelete(cleanedName,
473 CFRangeMake(mnemonicStart.location,
474 mnemonicEnd.location + 1 -
475 mnemonicStart.location));
476
477 CFRelease(name);
478 name = cleanedName;
479 }
480 }
481 }
482 }
483
484 return name;
485}
486#endif
487
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488/*
489 * Convert a list of FSSpec aliases into a list of fullpathname
490 * character strings.
491 */
492
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000493 char_u **
494new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495{
496 char_u **fnames = NULL;
497 OSErr newError;
498 long fileCount;
499 FSSpec fileToOpen;
500 long actualSize;
501 AEKeyword dummyKeyword;
502 DescType dummyType;
503
504 /* Get number of files in list */
505 *error = AECountItems(theList, numFiles);
506 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000507 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508
509 /* Allocate the pointer list */
510 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
511
512 /* Empty out the list */
513 for (fileCount = 0; fileCount < *numFiles; fileCount++)
514 fnames[fileCount] = NULL;
515
516 /* Scan the list of FSSpec */
517 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
518 {
519 /* Get the alias for the nth file, convert to an FSSpec */
520 newError = AEGetNthPtr(theList, fileCount, typeFSS,
521 &dummyKeyword, &dummyType,
522 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
523 if (newError)
524 {
525 /* Caller is able to clean up */
526 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000527 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528 }
529
530 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000531 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 }
533
534 return (fnames);
535}
536
537/*
538 * ------------------------------------------------------------
539 * CodeWarrior External Editor Support
540 * ------------------------------------------------------------
541 */
542#ifdef FEAT_CW_EDITOR
543
544/*
545 * Handle the Window Search event from CodeWarrior
546 *
547 * Description
548 * -----------
549 *
550 * The IDE sends the Window Search AppleEvent to the editor when it
551 * needs to know whether a particular file is open in the editor.
552 *
553 * Event Reply
554 * -----------
555 *
556 * None. Put data in the location specified in the structure received.
557 *
558 * Remarks
559 * -------
560 *
561 * When the editor receives this event, determine whether the specified
562 * file is open. If it is, return the modification date/time for that file
563 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000564 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 *
566 */
567
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568typedef struct WindowSearch WindowSearch;
569struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
570{
571 FSSpec theFile; // identifies the file
572 long *theDate; // where to put the modification date/time
573};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000575 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000576Handle_KAHL_SRCH_AE(
577 const AppleEvent *theAEvent,
578 AppleEvent *theReply,
579 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580{
581 OSErr error = noErr;
582 buf_T *buf;
583 int foundFile = false;
584 DescType typeCode;
585 WindowSearch SearchData;
586 Size actualSize;
587
588 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
589 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000590 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000592 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000594 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595
596 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
597 if (buf->b_ml.ml_mfp != NULL
598 && SearchData.theFile.parID == buf->b_FSSpec.parID
599 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
600 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
601 {
602 foundFile = true;
603 break;
604 }
605
606 if (foundFile == false)
607 *SearchData.theDate = fnfErr;
608 else
609 *SearchData.theDate = buf->b_mtime;
610
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 return error;
612};
613
614/*
615 * Handle the Modified (from IDE to Editor) event from CodeWarrior
616 *
617 * Description
618 * -----------
619 *
620 * The IDE sends this event to the external editor when it wants to
621 * know which files that are open in the editor have been modified.
622 *
623 * Parameters None.
624 * ----------
625 *
626 * Event Reply
627 * -----------
628 * The reply for this event is:
629 *
630 * keyDirectObject typeAEList required
631 * each element in the list is a structure of typeChar
632 *
633 * Remarks
634 * -------
635 *
636 * When building the reply event, include one element in the list for
637 * each open file that has been modified.
638 *
639 */
640
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641typedef struct ModificationInfo ModificationInfo;
642struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
643{
644 FSSpec theFile; // identifies the file
645 long theDate; // the date/time the file was last modified
646 short saved; // set this to zero when replying, unused
647};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000649 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000650Handle_KAHL_MOD_AE(
651 const AppleEvent *theAEvent,
652 AppleEvent *theReply,
653 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654{
655 OSErr error = noErr;
656 AEDescList replyList;
657 long numFiles;
658 ModificationInfo theFile;
659 buf_T *buf;
660
661 theFile.saved = 0;
662
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000663 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000665 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666
667 /* Send the reply */
668/* replyObject.descriptorType = typeNull;
669 replyObject.dataHandle = nil;*/
670
671/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
672 error = AECreateList(nil, 0, false, &replyList);
673 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000674 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675
676#if 0
677 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000679 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
680 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 * sizeof(DescType))
682 */
683
684 /* AEPutDesc */
685#endif
686
687 numFiles = 0;
688 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
689 if (buf->b_ml.ml_mfp != NULL)
690 {
691 /* Add this file to the list */
692 theFile.theFile = buf->b_FSSpec;
693 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000694/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
695 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 };
697
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698#if 0
699 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700#endif
701
702 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000703 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 if (replyList.dataHandle)
706 AEDisposeDesc(&replyList);
707
708 return error;
709};
710
711/*
712 * Handle the Get Text event from CodeWarrior
713 *
714 * Description
715 * -----------
716 *
717 * The IDE sends the Get Text AppleEvent to the editor when it needs
718 * the source code from a file. For example, when the user issues a
719 * Check Syntax or Compile command, the compiler needs access to
720 * the source code contained in the file.
721 *
722 * Event Reply
723 * -----------
724 *
725 * None. Put data in locations specified in the structure received.
726 *
727 * Remarks
728 * -------
729 *
730 * When the editor receives this event, it must set the size of the handle
731 * in theText to fit the data in the file. It must then copy the entire
732 * contents of the specified file into the memory location specified in
733 * theText.
734 *
735 */
736
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737typedef struct CW_GetText CW_GetText;
738struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
739{
740 FSSpec theFile; /* identifies the file */
741 Handle theText; /* the location where you return the text (must be resized properly) */
742 long *unused; /* 0 (not used) */
743 long *theDate; /* where to put the modification date/time */
744};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000746 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000747Handle_KAHL_GTTX_AE(
748 const AppleEvent *theAEvent,
749 AppleEvent *theReply,
750 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751{
752 OSErr error = noErr;
753 buf_T *buf;
754 int foundFile = false;
755 DescType typeCode;
756 CW_GetText GetTextData;
757 Size actualSize;
758 char_u *line;
759 char_u *fullbuffer = NULL;
760 long linesize;
761 long lineStart;
762 long BufferSize;
763 long lineno;
764
765 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
766
767 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000768 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769
770 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
771 if (buf->b_ml.ml_mfp != NULL)
772 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
773 {
774 foundFile = true;
775 break;
776 }
777
778 if (foundFile)
779 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000780 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
782 {
783 /* Must use the right buffer */
784 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
785 linesize = STRLEN(line) + 1;
786 lineStart = BufferSize;
787 BufferSize += linesize;
788 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000789 SetHandleSize(GetTextData.theText, BufferSize);
790 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 break; /* Simple handling for now */
793 }
794 else
795 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000796 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000798 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000800 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 }
802 }
803 if (fullbuffer != NULL)
804 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000805 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000807 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 }
809 if (foundFile == false)
810 *GetTextData.theDate = fnfErr;
811 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000812/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 *GetTextData.theDate = buf->b_mtime;
814 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000816 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000818 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819}
820
821/*
822 *
823 */
824
825/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000826 pascal OSErr
827FindProcessBySignature(
828 const OSType targetType,
829 const OSType targetCreator,
830 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831{
832 OSErr anErr = noErr;
833 Boolean lookingForProcess = true;
834
835 ProcessInfoRec infoRec;
836
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000837 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 infoRec.processName = nil;
839 infoRec.processAppSpec = nil;
840
841 psnPtr->lowLongOfPSN = kNoProcess;
842 psnPtr->highLongOfPSN = kNoProcess;
843
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000844 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000846 anErr = GetNextProcess(psnPtr);
847 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 else
850 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000851 anErr = GetProcessInformation(psnPtr, &infoRec);
852 if ((anErr == noErr)
853 && (infoRec.processType == targetType)
854 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 }
857 }
858
859 return anErr;
860}//end FindProcessBySignature
861
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000862 void
863Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000865 OSErr anErr = noErr;
866 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
868 AppleEvent theReply = { typeNull, nil };
869 AESendMode sendMode;
870 AppleEvent theEvent = {typeNull, nil };
871 AEIdleUPP idleProcUPP = nil;
872 ModificationInfo ModData;
873
874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000875 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000876 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000878 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
879 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000881 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882 {
883 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
884 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
885 }
886
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000887 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888
889 /* Add the parms */
890 ModData.theFile = buf->b_FSSpec;
891 ModData.theDate = buf->b_mtime;
892
893 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000894 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000896 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 sendMode = kAENoReply;
898 else
899 sendMode = kAEWaitReply;
900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000901 if (anErr == noErr)
902 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
903 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000905/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000907 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908 }
909}
910#endif /* FEAT_CW_EDITOR */
911
912/*
913 * ------------------------------------------------------------
914 * Apple Event Handling procedure
915 * ------------------------------------------------------------
916 */
917#ifdef USE_AEVENT
918
919/*
920 * Handle the Unused parms of an AppleEvent
921 */
922
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000923 OSErr
924HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925{
926 OSErr error;
927 long actualSize;
928 DescType dummyType;
929 AEKeyword missedKeyword;
930
931 /* Get the "missed keyword" attribute from the AppleEvent. */
932 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
933 typeKeyword, &dummyType,
934 (Ptr)&missedKeyword, sizeof(missedKeyword),
935 &actualSize);
936
937 /* If the descriptor isn't found, then we got the required parameters. */
938 if (error == errAEDescNotFound)
939 {
940 error = noErr;
941 }
942 else
943 {
944#if 0
945 /* Why is this removed? */
946 error = errAEEventNotHandled;
947#endif
948 }
949
950 return error;
951}
952
953
954/*
955 * Handle the ODoc AppleEvent
956 *
957 * Deals with all files dragged to the application icon.
958 *
959 */
960
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961typedef struct SelectionRange SelectionRange;
962struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
963{
964 short unused1; // 0 (not used)
965 short lineNum; // line to select (<0 to specify range)
966 long startRange; // start of selection range (if line < 0)
967 long endRange; // end of selection range (if line < 0)
968 long unused2; // 0 (not used)
969 long theDate; // modification date/time
970};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971
972/* The IDE uses the optional keyAEPosition parameter to tell the ed-
973 itor the selection range. If lineNum is zero or greater, scroll the text
974 to the specified line. If lineNum is less than zero, use the values in
975 startRange and endRange to select the specified characters. Scroll
976 the text to display the selection. If lineNum, startRange, and
977 endRange are all negative, there is no selection range specified.
978 */
979
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000980 pascal OSErr
981HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982{
983 /*
984 * TODO: Clean up the code with convert the AppleEvent into
985 * a ":args"
986 */
987 OSErr error = noErr;
988// OSErr firstError = noErr;
989// short numErrors = 0;
990 AEDesc theList;
991 DescType typeCode;
992 long numFiles;
993 // long fileCount;
994 char_u **fnames;
995// char_u fname[256];
996 Size actualSize;
997 SelectionRange thePosition;
998 short gotPosition = false;
999 long lnum;
1000
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 /* the direct object parameter is the list of aliases to files (one or more) */
1002 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1003 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001004 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005
1006
1007 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1008 if (error == noErr)
1009 gotPosition = true;
1010 if (error == errAEDescNotFound)
1011 error = noErr;
1012 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001013 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014
Bram Moolenaar071d4272004-06-13 20:20:40 +00001015/*
1016 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1017
1018 if (^error) then
1019 {
1020 if (thePosition.lineNum >= 0)
1021 {
1022 // Goto this line
1023 }
1024 else
1025 {
1026 // Set the range char wise
1027 }
1028 }
1029 */
1030
1031
1032#ifdef FEAT_VISUAL
1033 reset_VIsual();
1034#endif
1035
1036 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1037
1038 if (error)
1039 {
1040 /* TODO: empty fnames[] first */
1041 vim_free(fnames);
1042 return (error);
1043 }
1044
1045 if (starting > 0)
1046 {
1047 int i;
1048 char_u *p;
1049
1050 /* these are the initial files dropped on the Vim icon */
1051 for (i = 0 ; i < numFiles; i++)
1052 {
1053 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1054 || (p = vim_strsave(fnames[i])) == NULL)
1055 mch_exit(2);
1056 else
1057 alist_add(&global_alist, p, 2);
1058 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001059
1060 /* Change directory to the location of the first file. */
1061 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1062 shorten_fnames(TRUE);
1063
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 goto finished;
1065 }
1066
1067 /* Handle the drop, :edit to get to the file */
1068 handle_drop(numFiles, fnames, FALSE);
1069
1070 /* TODO: Handle the goto/select line more cleanly */
1071 if ((numFiles == 1) & (gotPosition))
1072 {
1073 if (thePosition.lineNum >= 0)
1074 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001075 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 /* oap->motion_type = MLINE;
1077 setpcmark();*/
1078 if (lnum < 1L)
1079 lnum = 1L;
1080 else if (lnum > curbuf->b_ml.ml_line_count)
1081 lnum = curbuf->b_ml.ml_line_count;
1082 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001083 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084 /* beginline(BL_SOL | BL_FIX);*/
1085 }
1086 else
1087 goto_byte(thePosition.startRange + 1);
1088 }
1089
1090 /* Update the screen display */
1091 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001092#ifdef FEAT_VISUAL
1093 /* Select the text if possible */
1094 if (gotPosition)
1095 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001096 VIsual_active = TRUE;
1097 VIsual_select = FALSE;
1098 VIsual = curwin->w_cursor;
1099 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001100 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001101 VIsual_mode = 'v';
1102 goto_byte(thePosition.endRange);
1103 }
1104 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001105 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001106 VIsual_mode = 'V';
1107 VIsual.col = 0;
1108 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001109 }
1110#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 setcursor();
1112 out_flush();
1113
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001114 /* Fake mouse event to wake from stall */
1115 PostEvent(mouseUp, 0);
1116
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001117finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 AEDisposeDesc(&theList); /* dispose what we allocated */
1119
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001120 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001121 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122}
1123
1124/*
1125 *
1126 */
1127
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001128 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001129Handle_aevt_oapp_AE(
1130 const AppleEvent *theAEvent,
1131 AppleEvent *theReply,
1132 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133{
1134 OSErr error = noErr;
1135
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001136 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001137 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001138}
1139
1140/*
1141 *
1142 */
1143
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001144 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001145Handle_aevt_quit_AE(
1146 const AppleEvent *theAEvent,
1147 AppleEvent *theReply,
1148 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149{
1150 OSErr error = noErr;
1151
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001152 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001154 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155
1156 /* Need to fake a :confirm qa */
1157 do_cmdline_cmd((char_u *)"confirm qa");
1158
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001159 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160}
1161
1162/*
1163 *
1164 */
1165
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001166 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001167Handle_aevt_pdoc_AE(
1168 const AppleEvent *theAEvent,
1169 AppleEvent *theReply,
1170 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171{
1172 OSErr error = noErr;
1173
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001174 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001176 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177}
1178
1179/*
1180 * Handling of unknown AppleEvent
1181 *
1182 * (Just get rid of all the parms)
1183 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001184 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001185Handle_unknown_AE(
1186 const AppleEvent *theAEvent,
1187 AppleEvent *theReply,
1188 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189{
1190 OSErr error = noErr;
1191
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001192 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001193
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001194 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001195}
1196
1197
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198/*
1199 * Install the various AppleEvent Handlers
1200 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001201 OSErr
1202InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203{
1204 OSErr error;
1205
1206 /* install open application handler */
1207 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001208 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209 if (error)
1210 {
1211 return error;
1212 }
1213
1214 /* install quit application handler */
1215 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001216 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217 if (error)
1218 {
1219 return error;
1220 }
1221
1222 /* install open document handler */
1223 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001224 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225 if (error)
1226 {
1227 return error;
1228 }
1229
1230 /* install print document handler */
1231 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001232 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233
1234/* Install Core Suite */
1235/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001236 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237
1238 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001239 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240
1241 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001242 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243
1244 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001245 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246
1247 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001248 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249
1250 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001251 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252
1253 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001254 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255
1256 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001257 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258
1259 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001260 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261
1262 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001263 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264
1265 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001266 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267
1268 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001269 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001270
1271 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001272 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273*/
1274
1275#ifdef FEAT_CW_EDITOR
1276 /*
1277 * Bind codewarrior support handlers
1278 */
1279 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001280 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 if (error)
1282 {
1283 return error;
1284 }
1285 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001286 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287 if (error)
1288 {
1289 return error;
1290 }
1291 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001292 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 if (error)
1294 {
1295 return error;
1296 }
1297#endif
1298
1299 return error;
1300
1301}
1302#endif /* USE_AEVENT */
1303
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001304
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001305/*
1306 * Callback function, installed by InstallFontPanelHandler(), below,
1307 * to handle Font Panel events.
1308 */
1309 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001310FontPanelHandler(
1311 EventHandlerCallRef inHandlerCallRef,
1312 EventRef inEvent,
1313 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001314{
1315 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1316 {
1317 gFontPanelInfo.isPanelVisible = false;
1318 return noErr;
1319 }
1320
1321 if (GetEventKind(inEvent) == kEventFontSelection)
1322 {
1323 OSStatus status;
1324 FMFontFamily newFamily;
1325 FMFontSize newSize;
1326 FMFontStyle newStyle;
1327
1328 /* Retrieve the font family ID number. */
1329 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1330 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1331 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1332 &newFamily);
1333 if (status == noErr)
1334 gFontPanelInfo.family = newFamily;
1335
1336 /* Retrieve the font size. */
1337 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1338 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1339 if (status == noErr)
1340 gFontPanelInfo.size = newSize;
1341
1342 /* Retrieve the font style (bold, etc.). Currently unused. */
1343 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1344 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1345 if (status == noErr)
1346 gFontPanelInfo.style = newStyle;
1347 }
1348 return noErr;
1349}
1350
1351
1352 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001353InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001354{
1355 EventTypeSpec eventTypes[2];
1356 EventHandlerUPP handlerUPP;
1357 /* EventHandlerRef handlerRef; */
1358
1359 eventTypes[0].eventClass = kEventClassFont;
1360 eventTypes[0].eventKind = kEventFontSelection;
1361 eventTypes[1].eventClass = kEventClassFont;
1362 eventTypes[1].eventKind = kEventFontPanelClosed;
1363
1364 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1365
1366 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1367 /*userData=*/NULL, /*handlerRef=*/NULL);
1368}
1369
1370
1371/*
1372 * Fill the buffer pointed to by outName with the name and size
1373 * of the font currently selected in the Font Panel.
1374 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001375#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001376 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001377GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001378{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001379 Str255 buf;
1380 ByteCount fontNameLen = 0;
1381 ATSUFontID fid;
1382 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001383
1384 if (!outName)
1385 return;
1386
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001387 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1388 {
1389 /* Canonicalize localized font names */
1390 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1391 gFontPanelInfo.style, &fid, NULL) != noErr)
1392 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001393
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001394 /* Request font name with Mac encoding (otherwise we could
1395 * get an unwanted utf-16 name) */
1396 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1397 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001398 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001399 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001400
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001401 /* Only encode font size, because style (bold, italic, etc) is
1402 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001403 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001404 gFontPanelInfo.size/*,
1405 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1406 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1407 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1408
1409 if ((fontNameLen + STRLEN(styleString)) < 255)
1410 STRCPY(outName + fontNameLen, styleString);
1411 }
1412 else
1413 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001414 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001415 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001416}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001417
1418
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419/*
1420 * ------------------------------------------------------------
1421 * Unfiled yet
1422 * ------------------------------------------------------------
1423 */
1424
1425/*
1426 * gui_mac_get_menu_item_index
1427 *
1428 * Returns the index inside the menu wher
1429 */
1430 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001431gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432{
1433 short index;
1434 short itemIndex = -1;
1435 vimmenu_T *pBrother;
1436
1437 /* Only menu without parent are the:
1438 * -menu in the menubar
1439 * -popup menu
1440 * -toolbar (guess)
1441 *
1442 * Which are not items anyway.
1443 */
1444 if (pMenu->parent)
1445 {
1446 /* Start from the Oldest Brother */
1447 pBrother = pMenu->parent->children;
1448 index = 1;
1449 while ((pBrother) && (itemIndex == -1))
1450 {
1451 if (pBrother == pMenu)
1452 itemIndex = index;
1453 index++;
1454 pBrother = pBrother->next;
1455 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456 }
1457 return itemIndex;
1458}
1459
1460 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001461gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462{
1463 short index;
1464 vimmenu_T *pChildMenu;
1465 vimmenu_T *pElder = pMenu->parent;
1466
1467
1468 /* Only menu without parent are the:
1469 * -menu in the menubar
1470 * -popup menu
1471 * -toolbar (guess)
1472 *
1473 * Which are not items anyway.
1474 */
1475
1476 if ((pElder) && (pElder->submenu_id == menuID))
1477 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1479 pMenu = pMenu->next;
1480 }
1481 else
1482 {
1483 for (; pMenu != NULL; pMenu = pMenu->next)
1484 {
1485 if (pMenu->children != NULL)
1486 {
1487 pChildMenu = gui_mac_get_vim_menu
1488 (menuID, itemIndex, pMenu->children);
1489 if (pChildMenu)
1490 {
1491 pMenu = pChildMenu;
1492 break;
1493 }
1494 }
1495 }
1496 }
1497 return pMenu;
1498}
1499
1500/*
1501 * ------------------------------------------------------------
1502 * MacOS Feedback procedures
1503 * ------------------------------------------------------------
1504 */
1505 pascal
1506 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001507gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508{
1509 scrollbar_T *sb;
1510 int value, dragging;
1511 ControlHandle theControlToUse;
1512 int dont_scroll_save = dont_scroll;
1513
1514 theControlToUse = dragged_sb;
1515
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001516 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517
1518 if (sb == NULL)
1519 return;
1520
1521 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001522 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001523 dragging = (partCode != 0);
1524
1525 /* When "allow_scrollbar" is FALSE still need to remember the new
1526 * position, but don't actually scroll by setting "dont_scroll". */
1527 dont_scroll = !allow_scrollbar;
1528 gui_drag_scrollbar(sb, value, dragging);
1529 dont_scroll = dont_scroll_save;
1530}
1531
1532 pascal
1533 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001534gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535{
1536 /* TODO: have live support */
1537 scrollbar_T *sb, *sb_info;
1538 long data;
1539 long value;
1540 int page;
1541 int dragging = FALSE;
1542 int dont_scroll_save = dont_scroll;
1543
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001544 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545
1546 if (sb == NULL)
1547 return;
1548
1549 if (sb->wp != NULL) /* Left or right scrollbar */
1550 {
1551 /*
1552 * Careful: need to get scrollbar info out of first (left) scrollbar
1553 * for window, but keep real scrollbar too because we must pass it to
1554 * gui_drag_scrollbar().
1555 */
1556 sb_info = &sb->wp->w_scrollbars[0];
1557
1558 if (sb_info->size > 5)
1559 page = sb_info->size - 2; /* use two lines of context */
1560 else
1561 page = sb_info->size;
1562 }
1563 else /* Bottom scrollbar */
1564 {
1565 sb_info = sb;
1566 page = W_WIDTH(curwin) - 5;
1567 }
1568
1569 switch (partCode)
1570 {
1571 case kControlUpButtonPart: data = -1; break;
1572 case kControlDownButtonPart: data = 1; break;
1573 case kControlPageDownPart: data = page; break;
1574 case kControlPageUpPart: data = -page; break;
1575 default: data = 0; break;
1576 }
1577
1578 value = sb_info->value + data;
1579/* if (value > sb_info->max)
1580 value = sb_info->max;
1581 else if (value < 0)
1582 value = 0;*/
1583
1584 /* When "allow_scrollbar" is FALSE still need to remember the new
1585 * position, but don't actually scroll by setting "dont_scroll". */
1586 dont_scroll = !allow_scrollbar;
1587 gui_drag_scrollbar(sb, value, dragging);
1588 dont_scroll = dont_scroll_save;
1589
1590 out_flush();
1591 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1592
1593/* if (sb_info->wp != NULL)
1594 {
1595 win_T *wp;
1596 int sb_num;
1597
1598 sb_num = 0;
1599 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1600 sb_num++;
1601
1602 if (wp != NULL)
1603 {
1604 current_scrollbar = sb_num;
1605 scrollbar_value = value;
1606 gui_do_scroll();
1607 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1608 }
1609 }*/
1610}
1611
1612/*
1613 * ------------------------------------------------------------
1614 * MacOS Click Handling procedures
1615 * ------------------------------------------------------------
1616 */
1617
1618
1619/*
1620 * Handle a click inside the window, it may happens in the
1621 * scrollbar or the contents.
1622 *
1623 * TODO: Add support for potential TOOLBAR
1624 */
1625 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001626gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627{
1628 Point thePoint;
1629 int_u vimModifiers;
1630 short thePortion;
1631 ControlHandle theControl;
1632 int vimMouseButton;
1633 short dblClick;
1634
1635 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001636 GlobalToLocal(&thePoint);
1637 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001639 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640
1641 if (theControl != NUL)
1642 {
1643 /* We hit a scollbar */
1644
1645 if (thePortion != kControlIndicatorPart)
1646 {
1647 dragged_sb = theControl;
1648 TrackControl(theControl, thePoint, gScrollAction);
1649 dragged_sb = NULL;
1650 }
1651 else
1652 {
1653 dragged_sb = theControl;
1654#if 1
1655 TrackControl(theControl, thePoint, gScrollDrag);
1656#else
1657 TrackControl(theControl, thePoint, NULL);
1658#endif
1659 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1660 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001661 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 dragged_sb = NULL;
1663 }
1664 }
1665 else
1666 {
1667 /* We are inside the contents */
1668
1669 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1670 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1671
1672 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1673 vimMouseButton = MOUSE_LEFT;
1674
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001676 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677 clickIsPopup = FALSE;
1678
1679 if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup()))
1680 if (IsShowContextualMenuClick(theEvent))
1681 {
1682 vimMouseButton = MOUSE_RIGHT;
1683 vimModifiers &= ~MOUSE_CTRL;
1684 clickIsPopup = TRUE;
1685 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686
1687 /* Is it a double click ? */
1688 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1689
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001690 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 gui_send_mouse_event(vimMouseButton, thePoint.h,
1692 thePoint.v, dblClick, vimModifiers);
1693
1694 /* Create the rectangle around the cursor to detect
1695 * the mouse dragging
1696 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697#if 0
1698 /* TODO: Do we need to this even for the contextual menu?
1699 * It may be require for popup_setpos, but for popup?
1700 */
1701 if (vimMouseButton == MOUSE_LEFT)
1702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001704 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705 FILL_Y(Y_2_ROW(thePoint.v)),
1706 FILL_X(X_2_COL(thePoint.h)+1),
1707 FILL_Y(Y_2_ROW(thePoint.v)+1));
1708
1709 dragRectEnbl = TRUE;
1710 dragRectControl = kCreateRect;
1711 }
1712 }
1713}
1714
1715/*
1716 * Handle the click in the titlebar (to move the window)
1717 */
1718 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001719gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720{
1721 Rect movingLimits;
1722 Rect *movingLimitsPtr = &movingLimits;
1723
1724 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001725 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001726 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727}
1728
1729/*
1730 * Handle the click in the grow box
1731 */
1732 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001733gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734{
1735
1736 long newSize;
1737 unsigned short newWidth;
1738 unsigned short newHeight;
1739 Rect resizeLimits;
1740 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 Rect NewContentRect;
1742
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001743 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744
Bram Moolenaar720c7102007-05-10 18:07:50 +00001745 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 /* TODO: Should this come from Vim? */
1747 resizeLimits.top = 100;
1748 resizeLimits.left = 100;
1749
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1751 newWidth = NewContentRect.right - NewContentRect.left;
1752 newHeight = NewContentRect.bottom - NewContentRect.top;
1753 gui_resize_shell(newWidth, newHeight);
1754 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001755 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756}
1757
1758/*
1759 * Handle the click in the zoom box
1760 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001762gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763{
1764 Rect r;
1765 Point p;
1766 short thePart;
1767
1768 /* ideal width is current */
1769 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1770 if (gui.which_scrollbars[SBAR_LEFT])
1771 p.h += gui.scrollbar_width;
1772 if (gui.which_scrollbars[SBAR_RIGHT])
1773 p.h += gui.scrollbar_width;
1774 /* ideal height is as heigh as we can get */
1775 p.v = 15 * 1024;
1776
1777 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1778 ? inZoomIn : inZoomOut;
1779
1780 if (!TrackBox(whichWindow, theEvent->where, thePart))
1781 return;
1782
1783 /* use returned width */
1784 p.h = r.right - r.left;
1785 /* adjust returned height */
1786 p.v = r.bottom - r.top - 2 * gui.border_offset;
1787 if (gui.which_scrollbars[SBAR_BOTTOM])
1788 p.v -= gui.scrollbar_height;
1789 p.v -= p.v % gui.char_height;
1790 p.v += 2 * gui.border_width;
1791 if (gui.which_scrollbars[SBAR_BOTTOM]);
1792 p.v += gui.scrollbar_height;
1793
1794 ZoomWindowIdeal(whichWindow, thePart, &p);
1795
1796 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1797 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1798 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001799 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801
1802/*
1803 * ------------------------------------------------------------
1804 * MacOS Event Handling procedure
1805 * ------------------------------------------------------------
1806 */
1807
1808/*
1809 * Handle the Update Event
1810 */
1811
1812 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001813gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814{
1815 WindowPtr whichWindow;
1816 GrafPtr savePort;
1817 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 Rect *updateRectPtr;
1820 Rect rc;
1821 Rect growRect;
1822 RgnHandle saveRgn;
1823
1824
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825 updateRgn = NewRgn();
1826 if (updateRgn == NULL)
1827 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828
1829 /* This could be done by the caller as we
1830 * don't require anything else out of the event
1831 */
1832 whichWindow = (WindowPtr) event->message;
1833
1834 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001835 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836
1837 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001838 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839
1840 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001841 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 /* Redraw the biggest rectangle covering the area
1843 * to be updated.
1844 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1846# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001847 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 * seem to work under MacOS X (Dany)
1849 */
1850 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1851# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001852
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001854 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001855
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001856 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857# if 0
1858 /* Code from original Carbon Port (using GetWindowRegion.
1859 * I believe the UpdateRgn is already in local (Dany)
1860 */
1861 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1862 GlobalToLocal(&botRight(updateRect));
1863# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 /* Update the content (i.e. the text) */
1865 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1866 updateRectPtr->right - updateRectPtr->left,
1867 updateRectPtr->bottom - updateRectPtr->top);
1868 /* Clear the border areas if needed */
1869 gui_mch_set_bg_color(gui.back_pixel);
1870 if (updateRectPtr->left < FILL_X(0))
1871 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001872 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1873 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 }
1875 if (updateRectPtr->top < FILL_Y(0))
1876 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001877 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1878 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 }
1880 if (updateRectPtr->right > FILL_X(Columns))
1881 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001882 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001884 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885 }
1886 if (updateRectPtr->bottom > FILL_Y(Rows))
1887 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001888 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001890 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001892 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001893 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894
1895 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001896 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897
1898 /* Update the GrowBox */
1899 /* Taken from FAQ 33-27 */
1900 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001902 GetClip(saveRgn);
1903 ClipRect(&growRect);
1904 DrawGrowIcon(whichWindow);
1905 SetClip(saveRgn);
1906 DisposeRgn(saveRgn);
1907 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908
1909 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001910 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911}
1912
1913/*
1914 * Handle the activate/deactivate event
1915 * (apply to a window)
1916 */
1917 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001918gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919{
1920 WindowPtr whichWindow;
1921
1922 whichWindow = (WindowPtr) event->message;
1923 if ((event->modifiers) & activeFlag)
1924 /* Activate */
1925 gui_focus_change(TRUE);
1926 else
1927 {
1928 /* Deactivate */
1929 gui_focus_change(FALSE);
1930/* DON'T KNOW what the code below was doing
1931 found in the deactivate clause, but the
Bram Moolenaar720c7102007-05-10 18:07:50 +00001932 clause writing TRUE into in_focus (BUG)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 */
1934
1935#if 0 /* Removed by Dany as per above June 2001 */
1936 a_bool = false;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001937 SetPreserveGlyph(a_bool);
1938 SetOutlinePreferred(a_bool);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939#endif
1940 }
1941}
1942
1943
1944/*
1945 * Handle the suspend/resume event
1946 * (apply to the application)
1947 */
1948 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001949gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950{
1951 /* The frontmost application just changed */
1952
1953 /* NOTE: the suspend may happen before the deactivate
1954 * seen on MacOS X
1955 */
1956
1957 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00001958 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 */
1960 if (event->message & 1)
1961 /* Resume */
1962 gui_focus_change(TRUE);
1963 else
1964 /* Suspend */
1965 gui_focus_change(FALSE);
1966}
1967
1968/*
1969 * Handle the key
1970 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001971#ifdef USE_CARBONKEYHANDLER
Bram Moolenaard68071d2006-05-02 22:08:30 +00001972
1973static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the keys */
1974
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001975# define INLINE_KEY_BUFFER_SIZE 80
1976 static pascal OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001977gui_mac_doKeyEventCarbon(
1978 EventHandlerCallRef nextHandler,
1979 EventRef theEvent,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001980 void *data)
1981{
1982 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001983 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001984 UInt32 actualSize;
1985 UniChar *text;
1986 char_u result[INLINE_KEY_BUFFER_SIZE];
1987 short len = 0;
1988 UInt32 key_sym;
1989 char charcode;
1990 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001991 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001992 size_t encLen;
1993 char_u *to = NULL;
1994 Boolean isSpecial = FALSE;
1995 int i;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001996 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001997
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001998 /* Mask the mouse (as per user setting) */
1999 if (p_mh)
2000 ObscureCursor();
2001
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002002 /* Don't use the keys when the dialog wants them. */
2003 if (dialog_busy)
2004 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002005
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002006 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2007 typeUnicodeText, NULL, 0, &actualSize, NULL))
2008 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002009
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002010 text = (UniChar *)alloc(actualSize);
2011 if (!text)
2012 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002013
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002014 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
2015 typeUnicodeText, NULL, actualSize, NULL, text);
2016 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002017
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002018 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
2019 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
2020 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002021
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002022 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
2023 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
2024 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002025
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002026 err = GetEventParameter(keyEvent, kEventParamKeyCode,
2027 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
2028 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002029
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002030 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
2031 typeChar, NULL, sizeof(char), NULL, &charcode);
2032 require_noerr(err, done);
2033
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002034#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002035 if (modifiers & cmdKey)
2036 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002037#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002038
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002039 key_char = charcode;
2040 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002041
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002042 /* Find the special key (eg., for cursor keys) */
2043 if (actualSize <= sizeof(UniChar) &&
2044 ((text[0] < 0x20) || (text[0] == 0x7f)))
2045 {
2046 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2047 if (special_keys[i].key_sym == key_sym)
2048 {
2049 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2050 special_keys[i].vim_code1);
2051 key_char = simplify_key(key_char,
2052 (int *)&vimModifiers);
2053 isSpecial = TRUE;
2054 break;
2055 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002056 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002057
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002058 /* Intercept CMD-. and CTRL-c */
2059 if (((modifiers & controlKey) && key_char == 'c') ||
2060 ((modifiers & cmdKey) && key_char == '.'))
2061 got_int = TRUE;
2062
2063 if (!isSpecial)
2064 {
2065 /* remove SHIFT for keys that are already shifted, e.g.,
2066 * '(' and '*' */
2067 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2068 vimModifiers &= ~MOD_MASK_SHIFT;
2069
2070 /* remove CTRL from keys that already have it */
2071 if (key_char < 0x20)
2072 vimModifiers &= ~MOD_MASK_CTRL;
2073
2074 /* don't process unicode characters here */
2075 if (!IS_SPECIAL(key_char))
2076 {
2077 /* Following code to simplify and consolidate vimModifiers
2078 * taken liberally from gui_w48.c */
2079 key_char = simplify_key(key_char, (int *)&vimModifiers);
2080
2081 /* Interpret META, include SHIFT, etc. */
2082 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2083 if (key_char == CSI)
2084 key_char = K_CSI;
2085
2086 if (IS_SPECIAL(key_char))
2087 isSpecial = TRUE;
2088 }
2089 }
2090
2091 if (vimModifiers)
2092 {
2093 result[len++] = CSI;
2094 result[len++] = KS_MODIFIER;
2095 result[len++] = vimModifiers;
2096 }
2097
2098 if (isSpecial && IS_SPECIAL(key_char))
2099 {
2100 result[len++] = CSI;
2101 result[len++] = K_SECOND(key_char);
2102 result[len++] = K_THIRD(key_char);
2103 }
2104 else
2105 {
2106 encLen = actualSize;
2107 to = mac_utf16_to_enc(text, actualSize, &encLen);
2108 if (to)
2109 {
2110 /* This is basically add_to_input_buf_csi() */
2111 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2112 {
2113 result[len++] = to[i];
2114 if (to[i] == CSI)
2115 {
2116 result[len++] = KS_EXTRA;
2117 result[len++] = (int)KE_CSI;
2118 }
2119 }
2120 vim_free(to);
2121 }
2122 }
2123
2124 add_to_input_buf(result, len);
2125 err = noErr;
2126
2127done:
2128 vim_free(text);
2129 if (err == noErr)
2130 {
2131 /* Fake event to wake up WNE (required to get
2132 * key repeat working */
2133 PostEvent(keyUp, 0);
2134 return noErr;
2135 }
2136
2137 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002138}
2139#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 void
2141gui_mac_doKeyEvent(EventRecord *theEvent)
2142{
2143 /* TODO: add support for COMMAND KEY */
2144 long menu;
2145 unsigned char string[20];
2146 short num, i;
2147 short len = 0;
2148 KeySym key_sym;
2149 int key_char;
2150 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002151 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152
2153 /* Mask the mouse (as per user setting) */
2154 if (p_mh)
2155 ObscureCursor();
2156
2157 /* Get the key code and it's ASCII representation */
2158 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2159 key_char = theEvent->message & charCodeMask;
2160 num = 1;
2161
2162 /* Intercept CTRL-C */
2163 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002164 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 if (key_char == Ctrl_C && ctrl_c_interrupts)
2166 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002167 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2168 && (key_char == '2' || key_char == '6'))
2169 {
2170 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2171 if (key_char == '2')
2172 key_char = Ctrl_AT;
2173 else
2174 key_char = Ctrl_HAT;
2175 theEvent->modifiers = 0;
2176 }
2177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178
2179 /* Intercept CMD-. */
2180 if (theEvent->modifiers & cmdKey)
2181 if (key_char == '.')
2182 got_int = TRUE;
2183
2184 /* Handle command key as per menu */
2185 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2186 if (theEvent->modifiers & cmdKey)
2187 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2188 * Why the mouse button? */
2189 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2190 {
2191 menu = MenuKey(key_char);
2192 if (HiWord(menu))
2193 {
2194 gui_mac_handle_menu(menu);
2195 return;
2196 }
2197 }
2198
2199 /* Convert the modifiers */
2200 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2201
2202
2203 /* Handle special keys. */
2204#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002205 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2207#endif
2208 {
2209 /* Find the special key (for non-printable keyt_char) */
2210 if ((key_char < 0x20) || (key_char == 0x7f))
2211 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2212 if (special_keys[i].key_sym == key_sym)
2213 {
2214# if 0
2215 /* We currently don't have not so special key */
2216 if (special_keys[i].vim_code1 == NUL)
2217 key_char = special_keys[i].vim_code0;
2218 else
2219# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002220 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2221 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002222 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 break;
2224 }
2225 }
2226
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002227 /* For some keys the modifier is included in the char itself. */
2228 if (simplify || key_char == TAB || key_char == ' ')
2229 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230
2231 /* Add the modifier to the input bu if needed */
2232 /* Do not want SHIFT-A or CTRL-A with modifier */
2233 if (!IS_SPECIAL(key_char)
2234 && key_sym != vk_Space
2235 && key_sym != vk_Tab
2236 && key_sym != vk_Return
2237 && key_sym != vk_Enter
2238 && key_sym != vk_Esc)
2239 {
2240#if 1
2241 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002242 if ((modifiers == MOD_MASK_SHIFT)
2243 || (modifiers == MOD_MASK_CTRL)
2244 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 modifiers = 0;
2246#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002247 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002249 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002251 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 modifiers = modifiers & ~MOD_MASK_SHIFT;
2253#endif
2254 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002255 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002257 string[len++] = CSI;
2258 string[len++] = KS_MODIFIER;
2259 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 }
2261
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002262 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002264 string[len++] = CSI;
2265 string[len++] = K_SECOND(key_char);
2266 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 }
2268 else
2269 {
2270#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002271 /* Convert characters when needed (e.g., from MacRoman to latin1).
2272 * This doesn't work for the NUL byte. */
2273 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 {
2275 char_u from[2], *to;
2276 int l;
2277
2278 from[0] = key_char;
2279 from[1] = NUL;
2280 l = 1;
2281 to = string_convert(&input_conv, from, &l);
2282 if (to != NULL)
2283 {
2284 for (i = 0; i < l && len < 19; i++)
2285 {
2286 if (to[i] == CSI)
2287 {
2288 string[len++] = KS_EXTRA;
2289 string[len++] = KE_CSI;
2290 }
2291 else
2292 string[len++] = to[i];
2293 }
2294 vim_free(to);
2295 }
2296 else
2297 string[len++] = key_char;
2298 }
2299 else
2300#endif
2301 string[len++] = key_char;
2302 }
2303
2304 if (len == 1 && string[0] == CSI)
2305 {
2306 /* Turn CSI into K_CSI. */
2307 string[ len++ ] = KS_EXTRA;
2308 string[ len++ ] = KE_CSI;
2309 }
2310
2311 add_to_input_buf(string, len);
2312}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002313#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314
2315/*
2316 * Handle MouseClick
2317 */
2318 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002319gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320{
2321 short thePart;
2322 WindowPtr whichWindow;
2323
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002324 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002326#ifdef FEAT_GUI_TABLINE
2327 /* prevent that the vim window size changes if it's activated by a
2328 click into the tab pane */
2329 if (whichWindow == drawer)
2330 return;
2331#endif
2332
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 switch (thePart)
2334 {
2335 case (inDesk):
2336 /* TODO: what to do? */
2337 break;
2338
2339 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002340 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 break;
2342
2343 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002344 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 break;
2346
2347 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002348 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 break;
2350
2351 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002352 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 break;
2354
2355 case (inGoAway):
2356 if (TrackGoAway(whichWindow, theEvent->where))
2357 gui_shell_closed();
2358 break;
2359
2360 case (inZoomIn):
2361 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 break;
2364 }
2365}
2366
2367/*
2368 * Handle MouseMoved
2369 * [this event is a moving in and out of a region]
2370 */
2371 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002372gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373{
2374 Point thePoint;
2375 int_u vimModifiers;
2376
2377 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002378 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2380
2381 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002382 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2386 thePoint.v, FALSE, vimModifiers);
2387
2388 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002389 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 FILL_Y(Y_2_ROW(thePoint.v)),
2391 FILL_X(X_2_COL(thePoint.h)+1),
2392 FILL_Y(Y_2_ROW(thePoint.v)+1));
2393
2394 if (dragRectEnbl)
2395 dragRectControl = kCreateRect;
2396
2397}
2398
2399/*
2400 * Handle the mouse release
2401 */
2402 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002403gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404{
2405 Point thePoint;
2406 int_u vimModifiers;
2407
2408 /* TODO: Properly convert the Contextual menu mouse-up */
2409 /* Potential source of the double menu */
2410 lastMouseTick = theEvent->when;
2411 dragRectEnbl = FALSE;
2412 dragRectControl = kCreateEmpty;
2413 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002414 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415
2416 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 if (clickIsPopup)
2418 {
2419 vimModifiers &= ~MOUSE_CTRL;
2420 clickIsPopup = FALSE;
2421 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002422 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423}
2424
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 static pascal OSStatus
2426gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2427 void *data)
2428{
2429 EventRef bogusEvent;
2430 Point point;
2431 Rect bounds;
2432 UInt32 mod;
2433 SInt32 delta;
2434 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002435 EventMouseWheelAxis axis;
2436
2437 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2438 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2439 && axis != kEventMouseWheelAxisY)
2440 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441
2442 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2443 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2444 goto bail;
2445 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2446 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2447 goto bail;
2448 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2449 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2450 goto bail;
2451
2452 vim_mod = 0;
2453 if (mod & shiftKey)
2454 vim_mod |= MOUSE_SHIFT;
2455 if (mod & controlKey)
2456 vim_mod |= MOUSE_CTRL;
2457 if (mod & optionKey)
2458 vim_mod |= MOUSE_ALT;
2459
2460 /* post a bogus event to wake up WaitNextEvent */
2461 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2462 kEventAttributeNone, &bogusEvent))
2463 goto bail;
2464 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2465 kEventPriorityLow))
2466 goto bail;
2467
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002468 ReleaseEvent(bogusEvent);
2469
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2471 {
2472 point.h -= bounds.left;
2473 point.v -= bounds.top;
2474 }
2475
2476 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2477 point.h, point.v, FALSE, vim_mod);
2478
2479 return noErr;
2480
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002481bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 /*
2483 * when we fail give any additional callback handler a chance to perform
2484 * it's actions
2485 */
2486 return CallNextEventHandler(nextHandler, theEvent);
2487}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488
2489#if 0
2490
2491/*
2492 * This would be the normal way of invoking the contextual menu
2493 * but the Vim API doesn't seem to a support a request to get
2494 * the menu that we should display
2495 */
2496 void
2497gui_mac_handle_contextual_menu(event)
2498 EventRecord *event;
2499{
2500/*
2501 * Clone PopUp to use menu
2502 * Create a object descriptor for the current selection
2503 * Call the procedure
2504 */
2505
2506// Call to Handle Popup
2507 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2508
2509 if (status != noErr)
2510 return;
2511
2512 if (CntxType == kCMMenuItemSelected)
2513 {
2514 /* Handle the menu CntxMenuID, CntxMenuItem */
2515 /* The submenu can be handle directly by gui_mac_handle_menu */
2516 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002517 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 }
2519 else if (CntxMenuID == kCMShowHelpSelected)
2520 {
2521 /* Should come up with the help */
2522 }
2523
2524}
2525#endif
2526
2527/*
2528 * Handle menubar selection
2529 */
2530 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002531gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532{
2533 short menu = HiWord(menuChoice);
2534 short item = LoWord(menuChoice);
2535 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536
2537 if (menu == 256) /* TODO: use constant or gui.xyz */
2538 {
2539 if (item == 1)
2540 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 }
2542 else if (item != 0)
2543 {
2544 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2545
2546 if (theVimMenu)
2547 gui_menu_cb(theVimMenu);
2548 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002549 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550}
2551
2552/*
2553 * Dispatch the event to proper handler
2554 */
2555
2556 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002557gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558{
2559 OSErr error;
2560
2561 /* Handle contextual menu right now (if needed) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 if (gui.MacOSHaveCntxMenu)
2563 if (IsShowContextualMenuClick(event))
2564 {
2565# if 0
2566 gui_mac_handle_contextual_menu(event);
2567# else
2568 gui_mac_doMouseDownEvent(event);
2569# endif
2570 return;
2571 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572
2573 /* Handle normal event */
2574 switch (event->what)
2575 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002576#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 case (keyDown):
2578 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002579 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002581#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002583 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 break;
2585
2586 case (mouseDown):
2587 gui_mac_doMouseDownEvent(event);
2588 break;
2589
2590 case (mouseUp):
2591 gui_mac_doMouseUpEvent(event);
2592 break;
2593
2594 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002595 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 break;
2597
2598 case (diskEvt):
2599 /* We don't need special handling for disk insertion */
2600 break;
2601
2602 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002603 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604 break;
2605
2606 case (osEvt):
2607 switch ((event->message >> 24) & 0xFF)
2608 {
2609 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002610 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611 break;
2612 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002613 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 break;
2615 }
2616 break;
2617
2618#ifdef USE_AEVENT
2619 case (kHighLevelEvent):
2620 /* Someone's talking to us, through AppleEvents */
2621 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2622 break;
2623#endif
2624 }
2625}
2626
2627/*
2628 * ------------------------------------------------------------
2629 * Unknown Stuff
2630 * ------------------------------------------------------------
2631 */
2632
2633
2634 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002635gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636{
2637 char_u c;
2638 char_u *p;
2639 char_u pFontName[256];
2640 Str255 systemFontname;
2641 short font_id;
2642 short size=9;
2643 GuiFont font;
2644#if 0
2645 char_u *fontNamePtr;
2646#endif
2647
2648 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2649 ;
2650
2651 c = *p;
2652 *p = 0;
2653
2654#if 1
2655 STRCPY(&pFontName[1], font_name);
2656 pFontName[0] = STRLEN(font_name);
2657 *p = c;
2658
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002659 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002660 char_u fontName[256];
2661 char_u *styleStart = vim_strchr(font_name, ':');
2662 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2663 vim_strncpy(fontName, font_name, fontNameLen);
2664
2665 ATSUFontID fontRef;
2666 FMFontStyle fontStyle;
2667 font_id = 0;
2668
2669 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2670 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2671 &fontRef) == noErr)
2672 {
2673 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2674 font_id = 0;
2675 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002676
2677 if (font_id == 0)
2678 {
2679 /*
2680 * Try again, this time replacing underscores in the font name
2681 * with spaces (:set guifont allows the two to be used
2682 * interchangeably; the Font Manager doesn't).
2683 */
2684 int i, changed = FALSE;
2685
2686 for (i = pFontName[0]; i > 0; --i)
2687 {
2688 if (pFontName[i] == '_')
2689 {
2690 pFontName[i] = ' ';
2691 changed = TRUE;
2692 }
2693 }
2694 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002695 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2696 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2697 kFontNoLanguageCode, &fontRef) == noErr)
2698 {
2699 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2700 font_id = 0;
2701 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002702 }
2703
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704#else
2705 /* name = C2Pascal_save(menu->dname); */
2706 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2707
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002708 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709#endif
2710
2711
2712 if (font_id == 0)
2713 {
2714 /* Oups, the system font was it the one the user want */
2715
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002716 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2717 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 if (!EqualString(pFontName, systemFontname, false, false))
2719 return NOFONT;
2720 }
2721 if (*p == ':')
2722 {
2723 p++;
2724 /* Set the values found after ':' */
2725 while (*p)
2726 {
2727 switch (*p++)
2728 {
2729 case 'h':
2730 size = points_to_pixels(p, &p, TRUE);
2731 break;
2732 /*
2733 * TODO: Maybe accept width and styles
2734 */
2735 }
2736 while (*p == ':')
2737 p++;
2738 }
2739 }
2740
2741 if (size < 1)
2742 size = 1; /* Avoid having a size of 0 with system font */
2743
2744 font = (size << 16) + ((long) font_id & 0xFFFF);
2745
2746 return font;
2747}
2748
2749/*
2750 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002751 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752 * ------------------------------------------------------------
2753 */
2754
2755/*
2756 * Parse the GUI related command-line arguments. Any arguments used are
2757 * deleted from argv, and *argc is decremented accordingly. This is called
2758 * when vim is started, whether or not the GUI has been started.
2759 */
2760 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002761gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762{
2763 /* TODO: Move most of this stuff toward gui_mch_init */
2764#ifdef USE_EXE_NAME
2765 FSSpec applDir;
2766# ifndef USE_FIND_BUNDLE_PATH
2767 short applVRefNum;
2768 long applDirID;
2769 Str255 volName;
2770# else
2771 ProcessSerialNumber psn;
2772 FSRef applFSRef;
2773# endif
2774#endif
2775
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776#if 0
2777 InitCursor();
2778
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780
2781#ifdef USE_AEVENT
2782 (void) InstallAEHandlers();
2783#endif
2784
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2786 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2787 else
2788 gui.MacOSHaveCntxMenu = false;
2789
2790 if (gui.MacOSHaveCntxMenu)
2791 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002793 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002795 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002797 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798
2799 DrawMenuBar();
2800
2801
2802#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002803 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002805 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806#endif
2807
2808
Bram Moolenaar071d4272004-06-13 20:20:40 +00002809 CreateNewWindow(kDocumentWindowClass,
2810 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002811 &windRect, &gui.VimWindow);
2812 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813
2814 gui.char_width = 7;
2815 gui.char_height = 11;
2816 gui.char_ascent = 6;
2817 gui.num_rows = 24;
2818 gui.num_cols = 80;
2819 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002821 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2822 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002823
2824 dragRectEnbl = FALSE;
2825 dragRgn = NULL;
2826 dragRectControl = kCreateEmpty;
2827 cursorRgn = NewRgn();
2828#endif
2829#ifdef USE_EXE_NAME
2830# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002831 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002833 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834# else
2835 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2836 * of TN2015
2837 * This technic remove the ../Contents/MacOS/etc part
2838 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002839 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 /* if (err != noErr) return err; */
2841
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002842 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 /* if (err != noErr) return err; */
2844
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002845 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846
2847 /* This technic return NIL when we disallow_gui */
2848# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002849 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851}
2852
2853#ifndef ALWAYS_USE_GUI
2854/*
2855 * Check if the GUI can be started. Called before gvimrc is sourced.
2856 * Return OK or FAIL.
2857 */
2858 int
2859gui_mch_init_check(void)
2860{
2861 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2862 * using the >console
2863 */
2864 if (disallow_gui) /* see main.c for reason to disallow */
2865 return FAIL;
2866 return OK;
2867}
2868#endif
2869
2870 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002871receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872{
2873 int x, y;
2874 int_u modifiers;
2875 char_u **fnames = NULL;
2876 int count;
2877 int i, j;
2878
2879 /* Get drop position, modifiers and count of items */
2880 {
2881 Point point;
2882 SInt16 mouseUpModifiers;
2883 UInt16 countItem;
2884
2885 GetDragMouse(theDrag, &point, NULL);
2886 GlobalToLocal(&point);
2887 x = point.h;
2888 y = point.v;
2889 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2890 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2891 CountDragItems(theDrag, &countItem);
2892 count = countItem;
2893 }
2894
2895 fnames = (char_u **)alloc(count * sizeof(char_u *));
2896 if (fnames == NULL)
2897 return dragNotAcceptedErr;
2898
2899 /* Get file names dropped */
2900 for (i = j = 0; i < count; ++i)
2901 {
2902 DragItemRef item;
2903 OSErr err;
2904 Size size;
2905 FlavorType type = flavorTypeHFS;
2906 HFSFlavor hfsFlavor;
2907
2908 fnames[i] = NULL;
2909 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2910 err = GetFlavorDataSize(theDrag, item, type, &size);
2911 if (err != noErr || size > sizeof(hfsFlavor))
2912 continue;
2913 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2914 if (err != noErr)
2915 continue;
2916 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
2917 }
2918 count = j;
2919
2920 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002921
2922 /* Fake mouse event to wake from stall */
2923 PostEvent(mouseUp, 0);
2924
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 return noErr;
2926}
2927
2928/*
2929 * Initialise the GUI. Create all the windows, set up all the call-backs
2930 * etc.
2931 */
2932 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002933gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934{
2935 /* TODO: Move most of this stuff toward gui_mch_init */
2936 Rect windRect;
2937 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 long gestalt_rc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939 EventTypeSpec eventTypeSpec;
2940 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002941#ifdef USE_CARBONKEYHANDLER
2942 EventHandlerRef keyEventHandlerRef;
2943#endif
2944
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002945 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002946 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002947
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948#if 1
2949 InitCursor();
2950
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952
2953#ifdef USE_AEVENT
2954 (void) InstallAEHandlers();
2955#endif
2956
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002957 /* Ctrl click */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr)
2959 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable);
2960 else
2961 gui.MacOSHaveCntxMenu = false;
2962
2963 if (gui.MacOSHaveCntxMenu)
2964 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002966 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002968 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002970 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971
2972 DrawMenuBar();
2973
2974
2975#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002976 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002978 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979#endif
2980
2981 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002982 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983 (WindowPtr)-1L, true, 0);
2984 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
2985 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002986 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987
2988 gui.char_width = 7;
2989 gui.char_height = 11;
2990 gui.char_ascent = 6;
2991 gui.num_rows = 24;
2992 gui.num_cols = 80;
2993 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2994
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002995 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2996 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002998 /* Install Carbon event callbacks. */
2999 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000
3001 dragRectEnbl = FALSE;
3002 dragRgn = NULL;
3003 dragRectControl = kCreateEmpty;
3004 cursorRgn = NewRgn();
3005#endif
3006 /* Display any pending error messages */
3007 display_errors();
3008
3009 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003010 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 gui.norm_pixel = 0x00000000;
3012 gui.back_pixel = 0x00FFFFFF;
3013
3014 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3015 * file). */
3016 set_normal_colors();
3017
3018 /*
3019 * Check that none of the colors are the same as the background color.
3020 * Then store the current values as the defaults.
3021 */
3022 gui_check_colors();
3023 gui.def_norm_pixel = gui.norm_pixel;
3024 gui.def_back_pixel = gui.back_pixel;
3025
3026 /* Get the colors for the highlight groups (gui_check_colors() might have
3027 * changed them) */
3028 highlight_gui_started();
3029
3030 /*
3031 * Setting the gui constants
3032 */
3033#ifdef FEAT_MENU
3034 gui.menu_height = 0;
3035#endif
3036 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3037 gui.border_offset = gui.border_width = 2;
3038
Bram Moolenaar720c7102007-05-10 18:07:50 +00003039 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040 gui_mch_draw_string() below), enable it for all font sizes. */
3041 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043 eventTypeSpec.eventClass = kEventClassMouse;
3044 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3045 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3046 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3047 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3048 {
3049 mouseWheelHandlerRef = NULL;
3050 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3051 mouseWheelHandlerUPP = NULL;
3052 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003054#ifdef USE_CARBONKEYHANDLER
3055 eventTypeSpec.eventClass = kEventClassTextInput;
3056 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3057 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3058 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3059 &eventTypeSpec, NULL, &keyEventHandlerRef))
3060 {
3061 keyEventHandlerRef = NULL;
3062 DisposeEventHandlerUPP(keyEventHandlerUPP);
3063 keyEventHandlerUPP = NULL;
3064 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065#endif
3066
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003067/*
3068#ifdef FEAT_MBYTE
3069 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3070#endif
3071*/
3072
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003073#ifdef FEAT_GUI_TABLINE
3074 /*
3075 * Create the tabline
3076 */
3077 initialise_tabline();
3078#endif
3079
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080 /* TODO: Load bitmap if using TOOLBAR */
3081 return OK;
3082}
3083
3084/*
3085 * Called when the foreground or background color has been changed.
3086 */
3087 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003088gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089{
3090 /* TODO:
3091 * This proc is called when Normal is set to a value
3092 * so what msut be done? I don't know
3093 */
3094}
3095
3096/*
3097 * Open the GUI window which was created by a call to gui_mch_init().
3098 */
3099 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003100gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101{
3102 ShowWindow(gui.VimWindow);
3103
3104 if (gui_win_x != -1 && gui_win_y != -1)
3105 gui_mch_set_winpos(gui_win_x, gui_win_y);
3106
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 /*
3108 * Make the GUI the foreground process (in case it was launched
3109 * from the Terminal or via :gui).
3110 */
3111 {
3112 ProcessSerialNumber psn;
3113 if (GetCurrentProcess(&psn) == noErr)
3114 SetFrontProcess(&psn);
3115 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116
3117 return OK;
3118}
3119
3120 void
3121gui_mch_exit(int rc)
3122{
3123 /* TODO: find out all what is missing here? */
3124 DisposeRgn(cursorRgn);
3125
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003126#ifdef USE_CARBONKEYHANDLER
3127 if (keyEventHandlerUPP)
3128 DisposeEventHandlerUPP(keyEventHandlerUPP);
3129#endif
3130
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 if (mouseWheelHandlerUPP != NULL)
3132 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003134#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003135 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003136 ATSUDisposeStyle(gFontStyle);
3137#endif
3138
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 /* Exit to shell? */
3140 exit(rc);
3141}
3142
3143/*
3144 * Get the position of the top left corner of the window.
3145 */
3146 int
3147gui_mch_get_winpos(int *x, int *y)
3148{
3149 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 Rect bounds;
3151 OSStatus status;
3152
3153 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003154 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155
3156 if (status != noErr)
3157 return FAIL;
3158 *x = bounds.left;
3159 *y = bounds.top;
3160 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161 return FAIL;
3162}
3163
3164/*
3165 * Set the position of the top left corner of the window to the given
3166 * coordinates.
3167 */
3168 void
3169gui_mch_set_winpos(int x, int y)
3170{
3171 /* TODO: Should make sure the window is move within range
3172 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3173 */
3174 MoveWindow(gui.VimWindow, x, y, TRUE);
3175}
3176
3177 void
3178gui_mch_set_shellsize(
3179 int width,
3180 int height,
3181 int min_width,
3182 int min_height,
3183 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003184 int base_height,
3185 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 CGrafPtr VimPort;
3188 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189
3190 if (gui.which_scrollbars[SBAR_LEFT])
3191 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003192 VimPort = GetWindowPort(gui.VimWindow);
3193 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003195 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 }
3198 else
3199 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003200 VimPort = GetWindowPort(gui.VimWindow);
3201 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003203 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 }
3205
3206 SizeWindow(gui.VimWindow, width, height, TRUE);
3207
3208 gui_resize_shell(width, height);
3209}
3210
3211/*
3212 * Get the screen dimensions.
3213 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3214 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003215 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 */
3217 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003218gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219{
3220 GDHandle dominantDevice = GetMainDevice();
3221 Rect screenRect = (**dominantDevice).gdRect;
3222
3223 *screen_w = screenRect.right - 10;
3224 *screen_h = screenRect.bottom - 40;
3225}
3226
3227
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003228/*
3229 * Open the Font Panel and wait for the user to select a font and
3230 * close the panel. Then fill the buffer pointed to by font_name with
3231 * the name and size of the selected font and return the font's handle,
3232 * or NOFONT in case of an error.
3233 */
3234 static GuiFont
3235gui_mac_select_font(char_u *font_name)
3236{
3237 GuiFont selected_font = NOFONT;
3238 OSStatus status;
3239 FontSelectionQDStyle curr_font;
3240
3241 /* Initialize the Font Panel with the current font. */
3242 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3243 curr_font.size = (gui.norm_font >> 16);
3244 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3245 curr_font.instance.fontStyle = 0;
3246 curr_font.hasColor = false;
3247 curr_font.version = 0; /* version number of the style structure */
3248 status = SetFontInfoForSelection(kFontSelectionQDType,
3249 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3250
3251 gFontPanelInfo.family = curr_font.instance.fontFamily;
3252 gFontPanelInfo.style = curr_font.instance.fontStyle;
3253 gFontPanelInfo.size = curr_font.size;
3254
3255 /* Pop up the Font Panel. */
3256 status = FPShowHideFontPanel();
3257 if (status == noErr)
3258 {
3259 /*
3260 * The Font Panel is modeless. We really need it to be modal,
3261 * so we spin in an event loop until the panel is closed.
3262 */
3263 gFontPanelInfo.isPanelVisible = true;
3264 while (gFontPanelInfo.isPanelVisible)
3265 {
3266 EventRecord e;
3267 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3268 }
3269
3270 GetFontPanelSelection(font_name);
3271 selected_font = gui_mac_find_font(font_name);
3272 }
3273 return selected_font;
3274}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003275
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276
3277/*
3278 * Initialise vim to use the font with the given name. Return FAIL if the font
3279 * could not be loaded, OK otherwise.
3280 */
3281 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003282gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283{
3284 /* TODO: Add support for bold italic underline proportional etc... */
3285 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003286 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 FontInfo font_info;
3288 short font_id;
3289 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003290 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003292#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003293 if (p_macatsui && gFontStyle == NULL)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003294 {
3295 if (ATSUCreateStyle(&gFontStyle) != noErr)
3296 gFontStyle = NULL;
3297 }
3298#endif
3299
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 if (font_name == NULL)
3301 {
3302 /* First try to get the suggested font */
3303 GetFNum(suggestedFont, &font_id);
3304
3305 if (font_id == 0)
3306 {
3307 /* Then pickup the standard application font */
3308 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003309 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003311 else
3312 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3314 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003315 else if (STRCMP(font_name, "*") == 0)
3316 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003317 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003318
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003319 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003320 if (font == NOFONT)
3321 return FAIL;
3322
3323 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003324 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003325 if (new_p_guifont != NULL)
3326 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003327 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003328 vim_free(p_guifont);
3329 p_guifont = new_p_guifont;
3330 /* Replace spaces in the font name with underscores. */
3331 for ( ; *new_p_guifont; ++new_p_guifont)
3332 {
3333 if (*new_p_guifont == ' ')
3334 *new_p_guifont = '_';
3335 }
3336 }
3337 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 else
3339 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003341 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342
3343 if (font == NOFONT)
3344 return FAIL;
3345 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003346
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 gui.norm_font = font;
3348
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003349 hl_set_font_name(used_font_name);
3350
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003351 TextSize(font >> 16);
3352 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003354 GetFontInfo(&font_info);
3355
3356 gui.char_ascent = font_info.ascent;
3357 gui.char_width = CharWidth('_');
3358 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3359
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003360#ifdef USE_ATSUI_DRAWING
3361 ATSUFontID fontID;
3362 Fixed fontSize;
3363 ATSStyleRenderingOptions fontOptions;
3364
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003365 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003366 {
3367 fontID = font & 0xFFFF;
3368 fontSize = Long2Fix(font >> 16);
3369
3370 /* No antialiasing by default (do not attempt to touch antialising
3371 * options on pre-Jaguar) */
3372 fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003373 (gMacSystemVersion >= 0x1020) ?
3374 kATSStyleNoAntiAliasing :
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003375 kATSStyleNoOptions;
3376
3377 ATSUAttributeTag attribTags[] =
3378 {
3379 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3380 kATSUMaxATSUITagValue+1
3381 };
3382 ByteCount attribSizes[] =
3383 {
3384 sizeof(ATSUFontID), sizeof(Fixed),
3385 sizeof(ATSStyleRenderingOptions), sizeof font
3386 };
3387 ATSUAttributeValuePtr attribValues[] =
3388 {
3389 &fontID, &fontSize, &fontOptions, &font
3390 };
3391
3392 /* Convert font id to ATSUFontID */
3393 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3394 {
3395 if (ATSUSetAttributes(gFontStyle,
3396 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3397 attribTags, attribSizes, attribValues) != noErr)
3398 {
3399 ATSUDisposeStyle(gFontStyle);
3400 gFontStyle = NULL;
3401 }
3402 }
3403 }
3404#endif
3405
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407}
3408
Bram Moolenaar02743632005-07-25 20:42:36 +00003409/*
3410 * Adjust gui.char_height (after 'linespace' was changed).
3411 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003413gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414{
3415 FontInfo font_info;
3416
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003417 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3419 gui.char_ascent = font_info.ascent + p_linespace / 2;
3420 return OK;
3421}
3422
3423/*
3424 * Get a font structure for highlighting.
3425 */
3426 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003427gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428{
3429 GuiFont font;
3430
3431 font = gui_mac_find_font(name);
3432
3433 if (font == NOFONT)
3434 {
3435 if (giveErrorIfMissing)
3436 EMSG2(_(e_font), name);
3437 return NOFONT;
3438 }
3439 /*
3440 * TODO : Accept only monospace
3441 */
3442
3443 return font;
3444}
3445
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003446#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003448 * Return the name of font "font" in allocated memory.
3449 * Don't know how to get the actual name, thus use the provided name.
3450 */
3451 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003452gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003453{
3454 if (name == NULL)
3455 return NULL;
3456 return vim_strsave(name);
3457}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003458#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003459
3460/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 * Set the current text font.
3462 */
3463 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003464gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003466#ifdef USE_ATSUI_DRAWING
3467 GuiFont currFont;
3468 ByteCount actualFontByteCount;
3469 ATSUFontID fontID;
3470 Fixed fontSize;
3471 ATSStyleRenderingOptions fontOptions;
3472
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003473 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003474 {
3475 /* Avoid setting same font again */
3476 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
3477 &currFont, &actualFontByteCount) == noErr &&
3478 actualFontByteCount == (sizeof font))
3479 {
3480 if (currFont == font)
3481 return;
3482 }
3483
3484 fontID = font & 0xFFFF;
3485 fontSize = Long2Fix(font >> 16);
3486 /* Respect p_antialias setting only for wide font.
3487 * The reason for doing this at the moment is a bit complicated,
3488 * but it's mainly because a) latin (non-wide) aliased fonts
3489 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3490 * b) wide multibyte input does not suffer from that problem. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003491 /*fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003492 (p_antialias && (font == gui.wide_font)) ?
3493 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003494 */
3495 /*fontOptions = kATSStyleAntiAliasing;*/
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003496
3497 ATSUAttributeTag attribTags[] =
3498 {
3499 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3500 kATSUMaxATSUITagValue+1
3501 };
3502 ByteCount attribSizes[] =
3503 {
3504 sizeof(ATSUFontID), sizeof(Fixed),
3505 sizeof(ATSStyleRenderingOptions), sizeof font
3506 };
3507 ATSUAttributeValuePtr attribValues[] =
3508 {
3509 &fontID, &fontSize, &fontOptions, &font
3510 };
3511
3512 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3513 {
3514 if (ATSUSetAttributes(gFontStyle,
3515 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3516 attribTags, attribSizes, attribValues) != noErr)
3517 {
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003518# ifndef NDEBUG
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003519 fprintf(stderr, "couldn't set font style\n");
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003520# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003521 ATSUDisposeStyle(gFontStyle);
3522 gFontStyle = NULL;
3523 }
3524 }
3525
3526 }
3527
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003528 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003529 {
3530 /* Setup automatic font substitution. The user's guifontwide
3531 * is tried first, then the system tries other fonts. */
3532/*
3533 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3534 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3535 ATSUCreateFontFallbacks(&gFontFallbacks);
3536 ATSUSetObjFontFallbacks(gFontFallbacks, );
3537*/
3538 if (gui.wide_font)
3539 {
3540 ATSUFontID fallbackFonts;
3541 gIsFontFallbackSet = TRUE;
3542
3543 if (FMGetFontFromFontFamilyInstance(
3544 (gui.wide_font & 0xFFFF),
3545 0,
3546 &fallbackFonts,
3547 NULL) == noErr)
3548 {
3549 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
3550 }
3551/*
3552 ATSUAttributeValuePtr fallbackValues[] = { };
3553*/
3554 }
3555 }
3556#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557 TextSize(font >> 16);
3558 TextFont(font & 0xFFFF);
3559}
3560
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561/*
3562 * If a font is not going to be used, free its structure.
3563 */
3564 void
3565gui_mch_free_font(font)
3566 GuiFont font;
3567{
3568 /*
3569 * Free font when "font" is not 0.
3570 * Nothing to do in the current implementation, since
3571 * nothing is allocated for each font used.
3572 */
3573}
3574
3575 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003576hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577{
3578 if (isdigit(c))
3579 return c - '0';
3580 c = TOLOWER_ASC(c);
3581 if (c >= 'a' && c <= 'f')
3582 return c - 'a' + 10;
3583 return -1000;
3584}
3585
3586/*
3587 * Return the Pixel value (color) for the given color name. This routine was
3588 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3589 * Programmer's Guide.
3590 * Return INVALCOLOR when failed.
3591 */
3592 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003593gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594{
3595 /* TODO: Add support for the new named color of MacOS 8
3596 */
3597 RGBColor MacColor;
3598// guicolor_T color = 0;
3599
3600 typedef struct guicolor_tTable
3601 {
3602 char *name;
3603 guicolor_T color;
3604 } guicolor_tTable;
3605
3606 /*
3607 * The comment at the end of each line is the source
3608 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3609 */
3610 static guicolor_tTable table[] =
3611 {
3612 {"Black", RGB(0x00, 0x00, 0x00)},
3613 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3614 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3615 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3616 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3617 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3618 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003619 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3620 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3621 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3622 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3623 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3624 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3625 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3626 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3627 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3628 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3629 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3630 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3631 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3632 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3633 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3634 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003635 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3636 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 {"white", RGB(0xFF, 0xFF, 0xFF)},
3638 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3639 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3640 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3641 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3642 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3643 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3644 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3645 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3646 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3647 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3648 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3649 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3650 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3651 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3652 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3653 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3654 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3655 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003656 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3658 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3659 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3660 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3661 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3662 };
3663
3664 int r, g, b;
3665 int i;
3666
3667 if (name[0] == '#' && strlen((char *) name) == 7)
3668 {
3669 /* Name is in "#rrggbb" format */
3670 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3671 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3672 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3673 if (r < 0 || g < 0 || b < 0)
3674 return INVALCOLOR;
3675 return RGB(r, g, b);
3676 }
3677 else
3678 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003679 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003681 LMGetHiliteRGB(&MacColor);
3682 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683 }
3684 /* Check if the name is one of the colors we know */
3685 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3686 if (STRICMP(name, table[i].name) == 0)
3687 return table[i].color;
3688 }
3689
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 /*
3691 * Last attempt. Look in the file "$VIM/rgb.txt".
3692 */
3693 {
3694#define LINE_LEN 100
3695 FILE *fd;
3696 char line[LINE_LEN];
3697 char_u *fname;
3698
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700 if (fname == NULL)
3701 return INVALCOLOR;
3702
3703 fd = fopen((char *)fname, "rt");
3704 vim_free(fname);
3705 if (fd == NULL)
3706 return INVALCOLOR;
3707
3708 while (!feof(fd))
3709 {
3710 int len;
3711 int pos;
3712 char *color;
3713
3714 fgets(line, LINE_LEN, fd);
3715 len = strlen(line);
3716
3717 if (len <= 1 || line[len-1] != '\n')
3718 continue;
3719
3720 line[len-1] = '\0';
3721
3722 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3723 if (i != 3)
3724 continue;
3725
3726 color = line + pos;
3727
3728 if (STRICMP(color, name) == 0)
3729 {
3730 fclose(fd);
3731 return (guicolor_T) RGB(r, g, b);
3732 }
3733 }
3734 fclose(fd);
3735 }
3736
3737 return INVALCOLOR;
3738}
3739
3740/*
3741 * Set the current text foreground color.
3742 */
3743 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003744gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745{
3746 RGBColor TheColor;
3747
3748 TheColor.red = Red(color) * 0x0101;
3749 TheColor.green = Green(color) * 0x0101;
3750 TheColor.blue = Blue(color) * 0x0101;
3751
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003752 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753}
3754
3755/*
3756 * Set the current text background color.
3757 */
3758 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003759gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760{
3761 RGBColor TheColor;
3762
3763 TheColor.red = Red(color) * 0x0101;
3764 TheColor.green = Green(color) * 0x0101;
3765 TheColor.blue = Blue(color) * 0x0101;
3766
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003767 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003768}
3769
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003770RGBColor specialColor;
3771
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003772/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003773 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003774 */
3775 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003776gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003777{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003778 specialColor.red = Red(color) * 0x0101;
3779 specialColor.green = Green(color) * 0x0101;
3780 specialColor.blue = Blue(color) * 0x0101;
3781}
3782
3783/*
3784 * Draw undercurl at the bottom of the character cell.
3785 */
3786 static void
3787draw_undercurl(int flags, int row, int col, int cells)
3788{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003789 int x;
3790 int offset;
3791 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3792 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003793
3794 RGBForeColor(&specialColor);
3795
3796 offset = val[FILL_X(col) % 8];
3797 MoveTo(FILL_X(col), y - offset);
3798
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003799 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003800 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003801 offset = val[x % 8];
3802 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003803 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003804}
3805
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003806
3807 static void
3808draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810#ifdef FEAT_MBYTE
3811 char_u *tofree = NULL;
3812
3813 if (output_conv.vc_type != CONV_NONE)
3814 {
3815 tofree = string_convert(&output_conv, s, &len);
3816 if (tofree != NULL)
3817 s = tofree;
3818 }
3819#endif
3820
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 /*
3822 * On OS X, try using Quartz-style text antialiasing.
3823 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003824 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 {
3826 /* Quartz antialiasing is available only in OS 10.2 and later. */
3827 UInt32 qd_flags = (p_antialias ?
3828 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003829 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830 }
3831
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003832 /*
3833 * When antialiasing we're using srcOr mode, we have to clear the block
3834 * before drawing the text.
3835 * Also needed when 'linespace' is non-zero to remove the cursor and
3836 * underlining.
3837 * But not when drawing transparently.
3838 * The following is like calling gui_mch_clear_block(row, col, row, col +
3839 * len - 1), but without setting the bg color to gui.back_pixel.
3840 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003841 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003842 && !(flags & DRAW_TRANSP))
3843 {
3844 Rect rc;
3845
3846 rc.left = FILL_X(col);
3847 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003848#ifdef FEAT_MBYTE
3849 /* Multibyte computation taken from gui_w32.c */
3850 if (has_mbyte)
3851 {
3852 int cell_len = 0;
3853 int n;
3854
3855 /* Compute the length in display cells. */
3856 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3857 cell_len += (*mb_ptr2cells)(s + n);
3858 rc.right = FILL_X(col + cell_len);
3859 }
3860 else
3861#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003862 rc.right = FILL_X(col + len) + (col + len == Columns);
3863 rc.bottom = FILL_Y(row + 1);
3864 EraseRect(&rc);
3865 }
3866
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003867 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 {
3869 StyleParameter face;
3870
3871 face = normal;
3872 if (flags & DRAW_BOLD)
3873 face |= bold;
3874 if (flags & DRAW_UNDERL)
3875 face |= underline;
3876 TextFace(face);
3877
3878 /* Quartz antialiasing works only in srcOr transfer mode. */
3879 TextMode(srcOr);
3880
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 MoveTo(TEXT_X(col), TEXT_Y(row));
3882 DrawText((char*)s, 0, len);
3883 }
3884 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 {
3886 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003887 TextMode(srcCopy);
3888 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003889
3890 /* SelectFont(hdc, gui.currFont); */
3891
3892 if (flags & DRAW_TRANSP)
3893 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003894 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 }
3896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003897 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003898 DrawText((char *)s, 0, len);
3899
3900 if (flags & DRAW_BOLD)
3901 {
3902 TextMode(srcOr);
3903 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3904 DrawText((char *)s, 0, len);
3905 }
3906
3907 if (flags & DRAW_UNDERL)
3908 {
3909 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3910 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3911 }
3912 }
3913
3914 if (flags & DRAW_UNDERC)
3915 draw_undercurl(flags, row, col, len);
3916
3917#ifdef FEAT_MBYTE
3918 vim_free(tofree);
3919#endif
3920}
3921
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003922#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003923
3924 static void
3925draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3926{
3927 /* ATSUI requires utf-16 strings */
3928 UniCharCount utf16_len;
3929 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3930 utf16_len /= sizeof(UniChar);
3931
3932 /* - ATSUI automatically antialiases text (Someone)
3933 * - for some reason it does not work... (Jussi) */
3934
3935 /*
3936 * When antialiasing we're using srcOr mode, we have to clear the block
3937 * before drawing the text.
3938 * Also needed when 'linespace' is non-zero to remove the cursor and
3939 * underlining.
3940 * But not when drawing transparently.
3941 * The following is like calling gui_mch_clear_block(row, col, row, col +
3942 * len - 1), but without setting the bg color to gui.back_pixel.
3943 */
3944 if ((flags & DRAW_TRANSP) == 0)
3945 {
3946 Rect rc;
3947
3948 rc.left = FILL_X(col);
3949 rc.top = FILL_Y(row);
3950 /* Multibyte computation taken from gui_w32.c */
3951 if (has_mbyte)
3952 {
3953 int cell_len = 0;
3954 int n;
3955
3956 /* Compute the length in display cells. */
3957 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3958 cell_len += (*mb_ptr2cells)(s + n);
3959 rc.right = FILL_X(col + cell_len);
3960 }
3961 else
3962 rc.right = FILL_X(col + len) + (col + len == Columns);
3963
3964 rc.bottom = FILL_Y(row + 1);
3965 EraseRect(&rc);
3966 }
3967
3968 {
3969 /* Use old-style, non-antialiased QuickDraw text rendering. */
3970 TextMode(srcCopy);
3971 TextFace(normal);
3972
3973 /* SelectFont(hdc, gui.currFont); */
3974
3975 if (flags & DRAW_TRANSP)
3976 {
3977 TextMode(srcOr);
3978 }
3979
3980 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003981 ATSUTextLayout textLayout;
3982
3983 if (ATSUCreateTextLayoutWithTextPtr(tofree,
3984 kATSUFromTextBeginning, kATSUToTextEnd,
3985 utf16_len,
3986 (gFontStyle ? 1 : 0), &utf16_len,
3987 (gFontStyle ? &gFontStyle : NULL),
3988 &textLayout) == noErr)
3989 {
3990 ATSUSetTransientFontMatching(textLayout, TRUE);
3991
3992 ATSUDrawText(textLayout,
3993 kATSUFromTextBeginning, kATSUToTextEnd,
3994 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
3995
3996 ATSUDisposeTextLayout(textLayout);
3997 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003998 }
3999
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004000 if (flags & DRAW_UNDERC)
4001 draw_undercurl(flags, row, col, len);
4002
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004004}
4005#endif
4006
4007 void
4008gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4009{
4010#if defined(USE_ATSUI_DRAWING)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004011 if (p_macatsui)
4012 draw_string_ATSUI(row, col, s, len, flags);
4013 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004015 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016}
4017
4018/*
4019 * Return OK if the key with the termcap name "name" is supported.
4020 */
4021 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004022gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023{
4024 int i;
4025
4026 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4027 if (name[0] == special_keys[i].vim_code0 &&
4028 name[1] == special_keys[i].vim_code1)
4029 return OK;
4030 return FAIL;
4031}
4032
4033 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004034gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004036 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037}
4038
4039 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004040gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041{
4042 /* Do a visual beep by reversing the foreground and background colors */
4043 Rect rc;
4044
4045 /*
4046 * Note: InvertRect() excludes right and bottom of rectangle.
4047 */
4048 rc.left = 0;
4049 rc.top = 0;
4050 rc.right = gui.num_cols * gui.char_width;
4051 rc.bottom = gui.num_rows * gui.char_height;
4052 InvertRect(&rc);
4053
4054 ui_delay((long)msec, TRUE); /* wait for some msec */
4055
4056 InvertRect(&rc);
4057}
4058
4059/*
4060 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4061 */
4062 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004063gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064{
4065 Rect rc;
4066
4067 /*
4068 * Note: InvertRect() excludes right and bottom of rectangle.
4069 */
4070 rc.left = FILL_X(c);
4071 rc.top = FILL_Y(r);
4072 rc.right = rc.left + nc * gui.char_width;
4073 rc.bottom = rc.top + nr * gui.char_height;
4074 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075}
4076
4077/*
4078 * Iconify the GUI window.
4079 */
4080 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004081gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082{
4083 /* TODO: find out what could replace iconify
4084 * -window shade?
4085 * -hide application?
4086 */
4087}
4088
4089#if defined(FEAT_EVAL) || defined(PROTO)
4090/*
4091 * Bring the Vim window to the foreground.
4092 */
4093 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004094gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095{
4096 /* TODO */
4097}
4098#endif
4099
4100/*
4101 * Draw a cursor without focus.
4102 */
4103 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004104gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105{
4106 Rect rc;
4107
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 /*
4109 * Note: FrameRect() excludes right and bottom of rectangle.
4110 */
4111 rc.left = FILL_X(gui.col);
4112 rc.top = FILL_Y(gui.row);
4113 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004114#ifdef FEAT_MBYTE
4115 if (mb_lefthalve(gui.row, gui.col))
4116 rc.right += gui.char_width;
4117#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 rc.bottom = rc.top + gui.char_height;
4119
4120 gui_mch_set_fg_color(color);
4121
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004122 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123}
4124
4125/*
4126 * Draw part of a cursor, only w pixels wide, and h pixels high.
4127 */
4128 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004129gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130{
4131 Rect rc;
4132
4133#ifdef FEAT_RIGHTLEFT
4134 /* vertical line should be on the right of current point */
4135 if (CURSOR_BAR_RIGHT)
4136 rc.left = FILL_X(gui.col + 1) - w;
4137 else
4138#endif
4139 rc.left = FILL_X(gui.col);
4140 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4141 rc.right = rc.left + w;
4142 rc.bottom = rc.top + h;
4143
4144 gui_mch_set_fg_color(color);
4145
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004146 FrameRect(&rc);
4147// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148}
4149
4150
4151
4152/*
4153 * Catch up with any queued X events. This may put keyboard input into the
4154 * input buffer, call resize call-backs, trigger timers etc. If there is
4155 * nothing in the X event queue (& no timers pending), then we return
4156 * immediately.
4157 */
4158 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004159gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160{
4161 /* TODO: find what to do
4162 * maybe call gui_mch_wait_for_chars (0)
4163 * more like look at EventQueue then
4164 * call heart of gui_mch_wait_for_chars;
4165 *
4166 * if (eventther)
4167 * gui_mac_handle_event(&event);
4168 */
4169 EventRecord theEvent;
4170
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004171 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 if (theEvent.what != nullEvent)
4173 gui_mch_wait_for_chars(0);
4174}
4175
4176/*
4177 * Simple wrapper to neglect more easily the time
4178 * spent inside WaitNextEvent while profiling.
4179 */
4180
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 pascal
4182 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004183WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184{
4185 if (((long) sleep) < -1)
4186 sleep = 32767;
4187 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4188}
4189
4190/*
4191 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4192 * from the keyboard.
4193 * wtime == -1 Wait forever.
4194 * wtime == 0 This should never happen.
4195 * wtime > 0 Wait wtime milliseconds for a character.
4196 * Returns OK if a character was found to be available within the given time,
4197 * or FAIL otherwise.
4198 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004200gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201{
4202 EventMask mask = (everyEvent);
4203 EventRecord event;
4204 long entryTick;
4205 long currentTick;
4206 long sleeppyTick;
4207
4208 /* If we are providing life feedback with the scrollbar,
4209 * we don't want to try to wait for an event, or else
4210 * there won't be any life feedback.
4211 */
4212 if (dragged_sb != NULL)
4213 return FAIL;
4214 /* TODO: Check if FAIL is the proper return code */
4215
4216 entryTick = TickCount();
4217
4218 allow_scrollbar = TRUE;
4219
4220 do
4221 {
4222/* if (dragRectControl == kCreateEmpty)
4223 {
4224 dragRgn = NULL;
4225 dragRectControl = kNothing;
4226 }
4227 else*/ if (dragRectControl == kCreateRect)
4228 {
4229 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004230 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231 dragRectControl = kNothing;
4232 }
4233 /*
4234 * Don't use gui_mch_update() because then we will spin-lock until a
4235 * char arrives, instead we use WaitNextEventWrp() to hang until an
4236 * event arrives. No need to check for input_buf_full because we are
4237 * returning as soon as it contains a single char.
4238 */
4239 /* TODO: reduce wtime accordinly??? */
4240 if (wtime > -1)
4241 sleeppyTick = 60*wtime/1000;
4242 else
4243 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004244 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004246 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 if (input_available())
4248 {
4249 allow_scrollbar = FALSE;
4250 return OK;
4251 }
4252 }
4253 currentTick = TickCount();
4254 }
4255 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4256
4257 allow_scrollbar = FALSE;
4258 return FAIL;
4259}
4260
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261/*
4262 * Output routines.
4263 */
4264
4265/* Flush any output to the screen */
4266 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004267gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268{
4269 /* TODO: Is anything needed here? */
4270}
4271
4272/*
4273 * Clear a rectangular region of the screen from text pos (row1, col1) to
4274 * (row2, col2) inclusive.
4275 */
4276 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004277gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278{
4279 Rect rc;
4280
4281 /*
4282 * Clear one extra pixel at the far right, for when bold characters have
4283 * spilled over to the next column.
4284 */
4285 rc.left = FILL_X(col1);
4286 rc.top = FILL_Y(row1);
4287 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4288 rc.bottom = FILL_Y(row2 + 1);
4289
4290 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004291 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292}
4293
4294/*
4295 * Clear the whole text window.
4296 */
4297 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004298gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004299{
4300 Rect rc;
4301
4302 rc.left = 0;
4303 rc.top = 0;
4304 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4305 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4306
4307 gui_mch_set_bg_color(gui.back_pixel);
4308 EraseRect(&rc);
4309/* gui_mch_set_fg_color(gui.norm_pixel);
4310 FrameRect(&rc);
4311*/
4312}
4313
4314/*
4315 * Delete the given number of lines from the given row, scrolling up any
4316 * text further down within the scroll region.
4317 */
4318 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004319gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320{
4321 Rect rc;
4322
4323 /* changed without checking! */
4324 rc.left = FILL_X(gui.scroll_region_left);
4325 rc.right = FILL_X(gui.scroll_region_right + 1);
4326 rc.top = FILL_Y(row);
4327 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4328
4329 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004330 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331
4332 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4333 gui.scroll_region_left,
4334 gui.scroll_region_bot, gui.scroll_region_right);
4335}
4336
4337/*
4338 * Insert the given number of lines before the given row, scrolling down any
4339 * following text within the scroll region.
4340 */
4341 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004342gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343{
4344 Rect rc;
4345
4346 rc.left = FILL_X(gui.scroll_region_left);
4347 rc.right = FILL_X(gui.scroll_region_right + 1);
4348 rc.top = FILL_Y(row);
4349 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4350
4351 gui_mch_set_bg_color(gui.back_pixel);
4352
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004353 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354
4355 /* Update gui.cursor_row if the cursor scrolled or copied over */
4356 if (gui.cursor_row >= gui.row
4357 && gui.cursor_col >= gui.scroll_region_left
4358 && gui.cursor_col <= gui.scroll_region_right)
4359 {
4360 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4361 gui.cursor_row += num_lines;
4362 else if (gui.cursor_row <= gui.scroll_region_bot)
4363 gui.cursor_is_valid = FALSE;
4364 }
4365
4366 gui_clear_block(row, gui.scroll_region_left,
4367 row + num_lines - 1, gui.scroll_region_right);
4368}
4369
4370 /*
4371 * TODO: add a vim format to the clipboard which remember
4372 * LINEWISE, CHARWISE, BLOCKWISE
4373 */
4374
4375 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004376clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377{
4378
4379 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004380 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 Size scrapSize;
4382 ScrapFlavorFlags scrapFlags;
4383 ScrapRef scrap = nil;
4384 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 int type;
4386 char *searchCR;
4387 char_u *tempclip;
4388
4389
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004390 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 if (error != noErr)
4392 return;
4393
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004394 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4395 if (error == noErr)
4396 {
4397 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4398 if (error == noErr && scrapSize > 1)
4399 flavor = 1;
4400 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004402 if (flavor == 0)
4403 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004404 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004405 if (error != noErr)
4406 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004408 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004409 if (error != noErr)
4410 return;
4411 }
4412
4413 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004415 /* In CARBON we don't need a Handle, a pointer is good */
4416 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004418 /* tempclip = lalloc(scrapSize+1, TRUE); */
4419 HLock(textOfClip);
4420 error = GetScrapFlavorData(scrap,
4421 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4422 &scrapSize, *textOfClip);
4423 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004425 if (flavor)
4426 type = **textOfClip;
4427 else
4428 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4429
4430 tempclip = lalloc(scrapSize + 1, TRUE);
4431 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4432 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004434#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004435 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004436 /* Convert from utf-16 (clipboard) */
4437 size_t encLen = 0;
4438 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004439
4440 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004442 scrapSize = encLen;
4443 vim_free(tempclip);
4444 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004446 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004448
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004449 searchCR = (char *)tempclip;
4450 while (searchCR != NULL)
4451 {
4452 searchCR = strchr(searchCR, '\r');
4453 if (searchCR != NULL)
4454 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004456
4457 clip_yank_selection(type, tempclip, scrapSize, cbd);
4458
4459 vim_free(tempclip);
4460 HUnlock(textOfClip);
4461
4462 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463}
4464
4465 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004466clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467{
4468 /*
4469 * TODO: Really nothing to do?
4470 */
4471}
4472
4473 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004474clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475{
4476 return OK;
4477}
4478
4479/*
4480 * Send the current selection to the clipboard.
4481 */
4482 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004483clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484{
4485 Handle textOfClip;
4486 long scrapSize;
4487 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489
4490 char_u *str = NULL;
4491
4492 if (!cbd->owned)
4493 return;
4494
4495 clip_get_selection(cbd);
4496
4497 /*
4498 * Once we set the clipboard, lose ownership. If another application sets
4499 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 cbd->owned = FALSE;
4502
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004503 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004505#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004506 size_t utf16_len = 0;
4507 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4508 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004510 scrapSize = utf16_len;
4511 vim_free(str);
4512 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513 }
4514#endif
4515
4516 if (type >= 0)
4517 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004520 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 HLock(textOfClip);
4522
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004523 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004524 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004525 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004526 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004527 scrapSize, *textOfClip + 1);
4528 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4529 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530 HUnlock(textOfClip);
4531 DisposeHandle(textOfClip);
4532 }
4533
4534 vim_free(str);
4535}
4536
4537 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004538gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539{
4540 Rect VimBound;
4541
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004542/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544
4545 if (gui.which_scrollbars[SBAR_LEFT])
4546 {
4547 VimBound.left = -gui.scrollbar_width + 1;
4548 }
4549 else
4550 {
4551 VimBound.left = 0;
4552 }
4553
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004556 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557}
4558
4559/*
4560 * Menu stuff.
4561 */
4562
4563 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004564gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565{
4566 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004567 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568 */
4569}
4570
4571 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004572gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573{
4574 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004575 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004576 */
4577}
4578
4579/*
4580 * Add a sub menu to the menu bar.
4581 */
4582 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004583gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584{
4585 /*
4586 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4587 * TODO: use menu->mnemonic and menu->actext
4588 * TODO: Try to reuse menu id
4589 * Carbon Help suggest to use only id between 1 and 235
4590 */
4591 static long next_avail_id = 128;
4592 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004593#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004594 CFStringRef name;
4595#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004597#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004598 short index;
4599 vimmenu_T *parent = menu->parent;
4600 vimmenu_T *brother = menu->next;
4601
4602 /* Cannot add a menu if ... */
4603 if ((parent != NULL && parent->submenu_id == 0))
4604 return;
4605
4606 /* menu ID greater than 1024 are reserved for ??? */
4607 if (next_avail_id == 1024)
4608 return;
4609
4610 /* My brother could be the PopUp, find my real brother */
4611 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4612 brother = brother->next;
4613
4614 /* Find where to insert the menu (for MenuBar) */
4615 if ((parent == NULL) && (brother != NULL))
4616 menu_after_me = brother->submenu_id;
4617
4618 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4619 if (!menu_is_menubar(menu->name))
4620 menu_after_me = hierMenu;
4621
4622 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004623#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004624 name = menu_title_removing_mnemonic(menu);
4625#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004627#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 if (name == NULL)
4629 return;
4630
4631 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632 {
4633 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004634 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4635 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 */
4637 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004638#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004639 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4640 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4641#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004642 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004643#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 next_avail_id++;
4645 }
4646
4647 if (parent == NULL)
4648 {
4649 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4650
4651 /* TODO: Verify if we could only Insert Menu if really part of the
4652 * menubar The Inserted menu are scanned or the Command-key combos
4653 */
4654
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004655 /* Insert the menu */
4656 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657#if 1
4658 /* Vim should normally update it. TODO: verify */
4659 DrawMenuBar();
4660#endif
4661 }
4662 else
4663 {
4664 /* Adding as a submenu */
4665
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004666 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667
4668 /* Call InsertMenuItem followed by SetMenuItemText
4669 * to avoid special character recognition by InsertMenuItem
4670 */
4671 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004672#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004673 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4674#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4678 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4679 InsertMenu(menu->submenu_handle, hierMenu);
4680 }
4681
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004682#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004683 CFRelease(name);
4684#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004685 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004686#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687
4688#if 0
4689 /* Done by Vim later on */
4690 DrawMenuBar();
4691#endif
4692}
4693
4694/*
4695 * Add a menu item to a menu
4696 */
4697 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004698gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004700#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004701 CFStringRef name;
4702#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004704#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 vimmenu_T *parent = menu->parent;
4706 int menu_inserted;
4707
4708 /* Cannot add item, if the menu have not been created */
4709 if (parent->submenu_id == 0)
4710 return;
4711
4712 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4713 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4714
4715 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004716#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004717 name = menu_title_removing_mnemonic(menu);
4718#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004720#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721
4722 /* Where are just a menu item, so no handle, no id */
4723 menu->submenu_id = 0;
4724 menu->submenu_handle = NULL;
4725
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 menu_inserted = 0;
4727 if (menu->actext)
4728 {
4729 /* If the accelerator text for the menu item looks like it describes
4730 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4731 * item's command equivalent.
4732 */
4733 int key = 0;
4734 int modifiers = 0;
4735 char_u *p_actext;
4736
4737 p_actext = menu->actext;
4738 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4739 if (*p_actext != 0)
4740 key = 0; /* error: trailing text */
4741 /* find_special_key() returns a keycode with as many of the
4742 * specified modifiers as appropriate already applied (e.g., for
4743 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4744 * as the only modifier). Since we want to display all of the
4745 * modifiers, we need to convert the keycode back to a printable
4746 * character plus modifiers.
4747 * TODO: Write an alternative find_special_key() that doesn't
4748 * apply modifiers.
4749 */
4750 if (key > 0 && key < 32)
4751 {
4752 /* Convert a control key to an uppercase letter. Note that
4753 * by this point it is no longer possible to distinguish
4754 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4755 */
4756 modifiers |= MOD_MASK_CTRL;
4757 key += '@';
4758 }
4759 /* If the keycode is an uppercase letter, set the Shift modifier.
4760 * If it is a lowercase letter, don't set the modifier, but convert
4761 * the letter to uppercase for display in the menu.
4762 */
4763 else if (key >= 'A' && key <= 'Z')
4764 modifiers |= MOD_MASK_SHIFT;
4765 else if (key >= 'a' && key <= 'z')
4766 key += 'A' - 'a';
4767 /* Note: keycodes below 0x22 are reserved by Apple. */
4768 if (key >= 0x22 && vim_isprintc_strict(key))
4769 {
4770 int valid = 1;
4771 char_u mac_mods = kMenuNoModifiers;
4772 /* Convert Vim modifier codes to Menu Manager equivalents. */
4773 if (modifiers & MOD_MASK_SHIFT)
4774 mac_mods |= kMenuShiftModifier;
4775 if (modifiers & MOD_MASK_CTRL)
4776 mac_mods |= kMenuControlModifier;
4777 if (!(modifiers & MOD_MASK_CMD))
4778 mac_mods |= kMenuNoCommandModifier;
4779 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4780 valid = 0; /* TODO: will Alt someday map to Option? */
4781 if (valid)
4782 {
4783 char_u item_txt[10];
4784 /* Insert the menu item after idx, with its command key. */
4785 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4786 item_txt[3] = key;
4787 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4788 /* Set the modifier keys. */
4789 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4790 menu_inserted = 1;
4791 }
4792 }
4793 }
4794 /* Call InsertMenuItem followed by SetMenuItemText
4795 * to avoid special character recognition by InsertMenuItem
4796 */
4797 if (!menu_inserted)
4798 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4799 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004800#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004801 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4802#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004804#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805
4806#if 0
4807 /* Called by Vim */
4808 DrawMenuBar();
4809#endif
4810
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004811#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004812 CFRelease(name);
4813#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814 /* TODO: Can name be freed? */
4815 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004816#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004817}
4818
4819 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004820gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821{
4822 /* no tearoff menus */
4823}
4824
4825/*
4826 * Destroy the machine specific menu widget.
4827 */
4828 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004829gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004831 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004832
4833 if (index > 0)
4834 {
4835 if (menu->parent)
4836 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 {
4838 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004839 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840
4841 /* Delete the Menu if it was a hierarchical Menu */
4842 if (menu->submenu_id != 0)
4843 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004844 DeleteMenu(menu->submenu_id);
4845 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 }
4847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 }
4849#ifdef DEBUG_MAC_MENU
4850 else
4851 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004852 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 }
4854#endif
4855 }
4856 else
4857 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004859 DeleteMenu(menu->submenu_id);
4860 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861 }
4862 }
4863 /* Shouldn't this be already done by Vim. TODO: Check */
4864 DrawMenuBar();
4865}
4866
4867/*
4868 * Make a menu either grey or not grey.
4869 */
4870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004871gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872{
4873 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004874 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875/*
4876 index = menu->index;
4877*/
4878 if (grey)
4879 {
4880 if (menu->children)
4881 DisableMenuItem(menu->submenu_handle, index);
4882 if (menu->parent)
4883 if (menu->parent->submenu_handle)
4884 DisableMenuItem(menu->parent->submenu_handle, index);
4885 }
4886 else
4887 {
4888 if (menu->children)
4889 EnableMenuItem(menu->submenu_handle, index);
4890 if (menu->parent)
4891 if (menu->parent->submenu_handle)
4892 EnableMenuItem(menu->parent->submenu_handle, index);
4893 }
4894}
4895
4896/*
4897 * Make menu item hidden or not hidden
4898 */
4899 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004900gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901{
4902 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004903 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004904}
4905
4906
4907/*
4908 * This is called after setting all the menus to grey/hidden or not.
4909 */
4910 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004911gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912{
4913 DrawMenuBar();
4914}
4915
4916
4917/*
4918 * Scrollbar stuff.
4919 */
4920
4921 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004922gui_mch_enable_scrollbar(
4923 scrollbar_T *sb,
4924 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925{
4926 if (flag)
4927 ShowControl(sb->id);
4928 else
4929 HideControl(sb->id);
4930
4931#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004932 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933#endif
4934}
4935
4936 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004937gui_mch_set_scrollbar_thumb(
4938 scrollbar_T *sb,
4939 long val,
4940 long size,
4941 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942{
4943 SetControl32BitMaximum (sb->id, max);
4944 SetControl32BitMinimum (sb->id, 0);
4945 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004946 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004948 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949#endif
4950}
4951
4952 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004953gui_mch_set_scrollbar_pos(
4954 scrollbar_T *sb,
4955 int x,
4956 int y,
4957 int w,
4958 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004959{
4960 gui_mch_set_bg_color(gui.back_pixel);
4961/* if (gui.which_scrollbars[SBAR_LEFT])
4962 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004963 MoveControl(sb->id, x-16, y);
4964 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 }
4966 else
4967 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004968 MoveControl(sb->id, x, y);
4969 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004970 }*/
4971 if (sb == &gui.bottom_sbar)
4972 h += 1;
4973 else
4974 w += 1;
4975
4976 if (gui.which_scrollbars[SBAR_LEFT])
4977 x -= 15;
4978
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004979 MoveControl(sb->id, x, y);
4980 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004982 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004983#endif
4984}
4985
4986 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004987gui_mch_create_scrollbar(
4988 scrollbar_T *sb,
4989 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990{
4991 Rect bounds;
4992
4993 bounds.top = -16;
4994 bounds.bottom = -10;
4995 bounds.right = -10;
4996 bounds.left = -16;
4997
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004998 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 &bounds,
5000 "\pScrollBar",
5001 TRUE,
5002 0, /* current*/
5003 0, /* top */
5004 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005006 (long) sb->ident);
5007#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005008 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009#endif
5010}
5011
5012 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005013gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014{
5015 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005016 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005018 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005019#endif
5020}
5021
5022
5023/*
5024 * Cursor blink functions.
5025 *
5026 * This is a simple state machine:
5027 * BLINK_NONE not blinking at all
5028 * BLINK_OFF blinking, cursor is not shown
5029 * BLINK_ON blinking, cursor is shown
5030 */
5031 void
5032gui_mch_set_blinking(long wait, long on, long off)
5033{
5034 /* TODO: TODO: TODO: TODO: */
5035/* blink_waittime = wait;
5036 blink_ontime = on;
5037 blink_offtime = off;*/
5038}
5039
5040/*
5041 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5042 */
5043 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005044gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005045{
5046 gui_update_cursor(TRUE, FALSE);
5047 /* TODO: TODO: TODO: TODO: */
5048/* gui_w32_rm_blink_timer();
5049 if (blink_state == BLINK_OFF)
5050 gui_update_cursor(TRUE, FALSE);
5051 blink_state = BLINK_NONE;*/
5052}
5053
5054/*
5055 * Start the cursor blinking. If it was already blinking, this restarts the
5056 * waiting time and shows the cursor.
5057 */
5058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005059gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060{
5061 gui_update_cursor(TRUE, FALSE);
5062 /* TODO: TODO: TODO: TODO: */
5063/* gui_w32_rm_blink_timer(); */
5064
5065 /* Only switch blinking on if none of the times is zero */
5066/* if (blink_waittime && blink_ontime && blink_offtime)
5067 {
5068 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5069 (TIMERPROC)_OnBlinkTimer);
5070 blink_state = BLINK_ON;
5071 gui_update_cursor(TRUE, FALSE);
5072 }*/
5073}
5074
5075/*
5076 * Return the RGB value of a pixel as long.
5077 */
5078 long_u
5079gui_mch_get_rgb(guicolor_T pixel)
5080{
5081 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5082}
5083
5084
5085
5086#ifdef FEAT_BROWSE
5087/*
5088 * Pop open a file browser and return the file selected, in allocated memory,
5089 * or NULL if Cancel is hit.
5090 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5091 * title - Title message for the file browser dialog.
5092 * dflt - Default name of file.
5093 * ext - Default extension to be added to files without extensions.
5094 * initdir - directory in which to open the browser (NULL = current dir)
5095 * filter - Filter for matched files to choose from.
5096 * Has a format like this:
5097 * "C Files (*.c)\0*.c\0"
5098 * "All Files\0*.*\0\0"
5099 * If these two strings were concatenated, then a choice of two file
5100 * filters will be selectable to the user. Then only matching files will
5101 * be shown in the browser. If NULL, the default allows all files.
5102 *
5103 * *NOTE* - the filter string must be terminated with TWO nulls.
5104 */
5105 char_u *
5106gui_mch_browse(
5107 int saving,
5108 char_u *title,
5109 char_u *dflt,
5110 char_u *ext,
5111 char_u *initdir,
5112 char_u *filter)
5113{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114 /* TODO: Add Ammon's safety checl (Dany) */
5115 NavReplyRecord reply;
5116 char_u *fname = NULL;
5117 char_u **fnames = NULL;
5118 long numFiles;
5119 NavDialogOptions navOptions;
5120 OSErr error;
5121
5122 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005123 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124
5125
5126 /* TODO: If we get a :browse args, set the Multiple bit. */
5127 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5128 | kNavDontAutoTranslate
5129 | kNavDontAddTranslateItems
5130 /* | kNavAllowMultipleFiles */
5131 | kNavAllowStationery;
5132
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005133 (void) C2PascalString(title, &navOptions.message);
5134 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135 /* Could set clientName?
5136 * windowTitle? (there's no title bar?)
5137 */
5138
5139 if (saving)
5140 {
5141 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005142 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 if (!reply.validRecord)
5144 return NULL;
5145 }
5146 else
5147 {
5148 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5149 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5150 if (!reply.validRecord)
5151 return NULL;
5152 }
5153
5154 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5155
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005156 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157
5158 if (fnames)
5159 {
5160 fname = fnames[0];
5161 vim_free(fnames);
5162 }
5163
5164 /* TODO: Shorten the file name if possible */
5165 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166}
5167#endif /* FEAT_BROWSE */
5168
5169#ifdef FEAT_GUI_DIALOG
5170/*
5171 * Stuff for dialogues
5172 */
5173
5174/*
5175 * Create a dialogue dynamically from the parameter strings.
5176 * type = type of dialogue (question, alert, etc.)
5177 * title = dialogue title. may be NULL for default title.
5178 * message = text to display. Dialogue sizes to accommodate it.
5179 * buttons = '\n' separated list of button captions, default first.
5180 * dfltbutton = number of default button.
5181 *
5182 * This routine returns 1 if the first button is pressed,
5183 * 2 for the second, etc.
5184 *
5185 * 0 indicates Esc was pressed.
5186 * -1 for unexpected error
5187 *
5188 * If stubbing out this fn, return 1.
5189 */
5190
5191typedef struct
5192{
5193 short idx;
5194 short width; /* Size of the text in pixel */
5195 Rect box;
5196} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5197
5198#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5199
5200 static void
5201macMoveDialogItem(
5202 DialogRef theDialog,
5203 short itemNumber,
5204 short X,
5205 short Y,
5206 Rect *inBox)
5207{
5208#if 0 /* USE_CARBONIZED */
5209 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005210 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005212 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005213#else
5214 short itemType;
5215 Handle itemHandle;
5216 Rect localBox;
5217 Rect *itemBox = &localBox;
5218
5219 if (inBox != nil)
5220 itemBox = inBox;
5221
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005222 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5223 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5224 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225 /* To move a control (like a button) we need to call both
5226 * MoveControl and SetDialogItem. FAQ 6-18 */
5227 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005228 MoveControl((ControlRef) itemHandle, X, Y);
5229 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230#endif
5231}
5232
5233 static void
5234macSizeDialogItem(
5235 DialogRef theDialog,
5236 short itemNumber,
5237 short width,
5238 short height)
5239{
5240 short itemType;
5241 Handle itemHandle;
5242 Rect itemBox;
5243
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005244 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245
5246 /* When width or height is zero do not change it */
5247 if (width == 0)
5248 width = itemBox.right - itemBox.left;
5249 if (height == 0)
5250 height = itemBox.bottom - itemBox.top;
5251
5252#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005253 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254#else
5255 /* Resize the bounding box */
5256 itemBox.right = itemBox.left + width;
5257 itemBox.bottom = itemBox.top + height;
5258
5259 /* To resize a control (like a button) we need to call both
5260 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5261 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005262 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263
5264 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005265 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005266#endif
5267}
5268
5269 static void
5270macSetDialogItemText(
5271 DialogRef theDialog,
5272 short itemNumber,
5273 Str255 itemName)
5274{
5275 short itemType;
5276 Handle itemHandle;
5277 Rect itemBox;
5278
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005279 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005280
5281 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005282 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005284 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285}
5286
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005287/* TODO: There have been some crashes with dialogs, check your inbox
5288 * (Jussi)
5289 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290 int
5291gui_mch_dialog(
5292 int type,
5293 char_u *title,
5294 char_u *message,
5295 char_u *buttons,
5296 int dfltbutton,
5297 char_u *textfield)
5298{
5299 Handle buttonDITL;
5300 Handle iconDITL;
5301 Handle inputDITL;
5302 Handle messageDITL;
5303 Handle itemHandle;
5304 Handle iconHandle;
5305 DialogPtr theDialog;
5306 char_u len;
5307 char_u PascalTitle[256]; /* place holder for the title */
5308 char_u name[256];
5309 GrafPtr oldPort;
5310 short itemHit;
5311 char_u *buttonChar;
5312 Rect box;
5313 short button;
5314 short lastButton;
5315 short itemType;
5316 short useIcon;
5317 short width;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005318 short totalButtonWidth = 0; /* the width of all button together
5319 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320 short widestButton = 0;
5321 short dfltButtonEdge = 20; /* gut feeling */
5322 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5323 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5324 short maximumWidth = 400; /* gut feeling */
5325 short maxButtonWidth = 175; /* gut feeling */
5326
5327 short vertical;
5328 short dialogHeight;
5329 short messageLines = 3;
5330 FontInfo textFontInfo;
5331
5332 vgmDlgItm iconItm;
5333 vgmDlgItm messageItm;
5334 vgmDlgItm inputItm;
5335 vgmDlgItm buttonItm;
5336
5337 WindowRef theWindow;
5338
5339 /* Check 'v' flag in 'guioptions': vertical button placement. */
5340 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5341
5342 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005343 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344
5345 /* Get the WindowRef */
5346 theWindow = GetDialogWindow(theDialog);
5347
5348 /* Hide the window.
5349 * 1. to avoid seeing slow drawing
5350 * 2. to prevent a problem seen while moving dialog item
5351 * within a visible window. (non-Carbon MacOS 9)
5352 * Could be avoided by changing the resource.
5353 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005354 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005355
5356 /* Change the graphical port to the dialog,
5357 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005358 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005359 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005360
5361 /* Get the info about the default text,
5362 * used to calculate the height of the message
5363 * and of the text field */
5364 GetFontInfo(&textFontInfo);
5365
5366 /* Set the dialog title */
5367 if (title != NULL)
5368 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005369 (void) C2PascalString(title, &PascalTitle);
5370 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 }
5372
5373 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005374 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375 buttonChar = buttons;
5376 button = 0;
5377
5378 for (;*buttonChar != 0;)
5379 {
5380 /* Get the name of the button */
5381 button++;
5382 len = 0;
5383 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5384 {
5385 if (*buttonChar != DLG_HOTKEY_CHAR)
5386 name[++len] = *buttonChar;
5387 }
5388 if (*buttonChar != 0)
5389 buttonChar++;
5390 name[0] = len;
5391
5392 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005393 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394
5395 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005396 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397
5398 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005399 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 /* Limite the size of any button to an acceptable value. */
5401 /* TODO: Should be based on the message width */
5402 if (width > maxButtonWidth)
5403 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005404 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005405
5406 totalButtonWidth += width;
5407
5408 if (width > widestButton)
5409 widestButton = width;
5410 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005411 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005412 lastButton = button;
5413
5414 /* Add the icon to the Dialog Box. */
5415 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005416 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005417 switch (type)
5418 {
5419 case VIM_GENERIC: useIcon = kNoteIcon;
5420 case VIM_ERROR: useIcon = kStopIcon;
5421 case VIM_WARNING: useIcon = kCautionIcon;
5422 case VIM_INFO: useIcon = kNoteIcon;
5423 case VIM_QUESTION: useIcon = kNoteIcon;
5424 default: useIcon = kStopIcon;
5425 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005426 AppendDITL(theDialog, iconDITL, overlayDITL);
5427 ReleaseResource(iconDITL);
5428 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005429 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005430 iconHandle = GetIcon(useIcon);
5431 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005432
5433 /* Add the message to the Dialog box. */
5434 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005435 messageDITL = GetResource('DITL', 132);
5436 AppendDITL(theDialog, messageDITL, overlayDITL);
5437 ReleaseResource(messageDITL);
5438 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5439 (void) C2PascalString(message, &name);
5440 SetDialogItemText(itemHandle, name);
5441 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005442
5443 /* Add the input box if needed */
5444 if (textfield != NULL)
5445 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005446 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005447 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005448 inputDITL = GetResource('DITL', 132);
5449 AppendDITL(theDialog, inputDITL, overlayDITL);
5450 ReleaseResource(inputDITL);
5451 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5452/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5453 (void) C2PascalString(textfield, &name);
5454 SetDialogItemText(itemHandle, name);
5455 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456 }
5457
5458 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005459 SetDialogDefaultItem(theDialog, dfltbutton);
5460 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005461
5462 /* Reposition element */
5463
5464 /* Check if we need to force vertical */
5465 if (totalButtonWidth > maximumWidth)
5466 vertical = TRUE;
5467
5468 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005469 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470 iconItm.box.right = box.right;
5471 iconItm.box.bottom = box.bottom;
5472
5473 /* Place Message */
5474 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005475 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5476 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005477
5478 /* Place Input */
5479 if (textfield != NULL)
5480 {
5481 inputItm.box.left = messageItm.box.left;
5482 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005483 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5484 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005485 /* Convert the static text into a text edit.
5486 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005487 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5488 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5490 }
5491
5492 /* Place Button */
5493 if (textfield != NULL)
5494 {
5495 buttonItm.box.left = inputItm.box.left;
5496 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5497 }
5498 else
5499 {
5500 buttonItm.box.left = messageItm.box.left;
5501 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5502 }
5503
5504 for (button=1; button <= lastButton; button++)
5505 {
5506
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005507 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005508 /* With vertical, it's better to have all button the same lenght */
5509 if (vertical)
5510 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005511 macSizeDialogItem(theDialog, button, widestButton, 0);
5512 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005513 }
5514 /* Calculate position of next button */
5515 if (vertical)
5516 buttonItm.box.top = box.bottom + dfltElementSpacing;
5517 else
5518 buttonItm.box.left = box.right + dfltElementSpacing;
5519 }
5520
5521 /* Resize the dialog box */
5522 dialogHeight = box.bottom + dfltElementSpacing;
5523 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5524
Bram Moolenaar071d4272004-06-13 20:20:40 +00005525 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005526 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005528
5529 /* Display it */
5530 ShowWindow(theWindow);
5531/* BringToFront(theWindow); */
5532 SelectWindow(theWindow);
5533
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005534/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005535#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005536 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005537 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005538#endif
5539
Bram Moolenaard68071d2006-05-02 22:08:30 +00005540#ifdef USE_CARBONKEYHANDLER
5541 /* Avoid that we use key events for the main window. */
5542 dialog_busy = TRUE;
5543#endif
5544
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545 /* Hang until one of the button is hit */
5546 do
5547 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005548 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005549 } while ((itemHit < 1) || (itemHit > lastButton));
5550
Bram Moolenaard68071d2006-05-02 22:08:30 +00005551#ifdef USE_CARBONKEYHANDLER
5552 dialog_busy = FALSE;
5553#endif
5554
Bram Moolenaar071d4272004-06-13 20:20:40 +00005555 /* Copy back the text entered by the user into the param */
5556 if (textfield != NULL)
5557 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005558 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5559 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005560#if IOSIZE < 256
5561 /* Truncate the name to IOSIZE if needed */
5562 if (name[0] > IOSIZE)
5563 name[0] = IOSIZE - 1;
5564#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005565 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005566 }
5567
5568 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005569 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570
5571 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005572 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573
5574 return itemHit;
5575/*
5576 * Usefull thing which could be used
5577 * SetDialogTimeout(): Auto click a button after timeout
5578 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5579 * MoveDialogItem(): Probably better than SetDialogItem
5580 * SizeDialogItem(): (but is it Carbon Only?)
5581 * AutoSizeDialog(): Magic resize of dialog based on text lenght
5582 */
5583}
5584#endif /* FEAT_DIALOG_GUI */
5585
5586/*
5587 * Display the saved error message(s).
5588 */
5589#ifdef USE_MCH_ERRMSG
5590 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005591display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005592{
5593 char *p;
5594 char_u pError[256];
5595
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005596 if (error_ga.ga_data == NULL)
5597 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005598
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005599 /* avoid putting up a message box with blanks only */
5600 for (p = (char *)error_ga.ga_data; *p; ++p)
5601 if (!isspace(*p))
5602 {
5603 if (STRLEN(p) > 255)
5604 pError[0] = 255;
5605 else
5606 pError[0] = STRLEN(p);
5607
5608 STRNCPY(&pError[1], p, pError[0]);
5609 ParamText(pError, nil, nil, nil);
5610 Alert(128, nil);
5611 break;
5612 /* TODO: handled message longer than 256 chars
5613 * use auto-sizeable alert
5614 * or dialog with scrollbars (TextEdit zone)
5615 */
5616 }
5617 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005618}
5619#endif
5620
5621/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005622 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005624 void
5625gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626{
5627 Point where;
5628
5629 GetMouse(&where);
5630
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005631 *x = where.h;
5632 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633}
5634
5635 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005636gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637{
5638 /* TODO */
5639#if 0
5640 /* From FAQ 3-11 */
5641
5642 CursorDevicePtr myMouse;
5643 Point where;
5644
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005645 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5646 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 {
5648 /* New way */
5649
5650 /*
5651 * Get first devoice with one button.
5652 * This will probably be the standad mouse
5653 * startat head of cursor dev list
5654 *
5655 */
5656
5657 myMouse = nil;
5658
5659 do
5660 {
5661 /* Get the next cursor device */
5662 CursorDeviceNextDevice(&myMouse);
5663 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005664 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005666 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667 }
5668 else
5669 {
5670 /* Old way */
5671 where.h = x;
5672 where.v = y;
5673
5674 *(Point *)RawMouse = where;
5675 *(Point *)MTemp = where;
5676 *(Ptr) CrsrNew = 0xFFFF;
5677 }
5678#endif
5679}
5680
5681 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005682gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005683{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684/*
5685 * Clone PopUp to use menu
5686 * Create a object descriptor for the current selection
5687 * Call the procedure
5688 */
5689
5690 MenuHandle CntxMenu;
5691 Point where;
5692 OSStatus status;
5693 UInt32 CntxType;
5694 SInt16 CntxMenuID;
5695 UInt16 CntxMenuItem;
5696 Str255 HelpName = "";
5697 GrafPtr savePort;
5698
5699 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005700 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005702 GetMouse(&where);
5703 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704 CntxMenu = menu->submenu_handle;
5705
5706 /* TODO: Get the text selection from Vim */
5707
5708 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005709 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005710 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711
5712 if (status == noErr)
5713 {
5714 if (CntxType == kCMMenuItemSelected)
5715 {
5716 /* Handle the menu CntxMenuID, CntxMenuItem */
5717 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005718 /* But what about the current menu, is the menu changed by
5719 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005720 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721 }
5722 else if (CntxMenuID == kCMShowHelpSelected)
5723 {
5724 /* Should come up with the help */
5725 }
5726 }
5727
5728 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005729 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005730}
5731
5732#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5733/* TODO: Is it need for MACOS_X? (Dany) */
5734 void
5735mch_post_buffer_write(buf_T *buf)
5736{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005737 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5738 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739}
5740#endif
5741
5742#ifdef FEAT_TITLE
5743/*
5744 * Set the window title and icon.
5745 * (The icon is not taken care of).
5746 */
5747 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005748gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005749{
5750 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5751 * that 256. Even better get it to fit nicely in the titlebar.
5752 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005753#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005754 CFStringRef windowTitle;
5755 size_t windowTitleLen;
5756#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005757 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005758#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759
5760 if (title == NULL) /* nothing to do */
5761 return;
5762
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005763#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005764 windowTitleLen = STRLEN(title);
5765 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
5766
5767 if (windowTitle)
5768 {
5769 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5770 CFRelease(windowTitle);
5771 }
5772#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773 pascalTitle = C2Pascal_save(title);
5774 if (pascalTitle != NULL)
5775 {
5776 SetWTitle(gui.VimWindow, pascalTitle);
5777 vim_free(pascalTitle);
5778 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005779#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780}
5781#endif
5782
5783/*
5784 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5785 */
5786
5787 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005788C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005789{
5790 char_u *PascalPtr = (char_u *) PascalString;
5791 int len;
5792 int i;
5793
5794 PascalPtr[0] = 0;
5795 if (CString == NULL)
5796 return 0;
5797
5798 len = STRLEN(CString);
5799 if (len > 255)
5800 len = 255;
5801
5802 for (i = 0; i < len; i++)
5803 PascalPtr[i+1] = CString[i];
5804
5805 PascalPtr[0] = len;
5806
5807 return 0;
5808}
5809
5810 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005811GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005812{
5813 /* From FAQ 8-12 */
5814 Str255 filePascal;
5815 CInfoPBRec myCPB;
5816 OSErr err;
5817
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005818 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819
5820 myCPB.dirInfo.ioNamePtr = filePascal;
5821 myCPB.dirInfo.ioVRefNum = 0;
5822 myCPB.dirInfo.ioFDirIndex = 0;
5823 myCPB.dirInfo.ioDrDirID = 0;
5824
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005825 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826
5827 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005828 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829
5830 /* TODO: Use an error code mechanism */
5831 return 0;
5832}
5833
5834/*
5835 * Convert a FSSpec to a fuill path
5836 */
5837
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005838char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839{
5840 /*
5841 * TODO: Add protection for 256 char max.
5842 */
5843
5844 CInfoPBRec theCPB;
5845 char_u fname[256];
5846 char_u *filenamePtr = fname;
5847 OSErr error;
5848 int folder = 1;
5849#ifdef USE_UNIXFILENAME
5850 SInt16 dfltVol_vRefNum;
5851 SInt32 dfltVol_dirID;
5852 FSRef refFile;
5853 OSStatus status;
5854 UInt32 pathSize = 256;
5855 char_u pathname[256];
5856 char_u *path = pathname;
5857#else
5858 Str255 directoryName;
5859 char_u temporary[255];
5860 char_u *temporaryPtr = temporary;
5861#endif
5862
5863#ifdef USE_UNIXFILENAME
5864 /* Get the default volume */
5865 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005866 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005867
5868 if (error)
5869 return NULL;
5870#endif
5871
5872 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005873 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874
5875 /* Get the info about the file specified in FSSpec */
5876 theCPB.dirInfo.ioFDirIndex = 0;
5877 theCPB.dirInfo.ioNamePtr = file.name;
5878 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00005879 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880 theCPB.dirInfo.ioDrDirID = file.parID;
5881
5882 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5883 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005884 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885
5886 /* If we are called for a new file we expect fnfErr */
5887 if ((error) && (error != fnfErr))
5888 return NULL;
5889
5890 /* Check if it's a file or folder */
5891 /* default to file if file don't exist */
5892 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
5893 folder = 0; /* It's not a folder */
5894 else
5895 folder = 1;
5896
5897#ifdef USE_UNIXFILENAME
5898 /*
5899 * The function used here are available in Carbon, but
5900 * do nothing une MacOS 8 and 9
5901 */
5902 if (error == fnfErr)
5903 {
5904 /* If the file to be saved does not already exist, it isn't possible
5905 to convert its FSSpec into an FSRef. But we can construct an
5906 FSSpec for the file's parent folder (since we have its volume and
5907 directory IDs), and since that folder does exist, we can convert
5908 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5909 and, finally, append the filename. */
5910 FSSpec dirSpec;
5911 FSRef dirRef;
5912 Str255 emptyFilename = "\p";
5913 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
5914 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
5915 if (error)
5916 return NULL;
5917
5918 error = FSpMakeFSRef(&dirSpec, &dirRef);
5919 if (error)
5920 return NULL;
5921
5922 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
5923 if (status)
5924 return NULL;
5925
5926 STRCAT(path, "/");
5927 STRCAT(path, filenamePtr);
5928 }
5929 else
5930 {
5931 /* If the file to be saved already exists, we can get its full path
5932 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005933 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934 if (error)
5935 return NULL;
5936
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005937 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938 if (status)
5939 return NULL;
5940 }
5941
5942 /* Add a slash at the end if needed */
5943 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005944 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005945
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005946 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947#else
5948 /* TODO: Get rid of all USE_UNIXFILENAME below */
5949 /* Set ioNamePtr, it's the same area which is always reused. */
5950 theCPB.dirInfo.ioNamePtr = directoryName;
5951
5952 /* Trick for first entry, set ioDrParID to the first value
5953 * we want for ioDrDirID*/
5954 theCPB.dirInfo.ioDrParID = file.parID;
5955 theCPB.dirInfo.ioDrDirID = file.parID;
5956
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005957 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005958 do
5959 {
5960 theCPB.dirInfo.ioFDirIndex = -1;
5961 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5962 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005963 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5965
5966 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5967 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005968 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969
5970 if (error)
5971 return NULL;
5972
5973 /* Put the new directoryName in front of the current fname */
5974 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005975 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005976 STRCAT(filenamePtr, ":");
5977 STRCAT(filenamePtr, temporaryPtr);
5978 }
5979#if 1 /* def USE_UNIXFILENAME */
5980 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
5981 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5982#else
5983 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
5984#endif
5985
5986 /* Get the information about the volume on which the file reside */
5987 theCPB.dirInfo.ioFDirIndex = -1;
5988 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5989 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005990 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5992
5993 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5994 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005995 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005996
5997 if (error)
5998 return NULL;
5999
6000 /* For MacOS Classic always add the volume name */
6001 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006002 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003#ifdef USE_UNIXFILENAME
6004 if (file.vRefNum != dfltVol_vRefNum)
6005#endif
6006 {
6007 /* Add the volume name */
6008 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006009 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006010 STRCAT(filenamePtr, ":");
6011 STRCAT(filenamePtr, temporaryPtr);
6012
6013#ifdef USE_UNIXFILENAME
6014 STRCPY(temporaryPtr, filenamePtr);
6015 filenamePtr[0] = 0; /* NULL terminate the string */
6016 STRCAT(filenamePtr, "Volumes:");
6017 STRCAT(filenamePtr, temporaryPtr);
6018#endif
6019 }
6020
6021 /* Append final path separator if it's a folder */
6022 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006023 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024
6025 /* As we use Unix File Name for MacOS X convert it */
6026#ifdef USE_UNIXFILENAME
6027 /* Need to insert leading / */
6028 /* TODO: get the above code to use directly the / */
6029 STRCPY(&temporaryPtr[1], filenamePtr);
6030 temporaryPtr[0] = '/';
6031 STRCPY(filenamePtr, temporaryPtr);
6032 {
6033 char *p;
6034 for (p = fname; *p; p++)
6035 if (*p == ':')
6036 *p = '/';
6037 }
6038#endif
6039
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006040 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041#endif
6042}
6043
6044#if defined(USE_IM_CONTROL) || defined(PROTO)
6045/*
6046 * Input Method Control functions.
6047 */
6048
6049/*
6050 * Notify cursor position to IM.
6051 */
6052 void
6053im_set_position(int row, int col)
6054{
6055 /* TODO: Implement me! */
6056}
6057
6058/*
6059 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6060 */
6061 void
6062im_set_active(int active)
6063{
6064 KeyScript(active ? smKeySysScript : smKeyRoman);
6065}
6066
6067/*
6068 * Get IM status. When IM is on, return not 0. Else return 0.
6069 */
6070 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006071im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072{
6073 SInt32 script = GetScriptManagerVariable(smKeyScript);
6074 return (script != smRoman
6075 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6076}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006077
Bram Moolenaar071d4272004-06-13 20:20:40 +00006078#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006079
6080
6081
6082
6083#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6084// drawer implementation
6085static MenuRef contextMenu = NULL;
6086enum
6087{
6088 kTabContextMenuId = 42,
6089};
6090
6091// the caller has to CFRelease() the returned string
6092 static CFStringRef
6093getTabLabel(tabpage_T *page)
6094{
6095 get_tabline_label(page, FALSE);
6096#ifdef MACOS_CONVERT
6097 return mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6098#else
6099 // TODO: check internal encoding?
6100 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6101 kCFStringEncodingMacRoman);
6102#endif
6103}
6104
6105
6106#define DRAWER_SIZE 150
6107#define DRAWER_INSET 16
6108
6109static ControlRef dataBrowser = NULL;
6110
6111// when the tabline is hidden, vim doesn't call update_tabline(). When
6112// the tabline is shown again, show_tabline() is called before upate_tabline(),
6113// and because of this, the tab labels and vims internal tabs are out of sync
6114// for a very short time. to prevent inconsistent state, we store the labels
6115// of the tabs, not pointers to the tabs (which are invalid for a short time).
6116static CFStringRef *tabLabels = NULL;
6117static int tabLabelsSize = 0;
6118
6119enum
6120{
6121 kTabsColumn = 'Tabs'
6122};
6123
6124 static int
6125getTabCount(void)
6126{
6127 tabpage_T *tp;
6128 int numTabs = 0;
6129
6130 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6131 ++numTabs;
6132 return numTabs;
6133}
6134
6135// data browser item display callback
6136 static OSStatus
6137dbItemDataCallback(ControlRef browser,
6138 DataBrowserItemID itemID,
6139 DataBrowserPropertyID property /* column id */,
6140 DataBrowserItemDataRef itemData,
6141 Boolean changeValue)
6142{
6143 OSStatus status = noErr;
6144
6145 // assert(property == kTabsColumn); // why is this violated??
6146
6147 // changeValue is true if we have a modifieable list and data was changed.
6148 // In our case, it's always false.
6149 // (that is: if (changeValue) updateInternalData(); else return
6150 // internalData();
6151 if (!changeValue)
6152 {
6153 CFStringRef str;
6154
6155 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6156 str = tabLabels[itemID - 1];
6157 status = SetDataBrowserItemDataText(itemData, str);
6158 }
6159 else
6160 status = errDataBrowserPropertyNotSupported;
6161
6162 return status;
6163}
6164
6165// data browser action callback
6166 static void
6167dbItemNotificationCallback(ControlRef browser,
6168 DataBrowserItemID item,
6169 DataBrowserItemNotification message)
6170{
6171 switch (message)
6172 {
6173 case kDataBrowserItemSelected:
6174 send_tabline_event(item);
6175 break;
6176 }
6177}
6178
6179// callbacks needed for contextual menu:
6180 static void
6181dbGetContextualMenuCallback(ControlRef browser,
6182 MenuRef *menu,
6183 UInt32 *helpType,
6184 CFStringRef *helpItemString,
6185 AEDesc *selection)
6186{
6187 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6188 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6189 *helpItemString = NULL;
6190
6191 *menu = contextMenu;
6192}
6193
6194 static void
6195dbSelectContextualMenuCallback(ControlRef browser,
6196 MenuRef menu,
6197 UInt32 selectionType,
6198 SInt16 menuID,
6199 MenuItemIndex menuItem)
6200{
6201 if (selectionType == kCMMenuItemSelected)
6202 {
6203 MenuCommand command;
6204 GetMenuItemCommandID(menu, menuItem, &command);
6205
6206 // get tab that was selected when the context menu appeared
6207 // (there is always one tab selected). TODO: check if the context menu
6208 // isn't opened on an item but on empty space (has to be possible some
6209 // way, the finder does it too ;-) )
6210 Handle items = NewHandle(0);
6211 if (items != NULL)
6212 {
6213 int numItems;
6214
6215 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6216 kDataBrowserItemIsSelected, items);
6217 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6218 if (numItems > 0)
6219 {
6220 int idx;
6221 DataBrowserItemID *itemsPtr;
6222
6223 HLock(items);
6224 itemsPtr = (DataBrowserItemID *)*items;
6225 idx = itemsPtr[0];
6226 HUnlock(items);
6227 send_tabline_menu_event(idx, command);
6228 }
6229 DisposeHandle(items);
6230 }
6231 }
6232}
6233
6234// focus callback of the data browser to always leave focus in vim
6235 static OSStatus
6236dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6237{
6238 assert(GetEventClass(event) == kEventClassControl
6239 && GetEventKind(event) == kEventControlSetFocusPart);
6240
6241 return paramErr;
6242}
6243
6244
6245// drawer callback to resize data browser to drawer size
6246 static OSStatus
6247drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6248{
6249 switch (GetEventKind(event))
6250 {
6251 case kEventWindowBoundsChanged: // move or resize
6252 {
6253 UInt32 attribs;
6254 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6255 NULL, sizeof(attribs), NULL, &attribs);
6256 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6257 {
6258 Rect r;
6259 GetWindowBounds(drawer, kWindowContentRgn, &r);
6260 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6261 SetControlBounds(dataBrowser, &r);
6262 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6263 kTabsColumn, r.right);
6264 }
6265 }
6266 break;
6267 }
6268
6269 return eventNotHandledErr;
6270}
6271
6272// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6273// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6274// blue highlights in the list view on these systems, though. Oh well.)
6275
6276
6277#import <mach-o/dyld.h>
6278
6279enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6280
6281 static OSStatus
6282myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6283 OptionBits inAttributesToSet,
6284 OptionBits inAttributesToClear)
6285{
6286 long osVersion;
6287 char *symbolName;
6288 NSSymbol symbol = NULL;
6289 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6290 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6291
6292 Gestalt(gestaltSystemVersion, &osVersion);
6293 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6294 return noErr;
6295
6296 // C name mangling...
6297 symbolName = "_DataBrowserChangeAttributes";
6298 if (!NSIsSymbolNameDefined(symbolName)
6299 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6300 return noErr;
6301
6302 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6303 if (dataBrowserChangeAttributes == NULL)
6304 return noErr; // well...
6305 return dataBrowserChangeAttributes(inDataBrowser,
6306 inAttributesToSet, inAttributesToClear);
6307}
6308
6309 static void
6310initialise_tabline(void)
6311{
6312 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6313 DataBrowserCallbacks dbCallbacks;
6314 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6315 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6316 DataBrowserListViewColumnDesc colDesc;
6317
6318 // drawers have to have compositing enabled
6319 CreateNewWindow(kDrawerWindowClass,
6320 kWindowStandardHandlerAttribute
6321 | kWindowCompositingAttribute
6322 | kWindowResizableAttribute
6323 | kWindowLiveResizeAttribute,
6324 &drawerRect, &drawer);
6325
6326 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6327 SetDrawerParent(drawer, gui.VimWindow);
6328 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6329
6330
6331 // create list view embedded in drawer
6332 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6333 &dataBrowser);
6334
6335 dbCallbacks.version = kDataBrowserLatestCallbacks;
6336 InitDataBrowserCallbacks(&dbCallbacks);
6337 dbCallbacks.u.v1.itemDataCallback =
6338 NewDataBrowserItemDataUPP(dbItemDataCallback);
6339 dbCallbacks.u.v1.itemNotificationCallback =
6340 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6341 dbCallbacks.u.v1.getContextualMenuCallback =
6342 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6343 dbCallbacks.u.v1.selectContextualMenuCallback =
6344 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6345
6346 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6347
6348 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6349 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6350 SetDataBrowserSelectionFlags(dataBrowser,
6351 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6352 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6353 kDataBrowserTableViewFillHilite);
6354 Boolean b = false;
6355 SetControlData(dataBrowser, kControlEntireControl,
6356 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6357
6358 // enable blue background in data browser (this is only in 10.4 and vim
6359 // has to support older osx versions as well, so we have to load this
6360 // function dynamically)
6361 myDataBrowserChangeAttributes(dataBrowser,
6362 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6363
6364 // install callback that keeps focus in vim and away from the data browser
6365 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6366 NULL, NULL);
6367
6368 // install callback that keeps data browser at the size of the drawer
6369 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6370 NULL, NULL);
6371
6372 // add "tabs" column to data browser
6373 colDesc.propertyDesc.propertyID = kTabsColumn;
6374 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6375
6376 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6377 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6378
6379 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6380 colDesc.headerBtnDesc.minimumWidth = 100;
6381 colDesc.headerBtnDesc.maximumWidth = 150;
6382 colDesc.headerBtnDesc.titleOffset = 0;
6383 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6384 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6385 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6386 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6387
6388 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6389
6390 // create tabline popup menu required by vim docs (see :he tabline-menu)
6391 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6392 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6393 TABLINE_MENU_CLOSE, NULL);
6394 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6395 TABLINE_MENU_NEW, NULL);
6396 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6397 TABLINE_MENU_OPEN, NULL);
6398}
6399
6400
6401/*
6402 * Show or hide the tabline.
6403 */
6404 void
6405gui_mch_show_tabline(int showit)
6406{
6407 if (showit == 0)
6408 CloseDrawer(drawer, true);
6409 else
6410 OpenDrawer(drawer, kWindowEdgeRight, true);
6411}
6412
6413/*
6414 * Return TRUE when tabline is displayed.
6415 */
6416 int
6417gui_mch_showing_tabline(void)
6418{
6419 WindowDrawerState state = GetDrawerState(drawer);
6420
6421 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6422}
6423
6424/*
6425 * Update the labels of the tabline.
6426 */
6427 void
6428gui_mch_update_tabline(void)
6429{
6430 tabpage_T *tp;
6431 int numTabs = getTabCount();
6432 int nr = 1;
6433 int curtabidx = 1;
6434
6435 // adjust data browser
6436 if (tabLabels != NULL)
6437 {
6438 int i;
6439
6440 for (i = 0; i < tabLabelsSize; ++i)
6441 CFRelease(tabLabels[i]);
6442 free(tabLabels);
6443 }
6444 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6445 tabLabelsSize = numTabs;
6446
6447 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6448 {
6449 if (tp == curtab)
6450 curtabidx = nr;
6451 tabLabels[nr-1] = getTabLabel(tp);
6452 }
6453
6454 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6455 kDataBrowserItemNoProperty);
6456 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6457 // can pass NULL for the id array
6458 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6459 kDataBrowserItemNoProperty);
6460
6461 DataBrowserItemID item = curtabidx;
6462 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6463}
6464
6465/*
6466 * Set the current tab to "nr". First tab is 1.
6467 */
6468 void
6469gui_mch_set_curtab(nr)
6470 int nr;
6471{
6472 DataBrowserItemID item = nr;
6473 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6474
6475 // TODO: call something like this?: (or restore scroll position, or...)
6476 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6477 kDataBrowserRevealOnly);
6478}
6479
6480#endif // FEAT_GUI_TABLINE