blob: 2d3da309490c353cb4a2b2777a51e8c7f3e52eb0 [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
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001679 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1680 {
1681 vimMouseButton = MOUSE_RIGHT;
1682 vimModifiers &= ~MOUSE_CTRL;
1683 clickIsPopup = TRUE;
1684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685
1686 /* Is it a double click ? */
1687 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1688
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001689 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 gui_send_mouse_event(vimMouseButton, thePoint.h,
1691 thePoint.v, dblClick, vimModifiers);
1692
1693 /* Create the rectangle around the cursor to detect
1694 * the mouse dragging
1695 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696#if 0
1697 /* TODO: Do we need to this even for the contextual menu?
1698 * It may be require for popup_setpos, but for popup?
1699 */
1700 if (vimMouseButton == MOUSE_LEFT)
1701#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001703 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704 FILL_Y(Y_2_ROW(thePoint.v)),
1705 FILL_X(X_2_COL(thePoint.h)+1),
1706 FILL_Y(Y_2_ROW(thePoint.v)+1));
1707
1708 dragRectEnbl = TRUE;
1709 dragRectControl = kCreateRect;
1710 }
1711 }
1712}
1713
1714/*
1715 * Handle the click in the titlebar (to move the window)
1716 */
1717 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001718gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719{
1720 Rect movingLimits;
1721 Rect *movingLimitsPtr = &movingLimits;
1722
1723 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001724 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001725 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726}
1727
1728/*
1729 * Handle the click in the grow box
1730 */
1731 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001732gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733{
1734
1735 long newSize;
1736 unsigned short newWidth;
1737 unsigned short newHeight;
1738 Rect resizeLimits;
1739 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 Rect NewContentRect;
1741
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001742 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743
Bram Moolenaar720c7102007-05-10 18:07:50 +00001744 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 /* TODO: Should this come from Vim? */
1746 resizeLimits.top = 100;
1747 resizeLimits.left = 100;
1748
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1750 newWidth = NewContentRect.right - NewContentRect.left;
1751 newHeight = NewContentRect.bottom - NewContentRect.top;
1752 gui_resize_shell(newWidth, newHeight);
1753 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001754 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755}
1756
1757/*
1758 * Handle the click in the zoom box
1759 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001761gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762{
1763 Rect r;
1764 Point p;
1765 short thePart;
1766
1767 /* ideal width is current */
1768 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1769 if (gui.which_scrollbars[SBAR_LEFT])
1770 p.h += gui.scrollbar_width;
1771 if (gui.which_scrollbars[SBAR_RIGHT])
1772 p.h += gui.scrollbar_width;
1773 /* ideal height is as heigh as we can get */
1774 p.v = 15 * 1024;
1775
1776 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1777 ? inZoomIn : inZoomOut;
1778
1779 if (!TrackBox(whichWindow, theEvent->where, thePart))
1780 return;
1781
1782 /* use returned width */
1783 p.h = r.right - r.left;
1784 /* adjust returned height */
1785 p.v = r.bottom - r.top - 2 * gui.border_offset;
1786 if (gui.which_scrollbars[SBAR_BOTTOM])
1787 p.v -= gui.scrollbar_height;
1788 p.v -= p.v % gui.char_height;
1789 p.v += 2 * gui.border_width;
1790 if (gui.which_scrollbars[SBAR_BOTTOM]);
1791 p.v += gui.scrollbar_height;
1792
1793 ZoomWindowIdeal(whichWindow, thePart, &p);
1794
1795 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1796 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1797 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001798 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800
1801/*
1802 * ------------------------------------------------------------
1803 * MacOS Event Handling procedure
1804 * ------------------------------------------------------------
1805 */
1806
1807/*
1808 * Handle the Update Event
1809 */
1810
1811 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001812gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813{
1814 WindowPtr whichWindow;
1815 GrafPtr savePort;
1816 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 Rect *updateRectPtr;
1819 Rect rc;
1820 Rect growRect;
1821 RgnHandle saveRgn;
1822
1823
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 updateRgn = NewRgn();
1825 if (updateRgn == NULL)
1826 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827
1828 /* This could be done by the caller as we
1829 * don't require anything else out of the event
1830 */
1831 whichWindow = (WindowPtr) event->message;
1832
1833 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001834 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
1836 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001837 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838
1839 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001840 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841 /* Redraw the biggest rectangle covering the area
1842 * to be updated.
1843 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1845# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001846 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847 * seem to work under MacOS X (Dany)
1848 */
1849 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1850# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001851
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001853 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001854
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001855 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001856# if 0
1857 /* Code from original Carbon Port (using GetWindowRegion.
1858 * I believe the UpdateRgn is already in local (Dany)
1859 */
1860 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1861 GlobalToLocal(&botRight(updateRect));
1862# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 /* Update the content (i.e. the text) */
1864 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1865 updateRectPtr->right - updateRectPtr->left,
1866 updateRectPtr->bottom - updateRectPtr->top);
1867 /* Clear the border areas if needed */
1868 gui_mch_set_bg_color(gui.back_pixel);
1869 if (updateRectPtr->left < FILL_X(0))
1870 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001871 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1872 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 }
1874 if (updateRectPtr->top < FILL_Y(0))
1875 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001876 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1877 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 }
1879 if (updateRectPtr->right > FILL_X(Columns))
1880 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001881 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001883 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884 }
1885 if (updateRectPtr->bottom > FILL_Y(Rows))
1886 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001887 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001891 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001892 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893
1894 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001895 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896
1897 /* Update the GrowBox */
1898 /* Taken from FAQ 33-27 */
1899 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 GetClip(saveRgn);
1902 ClipRect(&growRect);
1903 DrawGrowIcon(whichWindow);
1904 SetClip(saveRgn);
1905 DisposeRgn(saveRgn);
1906 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907
1908 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001909 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910}
1911
1912/*
1913 * Handle the activate/deactivate event
1914 * (apply to a window)
1915 */
1916 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001917gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918{
1919 WindowPtr whichWindow;
1920
1921 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001922 /* Dim scrollbars */
1923 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 {
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001925 ControlRef rootControl;
1926 GetRootControl(gui.VimWindow, &rootControl);
1927 if ((event->modifiers) & activeFlag)
1928 ActivateControl(rootControl);
1929 else
1930 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001932
1933 /* Activate */
1934 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935}
1936
1937
1938/*
1939 * Handle the suspend/resume event
1940 * (apply to the application)
1941 */
1942 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001943gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944{
1945 /* The frontmost application just changed */
1946
1947 /* NOTE: the suspend may happen before the deactivate
1948 * seen on MacOS X
1949 */
1950
1951 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00001952 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953 */
1954 if (event->message & 1)
1955 /* Resume */
1956 gui_focus_change(TRUE);
1957 else
1958 /* Suspend */
1959 gui_focus_change(FALSE);
1960}
1961
1962/*
1963 * Handle the key
1964 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001965#ifdef USE_CARBONKEYHANDLER
Bram Moolenaard68071d2006-05-02 22:08:30 +00001966
1967static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the keys */
1968
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001969# define INLINE_KEY_BUFFER_SIZE 80
1970 static pascal OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001971gui_mac_doKeyEventCarbon(
1972 EventHandlerCallRef nextHandler,
1973 EventRef theEvent,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001974 void *data)
1975{
1976 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001977 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001978 UInt32 actualSize;
1979 UniChar *text;
1980 char_u result[INLINE_KEY_BUFFER_SIZE];
1981 short len = 0;
1982 UInt32 key_sym;
1983 char charcode;
1984 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001985 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001986 size_t encLen;
1987 char_u *to = NULL;
1988 Boolean isSpecial = FALSE;
1989 int i;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001990 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001992 /* Mask the mouse (as per user setting) */
1993 if (p_mh)
1994 ObscureCursor();
1995
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001996 /* Don't use the keys when the dialog wants them. */
1997 if (dialog_busy)
1998 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00001999
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002000 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2001 typeUnicodeText, NULL, 0, &actualSize, NULL))
2002 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002003
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002004 text = (UniChar *)alloc(actualSize);
2005 if (!text)
2006 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002007
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002008 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
2009 typeUnicodeText, NULL, actualSize, NULL, text);
2010 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002011
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002012 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
2013 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
2014 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002015
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002016 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
2017 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
2018 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002019
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002020 err = GetEventParameter(keyEvent, kEventParamKeyCode,
2021 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
2022 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002023
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002024 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
2025 typeChar, NULL, sizeof(char), NULL, &charcode);
2026 require_noerr(err, done);
2027
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002028#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002029 if (modifiers & cmdKey)
2030 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002031#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002032
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002033 key_char = charcode;
2034 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002035
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002036 /* Find the special key (eg., for cursor keys) */
2037 if (actualSize <= sizeof(UniChar) &&
2038 ((text[0] < 0x20) || (text[0] == 0x7f)))
2039 {
2040 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2041 if (special_keys[i].key_sym == key_sym)
2042 {
2043 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2044 special_keys[i].vim_code1);
2045 key_char = simplify_key(key_char,
2046 (int *)&vimModifiers);
2047 isSpecial = TRUE;
2048 break;
2049 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002050 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002051
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002052 /* Intercept CMD-. and CTRL-c */
2053 if (((modifiers & controlKey) && key_char == 'c') ||
2054 ((modifiers & cmdKey) && key_char == '.'))
2055 got_int = TRUE;
2056
2057 if (!isSpecial)
2058 {
2059 /* remove SHIFT for keys that are already shifted, e.g.,
2060 * '(' and '*' */
2061 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2062 vimModifiers &= ~MOD_MASK_SHIFT;
2063
2064 /* remove CTRL from keys that already have it */
2065 if (key_char < 0x20)
2066 vimModifiers &= ~MOD_MASK_CTRL;
2067
2068 /* don't process unicode characters here */
2069 if (!IS_SPECIAL(key_char))
2070 {
2071 /* Following code to simplify and consolidate vimModifiers
2072 * taken liberally from gui_w48.c */
2073 key_char = simplify_key(key_char, (int *)&vimModifiers);
2074
2075 /* Interpret META, include SHIFT, etc. */
2076 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2077 if (key_char == CSI)
2078 key_char = K_CSI;
2079
2080 if (IS_SPECIAL(key_char))
2081 isSpecial = TRUE;
2082 }
2083 }
2084
2085 if (vimModifiers)
2086 {
2087 result[len++] = CSI;
2088 result[len++] = KS_MODIFIER;
2089 result[len++] = vimModifiers;
2090 }
2091
2092 if (isSpecial && IS_SPECIAL(key_char))
2093 {
2094 result[len++] = CSI;
2095 result[len++] = K_SECOND(key_char);
2096 result[len++] = K_THIRD(key_char);
2097 }
2098 else
2099 {
2100 encLen = actualSize;
2101 to = mac_utf16_to_enc(text, actualSize, &encLen);
2102 if (to)
2103 {
2104 /* This is basically add_to_input_buf_csi() */
2105 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2106 {
2107 result[len++] = to[i];
2108 if (to[i] == CSI)
2109 {
2110 result[len++] = KS_EXTRA;
2111 result[len++] = (int)KE_CSI;
2112 }
2113 }
2114 vim_free(to);
2115 }
2116 }
2117
2118 add_to_input_buf(result, len);
2119 err = noErr;
2120
2121done:
2122 vim_free(text);
2123 if (err == noErr)
2124 {
2125 /* Fake event to wake up WNE (required to get
2126 * key repeat working */
2127 PostEvent(keyUp, 0);
2128 return noErr;
2129 }
2130
2131 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002132}
2133#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134 void
2135gui_mac_doKeyEvent(EventRecord *theEvent)
2136{
2137 /* TODO: add support for COMMAND KEY */
2138 long menu;
2139 unsigned char string[20];
2140 short num, i;
2141 short len = 0;
2142 KeySym key_sym;
2143 int key_char;
2144 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002145 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146
2147 /* Mask the mouse (as per user setting) */
2148 if (p_mh)
2149 ObscureCursor();
2150
2151 /* Get the key code and it's ASCII representation */
2152 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2153 key_char = theEvent->message & charCodeMask;
2154 num = 1;
2155
2156 /* Intercept CTRL-C */
2157 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002158 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 if (key_char == Ctrl_C && ctrl_c_interrupts)
2160 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002161 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2162 && (key_char == '2' || key_char == '6'))
2163 {
2164 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2165 if (key_char == '2')
2166 key_char = Ctrl_AT;
2167 else
2168 key_char = Ctrl_HAT;
2169 theEvent->modifiers = 0;
2170 }
2171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172
2173 /* Intercept CMD-. */
2174 if (theEvent->modifiers & cmdKey)
2175 if (key_char == '.')
2176 got_int = TRUE;
2177
2178 /* Handle command key as per menu */
2179 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2180 if (theEvent->modifiers & cmdKey)
2181 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2182 * Why the mouse button? */
2183 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2184 {
2185 menu = MenuKey(key_char);
2186 if (HiWord(menu))
2187 {
2188 gui_mac_handle_menu(menu);
2189 return;
2190 }
2191 }
2192
2193 /* Convert the modifiers */
2194 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2195
2196
2197 /* Handle special keys. */
2198#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002199 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2201#endif
2202 {
2203 /* Find the special key (for non-printable keyt_char) */
2204 if ((key_char < 0x20) || (key_char == 0x7f))
2205 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2206 if (special_keys[i].key_sym == key_sym)
2207 {
2208# if 0
2209 /* We currently don't have not so special key */
2210 if (special_keys[i].vim_code1 == NUL)
2211 key_char = special_keys[i].vim_code0;
2212 else
2213# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002214 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2215 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002216 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 break;
2218 }
2219 }
2220
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002221 /* For some keys the modifier is included in the char itself. */
2222 if (simplify || key_char == TAB || key_char == ' ')
2223 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224
2225 /* Add the modifier to the input bu if needed */
2226 /* Do not want SHIFT-A or CTRL-A with modifier */
2227 if (!IS_SPECIAL(key_char)
2228 && key_sym != vk_Space
2229 && key_sym != vk_Tab
2230 && key_sym != vk_Return
2231 && key_sym != vk_Enter
2232 && key_sym != vk_Esc)
2233 {
2234#if 1
2235 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002236 if ((modifiers == MOD_MASK_SHIFT)
2237 || (modifiers == MOD_MASK_CTRL)
2238 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 modifiers = 0;
2240#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002241 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002243 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002245 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 modifiers = modifiers & ~MOD_MASK_SHIFT;
2247#endif
2248 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002249 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002250 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002251 string[len++] = CSI;
2252 string[len++] = KS_MODIFIER;
2253 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 }
2255
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002256 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002258 string[len++] = CSI;
2259 string[len++] = K_SECOND(key_char);
2260 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 }
2262 else
2263 {
2264#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002265 /* Convert characters when needed (e.g., from MacRoman to latin1).
2266 * This doesn't work for the NUL byte. */
2267 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 {
2269 char_u from[2], *to;
2270 int l;
2271
2272 from[0] = key_char;
2273 from[1] = NUL;
2274 l = 1;
2275 to = string_convert(&input_conv, from, &l);
2276 if (to != NULL)
2277 {
2278 for (i = 0; i < l && len < 19; i++)
2279 {
2280 if (to[i] == CSI)
2281 {
2282 string[len++] = KS_EXTRA;
2283 string[len++] = KE_CSI;
2284 }
2285 else
2286 string[len++] = to[i];
2287 }
2288 vim_free(to);
2289 }
2290 else
2291 string[len++] = key_char;
2292 }
2293 else
2294#endif
2295 string[len++] = key_char;
2296 }
2297
2298 if (len == 1 && string[0] == CSI)
2299 {
2300 /* Turn CSI into K_CSI. */
2301 string[ len++ ] = KS_EXTRA;
2302 string[ len++ ] = KE_CSI;
2303 }
2304
2305 add_to_input_buf(string, len);
2306}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002307#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308
2309/*
2310 * Handle MouseClick
2311 */
2312 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002313gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314{
2315 short thePart;
2316 WindowPtr whichWindow;
2317
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002318 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002320#ifdef FEAT_GUI_TABLINE
2321 /* prevent that the vim window size changes if it's activated by a
2322 click into the tab pane */
2323 if (whichWindow == drawer)
2324 return;
2325#endif
2326
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 switch (thePart)
2328 {
2329 case (inDesk):
2330 /* TODO: what to do? */
2331 break;
2332
2333 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002334 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 break;
2336
2337 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002338 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 break;
2340
2341 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002342 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343 break;
2344
2345 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002346 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347 break;
2348
2349 case (inGoAway):
2350 if (TrackGoAway(whichWindow, theEvent->where))
2351 gui_shell_closed();
2352 break;
2353
2354 case (inZoomIn):
2355 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 break;
2358 }
2359}
2360
2361/*
2362 * Handle MouseMoved
2363 * [this event is a moving in and out of a region]
2364 */
2365 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002366gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367{
2368 Point thePoint;
2369 int_u vimModifiers;
2370
2371 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2374
2375 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2380 thePoint.v, FALSE, vimModifiers);
2381
2382 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002383 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 FILL_Y(Y_2_ROW(thePoint.v)),
2385 FILL_X(X_2_COL(thePoint.h)+1),
2386 FILL_Y(Y_2_ROW(thePoint.v)+1));
2387
2388 if (dragRectEnbl)
2389 dragRectControl = kCreateRect;
2390
2391}
2392
2393/*
2394 * Handle the mouse release
2395 */
2396 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002397gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398{
2399 Point thePoint;
2400 int_u vimModifiers;
2401
2402 /* TODO: Properly convert the Contextual menu mouse-up */
2403 /* Potential source of the double menu */
2404 lastMouseTick = theEvent->when;
2405 dragRectEnbl = FALSE;
2406 dragRectControl = kCreateEmpty;
2407 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002408 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409
2410 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 if (clickIsPopup)
2412 {
2413 vimModifiers &= ~MOUSE_CTRL;
2414 clickIsPopup = FALSE;
2415 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002416 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417}
2418
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 static pascal OSStatus
2420gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2421 void *data)
2422{
2423 EventRef bogusEvent;
2424 Point point;
2425 Rect bounds;
2426 UInt32 mod;
2427 SInt32 delta;
2428 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002429 EventMouseWheelAxis axis;
2430
2431 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2432 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2433 && axis != kEventMouseWheelAxisY)
2434 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435
2436 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2437 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2438 goto bail;
2439 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2440 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2441 goto bail;
2442 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2443 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2444 goto bail;
2445
2446 vim_mod = 0;
2447 if (mod & shiftKey)
2448 vim_mod |= MOUSE_SHIFT;
2449 if (mod & controlKey)
2450 vim_mod |= MOUSE_CTRL;
2451 if (mod & optionKey)
2452 vim_mod |= MOUSE_ALT;
2453
2454 /* post a bogus event to wake up WaitNextEvent */
2455 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2456 kEventAttributeNone, &bogusEvent))
2457 goto bail;
2458 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2459 kEventPriorityLow))
2460 goto bail;
2461
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002462 ReleaseEvent(bogusEvent);
2463
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2465 {
2466 point.h -= bounds.left;
2467 point.v -= bounds.top;
2468 }
2469
2470 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2471 point.h, point.v, FALSE, vim_mod);
2472
2473 return noErr;
2474
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002475bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 /*
2477 * when we fail give any additional callback handler a chance to perform
2478 * it's actions
2479 */
2480 return CallNextEventHandler(nextHandler, theEvent);
2481}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482
2483#if 0
2484
2485/*
2486 * This would be the normal way of invoking the contextual menu
2487 * but the Vim API doesn't seem to a support a request to get
2488 * the menu that we should display
2489 */
2490 void
2491gui_mac_handle_contextual_menu(event)
2492 EventRecord *event;
2493{
2494/*
2495 * Clone PopUp to use menu
2496 * Create a object descriptor for the current selection
2497 * Call the procedure
2498 */
2499
2500// Call to Handle Popup
2501 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2502
2503 if (status != noErr)
2504 return;
2505
2506 if (CntxType == kCMMenuItemSelected)
2507 {
2508 /* Handle the menu CntxMenuID, CntxMenuItem */
2509 /* The submenu can be handle directly by gui_mac_handle_menu */
2510 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002511 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 }
2513 else if (CntxMenuID == kCMShowHelpSelected)
2514 {
2515 /* Should come up with the help */
2516 }
2517
2518}
2519#endif
2520
2521/*
2522 * Handle menubar selection
2523 */
2524 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002525gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526{
2527 short menu = HiWord(menuChoice);
2528 short item = LoWord(menuChoice);
2529 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530
2531 if (menu == 256) /* TODO: use constant or gui.xyz */
2532 {
2533 if (item == 1)
2534 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535 }
2536 else if (item != 0)
2537 {
2538 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2539
2540 if (theVimMenu)
2541 gui_menu_cb(theVimMenu);
2542 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002543 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544}
2545
2546/*
2547 * Dispatch the event to proper handler
2548 */
2549
2550 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002551gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552{
2553 OSErr error;
2554
2555 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002556 if (IsShowContextualMenuClick(event))
2557 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558# if 0
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002559 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560# else
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002561 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562# endif
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002563 return;
2564 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565
2566 /* Handle normal event */
2567 switch (event->what)
2568 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002569#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 case (keyDown):
2571 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002572 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002574#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002576 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 break;
2578
2579 case (mouseDown):
2580 gui_mac_doMouseDownEvent(event);
2581 break;
2582
2583 case (mouseUp):
2584 gui_mac_doMouseUpEvent(event);
2585 break;
2586
2587 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002588 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 break;
2590
2591 case (diskEvt):
2592 /* We don't need special handling for disk insertion */
2593 break;
2594
2595 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002596 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 break;
2598
2599 case (osEvt):
2600 switch ((event->message >> 24) & 0xFF)
2601 {
2602 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002603 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604 break;
2605 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002606 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 break;
2608 }
2609 break;
2610
2611#ifdef USE_AEVENT
2612 case (kHighLevelEvent):
2613 /* Someone's talking to us, through AppleEvents */
2614 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2615 break;
2616#endif
2617 }
2618}
2619
2620/*
2621 * ------------------------------------------------------------
2622 * Unknown Stuff
2623 * ------------------------------------------------------------
2624 */
2625
2626
2627 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002628gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002629{
2630 char_u c;
2631 char_u *p;
2632 char_u pFontName[256];
2633 Str255 systemFontname;
2634 short font_id;
2635 short size=9;
2636 GuiFont font;
2637#if 0
2638 char_u *fontNamePtr;
2639#endif
2640
2641 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2642 ;
2643
2644 c = *p;
2645 *p = 0;
2646
2647#if 1
2648 STRCPY(&pFontName[1], font_name);
2649 pFontName[0] = STRLEN(font_name);
2650 *p = c;
2651
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002652 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002653 char_u fontName[256];
2654 char_u *styleStart = vim_strchr(font_name, ':');
2655 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2656 vim_strncpy(fontName, font_name, fontNameLen);
2657
2658 ATSUFontID fontRef;
2659 FMFontStyle fontStyle;
2660 font_id = 0;
2661
2662 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2663 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2664 &fontRef) == noErr)
2665 {
2666 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2667 font_id = 0;
2668 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002669
2670 if (font_id == 0)
2671 {
2672 /*
2673 * Try again, this time replacing underscores in the font name
2674 * with spaces (:set guifont allows the two to be used
2675 * interchangeably; the Font Manager doesn't).
2676 */
2677 int i, changed = FALSE;
2678
2679 for (i = pFontName[0]; i > 0; --i)
2680 {
2681 if (pFontName[i] == '_')
2682 {
2683 pFontName[i] = ' ';
2684 changed = TRUE;
2685 }
2686 }
2687 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002688 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2689 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2690 kFontNoLanguageCode, &fontRef) == noErr)
2691 {
2692 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2693 font_id = 0;
2694 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002695 }
2696
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697#else
2698 /* name = C2Pascal_save(menu->dname); */
2699 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2700
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002701 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702#endif
2703
2704
2705 if (font_id == 0)
2706 {
2707 /* Oups, the system font was it the one the user want */
2708
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002709 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2710 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 if (!EqualString(pFontName, systemFontname, false, false))
2712 return NOFONT;
2713 }
2714 if (*p == ':')
2715 {
2716 p++;
2717 /* Set the values found after ':' */
2718 while (*p)
2719 {
2720 switch (*p++)
2721 {
2722 case 'h':
2723 size = points_to_pixels(p, &p, TRUE);
2724 break;
2725 /*
2726 * TODO: Maybe accept width and styles
2727 */
2728 }
2729 while (*p == ':')
2730 p++;
2731 }
2732 }
2733
2734 if (size < 1)
2735 size = 1; /* Avoid having a size of 0 with system font */
2736
2737 font = (size << 16) + ((long) font_id & 0xFFFF);
2738
2739 return font;
2740}
2741
2742/*
2743 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002744 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 * ------------------------------------------------------------
2746 */
2747
2748/*
2749 * Parse the GUI related command-line arguments. Any arguments used are
2750 * deleted from argv, and *argc is decremented accordingly. This is called
2751 * when vim is started, whether or not the GUI has been started.
2752 */
2753 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002754gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755{
2756 /* TODO: Move most of this stuff toward gui_mch_init */
2757#ifdef USE_EXE_NAME
2758 FSSpec applDir;
2759# ifndef USE_FIND_BUNDLE_PATH
2760 short applVRefNum;
2761 long applDirID;
2762 Str255 volName;
2763# else
2764 ProcessSerialNumber psn;
2765 FSRef applFSRef;
2766# endif
2767#endif
2768
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769#if 0
2770 InitCursor();
2771
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773
2774#ifdef USE_AEVENT
2775 (void) InstallAEHandlers();
2776#endif
2777
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002778 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002780 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002782 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783
2784 DrawMenuBar();
2785
2786
2787#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002788 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002790 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791#endif
2792
2793
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794 CreateNewWindow(kDocumentWindowClass,
2795 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002796 &windRect, &gui.VimWindow);
2797 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798
2799 gui.char_width = 7;
2800 gui.char_height = 11;
2801 gui.char_ascent = 6;
2802 gui.num_rows = 24;
2803 gui.num_cols = 80;
2804 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2805
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002806 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2807 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808
2809 dragRectEnbl = FALSE;
2810 dragRgn = NULL;
2811 dragRectControl = kCreateEmpty;
2812 cursorRgn = NewRgn();
2813#endif
2814#ifdef USE_EXE_NAME
2815# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002816 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002818 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819# else
2820 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2821 * of TN2015
2822 * This technic remove the ../Contents/MacOS/etc part
2823 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002824 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825 /* if (err != noErr) return err; */
2826
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002827 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 /* if (err != noErr) return err; */
2829
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002830 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831
2832 /* This technic return NIL when we disallow_gui */
2833# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002834 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836}
2837
2838#ifndef ALWAYS_USE_GUI
2839/*
2840 * Check if the GUI can be started. Called before gvimrc is sourced.
2841 * Return OK or FAIL.
2842 */
2843 int
2844gui_mch_init_check(void)
2845{
2846 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2847 * using the >console
2848 */
2849 if (disallow_gui) /* see main.c for reason to disallow */
2850 return FAIL;
2851 return OK;
2852}
2853#endif
2854
2855 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002856receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857{
2858 int x, y;
2859 int_u modifiers;
2860 char_u **fnames = NULL;
2861 int count;
2862 int i, j;
2863
2864 /* Get drop position, modifiers and count of items */
2865 {
2866 Point point;
2867 SInt16 mouseUpModifiers;
2868 UInt16 countItem;
2869
2870 GetDragMouse(theDrag, &point, NULL);
2871 GlobalToLocal(&point);
2872 x = point.h;
2873 y = point.v;
2874 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2875 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2876 CountDragItems(theDrag, &countItem);
2877 count = countItem;
2878 }
2879
2880 fnames = (char_u **)alloc(count * sizeof(char_u *));
2881 if (fnames == NULL)
2882 return dragNotAcceptedErr;
2883
2884 /* Get file names dropped */
2885 for (i = j = 0; i < count; ++i)
2886 {
2887 DragItemRef item;
2888 OSErr err;
2889 Size size;
2890 FlavorType type = flavorTypeHFS;
2891 HFSFlavor hfsFlavor;
2892
2893 fnames[i] = NULL;
2894 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2895 err = GetFlavorDataSize(theDrag, item, type, &size);
2896 if (err != noErr || size > sizeof(hfsFlavor))
2897 continue;
2898 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2899 if (err != noErr)
2900 continue;
2901 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
2902 }
2903 count = j;
2904
2905 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002906
2907 /* Fake mouse event to wake from stall */
2908 PostEvent(mouseUp, 0);
2909
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 return noErr;
2911}
2912
2913/*
2914 * Initialise the GUI. Create all the windows, set up all the call-backs
2915 * etc.
2916 */
2917 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002918gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919{
2920 /* TODO: Move most of this stuff toward gui_mch_init */
2921 Rect windRect;
2922 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 long gestalt_rc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 EventTypeSpec eventTypeSpec;
2925 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002926#ifdef USE_CARBONKEYHANDLER
2927 EventHandlerRef keyEventHandlerRef;
2928#endif
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002929 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002930
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002931 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002932 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002933
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934#if 1
2935 InitCursor();
2936
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938
2939#ifdef USE_AEVENT
2940 (void) InstallAEHandlers();
2941#endif
2942
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002943 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002945 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002947 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948
2949 DrawMenuBar();
2950
2951
2952#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002953 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002955 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956#endif
2957
2958 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002961 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
2963 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002964 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965
2966 gui.char_width = 7;
2967 gui.char_height = 11;
2968 gui.char_ascent = 6;
2969 gui.num_rows = 24;
2970 gui.num_cols = 80;
2971 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2972
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002973 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2974 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002976 /* Install Carbon event callbacks. */
2977 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978
2979 dragRectEnbl = FALSE;
2980 dragRgn = NULL;
2981 dragRectControl = kCreateEmpty;
2982 cursorRgn = NewRgn();
2983#endif
2984 /* Display any pending error messages */
2985 display_errors();
2986
2987 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00002988 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989 gui.norm_pixel = 0x00000000;
2990 gui.back_pixel = 0x00FFFFFF;
2991
2992 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
2993 * file). */
2994 set_normal_colors();
2995
2996 /*
2997 * Check that none of the colors are the same as the background color.
2998 * Then store the current values as the defaults.
2999 */
3000 gui_check_colors();
3001 gui.def_norm_pixel = gui.norm_pixel;
3002 gui.def_back_pixel = gui.back_pixel;
3003
3004 /* Get the colors for the highlight groups (gui_check_colors() might have
3005 * changed them) */
3006 highlight_gui_started();
3007
3008 /*
3009 * Setting the gui constants
3010 */
3011#ifdef FEAT_MENU
3012 gui.menu_height = 0;
3013#endif
3014 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3015 gui.border_offset = gui.border_width = 2;
3016
Bram Moolenaar720c7102007-05-10 18:07:50 +00003017 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 gui_mch_draw_string() below), enable it for all font sizes. */
3019 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 eventTypeSpec.eventClass = kEventClassMouse;
3022 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3023 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3024 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3025 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3026 {
3027 mouseWheelHandlerRef = NULL;
3028 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3029 mouseWheelHandlerUPP = NULL;
3030 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003032#ifdef USE_CARBONKEYHANDLER
3033 eventTypeSpec.eventClass = kEventClassTextInput;
3034 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3035 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3036 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3037 &eventTypeSpec, NULL, &keyEventHandlerRef))
3038 {
3039 keyEventHandlerRef = NULL;
3040 DisposeEventHandlerUPP(keyEventHandlerUPP);
3041 keyEventHandlerUPP = NULL;
3042 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043#endif
3044
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003045/*
3046#ifdef FEAT_MBYTE
3047 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3048#endif
3049*/
3050
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003051#ifdef FEAT_GUI_TABLINE
3052 /*
3053 * Create the tabline
3054 */
3055 initialise_tabline();
3056#endif
3057
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 /* TODO: Load bitmap if using TOOLBAR */
3059 return OK;
3060}
3061
3062/*
3063 * Called when the foreground or background color has been changed.
3064 */
3065 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003066gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067{
3068 /* TODO:
3069 * This proc is called when Normal is set to a value
3070 * so what msut be done? I don't know
3071 */
3072}
3073
3074/*
3075 * Open the GUI window which was created by a call to gui_mch_init().
3076 */
3077 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003078gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079{
3080 ShowWindow(gui.VimWindow);
3081
3082 if (gui_win_x != -1 && gui_win_y != -1)
3083 gui_mch_set_winpos(gui_win_x, gui_win_y);
3084
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 /*
3086 * Make the GUI the foreground process (in case it was launched
3087 * from the Terminal or via :gui).
3088 */
3089 {
3090 ProcessSerialNumber psn;
3091 if (GetCurrentProcess(&psn) == noErr)
3092 SetFrontProcess(&psn);
3093 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094
3095 return OK;
3096}
3097
3098 void
3099gui_mch_exit(int rc)
3100{
3101 /* TODO: find out all what is missing here? */
3102 DisposeRgn(cursorRgn);
3103
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003104#ifdef USE_CARBONKEYHANDLER
3105 if (keyEventHandlerUPP)
3106 DisposeEventHandlerUPP(keyEventHandlerUPP);
3107#endif
3108
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109 if (mouseWheelHandlerUPP != NULL)
3110 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003112#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003113 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003114 ATSUDisposeStyle(gFontStyle);
3115#endif
3116
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117 /* Exit to shell? */
3118 exit(rc);
3119}
3120
3121/*
3122 * Get the position of the top left corner of the window.
3123 */
3124 int
3125gui_mch_get_winpos(int *x, int *y)
3126{
3127 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 Rect bounds;
3129 OSStatus status;
3130
3131 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003132 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133
3134 if (status != noErr)
3135 return FAIL;
3136 *x = bounds.left;
3137 *y = bounds.top;
3138 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139 return FAIL;
3140}
3141
3142/*
3143 * Set the position of the top left corner of the window to the given
3144 * coordinates.
3145 */
3146 void
3147gui_mch_set_winpos(int x, int y)
3148{
3149 /* TODO: Should make sure the window is move within range
3150 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3151 */
3152 MoveWindow(gui.VimWindow, x, y, TRUE);
3153}
3154
3155 void
3156gui_mch_set_shellsize(
3157 int width,
3158 int height,
3159 int min_width,
3160 int min_height,
3161 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003162 int base_height,
3163 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 CGrafPtr VimPort;
3166 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003167
3168 if (gui.which_scrollbars[SBAR_LEFT])
3169 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003170 VimPort = GetWindowPort(gui.VimWindow);
3171 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003173 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175 }
3176 else
3177 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003178 VimPort = GetWindowPort(gui.VimWindow);
3179 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003181 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 }
3183
3184 SizeWindow(gui.VimWindow, width, height, TRUE);
3185
3186 gui_resize_shell(width, height);
3187}
3188
3189/*
3190 * Get the screen dimensions.
3191 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3192 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003193 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194 */
3195 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003196gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197{
3198 GDHandle dominantDevice = GetMainDevice();
3199 Rect screenRect = (**dominantDevice).gdRect;
3200
3201 *screen_w = screenRect.right - 10;
3202 *screen_h = screenRect.bottom - 40;
3203}
3204
3205
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003206/*
3207 * Open the Font Panel and wait for the user to select a font and
3208 * close the panel. Then fill the buffer pointed to by font_name with
3209 * the name and size of the selected font and return the font's handle,
3210 * or NOFONT in case of an error.
3211 */
3212 static GuiFont
3213gui_mac_select_font(char_u *font_name)
3214{
3215 GuiFont selected_font = NOFONT;
3216 OSStatus status;
3217 FontSelectionQDStyle curr_font;
3218
3219 /* Initialize the Font Panel with the current font. */
3220 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3221 curr_font.size = (gui.norm_font >> 16);
3222 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3223 curr_font.instance.fontStyle = 0;
3224 curr_font.hasColor = false;
3225 curr_font.version = 0; /* version number of the style structure */
3226 status = SetFontInfoForSelection(kFontSelectionQDType,
3227 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3228
3229 gFontPanelInfo.family = curr_font.instance.fontFamily;
3230 gFontPanelInfo.style = curr_font.instance.fontStyle;
3231 gFontPanelInfo.size = curr_font.size;
3232
3233 /* Pop up the Font Panel. */
3234 status = FPShowHideFontPanel();
3235 if (status == noErr)
3236 {
3237 /*
3238 * The Font Panel is modeless. We really need it to be modal,
3239 * so we spin in an event loop until the panel is closed.
3240 */
3241 gFontPanelInfo.isPanelVisible = true;
3242 while (gFontPanelInfo.isPanelVisible)
3243 {
3244 EventRecord e;
3245 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3246 }
3247
3248 GetFontPanelSelection(font_name);
3249 selected_font = gui_mac_find_font(font_name);
3250 }
3251 return selected_font;
3252}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003253
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254
3255/*
3256 * Initialise vim to use the font with the given name. Return FAIL if the font
3257 * could not be loaded, OK otherwise.
3258 */
3259 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003260gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261{
3262 /* TODO: Add support for bold italic underline proportional etc... */
3263 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003264 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 FontInfo font_info;
3266 short font_id;
3267 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003268 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003270#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003271 if (p_macatsui && gFontStyle == NULL)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003272 {
3273 if (ATSUCreateStyle(&gFontStyle) != noErr)
3274 gFontStyle = NULL;
3275 }
3276#endif
3277
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278 if (font_name == NULL)
3279 {
3280 /* First try to get the suggested font */
3281 GetFNum(suggestedFont, &font_id);
3282
3283 if (font_id == 0)
3284 {
3285 /* Then pickup the standard application font */
3286 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003287 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003289 else
3290 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3292 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003293 else if (STRCMP(font_name, "*") == 0)
3294 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003295 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003296
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003297 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003298 if (font == NOFONT)
3299 return FAIL;
3300
3301 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003302 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003303 if (new_p_guifont != NULL)
3304 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003305 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003306 vim_free(p_guifont);
3307 p_guifont = new_p_guifont;
3308 /* Replace spaces in the font name with underscores. */
3309 for ( ; *new_p_guifont; ++new_p_guifont)
3310 {
3311 if (*new_p_guifont == ' ')
3312 *new_p_guifont = '_';
3313 }
3314 }
3315 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 else
3317 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003318 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003319 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320
3321 if (font == NOFONT)
3322 return FAIL;
3323 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003324
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 gui.norm_font = font;
3326
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003327 hl_set_font_name(used_font_name);
3328
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003329 TextSize(font >> 16);
3330 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003332 GetFontInfo(&font_info);
3333
3334 gui.char_ascent = font_info.ascent;
3335 gui.char_width = CharWidth('_');
3336 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3337
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003338#ifdef USE_ATSUI_DRAWING
3339 ATSUFontID fontID;
3340 Fixed fontSize;
3341 ATSStyleRenderingOptions fontOptions;
3342
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003343 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003344 {
3345 fontID = font & 0xFFFF;
3346 fontSize = Long2Fix(font >> 16);
3347
3348 /* No antialiasing by default (do not attempt to touch antialising
3349 * options on pre-Jaguar) */
3350 fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003351 (gMacSystemVersion >= 0x1020) ?
3352 kATSStyleNoAntiAliasing :
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003353 kATSStyleNoOptions;
3354
3355 ATSUAttributeTag attribTags[] =
3356 {
3357 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3358 kATSUMaxATSUITagValue+1
3359 };
3360 ByteCount attribSizes[] =
3361 {
3362 sizeof(ATSUFontID), sizeof(Fixed),
3363 sizeof(ATSStyleRenderingOptions), sizeof font
3364 };
3365 ATSUAttributeValuePtr attribValues[] =
3366 {
3367 &fontID, &fontSize, &fontOptions, &font
3368 };
3369
3370 /* Convert font id to ATSUFontID */
3371 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3372 {
3373 if (ATSUSetAttributes(gFontStyle,
3374 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3375 attribTags, attribSizes, attribValues) != noErr)
3376 {
3377 ATSUDisposeStyle(gFontStyle);
3378 gFontStyle = NULL;
3379 }
3380 }
3381 }
3382#endif
3383
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385}
3386
Bram Moolenaar02743632005-07-25 20:42:36 +00003387/*
3388 * Adjust gui.char_height (after 'linespace' was changed).
3389 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003391gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392{
3393 FontInfo font_info;
3394
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003395 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3397 gui.char_ascent = font_info.ascent + p_linespace / 2;
3398 return OK;
3399}
3400
3401/*
3402 * Get a font structure for highlighting.
3403 */
3404 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003405gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406{
3407 GuiFont font;
3408
3409 font = gui_mac_find_font(name);
3410
3411 if (font == NOFONT)
3412 {
3413 if (giveErrorIfMissing)
3414 EMSG2(_(e_font), name);
3415 return NOFONT;
3416 }
3417 /*
3418 * TODO : Accept only monospace
3419 */
3420
3421 return font;
3422}
3423
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003424#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003426 * Return the name of font "font" in allocated memory.
3427 * Don't know how to get the actual name, thus use the provided name.
3428 */
3429 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003430gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003431{
3432 if (name == NULL)
3433 return NULL;
3434 return vim_strsave(name);
3435}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003436#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003437
3438/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003439 * Set the current text font.
3440 */
3441 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003442gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003444#ifdef USE_ATSUI_DRAWING
3445 GuiFont currFont;
3446 ByteCount actualFontByteCount;
3447 ATSUFontID fontID;
3448 Fixed fontSize;
3449 ATSStyleRenderingOptions fontOptions;
3450
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003451 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003452 {
3453 /* Avoid setting same font again */
3454 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
3455 &currFont, &actualFontByteCount) == noErr &&
3456 actualFontByteCount == (sizeof font))
3457 {
3458 if (currFont == font)
3459 return;
3460 }
3461
3462 fontID = font & 0xFFFF;
3463 fontSize = Long2Fix(font >> 16);
3464 /* Respect p_antialias setting only for wide font.
3465 * The reason for doing this at the moment is a bit complicated,
3466 * but it's mainly because a) latin (non-wide) aliased fonts
3467 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3468 * b) wide multibyte input does not suffer from that problem. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003469 /*fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003470 (p_antialias && (font == gui.wide_font)) ?
3471 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003472 */
3473 /*fontOptions = kATSStyleAntiAliasing;*/
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003474
3475 ATSUAttributeTag attribTags[] =
3476 {
3477 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3478 kATSUMaxATSUITagValue+1
3479 };
3480 ByteCount attribSizes[] =
3481 {
3482 sizeof(ATSUFontID), sizeof(Fixed),
3483 sizeof(ATSStyleRenderingOptions), sizeof font
3484 };
3485 ATSUAttributeValuePtr attribValues[] =
3486 {
3487 &fontID, &fontSize, &fontOptions, &font
3488 };
3489
3490 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3491 {
3492 if (ATSUSetAttributes(gFontStyle,
3493 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3494 attribTags, attribSizes, attribValues) != noErr)
3495 {
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003496# ifndef NDEBUG
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003497 fprintf(stderr, "couldn't set font style\n");
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003498# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003499 ATSUDisposeStyle(gFontStyle);
3500 gFontStyle = NULL;
3501 }
3502 }
3503
3504 }
3505
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003506 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003507 {
3508 /* Setup automatic font substitution. The user's guifontwide
3509 * is tried first, then the system tries other fonts. */
3510/*
3511 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3512 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3513 ATSUCreateFontFallbacks(&gFontFallbacks);
3514 ATSUSetObjFontFallbacks(gFontFallbacks, );
3515*/
3516 if (gui.wide_font)
3517 {
3518 ATSUFontID fallbackFonts;
3519 gIsFontFallbackSet = TRUE;
3520
3521 if (FMGetFontFromFontFamilyInstance(
3522 (gui.wide_font & 0xFFFF),
3523 0,
3524 &fallbackFonts,
3525 NULL) == noErr)
3526 {
3527 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
3528 }
3529/*
3530 ATSUAttributeValuePtr fallbackValues[] = { };
3531*/
3532 }
3533 }
3534#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 TextSize(font >> 16);
3536 TextFont(font & 0xFFFF);
3537}
3538
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539/*
3540 * If a font is not going to be used, free its structure.
3541 */
3542 void
3543gui_mch_free_font(font)
3544 GuiFont font;
3545{
3546 /*
3547 * Free font when "font" is not 0.
3548 * Nothing to do in the current implementation, since
3549 * nothing is allocated for each font used.
3550 */
3551}
3552
3553 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003554hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555{
3556 if (isdigit(c))
3557 return c - '0';
3558 c = TOLOWER_ASC(c);
3559 if (c >= 'a' && c <= 'f')
3560 return c - 'a' + 10;
3561 return -1000;
3562}
3563
3564/*
3565 * Return the Pixel value (color) for the given color name. This routine was
3566 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3567 * Programmer's Guide.
3568 * Return INVALCOLOR when failed.
3569 */
3570 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003571gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572{
3573 /* TODO: Add support for the new named color of MacOS 8
3574 */
3575 RGBColor MacColor;
3576// guicolor_T color = 0;
3577
3578 typedef struct guicolor_tTable
3579 {
3580 char *name;
3581 guicolor_T color;
3582 } guicolor_tTable;
3583
3584 /*
3585 * The comment at the end of each line is the source
3586 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3587 */
3588 static guicolor_tTable table[] =
3589 {
3590 {"Black", RGB(0x00, 0x00, 0x00)},
3591 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3592 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3593 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3594 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3595 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3596 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003597 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3598 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3599 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3600 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3601 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3602 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3603 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3604 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3605 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3606 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3607 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3608 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3609 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3610 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3611 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3612 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003613 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3614 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615 {"white", RGB(0xFF, 0xFF, 0xFF)},
3616 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3617 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3618 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3619 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3620 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3621 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3622 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3623 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3624 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3625 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3626 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3627 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3628 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3629 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3630 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3631 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3632 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3633 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003634 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3636 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3637 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3638 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3639 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3640 };
3641
3642 int r, g, b;
3643 int i;
3644
3645 if (name[0] == '#' && strlen((char *) name) == 7)
3646 {
3647 /* Name is in "#rrggbb" format */
3648 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3649 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3650 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3651 if (r < 0 || g < 0 || b < 0)
3652 return INVALCOLOR;
3653 return RGB(r, g, b);
3654 }
3655 else
3656 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003657 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003659 LMGetHiliteRGB(&MacColor);
3660 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 }
3662 /* Check if the name is one of the colors we know */
3663 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3664 if (STRICMP(name, table[i].name) == 0)
3665 return table[i].color;
3666 }
3667
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 /*
3669 * Last attempt. Look in the file "$VIM/rgb.txt".
3670 */
3671 {
3672#define LINE_LEN 100
3673 FILE *fd;
3674 char line[LINE_LEN];
3675 char_u *fname;
3676
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 if (fname == NULL)
3679 return INVALCOLOR;
3680
3681 fd = fopen((char *)fname, "rt");
3682 vim_free(fname);
3683 if (fd == NULL)
3684 return INVALCOLOR;
3685
3686 while (!feof(fd))
3687 {
3688 int len;
3689 int pos;
3690 char *color;
3691
3692 fgets(line, LINE_LEN, fd);
3693 len = strlen(line);
3694
3695 if (len <= 1 || line[len-1] != '\n')
3696 continue;
3697
3698 line[len-1] = '\0';
3699
3700 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3701 if (i != 3)
3702 continue;
3703
3704 color = line + pos;
3705
3706 if (STRICMP(color, name) == 0)
3707 {
3708 fclose(fd);
3709 return (guicolor_T) RGB(r, g, b);
3710 }
3711 }
3712 fclose(fd);
3713 }
3714
3715 return INVALCOLOR;
3716}
3717
3718/*
3719 * Set the current text foreground color.
3720 */
3721 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003722gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723{
3724 RGBColor TheColor;
3725
3726 TheColor.red = Red(color) * 0x0101;
3727 TheColor.green = Green(color) * 0x0101;
3728 TheColor.blue = Blue(color) * 0x0101;
3729
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003730 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731}
3732
3733/*
3734 * Set the current text background color.
3735 */
3736 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003737gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738{
3739 RGBColor TheColor;
3740
3741 TheColor.red = Red(color) * 0x0101;
3742 TheColor.green = Green(color) * 0x0101;
3743 TheColor.blue = Blue(color) * 0x0101;
3744
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003745 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746}
3747
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003748RGBColor specialColor;
3749
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003750/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003751 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003752 */
3753 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003754gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003755{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003756 specialColor.red = Red(color) * 0x0101;
3757 specialColor.green = Green(color) * 0x0101;
3758 specialColor.blue = Blue(color) * 0x0101;
3759}
3760
3761/*
3762 * Draw undercurl at the bottom of the character cell.
3763 */
3764 static void
3765draw_undercurl(int flags, int row, int col, int cells)
3766{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003767 int x;
3768 int offset;
3769 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3770 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003771
3772 RGBForeColor(&specialColor);
3773
3774 offset = val[FILL_X(col) % 8];
3775 MoveTo(FILL_X(col), y - offset);
3776
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003777 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003778 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003779 offset = val[x % 8];
3780 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003781 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003782}
3783
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003784
3785 static void
3786draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003787{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788#ifdef FEAT_MBYTE
3789 char_u *tofree = NULL;
3790
3791 if (output_conv.vc_type != CONV_NONE)
3792 {
3793 tofree = string_convert(&output_conv, s, &len);
3794 if (tofree != NULL)
3795 s = tofree;
3796 }
3797#endif
3798
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799 /*
3800 * On OS X, try using Quartz-style text antialiasing.
3801 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003802 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803 {
3804 /* Quartz antialiasing is available only in OS 10.2 and later. */
3805 UInt32 qd_flags = (p_antialias ?
3806 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003807 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 }
3809
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003810 /*
3811 * When antialiasing we're using srcOr mode, we have to clear the block
3812 * before drawing the text.
3813 * Also needed when 'linespace' is non-zero to remove the cursor and
3814 * underlining.
3815 * But not when drawing transparently.
3816 * The following is like calling gui_mch_clear_block(row, col, row, col +
3817 * len - 1), but without setting the bg color to gui.back_pixel.
3818 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003819 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003820 && !(flags & DRAW_TRANSP))
3821 {
3822 Rect rc;
3823
3824 rc.left = FILL_X(col);
3825 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003826#ifdef FEAT_MBYTE
3827 /* Multibyte computation taken from gui_w32.c */
3828 if (has_mbyte)
3829 {
3830 int cell_len = 0;
3831 int n;
3832
3833 /* Compute the length in display cells. */
3834 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3835 cell_len += (*mb_ptr2cells)(s + n);
3836 rc.right = FILL_X(col + cell_len);
3837 }
3838 else
3839#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003840 rc.right = FILL_X(col + len) + (col + len == Columns);
3841 rc.bottom = FILL_Y(row + 1);
3842 EraseRect(&rc);
3843 }
3844
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003845 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846 {
3847 StyleParameter face;
3848
3849 face = normal;
3850 if (flags & DRAW_BOLD)
3851 face |= bold;
3852 if (flags & DRAW_UNDERL)
3853 face |= underline;
3854 TextFace(face);
3855
3856 /* Quartz antialiasing works only in srcOr transfer mode. */
3857 TextMode(srcOr);
3858
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 MoveTo(TEXT_X(col), TEXT_Y(row));
3860 DrawText((char*)s, 0, len);
3861 }
3862 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003863 {
3864 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003865 TextMode(srcCopy);
3866 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867
3868 /* SelectFont(hdc, gui.currFont); */
3869
3870 if (flags & DRAW_TRANSP)
3871 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003872 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 }
3874
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003875 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003876 DrawText((char *)s, 0, len);
3877
3878 if (flags & DRAW_BOLD)
3879 {
3880 TextMode(srcOr);
3881 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3882 DrawText((char *)s, 0, len);
3883 }
3884
3885 if (flags & DRAW_UNDERL)
3886 {
3887 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3888 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3889 }
3890 }
3891
3892 if (flags & DRAW_UNDERC)
3893 draw_undercurl(flags, row, col, len);
3894
3895#ifdef FEAT_MBYTE
3896 vim_free(tofree);
3897#endif
3898}
3899
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003900#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003901
3902 static void
3903draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3904{
3905 /* ATSUI requires utf-16 strings */
3906 UniCharCount utf16_len;
3907 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3908 utf16_len /= sizeof(UniChar);
3909
3910 /* - ATSUI automatically antialiases text (Someone)
3911 * - for some reason it does not work... (Jussi) */
3912
3913 /*
3914 * When antialiasing we're using srcOr mode, we have to clear the block
3915 * before drawing the text.
3916 * Also needed when 'linespace' is non-zero to remove the cursor and
3917 * underlining.
3918 * But not when drawing transparently.
3919 * The following is like calling gui_mch_clear_block(row, col, row, col +
3920 * len - 1), but without setting the bg color to gui.back_pixel.
3921 */
3922 if ((flags & DRAW_TRANSP) == 0)
3923 {
3924 Rect rc;
3925
3926 rc.left = FILL_X(col);
3927 rc.top = FILL_Y(row);
3928 /* Multibyte computation taken from gui_w32.c */
3929 if (has_mbyte)
3930 {
3931 int cell_len = 0;
3932 int n;
3933
3934 /* Compute the length in display cells. */
3935 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3936 cell_len += (*mb_ptr2cells)(s + n);
3937 rc.right = FILL_X(col + cell_len);
3938 }
3939 else
3940 rc.right = FILL_X(col + len) + (col + len == Columns);
3941
3942 rc.bottom = FILL_Y(row + 1);
3943 EraseRect(&rc);
3944 }
3945
3946 {
3947 /* Use old-style, non-antialiased QuickDraw text rendering. */
3948 TextMode(srcCopy);
3949 TextFace(normal);
3950
3951 /* SelectFont(hdc, gui.currFont); */
3952
3953 if (flags & DRAW_TRANSP)
3954 {
3955 TextMode(srcOr);
3956 }
3957
3958 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003959 ATSUTextLayout textLayout;
3960
3961 if (ATSUCreateTextLayoutWithTextPtr(tofree,
3962 kATSUFromTextBeginning, kATSUToTextEnd,
3963 utf16_len,
3964 (gFontStyle ? 1 : 0), &utf16_len,
3965 (gFontStyle ? &gFontStyle : NULL),
3966 &textLayout) == noErr)
3967 {
3968 ATSUSetTransientFontMatching(textLayout, TRUE);
3969
3970 ATSUDrawText(textLayout,
3971 kATSUFromTextBeginning, kATSUToTextEnd,
3972 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
3973
3974 ATSUDisposeTextLayout(textLayout);
3975 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 }
3977
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003978 if (flags & DRAW_UNDERC)
3979 draw_undercurl(flags, row, col, len);
3980
Bram Moolenaar071d4272004-06-13 20:20:40 +00003981 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003982}
3983#endif
3984
3985 void
3986gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
3987{
3988#if defined(USE_ATSUI_DRAWING)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003989 if (p_macatsui)
3990 draw_string_ATSUI(row, col, s, len, flags);
3991 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003993 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994}
3995
3996/*
3997 * Return OK if the key with the termcap name "name" is supported.
3998 */
3999 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004000gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001{
4002 int i;
4003
4004 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4005 if (name[0] == special_keys[i].vim_code0 &&
4006 name[1] == special_keys[i].vim_code1)
4007 return OK;
4008 return FAIL;
4009}
4010
4011 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004012gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004014 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015}
4016
4017 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004018gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019{
4020 /* Do a visual beep by reversing the foreground and background colors */
4021 Rect rc;
4022
4023 /*
4024 * Note: InvertRect() excludes right and bottom of rectangle.
4025 */
4026 rc.left = 0;
4027 rc.top = 0;
4028 rc.right = gui.num_cols * gui.char_width;
4029 rc.bottom = gui.num_rows * gui.char_height;
4030 InvertRect(&rc);
4031
4032 ui_delay((long)msec, TRUE); /* wait for some msec */
4033
4034 InvertRect(&rc);
4035}
4036
4037/*
4038 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4039 */
4040 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004041gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042{
4043 Rect rc;
4044
4045 /*
4046 * Note: InvertRect() excludes right and bottom of rectangle.
4047 */
4048 rc.left = FILL_X(c);
4049 rc.top = FILL_Y(r);
4050 rc.right = rc.left + nc * gui.char_width;
4051 rc.bottom = rc.top + nr * gui.char_height;
4052 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053}
4054
4055/*
4056 * Iconify the GUI window.
4057 */
4058 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004059gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060{
4061 /* TODO: find out what could replace iconify
4062 * -window shade?
4063 * -hide application?
4064 */
4065}
4066
4067#if defined(FEAT_EVAL) || defined(PROTO)
4068/*
4069 * Bring the Vim window to the foreground.
4070 */
4071 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004072gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073{
4074 /* TODO */
4075}
4076#endif
4077
4078/*
4079 * Draw a cursor without focus.
4080 */
4081 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004082gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083{
4084 Rect rc;
4085
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086 /*
4087 * Note: FrameRect() excludes right and bottom of rectangle.
4088 */
4089 rc.left = FILL_X(gui.col);
4090 rc.top = FILL_Y(gui.row);
4091 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004092#ifdef FEAT_MBYTE
4093 if (mb_lefthalve(gui.row, gui.col))
4094 rc.right += gui.char_width;
4095#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 rc.bottom = rc.top + gui.char_height;
4097
4098 gui_mch_set_fg_color(color);
4099
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004100 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101}
4102
4103/*
4104 * Draw part of a cursor, only w pixels wide, and h pixels high.
4105 */
4106 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004107gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108{
4109 Rect rc;
4110
4111#ifdef FEAT_RIGHTLEFT
4112 /* vertical line should be on the right of current point */
4113 if (CURSOR_BAR_RIGHT)
4114 rc.left = FILL_X(gui.col + 1) - w;
4115 else
4116#endif
4117 rc.left = FILL_X(gui.col);
4118 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4119 rc.right = rc.left + w;
4120 rc.bottom = rc.top + h;
4121
4122 gui_mch_set_fg_color(color);
4123
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004124 FrameRect(&rc);
4125// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126}
4127
4128
4129
4130/*
4131 * Catch up with any queued X events. This may put keyboard input into the
4132 * input buffer, call resize call-backs, trigger timers etc. If there is
4133 * nothing in the X event queue (& no timers pending), then we return
4134 * immediately.
4135 */
4136 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004137gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138{
4139 /* TODO: find what to do
4140 * maybe call gui_mch_wait_for_chars (0)
4141 * more like look at EventQueue then
4142 * call heart of gui_mch_wait_for_chars;
4143 *
4144 * if (eventther)
4145 * gui_mac_handle_event(&event);
4146 */
4147 EventRecord theEvent;
4148
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004149 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 if (theEvent.what != nullEvent)
4151 gui_mch_wait_for_chars(0);
4152}
4153
4154/*
4155 * Simple wrapper to neglect more easily the time
4156 * spent inside WaitNextEvent while profiling.
4157 */
4158
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 pascal
4160 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004161WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162{
4163 if (((long) sleep) < -1)
4164 sleep = 32767;
4165 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4166}
4167
4168/*
4169 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4170 * from the keyboard.
4171 * wtime == -1 Wait forever.
4172 * wtime == 0 This should never happen.
4173 * wtime > 0 Wait wtime milliseconds for a character.
4174 * Returns OK if a character was found to be available within the given time,
4175 * or FAIL otherwise.
4176 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004178gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179{
4180 EventMask mask = (everyEvent);
4181 EventRecord event;
4182 long entryTick;
4183 long currentTick;
4184 long sleeppyTick;
4185
4186 /* If we are providing life feedback with the scrollbar,
4187 * we don't want to try to wait for an event, or else
4188 * there won't be any life feedback.
4189 */
4190 if (dragged_sb != NULL)
4191 return FAIL;
4192 /* TODO: Check if FAIL is the proper return code */
4193
4194 entryTick = TickCount();
4195
4196 allow_scrollbar = TRUE;
4197
4198 do
4199 {
4200/* if (dragRectControl == kCreateEmpty)
4201 {
4202 dragRgn = NULL;
4203 dragRectControl = kNothing;
4204 }
4205 else*/ if (dragRectControl == kCreateRect)
4206 {
4207 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004208 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209 dragRectControl = kNothing;
4210 }
4211 /*
4212 * Don't use gui_mch_update() because then we will spin-lock until a
4213 * char arrives, instead we use WaitNextEventWrp() to hang until an
4214 * event arrives. No need to check for input_buf_full because we are
4215 * returning as soon as it contains a single char.
4216 */
4217 /* TODO: reduce wtime accordinly??? */
4218 if (wtime > -1)
4219 sleeppyTick = 60*wtime/1000;
4220 else
4221 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004222 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004224 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 if (input_available())
4226 {
4227 allow_scrollbar = FALSE;
4228 return OK;
4229 }
4230 }
4231 currentTick = TickCount();
4232 }
4233 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4234
4235 allow_scrollbar = FALSE;
4236 return FAIL;
4237}
4238
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239/*
4240 * Output routines.
4241 */
4242
4243/* Flush any output to the screen */
4244 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004245gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246{
4247 /* TODO: Is anything needed here? */
4248}
4249
4250/*
4251 * Clear a rectangular region of the screen from text pos (row1, col1) to
4252 * (row2, col2) inclusive.
4253 */
4254 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004255gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256{
4257 Rect rc;
4258
4259 /*
4260 * Clear one extra pixel at the far right, for when bold characters have
4261 * spilled over to the next column.
4262 */
4263 rc.left = FILL_X(col1);
4264 rc.top = FILL_Y(row1);
4265 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4266 rc.bottom = FILL_Y(row2 + 1);
4267
4268 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004269 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270}
4271
4272/*
4273 * Clear the whole text window.
4274 */
4275 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004276gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277{
4278 Rect rc;
4279
4280 rc.left = 0;
4281 rc.top = 0;
4282 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4283 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4284
4285 gui_mch_set_bg_color(gui.back_pixel);
4286 EraseRect(&rc);
4287/* gui_mch_set_fg_color(gui.norm_pixel);
4288 FrameRect(&rc);
4289*/
4290}
4291
4292/*
4293 * Delete the given number of lines from the given row, scrolling up any
4294 * text further down within the scroll region.
4295 */
4296 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004297gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298{
4299 Rect rc;
4300
4301 /* changed without checking! */
4302 rc.left = FILL_X(gui.scroll_region_left);
4303 rc.right = FILL_X(gui.scroll_region_right + 1);
4304 rc.top = FILL_Y(row);
4305 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4306
4307 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004308 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309
4310 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4311 gui.scroll_region_left,
4312 gui.scroll_region_bot, gui.scroll_region_right);
4313}
4314
4315/*
4316 * Insert the given number of lines before the given row, scrolling down any
4317 * following text within the scroll region.
4318 */
4319 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004320gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321{
4322 Rect rc;
4323
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);
4330
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004331 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332
4333 /* Update gui.cursor_row if the cursor scrolled or copied over */
4334 if (gui.cursor_row >= gui.row
4335 && gui.cursor_col >= gui.scroll_region_left
4336 && gui.cursor_col <= gui.scroll_region_right)
4337 {
4338 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4339 gui.cursor_row += num_lines;
4340 else if (gui.cursor_row <= gui.scroll_region_bot)
4341 gui.cursor_is_valid = FALSE;
4342 }
4343
4344 gui_clear_block(row, gui.scroll_region_left,
4345 row + num_lines - 1, gui.scroll_region_right);
4346}
4347
4348 /*
4349 * TODO: add a vim format to the clipboard which remember
4350 * LINEWISE, CHARWISE, BLOCKWISE
4351 */
4352
4353 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004354clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355{
4356
4357 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004358 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 Size scrapSize;
4360 ScrapFlavorFlags scrapFlags;
4361 ScrapRef scrap = nil;
4362 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 int type;
4364 char *searchCR;
4365 char_u *tempclip;
4366
4367
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004368 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 if (error != noErr)
4370 return;
4371
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004372 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4373 if (error == noErr)
4374 {
4375 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4376 if (error == noErr && scrapSize > 1)
4377 flavor = 1;
4378 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004379
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004380 if (flavor == 0)
4381 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004382 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004383 if (error != noErr)
4384 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004386 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004387 if (error != noErr)
4388 return;
4389 }
4390
4391 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004393 /* In CARBON we don't need a Handle, a pointer is good */
4394 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004396 /* tempclip = lalloc(scrapSize+1, TRUE); */
4397 HLock(textOfClip);
4398 error = GetScrapFlavorData(scrap,
4399 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4400 &scrapSize, *textOfClip);
4401 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004403 if (flavor)
4404 type = **textOfClip;
4405 else
4406 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4407
4408 tempclip = lalloc(scrapSize + 1, TRUE);
4409 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4410 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004412#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004413 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004414 /* Convert from utf-16 (clipboard) */
4415 size_t encLen = 0;
4416 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004417
4418 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004420 scrapSize = encLen;
4421 vim_free(tempclip);
4422 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004424 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004426
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004427 searchCR = (char *)tempclip;
4428 while (searchCR != NULL)
4429 {
4430 searchCR = strchr(searchCR, '\r');
4431 if (searchCR != NULL)
4432 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004434
4435 clip_yank_selection(type, tempclip, scrapSize, cbd);
4436
4437 vim_free(tempclip);
4438 HUnlock(textOfClip);
4439
4440 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441}
4442
4443 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004444clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445{
4446 /*
4447 * TODO: Really nothing to do?
4448 */
4449}
4450
4451 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004452clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453{
4454 return OK;
4455}
4456
4457/*
4458 * Send the current selection to the clipboard.
4459 */
4460 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004461clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462{
4463 Handle textOfClip;
4464 long scrapSize;
4465 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467
4468 char_u *str = NULL;
4469
4470 if (!cbd->owned)
4471 return;
4472
4473 clip_get_selection(cbd);
4474
4475 /*
4476 * Once we set the clipboard, lose ownership. If another application sets
4477 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 cbd->owned = FALSE;
4480
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004481 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004483#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004484 size_t utf16_len = 0;
4485 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4486 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004487 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004488 scrapSize = utf16_len;
4489 vim_free(str);
4490 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 }
4492#endif
4493
4494 if (type >= 0)
4495 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004498 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 HLock(textOfClip);
4500
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004501 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004502 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004503 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004504 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004505 scrapSize, *textOfClip + 1);
4506 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4507 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 HUnlock(textOfClip);
4509 DisposeHandle(textOfClip);
4510 }
4511
4512 vim_free(str);
4513}
4514
4515 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004516gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517{
4518 Rect VimBound;
4519
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004520/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522
4523 if (gui.which_scrollbars[SBAR_LEFT])
4524 {
4525 VimBound.left = -gui.scrollbar_width + 1;
4526 }
4527 else
4528 {
4529 VimBound.left = 0;
4530 }
4531
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004534 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535}
4536
4537/*
4538 * Menu stuff.
4539 */
4540
4541 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004542gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543{
4544 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004545 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 */
4547}
4548
4549 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004550gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551{
4552 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004553 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 */
4555}
4556
4557/*
4558 * Add a sub menu to the menu bar.
4559 */
4560 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004561gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562{
4563 /*
4564 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4565 * TODO: use menu->mnemonic and menu->actext
4566 * TODO: Try to reuse menu id
4567 * Carbon Help suggest to use only id between 1 and 235
4568 */
4569 static long next_avail_id = 128;
4570 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004571#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004572 CFStringRef name;
4573#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004575#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004576 short index;
4577 vimmenu_T *parent = menu->parent;
4578 vimmenu_T *brother = menu->next;
4579
4580 /* Cannot add a menu if ... */
4581 if ((parent != NULL && parent->submenu_id == 0))
4582 return;
4583
4584 /* menu ID greater than 1024 are reserved for ??? */
4585 if (next_avail_id == 1024)
4586 return;
4587
4588 /* My brother could be the PopUp, find my real brother */
4589 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4590 brother = brother->next;
4591
4592 /* Find where to insert the menu (for MenuBar) */
4593 if ((parent == NULL) && (brother != NULL))
4594 menu_after_me = brother->submenu_id;
4595
4596 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4597 if (!menu_is_menubar(menu->name))
4598 menu_after_me = hierMenu;
4599
4600 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004601#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004602 name = menu_title_removing_mnemonic(menu);
4603#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004605#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 if (name == NULL)
4607 return;
4608
4609 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 {
4611 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004612 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4613 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 */
4615 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004616#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004617 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4618 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4619#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004620 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004621#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 next_avail_id++;
4623 }
4624
4625 if (parent == NULL)
4626 {
4627 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4628
4629 /* TODO: Verify if we could only Insert Menu if really part of the
4630 * menubar The Inserted menu are scanned or the Command-key combos
4631 */
4632
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004633 /* Insert the menu */
4634 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635#if 1
4636 /* Vim should normally update it. TODO: verify */
4637 DrawMenuBar();
4638#endif
4639 }
4640 else
4641 {
4642 /* Adding as a submenu */
4643
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004644 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645
4646 /* Call InsertMenuItem followed by SetMenuItemText
4647 * to avoid special character recognition by InsertMenuItem
4648 */
4649 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004650#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004651 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4652#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004654#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4656 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4657 InsertMenu(menu->submenu_handle, hierMenu);
4658 }
4659
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004660#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004661 CFRelease(name);
4662#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004663 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004664#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665
4666#if 0
4667 /* Done by Vim later on */
4668 DrawMenuBar();
4669#endif
4670}
4671
4672/*
4673 * Add a menu item to a menu
4674 */
4675 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004676gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004678#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004679 CFStringRef name;
4680#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004682#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683 vimmenu_T *parent = menu->parent;
4684 int menu_inserted;
4685
4686 /* Cannot add item, if the menu have not been created */
4687 if (parent->submenu_id == 0)
4688 return;
4689
4690 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4691 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4692
4693 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004694#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004695 name = menu_title_removing_mnemonic(menu);
4696#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004698#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699
4700 /* Where are just a menu item, so no handle, no id */
4701 menu->submenu_id = 0;
4702 menu->submenu_handle = NULL;
4703
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704 menu_inserted = 0;
4705 if (menu->actext)
4706 {
4707 /* If the accelerator text for the menu item looks like it describes
4708 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4709 * item's command equivalent.
4710 */
4711 int key = 0;
4712 int modifiers = 0;
4713 char_u *p_actext;
4714
4715 p_actext = menu->actext;
4716 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4717 if (*p_actext != 0)
4718 key = 0; /* error: trailing text */
4719 /* find_special_key() returns a keycode with as many of the
4720 * specified modifiers as appropriate already applied (e.g., for
4721 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4722 * as the only modifier). Since we want to display all of the
4723 * modifiers, we need to convert the keycode back to a printable
4724 * character plus modifiers.
4725 * TODO: Write an alternative find_special_key() that doesn't
4726 * apply modifiers.
4727 */
4728 if (key > 0 && key < 32)
4729 {
4730 /* Convert a control key to an uppercase letter. Note that
4731 * by this point it is no longer possible to distinguish
4732 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4733 */
4734 modifiers |= MOD_MASK_CTRL;
4735 key += '@';
4736 }
4737 /* If the keycode is an uppercase letter, set the Shift modifier.
4738 * If it is a lowercase letter, don't set the modifier, but convert
4739 * the letter to uppercase for display in the menu.
4740 */
4741 else if (key >= 'A' && key <= 'Z')
4742 modifiers |= MOD_MASK_SHIFT;
4743 else if (key >= 'a' && key <= 'z')
4744 key += 'A' - 'a';
4745 /* Note: keycodes below 0x22 are reserved by Apple. */
4746 if (key >= 0x22 && vim_isprintc_strict(key))
4747 {
4748 int valid = 1;
4749 char_u mac_mods = kMenuNoModifiers;
4750 /* Convert Vim modifier codes to Menu Manager equivalents. */
4751 if (modifiers & MOD_MASK_SHIFT)
4752 mac_mods |= kMenuShiftModifier;
4753 if (modifiers & MOD_MASK_CTRL)
4754 mac_mods |= kMenuControlModifier;
4755 if (!(modifiers & MOD_MASK_CMD))
4756 mac_mods |= kMenuNoCommandModifier;
4757 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4758 valid = 0; /* TODO: will Alt someday map to Option? */
4759 if (valid)
4760 {
4761 char_u item_txt[10];
4762 /* Insert the menu item after idx, with its command key. */
4763 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4764 item_txt[3] = key;
4765 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4766 /* Set the modifier keys. */
4767 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4768 menu_inserted = 1;
4769 }
4770 }
4771 }
4772 /* Call InsertMenuItem followed by SetMenuItemText
4773 * to avoid special character recognition by InsertMenuItem
4774 */
4775 if (!menu_inserted)
4776 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4777 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004778#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004779 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4780#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004782#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783
4784#if 0
4785 /* Called by Vim */
4786 DrawMenuBar();
4787#endif
4788
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004789#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004790 CFRelease(name);
4791#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 /* TODO: Can name be freed? */
4793 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004794#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795}
4796
4797 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004798gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799{
4800 /* no tearoff menus */
4801}
4802
4803/*
4804 * Destroy the machine specific menu widget.
4805 */
4806 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004807gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004809 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810
4811 if (index > 0)
4812 {
4813 if (menu->parent)
4814 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 {
4816 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004817 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818
4819 /* Delete the Menu if it was a hierarchical Menu */
4820 if (menu->submenu_id != 0)
4821 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004822 DeleteMenu(menu->submenu_id);
4823 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 }
4825 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 }
4827#ifdef DEBUG_MAC_MENU
4828 else
4829 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004830 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831 }
4832#endif
4833 }
4834 else
4835 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004837 DeleteMenu(menu->submenu_id);
4838 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 }
4840 }
4841 /* Shouldn't this be already done by Vim. TODO: Check */
4842 DrawMenuBar();
4843}
4844
4845/*
4846 * Make a menu either grey or not grey.
4847 */
4848 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004849gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004850{
4851 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004852 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853/*
4854 index = menu->index;
4855*/
4856 if (grey)
4857 {
4858 if (menu->children)
4859 DisableMenuItem(menu->submenu_handle, index);
4860 if (menu->parent)
4861 if (menu->parent->submenu_handle)
4862 DisableMenuItem(menu->parent->submenu_handle, index);
4863 }
4864 else
4865 {
4866 if (menu->children)
4867 EnableMenuItem(menu->submenu_handle, index);
4868 if (menu->parent)
4869 if (menu->parent->submenu_handle)
4870 EnableMenuItem(menu->parent->submenu_handle, index);
4871 }
4872}
4873
4874/*
4875 * Make menu item hidden or not hidden
4876 */
4877 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004878gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879{
4880 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004881 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882}
4883
4884
4885/*
4886 * This is called after setting all the menus to grey/hidden or not.
4887 */
4888 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004889gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890{
4891 DrawMenuBar();
4892}
4893
4894
4895/*
4896 * Scrollbar stuff.
4897 */
4898
4899 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004900gui_mch_enable_scrollbar(
4901 scrollbar_T *sb,
4902 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004903{
4904 if (flag)
4905 ShowControl(sb->id);
4906 else
4907 HideControl(sb->id);
4908
4909#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004910 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911#endif
4912}
4913
4914 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004915gui_mch_set_scrollbar_thumb(
4916 scrollbar_T *sb,
4917 long val,
4918 long size,
4919 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920{
4921 SetControl32BitMaximum (sb->id, max);
4922 SetControl32BitMinimum (sb->id, 0);
4923 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004924 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004926 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927#endif
4928}
4929
4930 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004931gui_mch_set_scrollbar_pos(
4932 scrollbar_T *sb,
4933 int x,
4934 int y,
4935 int w,
4936 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937{
4938 gui_mch_set_bg_color(gui.back_pixel);
4939/* if (gui.which_scrollbars[SBAR_LEFT])
4940 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004941 MoveControl(sb->id, x-16, y);
4942 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 }
4944 else
4945 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004946 MoveControl(sb->id, x, y);
4947 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004948 }*/
4949 if (sb == &gui.bottom_sbar)
4950 h += 1;
4951 else
4952 w += 1;
4953
4954 if (gui.which_scrollbars[SBAR_LEFT])
4955 x -= 15;
4956
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004957 MoveControl(sb->id, x, y);
4958 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004959#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004960 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004961#endif
4962}
4963
4964 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004965gui_mch_create_scrollbar(
4966 scrollbar_T *sb,
4967 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004968{
4969 Rect bounds;
4970
4971 bounds.top = -16;
4972 bounds.bottom = -10;
4973 bounds.right = -10;
4974 bounds.left = -16;
4975
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004976 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 &bounds,
4978 "\pScrollBar",
4979 TRUE,
4980 0, /* current*/
4981 0, /* top */
4982 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004983 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004984 (long) sb->ident);
4985#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004986 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004987#endif
4988}
4989
4990 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004991gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992{
4993 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004994 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004996 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997#endif
4998}
4999
5000
5001/*
5002 * Cursor blink functions.
5003 *
5004 * This is a simple state machine:
5005 * BLINK_NONE not blinking at all
5006 * BLINK_OFF blinking, cursor is not shown
5007 * BLINK_ON blinking, cursor is shown
5008 */
5009 void
5010gui_mch_set_blinking(long wait, long on, long off)
5011{
5012 /* TODO: TODO: TODO: TODO: */
5013/* blink_waittime = wait;
5014 blink_ontime = on;
5015 blink_offtime = off;*/
5016}
5017
5018/*
5019 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5020 */
5021 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005022gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023{
5024 gui_update_cursor(TRUE, FALSE);
5025 /* TODO: TODO: TODO: TODO: */
5026/* gui_w32_rm_blink_timer();
5027 if (blink_state == BLINK_OFF)
5028 gui_update_cursor(TRUE, FALSE);
5029 blink_state = BLINK_NONE;*/
5030}
5031
5032/*
5033 * Start the cursor blinking. If it was already blinking, this restarts the
5034 * waiting time and shows the cursor.
5035 */
5036 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005037gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038{
5039 gui_update_cursor(TRUE, FALSE);
5040 /* TODO: TODO: TODO: TODO: */
5041/* gui_w32_rm_blink_timer(); */
5042
5043 /* Only switch blinking on if none of the times is zero */
5044/* if (blink_waittime && blink_ontime && blink_offtime)
5045 {
5046 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5047 (TIMERPROC)_OnBlinkTimer);
5048 blink_state = BLINK_ON;
5049 gui_update_cursor(TRUE, FALSE);
5050 }*/
5051}
5052
5053/*
5054 * Return the RGB value of a pixel as long.
5055 */
5056 long_u
5057gui_mch_get_rgb(guicolor_T pixel)
5058{
5059 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5060}
5061
5062
5063
5064#ifdef FEAT_BROWSE
5065/*
5066 * Pop open a file browser and return the file selected, in allocated memory,
5067 * or NULL if Cancel is hit.
5068 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5069 * title - Title message for the file browser dialog.
5070 * dflt - Default name of file.
5071 * ext - Default extension to be added to files without extensions.
5072 * initdir - directory in which to open the browser (NULL = current dir)
5073 * filter - Filter for matched files to choose from.
5074 * Has a format like this:
5075 * "C Files (*.c)\0*.c\0"
5076 * "All Files\0*.*\0\0"
5077 * If these two strings were concatenated, then a choice of two file
5078 * filters will be selectable to the user. Then only matching files will
5079 * be shown in the browser. If NULL, the default allows all files.
5080 *
5081 * *NOTE* - the filter string must be terminated with TWO nulls.
5082 */
5083 char_u *
5084gui_mch_browse(
5085 int saving,
5086 char_u *title,
5087 char_u *dflt,
5088 char_u *ext,
5089 char_u *initdir,
5090 char_u *filter)
5091{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092 /* TODO: Add Ammon's safety checl (Dany) */
5093 NavReplyRecord reply;
5094 char_u *fname = NULL;
5095 char_u **fnames = NULL;
5096 long numFiles;
5097 NavDialogOptions navOptions;
5098 OSErr error;
5099
5100 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005101 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102
5103
5104 /* TODO: If we get a :browse args, set the Multiple bit. */
5105 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5106 | kNavDontAutoTranslate
5107 | kNavDontAddTranslateItems
5108 /* | kNavAllowMultipleFiles */
5109 | kNavAllowStationery;
5110
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005111 (void) C2PascalString(title, &navOptions.message);
5112 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113 /* Could set clientName?
5114 * windowTitle? (there's no title bar?)
5115 */
5116
5117 if (saving)
5118 {
5119 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005120 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 if (!reply.validRecord)
5122 return NULL;
5123 }
5124 else
5125 {
5126 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5127 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5128 if (!reply.validRecord)
5129 return NULL;
5130 }
5131
5132 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5133
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005134 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135
5136 if (fnames)
5137 {
5138 fname = fnames[0];
5139 vim_free(fnames);
5140 }
5141
5142 /* TODO: Shorten the file name if possible */
5143 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005144}
5145#endif /* FEAT_BROWSE */
5146
5147#ifdef FEAT_GUI_DIALOG
5148/*
5149 * Stuff for dialogues
5150 */
5151
5152/*
5153 * Create a dialogue dynamically from the parameter strings.
5154 * type = type of dialogue (question, alert, etc.)
5155 * title = dialogue title. may be NULL for default title.
5156 * message = text to display. Dialogue sizes to accommodate it.
5157 * buttons = '\n' separated list of button captions, default first.
5158 * dfltbutton = number of default button.
5159 *
5160 * This routine returns 1 if the first button is pressed,
5161 * 2 for the second, etc.
5162 *
5163 * 0 indicates Esc was pressed.
5164 * -1 for unexpected error
5165 *
5166 * If stubbing out this fn, return 1.
5167 */
5168
5169typedef struct
5170{
5171 short idx;
5172 short width; /* Size of the text in pixel */
5173 Rect box;
5174} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5175
5176#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5177
5178 static void
5179macMoveDialogItem(
5180 DialogRef theDialog,
5181 short itemNumber,
5182 short X,
5183 short Y,
5184 Rect *inBox)
5185{
5186#if 0 /* USE_CARBONIZED */
5187 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005188 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005190 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005191#else
5192 short itemType;
5193 Handle itemHandle;
5194 Rect localBox;
5195 Rect *itemBox = &localBox;
5196
5197 if (inBox != nil)
5198 itemBox = inBox;
5199
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005200 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5201 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5202 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 /* To move a control (like a button) we need to call both
5204 * MoveControl and SetDialogItem. FAQ 6-18 */
5205 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005206 MoveControl((ControlRef) itemHandle, X, Y);
5207 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208#endif
5209}
5210
5211 static void
5212macSizeDialogItem(
5213 DialogRef theDialog,
5214 short itemNumber,
5215 short width,
5216 short height)
5217{
5218 short itemType;
5219 Handle itemHandle;
5220 Rect itemBox;
5221
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005222 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223
5224 /* When width or height is zero do not change it */
5225 if (width == 0)
5226 width = itemBox.right - itemBox.left;
5227 if (height == 0)
5228 height = itemBox.bottom - itemBox.top;
5229
5230#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005231 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232#else
5233 /* Resize the bounding box */
5234 itemBox.right = itemBox.left + width;
5235 itemBox.bottom = itemBox.top + height;
5236
5237 /* To resize a control (like a button) we need to call both
5238 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5239 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005240 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005241
5242 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005243 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005244#endif
5245}
5246
5247 static void
5248macSetDialogItemText(
5249 DialogRef theDialog,
5250 short itemNumber,
5251 Str255 itemName)
5252{
5253 short itemType;
5254 Handle itemHandle;
5255 Rect itemBox;
5256
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005257 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258
5259 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005260 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005261 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005262 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263}
5264
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005265/* TODO: There have been some crashes with dialogs, check your inbox
5266 * (Jussi)
5267 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005268 int
5269gui_mch_dialog(
5270 int type,
5271 char_u *title,
5272 char_u *message,
5273 char_u *buttons,
5274 int dfltbutton,
5275 char_u *textfield)
5276{
5277 Handle buttonDITL;
5278 Handle iconDITL;
5279 Handle inputDITL;
5280 Handle messageDITL;
5281 Handle itemHandle;
5282 Handle iconHandle;
5283 DialogPtr theDialog;
5284 char_u len;
5285 char_u PascalTitle[256]; /* place holder for the title */
5286 char_u name[256];
5287 GrafPtr oldPort;
5288 short itemHit;
5289 char_u *buttonChar;
5290 Rect box;
5291 short button;
5292 short lastButton;
5293 short itemType;
5294 short useIcon;
5295 short width;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005296 short totalButtonWidth = 0; /* the width of all button together
5297 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005298 short widestButton = 0;
5299 short dfltButtonEdge = 20; /* gut feeling */
5300 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5301 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5302 short maximumWidth = 400; /* gut feeling */
5303 short maxButtonWidth = 175; /* gut feeling */
5304
5305 short vertical;
5306 short dialogHeight;
5307 short messageLines = 3;
5308 FontInfo textFontInfo;
5309
5310 vgmDlgItm iconItm;
5311 vgmDlgItm messageItm;
5312 vgmDlgItm inputItm;
5313 vgmDlgItm buttonItm;
5314
5315 WindowRef theWindow;
5316
5317 /* Check 'v' flag in 'guioptions': vertical button placement. */
5318 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5319
5320 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005321 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005322
5323 /* Get the WindowRef */
5324 theWindow = GetDialogWindow(theDialog);
5325
5326 /* Hide the window.
5327 * 1. to avoid seeing slow drawing
5328 * 2. to prevent a problem seen while moving dialog item
5329 * within a visible window. (non-Carbon MacOS 9)
5330 * Could be avoided by changing the resource.
5331 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005332 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005333
5334 /* Change the graphical port to the dialog,
5335 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005336 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005337 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005338
5339 /* Get the info about the default text,
5340 * used to calculate the height of the message
5341 * and of the text field */
5342 GetFontInfo(&textFontInfo);
5343
5344 /* Set the dialog title */
5345 if (title != NULL)
5346 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005347 (void) C2PascalString(title, &PascalTitle);
5348 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005349 }
5350
5351 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005352 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353 buttonChar = buttons;
5354 button = 0;
5355
5356 for (;*buttonChar != 0;)
5357 {
5358 /* Get the name of the button */
5359 button++;
5360 len = 0;
5361 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5362 {
5363 if (*buttonChar != DLG_HOTKEY_CHAR)
5364 name[++len] = *buttonChar;
5365 }
5366 if (*buttonChar != 0)
5367 buttonChar++;
5368 name[0] = len;
5369
5370 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005371 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372
5373 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005374 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005375
5376 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005377 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 /* Limite the size of any button to an acceptable value. */
5379 /* TODO: Should be based on the message width */
5380 if (width > maxButtonWidth)
5381 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005382 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005383
5384 totalButtonWidth += width;
5385
5386 if (width > widestButton)
5387 widestButton = width;
5388 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005389 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390 lastButton = button;
5391
5392 /* Add the icon to the Dialog Box. */
5393 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005394 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005395 switch (type)
5396 {
5397 case VIM_GENERIC: useIcon = kNoteIcon;
5398 case VIM_ERROR: useIcon = kStopIcon;
5399 case VIM_WARNING: useIcon = kCautionIcon;
5400 case VIM_INFO: useIcon = kNoteIcon;
5401 case VIM_QUESTION: useIcon = kNoteIcon;
5402 default: useIcon = kStopIcon;
5403 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005404 AppendDITL(theDialog, iconDITL, overlayDITL);
5405 ReleaseResource(iconDITL);
5406 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005408 iconHandle = GetIcon(useIcon);
5409 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005410
5411 /* Add the message to the Dialog box. */
5412 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005413 messageDITL = GetResource('DITL', 132);
5414 AppendDITL(theDialog, messageDITL, overlayDITL);
5415 ReleaseResource(messageDITL);
5416 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5417 (void) C2PascalString(message, &name);
5418 SetDialogItemText(itemHandle, name);
5419 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420
5421 /* Add the input box if needed */
5422 if (textfield != NULL)
5423 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005424 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005426 inputDITL = GetResource('DITL', 132);
5427 AppendDITL(theDialog, inputDITL, overlayDITL);
5428 ReleaseResource(inputDITL);
5429 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5430/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5431 (void) C2PascalString(textfield, &name);
5432 SetDialogItemText(itemHandle, name);
5433 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005434 }
5435
5436 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005437 SetDialogDefaultItem(theDialog, dfltbutton);
5438 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439
5440 /* Reposition element */
5441
5442 /* Check if we need to force vertical */
5443 if (totalButtonWidth > maximumWidth)
5444 vertical = TRUE;
5445
5446 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005447 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005448 iconItm.box.right = box.right;
5449 iconItm.box.bottom = box.bottom;
5450
5451 /* Place Message */
5452 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005453 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5454 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005455
5456 /* Place Input */
5457 if (textfield != NULL)
5458 {
5459 inputItm.box.left = messageItm.box.left;
5460 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005461 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5462 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 /* Convert the static text into a text edit.
5464 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005465 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5466 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5468 }
5469
5470 /* Place Button */
5471 if (textfield != NULL)
5472 {
5473 buttonItm.box.left = inputItm.box.left;
5474 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5475 }
5476 else
5477 {
5478 buttonItm.box.left = messageItm.box.left;
5479 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5480 }
5481
5482 for (button=1; button <= lastButton; button++)
5483 {
5484
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005485 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486 /* With vertical, it's better to have all button the same lenght */
5487 if (vertical)
5488 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005489 macSizeDialogItem(theDialog, button, widestButton, 0);
5490 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005491 }
5492 /* Calculate position of next button */
5493 if (vertical)
5494 buttonItm.box.top = box.bottom + dfltElementSpacing;
5495 else
5496 buttonItm.box.left = box.right + dfltElementSpacing;
5497 }
5498
5499 /* Resize the dialog box */
5500 dialogHeight = box.bottom + dfltElementSpacing;
5501 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5502
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005504 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005505 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005506
5507 /* Display it */
5508 ShowWindow(theWindow);
5509/* BringToFront(theWindow); */
5510 SelectWindow(theWindow);
5511
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005512/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005513#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005514 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005515 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005516#endif
5517
Bram Moolenaard68071d2006-05-02 22:08:30 +00005518#ifdef USE_CARBONKEYHANDLER
5519 /* Avoid that we use key events for the main window. */
5520 dialog_busy = TRUE;
5521#endif
5522
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523 /* Hang until one of the button is hit */
5524 do
5525 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005526 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 } while ((itemHit < 1) || (itemHit > lastButton));
5528
Bram Moolenaard68071d2006-05-02 22:08:30 +00005529#ifdef USE_CARBONKEYHANDLER
5530 dialog_busy = FALSE;
5531#endif
5532
Bram Moolenaar071d4272004-06-13 20:20:40 +00005533 /* Copy back the text entered by the user into the param */
5534 if (textfield != NULL)
5535 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005536 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5537 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005538#if IOSIZE < 256
5539 /* Truncate the name to IOSIZE if needed */
5540 if (name[0] > IOSIZE)
5541 name[0] = IOSIZE - 1;
5542#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005543 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005544 }
5545
5546 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005547 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548
5549 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005550 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005551
5552 return itemHit;
5553/*
5554 * Usefull thing which could be used
5555 * SetDialogTimeout(): Auto click a button after timeout
5556 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5557 * MoveDialogItem(): Probably better than SetDialogItem
5558 * SizeDialogItem(): (but is it Carbon Only?)
5559 * AutoSizeDialog(): Magic resize of dialog based on text lenght
5560 */
5561}
5562#endif /* FEAT_DIALOG_GUI */
5563
5564/*
5565 * Display the saved error message(s).
5566 */
5567#ifdef USE_MCH_ERRMSG
5568 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005569display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570{
5571 char *p;
5572 char_u pError[256];
5573
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005574 if (error_ga.ga_data == NULL)
5575 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005577 /* avoid putting up a message box with blanks only */
5578 for (p = (char *)error_ga.ga_data; *p; ++p)
5579 if (!isspace(*p))
5580 {
5581 if (STRLEN(p) > 255)
5582 pError[0] = 255;
5583 else
5584 pError[0] = STRLEN(p);
5585
5586 STRNCPY(&pError[1], p, pError[0]);
5587 ParamText(pError, nil, nil, nil);
5588 Alert(128, nil);
5589 break;
5590 /* TODO: handled message longer than 256 chars
5591 * use auto-sizeable alert
5592 * or dialog with scrollbars (TextEdit zone)
5593 */
5594 }
5595 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596}
5597#endif
5598
5599/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005600 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005601 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005602 void
5603gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604{
5605 Point where;
5606
5607 GetMouse(&where);
5608
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005609 *x = where.h;
5610 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005611}
5612
5613 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005614gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005615{
5616 /* TODO */
5617#if 0
5618 /* From FAQ 3-11 */
5619
5620 CursorDevicePtr myMouse;
5621 Point where;
5622
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005623 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5624 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005625 {
5626 /* New way */
5627
5628 /*
5629 * Get first devoice with one button.
5630 * This will probably be the standad mouse
5631 * startat head of cursor dev list
5632 *
5633 */
5634
5635 myMouse = nil;
5636
5637 do
5638 {
5639 /* Get the next cursor device */
5640 CursorDeviceNextDevice(&myMouse);
5641 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005642 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005643
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005644 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645 }
5646 else
5647 {
5648 /* Old way */
5649 where.h = x;
5650 where.v = y;
5651
5652 *(Point *)RawMouse = where;
5653 *(Point *)MTemp = where;
5654 *(Ptr) CrsrNew = 0xFFFF;
5655 }
5656#endif
5657}
5658
5659 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005660gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005662/*
5663 * Clone PopUp to use menu
5664 * Create a object descriptor for the current selection
5665 * Call the procedure
5666 */
5667
5668 MenuHandle CntxMenu;
5669 Point where;
5670 OSStatus status;
5671 UInt32 CntxType;
5672 SInt16 CntxMenuID;
5673 UInt16 CntxMenuItem;
5674 Str255 HelpName = "";
5675 GrafPtr savePort;
5676
5677 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005678 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005679
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005680 GetMouse(&where);
5681 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682 CntxMenu = menu->submenu_handle;
5683
5684 /* TODO: Get the text selection from Vim */
5685
5686 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005687 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005688 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689
5690 if (status == noErr)
5691 {
5692 if (CntxType == kCMMenuItemSelected)
5693 {
5694 /* Handle the menu CntxMenuID, CntxMenuItem */
5695 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005696 /* But what about the current menu, is the menu changed by
5697 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005698 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005699 }
5700 else if (CntxMenuID == kCMShowHelpSelected)
5701 {
5702 /* Should come up with the help */
5703 }
5704 }
5705
5706 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708}
5709
5710#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5711/* TODO: Is it need for MACOS_X? (Dany) */
5712 void
5713mch_post_buffer_write(buf_T *buf)
5714{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005715 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5716 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005717}
5718#endif
5719
5720#ifdef FEAT_TITLE
5721/*
5722 * Set the window title and icon.
5723 * (The icon is not taken care of).
5724 */
5725 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005726gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005727{
5728 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5729 * that 256. Even better get it to fit nicely in the titlebar.
5730 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005731#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005732 CFStringRef windowTitle;
5733 size_t windowTitleLen;
5734#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005736#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737
5738 if (title == NULL) /* nothing to do */
5739 return;
5740
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005741#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005742 windowTitleLen = STRLEN(title);
5743 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
5744
5745 if (windowTitle)
5746 {
5747 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5748 CFRelease(windowTitle);
5749 }
5750#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751 pascalTitle = C2Pascal_save(title);
5752 if (pascalTitle != NULL)
5753 {
5754 SetWTitle(gui.VimWindow, pascalTitle);
5755 vim_free(pascalTitle);
5756 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005757#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005758}
5759#endif
5760
5761/*
5762 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5763 */
5764
5765 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005766C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767{
5768 char_u *PascalPtr = (char_u *) PascalString;
5769 int len;
5770 int i;
5771
5772 PascalPtr[0] = 0;
5773 if (CString == NULL)
5774 return 0;
5775
5776 len = STRLEN(CString);
5777 if (len > 255)
5778 len = 255;
5779
5780 for (i = 0; i < len; i++)
5781 PascalPtr[i+1] = CString[i];
5782
5783 PascalPtr[0] = len;
5784
5785 return 0;
5786}
5787
5788 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005789GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005790{
5791 /* From FAQ 8-12 */
5792 Str255 filePascal;
5793 CInfoPBRec myCPB;
5794 OSErr err;
5795
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005796 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797
5798 myCPB.dirInfo.ioNamePtr = filePascal;
5799 myCPB.dirInfo.ioVRefNum = 0;
5800 myCPB.dirInfo.ioFDirIndex = 0;
5801 myCPB.dirInfo.ioDrDirID = 0;
5802
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005803 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005804
5805 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005806 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005807
5808 /* TODO: Use an error code mechanism */
5809 return 0;
5810}
5811
5812/*
5813 * Convert a FSSpec to a fuill path
5814 */
5815
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005816char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005817{
5818 /*
5819 * TODO: Add protection for 256 char max.
5820 */
5821
5822 CInfoPBRec theCPB;
5823 char_u fname[256];
5824 char_u *filenamePtr = fname;
5825 OSErr error;
5826 int folder = 1;
5827#ifdef USE_UNIXFILENAME
5828 SInt16 dfltVol_vRefNum;
5829 SInt32 dfltVol_dirID;
5830 FSRef refFile;
5831 OSStatus status;
5832 UInt32 pathSize = 256;
5833 char_u pathname[256];
5834 char_u *path = pathname;
5835#else
5836 Str255 directoryName;
5837 char_u temporary[255];
5838 char_u *temporaryPtr = temporary;
5839#endif
5840
5841#ifdef USE_UNIXFILENAME
5842 /* Get the default volume */
5843 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005844 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845
5846 if (error)
5847 return NULL;
5848#endif
5849
5850 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005851 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852
5853 /* Get the info about the file specified in FSSpec */
5854 theCPB.dirInfo.ioFDirIndex = 0;
5855 theCPB.dirInfo.ioNamePtr = file.name;
5856 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00005857 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005858 theCPB.dirInfo.ioDrDirID = file.parID;
5859
5860 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5861 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005862 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863
5864 /* If we are called for a new file we expect fnfErr */
5865 if ((error) && (error != fnfErr))
5866 return NULL;
5867
5868 /* Check if it's a file or folder */
5869 /* default to file if file don't exist */
5870 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
5871 folder = 0; /* It's not a folder */
5872 else
5873 folder = 1;
5874
5875#ifdef USE_UNIXFILENAME
5876 /*
5877 * The function used here are available in Carbon, but
5878 * do nothing une MacOS 8 and 9
5879 */
5880 if (error == fnfErr)
5881 {
5882 /* If the file to be saved does not already exist, it isn't possible
5883 to convert its FSSpec into an FSRef. But we can construct an
5884 FSSpec for the file's parent folder (since we have its volume and
5885 directory IDs), and since that folder does exist, we can convert
5886 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5887 and, finally, append the filename. */
5888 FSSpec dirSpec;
5889 FSRef dirRef;
5890 Str255 emptyFilename = "\p";
5891 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
5892 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
5893 if (error)
5894 return NULL;
5895
5896 error = FSpMakeFSRef(&dirSpec, &dirRef);
5897 if (error)
5898 return NULL;
5899
5900 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
5901 if (status)
5902 return NULL;
5903
5904 STRCAT(path, "/");
5905 STRCAT(path, filenamePtr);
5906 }
5907 else
5908 {
5909 /* If the file to be saved already exists, we can get its full path
5910 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005911 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912 if (error)
5913 return NULL;
5914
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005915 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005916 if (status)
5917 return NULL;
5918 }
5919
5920 /* Add a slash at the end if needed */
5921 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005922 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005924 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005925#else
5926 /* TODO: Get rid of all USE_UNIXFILENAME below */
5927 /* Set ioNamePtr, it's the same area which is always reused. */
5928 theCPB.dirInfo.ioNamePtr = directoryName;
5929
5930 /* Trick for first entry, set ioDrParID to the first value
5931 * we want for ioDrDirID*/
5932 theCPB.dirInfo.ioDrParID = file.parID;
5933 theCPB.dirInfo.ioDrDirID = file.parID;
5934
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005935 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936 do
5937 {
5938 theCPB.dirInfo.ioFDirIndex = -1;
5939 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5940 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005941 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005942 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5943
5944 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5945 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005946 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947
5948 if (error)
5949 return NULL;
5950
5951 /* Put the new directoryName in front of the current fname */
5952 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005953 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005954 STRCAT(filenamePtr, ":");
5955 STRCAT(filenamePtr, temporaryPtr);
5956 }
5957#if 1 /* def USE_UNIXFILENAME */
5958 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
5959 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5960#else
5961 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
5962#endif
5963
5964 /* Get the information about the volume on which the file reside */
5965 theCPB.dirInfo.ioFDirIndex = -1;
5966 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5967 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005968 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5970
5971 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5972 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005973 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974
5975 if (error)
5976 return NULL;
5977
5978 /* For MacOS Classic always add the volume name */
5979 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00005980 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005981#ifdef USE_UNIXFILENAME
5982 if (file.vRefNum != dfltVol_vRefNum)
5983#endif
5984 {
5985 /* Add the volume name */
5986 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005987 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005988 STRCAT(filenamePtr, ":");
5989 STRCAT(filenamePtr, temporaryPtr);
5990
5991#ifdef USE_UNIXFILENAME
5992 STRCPY(temporaryPtr, filenamePtr);
5993 filenamePtr[0] = 0; /* NULL terminate the string */
5994 STRCAT(filenamePtr, "Volumes:");
5995 STRCAT(filenamePtr, temporaryPtr);
5996#endif
5997 }
5998
5999 /* Append final path separator if it's a folder */
6000 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006001 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006002
6003 /* As we use Unix File Name for MacOS X convert it */
6004#ifdef USE_UNIXFILENAME
6005 /* Need to insert leading / */
6006 /* TODO: get the above code to use directly the / */
6007 STRCPY(&temporaryPtr[1], filenamePtr);
6008 temporaryPtr[0] = '/';
6009 STRCPY(filenamePtr, temporaryPtr);
6010 {
6011 char *p;
6012 for (p = fname; *p; p++)
6013 if (*p == ':')
6014 *p = '/';
6015 }
6016#endif
6017
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006018 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019#endif
6020}
6021
6022#if defined(USE_IM_CONTROL) || defined(PROTO)
6023/*
6024 * Input Method Control functions.
6025 */
6026
6027/*
6028 * Notify cursor position to IM.
6029 */
6030 void
6031im_set_position(int row, int col)
6032{
6033 /* TODO: Implement me! */
6034}
6035
6036/*
6037 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6038 */
6039 void
6040im_set_active(int active)
6041{
6042 KeyScript(active ? smKeySysScript : smKeyRoman);
6043}
6044
6045/*
6046 * Get IM status. When IM is on, return not 0. Else return 0.
6047 */
6048 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006049im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050{
6051 SInt32 script = GetScriptManagerVariable(smKeyScript);
6052 return (script != smRoman
6053 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6054}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006055
Bram Moolenaar071d4272004-06-13 20:20:40 +00006056#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006057
6058
6059
6060
6061#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6062// drawer implementation
6063static MenuRef contextMenu = NULL;
6064enum
6065{
6066 kTabContextMenuId = 42,
6067};
6068
6069// the caller has to CFRelease() the returned string
6070 static CFStringRef
6071getTabLabel(tabpage_T *page)
6072{
6073 get_tabline_label(page, FALSE);
6074#ifdef MACOS_CONVERT
6075 return mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6076#else
6077 // TODO: check internal encoding?
6078 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6079 kCFStringEncodingMacRoman);
6080#endif
6081}
6082
6083
6084#define DRAWER_SIZE 150
6085#define DRAWER_INSET 16
6086
6087static ControlRef dataBrowser = NULL;
6088
6089// when the tabline is hidden, vim doesn't call update_tabline(). When
6090// the tabline is shown again, show_tabline() is called before upate_tabline(),
6091// and because of this, the tab labels and vims internal tabs are out of sync
6092// for a very short time. to prevent inconsistent state, we store the labels
6093// of the tabs, not pointers to the tabs (which are invalid for a short time).
6094static CFStringRef *tabLabels = NULL;
6095static int tabLabelsSize = 0;
6096
6097enum
6098{
6099 kTabsColumn = 'Tabs'
6100};
6101
6102 static int
6103getTabCount(void)
6104{
6105 tabpage_T *tp;
6106 int numTabs = 0;
6107
6108 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6109 ++numTabs;
6110 return numTabs;
6111}
6112
6113// data browser item display callback
6114 static OSStatus
6115dbItemDataCallback(ControlRef browser,
6116 DataBrowserItemID itemID,
6117 DataBrowserPropertyID property /* column id */,
6118 DataBrowserItemDataRef itemData,
6119 Boolean changeValue)
6120{
6121 OSStatus status = noErr;
6122
6123 // assert(property == kTabsColumn); // why is this violated??
6124
6125 // changeValue is true if we have a modifieable list and data was changed.
6126 // In our case, it's always false.
6127 // (that is: if (changeValue) updateInternalData(); else return
6128 // internalData();
6129 if (!changeValue)
6130 {
6131 CFStringRef str;
6132
6133 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6134 str = tabLabels[itemID - 1];
6135 status = SetDataBrowserItemDataText(itemData, str);
6136 }
6137 else
6138 status = errDataBrowserPropertyNotSupported;
6139
6140 return status;
6141}
6142
6143// data browser action callback
6144 static void
6145dbItemNotificationCallback(ControlRef browser,
6146 DataBrowserItemID item,
6147 DataBrowserItemNotification message)
6148{
6149 switch (message)
6150 {
6151 case kDataBrowserItemSelected:
6152 send_tabline_event(item);
6153 break;
6154 }
6155}
6156
6157// callbacks needed for contextual menu:
6158 static void
6159dbGetContextualMenuCallback(ControlRef browser,
6160 MenuRef *menu,
6161 UInt32 *helpType,
6162 CFStringRef *helpItemString,
6163 AEDesc *selection)
6164{
6165 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6166 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6167 *helpItemString = NULL;
6168
6169 *menu = contextMenu;
6170}
6171
6172 static void
6173dbSelectContextualMenuCallback(ControlRef browser,
6174 MenuRef menu,
6175 UInt32 selectionType,
6176 SInt16 menuID,
6177 MenuItemIndex menuItem)
6178{
6179 if (selectionType == kCMMenuItemSelected)
6180 {
6181 MenuCommand command;
6182 GetMenuItemCommandID(menu, menuItem, &command);
6183
6184 // get tab that was selected when the context menu appeared
6185 // (there is always one tab selected). TODO: check if the context menu
6186 // isn't opened on an item but on empty space (has to be possible some
6187 // way, the finder does it too ;-) )
6188 Handle items = NewHandle(0);
6189 if (items != NULL)
6190 {
6191 int numItems;
6192
6193 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6194 kDataBrowserItemIsSelected, items);
6195 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6196 if (numItems > 0)
6197 {
6198 int idx;
6199 DataBrowserItemID *itemsPtr;
6200
6201 HLock(items);
6202 itemsPtr = (DataBrowserItemID *)*items;
6203 idx = itemsPtr[0];
6204 HUnlock(items);
6205 send_tabline_menu_event(idx, command);
6206 }
6207 DisposeHandle(items);
6208 }
6209 }
6210}
6211
6212// focus callback of the data browser to always leave focus in vim
6213 static OSStatus
6214dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6215{
6216 assert(GetEventClass(event) == kEventClassControl
6217 && GetEventKind(event) == kEventControlSetFocusPart);
6218
6219 return paramErr;
6220}
6221
6222
6223// drawer callback to resize data browser to drawer size
6224 static OSStatus
6225drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6226{
6227 switch (GetEventKind(event))
6228 {
6229 case kEventWindowBoundsChanged: // move or resize
6230 {
6231 UInt32 attribs;
6232 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6233 NULL, sizeof(attribs), NULL, &attribs);
6234 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6235 {
6236 Rect r;
6237 GetWindowBounds(drawer, kWindowContentRgn, &r);
6238 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6239 SetControlBounds(dataBrowser, &r);
6240 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6241 kTabsColumn, r.right);
6242 }
6243 }
6244 break;
6245 }
6246
6247 return eventNotHandledErr;
6248}
6249
6250// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6251// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6252// blue highlights in the list view on these systems, though. Oh well.)
6253
6254
6255#import <mach-o/dyld.h>
6256
6257enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6258
6259 static OSStatus
6260myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6261 OptionBits inAttributesToSet,
6262 OptionBits inAttributesToClear)
6263{
6264 long osVersion;
6265 char *symbolName;
6266 NSSymbol symbol = NULL;
6267 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6268 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6269
6270 Gestalt(gestaltSystemVersion, &osVersion);
6271 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6272 return noErr;
6273
6274 // C name mangling...
6275 symbolName = "_DataBrowserChangeAttributes";
6276 if (!NSIsSymbolNameDefined(symbolName)
6277 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6278 return noErr;
6279
6280 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6281 if (dataBrowserChangeAttributes == NULL)
6282 return noErr; // well...
6283 return dataBrowserChangeAttributes(inDataBrowser,
6284 inAttributesToSet, inAttributesToClear);
6285}
6286
6287 static void
6288initialise_tabline(void)
6289{
6290 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6291 DataBrowserCallbacks dbCallbacks;
6292 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6293 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6294 DataBrowserListViewColumnDesc colDesc;
6295
6296 // drawers have to have compositing enabled
6297 CreateNewWindow(kDrawerWindowClass,
6298 kWindowStandardHandlerAttribute
6299 | kWindowCompositingAttribute
6300 | kWindowResizableAttribute
6301 | kWindowLiveResizeAttribute,
6302 &drawerRect, &drawer);
6303
6304 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6305 SetDrawerParent(drawer, gui.VimWindow);
6306 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6307
6308
6309 // create list view embedded in drawer
6310 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6311 &dataBrowser);
6312
6313 dbCallbacks.version = kDataBrowserLatestCallbacks;
6314 InitDataBrowserCallbacks(&dbCallbacks);
6315 dbCallbacks.u.v1.itemDataCallback =
6316 NewDataBrowserItemDataUPP(dbItemDataCallback);
6317 dbCallbacks.u.v1.itemNotificationCallback =
6318 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6319 dbCallbacks.u.v1.getContextualMenuCallback =
6320 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6321 dbCallbacks.u.v1.selectContextualMenuCallback =
6322 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6323
6324 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6325
6326 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6327 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6328 SetDataBrowserSelectionFlags(dataBrowser,
6329 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6330 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6331 kDataBrowserTableViewFillHilite);
6332 Boolean b = false;
6333 SetControlData(dataBrowser, kControlEntireControl,
6334 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6335
6336 // enable blue background in data browser (this is only in 10.4 and vim
6337 // has to support older osx versions as well, so we have to load this
6338 // function dynamically)
6339 myDataBrowserChangeAttributes(dataBrowser,
6340 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6341
6342 // install callback that keeps focus in vim and away from the data browser
6343 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6344 NULL, NULL);
6345
6346 // install callback that keeps data browser at the size of the drawer
6347 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6348 NULL, NULL);
6349
6350 // add "tabs" column to data browser
6351 colDesc.propertyDesc.propertyID = kTabsColumn;
6352 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6353
6354 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6355 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6356
6357 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6358 colDesc.headerBtnDesc.minimumWidth = 100;
6359 colDesc.headerBtnDesc.maximumWidth = 150;
6360 colDesc.headerBtnDesc.titleOffset = 0;
6361 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6362 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6363 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6364 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6365
6366 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6367
6368 // create tabline popup menu required by vim docs (see :he tabline-menu)
6369 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6370 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6371 TABLINE_MENU_CLOSE, NULL);
6372 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6373 TABLINE_MENU_NEW, NULL);
6374 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6375 TABLINE_MENU_OPEN, NULL);
6376}
6377
6378
6379/*
6380 * Show or hide the tabline.
6381 */
6382 void
6383gui_mch_show_tabline(int showit)
6384{
6385 if (showit == 0)
6386 CloseDrawer(drawer, true);
6387 else
6388 OpenDrawer(drawer, kWindowEdgeRight, true);
6389}
6390
6391/*
6392 * Return TRUE when tabline is displayed.
6393 */
6394 int
6395gui_mch_showing_tabline(void)
6396{
6397 WindowDrawerState state = GetDrawerState(drawer);
6398
6399 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6400}
6401
6402/*
6403 * Update the labels of the tabline.
6404 */
6405 void
6406gui_mch_update_tabline(void)
6407{
6408 tabpage_T *tp;
6409 int numTabs = getTabCount();
6410 int nr = 1;
6411 int curtabidx = 1;
6412
6413 // adjust data browser
6414 if (tabLabels != NULL)
6415 {
6416 int i;
6417
6418 for (i = 0; i < tabLabelsSize; ++i)
6419 CFRelease(tabLabels[i]);
6420 free(tabLabels);
6421 }
6422 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6423 tabLabelsSize = numTabs;
6424
6425 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6426 {
6427 if (tp == curtab)
6428 curtabidx = nr;
6429 tabLabels[nr-1] = getTabLabel(tp);
6430 }
6431
6432 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6433 kDataBrowserItemNoProperty);
6434 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6435 // can pass NULL for the id array
6436 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6437 kDataBrowserItemNoProperty);
6438
6439 DataBrowserItemID item = curtabidx;
6440 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6441}
6442
6443/*
6444 * Set the current tab to "nr". First tab is 1.
6445 */
6446 void
6447gui_mch_set_curtab(nr)
6448 int nr;
6449{
6450 DataBrowserItemID item = nr;
6451 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6452
6453 // TODO: call something like this?: (or restore scroll position, or...)
6454 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6455 kDataBrowserRevealOnly);
6456}
6457
6458#endif // FEAT_GUI_TABLINE