blob: adc8ddc1f19884958b875d7c345b5670f07fe185 [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;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001049 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050
1051 /* these are the initial files dropped on the Vim icon */
1052 for (i = 0 ; i < numFiles; i++)
1053 {
1054 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1055 || (p = vim_strsave(fnames[i])) == NULL)
1056 mch_exit(2);
1057 else
1058 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001059 if (fnum == -1)
1060 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1061 }
1062
1063 /* If the file name was already in the buffer list we need to switch
1064 * to it. */
1065 if (curbuf->b_fnum != fnum)
1066 {
1067 char_u cmd[30];
1068
1069 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1070 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001072
1073 /* Change directory to the location of the first file. */
1074 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1075 shorten_fnames(TRUE);
1076
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 goto finished;
1078 }
1079
1080 /* Handle the drop, :edit to get to the file */
1081 handle_drop(numFiles, fnames, FALSE);
1082
1083 /* TODO: Handle the goto/select line more cleanly */
1084 if ((numFiles == 1) & (gotPosition))
1085 {
1086 if (thePosition.lineNum >= 0)
1087 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001088 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089 /* oap->motion_type = MLINE;
1090 setpcmark();*/
1091 if (lnum < 1L)
1092 lnum = 1L;
1093 else if (lnum > curbuf->b_ml.ml_line_count)
1094 lnum = curbuf->b_ml.ml_line_count;
1095 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001096 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 /* beginline(BL_SOL | BL_FIX);*/
1098 }
1099 else
1100 goto_byte(thePosition.startRange + 1);
1101 }
1102
1103 /* Update the screen display */
1104 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001105#ifdef FEAT_VISUAL
1106 /* Select the text if possible */
1107 if (gotPosition)
1108 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001109 VIsual_active = TRUE;
1110 VIsual_select = FALSE;
1111 VIsual = curwin->w_cursor;
1112 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001113 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001114 VIsual_mode = 'v';
1115 goto_byte(thePosition.endRange);
1116 }
1117 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001118 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001119 VIsual_mode = 'V';
1120 VIsual.col = 0;
1121 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001122 }
1123#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 setcursor();
1125 out_flush();
1126
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001127 /* Fake mouse event to wake from stall */
1128 PostEvent(mouseUp, 0);
1129
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001130finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 AEDisposeDesc(&theList); /* dispose what we allocated */
1132
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001133 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001134 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135}
1136
1137/*
1138 *
1139 */
1140
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001141 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001142Handle_aevt_oapp_AE(
1143 const AppleEvent *theAEvent,
1144 AppleEvent *theReply,
1145 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146{
1147 OSErr error = noErr;
1148
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001149 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001150 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151}
1152
1153/*
1154 *
1155 */
1156
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001157 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001158Handle_aevt_quit_AE(
1159 const AppleEvent *theAEvent,
1160 AppleEvent *theReply,
1161 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162{
1163 OSErr error = noErr;
1164
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001165 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001166 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001167 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168
1169 /* Need to fake a :confirm qa */
1170 do_cmdline_cmd((char_u *)"confirm qa");
1171
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001172 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173}
1174
1175/*
1176 *
1177 */
1178
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001179 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001180Handle_aevt_pdoc_AE(
1181 const AppleEvent *theAEvent,
1182 AppleEvent *theReply,
1183 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184{
1185 OSErr error = noErr;
1186
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001187 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001189 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190}
1191
1192/*
1193 * Handling of unknown AppleEvent
1194 *
1195 * (Just get rid of all the parms)
1196 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001197 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001198Handle_unknown_AE(
1199 const AppleEvent *theAEvent,
1200 AppleEvent *theReply,
1201 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202{
1203 OSErr error = noErr;
1204
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001205 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001207 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208}
1209
1210
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211/*
1212 * Install the various AppleEvent Handlers
1213 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001214 OSErr
1215InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216{
1217 OSErr error;
1218
1219 /* install open application handler */
1220 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001221 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222 if (error)
1223 {
1224 return error;
1225 }
1226
1227 /* install quit application handler */
1228 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001229 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001230 if (error)
1231 {
1232 return error;
1233 }
1234
1235 /* install open document handler */
1236 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001237 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 if (error)
1239 {
1240 return error;
1241 }
1242
1243 /* install print document handler */
1244 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001245 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246
1247/* Install Core Suite */
1248/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001249 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250
1251 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001252 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253
1254 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001255 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256
1257 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001258 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259
1260 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001261 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262
1263 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001264 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265
1266 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001267 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268
1269 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001270 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271
1272 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001273 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274
1275 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001276 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277
1278 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001279 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280
1281 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001282 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001283
1284 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001285 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286*/
1287
1288#ifdef FEAT_CW_EDITOR
1289 /*
1290 * Bind codewarrior support handlers
1291 */
1292 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001293 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 if (error)
1295 {
1296 return error;
1297 }
1298 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001299 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 if (error)
1301 {
1302 return error;
1303 }
1304 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001305 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 if (error)
1307 {
1308 return error;
1309 }
1310#endif
1311
1312 return error;
1313
1314}
1315#endif /* USE_AEVENT */
1316
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001317
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001318/*
1319 * Callback function, installed by InstallFontPanelHandler(), below,
1320 * to handle Font Panel events.
1321 */
1322 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001323FontPanelHandler(
1324 EventHandlerCallRef inHandlerCallRef,
1325 EventRef inEvent,
1326 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001327{
1328 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1329 {
1330 gFontPanelInfo.isPanelVisible = false;
1331 return noErr;
1332 }
1333
1334 if (GetEventKind(inEvent) == kEventFontSelection)
1335 {
1336 OSStatus status;
1337 FMFontFamily newFamily;
1338 FMFontSize newSize;
1339 FMFontStyle newStyle;
1340
1341 /* Retrieve the font family ID number. */
1342 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1343 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1344 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1345 &newFamily);
1346 if (status == noErr)
1347 gFontPanelInfo.family = newFamily;
1348
1349 /* Retrieve the font size. */
1350 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1351 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1352 if (status == noErr)
1353 gFontPanelInfo.size = newSize;
1354
1355 /* Retrieve the font style (bold, etc.). Currently unused. */
1356 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1357 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1358 if (status == noErr)
1359 gFontPanelInfo.style = newStyle;
1360 }
1361 return noErr;
1362}
1363
1364
1365 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001366InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001367{
1368 EventTypeSpec eventTypes[2];
1369 EventHandlerUPP handlerUPP;
1370 /* EventHandlerRef handlerRef; */
1371
1372 eventTypes[0].eventClass = kEventClassFont;
1373 eventTypes[0].eventKind = kEventFontSelection;
1374 eventTypes[1].eventClass = kEventClassFont;
1375 eventTypes[1].eventKind = kEventFontPanelClosed;
1376
1377 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1378
1379 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1380 /*userData=*/NULL, /*handlerRef=*/NULL);
1381}
1382
1383
1384/*
1385 * Fill the buffer pointed to by outName with the name and size
1386 * of the font currently selected in the Font Panel.
1387 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001388#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001389 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001390GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001391{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001392 Str255 buf;
1393 ByteCount fontNameLen = 0;
1394 ATSUFontID fid;
1395 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001396
1397 if (!outName)
1398 return;
1399
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001400 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1401 {
1402 /* Canonicalize localized font names */
1403 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1404 gFontPanelInfo.style, &fid, NULL) != noErr)
1405 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001406
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001407 /* Request font name with Mac encoding (otherwise we could
1408 * get an unwanted utf-16 name) */
1409 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1410 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001411 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001412 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001413
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001414 /* Only encode font size, because style (bold, italic, etc) is
1415 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001416 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001417 gFontPanelInfo.size/*,
1418 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1419 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1420 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1421
1422 if ((fontNameLen + STRLEN(styleString)) < 255)
1423 STRCPY(outName + fontNameLen, styleString);
1424 }
1425 else
1426 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001427 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001429}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001430
1431
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432/*
1433 * ------------------------------------------------------------
1434 * Unfiled yet
1435 * ------------------------------------------------------------
1436 */
1437
1438/*
1439 * gui_mac_get_menu_item_index
1440 *
1441 * Returns the index inside the menu wher
1442 */
1443 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001444gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445{
1446 short index;
1447 short itemIndex = -1;
1448 vimmenu_T *pBrother;
1449
1450 /* Only menu without parent are the:
1451 * -menu in the menubar
1452 * -popup menu
1453 * -toolbar (guess)
1454 *
1455 * Which are not items anyway.
1456 */
1457 if (pMenu->parent)
1458 {
1459 /* Start from the Oldest Brother */
1460 pBrother = pMenu->parent->children;
1461 index = 1;
1462 while ((pBrother) && (itemIndex == -1))
1463 {
1464 if (pBrother == pMenu)
1465 itemIndex = index;
1466 index++;
1467 pBrother = pBrother->next;
1468 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469 }
1470 return itemIndex;
1471}
1472
1473 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001474gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001475{
1476 short index;
1477 vimmenu_T *pChildMenu;
1478 vimmenu_T *pElder = pMenu->parent;
1479
1480
1481 /* Only menu without parent are the:
1482 * -menu in the menubar
1483 * -popup menu
1484 * -toolbar (guess)
1485 *
1486 * Which are not items anyway.
1487 */
1488
1489 if ((pElder) && (pElder->submenu_id == menuID))
1490 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1492 pMenu = pMenu->next;
1493 }
1494 else
1495 {
1496 for (; pMenu != NULL; pMenu = pMenu->next)
1497 {
1498 if (pMenu->children != NULL)
1499 {
1500 pChildMenu = gui_mac_get_vim_menu
1501 (menuID, itemIndex, pMenu->children);
1502 if (pChildMenu)
1503 {
1504 pMenu = pChildMenu;
1505 break;
1506 }
1507 }
1508 }
1509 }
1510 return pMenu;
1511}
1512
1513/*
1514 * ------------------------------------------------------------
1515 * MacOS Feedback procedures
1516 * ------------------------------------------------------------
1517 */
1518 pascal
1519 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001520gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001521{
1522 scrollbar_T *sb;
1523 int value, dragging;
1524 ControlHandle theControlToUse;
1525 int dont_scroll_save = dont_scroll;
1526
1527 theControlToUse = dragged_sb;
1528
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001529 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530
1531 if (sb == NULL)
1532 return;
1533
1534 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001535 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536 dragging = (partCode != 0);
1537
1538 /* When "allow_scrollbar" is FALSE still need to remember the new
1539 * position, but don't actually scroll by setting "dont_scroll". */
1540 dont_scroll = !allow_scrollbar;
1541 gui_drag_scrollbar(sb, value, dragging);
1542 dont_scroll = dont_scroll_save;
1543}
1544
1545 pascal
1546 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001547gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548{
1549 /* TODO: have live support */
1550 scrollbar_T *sb, *sb_info;
1551 long data;
1552 long value;
1553 int page;
1554 int dragging = FALSE;
1555 int dont_scroll_save = dont_scroll;
1556
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001557 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558
1559 if (sb == NULL)
1560 return;
1561
1562 if (sb->wp != NULL) /* Left or right scrollbar */
1563 {
1564 /*
1565 * Careful: need to get scrollbar info out of first (left) scrollbar
1566 * for window, but keep real scrollbar too because we must pass it to
1567 * gui_drag_scrollbar().
1568 */
1569 sb_info = &sb->wp->w_scrollbars[0];
1570
1571 if (sb_info->size > 5)
1572 page = sb_info->size - 2; /* use two lines of context */
1573 else
1574 page = sb_info->size;
1575 }
1576 else /* Bottom scrollbar */
1577 {
1578 sb_info = sb;
1579 page = W_WIDTH(curwin) - 5;
1580 }
1581
1582 switch (partCode)
1583 {
1584 case kControlUpButtonPart: data = -1; break;
1585 case kControlDownButtonPart: data = 1; break;
1586 case kControlPageDownPart: data = page; break;
1587 case kControlPageUpPart: data = -page; break;
1588 default: data = 0; break;
1589 }
1590
1591 value = sb_info->value + data;
1592/* if (value > sb_info->max)
1593 value = sb_info->max;
1594 else if (value < 0)
1595 value = 0;*/
1596
1597 /* When "allow_scrollbar" is FALSE still need to remember the new
1598 * position, but don't actually scroll by setting "dont_scroll". */
1599 dont_scroll = !allow_scrollbar;
1600 gui_drag_scrollbar(sb, value, dragging);
1601 dont_scroll = dont_scroll_save;
1602
1603 out_flush();
1604 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1605
1606/* if (sb_info->wp != NULL)
1607 {
1608 win_T *wp;
1609 int sb_num;
1610
1611 sb_num = 0;
1612 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1613 sb_num++;
1614
1615 if (wp != NULL)
1616 {
1617 current_scrollbar = sb_num;
1618 scrollbar_value = value;
1619 gui_do_scroll();
1620 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1621 }
1622 }*/
1623}
1624
1625/*
1626 * ------------------------------------------------------------
1627 * MacOS Click Handling procedures
1628 * ------------------------------------------------------------
1629 */
1630
1631
1632/*
1633 * Handle a click inside the window, it may happens in the
1634 * scrollbar or the contents.
1635 *
1636 * TODO: Add support for potential TOOLBAR
1637 */
1638 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001639gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640{
1641 Point thePoint;
1642 int_u vimModifiers;
1643 short thePortion;
1644 ControlHandle theControl;
1645 int vimMouseButton;
1646 short dblClick;
1647
1648 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001649 GlobalToLocal(&thePoint);
1650 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001652 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653
1654 if (theControl != NUL)
1655 {
1656 /* We hit a scollbar */
1657
1658 if (thePortion != kControlIndicatorPart)
1659 {
1660 dragged_sb = theControl;
1661 TrackControl(theControl, thePoint, gScrollAction);
1662 dragged_sb = NULL;
1663 }
1664 else
1665 {
1666 dragged_sb = theControl;
1667#if 1
1668 TrackControl(theControl, thePoint, gScrollDrag);
1669#else
1670 TrackControl(theControl, thePoint, NULL);
1671#endif
1672 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1673 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001674 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675 dragged_sb = NULL;
1676 }
1677 }
1678 else
1679 {
1680 /* We are inside the contents */
1681
1682 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1683 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1684
1685 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1686 vimMouseButton = MOUSE_LEFT;
1687
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001689 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 clickIsPopup = FALSE;
1691
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001692 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1693 {
1694 vimMouseButton = MOUSE_RIGHT;
1695 vimModifiers &= ~MOUSE_CTRL;
1696 clickIsPopup = TRUE;
1697 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698
1699 /* Is it a double click ? */
1700 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1701
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001702 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 gui_send_mouse_event(vimMouseButton, thePoint.h,
1704 thePoint.v, dblClick, vimModifiers);
1705
1706 /* Create the rectangle around the cursor to detect
1707 * the mouse dragging
1708 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709#if 0
1710 /* TODO: Do we need to this even for the contextual menu?
1711 * It may be require for popup_setpos, but for popup?
1712 */
1713 if (vimMouseButton == MOUSE_LEFT)
1714#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001716 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 FILL_Y(Y_2_ROW(thePoint.v)),
1718 FILL_X(X_2_COL(thePoint.h)+1),
1719 FILL_Y(Y_2_ROW(thePoint.v)+1));
1720
1721 dragRectEnbl = TRUE;
1722 dragRectControl = kCreateRect;
1723 }
1724 }
1725}
1726
1727/*
1728 * Handle the click in the titlebar (to move the window)
1729 */
1730 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001731gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732{
1733 Rect movingLimits;
1734 Rect *movingLimitsPtr = &movingLimits;
1735
1736 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001737 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001738 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739}
1740
1741/*
1742 * Handle the click in the grow box
1743 */
1744 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001745gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746{
1747
1748 long newSize;
1749 unsigned short newWidth;
1750 unsigned short newHeight;
1751 Rect resizeLimits;
1752 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753 Rect NewContentRect;
1754
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001755 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756
Bram Moolenaar720c7102007-05-10 18:07:50 +00001757 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758 /* TODO: Should this come from Vim? */
1759 resizeLimits.top = 100;
1760 resizeLimits.left = 100;
1761
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1763 newWidth = NewContentRect.right - NewContentRect.left;
1764 newHeight = NewContentRect.bottom - NewContentRect.top;
1765 gui_resize_shell(newWidth, newHeight);
1766 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001767 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768}
1769
1770/*
1771 * Handle the click in the zoom box
1772 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001774gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775{
1776 Rect r;
1777 Point p;
1778 short thePart;
1779
1780 /* ideal width is current */
1781 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1782 if (gui.which_scrollbars[SBAR_LEFT])
1783 p.h += gui.scrollbar_width;
1784 if (gui.which_scrollbars[SBAR_RIGHT])
1785 p.h += gui.scrollbar_width;
1786 /* ideal height is as heigh as we can get */
1787 p.v = 15 * 1024;
1788
1789 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1790 ? inZoomIn : inZoomOut;
1791
1792 if (!TrackBox(whichWindow, theEvent->where, thePart))
1793 return;
1794
1795 /* use returned width */
1796 p.h = r.right - r.left;
1797 /* adjust returned height */
1798 p.v = r.bottom - r.top - 2 * gui.border_offset;
1799 if (gui.which_scrollbars[SBAR_BOTTOM])
1800 p.v -= gui.scrollbar_height;
1801 p.v -= p.v % gui.char_height;
1802 p.v += 2 * gui.border_width;
1803 if (gui.which_scrollbars[SBAR_BOTTOM]);
1804 p.v += gui.scrollbar_height;
1805
1806 ZoomWindowIdeal(whichWindow, thePart, &p);
1807
1808 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1809 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1810 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001811 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813
1814/*
1815 * ------------------------------------------------------------
1816 * MacOS Event Handling procedure
1817 * ------------------------------------------------------------
1818 */
1819
1820/*
1821 * Handle the Update Event
1822 */
1823
1824 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001825gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826{
1827 WindowPtr whichWindow;
1828 GrafPtr savePort;
1829 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 Rect *updateRectPtr;
1832 Rect rc;
1833 Rect growRect;
1834 RgnHandle saveRgn;
1835
1836
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 updateRgn = NewRgn();
1838 if (updateRgn == NULL)
1839 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840
1841 /* This could be done by the caller as we
1842 * don't require anything else out of the event
1843 */
1844 whichWindow = (WindowPtr) event->message;
1845
1846 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001847 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001850 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851
1852 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001853 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 /* Redraw the biggest rectangle covering the area
1855 * to be updated.
1856 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1858# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001859 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 * seem to work under MacOS X (Dany)
1861 */
1862 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1863# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001864
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001866 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001867
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001868 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869# if 0
1870 /* Code from original Carbon Port (using GetWindowRegion.
1871 * I believe the UpdateRgn is already in local (Dany)
1872 */
1873 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1874 GlobalToLocal(&botRight(updateRect));
1875# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 /* Update the content (i.e. the text) */
1877 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1878 updateRectPtr->right - updateRectPtr->left,
1879 updateRectPtr->bottom - updateRectPtr->top);
1880 /* Clear the border areas if needed */
1881 gui_mch_set_bg_color(gui.back_pixel);
1882 if (updateRectPtr->left < FILL_X(0))
1883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001884 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1885 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 }
1887 if (updateRectPtr->top < FILL_Y(0))
1888 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1890 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 }
1892 if (updateRectPtr->right > FILL_X(Columns))
1893 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001894 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001896 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 }
1898 if (updateRectPtr->bottom > FILL_Y(Rows))
1899 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001900 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001902 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001904 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001905 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906
1907 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001908 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909
1910 /* Update the GrowBox */
1911 /* Taken from FAQ 33-27 */
1912 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001914 GetClip(saveRgn);
1915 ClipRect(&growRect);
1916 DrawGrowIcon(whichWindow);
1917 SetClip(saveRgn);
1918 DisposeRgn(saveRgn);
1919 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920
1921 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001922 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923}
1924
1925/*
1926 * Handle the activate/deactivate event
1927 * (apply to a window)
1928 */
1929 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001930gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931{
1932 WindowPtr whichWindow;
1933
1934 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001935 /* Dim scrollbars */
1936 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 {
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001938 ControlRef rootControl;
1939 GetRootControl(gui.VimWindow, &rootControl);
1940 if ((event->modifiers) & activeFlag)
1941 ActivateControl(rootControl);
1942 else
1943 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001945
1946 /* Activate */
1947 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948}
1949
1950
1951/*
1952 * Handle the suspend/resume event
1953 * (apply to the application)
1954 */
1955 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001956gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957{
1958 /* The frontmost application just changed */
1959
1960 /* NOTE: the suspend may happen before the deactivate
1961 * seen on MacOS X
1962 */
1963
1964 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00001965 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 */
1967 if (event->message & 1)
1968 /* Resume */
1969 gui_focus_change(TRUE);
1970 else
1971 /* Suspend */
1972 gui_focus_change(FALSE);
1973}
1974
1975/*
1976 * Handle the key
1977 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001978#ifdef USE_CARBONKEYHANDLER
Bram Moolenaard68071d2006-05-02 22:08:30 +00001979
1980static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the keys */
1981
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001982# define INLINE_KEY_BUFFER_SIZE 80
1983 static pascal OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001984gui_mac_doKeyEventCarbon(
1985 EventHandlerCallRef nextHandler,
1986 EventRef theEvent,
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001987 void *data)
1988{
1989 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001990 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001991 UInt32 actualSize;
1992 UniChar *text;
1993 char_u result[INLINE_KEY_BUFFER_SIZE];
1994 short len = 0;
1995 UInt32 key_sym;
1996 char charcode;
1997 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00001998 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001999 size_t encLen;
2000 char_u *to = NULL;
2001 Boolean isSpecial = FALSE;
2002 int i;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002003 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002005 /* Mask the mouse (as per user setting) */
2006 if (p_mh)
2007 ObscureCursor();
2008
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002009 /* Don't use the keys when the dialog wants them. */
2010 if (dialog_busy)
2011 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002012
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002013 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
2014 typeUnicodeText, NULL, 0, &actualSize, NULL))
2015 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002016
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002017 text = (UniChar *)alloc(actualSize);
2018 if (!text)
2019 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002020
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002021 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
2022 typeUnicodeText, NULL, actualSize, NULL, text);
2023 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002024
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002025 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
2026 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
2027 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002028
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002029 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
2030 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
2031 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002032
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002033 err = GetEventParameter(keyEvent, kEventParamKeyCode,
2034 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
2035 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002036
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002037 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
2038 typeChar, NULL, sizeof(char), NULL, &charcode);
2039 require_noerr(err, done);
2040
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002041#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002042 if (modifiers & cmdKey)
2043 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002044#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002045
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002046 key_char = charcode;
2047 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002048
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002049 /* Find the special key (eg., for cursor keys) */
2050 if (actualSize <= sizeof(UniChar) &&
2051 ((text[0] < 0x20) || (text[0] == 0x7f)))
2052 {
2053 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2054 if (special_keys[i].key_sym == key_sym)
2055 {
2056 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2057 special_keys[i].vim_code1);
2058 key_char = simplify_key(key_char,
2059 (int *)&vimModifiers);
2060 isSpecial = TRUE;
2061 break;
2062 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002063 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002064
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002065 /* Intercept CMD-. and CTRL-c */
2066 if (((modifiers & controlKey) && key_char == 'c') ||
2067 ((modifiers & cmdKey) && key_char == '.'))
2068 got_int = TRUE;
2069
2070 if (!isSpecial)
2071 {
2072 /* remove SHIFT for keys that are already shifted, e.g.,
2073 * '(' and '*' */
2074 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2075 vimModifiers &= ~MOD_MASK_SHIFT;
2076
2077 /* remove CTRL from keys that already have it */
2078 if (key_char < 0x20)
2079 vimModifiers &= ~MOD_MASK_CTRL;
2080
2081 /* don't process unicode characters here */
2082 if (!IS_SPECIAL(key_char))
2083 {
2084 /* Following code to simplify and consolidate vimModifiers
2085 * taken liberally from gui_w48.c */
2086 key_char = simplify_key(key_char, (int *)&vimModifiers);
2087
2088 /* Interpret META, include SHIFT, etc. */
2089 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2090 if (key_char == CSI)
2091 key_char = K_CSI;
2092
2093 if (IS_SPECIAL(key_char))
2094 isSpecial = TRUE;
2095 }
2096 }
2097
2098 if (vimModifiers)
2099 {
2100 result[len++] = CSI;
2101 result[len++] = KS_MODIFIER;
2102 result[len++] = vimModifiers;
2103 }
2104
2105 if (isSpecial && IS_SPECIAL(key_char))
2106 {
2107 result[len++] = CSI;
2108 result[len++] = K_SECOND(key_char);
2109 result[len++] = K_THIRD(key_char);
2110 }
2111 else
2112 {
2113 encLen = actualSize;
2114 to = mac_utf16_to_enc(text, actualSize, &encLen);
2115 if (to)
2116 {
2117 /* This is basically add_to_input_buf_csi() */
2118 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2119 {
2120 result[len++] = to[i];
2121 if (to[i] == CSI)
2122 {
2123 result[len++] = KS_EXTRA;
2124 result[len++] = (int)KE_CSI;
2125 }
2126 }
2127 vim_free(to);
2128 }
2129 }
2130
2131 add_to_input_buf(result, len);
2132 err = noErr;
2133
2134done:
2135 vim_free(text);
2136 if (err == noErr)
2137 {
2138 /* Fake event to wake up WNE (required to get
2139 * key repeat working */
2140 PostEvent(keyUp, 0);
2141 return noErr;
2142 }
2143
2144 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002145}
2146#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 void
2148gui_mac_doKeyEvent(EventRecord *theEvent)
2149{
2150 /* TODO: add support for COMMAND KEY */
2151 long menu;
2152 unsigned char string[20];
2153 short num, i;
2154 short len = 0;
2155 KeySym key_sym;
2156 int key_char;
2157 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002158 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159
2160 /* Mask the mouse (as per user setting) */
2161 if (p_mh)
2162 ObscureCursor();
2163
2164 /* Get the key code and it's ASCII representation */
2165 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2166 key_char = theEvent->message & charCodeMask;
2167 num = 1;
2168
2169 /* Intercept CTRL-C */
2170 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 if (key_char == Ctrl_C && ctrl_c_interrupts)
2173 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002174 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2175 && (key_char == '2' || key_char == '6'))
2176 {
2177 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2178 if (key_char == '2')
2179 key_char = Ctrl_AT;
2180 else
2181 key_char = Ctrl_HAT;
2182 theEvent->modifiers = 0;
2183 }
2184 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185
2186 /* Intercept CMD-. */
2187 if (theEvent->modifiers & cmdKey)
2188 if (key_char == '.')
2189 got_int = TRUE;
2190
2191 /* Handle command key as per menu */
2192 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2193 if (theEvent->modifiers & cmdKey)
2194 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2195 * Why the mouse button? */
2196 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2197 {
2198 menu = MenuKey(key_char);
2199 if (HiWord(menu))
2200 {
2201 gui_mac_handle_menu(menu);
2202 return;
2203 }
2204 }
2205
2206 /* Convert the modifiers */
2207 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2208
2209
2210 /* Handle special keys. */
2211#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002212 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002213 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2214#endif
2215 {
2216 /* Find the special key (for non-printable keyt_char) */
2217 if ((key_char < 0x20) || (key_char == 0x7f))
2218 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2219 if (special_keys[i].key_sym == key_sym)
2220 {
2221# if 0
2222 /* We currently don't have not so special key */
2223 if (special_keys[i].vim_code1 == NUL)
2224 key_char = special_keys[i].vim_code0;
2225 else
2226# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002227 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2228 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002229 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230 break;
2231 }
2232 }
2233
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002234 /* For some keys the modifier is included in the char itself. */
2235 if (simplify || key_char == TAB || key_char == ' ')
2236 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237
2238 /* Add the modifier to the input bu if needed */
2239 /* Do not want SHIFT-A or CTRL-A with modifier */
2240 if (!IS_SPECIAL(key_char)
2241 && key_sym != vk_Space
2242 && key_sym != vk_Tab
2243 && key_sym != vk_Return
2244 && key_sym != vk_Enter
2245 && key_sym != vk_Esc)
2246 {
2247#if 1
2248 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002249 if ((modifiers == MOD_MASK_SHIFT)
2250 || (modifiers == MOD_MASK_CTRL)
2251 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 modifiers = 0;
2253#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002254 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002256 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002258 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 modifiers = modifiers & ~MOD_MASK_SHIFT;
2260#endif
2261 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002262 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002264 string[len++] = CSI;
2265 string[len++] = KS_MODIFIER;
2266 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 }
2268
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002269 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002271 string[len++] = CSI;
2272 string[len++] = K_SECOND(key_char);
2273 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 }
2275 else
2276 {
2277#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002278 /* Convert characters when needed (e.g., from MacRoman to latin1).
2279 * This doesn't work for the NUL byte. */
2280 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281 {
2282 char_u from[2], *to;
2283 int l;
2284
2285 from[0] = key_char;
2286 from[1] = NUL;
2287 l = 1;
2288 to = string_convert(&input_conv, from, &l);
2289 if (to != NULL)
2290 {
2291 for (i = 0; i < l && len < 19; i++)
2292 {
2293 if (to[i] == CSI)
2294 {
2295 string[len++] = KS_EXTRA;
2296 string[len++] = KE_CSI;
2297 }
2298 else
2299 string[len++] = to[i];
2300 }
2301 vim_free(to);
2302 }
2303 else
2304 string[len++] = key_char;
2305 }
2306 else
2307#endif
2308 string[len++] = key_char;
2309 }
2310
2311 if (len == 1 && string[0] == CSI)
2312 {
2313 /* Turn CSI into K_CSI. */
2314 string[ len++ ] = KS_EXTRA;
2315 string[ len++ ] = KE_CSI;
2316 }
2317
2318 add_to_input_buf(string, len);
2319}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002320#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321
2322/*
2323 * Handle MouseClick
2324 */
2325 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002326gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327{
2328 short thePart;
2329 WindowPtr whichWindow;
2330
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002331 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002333#ifdef FEAT_GUI_TABLINE
2334 /* prevent that the vim window size changes if it's activated by a
2335 click into the tab pane */
2336 if (whichWindow == drawer)
2337 return;
2338#endif
2339
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 switch (thePart)
2341 {
2342 case (inDesk):
2343 /* TODO: what to do? */
2344 break;
2345
2346 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002347 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 break;
2349
2350 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002351 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 break;
2353
2354 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002355 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002356 break;
2357
2358 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002359 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 break;
2361
2362 case (inGoAway):
2363 if (TrackGoAway(whichWindow, theEvent->where))
2364 gui_shell_closed();
2365 break;
2366
2367 case (inZoomIn):
2368 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 break;
2371 }
2372}
2373
2374/*
2375 * Handle MouseMoved
2376 * [this event is a moving in and out of a region]
2377 */
2378 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002379gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380{
2381 Point thePoint;
2382 int_u vimModifiers;
2383
2384 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002385 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2387
2388 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002389 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2393 thePoint.v, FALSE, vimModifiers);
2394
2395 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002396 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 FILL_Y(Y_2_ROW(thePoint.v)),
2398 FILL_X(X_2_COL(thePoint.h)+1),
2399 FILL_Y(Y_2_ROW(thePoint.v)+1));
2400
2401 if (dragRectEnbl)
2402 dragRectControl = kCreateRect;
2403
2404}
2405
2406/*
2407 * Handle the mouse release
2408 */
2409 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002410gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411{
2412 Point thePoint;
2413 int_u vimModifiers;
2414
2415 /* TODO: Properly convert the Contextual menu mouse-up */
2416 /* Potential source of the double menu */
2417 lastMouseTick = theEvent->when;
2418 dragRectEnbl = FALSE;
2419 dragRectControl = kCreateEmpty;
2420 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002421 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422
2423 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424 if (clickIsPopup)
2425 {
2426 vimModifiers &= ~MOUSE_CTRL;
2427 clickIsPopup = FALSE;
2428 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002429 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430}
2431
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 static pascal OSStatus
2433gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2434 void *data)
2435{
2436 EventRef bogusEvent;
2437 Point point;
2438 Rect bounds;
2439 UInt32 mod;
2440 SInt32 delta;
2441 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002442 EventMouseWheelAxis axis;
2443
2444 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2445 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2446 && axis != kEventMouseWheelAxisY)
2447 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448
2449 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2450 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2451 goto bail;
2452 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2453 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2454 goto bail;
2455 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2456 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2457 goto bail;
2458
2459 vim_mod = 0;
2460 if (mod & shiftKey)
2461 vim_mod |= MOUSE_SHIFT;
2462 if (mod & controlKey)
2463 vim_mod |= MOUSE_CTRL;
2464 if (mod & optionKey)
2465 vim_mod |= MOUSE_ALT;
2466
2467 /* post a bogus event to wake up WaitNextEvent */
2468 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2469 kEventAttributeNone, &bogusEvent))
2470 goto bail;
2471 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2472 kEventPriorityLow))
2473 goto bail;
2474
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002475 ReleaseEvent(bogusEvent);
2476
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2478 {
2479 point.h -= bounds.left;
2480 point.v -= bounds.top;
2481 }
2482
2483 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2484 point.h, point.v, FALSE, vim_mod);
2485
2486 return noErr;
2487
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002488bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 /*
2490 * when we fail give any additional callback handler a chance to perform
2491 * it's actions
2492 */
2493 return CallNextEventHandler(nextHandler, theEvent);
2494}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495
2496#if 0
2497
2498/*
2499 * This would be the normal way of invoking the contextual menu
2500 * but the Vim API doesn't seem to a support a request to get
2501 * the menu that we should display
2502 */
2503 void
2504gui_mac_handle_contextual_menu(event)
2505 EventRecord *event;
2506{
2507/*
2508 * Clone PopUp to use menu
2509 * Create a object descriptor for the current selection
2510 * Call the procedure
2511 */
2512
2513// Call to Handle Popup
2514 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2515
2516 if (status != noErr)
2517 return;
2518
2519 if (CntxType == kCMMenuItemSelected)
2520 {
2521 /* Handle the menu CntxMenuID, CntxMenuItem */
2522 /* The submenu can be handle directly by gui_mac_handle_menu */
2523 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002524 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 }
2526 else if (CntxMenuID == kCMShowHelpSelected)
2527 {
2528 /* Should come up with the help */
2529 }
2530
2531}
2532#endif
2533
2534/*
2535 * Handle menubar selection
2536 */
2537 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002538gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539{
2540 short menu = HiWord(menuChoice);
2541 short item = LoWord(menuChoice);
2542 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543
2544 if (menu == 256) /* TODO: use constant or gui.xyz */
2545 {
2546 if (item == 1)
2547 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 }
2549 else if (item != 0)
2550 {
2551 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2552
2553 if (theVimMenu)
2554 gui_menu_cb(theVimMenu);
2555 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002556 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557}
2558
2559/*
2560 * Dispatch the event to proper handler
2561 */
2562
2563 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002564gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565{
2566 OSErr error;
2567
2568 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002569 if (IsShowContextualMenuClick(event))
2570 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571# if 0
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002572 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573# else
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002574 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575# endif
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002576 return;
2577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578
2579 /* Handle normal event */
2580 switch (event->what)
2581 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002582#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 case (keyDown):
2584 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002585 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002587#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002589 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 break;
2591
2592 case (mouseDown):
2593 gui_mac_doMouseDownEvent(event);
2594 break;
2595
2596 case (mouseUp):
2597 gui_mac_doMouseUpEvent(event);
2598 break;
2599
2600 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002601 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 break;
2603
2604 case (diskEvt):
2605 /* We don't need special handling for disk insertion */
2606 break;
2607
2608 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002609 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 break;
2611
2612 case (osEvt):
2613 switch ((event->message >> 24) & 0xFF)
2614 {
2615 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002616 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 break;
2618 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002619 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 break;
2621 }
2622 break;
2623
2624#ifdef USE_AEVENT
2625 case (kHighLevelEvent):
2626 /* Someone's talking to us, through AppleEvents */
2627 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2628 break;
2629#endif
2630 }
2631}
2632
2633/*
2634 * ------------------------------------------------------------
2635 * Unknown Stuff
2636 * ------------------------------------------------------------
2637 */
2638
2639
2640 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002641gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642{
2643 char_u c;
2644 char_u *p;
2645 char_u pFontName[256];
2646 Str255 systemFontname;
2647 short font_id;
2648 short size=9;
2649 GuiFont font;
2650#if 0
2651 char_u *fontNamePtr;
2652#endif
2653
2654 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2655 ;
2656
2657 c = *p;
2658 *p = 0;
2659
2660#if 1
2661 STRCPY(&pFontName[1], font_name);
2662 pFontName[0] = STRLEN(font_name);
2663 *p = c;
2664
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002665 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002666 char_u fontName[256];
2667 char_u *styleStart = vim_strchr(font_name, ':');
2668 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2669 vim_strncpy(fontName, font_name, fontNameLen);
2670
2671 ATSUFontID fontRef;
2672 FMFontStyle fontStyle;
2673 font_id = 0;
2674
2675 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2676 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2677 &fontRef) == noErr)
2678 {
2679 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2680 font_id = 0;
2681 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002682
2683 if (font_id == 0)
2684 {
2685 /*
2686 * Try again, this time replacing underscores in the font name
2687 * with spaces (:set guifont allows the two to be used
2688 * interchangeably; the Font Manager doesn't).
2689 */
2690 int i, changed = FALSE;
2691
2692 for (i = pFontName[0]; i > 0; --i)
2693 {
2694 if (pFontName[i] == '_')
2695 {
2696 pFontName[i] = ' ';
2697 changed = TRUE;
2698 }
2699 }
2700 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002701 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2702 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2703 kFontNoLanguageCode, &fontRef) == noErr)
2704 {
2705 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2706 font_id = 0;
2707 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002708 }
2709
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710#else
2711 /* name = C2Pascal_save(menu->dname); */
2712 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2713
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002714 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715#endif
2716
2717
2718 if (font_id == 0)
2719 {
2720 /* Oups, the system font was it the one the user want */
2721
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002722 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2723 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 if (!EqualString(pFontName, systemFontname, false, false))
2725 return NOFONT;
2726 }
2727 if (*p == ':')
2728 {
2729 p++;
2730 /* Set the values found after ':' */
2731 while (*p)
2732 {
2733 switch (*p++)
2734 {
2735 case 'h':
2736 size = points_to_pixels(p, &p, TRUE);
2737 break;
2738 /*
2739 * TODO: Maybe accept width and styles
2740 */
2741 }
2742 while (*p == ':')
2743 p++;
2744 }
2745 }
2746
2747 if (size < 1)
2748 size = 1; /* Avoid having a size of 0 with system font */
2749
2750 font = (size << 16) + ((long) font_id & 0xFFFF);
2751
2752 return font;
2753}
2754
2755/*
2756 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002757 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758 * ------------------------------------------------------------
2759 */
2760
2761/*
2762 * Parse the GUI related command-line arguments. Any arguments used are
2763 * deleted from argv, and *argc is decremented accordingly. This is called
2764 * when vim is started, whether or not the GUI has been started.
2765 */
2766 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002767gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768{
2769 /* TODO: Move most of this stuff toward gui_mch_init */
2770#ifdef USE_EXE_NAME
2771 FSSpec applDir;
2772# ifndef USE_FIND_BUNDLE_PATH
2773 short applVRefNum;
2774 long applDirID;
2775 Str255 volName;
2776# else
2777 ProcessSerialNumber psn;
2778 FSRef applFSRef;
2779# endif
2780#endif
2781
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782#if 0
2783 InitCursor();
2784
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786
2787#ifdef USE_AEVENT
2788 (void) InstallAEHandlers();
2789#endif
2790
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002791 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002793 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002795 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796
2797 DrawMenuBar();
2798
2799
2800#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002801 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002803 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804#endif
2805
2806
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 CreateNewWindow(kDocumentWindowClass,
2808 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002809 &windRect, &gui.VimWindow);
2810 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811
2812 gui.char_width = 7;
2813 gui.char_height = 11;
2814 gui.char_ascent = 6;
2815 gui.num_rows = 24;
2816 gui.num_cols = 80;
2817 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2818
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002819 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2820 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821
2822 dragRectEnbl = FALSE;
2823 dragRgn = NULL;
2824 dragRectControl = kCreateEmpty;
2825 cursorRgn = NewRgn();
2826#endif
2827#ifdef USE_EXE_NAME
2828# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002829 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002831 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832# else
2833 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2834 * of TN2015
2835 * This technic remove the ../Contents/MacOS/etc part
2836 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002837 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838 /* if (err != noErr) return err; */
2839
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002840 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 /* if (err != noErr) return err; */
2842
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002843 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844
2845 /* This technic return NIL when we disallow_gui */
2846# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002847 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849}
2850
2851#ifndef ALWAYS_USE_GUI
2852/*
2853 * Check if the GUI can be started. Called before gvimrc is sourced.
2854 * Return OK or FAIL.
2855 */
2856 int
2857gui_mch_init_check(void)
2858{
2859 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2860 * using the >console
2861 */
2862 if (disallow_gui) /* see main.c for reason to disallow */
2863 return FAIL;
2864 return OK;
2865}
2866#endif
2867
2868 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002869receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870{
2871 int x, y;
2872 int_u modifiers;
2873 char_u **fnames = NULL;
2874 int count;
2875 int i, j;
2876
2877 /* Get drop position, modifiers and count of items */
2878 {
2879 Point point;
2880 SInt16 mouseUpModifiers;
2881 UInt16 countItem;
2882
2883 GetDragMouse(theDrag, &point, NULL);
2884 GlobalToLocal(&point);
2885 x = point.h;
2886 y = point.v;
2887 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2888 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2889 CountDragItems(theDrag, &countItem);
2890 count = countItem;
2891 }
2892
2893 fnames = (char_u **)alloc(count * sizeof(char_u *));
2894 if (fnames == NULL)
2895 return dragNotAcceptedErr;
2896
2897 /* Get file names dropped */
2898 for (i = j = 0; i < count; ++i)
2899 {
2900 DragItemRef item;
2901 OSErr err;
2902 Size size;
2903 FlavorType type = flavorTypeHFS;
2904 HFSFlavor hfsFlavor;
2905
2906 fnames[i] = NULL;
2907 GetDragItemReferenceNumber(theDrag, i + 1, &item);
2908 err = GetFlavorDataSize(theDrag, item, type, &size);
2909 if (err != noErr || size > sizeof(hfsFlavor))
2910 continue;
2911 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
2912 if (err != noErr)
2913 continue;
2914 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
2915 }
2916 count = j;
2917
2918 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002919
2920 /* Fake mouse event to wake from stall */
2921 PostEvent(mouseUp, 0);
2922
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 return noErr;
2924}
2925
2926/*
2927 * Initialise the GUI. Create all the windows, set up all the call-backs
2928 * etc.
2929 */
2930 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002931gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932{
2933 /* TODO: Move most of this stuff toward gui_mch_init */
2934 Rect windRect;
2935 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 EventTypeSpec eventTypeSpec;
2937 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002938#ifdef USE_CARBONKEYHANDLER
2939 EventHandlerRef keyEventHandlerRef;
2940#endif
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002941 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002942
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002943 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002944 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002945
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946#if 1
2947 InitCursor();
2948
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950
2951#ifdef USE_AEVENT
2952 (void) InstallAEHandlers();
2953#endif
2954
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002955 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002956
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002957 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002959 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960
2961 DrawMenuBar();
2962
2963
2964#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002965 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002967 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002968#endif
2969
2970 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002971 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002973 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
2975 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002976 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002977
2978 gui.char_width = 7;
2979 gui.char_height = 11;
2980 gui.char_ascent = 6;
2981 gui.num_rows = 24;
2982 gui.num_cols = 80;
2983 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2984
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002985 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2986 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002988 /* Install Carbon event callbacks. */
2989 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990
2991 dragRectEnbl = FALSE;
2992 dragRgn = NULL;
2993 dragRectControl = kCreateEmpty;
2994 cursorRgn = NewRgn();
2995#endif
2996 /* Display any pending error messages */
2997 display_errors();
2998
2999 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003000 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001 gui.norm_pixel = 0x00000000;
3002 gui.back_pixel = 0x00FFFFFF;
3003
3004 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3005 * file). */
3006 set_normal_colors();
3007
3008 /*
3009 * Check that none of the colors are the same as the background color.
3010 * Then store the current values as the defaults.
3011 */
3012 gui_check_colors();
3013 gui.def_norm_pixel = gui.norm_pixel;
3014 gui.def_back_pixel = gui.back_pixel;
3015
3016 /* Get the colors for the highlight groups (gui_check_colors() might have
3017 * changed them) */
3018 highlight_gui_started();
3019
3020 /*
3021 * Setting the gui constants
3022 */
3023#ifdef FEAT_MENU
3024 gui.menu_height = 0;
3025#endif
3026 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3027 gui.border_offset = gui.border_width = 2;
3028
Bram Moolenaar720c7102007-05-10 18:07:50 +00003029 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 gui_mch_draw_string() below), enable it for all font sizes. */
3031 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033 eventTypeSpec.eventClass = kEventClassMouse;
3034 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3035 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3036 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3037 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3038 {
3039 mouseWheelHandlerRef = NULL;
3040 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3041 mouseWheelHandlerUPP = NULL;
3042 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003044#ifdef USE_CARBONKEYHANDLER
3045 eventTypeSpec.eventClass = kEventClassTextInput;
3046 eventTypeSpec.eventKind = kEventUnicodeForKeyEvent;
3047 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_doKeyEventCarbon);
3048 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP, 1,
3049 &eventTypeSpec, NULL, &keyEventHandlerRef))
3050 {
3051 keyEventHandlerRef = NULL;
3052 DisposeEventHandlerUPP(keyEventHandlerUPP);
3053 keyEventHandlerUPP = NULL;
3054 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055#endif
3056
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003057/*
3058#ifdef FEAT_MBYTE
3059 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3060#endif
3061*/
3062
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003063#ifdef FEAT_GUI_TABLINE
3064 /*
3065 * Create the tabline
3066 */
3067 initialise_tabline();
3068#endif
3069
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 /* TODO: Load bitmap if using TOOLBAR */
3071 return OK;
3072}
3073
3074/*
3075 * Called when the foreground or background color has been changed.
3076 */
3077 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003078gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079{
3080 /* TODO:
3081 * This proc is called when Normal is set to a value
3082 * so what msut be done? I don't know
3083 */
3084}
3085
3086/*
3087 * Open the GUI window which was created by a call to gui_mch_init().
3088 */
3089 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003090gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003091{
3092 ShowWindow(gui.VimWindow);
3093
3094 if (gui_win_x != -1 && gui_win_y != -1)
3095 gui_mch_set_winpos(gui_win_x, gui_win_y);
3096
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097 /*
3098 * Make the GUI the foreground process (in case it was launched
3099 * from the Terminal or via :gui).
3100 */
3101 {
3102 ProcessSerialNumber psn;
3103 if (GetCurrentProcess(&psn) == noErr)
3104 SetFrontProcess(&psn);
3105 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106
3107 return OK;
3108}
3109
3110 void
3111gui_mch_exit(int rc)
3112{
3113 /* TODO: find out all what is missing here? */
3114 DisposeRgn(cursorRgn);
3115
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003116#ifdef USE_CARBONKEYHANDLER
3117 if (keyEventHandlerUPP)
3118 DisposeEventHandlerUPP(keyEventHandlerUPP);
3119#endif
3120
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121 if (mouseWheelHandlerUPP != NULL)
3122 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003124#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003125 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003126 ATSUDisposeStyle(gFontStyle);
3127#endif
3128
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 /* Exit to shell? */
3130 exit(rc);
3131}
3132
3133/*
3134 * Get the position of the top left corner of the window.
3135 */
3136 int
3137gui_mch_get_winpos(int *x, int *y)
3138{
3139 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003140 Rect bounds;
3141 OSStatus status;
3142
3143 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003144 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145
3146 if (status != noErr)
3147 return FAIL;
3148 *x = bounds.left;
3149 *y = bounds.top;
3150 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151 return FAIL;
3152}
3153
3154/*
3155 * Set the position of the top left corner of the window to the given
3156 * coordinates.
3157 */
3158 void
3159gui_mch_set_winpos(int x, int y)
3160{
3161 /* TODO: Should make sure the window is move within range
3162 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3163 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003164 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165}
3166
3167 void
3168gui_mch_set_shellsize(
3169 int width,
3170 int height,
3171 int min_width,
3172 int min_height,
3173 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003174 int base_height,
3175 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003177 CGrafPtr VimPort;
3178 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179
3180 if (gui.which_scrollbars[SBAR_LEFT])
3181 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003182 VimPort = GetWindowPort(gui.VimWindow);
3183 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003185 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 }
3188 else
3189 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003190 VimPort = GetWindowPort(gui.VimWindow);
3191 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003193 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194 }
3195
3196 SizeWindow(gui.VimWindow, width, height, TRUE);
3197
3198 gui_resize_shell(width, height);
3199}
3200
3201/*
3202 * Get the screen dimensions.
3203 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3204 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003205 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206 */
3207 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003208gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210 GDHandle dominantDevice = GetMainDevice();
3211 Rect screenRect = (**dominantDevice).gdRect;
3212
3213 *screen_w = screenRect.right - 10;
3214 *screen_h = screenRect.bottom - 40;
3215}
3216
3217
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003218/*
3219 * Open the Font Panel and wait for the user to select a font and
3220 * close the panel. Then fill the buffer pointed to by font_name with
3221 * the name and size of the selected font and return the font's handle,
3222 * or NOFONT in case of an error.
3223 */
3224 static GuiFont
3225gui_mac_select_font(char_u *font_name)
3226{
3227 GuiFont selected_font = NOFONT;
3228 OSStatus status;
3229 FontSelectionQDStyle curr_font;
3230
3231 /* Initialize the Font Panel with the current font. */
3232 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3233 curr_font.size = (gui.norm_font >> 16);
3234 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3235 curr_font.instance.fontStyle = 0;
3236 curr_font.hasColor = false;
3237 curr_font.version = 0; /* version number of the style structure */
3238 status = SetFontInfoForSelection(kFontSelectionQDType,
3239 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3240
3241 gFontPanelInfo.family = curr_font.instance.fontFamily;
3242 gFontPanelInfo.style = curr_font.instance.fontStyle;
3243 gFontPanelInfo.size = curr_font.size;
3244
3245 /* Pop up the Font Panel. */
3246 status = FPShowHideFontPanel();
3247 if (status == noErr)
3248 {
3249 /*
3250 * The Font Panel is modeless. We really need it to be modal,
3251 * so we spin in an event loop until the panel is closed.
3252 */
3253 gFontPanelInfo.isPanelVisible = true;
3254 while (gFontPanelInfo.isPanelVisible)
3255 {
3256 EventRecord e;
3257 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3258 }
3259
3260 GetFontPanelSelection(font_name);
3261 selected_font = gui_mac_find_font(font_name);
3262 }
3263 return selected_font;
3264}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003265
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266
3267/*
3268 * Initialise vim to use the font with the given name. Return FAIL if the font
3269 * could not be loaded, OK otherwise.
3270 */
3271 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003272gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273{
3274 /* TODO: Add support for bold italic underline proportional etc... */
3275 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003276 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 FontInfo font_info;
3278 short font_id;
3279 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003280 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003282#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003283 if (p_macatsui && gFontStyle == NULL)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003284 {
3285 if (ATSUCreateStyle(&gFontStyle) != noErr)
3286 gFontStyle = NULL;
3287 }
3288#endif
3289
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 if (font_name == NULL)
3291 {
3292 /* First try to get the suggested font */
3293 GetFNum(suggestedFont, &font_id);
3294
3295 if (font_id == 0)
3296 {
3297 /* Then pickup the standard application font */
3298 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003299 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003301 else
3302 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3304 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003305 else if (STRCMP(font_name, "*") == 0)
3306 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003307 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003308
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003309 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003310 if (font == NOFONT)
3311 return FAIL;
3312
3313 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003314 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003315 if (new_p_guifont != NULL)
3316 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003317 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003318 vim_free(p_guifont);
3319 p_guifont = new_p_guifont;
3320 /* Replace spaces in the font name with underscores. */
3321 for ( ; *new_p_guifont; ++new_p_guifont)
3322 {
3323 if (*new_p_guifont == ' ')
3324 *new_p_guifont = '_';
3325 }
3326 }
3327 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 else
3329 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003330 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003331 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332
3333 if (font == NOFONT)
3334 return FAIL;
3335 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003336
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 gui.norm_font = font;
3338
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003339 hl_set_font_name(used_font_name);
3340
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003341 TextSize(font >> 16);
3342 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003344 GetFontInfo(&font_info);
3345
3346 gui.char_ascent = font_info.ascent;
3347 gui.char_width = CharWidth('_');
3348 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3349
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003350#ifdef USE_ATSUI_DRAWING
3351 ATSUFontID fontID;
3352 Fixed fontSize;
3353 ATSStyleRenderingOptions fontOptions;
3354
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003355 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003356 {
3357 fontID = font & 0xFFFF;
3358 fontSize = Long2Fix(font >> 16);
3359
3360 /* No antialiasing by default (do not attempt to touch antialising
3361 * options on pre-Jaguar) */
3362 fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003363 (gMacSystemVersion >= 0x1020) ?
3364 kATSStyleNoAntiAliasing :
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003365 kATSStyleNoOptions;
3366
3367 ATSUAttributeTag attribTags[] =
3368 {
3369 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3370 kATSUMaxATSUITagValue+1
3371 };
3372 ByteCount attribSizes[] =
3373 {
3374 sizeof(ATSUFontID), sizeof(Fixed),
3375 sizeof(ATSStyleRenderingOptions), sizeof font
3376 };
3377 ATSUAttributeValuePtr attribValues[] =
3378 {
3379 &fontID, &fontSize, &fontOptions, &font
3380 };
3381
3382 /* Convert font id to ATSUFontID */
3383 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3384 {
3385 if (ATSUSetAttributes(gFontStyle,
3386 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3387 attribTags, attribSizes, attribValues) != noErr)
3388 {
3389 ATSUDisposeStyle(gFontStyle);
3390 gFontStyle = NULL;
3391 }
3392 }
3393 }
3394#endif
3395
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397}
3398
Bram Moolenaar02743632005-07-25 20:42:36 +00003399/*
3400 * Adjust gui.char_height (after 'linespace' was changed).
3401 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003403gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404{
3405 FontInfo font_info;
3406
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003407 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003408 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3409 gui.char_ascent = font_info.ascent + p_linespace / 2;
3410 return OK;
3411}
3412
3413/*
3414 * Get a font structure for highlighting.
3415 */
3416 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003417gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418{
3419 GuiFont font;
3420
3421 font = gui_mac_find_font(name);
3422
3423 if (font == NOFONT)
3424 {
3425 if (giveErrorIfMissing)
3426 EMSG2(_(e_font), name);
3427 return NOFONT;
3428 }
3429 /*
3430 * TODO : Accept only monospace
3431 */
3432
3433 return font;
3434}
3435
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003436#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003438 * Return the name of font "font" in allocated memory.
3439 * Don't know how to get the actual name, thus use the provided name.
3440 */
3441 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003442gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003443{
3444 if (name == NULL)
3445 return NULL;
3446 return vim_strsave(name);
3447}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003448#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003449
3450/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451 * Set the current text font.
3452 */
3453 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003454gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003456#ifdef USE_ATSUI_DRAWING
3457 GuiFont currFont;
3458 ByteCount actualFontByteCount;
3459 ATSUFontID fontID;
3460 Fixed fontSize;
3461 ATSStyleRenderingOptions fontOptions;
3462
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003463 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003464 {
3465 /* Avoid setting same font again */
3466 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue+1, sizeof font,
3467 &currFont, &actualFontByteCount) == noErr &&
3468 actualFontByteCount == (sizeof font))
3469 {
3470 if (currFont == font)
3471 return;
3472 }
3473
3474 fontID = font & 0xFFFF;
3475 fontSize = Long2Fix(font >> 16);
3476 /* Respect p_antialias setting only for wide font.
3477 * The reason for doing this at the moment is a bit complicated,
3478 * but it's mainly because a) latin (non-wide) aliased fonts
3479 * look bad in OS X 10.3.x and below (due to a bug in ATS), and
3480 * b) wide multibyte input does not suffer from that problem. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003481 /*fontOptions =
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003482 (p_antialias && (font == gui.wide_font)) ?
3483 kATSStyleNoOptions : kATSStyleNoAntiAliasing;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003484 */
3485 /*fontOptions = kATSStyleAntiAliasing;*/
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003486
3487 ATSUAttributeTag attribTags[] =
3488 {
3489 kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag,
3490 kATSUMaxATSUITagValue+1
3491 };
3492 ByteCount attribSizes[] =
3493 {
3494 sizeof(ATSUFontID), sizeof(Fixed),
3495 sizeof(ATSStyleRenderingOptions), sizeof font
3496 };
3497 ATSUAttributeValuePtr attribValues[] =
3498 {
3499 &fontID, &fontSize, &fontOptions, &font
3500 };
3501
3502 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3503 {
3504 if (ATSUSetAttributes(gFontStyle,
3505 (sizeof attribTags)/sizeof(ATSUAttributeTag),
3506 attribTags, attribSizes, attribValues) != noErr)
3507 {
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003508# ifndef NDEBUG
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003509 fprintf(stderr, "couldn't set font style\n");
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003510# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003511 ATSUDisposeStyle(gFontStyle);
3512 gFontStyle = NULL;
3513 }
3514 }
3515
3516 }
3517
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003518 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003519 {
3520 /* Setup automatic font substitution. The user's guifontwide
3521 * is tried first, then the system tries other fonts. */
3522/*
3523 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3524 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3525 ATSUCreateFontFallbacks(&gFontFallbacks);
3526 ATSUSetObjFontFallbacks(gFontFallbacks, );
3527*/
3528 if (gui.wide_font)
3529 {
3530 ATSUFontID fallbackFonts;
3531 gIsFontFallbackSet = TRUE;
3532
3533 if (FMGetFontFromFontFamilyInstance(
3534 (gui.wide_font & 0xFFFF),
3535 0,
3536 &fallbackFonts,
3537 NULL) == noErr)
3538 {
3539 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID), &fallbackFonts, kATSUSequentialFallbacksPreferred);
3540 }
3541/*
3542 ATSUAttributeValuePtr fallbackValues[] = { };
3543*/
3544 }
3545 }
3546#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547 TextSize(font >> 16);
3548 TextFont(font & 0xFFFF);
3549}
3550
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551/*
3552 * If a font is not going to be used, free its structure.
3553 */
3554 void
3555gui_mch_free_font(font)
3556 GuiFont font;
3557{
3558 /*
3559 * Free font when "font" is not 0.
3560 * Nothing to do in the current implementation, since
3561 * nothing is allocated for each font used.
3562 */
3563}
3564
3565 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003566hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567{
3568 if (isdigit(c))
3569 return c - '0';
3570 c = TOLOWER_ASC(c);
3571 if (c >= 'a' && c <= 'f')
3572 return c - 'a' + 10;
3573 return -1000;
3574}
3575
3576/*
3577 * Return the Pixel value (color) for the given color name. This routine was
3578 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3579 * Programmer's Guide.
3580 * Return INVALCOLOR when failed.
3581 */
3582 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003583gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584{
3585 /* TODO: Add support for the new named color of MacOS 8
3586 */
3587 RGBColor MacColor;
3588// guicolor_T color = 0;
3589
3590 typedef struct guicolor_tTable
3591 {
3592 char *name;
3593 guicolor_T color;
3594 } guicolor_tTable;
3595
3596 /*
3597 * The comment at the end of each line is the source
3598 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3599 */
3600 static guicolor_tTable table[] =
3601 {
3602 {"Black", RGB(0x00, 0x00, 0x00)},
3603 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3604 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3605 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3606 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3607 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3608 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003609 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3610 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3611 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3612 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3613 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3614 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3615 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3616 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3617 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3618 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3619 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3620 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3621 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3622 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3623 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3624 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003625 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3626 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627 {"white", RGB(0xFF, 0xFF, 0xFF)},
3628 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3629 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3630 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3631 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3632 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3633 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3634 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3635 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3636 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3637 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3638 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3639 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3640 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3641 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3642 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3643 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3644 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3645 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003646 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3648 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3649 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3650 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3651 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3652 };
3653
3654 int r, g, b;
3655 int i;
3656
3657 if (name[0] == '#' && strlen((char *) name) == 7)
3658 {
3659 /* Name is in "#rrggbb" format */
3660 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3661 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3662 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3663 if (r < 0 || g < 0 || b < 0)
3664 return INVALCOLOR;
3665 return RGB(r, g, b);
3666 }
3667 else
3668 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003669 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003671 LMGetHiliteRGB(&MacColor);
3672 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 }
3674 /* Check if the name is one of the colors we know */
3675 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3676 if (STRICMP(name, table[i].name) == 0)
3677 return table[i].color;
3678 }
3679
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 /*
3681 * Last attempt. Look in the file "$VIM/rgb.txt".
3682 */
3683 {
3684#define LINE_LEN 100
3685 FILE *fd;
3686 char line[LINE_LEN];
3687 char_u *fname;
3688
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 if (fname == NULL)
3691 return INVALCOLOR;
3692
3693 fd = fopen((char *)fname, "rt");
3694 vim_free(fname);
3695 if (fd == NULL)
3696 return INVALCOLOR;
3697
3698 while (!feof(fd))
3699 {
3700 int len;
3701 int pos;
3702 char *color;
3703
3704 fgets(line, LINE_LEN, fd);
3705 len = strlen(line);
3706
3707 if (len <= 1 || line[len-1] != '\n')
3708 continue;
3709
3710 line[len-1] = '\0';
3711
3712 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3713 if (i != 3)
3714 continue;
3715
3716 color = line + pos;
3717
3718 if (STRICMP(color, name) == 0)
3719 {
3720 fclose(fd);
3721 return (guicolor_T) RGB(r, g, b);
3722 }
3723 }
3724 fclose(fd);
3725 }
3726
3727 return INVALCOLOR;
3728}
3729
3730/*
3731 * Set the current text foreground color.
3732 */
3733 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003734gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735{
3736 RGBColor TheColor;
3737
3738 TheColor.red = Red(color) * 0x0101;
3739 TheColor.green = Green(color) * 0x0101;
3740 TheColor.blue = Blue(color) * 0x0101;
3741
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003742 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743}
3744
3745/*
3746 * Set the current text background color.
3747 */
3748 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003749gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750{
3751 RGBColor TheColor;
3752
3753 TheColor.red = Red(color) * 0x0101;
3754 TheColor.green = Green(color) * 0x0101;
3755 TheColor.blue = Blue(color) * 0x0101;
3756
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003757 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758}
3759
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003760RGBColor specialColor;
3761
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003762/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003763 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003764 */
3765 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003766gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003767{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003768 specialColor.red = Red(color) * 0x0101;
3769 specialColor.green = Green(color) * 0x0101;
3770 specialColor.blue = Blue(color) * 0x0101;
3771}
3772
3773/*
3774 * Draw undercurl at the bottom of the character cell.
3775 */
3776 static void
3777draw_undercurl(int flags, int row, int col, int cells)
3778{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003779 int x;
3780 int offset;
3781 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3782 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003783
3784 RGBForeColor(&specialColor);
3785
3786 offset = val[FILL_X(col) % 8];
3787 MoveTo(FILL_X(col), y - offset);
3788
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003789 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003790 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003791 offset = val[x % 8];
3792 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003793 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003794}
3795
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003796
3797 static void
3798draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003799{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800#ifdef FEAT_MBYTE
3801 char_u *tofree = NULL;
3802
3803 if (output_conv.vc_type != CONV_NONE)
3804 {
3805 tofree = string_convert(&output_conv, s, &len);
3806 if (tofree != NULL)
3807 s = tofree;
3808 }
3809#endif
3810
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 /*
3812 * On OS X, try using Quartz-style text antialiasing.
3813 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003814 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 {
3816 /* Quartz antialiasing is available only in OS 10.2 and later. */
3817 UInt32 qd_flags = (p_antialias ?
3818 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003819 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 }
3821
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003822 /*
3823 * When antialiasing we're using srcOr mode, we have to clear the block
3824 * before drawing the text.
3825 * Also needed when 'linespace' is non-zero to remove the cursor and
3826 * underlining.
3827 * But not when drawing transparently.
3828 * The following is like calling gui_mch_clear_block(row, col, row, col +
3829 * len - 1), but without setting the bg color to gui.back_pixel.
3830 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003831 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003832 && !(flags & DRAW_TRANSP))
3833 {
3834 Rect rc;
3835
3836 rc.left = FILL_X(col);
3837 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003838#ifdef FEAT_MBYTE
3839 /* Multibyte computation taken from gui_w32.c */
3840 if (has_mbyte)
3841 {
3842 int cell_len = 0;
3843 int n;
3844
3845 /* Compute the length in display cells. */
3846 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3847 cell_len += (*mb_ptr2cells)(s + n);
3848 rc.right = FILL_X(col + cell_len);
3849 }
3850 else
3851#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003852 rc.right = FILL_X(col + len) + (col + len == Columns);
3853 rc.bottom = FILL_Y(row + 1);
3854 EraseRect(&rc);
3855 }
3856
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003857 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 {
3859 StyleParameter face;
3860
3861 face = normal;
3862 if (flags & DRAW_BOLD)
3863 face |= bold;
3864 if (flags & DRAW_UNDERL)
3865 face |= underline;
3866 TextFace(face);
3867
3868 /* Quartz antialiasing works only in srcOr transfer mode. */
3869 TextMode(srcOr);
3870
Bram Moolenaar071d4272004-06-13 20:20:40 +00003871 MoveTo(TEXT_X(col), TEXT_Y(row));
3872 DrawText((char*)s, 0, len);
3873 }
3874 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 {
3876 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003877 TextMode(srcCopy);
3878 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879
3880 /* SelectFont(hdc, gui.currFont); */
3881
3882 if (flags & DRAW_TRANSP)
3883 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003884 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 }
3886
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003887 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003888 DrawText((char *)s, 0, len);
3889
3890 if (flags & DRAW_BOLD)
3891 {
3892 TextMode(srcOr);
3893 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
3894 DrawText((char *)s, 0, len);
3895 }
3896
3897 if (flags & DRAW_UNDERL)
3898 {
3899 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
3900 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
3901 }
3902 }
3903
3904 if (flags & DRAW_UNDERC)
3905 draw_undercurl(flags, row, col, len);
3906
3907#ifdef FEAT_MBYTE
3908 vim_free(tofree);
3909#endif
3910}
3911
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003912#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003913
3914 static void
3915draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
3916{
3917 /* ATSUI requires utf-16 strings */
3918 UniCharCount utf16_len;
3919 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
3920 utf16_len /= sizeof(UniChar);
3921
3922 /* - ATSUI automatically antialiases text (Someone)
3923 * - for some reason it does not work... (Jussi) */
3924
3925 /*
3926 * When antialiasing we're using srcOr mode, we have to clear the block
3927 * before drawing the text.
3928 * Also needed when 'linespace' is non-zero to remove the cursor and
3929 * underlining.
3930 * But not when drawing transparently.
3931 * The following is like calling gui_mch_clear_block(row, col, row, col +
3932 * len - 1), but without setting the bg color to gui.back_pixel.
3933 */
3934 if ((flags & DRAW_TRANSP) == 0)
3935 {
3936 Rect rc;
3937
3938 rc.left = FILL_X(col);
3939 rc.top = FILL_Y(row);
3940 /* Multibyte computation taken from gui_w32.c */
3941 if (has_mbyte)
3942 {
3943 int cell_len = 0;
3944 int n;
3945
3946 /* Compute the length in display cells. */
3947 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3948 cell_len += (*mb_ptr2cells)(s + n);
3949 rc.right = FILL_X(col + cell_len);
3950 }
3951 else
3952 rc.right = FILL_X(col + len) + (col + len == Columns);
3953
3954 rc.bottom = FILL_Y(row + 1);
3955 EraseRect(&rc);
3956 }
3957
3958 {
3959 /* Use old-style, non-antialiased QuickDraw text rendering. */
3960 TextMode(srcCopy);
3961 TextFace(normal);
3962
3963 /* SelectFont(hdc, gui.currFont); */
3964
3965 if (flags & DRAW_TRANSP)
3966 {
3967 TextMode(srcOr);
3968 }
3969
3970 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003971 ATSUTextLayout textLayout;
3972
3973 if (ATSUCreateTextLayoutWithTextPtr(tofree,
3974 kATSUFromTextBeginning, kATSUToTextEnd,
3975 utf16_len,
3976 (gFontStyle ? 1 : 0), &utf16_len,
3977 (gFontStyle ? &gFontStyle : NULL),
3978 &textLayout) == noErr)
3979 {
3980 ATSUSetTransientFontMatching(textLayout, TRUE);
3981
3982 ATSUDrawText(textLayout,
3983 kATSUFromTextBeginning, kATSUToTextEnd,
3984 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
3985
3986 ATSUDisposeTextLayout(textLayout);
3987 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 }
3989
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003990 if (flags & DRAW_UNDERC)
3991 draw_undercurl(flags, row, col, len);
3992
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003994}
3995#endif
3996
3997 void
3998gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
3999{
4000#if defined(USE_ATSUI_DRAWING)
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004001 if (p_macatsui)
4002 draw_string_ATSUI(row, col, s, len, flags);
4003 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004005 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006}
4007
4008/*
4009 * Return OK if the key with the termcap name "name" is supported.
4010 */
4011 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004012gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013{
4014 int i;
4015
4016 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4017 if (name[0] == special_keys[i].vim_code0 &&
4018 name[1] == special_keys[i].vim_code1)
4019 return OK;
4020 return FAIL;
4021}
4022
4023 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004024gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004026 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027}
4028
4029 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004030gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031{
4032 /* Do a visual beep by reversing the foreground and background colors */
4033 Rect rc;
4034
4035 /*
4036 * Note: InvertRect() excludes right and bottom of rectangle.
4037 */
4038 rc.left = 0;
4039 rc.top = 0;
4040 rc.right = gui.num_cols * gui.char_width;
4041 rc.bottom = gui.num_rows * gui.char_height;
4042 InvertRect(&rc);
4043
4044 ui_delay((long)msec, TRUE); /* wait for some msec */
4045
4046 InvertRect(&rc);
4047}
4048
4049/*
4050 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4051 */
4052 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004053gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054{
4055 Rect rc;
4056
4057 /*
4058 * Note: InvertRect() excludes right and bottom of rectangle.
4059 */
4060 rc.left = FILL_X(c);
4061 rc.top = FILL_Y(r);
4062 rc.right = rc.left + nc * gui.char_width;
4063 rc.bottom = rc.top + nr * gui.char_height;
4064 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065}
4066
4067/*
4068 * Iconify the GUI window.
4069 */
4070 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004071gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072{
4073 /* TODO: find out what could replace iconify
4074 * -window shade?
4075 * -hide application?
4076 */
4077}
4078
4079#if defined(FEAT_EVAL) || defined(PROTO)
4080/*
4081 * Bring the Vim window to the foreground.
4082 */
4083 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004084gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085{
4086 /* TODO */
4087}
4088#endif
4089
4090/*
4091 * Draw a cursor without focus.
4092 */
4093 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004094gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095{
4096 Rect rc;
4097
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 /*
4099 * Note: FrameRect() excludes right and bottom of rectangle.
4100 */
4101 rc.left = FILL_X(gui.col);
4102 rc.top = FILL_Y(gui.row);
4103 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004104#ifdef FEAT_MBYTE
4105 if (mb_lefthalve(gui.row, gui.col))
4106 rc.right += gui.char_width;
4107#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 rc.bottom = rc.top + gui.char_height;
4109
4110 gui_mch_set_fg_color(color);
4111
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004112 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113}
4114
4115/*
4116 * Draw part of a cursor, only w pixels wide, and h pixels high.
4117 */
4118 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004119gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120{
4121 Rect rc;
4122
4123#ifdef FEAT_RIGHTLEFT
4124 /* vertical line should be on the right of current point */
4125 if (CURSOR_BAR_RIGHT)
4126 rc.left = FILL_X(gui.col + 1) - w;
4127 else
4128#endif
4129 rc.left = FILL_X(gui.col);
4130 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4131 rc.right = rc.left + w;
4132 rc.bottom = rc.top + h;
4133
4134 gui_mch_set_fg_color(color);
4135
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004136 FrameRect(&rc);
4137// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138}
4139
4140
4141
4142/*
4143 * Catch up with any queued X events. This may put keyboard input into the
4144 * input buffer, call resize call-backs, trigger timers etc. If there is
4145 * nothing in the X event queue (& no timers pending), then we return
4146 * immediately.
4147 */
4148 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004149gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150{
4151 /* TODO: find what to do
4152 * maybe call gui_mch_wait_for_chars (0)
4153 * more like look at EventQueue then
4154 * call heart of gui_mch_wait_for_chars;
4155 *
4156 * if (eventther)
4157 * gui_mac_handle_event(&event);
4158 */
4159 EventRecord theEvent;
4160
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004161 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 if (theEvent.what != nullEvent)
4163 gui_mch_wait_for_chars(0);
4164}
4165
4166/*
4167 * Simple wrapper to neglect more easily the time
4168 * spent inside WaitNextEvent while profiling.
4169 */
4170
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 pascal
4172 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004173WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174{
4175 if (((long) sleep) < -1)
4176 sleep = 32767;
4177 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4178}
4179
4180/*
4181 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4182 * from the keyboard.
4183 * wtime == -1 Wait forever.
4184 * wtime == 0 This should never happen.
4185 * wtime > 0 Wait wtime milliseconds for a character.
4186 * Returns OK if a character was found to be available within the given time,
4187 * or FAIL otherwise.
4188 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004190gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191{
4192 EventMask mask = (everyEvent);
4193 EventRecord event;
4194 long entryTick;
4195 long currentTick;
4196 long sleeppyTick;
4197
4198 /* If we are providing life feedback with the scrollbar,
4199 * we don't want to try to wait for an event, or else
4200 * there won't be any life feedback.
4201 */
4202 if (dragged_sb != NULL)
4203 return FAIL;
4204 /* TODO: Check if FAIL is the proper return code */
4205
4206 entryTick = TickCount();
4207
4208 allow_scrollbar = TRUE;
4209
4210 do
4211 {
4212/* if (dragRectControl == kCreateEmpty)
4213 {
4214 dragRgn = NULL;
4215 dragRectControl = kNothing;
4216 }
4217 else*/ if (dragRectControl == kCreateRect)
4218 {
4219 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004220 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 dragRectControl = kNothing;
4222 }
4223 /*
4224 * Don't use gui_mch_update() because then we will spin-lock until a
4225 * char arrives, instead we use WaitNextEventWrp() to hang until an
4226 * event arrives. No need to check for input_buf_full because we are
4227 * returning as soon as it contains a single char.
4228 */
4229 /* TODO: reduce wtime accordinly??? */
4230 if (wtime > -1)
4231 sleeppyTick = 60*wtime/1000;
4232 else
4233 sleeppyTick = 32767;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004234 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004236 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 if (input_available())
4238 {
4239 allow_scrollbar = FALSE;
4240 return OK;
4241 }
4242 }
4243 currentTick = TickCount();
4244 }
4245 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4246
4247 allow_scrollbar = FALSE;
4248 return FAIL;
4249}
4250
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251/*
4252 * Output routines.
4253 */
4254
4255/* Flush any output to the screen */
4256 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004257gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258{
4259 /* TODO: Is anything needed here? */
4260}
4261
4262/*
4263 * Clear a rectangular region of the screen from text pos (row1, col1) to
4264 * (row2, col2) inclusive.
4265 */
4266 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004267gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268{
4269 Rect rc;
4270
4271 /*
4272 * Clear one extra pixel at the far right, for when bold characters have
4273 * spilled over to the next column.
4274 */
4275 rc.left = FILL_X(col1);
4276 rc.top = FILL_Y(row1);
4277 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4278 rc.bottom = FILL_Y(row2 + 1);
4279
4280 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004281 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282}
4283
4284/*
4285 * Clear the whole text window.
4286 */
4287 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004288gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289{
4290 Rect rc;
4291
4292 rc.left = 0;
4293 rc.top = 0;
4294 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4295 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4296
4297 gui_mch_set_bg_color(gui.back_pixel);
4298 EraseRect(&rc);
4299/* gui_mch_set_fg_color(gui.norm_pixel);
4300 FrameRect(&rc);
4301*/
4302}
4303
4304/*
4305 * Delete the given number of lines from the given row, scrolling up any
4306 * text further down within the scroll region.
4307 */
4308 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004309gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310{
4311 Rect rc;
4312
4313 /* changed without checking! */
4314 rc.left = FILL_X(gui.scroll_region_left);
4315 rc.right = FILL_X(gui.scroll_region_right + 1);
4316 rc.top = FILL_Y(row);
4317 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4318
4319 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004320 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321
4322 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4323 gui.scroll_region_left,
4324 gui.scroll_region_bot, gui.scroll_region_right);
4325}
4326
4327/*
4328 * Insert the given number of lines before the given row, scrolling down any
4329 * following text within the scroll region.
4330 */
4331 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004332gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333{
4334 Rect rc;
4335
4336 rc.left = FILL_X(gui.scroll_region_left);
4337 rc.right = FILL_X(gui.scroll_region_right + 1);
4338 rc.top = FILL_Y(row);
4339 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4340
4341 gui_mch_set_bg_color(gui.back_pixel);
4342
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004343 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344
4345 /* Update gui.cursor_row if the cursor scrolled or copied over */
4346 if (gui.cursor_row >= gui.row
4347 && gui.cursor_col >= gui.scroll_region_left
4348 && gui.cursor_col <= gui.scroll_region_right)
4349 {
4350 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4351 gui.cursor_row += num_lines;
4352 else if (gui.cursor_row <= gui.scroll_region_bot)
4353 gui.cursor_is_valid = FALSE;
4354 }
4355
4356 gui_clear_block(row, gui.scroll_region_left,
4357 row + num_lines - 1, gui.scroll_region_right);
4358}
4359
4360 /*
4361 * TODO: add a vim format to the clipboard which remember
4362 * LINEWISE, CHARWISE, BLOCKWISE
4363 */
4364
4365 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004366clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367{
4368
4369 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004370 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004371 Size scrapSize;
4372 ScrapFlavorFlags scrapFlags;
4373 ScrapRef scrap = nil;
4374 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 int type;
4376 char *searchCR;
4377 char_u *tempclip;
4378
4379
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004380 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 if (error != noErr)
4382 return;
4383
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004384 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4385 if (error == noErr)
4386 {
4387 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4388 if (error == noErr && scrapSize > 1)
4389 flavor = 1;
4390 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004392 if (flavor == 0)
4393 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004394 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004395 if (error != noErr)
4396 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004398 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004399 if (error != noErr)
4400 return;
4401 }
4402
4403 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004405 /* In CARBON we don't need a Handle, a pointer is good */
4406 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004408 /* tempclip = lalloc(scrapSize+1, TRUE); */
4409 HLock(textOfClip);
4410 error = GetScrapFlavorData(scrap,
4411 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4412 &scrapSize, *textOfClip);
4413 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004415 if (flavor)
4416 type = **textOfClip;
4417 else
4418 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4419
4420 tempclip = lalloc(scrapSize + 1, TRUE);
4421 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4422 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004424#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004425 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004426 /* Convert from utf-16 (clipboard) */
4427 size_t encLen = 0;
4428 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004429
4430 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004432 scrapSize = encLen;
4433 vim_free(tempclip);
4434 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004436 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004438
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004439 searchCR = (char *)tempclip;
4440 while (searchCR != NULL)
4441 {
4442 searchCR = strchr(searchCR, '\r');
4443 if (searchCR != NULL)
4444 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004446
4447 clip_yank_selection(type, tempclip, scrapSize, cbd);
4448
4449 vim_free(tempclip);
4450 HUnlock(textOfClip);
4451
4452 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453}
4454
4455 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004456clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457{
4458 /*
4459 * TODO: Really nothing to do?
4460 */
4461}
4462
4463 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004464clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465{
4466 return OK;
4467}
4468
4469/*
4470 * Send the current selection to the clipboard.
4471 */
4472 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004473clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474{
4475 Handle textOfClip;
4476 long scrapSize;
4477 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479
4480 char_u *str = NULL;
4481
4482 if (!cbd->owned)
4483 return;
4484
4485 clip_get_selection(cbd);
4486
4487 /*
4488 * Once we set the clipboard, lose ownership. If another application sets
4489 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004490 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 cbd->owned = FALSE;
4492
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004493 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004495#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004496 size_t utf16_len = 0;
4497 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4498 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004500 scrapSize = utf16_len;
4501 vim_free(str);
4502 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 }
4504#endif
4505
4506 if (type >= 0)
4507 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004510 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 HLock(textOfClip);
4512
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004513 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004514 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004515 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004516 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004517 scrapSize, *textOfClip + 1);
4518 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4519 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 HUnlock(textOfClip);
4521 DisposeHandle(textOfClip);
4522 }
4523
4524 vim_free(str);
4525}
4526
4527 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004528gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529{
4530 Rect VimBound;
4531
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004532/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534
4535 if (gui.which_scrollbars[SBAR_LEFT])
4536 {
4537 VimBound.left = -gui.scrollbar_width + 1;
4538 }
4539 else
4540 {
4541 VimBound.left = 0;
4542 }
4543
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004546 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547}
4548
4549/*
4550 * Menu stuff.
4551 */
4552
4553 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004554gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555{
4556 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004557 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 */
4559}
4560
4561 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004562gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563{
4564 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004565 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566 */
4567}
4568
4569/*
4570 * Add a sub menu to the menu bar.
4571 */
4572 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004573gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574{
4575 /*
4576 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4577 * TODO: use menu->mnemonic and menu->actext
4578 * TODO: Try to reuse menu id
4579 * Carbon Help suggest to use only id between 1 and 235
4580 */
4581 static long next_avail_id = 128;
4582 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004583#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004584 CFStringRef name;
4585#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004587#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588 short index;
4589 vimmenu_T *parent = menu->parent;
4590 vimmenu_T *brother = menu->next;
4591
4592 /* Cannot add a menu if ... */
4593 if ((parent != NULL && parent->submenu_id == 0))
4594 return;
4595
4596 /* menu ID greater than 1024 are reserved for ??? */
4597 if (next_avail_id == 1024)
4598 return;
4599
4600 /* My brother could be the PopUp, find my real brother */
4601 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4602 brother = brother->next;
4603
4604 /* Find where to insert the menu (for MenuBar) */
4605 if ((parent == NULL) && (brother != NULL))
4606 menu_after_me = brother->submenu_id;
4607
4608 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4609 if (!menu_is_menubar(menu->name))
4610 menu_after_me = hierMenu;
4611
4612 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004613#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004614 name = menu_title_removing_mnemonic(menu);
4615#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004617#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 if (name == NULL)
4619 return;
4620
4621 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 {
4623 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004624 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4625 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 */
4627 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004628#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004629 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4630 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4631#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004632 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004633#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 next_avail_id++;
4635 }
4636
4637 if (parent == NULL)
4638 {
4639 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4640
4641 /* TODO: Verify if we could only Insert Menu if really part of the
4642 * menubar The Inserted menu are scanned or the Command-key combos
4643 */
4644
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004645 /* Insert the menu */
4646 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647#if 1
4648 /* Vim should normally update it. TODO: verify */
4649 DrawMenuBar();
4650#endif
4651 }
4652 else
4653 {
4654 /* Adding as a submenu */
4655
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004656 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657
4658 /* Call InsertMenuItem followed by SetMenuItemText
4659 * to avoid special character recognition by InsertMenuItem
4660 */
4661 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004662#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004663 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4664#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004666#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4668 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4669 InsertMenu(menu->submenu_handle, hierMenu);
4670 }
4671
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004672#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004673 CFRelease(name);
4674#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004675 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677
4678#if 0
4679 /* Done by Vim later on */
4680 DrawMenuBar();
4681#endif
4682}
4683
4684/*
4685 * Add a menu item to a menu
4686 */
4687 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004688gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004690#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004691 CFStringRef name;
4692#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004694#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 vimmenu_T *parent = menu->parent;
4696 int menu_inserted;
4697
4698 /* Cannot add item, if the menu have not been created */
4699 if (parent->submenu_id == 0)
4700 return;
4701
4702 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4703 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4704
4705 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004706#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004707 name = menu_title_removing_mnemonic(menu);
4708#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004709 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004710#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711
4712 /* Where are just a menu item, so no handle, no id */
4713 menu->submenu_id = 0;
4714 menu->submenu_handle = NULL;
4715
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716 menu_inserted = 0;
4717 if (menu->actext)
4718 {
4719 /* If the accelerator text for the menu item looks like it describes
4720 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4721 * item's command equivalent.
4722 */
4723 int key = 0;
4724 int modifiers = 0;
4725 char_u *p_actext;
4726
4727 p_actext = menu->actext;
4728 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4729 if (*p_actext != 0)
4730 key = 0; /* error: trailing text */
4731 /* find_special_key() returns a keycode with as many of the
4732 * specified modifiers as appropriate already applied (e.g., for
4733 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4734 * as the only modifier). Since we want to display all of the
4735 * modifiers, we need to convert the keycode back to a printable
4736 * character plus modifiers.
4737 * TODO: Write an alternative find_special_key() that doesn't
4738 * apply modifiers.
4739 */
4740 if (key > 0 && key < 32)
4741 {
4742 /* Convert a control key to an uppercase letter. Note that
4743 * by this point it is no longer possible to distinguish
4744 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4745 */
4746 modifiers |= MOD_MASK_CTRL;
4747 key += '@';
4748 }
4749 /* If the keycode is an uppercase letter, set the Shift modifier.
4750 * If it is a lowercase letter, don't set the modifier, but convert
4751 * the letter to uppercase for display in the menu.
4752 */
4753 else if (key >= 'A' && key <= 'Z')
4754 modifiers |= MOD_MASK_SHIFT;
4755 else if (key >= 'a' && key <= 'z')
4756 key += 'A' - 'a';
4757 /* Note: keycodes below 0x22 are reserved by Apple. */
4758 if (key >= 0x22 && vim_isprintc_strict(key))
4759 {
4760 int valid = 1;
4761 char_u mac_mods = kMenuNoModifiers;
4762 /* Convert Vim modifier codes to Menu Manager equivalents. */
4763 if (modifiers & MOD_MASK_SHIFT)
4764 mac_mods |= kMenuShiftModifier;
4765 if (modifiers & MOD_MASK_CTRL)
4766 mac_mods |= kMenuControlModifier;
4767 if (!(modifiers & MOD_MASK_CMD))
4768 mac_mods |= kMenuNoCommandModifier;
4769 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
4770 valid = 0; /* TODO: will Alt someday map to Option? */
4771 if (valid)
4772 {
4773 char_u item_txt[10];
4774 /* Insert the menu item after idx, with its command key. */
4775 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
4776 item_txt[3] = key;
4777 InsertMenuItem(parent->submenu_handle, item_txt, idx);
4778 /* Set the modifier keys. */
4779 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
4780 menu_inserted = 1;
4781 }
4782 }
4783 }
4784 /* Call InsertMenuItem followed by SetMenuItemText
4785 * to avoid special character recognition by InsertMenuItem
4786 */
4787 if (!menu_inserted)
4788 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
4789 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004790#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004791 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4792#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004794#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795
4796#if 0
4797 /* Called by Vim */
4798 DrawMenuBar();
4799#endif
4800
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004801#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004802 CFRelease(name);
4803#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804 /* TODO: Can name be freed? */
4805 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004806#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807}
4808
4809 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004810gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811{
4812 /* no tearoff menus */
4813}
4814
4815/*
4816 * Destroy the machine specific menu widget.
4817 */
4818 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004819gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004821 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822
4823 if (index > 0)
4824 {
4825 if (menu->parent)
4826 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827 {
4828 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004829 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830
4831 /* Delete the Menu if it was a hierarchical Menu */
4832 if (menu->submenu_id != 0)
4833 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004834 DeleteMenu(menu->submenu_id);
4835 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 }
4837 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 }
4839#ifdef DEBUG_MAC_MENU
4840 else
4841 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004842 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 }
4844#endif
4845 }
4846 else
4847 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004849 DeleteMenu(menu->submenu_id);
4850 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 }
4852 }
4853 /* Shouldn't this be already done by Vim. TODO: Check */
4854 DrawMenuBar();
4855}
4856
4857/*
4858 * Make a menu either grey or not grey.
4859 */
4860 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004861gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862{
4863 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004864 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865/*
4866 index = menu->index;
4867*/
4868 if (grey)
4869 {
4870 if (menu->children)
4871 DisableMenuItem(menu->submenu_handle, index);
4872 if (menu->parent)
4873 if (menu->parent->submenu_handle)
4874 DisableMenuItem(menu->parent->submenu_handle, index);
4875 }
4876 else
4877 {
4878 if (menu->children)
4879 EnableMenuItem(menu->submenu_handle, index);
4880 if (menu->parent)
4881 if (menu->parent->submenu_handle)
4882 EnableMenuItem(menu->parent->submenu_handle, index);
4883 }
4884}
4885
4886/*
4887 * Make menu item hidden or not hidden
4888 */
4889 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004890gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891{
4892 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004893 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894}
4895
4896
4897/*
4898 * This is called after setting all the menus to grey/hidden or not.
4899 */
4900 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004901gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004902{
4903 DrawMenuBar();
4904}
4905
4906
4907/*
4908 * Scrollbar stuff.
4909 */
4910
4911 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004912gui_mch_enable_scrollbar(
4913 scrollbar_T *sb,
4914 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915{
4916 if (flag)
4917 ShowControl(sb->id);
4918 else
4919 HideControl(sb->id);
4920
4921#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004922 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923#endif
4924}
4925
4926 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004927gui_mch_set_scrollbar_thumb(
4928 scrollbar_T *sb,
4929 long val,
4930 long size,
4931 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004932{
4933 SetControl32BitMaximum (sb->id, max);
4934 SetControl32BitMinimum (sb->id, 0);
4935 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00004936 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004937#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004938 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939#endif
4940}
4941
4942 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004943gui_mch_set_scrollbar_pos(
4944 scrollbar_T *sb,
4945 int x,
4946 int y,
4947 int w,
4948 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949{
4950 gui_mch_set_bg_color(gui.back_pixel);
4951/* if (gui.which_scrollbars[SBAR_LEFT])
4952 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004953 MoveControl(sb->id, x-16, y);
4954 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 }
4956 else
4957 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004958 MoveControl(sb->id, x, y);
4959 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004960 }*/
4961 if (sb == &gui.bottom_sbar)
4962 h += 1;
4963 else
4964 w += 1;
4965
4966 if (gui.which_scrollbars[SBAR_LEFT])
4967 x -= 15;
4968
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004969 MoveControl(sb->id, x, y);
4970 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004972 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973#endif
4974}
4975
4976 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004977gui_mch_create_scrollbar(
4978 scrollbar_T *sb,
4979 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980{
4981 Rect bounds;
4982
4983 bounds.top = -16;
4984 bounds.bottom = -10;
4985 bounds.right = -10;
4986 bounds.left = -16;
4987
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004988 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989 &bounds,
4990 "\pScrollBar",
4991 TRUE,
4992 0, /* current*/
4993 0, /* top */
4994 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996 (long) sb->ident);
4997#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004998 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999#endif
5000}
5001
5002 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005003gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004{
5005 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005006 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005008 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009#endif
5010}
5011
5012
5013/*
5014 * Cursor blink functions.
5015 *
5016 * This is a simple state machine:
5017 * BLINK_NONE not blinking at all
5018 * BLINK_OFF blinking, cursor is not shown
5019 * BLINK_ON blinking, cursor is shown
5020 */
5021 void
5022gui_mch_set_blinking(long wait, long on, long off)
5023{
5024 /* TODO: TODO: TODO: TODO: */
5025/* blink_waittime = wait;
5026 blink_ontime = on;
5027 blink_offtime = off;*/
5028}
5029
5030/*
5031 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5032 */
5033 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005034gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035{
5036 gui_update_cursor(TRUE, FALSE);
5037 /* TODO: TODO: TODO: TODO: */
5038/* gui_w32_rm_blink_timer();
5039 if (blink_state == BLINK_OFF)
5040 gui_update_cursor(TRUE, FALSE);
5041 blink_state = BLINK_NONE;*/
5042}
5043
5044/*
5045 * Start the cursor blinking. If it was already blinking, this restarts the
5046 * waiting time and shows the cursor.
5047 */
5048 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005049gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005050{
5051 gui_update_cursor(TRUE, FALSE);
5052 /* TODO: TODO: TODO: TODO: */
5053/* gui_w32_rm_blink_timer(); */
5054
5055 /* Only switch blinking on if none of the times is zero */
5056/* if (blink_waittime && blink_ontime && blink_offtime)
5057 {
5058 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5059 (TIMERPROC)_OnBlinkTimer);
5060 blink_state = BLINK_ON;
5061 gui_update_cursor(TRUE, FALSE);
5062 }*/
5063}
5064
5065/*
5066 * Return the RGB value of a pixel as long.
5067 */
5068 long_u
5069gui_mch_get_rgb(guicolor_T pixel)
5070{
5071 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5072}
5073
5074
5075
5076#ifdef FEAT_BROWSE
5077/*
5078 * Pop open a file browser and return the file selected, in allocated memory,
5079 * or NULL if Cancel is hit.
5080 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5081 * title - Title message for the file browser dialog.
5082 * dflt - Default name of file.
5083 * ext - Default extension to be added to files without extensions.
5084 * initdir - directory in which to open the browser (NULL = current dir)
5085 * filter - Filter for matched files to choose from.
5086 * Has a format like this:
5087 * "C Files (*.c)\0*.c\0"
5088 * "All Files\0*.*\0\0"
5089 * If these two strings were concatenated, then a choice of two file
5090 * filters will be selectable to the user. Then only matching files will
5091 * be shown in the browser. If NULL, the default allows all files.
5092 *
5093 * *NOTE* - the filter string must be terminated with TWO nulls.
5094 */
5095 char_u *
5096gui_mch_browse(
5097 int saving,
5098 char_u *title,
5099 char_u *dflt,
5100 char_u *ext,
5101 char_u *initdir,
5102 char_u *filter)
5103{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 /* TODO: Add Ammon's safety checl (Dany) */
5105 NavReplyRecord reply;
5106 char_u *fname = NULL;
5107 char_u **fnames = NULL;
5108 long numFiles;
5109 NavDialogOptions navOptions;
5110 OSErr error;
5111
5112 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005113 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114
5115
5116 /* TODO: If we get a :browse args, set the Multiple bit. */
5117 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5118 | kNavDontAutoTranslate
5119 | kNavDontAddTranslateItems
5120 /* | kNavAllowMultipleFiles */
5121 | kNavAllowStationery;
5122
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005123 (void) C2PascalString(title, &navOptions.message);
5124 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125 /* Could set clientName?
5126 * windowTitle? (there's no title bar?)
5127 */
5128
5129 if (saving)
5130 {
5131 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005132 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133 if (!reply.validRecord)
5134 return NULL;
5135 }
5136 else
5137 {
5138 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5139 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5140 if (!reply.validRecord)
5141 return NULL;
5142 }
5143
5144 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5145
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005146 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147
5148 if (fnames)
5149 {
5150 fname = fnames[0];
5151 vim_free(fnames);
5152 }
5153
5154 /* TODO: Shorten the file name if possible */
5155 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005156}
5157#endif /* FEAT_BROWSE */
5158
5159#ifdef FEAT_GUI_DIALOG
5160/*
5161 * Stuff for dialogues
5162 */
5163
5164/*
5165 * Create a dialogue dynamically from the parameter strings.
5166 * type = type of dialogue (question, alert, etc.)
5167 * title = dialogue title. may be NULL for default title.
5168 * message = text to display. Dialogue sizes to accommodate it.
5169 * buttons = '\n' separated list of button captions, default first.
5170 * dfltbutton = number of default button.
5171 *
5172 * This routine returns 1 if the first button is pressed,
5173 * 2 for the second, etc.
5174 *
5175 * 0 indicates Esc was pressed.
5176 * -1 for unexpected error
5177 *
5178 * If stubbing out this fn, return 1.
5179 */
5180
5181typedef struct
5182{
5183 short idx;
5184 short width; /* Size of the text in pixel */
5185 Rect box;
5186} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5187
5188#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5189
5190 static void
5191macMoveDialogItem(
5192 DialogRef theDialog,
5193 short itemNumber,
5194 short X,
5195 short Y,
5196 Rect *inBox)
5197{
5198#if 0 /* USE_CARBONIZED */
5199 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005200 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005202 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203#else
5204 short itemType;
5205 Handle itemHandle;
5206 Rect localBox;
5207 Rect *itemBox = &localBox;
5208
5209 if (inBox != nil)
5210 itemBox = inBox;
5211
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005212 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5213 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5214 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005215 /* To move a control (like a button) we need to call both
5216 * MoveControl and SetDialogItem. FAQ 6-18 */
5217 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005218 MoveControl((ControlRef) itemHandle, X, Y);
5219 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220#endif
5221}
5222
5223 static void
5224macSizeDialogItem(
5225 DialogRef theDialog,
5226 short itemNumber,
5227 short width,
5228 short height)
5229{
5230 short itemType;
5231 Handle itemHandle;
5232 Rect itemBox;
5233
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005234 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235
5236 /* When width or height is zero do not change it */
5237 if (width == 0)
5238 width = itemBox.right - itemBox.left;
5239 if (height == 0)
5240 height = itemBox.bottom - itemBox.top;
5241
5242#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005243 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005244#else
5245 /* Resize the bounding box */
5246 itemBox.right = itemBox.left + width;
5247 itemBox.bottom = itemBox.top + height;
5248
5249 /* To resize a control (like a button) we need to call both
5250 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5251 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005252 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253
5254 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005255 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256#endif
5257}
5258
5259 static void
5260macSetDialogItemText(
5261 DialogRef theDialog,
5262 short itemNumber,
5263 Str255 itemName)
5264{
5265 short itemType;
5266 Handle itemHandle;
5267 Rect itemBox;
5268
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005269 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005270
5271 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005272 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005274 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275}
5276
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005277/* TODO: There have been some crashes with dialogs, check your inbox
5278 * (Jussi)
5279 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005280 int
5281gui_mch_dialog(
5282 int type,
5283 char_u *title,
5284 char_u *message,
5285 char_u *buttons,
5286 int dfltbutton,
5287 char_u *textfield)
5288{
5289 Handle buttonDITL;
5290 Handle iconDITL;
5291 Handle inputDITL;
5292 Handle messageDITL;
5293 Handle itemHandle;
5294 Handle iconHandle;
5295 DialogPtr theDialog;
5296 char_u len;
5297 char_u PascalTitle[256]; /* place holder for the title */
5298 char_u name[256];
5299 GrafPtr oldPort;
5300 short itemHit;
5301 char_u *buttonChar;
5302 Rect box;
5303 short button;
5304 short lastButton;
5305 short itemType;
5306 short useIcon;
5307 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005308 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005309 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310 short widestButton = 0;
5311 short dfltButtonEdge = 20; /* gut feeling */
5312 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5313 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5314 short maximumWidth = 400; /* gut feeling */
5315 short maxButtonWidth = 175; /* gut feeling */
5316
5317 short vertical;
5318 short dialogHeight;
5319 short messageLines = 3;
5320 FontInfo textFontInfo;
5321
5322 vgmDlgItm iconItm;
5323 vgmDlgItm messageItm;
5324 vgmDlgItm inputItm;
5325 vgmDlgItm buttonItm;
5326
5327 WindowRef theWindow;
5328
5329 /* Check 'v' flag in 'guioptions': vertical button placement. */
5330 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5331
5332 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005333 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005334
5335 /* Get the WindowRef */
5336 theWindow = GetDialogWindow(theDialog);
5337
5338 /* Hide the window.
5339 * 1. to avoid seeing slow drawing
5340 * 2. to prevent a problem seen while moving dialog item
5341 * within a visible window. (non-Carbon MacOS 9)
5342 * Could be avoided by changing the resource.
5343 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005344 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345
5346 /* Change the graphical port to the dialog,
5347 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005348 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005349 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005350
5351 /* Get the info about the default text,
5352 * used to calculate the height of the message
5353 * and of the text field */
5354 GetFontInfo(&textFontInfo);
5355
5356 /* Set the dialog title */
5357 if (title != NULL)
5358 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005359 (void) C2PascalString(title, &PascalTitle);
5360 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005361 }
5362
5363 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005364 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365 buttonChar = buttons;
5366 button = 0;
5367
5368 for (;*buttonChar != 0;)
5369 {
5370 /* Get the name of the button */
5371 button++;
5372 len = 0;
5373 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5374 {
5375 if (*buttonChar != DLG_HOTKEY_CHAR)
5376 name[++len] = *buttonChar;
5377 }
5378 if (*buttonChar != 0)
5379 buttonChar++;
5380 name[0] = len;
5381
5382 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005383 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005384
5385 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005386 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005387
5388 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005389 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390 /* Limite the size of any button to an acceptable value. */
5391 /* TODO: Should be based on the message width */
5392 if (width > maxButtonWidth)
5393 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005394 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005395
5396 totalButtonWidth += width;
5397
5398 if (width > widestButton)
5399 widestButton = width;
5400 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005401 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005402 lastButton = button;
5403
5404 /* Add the icon to the Dialog Box. */
5405 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005406 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 switch (type)
5408 {
5409 case VIM_GENERIC: useIcon = kNoteIcon;
5410 case VIM_ERROR: useIcon = kStopIcon;
5411 case VIM_WARNING: useIcon = kCautionIcon;
5412 case VIM_INFO: useIcon = kNoteIcon;
5413 case VIM_QUESTION: useIcon = kNoteIcon;
5414 default: useIcon = kStopIcon;
5415 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005416 AppendDITL(theDialog, iconDITL, overlayDITL);
5417 ReleaseResource(iconDITL);
5418 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005420 iconHandle = GetIcon(useIcon);
5421 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005422
5423 /* Add the message to the Dialog box. */
5424 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005425 messageDITL = GetResource('DITL', 132);
5426 AppendDITL(theDialog, messageDITL, overlayDITL);
5427 ReleaseResource(messageDITL);
5428 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5429 (void) C2PascalString(message, &name);
5430 SetDialogItemText(itemHandle, name);
5431 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005432
5433 /* Add the input box if needed */
5434 if (textfield != NULL)
5435 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005436 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005437 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005438 inputDITL = GetResource('DITL', 132);
5439 AppendDITL(theDialog, inputDITL, overlayDITL);
5440 ReleaseResource(inputDITL);
5441 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5442/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5443 (void) C2PascalString(textfield, &name);
5444 SetDialogItemText(itemHandle, name);
5445 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 }
5447
5448 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005449 SetDialogDefaultItem(theDialog, dfltbutton);
5450 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005451
5452 /* Reposition element */
5453
5454 /* Check if we need to force vertical */
5455 if (totalButtonWidth > maximumWidth)
5456 vertical = TRUE;
5457
5458 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005459 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005460 iconItm.box.right = box.right;
5461 iconItm.box.bottom = box.bottom;
5462
5463 /* Place Message */
5464 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005465 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5466 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467
5468 /* Place Input */
5469 if (textfield != NULL)
5470 {
5471 inputItm.box.left = messageItm.box.left;
5472 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005473 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5474 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005475 /* Convert the static text into a text edit.
5476 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005477 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5478 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5480 }
5481
5482 /* Place Button */
5483 if (textfield != NULL)
5484 {
5485 buttonItm.box.left = inputItm.box.left;
5486 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5487 }
5488 else
5489 {
5490 buttonItm.box.left = messageItm.box.left;
5491 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5492 }
5493
5494 for (button=1; button <= lastButton; button++)
5495 {
5496
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005497 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005498 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005499 if (vertical)
5500 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005501 macSizeDialogItem(theDialog, button, widestButton, 0);
5502 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503 }
5504 /* Calculate position of next button */
5505 if (vertical)
5506 buttonItm.box.top = box.bottom + dfltElementSpacing;
5507 else
5508 buttonItm.box.left = box.right + dfltElementSpacing;
5509 }
5510
5511 /* Resize the dialog box */
5512 dialogHeight = box.bottom + dfltElementSpacing;
5513 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5514
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005516 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005517 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518
5519 /* Display it */
5520 ShowWindow(theWindow);
5521/* BringToFront(theWindow); */
5522 SelectWindow(theWindow);
5523
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005524/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005525#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005526 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005527 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005528#endif
5529
Bram Moolenaard68071d2006-05-02 22:08:30 +00005530#ifdef USE_CARBONKEYHANDLER
5531 /* Avoid that we use key events for the main window. */
5532 dialog_busy = TRUE;
5533#endif
5534
Bram Moolenaar071d4272004-06-13 20:20:40 +00005535 /* Hang until one of the button is hit */
5536 do
5537 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005538 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 } while ((itemHit < 1) || (itemHit > lastButton));
5540
Bram Moolenaard68071d2006-05-02 22:08:30 +00005541#ifdef USE_CARBONKEYHANDLER
5542 dialog_busy = FALSE;
5543#endif
5544
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545 /* Copy back the text entered by the user into the param */
5546 if (textfield != NULL)
5547 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005548 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5549 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005550#if IOSIZE < 256
5551 /* Truncate the name to IOSIZE if needed */
5552 if (name[0] > IOSIZE)
5553 name[0] = IOSIZE - 1;
5554#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005555 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005556 }
5557
5558 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005559 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005560
5561 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005562 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563
5564 return itemHit;
5565/*
5566 * Usefull thing which could be used
5567 * SetDialogTimeout(): Auto click a button after timeout
5568 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5569 * MoveDialogItem(): Probably better than SetDialogItem
5570 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005571 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005572 */
5573}
5574#endif /* FEAT_DIALOG_GUI */
5575
5576/*
5577 * Display the saved error message(s).
5578 */
5579#ifdef USE_MCH_ERRMSG
5580 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005581display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582{
5583 char *p;
5584 char_u pError[256];
5585
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005586 if (error_ga.ga_data == NULL)
5587 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005589 /* avoid putting up a message box with blanks only */
5590 for (p = (char *)error_ga.ga_data; *p; ++p)
5591 if (!isspace(*p))
5592 {
5593 if (STRLEN(p) > 255)
5594 pError[0] = 255;
5595 else
5596 pError[0] = STRLEN(p);
5597
5598 STRNCPY(&pError[1], p, pError[0]);
5599 ParamText(pError, nil, nil, nil);
5600 Alert(128, nil);
5601 break;
5602 /* TODO: handled message longer than 256 chars
5603 * use auto-sizeable alert
5604 * or dialog with scrollbars (TextEdit zone)
5605 */
5606 }
5607 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608}
5609#endif
5610
5611/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005612 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005614 void
5615gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005616{
5617 Point where;
5618
5619 GetMouse(&where);
5620
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005621 *x = where.h;
5622 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623}
5624
5625 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005626gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005627{
5628 /* TODO */
5629#if 0
5630 /* From FAQ 3-11 */
5631
5632 CursorDevicePtr myMouse;
5633 Point where;
5634
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005635 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5636 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 {
5638 /* New way */
5639
5640 /*
5641 * Get first devoice with one button.
5642 * This will probably be the standad mouse
5643 * startat head of cursor dev list
5644 *
5645 */
5646
5647 myMouse = nil;
5648
5649 do
5650 {
5651 /* Get the next cursor device */
5652 CursorDeviceNextDevice(&myMouse);
5653 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005654 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005655
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005656 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657 }
5658 else
5659 {
5660 /* Old way */
5661 where.h = x;
5662 where.v = y;
5663
5664 *(Point *)RawMouse = where;
5665 *(Point *)MTemp = where;
5666 *(Ptr) CrsrNew = 0xFFFF;
5667 }
5668#endif
5669}
5670
5671 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005672gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005673{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005674/*
5675 * Clone PopUp to use menu
5676 * Create a object descriptor for the current selection
5677 * Call the procedure
5678 */
5679
5680 MenuHandle CntxMenu;
5681 Point where;
5682 OSStatus status;
5683 UInt32 CntxType;
5684 SInt16 CntxMenuID;
5685 UInt16 CntxMenuItem;
5686 Str255 HelpName = "";
5687 GrafPtr savePort;
5688
5689 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005690 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005692 GetMouse(&where);
5693 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005694 CntxMenu = menu->submenu_handle;
5695
5696 /* TODO: Get the text selection from Vim */
5697
5698 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005699 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005700 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701
5702 if (status == noErr)
5703 {
5704 if (CntxType == kCMMenuItemSelected)
5705 {
5706 /* Handle the menu CntxMenuID, CntxMenuItem */
5707 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005708 /* But what about the current menu, is the menu changed by
5709 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005710 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 }
5712 else if (CntxMenuID == kCMShowHelpSelected)
5713 {
5714 /* Should come up with the help */
5715 }
5716 }
5717
5718 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005719 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720}
5721
5722#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5723/* TODO: Is it need for MACOS_X? (Dany) */
5724 void
5725mch_post_buffer_write(buf_T *buf)
5726{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005727 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5728 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729}
5730#endif
5731
5732#ifdef FEAT_TITLE
5733/*
5734 * Set the window title and icon.
5735 * (The icon is not taken care of).
5736 */
5737 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005738gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739{
5740 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5741 * that 256. Even better get it to fit nicely in the titlebar.
5742 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005743#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005744 CFStringRef windowTitle;
5745 size_t windowTitleLen;
5746#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005747 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005748#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005749
5750 if (title == NULL) /* nothing to do */
5751 return;
5752
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005753#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005754 windowTitleLen = STRLEN(title);
5755 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
5756
5757 if (windowTitle)
5758 {
5759 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
5760 CFRelease(windowTitle);
5761 }
5762#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005763 pascalTitle = C2Pascal_save(title);
5764 if (pascalTitle != NULL)
5765 {
5766 SetWTitle(gui.VimWindow, pascalTitle);
5767 vim_free(pascalTitle);
5768 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005769#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770}
5771#endif
5772
5773/*
5774 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
5775 */
5776
5777 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005778C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779{
5780 char_u *PascalPtr = (char_u *) PascalString;
5781 int len;
5782 int i;
5783
5784 PascalPtr[0] = 0;
5785 if (CString == NULL)
5786 return 0;
5787
5788 len = STRLEN(CString);
5789 if (len > 255)
5790 len = 255;
5791
5792 for (i = 0; i < len; i++)
5793 PascalPtr[i+1] = CString[i];
5794
5795 PascalPtr[0] = len;
5796
5797 return 0;
5798}
5799
5800 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005801GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802{
5803 /* From FAQ 8-12 */
5804 Str255 filePascal;
5805 CInfoPBRec myCPB;
5806 OSErr err;
5807
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005808 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809
5810 myCPB.dirInfo.ioNamePtr = filePascal;
5811 myCPB.dirInfo.ioVRefNum = 0;
5812 myCPB.dirInfo.ioFDirIndex = 0;
5813 myCPB.dirInfo.ioDrDirID = 0;
5814
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005815 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816
5817 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005818 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819
5820 /* TODO: Use an error code mechanism */
5821 return 0;
5822}
5823
5824/*
5825 * Convert a FSSpec to a fuill path
5826 */
5827
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005828char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829{
5830 /*
5831 * TODO: Add protection for 256 char max.
5832 */
5833
5834 CInfoPBRec theCPB;
5835 char_u fname[256];
5836 char_u *filenamePtr = fname;
5837 OSErr error;
5838 int folder = 1;
5839#ifdef USE_UNIXFILENAME
5840 SInt16 dfltVol_vRefNum;
5841 SInt32 dfltVol_dirID;
5842 FSRef refFile;
5843 OSStatus status;
5844 UInt32 pathSize = 256;
5845 char_u pathname[256];
5846 char_u *path = pathname;
5847#else
5848 Str255 directoryName;
5849 char_u temporary[255];
5850 char_u *temporaryPtr = temporary;
5851#endif
5852
5853#ifdef USE_UNIXFILENAME
5854 /* Get the default volume */
5855 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005856 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857
5858 if (error)
5859 return NULL;
5860#endif
5861
5862 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005863 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864
5865 /* Get the info about the file specified in FSSpec */
5866 theCPB.dirInfo.ioFDirIndex = 0;
5867 theCPB.dirInfo.ioNamePtr = file.name;
5868 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00005869 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870 theCPB.dirInfo.ioDrDirID = file.parID;
5871
5872 /* As ioFDirIndex = 0, get the info of ioNamePtr,
5873 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005874 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005875
5876 /* If we are called for a new file we expect fnfErr */
5877 if ((error) && (error != fnfErr))
5878 return NULL;
5879
5880 /* Check if it's a file or folder */
5881 /* default to file if file don't exist */
5882 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
5883 folder = 0; /* It's not a folder */
5884 else
5885 folder = 1;
5886
5887#ifdef USE_UNIXFILENAME
5888 /*
5889 * The function used here are available in Carbon, but
5890 * do nothing une MacOS 8 and 9
5891 */
5892 if (error == fnfErr)
5893 {
5894 /* If the file to be saved does not already exist, it isn't possible
5895 to convert its FSSpec into an FSRef. But we can construct an
5896 FSSpec for the file's parent folder (since we have its volume and
5897 directory IDs), and since that folder does exist, we can convert
5898 that FSSpec into an FSRef, convert the FSRef in turn into a path,
5899 and, finally, append the filename. */
5900 FSSpec dirSpec;
5901 FSRef dirRef;
5902 Str255 emptyFilename = "\p";
5903 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
5904 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
5905 if (error)
5906 return NULL;
5907
5908 error = FSpMakeFSRef(&dirSpec, &dirRef);
5909 if (error)
5910 return NULL;
5911
5912 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
5913 if (status)
5914 return NULL;
5915
5916 STRCAT(path, "/");
5917 STRCAT(path, filenamePtr);
5918 }
5919 else
5920 {
5921 /* If the file to be saved already exists, we can get its full path
5922 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005923 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005924 if (error)
5925 return NULL;
5926
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005927 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928 if (status)
5929 return NULL;
5930 }
5931
5932 /* Add a slash at the end if needed */
5933 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005934 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005935
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005936 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005937#else
5938 /* TODO: Get rid of all USE_UNIXFILENAME below */
5939 /* Set ioNamePtr, it's the same area which is always reused. */
5940 theCPB.dirInfo.ioNamePtr = directoryName;
5941
5942 /* Trick for first entry, set ioDrParID to the first value
5943 * we want for ioDrDirID*/
5944 theCPB.dirInfo.ioDrParID = file.parID;
5945 theCPB.dirInfo.ioDrDirID = file.parID;
5946
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005947 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948 do
5949 {
5950 theCPB.dirInfo.ioFDirIndex = -1;
5951 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5952 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005953 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005954 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5955
5956 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5957 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005958 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005959
5960 if (error)
5961 return NULL;
5962
5963 /* Put the new directoryName in front of the current fname */
5964 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005965 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005966 STRCAT(filenamePtr, ":");
5967 STRCAT(filenamePtr, temporaryPtr);
5968 }
5969#if 1 /* def USE_UNIXFILENAME */
5970 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
5971 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
5972#else
5973 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
5974#endif
5975
5976 /* Get the information about the volume on which the file reside */
5977 theCPB.dirInfo.ioFDirIndex = -1;
5978 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
5979 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00005980 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005981 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
5982
5983 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
5984 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005985 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005986
5987 if (error)
5988 return NULL;
5989
5990 /* For MacOS Classic always add the volume name */
5991 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00005992 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005993#ifdef USE_UNIXFILENAME
5994 if (file.vRefNum != dfltVol_vRefNum)
5995#endif
5996 {
5997 /* Add the volume name */
5998 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005999 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006000 STRCAT(filenamePtr, ":");
6001 STRCAT(filenamePtr, temporaryPtr);
6002
6003#ifdef USE_UNIXFILENAME
6004 STRCPY(temporaryPtr, filenamePtr);
6005 filenamePtr[0] = 0; /* NULL terminate the string */
6006 STRCAT(filenamePtr, "Volumes:");
6007 STRCAT(filenamePtr, temporaryPtr);
6008#endif
6009 }
6010
6011 /* Append final path separator if it's a folder */
6012 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006013 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014
6015 /* As we use Unix File Name for MacOS X convert it */
6016#ifdef USE_UNIXFILENAME
6017 /* Need to insert leading / */
6018 /* TODO: get the above code to use directly the / */
6019 STRCPY(&temporaryPtr[1], filenamePtr);
6020 temporaryPtr[0] = '/';
6021 STRCPY(filenamePtr, temporaryPtr);
6022 {
6023 char *p;
6024 for (p = fname; *p; p++)
6025 if (*p == ':')
6026 *p = '/';
6027 }
6028#endif
6029
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006030 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031#endif
6032}
6033
6034#if defined(USE_IM_CONTROL) || defined(PROTO)
6035/*
6036 * Input Method Control functions.
6037 */
6038
6039/*
6040 * Notify cursor position to IM.
6041 */
6042 void
6043im_set_position(int row, int col)
6044{
6045 /* TODO: Implement me! */
6046}
6047
6048/*
6049 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6050 */
6051 void
6052im_set_active(int active)
6053{
6054 KeyScript(active ? smKeySysScript : smKeyRoman);
6055}
6056
6057/*
6058 * Get IM status. When IM is on, return not 0. Else return 0.
6059 */
6060 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006061im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062{
6063 SInt32 script = GetScriptManagerVariable(smKeyScript);
6064 return (script != smRoman
6065 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0;
6066}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006067
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006069
6070
6071
6072
6073#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6074// drawer implementation
6075static MenuRef contextMenu = NULL;
6076enum
6077{
6078 kTabContextMenuId = 42,
6079};
6080
6081// the caller has to CFRelease() the returned string
6082 static CFStringRef
6083getTabLabel(tabpage_T *page)
6084{
6085 get_tabline_label(page, FALSE);
6086#ifdef MACOS_CONVERT
6087 return mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6088#else
6089 // TODO: check internal encoding?
6090 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6091 kCFStringEncodingMacRoman);
6092#endif
6093}
6094
6095
6096#define DRAWER_SIZE 150
6097#define DRAWER_INSET 16
6098
6099static ControlRef dataBrowser = NULL;
6100
6101// when the tabline is hidden, vim doesn't call update_tabline(). When
6102// the tabline is shown again, show_tabline() is called before upate_tabline(),
6103// and because of this, the tab labels and vims internal tabs are out of sync
6104// for a very short time. to prevent inconsistent state, we store the labels
6105// of the tabs, not pointers to the tabs (which are invalid for a short time).
6106static CFStringRef *tabLabels = NULL;
6107static int tabLabelsSize = 0;
6108
6109enum
6110{
6111 kTabsColumn = 'Tabs'
6112};
6113
6114 static int
6115getTabCount(void)
6116{
6117 tabpage_T *tp;
6118 int numTabs = 0;
6119
6120 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6121 ++numTabs;
6122 return numTabs;
6123}
6124
6125// data browser item display callback
6126 static OSStatus
6127dbItemDataCallback(ControlRef browser,
6128 DataBrowserItemID itemID,
6129 DataBrowserPropertyID property /* column id */,
6130 DataBrowserItemDataRef itemData,
6131 Boolean changeValue)
6132{
6133 OSStatus status = noErr;
6134
6135 // assert(property == kTabsColumn); // why is this violated??
6136
6137 // changeValue is true if we have a modifieable list and data was changed.
6138 // In our case, it's always false.
6139 // (that is: if (changeValue) updateInternalData(); else return
6140 // internalData();
6141 if (!changeValue)
6142 {
6143 CFStringRef str;
6144
6145 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6146 str = tabLabels[itemID - 1];
6147 status = SetDataBrowserItemDataText(itemData, str);
6148 }
6149 else
6150 status = errDataBrowserPropertyNotSupported;
6151
6152 return status;
6153}
6154
6155// data browser action callback
6156 static void
6157dbItemNotificationCallback(ControlRef browser,
6158 DataBrowserItemID item,
6159 DataBrowserItemNotification message)
6160{
6161 switch (message)
6162 {
6163 case kDataBrowserItemSelected:
6164 send_tabline_event(item);
6165 break;
6166 }
6167}
6168
6169// callbacks needed for contextual menu:
6170 static void
6171dbGetContextualMenuCallback(ControlRef browser,
6172 MenuRef *menu,
6173 UInt32 *helpType,
6174 CFStringRef *helpItemString,
6175 AEDesc *selection)
6176{
6177 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6178 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6179 *helpItemString = NULL;
6180
6181 *menu = contextMenu;
6182}
6183
6184 static void
6185dbSelectContextualMenuCallback(ControlRef browser,
6186 MenuRef menu,
6187 UInt32 selectionType,
6188 SInt16 menuID,
6189 MenuItemIndex menuItem)
6190{
6191 if (selectionType == kCMMenuItemSelected)
6192 {
6193 MenuCommand command;
6194 GetMenuItemCommandID(menu, menuItem, &command);
6195
6196 // get tab that was selected when the context menu appeared
6197 // (there is always one tab selected). TODO: check if the context menu
6198 // isn't opened on an item but on empty space (has to be possible some
6199 // way, the finder does it too ;-) )
6200 Handle items = NewHandle(0);
6201 if (items != NULL)
6202 {
6203 int numItems;
6204
6205 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6206 kDataBrowserItemIsSelected, items);
6207 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6208 if (numItems > 0)
6209 {
6210 int idx;
6211 DataBrowserItemID *itemsPtr;
6212
6213 HLock(items);
6214 itemsPtr = (DataBrowserItemID *)*items;
6215 idx = itemsPtr[0];
6216 HUnlock(items);
6217 send_tabline_menu_event(idx, command);
6218 }
6219 DisposeHandle(items);
6220 }
6221 }
6222}
6223
6224// focus callback of the data browser to always leave focus in vim
6225 static OSStatus
6226dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6227{
6228 assert(GetEventClass(event) == kEventClassControl
6229 && GetEventKind(event) == kEventControlSetFocusPart);
6230
6231 return paramErr;
6232}
6233
6234
6235// drawer callback to resize data browser to drawer size
6236 static OSStatus
6237drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6238{
6239 switch (GetEventKind(event))
6240 {
6241 case kEventWindowBoundsChanged: // move or resize
6242 {
6243 UInt32 attribs;
6244 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6245 NULL, sizeof(attribs), NULL, &attribs);
6246 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6247 {
6248 Rect r;
6249 GetWindowBounds(drawer, kWindowContentRgn, &r);
6250 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6251 SetControlBounds(dataBrowser, &r);
6252 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6253 kTabsColumn, r.right);
6254 }
6255 }
6256 break;
6257 }
6258
6259 return eventNotHandledErr;
6260}
6261
6262// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6263// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6264// blue highlights in the list view on these systems, though. Oh well.)
6265
6266
6267#import <mach-o/dyld.h>
6268
6269enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6270
6271 static OSStatus
6272myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6273 OptionBits inAttributesToSet,
6274 OptionBits inAttributesToClear)
6275{
6276 long osVersion;
6277 char *symbolName;
6278 NSSymbol symbol = NULL;
6279 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6280 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6281
6282 Gestalt(gestaltSystemVersion, &osVersion);
6283 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6284 return noErr;
6285
6286 // C name mangling...
6287 symbolName = "_DataBrowserChangeAttributes";
6288 if (!NSIsSymbolNameDefined(symbolName)
6289 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6290 return noErr;
6291
6292 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6293 if (dataBrowserChangeAttributes == NULL)
6294 return noErr; // well...
6295 return dataBrowserChangeAttributes(inDataBrowser,
6296 inAttributesToSet, inAttributesToClear);
6297}
6298
6299 static void
6300initialise_tabline(void)
6301{
6302 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6303 DataBrowserCallbacks dbCallbacks;
6304 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6305 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6306 DataBrowserListViewColumnDesc colDesc;
6307
6308 // drawers have to have compositing enabled
6309 CreateNewWindow(kDrawerWindowClass,
6310 kWindowStandardHandlerAttribute
6311 | kWindowCompositingAttribute
6312 | kWindowResizableAttribute
6313 | kWindowLiveResizeAttribute,
6314 &drawerRect, &drawer);
6315
6316 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6317 SetDrawerParent(drawer, gui.VimWindow);
6318 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6319
6320
6321 // create list view embedded in drawer
6322 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6323 &dataBrowser);
6324
6325 dbCallbacks.version = kDataBrowserLatestCallbacks;
6326 InitDataBrowserCallbacks(&dbCallbacks);
6327 dbCallbacks.u.v1.itemDataCallback =
6328 NewDataBrowserItemDataUPP(dbItemDataCallback);
6329 dbCallbacks.u.v1.itemNotificationCallback =
6330 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6331 dbCallbacks.u.v1.getContextualMenuCallback =
6332 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6333 dbCallbacks.u.v1.selectContextualMenuCallback =
6334 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6335
6336 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6337
6338 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6339 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6340 SetDataBrowserSelectionFlags(dataBrowser,
6341 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6342 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6343 kDataBrowserTableViewFillHilite);
6344 Boolean b = false;
6345 SetControlData(dataBrowser, kControlEntireControl,
6346 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6347
6348 // enable blue background in data browser (this is only in 10.4 and vim
6349 // has to support older osx versions as well, so we have to load this
6350 // function dynamically)
6351 myDataBrowserChangeAttributes(dataBrowser,
6352 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6353
6354 // install callback that keeps focus in vim and away from the data browser
6355 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6356 NULL, NULL);
6357
6358 // install callback that keeps data browser at the size of the drawer
6359 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6360 NULL, NULL);
6361
6362 // add "tabs" column to data browser
6363 colDesc.propertyDesc.propertyID = kTabsColumn;
6364 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6365
6366 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6367 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6368
6369 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6370 colDesc.headerBtnDesc.minimumWidth = 100;
6371 colDesc.headerBtnDesc.maximumWidth = 150;
6372 colDesc.headerBtnDesc.titleOffset = 0;
6373 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6374 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6375 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6376 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6377
6378 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6379
6380 // create tabline popup menu required by vim docs (see :he tabline-menu)
6381 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6382 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6383 TABLINE_MENU_CLOSE, NULL);
6384 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6385 TABLINE_MENU_NEW, NULL);
6386 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6387 TABLINE_MENU_OPEN, NULL);
6388}
6389
6390
6391/*
6392 * Show or hide the tabline.
6393 */
6394 void
6395gui_mch_show_tabline(int showit)
6396{
6397 if (showit == 0)
6398 CloseDrawer(drawer, true);
6399 else
6400 OpenDrawer(drawer, kWindowEdgeRight, true);
6401}
6402
6403/*
6404 * Return TRUE when tabline is displayed.
6405 */
6406 int
6407gui_mch_showing_tabline(void)
6408{
6409 WindowDrawerState state = GetDrawerState(drawer);
6410
6411 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6412}
6413
6414/*
6415 * Update the labels of the tabline.
6416 */
6417 void
6418gui_mch_update_tabline(void)
6419{
6420 tabpage_T *tp;
6421 int numTabs = getTabCount();
6422 int nr = 1;
6423 int curtabidx = 1;
6424
6425 // adjust data browser
6426 if (tabLabels != NULL)
6427 {
6428 int i;
6429
6430 for (i = 0; i < tabLabelsSize; ++i)
6431 CFRelease(tabLabels[i]);
6432 free(tabLabels);
6433 }
6434 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6435 tabLabelsSize = numTabs;
6436
6437 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6438 {
6439 if (tp == curtab)
6440 curtabidx = nr;
6441 tabLabels[nr-1] = getTabLabel(tp);
6442 }
6443
6444 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6445 kDataBrowserItemNoProperty);
6446 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6447 // can pass NULL for the id array
6448 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6449 kDataBrowserItemNoProperty);
6450
6451 DataBrowserItemID item = curtabidx;
6452 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6453}
6454
6455/*
6456 * Set the current tab to "nr". First tab is 1.
6457 */
6458 void
6459gui_mch_set_curtab(nr)
6460 int nr;
6461{
6462 DataBrowserItemID item = nr;
6463 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6464
6465 // TODO: call something like this?: (or restore scroll position, or...)
6466 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6467 kDataBrowserRevealOnly);
6468}
6469
6470#endif // FEAT_GUI_TABLINE