blob: 77006a73a0a2b23a80b2fe4d2907a02ac6188e68 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Macintosh port by Dany St-Amant
6 * and Axel Kielhorn
Bram Moolenaar79ee3152007-04-26 16:20:50 +00007 * Port to MPW by Bernhard Pruemmer
Bram Moolenaar071d4272004-06-13 20:20:40 +00008 * Initial Carbon port by Ammon Skidmore
9 *
10 * Do ":help uganda" in Vim to read copying and usage conditions.
11 * Do ":help credits" in Vim to see a list of people who contributed.
12 * See README.txt for an overview of the Vim source code.
13 */
14
15/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000016 * NOTES: - Vim 7+ does not support classic MacOS. Please use Vim 6.x
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000017 * - Comments mentioning FAQ refer to the book:
18 * "Macworld Mac Programming FAQs" from "IDG Books"
Bram Moolenaar071d4272004-06-13 20:20:40 +000019 */
20
21/*
22 * TODO: Change still to merge from the macvim's iDisk
23 *
24 * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse
25 * uses of MenuItemIndex, changes in gui_mch_set_shellsize,
26 * ScrapManager error handling.
27 * Comments about function remaining to Carbonize.
28 *
29 */
30
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +000031/* TODO (Jussi)
32 * * Clipboard does not work (at least some cases)
33 * * ATSU font rendering has some problems
34 * * Investigate and remove dead code (there is still lots of that)
35 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000036
37#include <Devices.h> /* included first to avoid CR problems */
38#include "vim.h"
39
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000040#define USE_CARBONIZED
41#define USE_AEVENT /* Enable AEVENT */
42#undef USE_OFFSETED_WINDOW /* Debugging feature: start Vim window OFFSETed */
Bram Moolenaar071d4272004-06-13 20:20:40 +000043
44/* Compile as CodeWarior External Editor */
45#if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT)
46# define USE_AEVENT /* Need Apple Event Support */
47#endif
48
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000049/* Vim's Scrap flavor. */
50#define VIMSCRAPFLAVOR 'VIM!'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000051#ifdef FEAT_MBYTE
52# define SCRAPTEXTFLAVOR kScrapFlavorTypeUnicode
53#else
54# define SCRAPTEXTFLAVOR kScrapFlavorTypeText
55#endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +000056
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static EventHandlerUPP mouseWheelHandlerUPP = NULL;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +000058SInt32 gMacSystemVersion;
Bram Moolenaar071d4272004-06-13 20:20:40 +000059
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000060#ifdef MACOS_CONVERT
61# define USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +000062
63static int im_is_active = FALSE;
64#if 0
65static int im_start_row = 0;
66static int im_start_col = 0;
67#endif
68
69#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
70
71static TSMDocumentID gTSMDocument;
72
73static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000074static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000075static EventHandlerUPP winEventHandlerUPP = NULL;
76
77static pascal OSStatus gui_mac_handle_window_activate(
78 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
79
80static pascal OSStatus gui_mac_handle_text_input(
81 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
82
83static pascal OSStatus gui_mac_update_input_area(
84 EventHandlerCallRef nextHandler, EventRef theEvent);
85
86static pascal OSStatus gui_mac_unicode_key_event(
87 EventHandlerCallRef nextHandler, EventRef theEvent);
88
Bram Moolenaar26a60b42005-02-22 08:49:11 +000089#endif
90
Bram Moolenaar071d4272004-06-13 20:20:40 +000091
92/* Include some file. TODO: move into os_mac.h */
93#include <Menus.h>
94#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000095#include <Processes.h>
96#ifdef USE_AEVENT
97# include <AppleEvents.h>
98# include <AERegistry.h>
99#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
102# include <ControlDefinitions.h>
103# include <Navigation.h> /* Navigation only part of ?? */
104#endif
105
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000106/* Help Manager (balloon.h, HM prefixed functions) are not supported
107 * under Carbon (Jussi) */
108# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000110# include <MacHelp.h>
111# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112
113/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000114 * These seem to be rectangle options. Why are they not found in
115 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117#define kNothing 0
118#define kCreateEmpty 2 /*1*/
119#define kCreateRect 2
120#define kDestroy 3
121
122/*
123 * Dany: Don't like those...
124 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125#define topLeft(r) (((Point*)&(r))[0])
126#define botRight(r) (((Point*)&(r))[1])
127
128
129/* Time of last mouse click, to detect double-click */
130static long lastMouseTick = 0;
131
132/* ??? */
133static RgnHandle cursorRgn;
134static RgnHandle dragRgn;
135static Rect dragRect;
136static short dragRectEnbl;
137static short dragRectControl;
138
139/* This variable is set when waiting for an event, which is the only moment
140 * scrollbar dragging can be done directly. It's not allowed while commands
141 * are executed, because it may move the cursor and that may cause unexpected
142 * problems (e.g., while ":s" is working).
143 */
144static int allow_scrollbar = FALSE;
145
146/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148
149/* Feedback Action for Scrollbar */
150ControlActionUPP gScrollAction;
151ControlActionUPP gScrollDrag;
152
153/* Keeping track of which scrollbar is being dragged */
154static ControlHandle dragged_sb = NULL;
155
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000156static struct
157{
158 FMFontFamily family;
159 FMFontSize size;
160 FMFontStyle style;
161 Boolean isPanelVisible;
162} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000163
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000164#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000165# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000166int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000167ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000168# ifdef FEAT_MBYTE
169ATSUStyle gWideFontStyle;
170# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000171Boolean gIsFontFallbackSet;
172#endif
173
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174/* Colors Macros */
175#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
176#define Red(c) ((c & 0x00FF0000) >> 16)
177#define Green(c) ((c & 0x0000FF00) >> 8)
178#define Blue(c) ((c & 0x000000FF) >> 0)
179
180/* Key mapping */
181
182#define vk_Esc 0x35 /* -> 1B */
183
184#define vk_F1 0x7A /* -> 10 */
185#define vk_F2 0x78 /*0x63*/
186#define vk_F3 0x63 /*0x76*/
187#define vk_F4 0x76 /*0x60*/
188#define vk_F5 0x60 /*0x61*/
189#define vk_F6 0x61 /*0x62*/
190#define vk_F7 0x62 /*0x63*/ /*?*/
191#define vk_F8 0x64
192#define vk_F9 0x65
193#define vk_F10 0x6D
194#define vk_F11 0x67
195#define vk_F12 0x6F
196#define vk_F13 0x69
197#define vk_F14 0x6B
198#define vk_F15 0x71
199
200#define vk_Clr 0x47 /* -> 1B (ESC) */
201#define vk_Enter 0x4C /* -> 03 */
202
203#define vk_Space 0x31 /* -> 20 */
204#define vk_Tab 0x30 /* -> 09 */
205#define vk_Return 0x24 /* -> 0D */
206/* This is wrong for OSX, what is it for? */
207#define vk_Delete 0X08 /* -> 08 BackSpace */
208
209#define vk_Help 0x72 /* -> 05 */
210#define vk_Home 0x73 /* -> 01 */
211#define vk_PageUp 0x74 /* -> 0D */
212#define vk_FwdDelete 0x75 /* -> 7F */
213#define vk_End 0x77 /* -> 04 */
214#define vk_PageDown 0x79 /* -> 0C */
215
216#define vk_Up 0x7E /* -> 1E */
217#define vk_Down 0x7D /* -> 1F */
218#define vk_Left 0x7B /* -> 1C */
219#define vk_Right 0x7C /* -> 1D */
220
221#define vk_Undo vk_F1
222#define vk_Cut vk_F2
223#define vk_Copy vk_F3
224#define vk_Paste vk_F4
225#define vk_PrintScreen vk_F13
226#define vk_SCrollLock vk_F14
227#define vk_Pause vk_F15
228#define vk_NumLock vk_Clr
229#define vk_Insert vk_Help
230
231#define KeySym char
232
233static struct
234{
235 KeySym key_sym;
236 char_u vim_code0;
237 char_u vim_code1;
238} special_keys[] =
239{
240 {vk_Up, 'k', 'u'},
241 {vk_Down, 'k', 'd'},
242 {vk_Left, 'k', 'l'},
243 {vk_Right, 'k', 'r'},
244
245 {vk_F1, 'k', '1'},
246 {vk_F2, 'k', '2'},
247 {vk_F3, 'k', '3'},
248 {vk_F4, 'k', '4'},
249 {vk_F5, 'k', '5'},
250 {vk_F6, 'k', '6'},
251 {vk_F7, 'k', '7'},
252 {vk_F8, 'k', '8'},
253 {vk_F9, 'k', '9'},
254 {vk_F10, 'k', ';'},
255
256 {vk_F11, 'F', '1'},
257 {vk_F12, 'F', '2'},
258 {vk_F13, 'F', '3'},
259 {vk_F14, 'F', '4'},
260 {vk_F15, 'F', '5'},
261
262/* {XK_Help, '%', '1'}, */
263/* {XK_Undo, '&', '8'}, */
264/* {XK_BackSpace, 'k', 'b'}, */
265#ifndef MACOS_X
266 {vk_Delete, 'k', 'b'},
267#endif
268 {vk_Insert, 'k', 'I'},
269 {vk_FwdDelete, 'k', 'D'},
270 {vk_Home, 'k', 'h'},
271 {vk_End, '@', '7'},
272/* {XK_Prior, 'k', 'P'}, */
273/* {XK_Next, 'k', 'N'}, */
274/* {XK_Print, '%', '9'}, */
275
276 {vk_PageUp, 'k', 'P'},
277 {vk_PageDown, 'k', 'N'},
278
279 /* End of list marker: */
280 {(KeySym)0, 0, 0}
281};
282
283/*
284 * ------------------------------------------------------------
285 * Forward declaration (for those needed)
286 * ------------------------------------------------------------
287 */
288
289#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000290OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291#endif
292
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000293#ifdef FEAT_GUI_TABLINE
294static void initialise_tabline(void);
295static WindowRef drawer = NULL; // TODO: put into gui.h
296#endif
297
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000298#ifdef USE_ATSUI_DRAWING
299static void gui_mac_set_font_attributes(GuiFont font);
300static void gui_mac_dispose_atsui_style(void);
301#endif
302
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303/*
304 * ------------------------------------------------------------
305 * Conversion Utility
306 * ------------------------------------------------------------
307 */
308
309/*
310 * C2Pascal_save
311 *
312 * Allocate memory and convert the C-String passed in
313 * into a pascal string
314 *
315 */
316
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000317 char_u *
318C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319{
320 char_u *PascalString;
321 int len;
322
323 if (Cstring == NULL)
324 return NULL;
325
326 len = STRLEN(Cstring);
327
328 if (len > 255) /* Truncate if necessary */
329 len = 255;
330
331 PascalString = alloc(len + 1);
332 if (PascalString != NULL)
333 {
334 mch_memmove(PascalString + 1, Cstring, len);
335 PascalString[0] = len;
336 }
337
338 return PascalString;
339}
340
341/*
342 * C2Pascal_save_and_remove_backslash
343 *
344 * Allocate memory and convert the C-String passed in
345 * into a pascal string. Also remove the backslash at the same time
346 *
347 */
348
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000349 char_u *
350C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000351{
352 char_u *PascalString;
353 int len;
354 char_u *p, *c;
355
356 len = STRLEN(Cstring);
357
358 if (len > 255) /* Truncate if necessary */
359 len = 255;
360
361 PascalString = alloc(len + 1);
362 if (PascalString != NULL)
363 {
364 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
365 {
366 if ((*c == '\\') && (c[1] != 0))
367 {
368 c++;
369 }
370 *p = *c;
371 p++;
372 len++;
373 }
374 PascalString[0] = len;
375 }
376
377 return PascalString;
378}
379
380/*
381 * Convert the modifiers of an Event into vim's modifiers (mouse)
382 */
383
384 int_u
385EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
386{
387 int_u vimModifiers = 0x00;
388
389 if (macModifiers & (shiftKey | rightShiftKey))
390 vimModifiers |= MOUSE_SHIFT;
391 if (macModifiers & (controlKey | rightControlKey))
392 vimModifiers |= MOUSE_CTRL;
393 if (macModifiers & (optionKey | rightOptionKey))
394 vimModifiers |= MOUSE_ALT;
395#if 0
396 /* Not yet supported */
397 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
398 vimModifiers |= MOUSE_CMD;
399#endif
400 return (vimModifiers);
401}
402
403/*
404 * Convert the modifiers of an Event into vim's modifiers (keys)
405 */
406
407 static int_u
408EventModifiers2VimModifiers(EventModifiers macModifiers)
409{
410 int_u vimModifiers = 0x00;
411
412 if (macModifiers & (shiftKey | rightShiftKey))
413 vimModifiers |= MOD_MASK_SHIFT;
414 if (macModifiers & (controlKey | rightControlKey))
415 vimModifiers |= MOD_MASK_CTRL;
416 if (macModifiers & (optionKey | rightOptionKey))
417 vimModifiers |= MOD_MASK_ALT;
418#ifdef USE_CMD_KEY
419 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
420 vimModifiers |= MOD_MASK_CMD;
421#endif
422 return (vimModifiers);
423}
424
425/* Convert a string representing a point size into pixels. The string should
426 * be a positive decimal number, with an optional decimal point (eg, "12", or
427 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
428 * character is stored in *end. The flag "vertical" says whether this
429 * calculation is for a vertical (height) size or a horizontal (width) one.
430 *
431 * From gui_w48.c
432 */
433 static int
434points_to_pixels(char_u *str, char_u **end, int vertical)
435{
436 int pixels;
437 int points = 0;
438 int divisor = 0;
439
440 while (*str)
441 {
442 if (*str == '.' && divisor == 0)
443 {
444 /* Start keeping a divisor, for later */
445 divisor = 1;
446 continue;
447 }
448
449 if (!isdigit(*str))
450 break;
451
452 points *= 10;
453 points += *str - '0';
454 divisor *= 10;
455
456 ++str;
457 }
458
459 if (divisor == 0)
460 divisor = 1;
461
462 pixels = points/divisor;
463 *end = str;
464 return pixels;
465}
466
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000467#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000468/*
469 * Deletes all traces of any Windows-style mnemonic text (including any
470 * parentheses) from a menu item and returns the cleaned menu item title.
471 * The caller is responsible for releasing the returned string.
472 */
473 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000474menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000475{
476 CFStringRef name;
477 size_t menuTitleLen;
478 CFIndex displayLen;
479 CFRange mnemonicStart;
480 CFRange mnemonicEnd;
481 CFMutableStringRef cleanedName;
482
483 menuTitleLen = STRLEN(menu->dname);
484 name = mac_enc_to_cfstring(menu->dname, menuTitleLen);
485
486 if (name)
487 {
488 /* Simple mnemonic-removal algorithm, assumes single parenthesized
489 * mnemonic character towards the end of the menu text */
490 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
491 displayLen = CFStringGetLength(name);
492
493 if (mnemonicStart.location != kCFNotFound
494 && (mnemonicStart.location + 2) < displayLen
495 && CFStringGetCharacterAtIndex(name,
496 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
497 {
498 if (CFStringFindWithOptions(name, CFSTR(")"),
499 CFRangeMake(mnemonicStart.location + 1,
500 displayLen - mnemonicStart.location - 1),
501 kCFCompareBackwards, &mnemonicEnd) &&
502 (mnemonicStart.location + 2) == mnemonicEnd.location)
503 {
504 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
505 if (cleanedName)
506 {
507 CFStringDelete(cleanedName,
508 CFRangeMake(mnemonicStart.location,
509 mnemonicEnd.location + 1 -
510 mnemonicStart.location));
511
512 CFRelease(name);
513 name = cleanedName;
514 }
515 }
516 }
517 }
518
519 return name;
520}
521#endif
522
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523/*
524 * Convert a list of FSSpec aliases into a list of fullpathname
525 * character strings.
526 */
527
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000528 char_u **
529new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530{
531 char_u **fnames = NULL;
532 OSErr newError;
533 long fileCount;
534 FSSpec fileToOpen;
535 long actualSize;
536 AEKeyword dummyKeyword;
537 DescType dummyType;
538
539 /* Get number of files in list */
540 *error = AECountItems(theList, numFiles);
541 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000542 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543
544 /* Allocate the pointer list */
545 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
546
547 /* Empty out the list */
548 for (fileCount = 0; fileCount < *numFiles; fileCount++)
549 fnames[fileCount] = NULL;
550
551 /* Scan the list of FSSpec */
552 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
553 {
554 /* Get the alias for the nth file, convert to an FSSpec */
555 newError = AEGetNthPtr(theList, fileCount, typeFSS,
556 &dummyKeyword, &dummyType,
557 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
558 if (newError)
559 {
560 /* Caller is able to clean up */
561 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000562 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 }
564
565 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000566 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 }
568
569 return (fnames);
570}
571
572/*
573 * ------------------------------------------------------------
574 * CodeWarrior External Editor Support
575 * ------------------------------------------------------------
576 */
577#ifdef FEAT_CW_EDITOR
578
579/*
580 * Handle the Window Search event from CodeWarrior
581 *
582 * Description
583 * -----------
584 *
585 * The IDE sends the Window Search AppleEvent to the editor when it
586 * needs to know whether a particular file is open in the editor.
587 *
588 * Event Reply
589 * -----------
590 *
591 * None. Put data in the location specified in the structure received.
592 *
593 * Remarks
594 * -------
595 *
596 * When the editor receives this event, determine whether the specified
597 * file is open. If it is, return the modification date/time for that file
598 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000599 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 *
601 */
602
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603typedef struct WindowSearch WindowSearch;
604struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
605{
606 FSSpec theFile; // identifies the file
607 long *theDate; // where to put the modification date/time
608};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000610 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000611Handle_KAHL_SRCH_AE(
612 const AppleEvent *theAEvent,
613 AppleEvent *theReply,
614 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615{
616 OSErr error = noErr;
617 buf_T *buf;
618 int foundFile = false;
619 DescType typeCode;
620 WindowSearch SearchData;
621 Size actualSize;
622
623 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
624 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000625 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000627 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000629 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630
631 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
632 if (buf->b_ml.ml_mfp != NULL
633 && SearchData.theFile.parID == buf->b_FSSpec.parID
634 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
635 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
636 {
637 foundFile = true;
638 break;
639 }
640
641 if (foundFile == false)
642 *SearchData.theDate = fnfErr;
643 else
644 *SearchData.theDate = buf->b_mtime;
645
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 return error;
647};
648
649/*
650 * Handle the Modified (from IDE to Editor) event from CodeWarrior
651 *
652 * Description
653 * -----------
654 *
655 * The IDE sends this event to the external editor when it wants to
656 * know which files that are open in the editor have been modified.
657 *
658 * Parameters None.
659 * ----------
660 *
661 * Event Reply
662 * -----------
663 * The reply for this event is:
664 *
665 * keyDirectObject typeAEList required
666 * each element in the list is a structure of typeChar
667 *
668 * Remarks
669 * -------
670 *
671 * When building the reply event, include one element in the list for
672 * each open file that has been modified.
673 *
674 */
675
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676typedef struct ModificationInfo ModificationInfo;
677struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
678{
679 FSSpec theFile; // identifies the file
680 long theDate; // the date/time the file was last modified
681 short saved; // set this to zero when replying, unused
682};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000684 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000685Handle_KAHL_MOD_AE(
686 const AppleEvent *theAEvent,
687 AppleEvent *theReply,
688 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689{
690 OSErr error = noErr;
691 AEDescList replyList;
692 long numFiles;
693 ModificationInfo theFile;
694 buf_T *buf;
695
696 theFile.saved = 0;
697
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000698 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000700 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701
702 /* Send the reply */
703/* replyObject.descriptorType = typeNull;
704 replyObject.dataHandle = nil;*/
705
706/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
707 error = AECreateList(nil, 0, false, &replyList);
708 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000709 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710
711#if 0
712 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000714 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
715 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716 * sizeof(DescType))
717 */
718
719 /* AEPutDesc */
720#endif
721
722 numFiles = 0;
723 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
724 if (buf->b_ml.ml_mfp != NULL)
725 {
726 /* Add this file to the list */
727 theFile.theFile = buf->b_FSSpec;
728 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000729/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
730 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 };
732
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733#if 0
734 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735#endif
736
737 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000738 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 if (replyList.dataHandle)
741 AEDisposeDesc(&replyList);
742
743 return error;
744};
745
746/*
747 * Handle the Get Text event from CodeWarrior
748 *
749 * Description
750 * -----------
751 *
752 * The IDE sends the Get Text AppleEvent to the editor when it needs
753 * the source code from a file. For example, when the user issues a
754 * Check Syntax or Compile command, the compiler needs access to
755 * the source code contained in the file.
756 *
757 * Event Reply
758 * -----------
759 *
760 * None. Put data in locations specified in the structure received.
761 *
762 * Remarks
763 * -------
764 *
765 * When the editor receives this event, it must set the size of the handle
766 * in theText to fit the data in the file. It must then copy the entire
767 * contents of the specified file into the memory location specified in
768 * theText.
769 *
770 */
771
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772typedef struct CW_GetText CW_GetText;
773struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
774{
775 FSSpec theFile; /* identifies the file */
776 Handle theText; /* the location where you return the text (must be resized properly) */
777 long *unused; /* 0 (not used) */
778 long *theDate; /* where to put the modification date/time */
779};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000781 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000782Handle_KAHL_GTTX_AE(
783 const AppleEvent *theAEvent,
784 AppleEvent *theReply,
785 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786{
787 OSErr error = noErr;
788 buf_T *buf;
789 int foundFile = false;
790 DescType typeCode;
791 CW_GetText GetTextData;
792 Size actualSize;
793 char_u *line;
794 char_u *fullbuffer = NULL;
795 long linesize;
796 long lineStart;
797 long BufferSize;
798 long lineno;
799
800 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
801
802 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000803 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804
805 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
806 if (buf->b_ml.ml_mfp != NULL)
807 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
808 {
809 foundFile = true;
810 break;
811 }
812
813 if (foundFile)
814 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000815 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
817 {
818 /* Must use the right buffer */
819 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
820 linesize = STRLEN(line) + 1;
821 lineStart = BufferSize;
822 BufferSize += linesize;
823 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000824 SetHandleSize(GetTextData.theText, BufferSize);
825 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 break; /* Simple handling for now */
828 }
829 else
830 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000831 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000833 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000835 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 }
837 }
838 if (fullbuffer != NULL)
839 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000840 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000842 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 }
844 if (foundFile == false)
845 *GetTextData.theDate = fnfErr;
846 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000847/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 *GetTextData.theDate = buf->b_mtime;
849 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000851 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000853 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854}
855
856/*
857 *
858 */
859
860/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000861 pascal OSErr
862FindProcessBySignature(
863 const OSType targetType,
864 const OSType targetCreator,
865 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866{
867 OSErr anErr = noErr;
868 Boolean lookingForProcess = true;
869
870 ProcessInfoRec infoRec;
871
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000872 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 infoRec.processName = nil;
874 infoRec.processAppSpec = nil;
875
876 psnPtr->lowLongOfPSN = kNoProcess;
877 psnPtr->highLongOfPSN = kNoProcess;
878
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000879 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000881 anErr = GetNextProcess(psnPtr);
882 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 else
885 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000886 anErr = GetProcessInformation(psnPtr, &infoRec);
887 if ((anErr == noErr)
888 && (infoRec.processType == targetType)
889 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891 }
892 }
893
894 return anErr;
895}//end FindProcessBySignature
896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000897 void
898Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000900 OSErr anErr = noErr;
901 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
903 AppleEvent theReply = { typeNull, nil };
904 AESendMode sendMode;
905 AppleEvent theEvent = {typeNull, nil };
906 AEIdleUPP idleProcUPP = nil;
907 ModificationInfo ModData;
908
909
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000910 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000911 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000913 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
914 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 {
918 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
919 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
920 }
921
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000922 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923
924 /* Add the parms */
925 ModData.theFile = buf->b_FSSpec;
926 ModData.theDate = buf->b_mtime;
927
928 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000929 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000931 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932 sendMode = kAENoReply;
933 else
934 sendMode = kAEWaitReply;
935
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000936 if (anErr == noErr)
937 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
938 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000939 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000940/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000942 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943 }
944}
945#endif /* FEAT_CW_EDITOR */
946
947/*
948 * ------------------------------------------------------------
949 * Apple Event Handling procedure
950 * ------------------------------------------------------------
951 */
952#ifdef USE_AEVENT
953
954/*
955 * Handle the Unused parms of an AppleEvent
956 */
957
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000958 OSErr
959HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960{
961 OSErr error;
962 long actualSize;
963 DescType dummyType;
964 AEKeyword missedKeyword;
965
966 /* Get the "missed keyword" attribute from the AppleEvent. */
967 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
968 typeKeyword, &dummyType,
969 (Ptr)&missedKeyword, sizeof(missedKeyword),
970 &actualSize);
971
972 /* If the descriptor isn't found, then we got the required parameters. */
973 if (error == errAEDescNotFound)
974 {
975 error = noErr;
976 }
977 else
978 {
979#if 0
980 /* Why is this removed? */
981 error = errAEEventNotHandled;
982#endif
983 }
984
985 return error;
986}
987
988
989/*
990 * Handle the ODoc AppleEvent
991 *
992 * Deals with all files dragged to the application icon.
993 *
994 */
995
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996typedef struct SelectionRange SelectionRange;
997struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
998{
999 short unused1; // 0 (not used)
1000 short lineNum; // line to select (<0 to specify range)
1001 long startRange; // start of selection range (if line < 0)
1002 long endRange; // end of selection range (if line < 0)
1003 long unused2; // 0 (not used)
1004 long theDate; // modification date/time
1005};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006
1007/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1008 itor the selection range. If lineNum is zero or greater, scroll the text
1009 to the specified line. If lineNum is less than zero, use the values in
1010 startRange and endRange to select the specified characters. Scroll
1011 the text to display the selection. If lineNum, startRange, and
1012 endRange are all negative, there is no selection range specified.
1013 */
1014
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001015 pascal OSErr
1016HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017{
1018 /*
1019 * TODO: Clean up the code with convert the AppleEvent into
1020 * a ":args"
1021 */
1022 OSErr error = noErr;
1023// OSErr firstError = noErr;
1024// short numErrors = 0;
1025 AEDesc theList;
1026 DescType typeCode;
1027 long numFiles;
1028 // long fileCount;
1029 char_u **fnames;
1030// char_u fname[256];
1031 Size actualSize;
1032 SelectionRange thePosition;
1033 short gotPosition = false;
1034 long lnum;
1035
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 /* the direct object parameter is the list of aliases to files (one or more) */
1037 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1038 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001039 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040
1041
1042 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1043 if (error == noErr)
1044 gotPosition = true;
1045 if (error == errAEDescNotFound)
1046 error = noErr;
1047 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001048 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050/*
1051 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1052
1053 if (^error) then
1054 {
1055 if (thePosition.lineNum >= 0)
1056 {
1057 // Goto this line
1058 }
1059 else
1060 {
1061 // Set the range char wise
1062 }
1063 }
1064 */
1065
1066
1067#ifdef FEAT_VISUAL
1068 reset_VIsual();
1069#endif
1070
1071 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1072
1073 if (error)
1074 {
1075 /* TODO: empty fnames[] first */
1076 vim_free(fnames);
1077 return (error);
1078 }
1079
1080 if (starting > 0)
1081 {
1082 int i;
1083 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001084 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085
1086 /* these are the initial files dropped on the Vim icon */
1087 for (i = 0 ; i < numFiles; i++)
1088 {
1089 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1090 || (p = vim_strsave(fnames[i])) == NULL)
1091 mch_exit(2);
1092 else
1093 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001094 if (fnum == -1)
1095 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1096 }
1097
1098 /* If the file name was already in the buffer list we need to switch
1099 * to it. */
1100 if (curbuf->b_fnum != fnum)
1101 {
1102 char_u cmd[30];
1103
1104 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1105 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001107
1108 /* Change directory to the location of the first file. */
1109 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1110 shorten_fnames(TRUE);
1111
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 goto finished;
1113 }
1114
1115 /* Handle the drop, :edit to get to the file */
1116 handle_drop(numFiles, fnames, FALSE);
1117
1118 /* TODO: Handle the goto/select line more cleanly */
1119 if ((numFiles == 1) & (gotPosition))
1120 {
1121 if (thePosition.lineNum >= 0)
1122 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001123 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 /* oap->motion_type = MLINE;
1125 setpcmark();*/
1126 if (lnum < 1L)
1127 lnum = 1L;
1128 else if (lnum > curbuf->b_ml.ml_line_count)
1129 lnum = curbuf->b_ml.ml_line_count;
1130 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001131 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 /* beginline(BL_SOL | BL_FIX);*/
1133 }
1134 else
1135 goto_byte(thePosition.startRange + 1);
1136 }
1137
1138 /* Update the screen display */
1139 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001140#ifdef FEAT_VISUAL
1141 /* Select the text if possible */
1142 if (gotPosition)
1143 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001144 VIsual_active = TRUE;
1145 VIsual_select = FALSE;
1146 VIsual = curwin->w_cursor;
1147 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001148 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001149 VIsual_mode = 'v';
1150 goto_byte(thePosition.endRange);
1151 }
1152 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001153 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001154 VIsual_mode = 'V';
1155 VIsual.col = 0;
1156 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001157 }
1158#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159 setcursor();
1160 out_flush();
1161
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001162 /* Fake mouse event to wake from stall */
1163 PostEvent(mouseUp, 0);
1164
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001165finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001166 AEDisposeDesc(&theList); /* dispose what we allocated */
1167
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001168 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001169 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170}
1171
1172/*
1173 *
1174 */
1175
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001176 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001177Handle_aevt_oapp_AE(
1178 const AppleEvent *theAEvent,
1179 AppleEvent *theReply,
1180 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181{
1182 OSErr error = noErr;
1183
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001184 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001185 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186}
1187
1188/*
1189 *
1190 */
1191
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001192 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001193Handle_aevt_quit_AE(
1194 const AppleEvent *theAEvent,
1195 AppleEvent *theReply,
1196 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197{
1198 OSErr error = noErr;
1199
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001200 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001202 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203
1204 /* Need to fake a :confirm qa */
1205 do_cmdline_cmd((char_u *)"confirm qa");
1206
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001207 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208}
1209
1210/*
1211 *
1212 */
1213
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001214 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001215Handle_aevt_pdoc_AE(
1216 const AppleEvent *theAEvent,
1217 AppleEvent *theReply,
1218 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219{
1220 OSErr error = noErr;
1221
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001222 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001224 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225}
1226
1227/*
1228 * Handling of unknown AppleEvent
1229 *
1230 * (Just get rid of all the parms)
1231 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001232 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001233Handle_unknown_AE(
1234 const AppleEvent *theAEvent,
1235 AppleEvent *theReply,
1236 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237{
1238 OSErr error = noErr;
1239
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001240 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001242 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243}
1244
1245
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246/*
1247 * Install the various AppleEvent Handlers
1248 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001249 OSErr
1250InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251{
1252 OSErr error;
1253
1254 /* install open application handler */
1255 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001256 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 if (error)
1258 {
1259 return error;
1260 }
1261
1262 /* install quit application handler */
1263 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001264 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 if (error)
1266 {
1267 return error;
1268 }
1269
1270 /* install open document handler */
1271 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001272 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273 if (error)
1274 {
1275 return error;
1276 }
1277
1278 /* install print document handler */
1279 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001280 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281
1282/* Install Core Suite */
1283/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001284 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285
1286 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001287 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288
1289 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001290 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291
1292 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001293 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294
1295 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001296 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297
1298 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001299 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300
1301 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001302 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303
1304 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001305 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306
1307 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001308 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309
1310 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001311 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312
1313 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001314 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315
1316 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001317 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318
1319 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001320 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321*/
1322
1323#ifdef FEAT_CW_EDITOR
1324 /*
1325 * Bind codewarrior support handlers
1326 */
1327 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001328 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329 if (error)
1330 {
1331 return error;
1332 }
1333 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001334 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001335 if (error)
1336 {
1337 return error;
1338 }
1339 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001340 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 if (error)
1342 {
1343 return error;
1344 }
1345#endif
1346
1347 return error;
1348
1349}
1350#endif /* USE_AEVENT */
1351
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001352
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001353/*
1354 * Callback function, installed by InstallFontPanelHandler(), below,
1355 * to handle Font Panel events.
1356 */
1357 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001358FontPanelHandler(
1359 EventHandlerCallRef inHandlerCallRef,
1360 EventRef inEvent,
1361 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001362{
1363 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1364 {
1365 gFontPanelInfo.isPanelVisible = false;
1366 return noErr;
1367 }
1368
1369 if (GetEventKind(inEvent) == kEventFontSelection)
1370 {
1371 OSStatus status;
1372 FMFontFamily newFamily;
1373 FMFontSize newSize;
1374 FMFontStyle newStyle;
1375
1376 /* Retrieve the font family ID number. */
1377 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1378 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1379 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1380 &newFamily);
1381 if (status == noErr)
1382 gFontPanelInfo.family = newFamily;
1383
1384 /* Retrieve the font size. */
1385 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1386 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1387 if (status == noErr)
1388 gFontPanelInfo.size = newSize;
1389
1390 /* Retrieve the font style (bold, etc.). Currently unused. */
1391 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1392 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1393 if (status == noErr)
1394 gFontPanelInfo.style = newStyle;
1395 }
1396 return noErr;
1397}
1398
1399
1400 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001401InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001402{
1403 EventTypeSpec eventTypes[2];
1404 EventHandlerUPP handlerUPP;
1405 /* EventHandlerRef handlerRef; */
1406
1407 eventTypes[0].eventClass = kEventClassFont;
1408 eventTypes[0].eventKind = kEventFontSelection;
1409 eventTypes[1].eventClass = kEventClassFont;
1410 eventTypes[1].eventKind = kEventFontPanelClosed;
1411
1412 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1413
1414 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1415 /*userData=*/NULL, /*handlerRef=*/NULL);
1416}
1417
1418
1419/*
1420 * Fill the buffer pointed to by outName with the name and size
1421 * of the font currently selected in the Font Panel.
1422 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001423#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001424 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001425GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001426{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001427 Str255 buf;
1428 ByteCount fontNameLen = 0;
1429 ATSUFontID fid;
1430 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001431
1432 if (!outName)
1433 return;
1434
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001435 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1436 {
1437 /* Canonicalize localized font names */
1438 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1439 gFontPanelInfo.style, &fid, NULL) != noErr)
1440 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001441
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001442 /* Request font name with Mac encoding (otherwise we could
1443 * get an unwanted utf-16 name) */
1444 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1445 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001446 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001447 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001448
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001449 /* Only encode font size, because style (bold, italic, etc) is
1450 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001451 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001452 gFontPanelInfo.size/*,
1453 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1454 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1455 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1456
1457 if ((fontNameLen + STRLEN(styleString)) < 255)
1458 STRCPY(outName + fontNameLen, styleString);
1459 }
1460 else
1461 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001462 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001463 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001464}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001465
1466
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467/*
1468 * ------------------------------------------------------------
1469 * Unfiled yet
1470 * ------------------------------------------------------------
1471 */
1472
1473/*
1474 * gui_mac_get_menu_item_index
1475 *
1476 * Returns the index inside the menu wher
1477 */
1478 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001479gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480{
1481 short index;
1482 short itemIndex = -1;
1483 vimmenu_T *pBrother;
1484
1485 /* Only menu without parent are the:
1486 * -menu in the menubar
1487 * -popup menu
1488 * -toolbar (guess)
1489 *
1490 * Which are not items anyway.
1491 */
1492 if (pMenu->parent)
1493 {
1494 /* Start from the Oldest Brother */
1495 pBrother = pMenu->parent->children;
1496 index = 1;
1497 while ((pBrother) && (itemIndex == -1))
1498 {
1499 if (pBrother == pMenu)
1500 itemIndex = index;
1501 index++;
1502 pBrother = pBrother->next;
1503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 }
1505 return itemIndex;
1506}
1507
1508 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001509gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510{
1511 short index;
1512 vimmenu_T *pChildMenu;
1513 vimmenu_T *pElder = pMenu->parent;
1514
1515
1516 /* Only menu without parent are the:
1517 * -menu in the menubar
1518 * -popup menu
1519 * -toolbar (guess)
1520 *
1521 * Which are not items anyway.
1522 */
1523
1524 if ((pElder) && (pElder->submenu_id == menuID))
1525 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1527 pMenu = pMenu->next;
1528 }
1529 else
1530 {
1531 for (; pMenu != NULL; pMenu = pMenu->next)
1532 {
1533 if (pMenu->children != NULL)
1534 {
1535 pChildMenu = gui_mac_get_vim_menu
1536 (menuID, itemIndex, pMenu->children);
1537 if (pChildMenu)
1538 {
1539 pMenu = pChildMenu;
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 return pMenu;
1546}
1547
1548/*
1549 * ------------------------------------------------------------
1550 * MacOS Feedback procedures
1551 * ------------------------------------------------------------
1552 */
1553 pascal
1554 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001555gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556{
1557 scrollbar_T *sb;
1558 int value, dragging;
1559 ControlHandle theControlToUse;
1560 int dont_scroll_save = dont_scroll;
1561
1562 theControlToUse = dragged_sb;
1563
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001564 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565
1566 if (sb == NULL)
1567 return;
1568
1569 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001570 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 dragging = (partCode != 0);
1572
1573 /* When "allow_scrollbar" is FALSE still need to remember the new
1574 * position, but don't actually scroll by setting "dont_scroll". */
1575 dont_scroll = !allow_scrollbar;
1576 gui_drag_scrollbar(sb, value, dragging);
1577 dont_scroll = dont_scroll_save;
1578}
1579
1580 pascal
1581 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001582gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583{
1584 /* TODO: have live support */
1585 scrollbar_T *sb, *sb_info;
1586 long data;
1587 long value;
1588 int page;
1589 int dragging = FALSE;
1590 int dont_scroll_save = dont_scroll;
1591
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001592 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 if (sb == NULL)
1595 return;
1596
1597 if (sb->wp != NULL) /* Left or right scrollbar */
1598 {
1599 /*
1600 * Careful: need to get scrollbar info out of first (left) scrollbar
1601 * for window, but keep real scrollbar too because we must pass it to
1602 * gui_drag_scrollbar().
1603 */
1604 sb_info = &sb->wp->w_scrollbars[0];
1605
1606 if (sb_info->size > 5)
1607 page = sb_info->size - 2; /* use two lines of context */
1608 else
1609 page = sb_info->size;
1610 }
1611 else /* Bottom scrollbar */
1612 {
1613 sb_info = sb;
1614 page = W_WIDTH(curwin) - 5;
1615 }
1616
1617 switch (partCode)
1618 {
1619 case kControlUpButtonPart: data = -1; break;
1620 case kControlDownButtonPart: data = 1; break;
1621 case kControlPageDownPart: data = page; break;
1622 case kControlPageUpPart: data = -page; break;
1623 default: data = 0; break;
1624 }
1625
1626 value = sb_info->value + data;
1627/* if (value > sb_info->max)
1628 value = sb_info->max;
1629 else if (value < 0)
1630 value = 0;*/
1631
1632 /* When "allow_scrollbar" is FALSE still need to remember the new
1633 * position, but don't actually scroll by setting "dont_scroll". */
1634 dont_scroll = !allow_scrollbar;
1635 gui_drag_scrollbar(sb, value, dragging);
1636 dont_scroll = dont_scroll_save;
1637
1638 out_flush();
1639 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1640
1641/* if (sb_info->wp != NULL)
1642 {
1643 win_T *wp;
1644 int sb_num;
1645
1646 sb_num = 0;
1647 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1648 sb_num++;
1649
1650 if (wp != NULL)
1651 {
1652 current_scrollbar = sb_num;
1653 scrollbar_value = value;
1654 gui_do_scroll();
1655 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1656 }
1657 }*/
1658}
1659
1660/*
1661 * ------------------------------------------------------------
1662 * MacOS Click Handling procedures
1663 * ------------------------------------------------------------
1664 */
1665
1666
1667/*
1668 * Handle a click inside the window, it may happens in the
1669 * scrollbar or the contents.
1670 *
1671 * TODO: Add support for potential TOOLBAR
1672 */
1673 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001674gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675{
1676 Point thePoint;
1677 int_u vimModifiers;
1678 short thePortion;
1679 ControlHandle theControl;
1680 int vimMouseButton;
1681 short dblClick;
1682
1683 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001684 GlobalToLocal(&thePoint);
1685 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001687 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688
1689 if (theControl != NUL)
1690 {
1691 /* We hit a scollbar */
1692
1693 if (thePortion != kControlIndicatorPart)
1694 {
1695 dragged_sb = theControl;
1696 TrackControl(theControl, thePoint, gScrollAction);
1697 dragged_sb = NULL;
1698 }
1699 else
1700 {
1701 dragged_sb = theControl;
1702#if 1
1703 TrackControl(theControl, thePoint, gScrollDrag);
1704#else
1705 TrackControl(theControl, thePoint, NULL);
1706#endif
1707 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1708 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001709 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 dragged_sb = NULL;
1711 }
1712 }
1713 else
1714 {
1715 /* We are inside the contents */
1716
1717 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1718 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1719
1720 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1721 vimMouseButton = MOUSE_LEFT;
1722
Bram Moolenaar071d4272004-06-13 20:20:40 +00001723 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001724 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 clickIsPopup = FALSE;
1726
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001727 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1728 {
1729 vimMouseButton = MOUSE_RIGHT;
1730 vimModifiers &= ~MOUSE_CTRL;
1731 clickIsPopup = TRUE;
1732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733
1734 /* Is it a double click ? */
1735 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1736
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001737 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 gui_send_mouse_event(vimMouseButton, thePoint.h,
1739 thePoint.v, dblClick, vimModifiers);
1740
1741 /* Create the rectangle around the cursor to detect
1742 * the mouse dragging
1743 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744#if 0
1745 /* TODO: Do we need to this even for the contextual menu?
1746 * It may be require for popup_setpos, but for popup?
1747 */
1748 if (vimMouseButton == MOUSE_LEFT)
1749#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001751 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 FILL_Y(Y_2_ROW(thePoint.v)),
1753 FILL_X(X_2_COL(thePoint.h)+1),
1754 FILL_Y(Y_2_ROW(thePoint.v)+1));
1755
1756 dragRectEnbl = TRUE;
1757 dragRectControl = kCreateRect;
1758 }
1759 }
1760}
1761
1762/*
1763 * Handle the click in the titlebar (to move the window)
1764 */
1765 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001766gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767{
1768 Rect movingLimits;
1769 Rect *movingLimitsPtr = &movingLimits;
1770
1771 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001772 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001773 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774}
1775
1776/*
1777 * Handle the click in the grow box
1778 */
1779 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001780gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781{
1782
1783 long newSize;
1784 unsigned short newWidth;
1785 unsigned short newHeight;
1786 Rect resizeLimits;
1787 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 Rect NewContentRect;
1789
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001790 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791
Bram Moolenaar720c7102007-05-10 18:07:50 +00001792 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 /* TODO: Should this come from Vim? */
1794 resizeLimits.top = 100;
1795 resizeLimits.left = 100;
1796
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1798 newWidth = NewContentRect.right - NewContentRect.left;
1799 newHeight = NewContentRect.bottom - NewContentRect.top;
1800 gui_resize_shell(newWidth, newHeight);
1801 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001802 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803}
1804
1805/*
1806 * Handle the click in the zoom box
1807 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001809gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810{
1811 Rect r;
1812 Point p;
1813 short thePart;
1814
1815 /* ideal width is current */
1816 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1817 if (gui.which_scrollbars[SBAR_LEFT])
1818 p.h += gui.scrollbar_width;
1819 if (gui.which_scrollbars[SBAR_RIGHT])
1820 p.h += gui.scrollbar_width;
1821 /* ideal height is as heigh as we can get */
1822 p.v = 15 * 1024;
1823
1824 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1825 ? inZoomIn : inZoomOut;
1826
1827 if (!TrackBox(whichWindow, theEvent->where, thePart))
1828 return;
1829
1830 /* use returned width */
1831 p.h = r.right - r.left;
1832 /* adjust returned height */
1833 p.v = r.bottom - r.top - 2 * gui.border_offset;
1834 if (gui.which_scrollbars[SBAR_BOTTOM])
1835 p.v -= gui.scrollbar_height;
1836 p.v -= p.v % gui.char_height;
1837 p.v += 2 * gui.border_width;
1838 if (gui.which_scrollbars[SBAR_BOTTOM]);
1839 p.v += gui.scrollbar_height;
1840
1841 ZoomWindowIdeal(whichWindow, thePart, &p);
1842
1843 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1844 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1845 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001846 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849/*
1850 * ------------------------------------------------------------
1851 * MacOS Event Handling procedure
1852 * ------------------------------------------------------------
1853 */
1854
1855/*
1856 * Handle the Update Event
1857 */
1858
1859 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001860gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861{
1862 WindowPtr whichWindow;
1863 GrafPtr savePort;
1864 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 Rect *updateRectPtr;
1867 Rect rc;
1868 Rect growRect;
1869 RgnHandle saveRgn;
1870
1871
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 updateRgn = NewRgn();
1873 if (updateRgn == NULL)
1874 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875
1876 /* This could be done by the caller as we
1877 * don't require anything else out of the event
1878 */
1879 whichWindow = (WindowPtr) event->message;
1880
1881 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001882 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883
1884 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001885 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001888 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 /* Redraw the biggest rectangle covering the area
1890 * to be updated.
1891 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1893# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001894 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 * seem to work under MacOS X (Dany)
1896 */
1897 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1898# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001899
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001901 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001902
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001903 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904# if 0
1905 /* Code from original Carbon Port (using GetWindowRegion.
1906 * I believe the UpdateRgn is already in local (Dany)
1907 */
1908 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1909 GlobalToLocal(&botRight(updateRect));
1910# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 /* Update the content (i.e. the text) */
1912 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1913 updateRectPtr->right - updateRectPtr->left,
1914 updateRectPtr->bottom - updateRectPtr->top);
1915 /* Clear the border areas if needed */
1916 gui_mch_set_bg_color(gui.back_pixel);
1917 if (updateRectPtr->left < FILL_X(0))
1918 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001919 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1920 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
1922 if (updateRectPtr->top < FILL_Y(0))
1923 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001924 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1925 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 }
1927 if (updateRectPtr->right > FILL_X(Columns))
1928 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001929 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001931 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 }
1933 if (updateRectPtr->bottom > FILL_Y(Rows))
1934 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001937 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941
1942 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
1945 /* Update the GrowBox */
1946 /* Taken from FAQ 33-27 */
1947 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001949 GetClip(saveRgn);
1950 ClipRect(&growRect);
1951 DrawGrowIcon(whichWindow);
1952 SetClip(saveRgn);
1953 DisposeRgn(saveRgn);
1954 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955
1956 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001957 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958}
1959
1960/*
1961 * Handle the activate/deactivate event
1962 * (apply to a window)
1963 */
1964 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001965gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966{
1967 WindowPtr whichWindow;
1968
1969 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001970 /* Dim scrollbars */
1971 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001973 ControlRef rootControl;
1974 GetRootControl(gui.VimWindow, &rootControl);
1975 if ((event->modifiers) & activeFlag)
1976 ActivateControl(rootControl);
1977 else
1978 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001980
1981 /* Activate */
1982 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983}
1984
1985
1986/*
1987 * Handle the suspend/resume event
1988 * (apply to the application)
1989 */
1990 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001991gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992{
1993 /* The frontmost application just changed */
1994
1995 /* NOTE: the suspend may happen before the deactivate
1996 * seen on MacOS X
1997 */
1998
1999 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002000 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001 */
2002 if (event->message & 1)
2003 /* Resume */
2004 gui_focus_change(TRUE);
2005 else
2006 /* Suspend */
2007 gui_focus_change(FALSE);
2008}
2009
2010/*
2011 * Handle the key
2012 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002013#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002014 static pascal OSStatus
2015gui_mac_handle_window_activate(
2016 EventHandlerCallRef nextHandler,
2017 EventRef theEvent,
2018 void *data)
2019{
2020 UInt32 eventClass = GetEventClass(theEvent);
2021 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002022
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002023 if (eventClass == kEventClassWindow)
2024 {
2025 switch (eventKind)
2026 {
2027 case kEventWindowActivated:
2028#if defined(USE_IM_CONTROL)
2029 im_on_window_switch(TRUE);
2030#endif
2031 return noErr;
2032
2033 case kEventWindowDeactivated:
2034#if defined(USE_IM_CONTROL)
2035 im_on_window_switch(FALSE);
2036#endif
2037 return noErr;
2038 }
2039 }
2040
2041 return eventNotHandledErr;
2042}
2043
2044 static pascal OSStatus
2045gui_mac_handle_text_input(
2046 EventHandlerCallRef nextHandler,
2047 EventRef theEvent,
2048 void *data)
2049{
2050 UInt32 eventClass = GetEventClass(theEvent);
2051 UInt32 eventKind = GetEventKind(theEvent);
2052
2053 if (eventClass != kEventClassTextInput)
2054 return eventNotHandledErr;
2055
2056 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2057 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2058 (kEventTextInputOffsetToPos != eventKind) &&
2059 (kEventTextInputPosToOffset != eventKind) &&
2060 (kEventTextInputGetSelectedText != eventKind))
2061 return eventNotHandledErr;
2062
2063 switch (eventKind)
2064 {
2065 case kEventTextInputUpdateActiveInputArea:
2066 return gui_mac_update_input_area(nextHandler, theEvent);
2067 case kEventTextInputUnicodeForKeyEvent:
2068 return gui_mac_unicode_key_event(nextHandler, theEvent);
2069
2070 case kEventTextInputOffsetToPos:
2071 case kEventTextInputPosToOffset:
2072 case kEventTextInputGetSelectedText:
2073 break;
2074 }
2075
2076 return eventNotHandledErr;
2077}
2078
2079 static pascal
2080OSStatus gui_mac_update_input_area(
2081 EventHandlerCallRef nextHandler,
2082 EventRef theEvent)
2083{
2084 return eventNotHandledErr;
2085}
2086
2087static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2088 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002089
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002090# define INLINE_KEY_BUFFER_SIZE 80
2091 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002092gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002093 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002094 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002095{
2096 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002097 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002098 UInt32 actualSize;
2099 UniChar *text;
2100 char_u result[INLINE_KEY_BUFFER_SIZE];
2101 short len = 0;
2102 UInt32 key_sym;
2103 char charcode;
2104 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002105 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002106 size_t encLen;
2107 char_u *to = NULL;
2108 Boolean isSpecial = FALSE;
2109 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002110 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002112 /* Mask the mouse (as per user setting) */
2113 if (p_mh)
2114 ObscureCursor();
2115
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002116 /* Don't use the keys when the dialog wants them. */
2117 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002118 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002121 typeUnicodeText, NULL, 0, &actualSize, NULL))
2122 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 text = (UniChar *)alloc(actualSize);
2125 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002126 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002127
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002128 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002129 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002130 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002131
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002132 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002133 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002134 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002135
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002136 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002138 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002139
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002140 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002141 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002142 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002143
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002144 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002145 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002146 require_noerr(err, done);
2147
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002148#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002149 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002150 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002151#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002153 key_char = charcode;
2154 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002156 /* Find the special key (eg., for cursor keys) */
2157 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002158 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002159 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002160 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2161 if (special_keys[i].key_sym == key_sym)
2162 {
2163 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2164 special_keys[i].vim_code1);
2165 key_char = simplify_key(key_char,
2166 (int *)&vimModifiers);
2167 isSpecial = TRUE;
2168 break;
2169 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002170 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002171
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002172 /* Intercept CMD-. and CTRL-c */
2173 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002174 ((modifiers & cmdKey) && key_char == '.'))
2175 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002176
2177 if (!isSpecial)
2178 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002179 /* remove SHIFT for keys that are already shifted, e.g.,
2180 * '(' and '*' */
2181 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2182 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002183
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002184 /* remove CTRL from keys that already have it */
2185 if (key_char < 0x20)
2186 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002187
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002188 /* don't process unicode characters here */
2189 if (!IS_SPECIAL(key_char))
2190 {
2191 /* Following code to simplify and consolidate vimModifiers
2192 * taken liberally from gui_w48.c */
2193 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002194
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002195 /* Interpret META, include SHIFT, etc. */
2196 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2197 if (key_char == CSI)
2198 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002199
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002200 if (IS_SPECIAL(key_char))
2201 isSpecial = TRUE;
2202 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002203 }
2204
2205 if (vimModifiers)
2206 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002207 result[len++] = CSI;
2208 result[len++] = KS_MODIFIER;
2209 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002210 }
2211
2212 if (isSpecial && IS_SPECIAL(key_char))
2213 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002214 result[len++] = CSI;
2215 result[len++] = K_SECOND(key_char);
2216 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002217 }
2218 else
2219 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002220 encLen = actualSize;
2221 to = mac_utf16_to_enc(text, actualSize, &encLen);
2222 if (to)
2223 {
2224 /* This is basically add_to_input_buf_csi() */
2225 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2226 {
2227 result[len++] = to[i];
2228 if (to[i] == CSI)
2229 {
2230 result[len++] = KS_EXTRA;
2231 result[len++] = (int)KE_CSI;
2232 }
2233 }
2234 vim_free(to);
2235 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002236 }
2237
2238 add_to_input_buf(result, len);
2239 err = noErr;
2240
2241done:
2242 vim_free(text);
2243 if (err == noErr)
2244 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002245 /* Fake event to wake up WNE (required to get
2246 * key repeat working */
2247 PostEvent(keyUp, 0);
2248 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002249 }
2250
2251 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002252}
2253#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 void
2255gui_mac_doKeyEvent(EventRecord *theEvent)
2256{
2257 /* TODO: add support for COMMAND KEY */
2258 long menu;
2259 unsigned char string[20];
2260 short num, i;
2261 short len = 0;
2262 KeySym key_sym;
2263 int key_char;
2264 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002265 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266
2267 /* Mask the mouse (as per user setting) */
2268 if (p_mh)
2269 ObscureCursor();
2270
2271 /* Get the key code and it's ASCII representation */
2272 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2273 key_char = theEvent->message & charCodeMask;
2274 num = 1;
2275
2276 /* Intercept CTRL-C */
2277 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002278 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 if (key_char == Ctrl_C && ctrl_c_interrupts)
2280 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002281 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2282 && (key_char == '2' || key_char == '6'))
2283 {
2284 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2285 if (key_char == '2')
2286 key_char = Ctrl_AT;
2287 else
2288 key_char = Ctrl_HAT;
2289 theEvent->modifiers = 0;
2290 }
2291 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292
2293 /* Intercept CMD-. */
2294 if (theEvent->modifiers & cmdKey)
2295 if (key_char == '.')
2296 got_int = TRUE;
2297
2298 /* Handle command key as per menu */
2299 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2300 if (theEvent->modifiers & cmdKey)
2301 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2302 * Why the mouse button? */
2303 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2304 {
2305 menu = MenuKey(key_char);
2306 if (HiWord(menu))
2307 {
2308 gui_mac_handle_menu(menu);
2309 return;
2310 }
2311 }
2312
2313 /* Convert the modifiers */
2314 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2315
2316
2317 /* Handle special keys. */
2318#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002319 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2321#endif
2322 {
2323 /* Find the special key (for non-printable keyt_char) */
2324 if ((key_char < 0x20) || (key_char == 0x7f))
2325 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2326 if (special_keys[i].key_sym == key_sym)
2327 {
2328# if 0
2329 /* We currently don't have not so special key */
2330 if (special_keys[i].vim_code1 == NUL)
2331 key_char = special_keys[i].vim_code0;
2332 else
2333# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002334 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2335 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002336 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 break;
2338 }
2339 }
2340
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002341 /* For some keys the modifier is included in the char itself. */
2342 if (simplify || key_char == TAB || key_char == ' ')
2343 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344
2345 /* Add the modifier to the input bu if needed */
2346 /* Do not want SHIFT-A or CTRL-A with modifier */
2347 if (!IS_SPECIAL(key_char)
2348 && key_sym != vk_Space
2349 && key_sym != vk_Tab
2350 && key_sym != vk_Return
2351 && key_sym != vk_Enter
2352 && key_sym != vk_Esc)
2353 {
2354#if 1
2355 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002356 if ((modifiers == MOD_MASK_SHIFT)
2357 || (modifiers == MOD_MASK_CTRL)
2358 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 modifiers = 0;
2360#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002361 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002363 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002365 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 modifiers = modifiers & ~MOD_MASK_SHIFT;
2367#endif
2368 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002369 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002371 string[len++] = CSI;
2372 string[len++] = KS_MODIFIER;
2373 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 }
2375
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002376 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002378 string[len++] = CSI;
2379 string[len++] = K_SECOND(key_char);
2380 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 }
2382 else
2383 {
2384#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002385 /* Convert characters when needed (e.g., from MacRoman to latin1).
2386 * This doesn't work for the NUL byte. */
2387 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 {
2389 char_u from[2], *to;
2390 int l;
2391
2392 from[0] = key_char;
2393 from[1] = NUL;
2394 l = 1;
2395 to = string_convert(&input_conv, from, &l);
2396 if (to != NULL)
2397 {
2398 for (i = 0; i < l && len < 19; i++)
2399 {
2400 if (to[i] == CSI)
2401 {
2402 string[len++] = KS_EXTRA;
2403 string[len++] = KE_CSI;
2404 }
2405 else
2406 string[len++] = to[i];
2407 }
2408 vim_free(to);
2409 }
2410 else
2411 string[len++] = key_char;
2412 }
2413 else
2414#endif
2415 string[len++] = key_char;
2416 }
2417
2418 if (len == 1 && string[0] == CSI)
2419 {
2420 /* Turn CSI into K_CSI. */
2421 string[ len++ ] = KS_EXTRA;
2422 string[ len++ ] = KE_CSI;
2423 }
2424
2425 add_to_input_buf(string, len);
2426}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002427#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428
2429/*
2430 * Handle MouseClick
2431 */
2432 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002433gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434{
2435 short thePart;
2436 WindowPtr whichWindow;
2437
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002438 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002440#ifdef FEAT_GUI_TABLINE
2441 /* prevent that the vim window size changes if it's activated by a
2442 click into the tab pane */
2443 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002444 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002445#endif
2446
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 switch (thePart)
2448 {
2449 case (inDesk):
2450 /* TODO: what to do? */
2451 break;
2452
2453 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002454 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455 break;
2456
2457 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002458 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 break;
2460
2461 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002462 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 break;
2464
2465 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002466 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 break;
2468
2469 case (inGoAway):
2470 if (TrackGoAway(whichWindow, theEvent->where))
2471 gui_shell_closed();
2472 break;
2473
2474 case (inZoomIn):
2475 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 break;
2478 }
2479}
2480
2481/*
2482 * Handle MouseMoved
2483 * [this event is a moving in and out of a region]
2484 */
2485 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002486gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487{
2488 Point thePoint;
2489 int_u vimModifiers;
2490
2491 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002492 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2494
2495 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002496 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2500 thePoint.v, FALSE, vimModifiers);
2501
2502 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002503 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 FILL_Y(Y_2_ROW(thePoint.v)),
2505 FILL_X(X_2_COL(thePoint.h)+1),
2506 FILL_Y(Y_2_ROW(thePoint.v)+1));
2507
2508 if (dragRectEnbl)
2509 dragRectControl = kCreateRect;
2510
2511}
2512
2513/*
2514 * Handle the mouse release
2515 */
2516 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002517gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518{
2519 Point thePoint;
2520 int_u vimModifiers;
2521
2522 /* TODO: Properly convert the Contextual menu mouse-up */
2523 /* Potential source of the double menu */
2524 lastMouseTick = theEvent->when;
2525 dragRectEnbl = FALSE;
2526 dragRectControl = kCreateEmpty;
2527 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002528 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529
2530 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 if (clickIsPopup)
2532 {
2533 vimModifiers &= ~MOUSE_CTRL;
2534 clickIsPopup = FALSE;
2535 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002536 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537}
2538
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 static pascal OSStatus
2540gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2541 void *data)
2542{
2543 EventRef bogusEvent;
2544 Point point;
2545 Rect bounds;
2546 UInt32 mod;
2547 SInt32 delta;
2548 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002549 EventMouseWheelAxis axis;
2550
2551 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2552 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2553 && axis != kEventMouseWheelAxisY)
2554 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555
2556 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2557 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2558 goto bail;
2559 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2560 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2561 goto bail;
2562 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2563 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2564 goto bail;
2565
2566 vim_mod = 0;
2567 if (mod & shiftKey)
2568 vim_mod |= MOUSE_SHIFT;
2569 if (mod & controlKey)
2570 vim_mod |= MOUSE_CTRL;
2571 if (mod & optionKey)
2572 vim_mod |= MOUSE_ALT;
2573
2574 /* post a bogus event to wake up WaitNextEvent */
2575 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0,
2576 kEventAttributeNone, &bogusEvent))
2577 goto bail;
2578 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent,
2579 kEventPriorityLow))
2580 goto bail;
2581
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00002582 ReleaseEvent(bogusEvent);
2583
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2585 {
2586 point.h -= bounds.left;
2587 point.v -= bounds.top;
2588 }
2589
2590 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2591 point.h, point.v, FALSE, vim_mod);
2592
2593 return noErr;
2594
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002595bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 /*
2597 * when we fail give any additional callback handler a chance to perform
2598 * it's actions
2599 */
2600 return CallNextEventHandler(nextHandler, theEvent);
2601}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602
2603#if 0
2604
2605/*
2606 * This would be the normal way of invoking the contextual menu
2607 * but the Vim API doesn't seem to a support a request to get
2608 * the menu that we should display
2609 */
2610 void
2611gui_mac_handle_contextual_menu(event)
2612 EventRecord *event;
2613{
2614/*
2615 * Clone PopUp to use menu
2616 * Create a object descriptor for the current selection
2617 * Call the procedure
2618 */
2619
2620// Call to Handle Popup
2621 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2622
2623 if (status != noErr)
2624 return;
2625
2626 if (CntxType == kCMMenuItemSelected)
2627 {
2628 /* Handle the menu CntxMenuID, CntxMenuItem */
2629 /* The submenu can be handle directly by gui_mac_handle_menu */
2630 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002631 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 }
2633 else if (CntxMenuID == kCMShowHelpSelected)
2634 {
2635 /* Should come up with the help */
2636 }
2637
2638}
2639#endif
2640
2641/*
2642 * Handle menubar selection
2643 */
2644 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002645gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646{
2647 short menu = HiWord(menuChoice);
2648 short item = LoWord(menuChoice);
2649 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650
2651 if (menu == 256) /* TODO: use constant or gui.xyz */
2652 {
2653 if (item == 1)
2654 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655 }
2656 else if (item != 0)
2657 {
2658 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2659
2660 if (theVimMenu)
2661 gui_menu_cb(theVimMenu);
2662 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002663 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664}
2665
2666/*
2667 * Dispatch the event to proper handler
2668 */
2669
2670 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002671gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672{
2673 OSErr error;
2674
2675 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002676 if (IsShowContextualMenuClick(event))
2677 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002679 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002681 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002683 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685
2686 /* Handle normal event */
2687 switch (event->what)
2688 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002689#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002690 case (keyDown):
2691 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002692 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002694#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002696 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002697 break;
2698
2699 case (mouseDown):
2700 gui_mac_doMouseDownEvent(event);
2701 break;
2702
2703 case (mouseUp):
2704 gui_mac_doMouseUpEvent(event);
2705 break;
2706
2707 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002708 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 break;
2710
2711 case (diskEvt):
2712 /* We don't need special handling for disk insertion */
2713 break;
2714
2715 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002716 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 break;
2718
2719 case (osEvt):
2720 switch ((event->message >> 24) & 0xFF)
2721 {
2722 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002723 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 break;
2725 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002726 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 break;
2728 }
2729 break;
2730
2731#ifdef USE_AEVENT
2732 case (kHighLevelEvent):
2733 /* Someone's talking to us, through AppleEvents */
2734 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2735 break;
2736#endif
2737 }
2738}
2739
2740/*
2741 * ------------------------------------------------------------
2742 * Unknown Stuff
2743 * ------------------------------------------------------------
2744 */
2745
2746
2747 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002748gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749{
2750 char_u c;
2751 char_u *p;
2752 char_u pFontName[256];
2753 Str255 systemFontname;
2754 short font_id;
2755 short size=9;
2756 GuiFont font;
2757#if 0
2758 char_u *fontNamePtr;
2759#endif
2760
2761 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2762 ;
2763
2764 c = *p;
2765 *p = 0;
2766
2767#if 1
2768 STRCPY(&pFontName[1], font_name);
2769 pFontName[0] = STRLEN(font_name);
2770 *p = c;
2771
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002772 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002773 char_u fontName[256];
2774 char_u *styleStart = vim_strchr(font_name, ':');
2775 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2776 vim_strncpy(fontName, font_name, fontNameLen);
2777
2778 ATSUFontID fontRef;
2779 FMFontStyle fontStyle;
2780 font_id = 0;
2781
2782 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2783 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2784 &fontRef) == noErr)
2785 {
2786 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2787 font_id = 0;
2788 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002789
2790 if (font_id == 0)
2791 {
2792 /*
2793 * Try again, this time replacing underscores in the font name
2794 * with spaces (:set guifont allows the two to be used
2795 * interchangeably; the Font Manager doesn't).
2796 */
2797 int i, changed = FALSE;
2798
2799 for (i = pFontName[0]; i > 0; --i)
2800 {
2801 if (pFontName[i] == '_')
2802 {
2803 pFontName[i] = ' ';
2804 changed = TRUE;
2805 }
2806 }
2807 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002808 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2809 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2810 kFontNoLanguageCode, &fontRef) == noErr)
2811 {
2812 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2813 font_id = 0;
2814 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002815 }
2816
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817#else
2818 /* name = C2Pascal_save(menu->dname); */
2819 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2820
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002821 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822#endif
2823
2824
2825 if (font_id == 0)
2826 {
2827 /* Oups, the system font was it the one the user want */
2828
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002829 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2830 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831 if (!EqualString(pFontName, systemFontname, false, false))
2832 return NOFONT;
2833 }
2834 if (*p == ':')
2835 {
2836 p++;
2837 /* Set the values found after ':' */
2838 while (*p)
2839 {
2840 switch (*p++)
2841 {
2842 case 'h':
2843 size = points_to_pixels(p, &p, TRUE);
2844 break;
2845 /*
2846 * TODO: Maybe accept width and styles
2847 */
2848 }
2849 while (*p == ':')
2850 p++;
2851 }
2852 }
2853
2854 if (size < 1)
2855 size = 1; /* Avoid having a size of 0 with system font */
2856
2857 font = (size << 16) + ((long) font_id & 0xFFFF);
2858
2859 return font;
2860}
2861
2862/*
2863 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002864 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002865 * ------------------------------------------------------------
2866 */
2867
2868/*
2869 * Parse the GUI related command-line arguments. Any arguments used are
2870 * deleted from argv, and *argc is decremented accordingly. This is called
2871 * when vim is started, whether or not the GUI has been started.
2872 */
2873 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002874gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875{
2876 /* TODO: Move most of this stuff toward gui_mch_init */
2877#ifdef USE_EXE_NAME
2878 FSSpec applDir;
2879# ifndef USE_FIND_BUNDLE_PATH
2880 short applVRefNum;
2881 long applDirID;
2882 Str255 volName;
2883# else
2884 ProcessSerialNumber psn;
2885 FSRef applFSRef;
2886# endif
2887#endif
2888
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889#if 0
2890 InitCursor();
2891
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893
2894#ifdef USE_AEVENT
2895 (void) InstallAEHandlers();
2896#endif
2897
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002898 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002900 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002902 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903
2904 DrawMenuBar();
2905
2906
2907#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002908 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002909#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002910 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002911#endif
2912
2913
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914 CreateNewWindow(kDocumentWindowClass,
2915 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002916 &windRect, &gui.VimWindow);
2917 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918
2919 gui.char_width = 7;
2920 gui.char_height = 11;
2921 gui.char_ascent = 6;
2922 gui.num_rows = 24;
2923 gui.num_cols = 80;
2924 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2925
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002926 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2927 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928
2929 dragRectEnbl = FALSE;
2930 dragRgn = NULL;
2931 dragRectControl = kCreateEmpty;
2932 cursorRgn = NewRgn();
2933#endif
2934#ifdef USE_EXE_NAME
2935# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002936 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002938 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002939# else
2940 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2941 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002943 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002944 /* if (err != noErr) return err; */
2945
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002946 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 /* if (err != noErr) return err; */
2948
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002949 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950
2951 /* This technic return NIL when we disallow_gui */
2952# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002953 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955}
2956
2957#ifndef ALWAYS_USE_GUI
2958/*
2959 * Check if the GUI can be started. Called before gvimrc is sourced.
2960 * Return OK or FAIL.
2961 */
2962 int
2963gui_mch_init_check(void)
2964{
2965 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2966 * using the >console
2967 */
2968 if (disallow_gui) /* see main.c for reason to disallow */
2969 return FAIL;
2970 return OK;
2971}
2972#endif
2973
2974 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002975receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002976{
2977 int x, y;
2978 int_u modifiers;
2979 char_u **fnames = NULL;
2980 int count;
2981 int i, j;
2982
2983 /* Get drop position, modifiers and count of items */
2984 {
2985 Point point;
2986 SInt16 mouseUpModifiers;
2987 UInt16 countItem;
2988
2989 GetDragMouse(theDrag, &point, NULL);
2990 GlobalToLocal(&point);
2991 x = point.h;
2992 y = point.v;
2993 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2994 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2995 CountDragItems(theDrag, &countItem);
2996 count = countItem;
2997 }
2998
2999 fnames = (char_u **)alloc(count * sizeof(char_u *));
3000 if (fnames == NULL)
3001 return dragNotAcceptedErr;
3002
3003 /* Get file names dropped */
3004 for (i = j = 0; i < count; ++i)
3005 {
3006 DragItemRef item;
3007 OSErr err;
3008 Size size;
3009 FlavorType type = flavorTypeHFS;
3010 HFSFlavor hfsFlavor;
3011
3012 fnames[i] = NULL;
3013 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3014 err = GetFlavorDataSize(theDrag, item, type, &size);
3015 if (err != noErr || size > sizeof(hfsFlavor))
3016 continue;
3017 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3018 if (err != noErr)
3019 continue;
3020 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3021 }
3022 count = j;
3023
3024 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003025
3026 /* Fake mouse event to wake from stall */
3027 PostEvent(mouseUp, 0);
3028
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029 return noErr;
3030}
3031
3032/*
3033 * Initialise the GUI. Create all the windows, set up all the call-backs
3034 * etc.
3035 */
3036 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003037gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038{
3039 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003040 Rect windRect;
3041 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003043 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003044 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003045
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003046 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003047 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003048
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049#if 1
3050 InitCursor();
3051
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053
3054#ifdef USE_AEVENT
3055 (void) InstallAEHandlers();
3056#endif
3057
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003058 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003060 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003062 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063
3064 DrawMenuBar();
3065
3066
3067#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003068 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003070 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071#endif
3072
3073 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003076 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3078 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003079 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003080
3081 gui.char_width = 7;
3082 gui.char_height = 11;
3083 gui.char_ascent = 6;
3084 gui.num_rows = 24;
3085 gui.num_cols = 80;
3086 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3087
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003088 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3089 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003091 /* Install Carbon event callbacks. */
3092 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093
3094 dragRectEnbl = FALSE;
3095 dragRgn = NULL;
3096 dragRectControl = kCreateEmpty;
3097 cursorRgn = NewRgn();
3098#endif
3099 /* Display any pending error messages */
3100 display_errors();
3101
3102 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003103 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003104 gui.norm_pixel = 0x00000000;
3105 gui.back_pixel = 0x00FFFFFF;
3106
3107 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3108 * file). */
3109 set_normal_colors();
3110
3111 /*
3112 * Check that none of the colors are the same as the background color.
3113 * Then store the current values as the defaults.
3114 */
3115 gui_check_colors();
3116 gui.def_norm_pixel = gui.norm_pixel;
3117 gui.def_back_pixel = gui.back_pixel;
3118
3119 /* Get the colors for the highlight groups (gui_check_colors() might have
3120 * changed them) */
3121 highlight_gui_started();
3122
3123 /*
3124 * Setting the gui constants
3125 */
3126#ifdef FEAT_MENU
3127 gui.menu_height = 0;
3128#endif
3129 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3130 gui.border_offset = gui.border_width = 2;
3131
Bram Moolenaar720c7102007-05-10 18:07:50 +00003132 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003133 gui_mch_draw_string() below), enable it for all font sizes. */
3134 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 eventTypeSpec.eventClass = kEventClassMouse;
3137 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3138 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3139 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3140 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3141 {
3142 mouseWheelHandlerRef = NULL;
3143 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3144 mouseWheelHandlerUPP = NULL;
3145 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003147#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003148 InterfaceTypeList supportedServices = { kUnicodeDocument };
3149 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3150
3151 /* We don't support inline input yet, use input window by default */
3152 UseInputWindow(gTSMDocument, TRUE);
3153
3154 /* Should we activate the document by default? */
3155 // ActivateTSMDocument(gTSMDocument);
3156
3157 EventTypeSpec textEventTypes[] = {
3158 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3159 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3160 { kEventClassTextInput, kEventTextInputPosToOffset },
3161 { kEventClassTextInput, kEventTextInputOffsetToPos },
3162 };
3163
3164 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3165 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3166 NR_ELEMS(textEventTypes),
3167 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003168 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003169 DisposeEventHandlerUPP(keyEventHandlerUPP);
3170 keyEventHandlerUPP = NULL;
3171 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003172
3173 EventTypeSpec windowEventTypes[] = {
3174 { kEventClassWindow, kEventWindowActivated },
3175 { kEventClassWindow, kEventWindowDeactivated },
3176 };
3177
3178 /* Install window event handler to support TSMDocument activate and
3179 * deactivate */
3180 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3181 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3182 winEventHandlerUPP,
3183 NR_ELEMS(windowEventTypes),
3184 windowEventTypes, NULL, NULL))
3185 {
3186 DisposeEventHandlerUPP(winEventHandlerUPP);
3187 winEventHandlerUPP = NULL;
3188 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189#endif
3190
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003191/*
3192#ifdef FEAT_MBYTE
3193 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3194#endif
3195*/
3196
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003197#ifdef FEAT_GUI_TABLINE
3198 /*
3199 * Create the tabline
3200 */
3201 initialise_tabline();
3202#endif
3203
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204 /* TODO: Load bitmap if using TOOLBAR */
3205 return OK;
3206}
3207
3208/*
3209 * Called when the foreground or background color has been changed.
3210 */
3211 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003212gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213{
3214 /* TODO:
3215 * This proc is called when Normal is set to a value
3216 * so what msut be done? I don't know
3217 */
3218}
3219
3220/*
3221 * Open the GUI window which was created by a call to gui_mch_init().
3222 */
3223 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003224gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225{
3226 ShowWindow(gui.VimWindow);
3227
3228 if (gui_win_x != -1 && gui_win_y != -1)
3229 gui_mch_set_winpos(gui_win_x, gui_win_y);
3230
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 /*
3232 * Make the GUI the foreground process (in case it was launched
3233 * from the Terminal or via :gui).
3234 */
3235 {
3236 ProcessSerialNumber psn;
3237 if (GetCurrentProcess(&psn) == noErr)
3238 SetFrontProcess(&psn);
3239 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240
3241 return OK;
3242}
3243
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003244#ifdef USE_ATSUI_DRAWING
3245 static void
3246gui_mac_dispose_atsui_style(void)
3247{
3248 if (p_macatsui && gFontStyle)
3249 ATSUDisposeStyle(gFontStyle);
3250#ifdef FEAT_MBYTE
3251 if (p_macatsui && gWideFontStyle)
3252 ATSUDisposeStyle(gWideFontStyle);
3253#endif
3254}
3255#endif
3256
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 void
3258gui_mch_exit(int rc)
3259{
3260 /* TODO: find out all what is missing here? */
3261 DisposeRgn(cursorRgn);
3262
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003263#ifdef USE_CARBONKEYHANDLER
3264 if (keyEventHandlerUPP)
3265 DisposeEventHandlerUPP(keyEventHandlerUPP);
3266#endif
3267
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 if (mouseWheelHandlerUPP != NULL)
3269 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003270
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003271#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003272 gui_mac_dispose_atsui_style();
3273#endif
3274
3275#ifdef USE_CARBONKEYHANDLER
3276 FixTSMDocument(gTSMDocument);
3277 DeactivateTSMDocument(gTSMDocument);
3278 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003279#endif
3280
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281 /* Exit to shell? */
3282 exit(rc);
3283}
3284
3285/*
3286 * Get the position of the top left corner of the window.
3287 */
3288 int
3289gui_mch_get_winpos(int *x, int *y)
3290{
3291 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 Rect bounds;
3293 OSStatus status;
3294
3295 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003296 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297
3298 if (status != noErr)
3299 return FAIL;
3300 *x = bounds.left;
3301 *y = bounds.top;
3302 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 return FAIL;
3304}
3305
3306/*
3307 * Set the position of the top left corner of the window to the given
3308 * coordinates.
3309 */
3310 void
3311gui_mch_set_winpos(int x, int y)
3312{
3313 /* TODO: Should make sure the window is move within range
3314 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3315 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003316 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317}
3318
3319 void
3320gui_mch_set_shellsize(
3321 int width,
3322 int height,
3323 int min_width,
3324 int min_height,
3325 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003326 int base_height,
3327 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329 CGrafPtr VimPort;
3330 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331
3332 if (gui.which_scrollbars[SBAR_LEFT])
3333 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003334 VimPort = GetWindowPort(gui.VimWindow);
3335 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003337 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 }
3340 else
3341 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003342 VimPort = GetWindowPort(gui.VimWindow);
3343 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003345 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 }
3347
3348 SizeWindow(gui.VimWindow, width, height, TRUE);
3349
3350 gui_resize_shell(width, height);
3351}
3352
3353/*
3354 * Get the screen dimensions.
3355 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3356 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003357 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358 */
3359 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003360gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361{
3362 GDHandle dominantDevice = GetMainDevice();
3363 Rect screenRect = (**dominantDevice).gdRect;
3364
3365 *screen_w = screenRect.right - 10;
3366 *screen_h = screenRect.bottom - 40;
3367}
3368
3369
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003370/*
3371 * Open the Font Panel and wait for the user to select a font and
3372 * close the panel. Then fill the buffer pointed to by font_name with
3373 * the name and size of the selected font and return the font's handle,
3374 * or NOFONT in case of an error.
3375 */
3376 static GuiFont
3377gui_mac_select_font(char_u *font_name)
3378{
3379 GuiFont selected_font = NOFONT;
3380 OSStatus status;
3381 FontSelectionQDStyle curr_font;
3382
3383 /* Initialize the Font Panel with the current font. */
3384 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3385 curr_font.size = (gui.norm_font >> 16);
3386 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3387 curr_font.instance.fontStyle = 0;
3388 curr_font.hasColor = false;
3389 curr_font.version = 0; /* version number of the style structure */
3390 status = SetFontInfoForSelection(kFontSelectionQDType,
3391 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3392
3393 gFontPanelInfo.family = curr_font.instance.fontFamily;
3394 gFontPanelInfo.style = curr_font.instance.fontStyle;
3395 gFontPanelInfo.size = curr_font.size;
3396
3397 /* Pop up the Font Panel. */
3398 status = FPShowHideFontPanel();
3399 if (status == noErr)
3400 {
3401 /*
3402 * The Font Panel is modeless. We really need it to be modal,
3403 * so we spin in an event loop until the panel is closed.
3404 */
3405 gFontPanelInfo.isPanelVisible = true;
3406 while (gFontPanelInfo.isPanelVisible)
3407 {
3408 EventRecord e;
3409 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3410 }
3411
3412 GetFontPanelSelection(font_name);
3413 selected_font = gui_mac_find_font(font_name);
3414 }
3415 return selected_font;
3416}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003417
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003418#ifdef USE_ATSUI_DRAWING
3419 static void
3420gui_mac_create_atsui_style(void)
3421{
3422 if (p_macatsui && gFontStyle == NULL)
3423 {
3424 if (ATSUCreateStyle(&gFontStyle) != noErr)
3425 gFontStyle = NULL;
3426 }
3427#ifdef FEAT_MBYTE
3428 if (p_macatsui && gWideFontStyle == NULL)
3429 {
3430 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3431 gWideFontStyle = NULL;
3432 }
3433#endif
3434
3435 p_macatsui_last = p_macatsui;
3436}
3437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438
3439/*
3440 * Initialise vim to use the font with the given name. Return FAIL if the font
3441 * could not be loaded, OK otherwise.
3442 */
3443 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003444gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445{
3446 /* TODO: Add support for bold italic underline proportional etc... */
3447 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003448 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 FontInfo font_info;
3450 short font_id;
3451 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003452 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003453
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003454#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003455 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003456#endif
3457
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 if (font_name == NULL)
3459 {
3460 /* First try to get the suggested font */
3461 GetFNum(suggestedFont, &font_id);
3462
3463 if (font_id == 0)
3464 {
3465 /* Then pickup the standard application font */
3466 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003467 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003469 else
3470 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3472 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003473 else if (STRCMP(font_name, "*") == 0)
3474 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003475 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003476
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003477 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003478 if (font == NOFONT)
3479 return FAIL;
3480
3481 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003482 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003483 if (new_p_guifont != NULL)
3484 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003485 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003486 vim_free(p_guifont);
3487 p_guifont = new_p_guifont;
3488 /* Replace spaces in the font name with underscores. */
3489 for ( ; *new_p_guifont; ++new_p_guifont)
3490 {
3491 if (*new_p_guifont == ' ')
3492 *new_p_guifont = '_';
3493 }
3494 }
3495 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496 else
3497 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003498 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003499 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500
3501 if (font == NOFONT)
3502 return FAIL;
3503 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003504
Bram Moolenaar071d4272004-06-13 20:20:40 +00003505 gui.norm_font = font;
3506
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003507 hl_set_font_name(used_font_name);
3508
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003509 TextSize(font >> 16);
3510 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003512 GetFontInfo(&font_info);
3513
3514 gui.char_ascent = font_info.ascent;
3515 gui.char_width = CharWidth('_');
3516 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3517
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003518#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003519 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003520 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003521#endif
3522
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003524}
3525
Bram Moolenaar02743632005-07-25 20:42:36 +00003526/*
3527 * Adjust gui.char_height (after 'linespace' was changed).
3528 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003530gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531{
3532 FontInfo font_info;
3533
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003534 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3536 gui.char_ascent = font_info.ascent + p_linespace / 2;
3537 return OK;
3538}
3539
3540/*
3541 * Get a font structure for highlighting.
3542 */
3543 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003544gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545{
3546 GuiFont font;
3547
3548 font = gui_mac_find_font(name);
3549
3550 if (font == NOFONT)
3551 {
3552 if (giveErrorIfMissing)
3553 EMSG2(_(e_font), name);
3554 return NOFONT;
3555 }
3556 /*
3557 * TODO : Accept only monospace
3558 */
3559
3560 return font;
3561}
3562
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003563#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003565 * Return the name of font "font" in allocated memory.
3566 * Don't know how to get the actual name, thus use the provided name.
3567 */
3568 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003569gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003570{
3571 if (name == NULL)
3572 return NULL;
3573 return vim_strsave(name);
3574}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003575#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003576
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003577#ifdef USE_ATSUI_DRAWING
3578 static void
3579gui_mac_set_font_attributes(GuiFont font)
3580{
3581 ATSUFontID fontID;
3582 Fixed fontSize;
3583 Fixed fontWidth;
3584
3585 fontID = font & 0xFFFF;
3586 fontSize = Long2Fix(font >> 16);
3587 fontWidth = Long2Fix(gui.char_width);
3588
3589 ATSUAttributeTag attribTags[] =
3590 {
3591 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3592 kATSUMaxATSUITagValue + 1
3593 };
3594
3595 ByteCount attribSizes[] =
3596 {
3597 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3598 sizeof(font)
3599 };
3600
3601 ATSUAttributeValuePtr attribValues[] =
3602 {
3603 &fontID, &fontSize, &fontWidth, &font
3604 };
3605
3606 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3607 {
3608 if (ATSUSetAttributes(gFontStyle,
3609 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3610 attribTags, attribSizes, attribValues) != noErr)
3611 {
3612# ifndef NDEBUG
3613 fprintf(stderr, "couldn't set font style\n");
3614# endif
3615 ATSUDisposeStyle(gFontStyle);
3616 gFontStyle = NULL;
3617 }
3618
3619#ifdef FEAT_MBYTE
3620 if (has_mbyte)
3621 {
3622 /* FIXME: we should use a more mbyte sensitive way to support
3623 * wide font drawing */
3624 fontWidth = Long2Fix(gui.char_width * 2);
3625
3626 if (ATSUSetAttributes(gWideFontStyle,
3627 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3628 attribTags, attribSizes, attribValues) != noErr)
3629 {
3630 ATSUDisposeStyle(gWideFontStyle);
3631 gWideFontStyle = NULL;
3632 }
3633 }
3634#endif
3635 }
3636}
3637#endif
3638
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003639/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640 * Set the current text font.
3641 */
3642 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003643gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003645#ifdef USE_ATSUI_DRAWING
3646 GuiFont currFont;
3647 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003648
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003649 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003650 {
3651 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003652 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3653 sizeof(font), &currFont, &actualFontByteCount) == noErr
3654 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003655 {
3656 if (currFont == font)
3657 return;
3658 }
3659
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003660 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003661 }
3662
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003663 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003664 {
3665 /* Setup automatic font substitution. The user's guifontwide
3666 * is tried first, then the system tries other fonts. */
3667/*
3668 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3669 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3670 ATSUCreateFontFallbacks(&gFontFallbacks);
3671 ATSUSetObjFontFallbacks(gFontFallbacks, );
3672*/
3673 if (gui.wide_font)
3674 {
3675 ATSUFontID fallbackFonts;
3676 gIsFontFallbackSet = TRUE;
3677
3678 if (FMGetFontFromFontFamilyInstance(
3679 (gui.wide_font & 0xFFFF),
3680 0,
3681 &fallbackFonts,
3682 NULL) == noErr)
3683 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003684 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3685 &fallbackFonts,
3686 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003687 }
3688/*
3689 ATSUAttributeValuePtr fallbackValues[] = { };
3690*/
3691 }
3692 }
3693#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694 TextSize(font >> 16);
3695 TextFont(font & 0xFFFF);
3696}
3697
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698/*
3699 * If a font is not going to be used, free its structure.
3700 */
3701 void
3702gui_mch_free_font(font)
3703 GuiFont font;
3704{
3705 /*
3706 * Free font when "font" is not 0.
3707 * Nothing to do in the current implementation, since
3708 * nothing is allocated for each font used.
3709 */
3710}
3711
3712 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003713hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714{
3715 if (isdigit(c))
3716 return c - '0';
3717 c = TOLOWER_ASC(c);
3718 if (c >= 'a' && c <= 'f')
3719 return c - 'a' + 10;
3720 return -1000;
3721}
3722
3723/*
3724 * Return the Pixel value (color) for the given color name. This routine was
3725 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3726 * Programmer's Guide.
3727 * Return INVALCOLOR when failed.
3728 */
3729 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003730gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731{
3732 /* TODO: Add support for the new named color of MacOS 8
3733 */
3734 RGBColor MacColor;
3735// guicolor_T color = 0;
3736
3737 typedef struct guicolor_tTable
3738 {
3739 char *name;
3740 guicolor_T color;
3741 } guicolor_tTable;
3742
3743 /*
3744 * The comment at the end of each line is the source
3745 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3746 */
3747 static guicolor_tTable table[] =
3748 {
3749 {"Black", RGB(0x00, 0x00, 0x00)},
3750 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3751 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3752 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3753 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3754 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3755 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003756 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3757 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3758 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3759 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3760 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3761 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3762 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3763 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3764 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3765 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3766 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3767 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3768 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3769 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3770 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3771 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003772 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3773 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774 {"white", RGB(0xFF, 0xFF, 0xFF)},
3775 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3776 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3777 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3778 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3779 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3780 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3781 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3782 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3783 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3784 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3785 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3786 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3787 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3788 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3789 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3790 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3791 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3792 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003793 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3795 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3796 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3797 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3798 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3799 };
3800
3801 int r, g, b;
3802 int i;
3803
3804 if (name[0] == '#' && strlen((char *) name) == 7)
3805 {
3806 /* Name is in "#rrggbb" format */
3807 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3808 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3809 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3810 if (r < 0 || g < 0 || b < 0)
3811 return INVALCOLOR;
3812 return RGB(r, g, b);
3813 }
3814 else
3815 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003816 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003818 LMGetHiliteRGB(&MacColor);
3819 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 }
3821 /* Check if the name is one of the colors we know */
3822 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3823 if (STRICMP(name, table[i].name) == 0)
3824 return table[i].color;
3825 }
3826
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 /*
3828 * Last attempt. Look in the file "$VIM/rgb.txt".
3829 */
3830 {
3831#define LINE_LEN 100
3832 FILE *fd;
3833 char line[LINE_LEN];
3834 char_u *fname;
3835
Bram Moolenaar071d4272004-06-13 20:20:40 +00003836 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 if (fname == NULL)
3838 return INVALCOLOR;
3839
3840 fd = fopen((char *)fname, "rt");
3841 vim_free(fname);
3842 if (fd == NULL)
3843 return INVALCOLOR;
3844
3845 while (!feof(fd))
3846 {
3847 int len;
3848 int pos;
3849 char *color;
3850
3851 fgets(line, LINE_LEN, fd);
3852 len = strlen(line);
3853
3854 if (len <= 1 || line[len-1] != '\n')
3855 continue;
3856
3857 line[len-1] = '\0';
3858
3859 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3860 if (i != 3)
3861 continue;
3862
3863 color = line + pos;
3864
3865 if (STRICMP(color, name) == 0)
3866 {
3867 fclose(fd);
3868 return (guicolor_T) RGB(r, g, b);
3869 }
3870 }
3871 fclose(fd);
3872 }
3873
3874 return INVALCOLOR;
3875}
3876
3877/*
3878 * Set the current text foreground color.
3879 */
3880 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003881gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882{
3883 RGBColor TheColor;
3884
3885 TheColor.red = Red(color) * 0x0101;
3886 TheColor.green = Green(color) * 0x0101;
3887 TheColor.blue = Blue(color) * 0x0101;
3888
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003889 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890}
3891
3892/*
3893 * Set the current text background color.
3894 */
3895 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003896gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897{
3898 RGBColor TheColor;
3899
3900 TheColor.red = Red(color) * 0x0101;
3901 TheColor.green = Green(color) * 0x0101;
3902 TheColor.blue = Blue(color) * 0x0101;
3903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003904 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905}
3906
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003907RGBColor specialColor;
3908
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003909/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003910 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003911 */
3912 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003913gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003914{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003915 specialColor.red = Red(color) * 0x0101;
3916 specialColor.green = Green(color) * 0x0101;
3917 specialColor.blue = Blue(color) * 0x0101;
3918}
3919
3920/*
3921 * Draw undercurl at the bottom of the character cell.
3922 */
3923 static void
3924draw_undercurl(int flags, int row, int col, int cells)
3925{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003926 int x;
3927 int offset;
3928 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3929 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003930
3931 RGBForeColor(&specialColor);
3932
3933 offset = val[FILL_X(col) % 8];
3934 MoveTo(FILL_X(col), y - offset);
3935
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003936 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003937 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003938 offset = val[x % 8];
3939 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003940 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003941}
3942
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003943
3944 static void
3945draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947#ifdef FEAT_MBYTE
3948 char_u *tofree = NULL;
3949
3950 if (output_conv.vc_type != CONV_NONE)
3951 {
3952 tofree = string_convert(&output_conv, s, &len);
3953 if (tofree != NULL)
3954 s = tofree;
3955 }
3956#endif
3957
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 /*
3959 * On OS X, try using Quartz-style text antialiasing.
3960 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003961 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 {
3963 /* Quartz antialiasing is available only in OS 10.2 and later. */
3964 UInt32 qd_flags = (p_antialias ?
3965 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003966 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003967 }
3968
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003969 /*
3970 * When antialiasing we're using srcOr mode, we have to clear the block
3971 * before drawing the text.
3972 * Also needed when 'linespace' is non-zero to remove the cursor and
3973 * underlining.
3974 * But not when drawing transparently.
3975 * The following is like calling gui_mch_clear_block(row, col, row, col +
3976 * len - 1), but without setting the bg color to gui.back_pixel.
3977 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003978 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003979 && !(flags & DRAW_TRANSP))
3980 {
3981 Rect rc;
3982
3983 rc.left = FILL_X(col);
3984 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003985#ifdef FEAT_MBYTE
3986 /* Multibyte computation taken from gui_w32.c */
3987 if (has_mbyte)
3988 {
3989 int cell_len = 0;
3990 int n;
3991
3992 /* Compute the length in display cells. */
3993 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3994 cell_len += (*mb_ptr2cells)(s + n);
3995 rc.right = FILL_X(col + cell_len);
3996 }
3997 else
3998#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003999 rc.right = FILL_X(col + len) + (col + len == Columns);
4000 rc.bottom = FILL_Y(row + 1);
4001 EraseRect(&rc);
4002 }
4003
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004004 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005 {
4006 StyleParameter face;
4007
4008 face = normal;
4009 if (flags & DRAW_BOLD)
4010 face |= bold;
4011 if (flags & DRAW_UNDERL)
4012 face |= underline;
4013 TextFace(face);
4014
4015 /* Quartz antialiasing works only in srcOr transfer mode. */
4016 TextMode(srcOr);
4017
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018 MoveTo(TEXT_X(col), TEXT_Y(row));
4019 DrawText((char*)s, 0, len);
4020 }
4021 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 {
4023 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004024 TextMode(srcCopy);
4025 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004026
4027 /* SelectFont(hdc, gui.currFont); */
4028
4029 if (flags & DRAW_TRANSP)
4030 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004031 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004032 }
4033
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004034 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004035 DrawText((char *)s, 0, len);
4036
4037 if (flags & DRAW_BOLD)
4038 {
4039 TextMode(srcOr);
4040 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4041 DrawText((char *)s, 0, len);
4042 }
4043
4044 if (flags & DRAW_UNDERL)
4045 {
4046 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4047 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4048 }
4049 }
4050
4051 if (flags & DRAW_UNDERC)
4052 draw_undercurl(flags, row, col, len);
4053
4054#ifdef FEAT_MBYTE
4055 vim_free(tofree);
4056#endif
4057}
4058
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004059#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004060
4061 static void
4062draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4063{
4064 /* ATSUI requires utf-16 strings */
4065 UniCharCount utf16_len;
4066 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4067 utf16_len /= sizeof(UniChar);
4068
4069 /* - ATSUI automatically antialiases text (Someone)
4070 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004071#ifdef MAC_ATSUI_DEBUG
4072 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4073 row, col, len, len == 1 ? s[0] : ' ');
4074#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004075 /*
4076 * When antialiasing we're using srcOr mode, we have to clear the block
4077 * before drawing the text.
4078 * Also needed when 'linespace' is non-zero to remove the cursor and
4079 * underlining.
4080 * But not when drawing transparently.
4081 * The following is like calling gui_mch_clear_block(row, col, row, col +
4082 * len - 1), but without setting the bg color to gui.back_pixel.
4083 */
4084 if ((flags & DRAW_TRANSP) == 0)
4085 {
4086 Rect rc;
4087
4088 rc.left = FILL_X(col);
4089 rc.top = FILL_Y(row);
4090 /* Multibyte computation taken from gui_w32.c */
4091 if (has_mbyte)
4092 {
4093 int cell_len = 0;
4094 int n;
4095
4096 /* Compute the length in display cells. */
4097 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4098 cell_len += (*mb_ptr2cells)(s + n);
4099 rc.right = FILL_X(col + cell_len);
4100 }
4101 else
4102 rc.right = FILL_X(col + len) + (col + len == Columns);
4103
4104 rc.bottom = FILL_Y(row + 1);
4105 EraseRect(&rc);
4106 }
4107
4108 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004109 TextMode(srcCopy);
4110 TextFace(normal);
4111
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004112 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004113 if (flags & DRAW_TRANSP)
4114 {
4115 TextMode(srcOr);
4116 }
4117
4118 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004119
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004120 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004121 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004122 Boolean attValue = true;
4123 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4124 ByteCount attribSizes[] = { sizeof(Boolean) };
4125 ATSUAttributeValuePtr attribValues[] = { &attValue };
4126
4127 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4128 }
4129
4130#ifdef FEAT_MBYTE
4131 if (has_mbyte)
4132 {
4133 int n, width_in_cell, last_width_in_cell;
4134 UniCharArrayOffset offset = 0;
4135 UniCharCount yet_to_draw = 0;
4136 ATSUTextLayout textLayout;
4137 ATSUStyle textStyle;
4138
4139 last_width_in_cell = 1;
4140 ATSUCreateTextLayout(&textLayout);
4141 ATSUSetTextPointerLocation(textLayout, tofree,
4142 kATSUFromTextBeginning,
4143 kATSUToTextEnd, utf16_len);
4144 /*
4145 ATSUSetRunStyle(textLayout, gFontStyle,
4146 kATSUFromTextBeginning, kATSUToTextEnd); */
4147
4148 /* Compute the length in display cells. */
4149 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4150 {
4151 width_in_cell = (*mb_ptr2cells)(s + n);
4152
4153 /* probably we are switching from single byte character
4154 * to multibyte characters (which requires more than one
4155 * cell to draw) */
4156 if (width_in_cell != last_width_in_cell)
4157 {
4158#ifdef MAC_ATSUI_DEBUG
4159 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4160 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4161#endif
4162 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4163 : gFontStyle;
4164
4165 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4166 offset += yet_to_draw;
4167 yet_to_draw = 0;
4168 last_width_in_cell = width_in_cell;
4169 }
4170
4171 yet_to_draw++;
4172 }
4173
4174 if (yet_to_draw)
4175 {
4176#ifdef MAC_ATSUI_DEBUG
4177 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4178 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4179#endif
4180 /* finish the rest style */
4181 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4182 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4183 }
4184
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004185 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004186 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004187 kATSUFromTextBeginning, kATSUToTextEnd,
4188 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004189 ATSUDisposeTextLayout(textLayout);
4190 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004191 else
4192#endif
4193 {
4194 ATSUTextLayout textLayout;
4195
4196 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4197 kATSUFromTextBeginning, kATSUToTextEnd,
4198 utf16_len,
4199 (gFontStyle ? 1 : 0), &utf16_len,
4200 (gFontStyle ? &gFontStyle : NULL),
4201 &textLayout) == noErr)
4202 {
4203 ATSUSetTransientFontMatching(textLayout, TRUE);
4204
4205 ATSUDrawText(textLayout,
4206 kATSUFromTextBeginning, kATSUToTextEnd,
4207 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4208
4209 ATSUDisposeTextLayout(textLayout);
4210 }
4211 }
4212
4213 /* drawing is done, now reset bold to normal */
4214 if (gFontStyle && flags & DRAW_BOLD)
4215 {
4216 Boolean attValue = false;
4217
4218 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4219 ByteCount attribSizes[] = { sizeof(Boolean) };
4220 ATSUAttributeValuePtr attribValues[] = { &attValue };
4221
4222 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4223 attribValues);
4224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 }
4226
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004227 if (flags & DRAW_UNDERC)
4228 draw_undercurl(flags, row, col, len);
4229
Bram Moolenaar071d4272004-06-13 20:20:40 +00004230 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004231}
4232#endif
4233
4234 void
4235gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4236{
4237#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004238 if (p_macatsui == 0 && p_macatsui_last != 0)
4239 /* switch from macatsui to nomacatsui */
4240 gui_mac_dispose_atsui_style();
4241 else if (p_macatsui != 0 && p_macatsui_last == 0)
4242 /* switch from nomacatsui to macatsui */
4243 gui_mac_create_atsui_style();
4244
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004245 if (p_macatsui)
4246 draw_string_ATSUI(row, col, s, len, flags);
4247 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004248#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004249 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250}
4251
4252/*
4253 * Return OK if the key with the termcap name "name" is supported.
4254 */
4255 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004256gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257{
4258 int i;
4259
4260 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4261 if (name[0] == special_keys[i].vim_code0 &&
4262 name[1] == special_keys[i].vim_code1)
4263 return OK;
4264 return FAIL;
4265}
4266
4267 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004268gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004270 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271}
4272
4273 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004274gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275{
4276 /* Do a visual beep by reversing the foreground and background colors */
4277 Rect rc;
4278
4279 /*
4280 * Note: InvertRect() excludes right and bottom of rectangle.
4281 */
4282 rc.left = 0;
4283 rc.top = 0;
4284 rc.right = gui.num_cols * gui.char_width;
4285 rc.bottom = gui.num_rows * gui.char_height;
4286 InvertRect(&rc);
4287
4288 ui_delay((long)msec, TRUE); /* wait for some msec */
4289
4290 InvertRect(&rc);
4291}
4292
4293/*
4294 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4295 */
4296 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004297gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298{
4299 Rect rc;
4300
4301 /*
4302 * Note: InvertRect() excludes right and bottom of rectangle.
4303 */
4304 rc.left = FILL_X(c);
4305 rc.top = FILL_Y(r);
4306 rc.right = rc.left + nc * gui.char_width;
4307 rc.bottom = rc.top + nr * gui.char_height;
4308 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309}
4310
4311/*
4312 * Iconify the GUI window.
4313 */
4314 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004315gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316{
4317 /* TODO: find out what could replace iconify
4318 * -window shade?
4319 * -hide application?
4320 */
4321}
4322
4323#if defined(FEAT_EVAL) || defined(PROTO)
4324/*
4325 * Bring the Vim window to the foreground.
4326 */
4327 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004328gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329{
4330 /* TODO */
4331}
4332#endif
4333
4334/*
4335 * Draw a cursor without focus.
4336 */
4337 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004338gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004339{
4340 Rect rc;
4341
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 /*
4343 * Note: FrameRect() excludes right and bottom of rectangle.
4344 */
4345 rc.left = FILL_X(gui.col);
4346 rc.top = FILL_Y(gui.row);
4347 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004348#ifdef FEAT_MBYTE
4349 if (mb_lefthalve(gui.row, gui.col))
4350 rc.right += gui.char_width;
4351#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352 rc.bottom = rc.top + gui.char_height;
4353
4354 gui_mch_set_fg_color(color);
4355
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004356 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357}
4358
4359/*
4360 * Draw part of a cursor, only w pixels wide, and h pixels high.
4361 */
4362 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004363gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364{
4365 Rect rc;
4366
4367#ifdef FEAT_RIGHTLEFT
4368 /* vertical line should be on the right of current point */
4369 if (CURSOR_BAR_RIGHT)
4370 rc.left = FILL_X(gui.col + 1) - w;
4371 else
4372#endif
4373 rc.left = FILL_X(gui.col);
4374 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4375 rc.right = rc.left + w;
4376 rc.bottom = rc.top + h;
4377
4378 gui_mch_set_fg_color(color);
4379
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004380 FrameRect(&rc);
4381// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382}
4383
4384
4385
4386/*
4387 * Catch up with any queued X events. This may put keyboard input into the
4388 * input buffer, call resize call-backs, trigger timers etc. If there is
4389 * nothing in the X event queue (& no timers pending), then we return
4390 * immediately.
4391 */
4392 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004393gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394{
4395 /* TODO: find what to do
4396 * maybe call gui_mch_wait_for_chars (0)
4397 * more like look at EventQueue then
4398 * call heart of gui_mch_wait_for_chars;
4399 *
4400 * if (eventther)
4401 * gui_mac_handle_event(&event);
4402 */
4403 EventRecord theEvent;
4404
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004405 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406 if (theEvent.what != nullEvent)
4407 gui_mch_wait_for_chars(0);
4408}
4409
4410/*
4411 * Simple wrapper to neglect more easily the time
4412 * spent inside WaitNextEvent while profiling.
4413 */
4414
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415 pascal
4416 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004417WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418{
4419 if (((long) sleep) < -1)
4420 sleep = 32767;
4421 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4422}
4423
4424/*
4425 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4426 * from the keyboard.
4427 * wtime == -1 Wait forever.
4428 * wtime == 0 This should never happen.
4429 * wtime > 0 Wait wtime milliseconds for a character.
4430 * Returns OK if a character was found to be available within the given time,
4431 * or FAIL otherwise.
4432 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004434gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435{
4436 EventMask mask = (everyEvent);
4437 EventRecord event;
4438 long entryTick;
4439 long currentTick;
4440 long sleeppyTick;
4441
4442 /* If we are providing life feedback with the scrollbar,
4443 * we don't want to try to wait for an event, or else
4444 * there won't be any life feedback.
4445 */
4446 if (dragged_sb != NULL)
4447 return FAIL;
4448 /* TODO: Check if FAIL is the proper return code */
4449
4450 entryTick = TickCount();
4451
4452 allow_scrollbar = TRUE;
4453
4454 do
4455 {
4456/* if (dragRectControl == kCreateEmpty)
4457 {
4458 dragRgn = NULL;
4459 dragRectControl = kNothing;
4460 }
4461 else*/ if (dragRectControl == kCreateRect)
4462 {
4463 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004464 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 dragRectControl = kNothing;
4466 }
4467 /*
4468 * Don't use gui_mch_update() because then we will spin-lock until a
4469 * char arrives, instead we use WaitNextEventWrp() to hang until an
4470 * event arrives. No need to check for input_buf_full because we are
4471 * returning as soon as it contains a single char.
4472 */
4473 /* TODO: reduce wtime accordinly??? */
4474 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004475 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476 else
4477 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004478
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004479 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004481 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482 if (input_available())
4483 {
4484 allow_scrollbar = FALSE;
4485 return OK;
4486 }
4487 }
4488 currentTick = TickCount();
4489 }
4490 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4491
4492 allow_scrollbar = FALSE;
4493 return FAIL;
4494}
4495
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496/*
4497 * Output routines.
4498 */
4499
4500/* Flush any output to the screen */
4501 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004502gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503{
4504 /* TODO: Is anything needed here? */
4505}
4506
4507/*
4508 * Clear a rectangular region of the screen from text pos (row1, col1) to
4509 * (row2, col2) inclusive.
4510 */
4511 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004512gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513{
4514 Rect rc;
4515
4516 /*
4517 * Clear one extra pixel at the far right, for when bold characters have
4518 * spilled over to the next column.
4519 */
4520 rc.left = FILL_X(col1);
4521 rc.top = FILL_Y(row1);
4522 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4523 rc.bottom = FILL_Y(row2 + 1);
4524
4525 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004526 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527}
4528
4529/*
4530 * Clear the whole text window.
4531 */
4532 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004533gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534{
4535 Rect rc;
4536
4537 rc.left = 0;
4538 rc.top = 0;
4539 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4540 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4541
4542 gui_mch_set_bg_color(gui.back_pixel);
4543 EraseRect(&rc);
4544/* gui_mch_set_fg_color(gui.norm_pixel);
4545 FrameRect(&rc);
4546*/
4547}
4548
4549/*
4550 * Delete the given number of lines from the given row, scrolling up any
4551 * text further down within the scroll region.
4552 */
4553 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004554gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555{
4556 Rect rc;
4557
4558 /* changed without checking! */
4559 rc.left = FILL_X(gui.scroll_region_left);
4560 rc.right = FILL_X(gui.scroll_region_right + 1);
4561 rc.top = FILL_Y(row);
4562 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4563
4564 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004565 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566
4567 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4568 gui.scroll_region_left,
4569 gui.scroll_region_bot, gui.scroll_region_right);
4570}
4571
4572/*
4573 * Insert the given number of lines before the given row, scrolling down any
4574 * following text within the scroll region.
4575 */
4576 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004577gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004578{
4579 Rect rc;
4580
4581 rc.left = FILL_X(gui.scroll_region_left);
4582 rc.right = FILL_X(gui.scroll_region_right + 1);
4583 rc.top = FILL_Y(row);
4584 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4585
4586 gui_mch_set_bg_color(gui.back_pixel);
4587
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004588 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589
4590 /* Update gui.cursor_row if the cursor scrolled or copied over */
4591 if (gui.cursor_row >= gui.row
4592 && gui.cursor_col >= gui.scroll_region_left
4593 && gui.cursor_col <= gui.scroll_region_right)
4594 {
4595 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4596 gui.cursor_row += num_lines;
4597 else if (gui.cursor_row <= gui.scroll_region_bot)
4598 gui.cursor_is_valid = FALSE;
4599 }
4600
4601 gui_clear_block(row, gui.scroll_region_left,
4602 row + num_lines - 1, gui.scroll_region_right);
4603}
4604
4605 /*
4606 * TODO: add a vim format to the clipboard which remember
4607 * LINEWISE, CHARWISE, BLOCKWISE
4608 */
4609
4610 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004611clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612{
4613
4614 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004615 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 Size scrapSize;
4617 ScrapFlavorFlags scrapFlags;
4618 ScrapRef scrap = nil;
4619 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 int type;
4621 char *searchCR;
4622 char_u *tempclip;
4623
4624
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004625 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 if (error != noErr)
4627 return;
4628
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004629 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4630 if (error == noErr)
4631 {
4632 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4633 if (error == noErr && scrapSize > 1)
4634 flavor = 1;
4635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004637 if (flavor == 0)
4638 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004639 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004640 if (error != noErr)
4641 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004643 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004644 if (error != noErr)
4645 return;
4646 }
4647
4648 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004650 /* In CARBON we don't need a Handle, a pointer is good */
4651 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004653 /* tempclip = lalloc(scrapSize+1, TRUE); */
4654 HLock(textOfClip);
4655 error = GetScrapFlavorData(scrap,
4656 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4657 &scrapSize, *textOfClip);
4658 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004660 if (flavor)
4661 type = **textOfClip;
4662 else
4663 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4664
4665 tempclip = lalloc(scrapSize + 1, TRUE);
4666 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4667 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004669#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004670 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004671 /* Convert from utf-16 (clipboard) */
4672 size_t encLen = 0;
4673 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004674
4675 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004677 scrapSize = encLen;
4678 vim_free(tempclip);
4679 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004681 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004683
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004684 searchCR = (char *)tempclip;
4685 while (searchCR != NULL)
4686 {
4687 searchCR = strchr(searchCR, '\r');
4688 if (searchCR != NULL)
4689 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004691
4692 clip_yank_selection(type, tempclip, scrapSize, cbd);
4693
4694 vim_free(tempclip);
4695 HUnlock(textOfClip);
4696
4697 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004698}
4699
4700 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004701clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702{
4703 /*
4704 * TODO: Really nothing to do?
4705 */
4706}
4707
4708 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004709clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710{
4711 return OK;
4712}
4713
4714/*
4715 * Send the current selection to the clipboard.
4716 */
4717 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004718clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719{
4720 Handle textOfClip;
4721 long scrapSize;
4722 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724
4725 char_u *str = NULL;
4726
4727 if (!cbd->owned)
4728 return;
4729
4730 clip_get_selection(cbd);
4731
4732 /*
4733 * Once we set the clipboard, lose ownership. If another application sets
4734 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736 cbd->owned = FALSE;
4737
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004738 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004740#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004741 size_t utf16_len = 0;
4742 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4743 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004745 scrapSize = utf16_len;
4746 vim_free(str);
4747 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 }
4749#endif
4750
4751 if (type >= 0)
4752 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004754
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004755 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756 HLock(textOfClip);
4757
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004758 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004759 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004760 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004761 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004762 scrapSize, *textOfClip + 1);
4763 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4764 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765 HUnlock(textOfClip);
4766 DisposeHandle(textOfClip);
4767 }
4768
4769 vim_free(str);
4770}
4771
4772 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004773gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774{
4775 Rect VimBound;
4776
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004777/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779
4780 if (gui.which_scrollbars[SBAR_LEFT])
4781 {
4782 VimBound.left = -gui.scrollbar_width + 1;
4783 }
4784 else
4785 {
4786 VimBound.left = 0;
4787 }
4788
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004790
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004791 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792}
4793
4794/*
4795 * Menu stuff.
4796 */
4797
4798 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004799gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800{
4801 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004802 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 */
4804}
4805
4806 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004807gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808{
4809 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004810 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 */
4812}
4813
4814/*
4815 * Add a sub menu to the menu bar.
4816 */
4817 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004818gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819{
4820 /*
4821 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4822 * TODO: use menu->mnemonic and menu->actext
4823 * TODO: Try to reuse menu id
4824 * Carbon Help suggest to use only id between 1 and 235
4825 */
4826 static long next_avail_id = 128;
4827 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004828#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004829 CFStringRef name;
4830#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004832#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 short index;
4834 vimmenu_T *parent = menu->parent;
4835 vimmenu_T *brother = menu->next;
4836
4837 /* Cannot add a menu if ... */
4838 if ((parent != NULL && parent->submenu_id == 0))
4839 return;
4840
4841 /* menu ID greater than 1024 are reserved for ??? */
4842 if (next_avail_id == 1024)
4843 return;
4844
4845 /* My brother could be the PopUp, find my real brother */
4846 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4847 brother = brother->next;
4848
4849 /* Find where to insert the menu (for MenuBar) */
4850 if ((parent == NULL) && (brother != NULL))
4851 menu_after_me = brother->submenu_id;
4852
4853 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4854 if (!menu_is_menubar(menu->name))
4855 menu_after_me = hierMenu;
4856
4857 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004858#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004859 name = menu_title_removing_mnemonic(menu);
4860#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004862#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 if (name == NULL)
4864 return;
4865
4866 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 {
4868 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004869 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4870 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004871 */
4872 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004873#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004874 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4875 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4876#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004877 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004878#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879 next_avail_id++;
4880 }
4881
4882 if (parent == NULL)
4883 {
4884 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4885
4886 /* TODO: Verify if we could only Insert Menu if really part of the
4887 * menubar The Inserted menu are scanned or the Command-key combos
4888 */
4889
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004890 /* Insert the menu */
4891 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892#if 1
4893 /* Vim should normally update it. TODO: verify */
4894 DrawMenuBar();
4895#endif
4896 }
4897 else
4898 {
4899 /* Adding as a submenu */
4900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004901 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004902
4903 /* Call InsertMenuItem followed by SetMenuItemText
4904 * to avoid special character recognition by InsertMenuItem
4905 */
4906 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004907#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004908 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4909#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004911#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4913 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4914 InsertMenu(menu->submenu_handle, hierMenu);
4915 }
4916
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004917#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004918 CFRelease(name);
4919#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004920 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004921#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922
4923#if 0
4924 /* Done by Vim later on */
4925 DrawMenuBar();
4926#endif
4927}
4928
4929/*
4930 * Add a menu item to a menu
4931 */
4932 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004933gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004935#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004936 CFStringRef name;
4937#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004938 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004939#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940 vimmenu_T *parent = menu->parent;
4941 int menu_inserted;
4942
4943 /* Cannot add item, if the menu have not been created */
4944 if (parent->submenu_id == 0)
4945 return;
4946
4947 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4948 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4949
4950 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004951#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004952 name = menu_title_removing_mnemonic(menu);
4953#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004954 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004955#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956
4957 /* Where are just a menu item, so no handle, no id */
4958 menu->submenu_id = 0;
4959 menu->submenu_handle = NULL;
4960
Bram Moolenaar071d4272004-06-13 20:20:40 +00004961 menu_inserted = 0;
4962 if (menu->actext)
4963 {
4964 /* If the accelerator text for the menu item looks like it describes
4965 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4966 * item's command equivalent.
4967 */
4968 int key = 0;
4969 int modifiers = 0;
4970 char_u *p_actext;
4971
4972 p_actext = menu->actext;
4973 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0);
4974 if (*p_actext != 0)
4975 key = 0; /* error: trailing text */
4976 /* find_special_key() returns a keycode with as many of the
4977 * specified modifiers as appropriate already applied (e.g., for
4978 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4979 * as the only modifier). Since we want to display all of the
4980 * modifiers, we need to convert the keycode back to a printable
4981 * character plus modifiers.
4982 * TODO: Write an alternative find_special_key() that doesn't
4983 * apply modifiers.
4984 */
4985 if (key > 0 && key < 32)
4986 {
4987 /* Convert a control key to an uppercase letter. Note that
4988 * by this point it is no longer possible to distinguish
4989 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4990 */
4991 modifiers |= MOD_MASK_CTRL;
4992 key += '@';
4993 }
4994 /* If the keycode is an uppercase letter, set the Shift modifier.
4995 * If it is a lowercase letter, don't set the modifier, but convert
4996 * the letter to uppercase for display in the menu.
4997 */
4998 else if (key >= 'A' && key <= 'Z')
4999 modifiers |= MOD_MASK_SHIFT;
5000 else if (key >= 'a' && key <= 'z')
5001 key += 'A' - 'a';
5002 /* Note: keycodes below 0x22 are reserved by Apple. */
5003 if (key >= 0x22 && vim_isprintc_strict(key))
5004 {
5005 int valid = 1;
5006 char_u mac_mods = kMenuNoModifiers;
5007 /* Convert Vim modifier codes to Menu Manager equivalents. */
5008 if (modifiers & MOD_MASK_SHIFT)
5009 mac_mods |= kMenuShiftModifier;
5010 if (modifiers & MOD_MASK_CTRL)
5011 mac_mods |= kMenuControlModifier;
5012 if (!(modifiers & MOD_MASK_CMD))
5013 mac_mods |= kMenuNoCommandModifier;
5014 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5015 valid = 0; /* TODO: will Alt someday map to Option? */
5016 if (valid)
5017 {
5018 char_u item_txt[10];
5019 /* Insert the menu item after idx, with its command key. */
5020 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5021 item_txt[3] = key;
5022 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5023 /* Set the modifier keys. */
5024 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5025 menu_inserted = 1;
5026 }
5027 }
5028 }
5029 /* Call InsertMenuItem followed by SetMenuItemText
5030 * to avoid special character recognition by InsertMenuItem
5031 */
5032 if (!menu_inserted)
5033 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5034 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005035#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005036 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5037#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005039#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040
5041#if 0
5042 /* Called by Vim */
5043 DrawMenuBar();
5044#endif
5045
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005046#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005047 CFRelease(name);
5048#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 /* TODO: Can name be freed? */
5050 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005051#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052}
5053
5054 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005055gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005056{
5057 /* no tearoff menus */
5058}
5059
5060/*
5061 * Destroy the machine specific menu widget.
5062 */
5063 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005064gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005066 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067
5068 if (index > 0)
5069 {
5070 if (menu->parent)
5071 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005072 {
5073 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005074 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075
5076 /* Delete the Menu if it was a hierarchical Menu */
5077 if (menu->submenu_id != 0)
5078 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005079 DeleteMenu(menu->submenu_id);
5080 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005081 }
5082 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083 }
5084#ifdef DEBUG_MAC_MENU
5085 else
5086 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005087 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088 }
5089#endif
5090 }
5091 else
5092 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005094 DeleteMenu(menu->submenu_id);
5095 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 }
5097 }
5098 /* Shouldn't this be already done by Vim. TODO: Check */
5099 DrawMenuBar();
5100}
5101
5102/*
5103 * Make a menu either grey or not grey.
5104 */
5105 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005106gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107{
5108 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005109 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110/*
5111 index = menu->index;
5112*/
5113 if (grey)
5114 {
5115 if (menu->children)
5116 DisableMenuItem(menu->submenu_handle, index);
5117 if (menu->parent)
5118 if (menu->parent->submenu_handle)
5119 DisableMenuItem(menu->parent->submenu_handle, index);
5120 }
5121 else
5122 {
5123 if (menu->children)
5124 EnableMenuItem(menu->submenu_handle, index);
5125 if (menu->parent)
5126 if (menu->parent->submenu_handle)
5127 EnableMenuItem(menu->parent->submenu_handle, index);
5128 }
5129}
5130
5131/*
5132 * Make menu item hidden or not hidden
5133 */
5134 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005135gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005136{
5137 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005138 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139}
5140
5141
5142/*
5143 * This is called after setting all the menus to grey/hidden or not.
5144 */
5145 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005146gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147{
5148 DrawMenuBar();
5149}
5150
5151
5152/*
5153 * Scrollbar stuff.
5154 */
5155
5156 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005157gui_mch_enable_scrollbar(
5158 scrollbar_T *sb,
5159 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005160{
5161 if (flag)
5162 ShowControl(sb->id);
5163 else
5164 HideControl(sb->id);
5165
5166#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005167 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005168#endif
5169}
5170
5171 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005172gui_mch_set_scrollbar_thumb(
5173 scrollbar_T *sb,
5174 long val,
5175 long size,
5176 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177{
5178 SetControl32BitMaximum (sb->id, max);
5179 SetControl32BitMinimum (sb->id, 0);
5180 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005181 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005183 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184#endif
5185}
5186
5187 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005188gui_mch_set_scrollbar_pos(
5189 scrollbar_T *sb,
5190 int x,
5191 int y,
5192 int w,
5193 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194{
5195 gui_mch_set_bg_color(gui.back_pixel);
5196/* if (gui.which_scrollbars[SBAR_LEFT])
5197 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005198 MoveControl(sb->id, x-16, y);
5199 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 }
5201 else
5202 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005203 MoveControl(sb->id, x, y);
5204 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 }*/
5206 if (sb == &gui.bottom_sbar)
5207 h += 1;
5208 else
5209 w += 1;
5210
5211 if (gui.which_scrollbars[SBAR_LEFT])
5212 x -= 15;
5213
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005214 MoveControl(sb->id, x, y);
5215 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005216#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005217 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218#endif
5219}
5220
5221 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005222gui_mch_create_scrollbar(
5223 scrollbar_T *sb,
5224 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225{
5226 Rect bounds;
5227
5228 bounds.top = -16;
5229 bounds.bottom = -10;
5230 bounds.right = -10;
5231 bounds.left = -16;
5232
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005233 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234 &bounds,
5235 "\pScrollBar",
5236 TRUE,
5237 0, /* current*/
5238 0, /* top */
5239 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005241 (long) sb->ident);
5242#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005243 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005244#endif
5245}
5246
5247 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005248gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249{
5250 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005251 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005253 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254#endif
5255}
5256
5257
5258/*
5259 * Cursor blink functions.
5260 *
5261 * This is a simple state machine:
5262 * BLINK_NONE not blinking at all
5263 * BLINK_OFF blinking, cursor is not shown
5264 * BLINK_ON blinking, cursor is shown
5265 */
5266 void
5267gui_mch_set_blinking(long wait, long on, long off)
5268{
5269 /* TODO: TODO: TODO: TODO: */
5270/* blink_waittime = wait;
5271 blink_ontime = on;
5272 blink_offtime = off;*/
5273}
5274
5275/*
5276 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5277 */
5278 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005279gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005280{
5281 gui_update_cursor(TRUE, FALSE);
5282 /* TODO: TODO: TODO: TODO: */
5283/* gui_w32_rm_blink_timer();
5284 if (blink_state == BLINK_OFF)
5285 gui_update_cursor(TRUE, FALSE);
5286 blink_state = BLINK_NONE;*/
5287}
5288
5289/*
5290 * Start the cursor blinking. If it was already blinking, this restarts the
5291 * waiting time and shows the cursor.
5292 */
5293 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005294gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005295{
5296 gui_update_cursor(TRUE, FALSE);
5297 /* TODO: TODO: TODO: TODO: */
5298/* gui_w32_rm_blink_timer(); */
5299
5300 /* Only switch blinking on if none of the times is zero */
5301/* if (blink_waittime && blink_ontime && blink_offtime)
5302 {
5303 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5304 (TIMERPROC)_OnBlinkTimer);
5305 blink_state = BLINK_ON;
5306 gui_update_cursor(TRUE, FALSE);
5307 }*/
5308}
5309
5310/*
5311 * Return the RGB value of a pixel as long.
5312 */
5313 long_u
5314gui_mch_get_rgb(guicolor_T pixel)
5315{
5316 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5317}
5318
5319
5320
5321#ifdef FEAT_BROWSE
5322/*
5323 * Pop open a file browser and return the file selected, in allocated memory,
5324 * or NULL if Cancel is hit.
5325 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5326 * title - Title message for the file browser dialog.
5327 * dflt - Default name of file.
5328 * ext - Default extension to be added to files without extensions.
5329 * initdir - directory in which to open the browser (NULL = current dir)
5330 * filter - Filter for matched files to choose from.
5331 * Has a format like this:
5332 * "C Files (*.c)\0*.c\0"
5333 * "All Files\0*.*\0\0"
5334 * If these two strings were concatenated, then a choice of two file
5335 * filters will be selectable to the user. Then only matching files will
5336 * be shown in the browser. If NULL, the default allows all files.
5337 *
5338 * *NOTE* - the filter string must be terminated with TWO nulls.
5339 */
5340 char_u *
5341gui_mch_browse(
5342 int saving,
5343 char_u *title,
5344 char_u *dflt,
5345 char_u *ext,
5346 char_u *initdir,
5347 char_u *filter)
5348{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005349 /* TODO: Add Ammon's safety checl (Dany) */
5350 NavReplyRecord reply;
5351 char_u *fname = NULL;
5352 char_u **fnames = NULL;
5353 long numFiles;
5354 NavDialogOptions navOptions;
5355 OSErr error;
5356
5357 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005358 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005359
5360
5361 /* TODO: If we get a :browse args, set the Multiple bit. */
5362 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5363 | kNavDontAutoTranslate
5364 | kNavDontAddTranslateItems
5365 /* | kNavAllowMultipleFiles */
5366 | kNavAllowStationery;
5367
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005368 (void) C2PascalString(title, &navOptions.message);
5369 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005370 /* Could set clientName?
5371 * windowTitle? (there's no title bar?)
5372 */
5373
5374 if (saving)
5375 {
5376 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005377 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 if (!reply.validRecord)
5379 return NULL;
5380 }
5381 else
5382 {
5383 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5384 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5385 if (!reply.validRecord)
5386 return NULL;
5387 }
5388
5389 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5390
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005391 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005392
5393 if (fnames)
5394 {
5395 fname = fnames[0];
5396 vim_free(fnames);
5397 }
5398
5399 /* TODO: Shorten the file name if possible */
5400 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005401}
5402#endif /* FEAT_BROWSE */
5403
5404#ifdef FEAT_GUI_DIALOG
5405/*
5406 * Stuff for dialogues
5407 */
5408
5409/*
5410 * Create a dialogue dynamically from the parameter strings.
5411 * type = type of dialogue (question, alert, etc.)
5412 * title = dialogue title. may be NULL for default title.
5413 * message = text to display. Dialogue sizes to accommodate it.
5414 * buttons = '\n' separated list of button captions, default first.
5415 * dfltbutton = number of default button.
5416 *
5417 * This routine returns 1 if the first button is pressed,
5418 * 2 for the second, etc.
5419 *
5420 * 0 indicates Esc was pressed.
5421 * -1 for unexpected error
5422 *
5423 * If stubbing out this fn, return 1.
5424 */
5425
5426typedef struct
5427{
5428 short idx;
5429 short width; /* Size of the text in pixel */
5430 Rect box;
5431} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5432
5433#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5434
5435 static void
5436macMoveDialogItem(
5437 DialogRef theDialog,
5438 short itemNumber,
5439 short X,
5440 short Y,
5441 Rect *inBox)
5442{
5443#if 0 /* USE_CARBONIZED */
5444 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005445 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005447 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005448#else
5449 short itemType;
5450 Handle itemHandle;
5451 Rect localBox;
5452 Rect *itemBox = &localBox;
5453
5454 if (inBox != nil)
5455 itemBox = inBox;
5456
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005457 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5458 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5459 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005460 /* To move a control (like a button) we need to call both
5461 * MoveControl and SetDialogItem. FAQ 6-18 */
5462 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005463 MoveControl((ControlRef) itemHandle, X, Y);
5464 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465#endif
5466}
5467
5468 static void
5469macSizeDialogItem(
5470 DialogRef theDialog,
5471 short itemNumber,
5472 short width,
5473 short height)
5474{
5475 short itemType;
5476 Handle itemHandle;
5477 Rect itemBox;
5478
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005479 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005480
5481 /* When width or height is zero do not change it */
5482 if (width == 0)
5483 width = itemBox.right - itemBox.left;
5484 if (height == 0)
5485 height = itemBox.bottom - itemBox.top;
5486
5487#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005488 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489#else
5490 /* Resize the bounding box */
5491 itemBox.right = itemBox.left + width;
5492 itemBox.bottom = itemBox.top + height;
5493
5494 /* To resize a control (like a button) we need to call both
5495 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5496 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005497 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005498
5499 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005500 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005501#endif
5502}
5503
5504 static void
5505macSetDialogItemText(
5506 DialogRef theDialog,
5507 short itemNumber,
5508 Str255 itemName)
5509{
5510 short itemType;
5511 Handle itemHandle;
5512 Rect itemBox;
5513
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005514 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515
5516 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005517 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005519 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520}
5521
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005522/* TODO: There have been some crashes with dialogs, check your inbox
5523 * (Jussi)
5524 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005525 int
5526gui_mch_dialog(
5527 int type,
5528 char_u *title,
5529 char_u *message,
5530 char_u *buttons,
5531 int dfltbutton,
5532 char_u *textfield)
5533{
5534 Handle buttonDITL;
5535 Handle iconDITL;
5536 Handle inputDITL;
5537 Handle messageDITL;
5538 Handle itemHandle;
5539 Handle iconHandle;
5540 DialogPtr theDialog;
5541 char_u len;
5542 char_u PascalTitle[256]; /* place holder for the title */
5543 char_u name[256];
5544 GrafPtr oldPort;
5545 short itemHit;
5546 char_u *buttonChar;
5547 Rect box;
5548 short button;
5549 short lastButton;
5550 short itemType;
5551 short useIcon;
5552 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005553 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005554 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005555 short widestButton = 0;
5556 short dfltButtonEdge = 20; /* gut feeling */
5557 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5558 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5559 short maximumWidth = 400; /* gut feeling */
5560 short maxButtonWidth = 175; /* gut feeling */
5561
5562 short vertical;
5563 short dialogHeight;
5564 short messageLines = 3;
5565 FontInfo textFontInfo;
5566
5567 vgmDlgItm iconItm;
5568 vgmDlgItm messageItm;
5569 vgmDlgItm inputItm;
5570 vgmDlgItm buttonItm;
5571
5572 WindowRef theWindow;
5573
5574 /* Check 'v' flag in 'guioptions': vertical button placement. */
5575 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5576
5577 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005578 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005579
5580 /* Get the WindowRef */
5581 theWindow = GetDialogWindow(theDialog);
5582
5583 /* Hide the window.
5584 * 1. to avoid seeing slow drawing
5585 * 2. to prevent a problem seen while moving dialog item
5586 * within a visible window. (non-Carbon MacOS 9)
5587 * Could be avoided by changing the resource.
5588 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005589 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005590
5591 /* Change the graphical port to the dialog,
5592 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005593 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005594 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595
5596 /* Get the info about the default text,
5597 * used to calculate the height of the message
5598 * and of the text field */
5599 GetFontInfo(&textFontInfo);
5600
5601 /* Set the dialog title */
5602 if (title != NULL)
5603 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005604 (void) C2PascalString(title, &PascalTitle);
5605 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005606 }
5607
5608 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005609 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005610 buttonChar = buttons;
5611 button = 0;
5612
5613 for (;*buttonChar != 0;)
5614 {
5615 /* Get the name of the button */
5616 button++;
5617 len = 0;
5618 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5619 {
5620 if (*buttonChar != DLG_HOTKEY_CHAR)
5621 name[++len] = *buttonChar;
5622 }
5623 if (*buttonChar != 0)
5624 buttonChar++;
5625 name[0] = len;
5626
5627 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005628 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629
5630 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005631 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005632
5633 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005634 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005635 /* Limite the size of any button to an acceptable value. */
5636 /* TODO: Should be based on the message width */
5637 if (width > maxButtonWidth)
5638 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005639 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640
5641 totalButtonWidth += width;
5642
5643 if (width > widestButton)
5644 widestButton = width;
5645 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005646 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 lastButton = button;
5648
5649 /* Add the icon to the Dialog Box. */
5650 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005651 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 switch (type)
5653 {
5654 case VIM_GENERIC: useIcon = kNoteIcon;
5655 case VIM_ERROR: useIcon = kStopIcon;
5656 case VIM_WARNING: useIcon = kCautionIcon;
5657 case VIM_INFO: useIcon = kNoteIcon;
5658 case VIM_QUESTION: useIcon = kNoteIcon;
5659 default: useIcon = kStopIcon;
5660 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005661 AppendDITL(theDialog, iconDITL, overlayDITL);
5662 ReleaseResource(iconDITL);
5663 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005664 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005665 iconHandle = GetIcon(useIcon);
5666 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667
5668 /* Add the message to the Dialog box. */
5669 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005670 messageDITL = GetResource('DITL', 132);
5671 AppendDITL(theDialog, messageDITL, overlayDITL);
5672 ReleaseResource(messageDITL);
5673 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5674 (void) C2PascalString(message, &name);
5675 SetDialogItemText(itemHandle, name);
5676 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005677
5678 /* Add the input box if needed */
5679 if (textfield != NULL)
5680 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005681 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005683 inputDITL = GetResource('DITL', 132);
5684 AppendDITL(theDialog, inputDITL, overlayDITL);
5685 ReleaseResource(inputDITL);
5686 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5687/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5688 (void) C2PascalString(textfield, &name);
5689 SetDialogItemText(itemHandle, name);
5690 inputItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 }
5692
5693 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005694 SetDialogDefaultItem(theDialog, dfltbutton);
5695 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696
5697 /* Reposition element */
5698
5699 /* Check if we need to force vertical */
5700 if (totalButtonWidth > maximumWidth)
5701 vertical = TRUE;
5702
5703 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005704 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705 iconItm.box.right = box.right;
5706 iconItm.box.bottom = box.bottom;
5707
5708 /* Place Message */
5709 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005710 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5711 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005712
5713 /* Place Input */
5714 if (textfield != NULL)
5715 {
5716 inputItm.box.left = messageItm.box.left;
5717 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005718 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5719 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 /* Convert the static text into a text edit.
5721 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005722 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5723 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5725 }
5726
5727 /* Place Button */
5728 if (textfield != NULL)
5729 {
5730 buttonItm.box.left = inputItm.box.left;
5731 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5732 }
5733 else
5734 {
5735 buttonItm.box.left = messageItm.box.left;
5736 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5737 }
5738
5739 for (button=1; button <= lastButton; button++)
5740 {
5741
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005742 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005743 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005744 if (vertical)
5745 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005746 macSizeDialogItem(theDialog, button, widestButton, 0);
5747 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005748 }
5749 /* Calculate position of next button */
5750 if (vertical)
5751 buttonItm.box.top = box.bottom + dfltElementSpacing;
5752 else
5753 buttonItm.box.left = box.right + dfltElementSpacing;
5754 }
5755
5756 /* Resize the dialog box */
5757 dialogHeight = box.bottom + dfltElementSpacing;
5758 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5759
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005761 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005763
5764 /* Display it */
5765 ShowWindow(theWindow);
5766/* BringToFront(theWindow); */
5767 SelectWindow(theWindow);
5768
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005769/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005771 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005772 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773#endif
5774
Bram Moolenaard68071d2006-05-02 22:08:30 +00005775#ifdef USE_CARBONKEYHANDLER
5776 /* Avoid that we use key events for the main window. */
5777 dialog_busy = TRUE;
5778#endif
5779
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780 /* Hang until one of the button is hit */
5781 do
5782 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005783 ModalDialog(nil, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005784 } while ((itemHit < 1) || (itemHit > lastButton));
5785
Bram Moolenaard68071d2006-05-02 22:08:30 +00005786#ifdef USE_CARBONKEYHANDLER
5787 dialog_busy = FALSE;
5788#endif
5789
Bram Moolenaar071d4272004-06-13 20:20:40 +00005790 /* Copy back the text entered by the user into the param */
5791 if (textfield != NULL)
5792 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005793 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5794 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005795#if IOSIZE < 256
5796 /* Truncate the name to IOSIZE if needed */
5797 if (name[0] > IOSIZE)
5798 name[0] = IOSIZE - 1;
5799#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005800 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005801 }
5802
5803 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005804 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005805
5806 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005807 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005808
5809 return itemHit;
5810/*
5811 * Usefull thing which could be used
5812 * SetDialogTimeout(): Auto click a button after timeout
5813 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5814 * MoveDialogItem(): Probably better than SetDialogItem
5815 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005816 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005817 */
5818}
5819#endif /* FEAT_DIALOG_GUI */
5820
5821/*
5822 * Display the saved error message(s).
5823 */
5824#ifdef USE_MCH_ERRMSG
5825 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005826display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005827{
5828 char *p;
5829 char_u pError[256];
5830
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005831 if (error_ga.ga_data == NULL)
5832 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005834 /* avoid putting up a message box with blanks only */
5835 for (p = (char *)error_ga.ga_data; *p; ++p)
5836 if (!isspace(*p))
5837 {
5838 if (STRLEN(p) > 255)
5839 pError[0] = 255;
5840 else
5841 pError[0] = STRLEN(p);
5842
5843 STRNCPY(&pError[1], p, pError[0]);
5844 ParamText(pError, nil, nil, nil);
5845 Alert(128, nil);
5846 break;
5847 /* TODO: handled message longer than 256 chars
5848 * use auto-sizeable alert
5849 * or dialog with scrollbars (TextEdit zone)
5850 */
5851 }
5852 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005853}
5854#endif
5855
5856/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005857 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005858 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005859 void
5860gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861{
5862 Point where;
5863
5864 GetMouse(&where);
5865
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005866 *x = where.h;
5867 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868}
5869
5870 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005871gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872{
5873 /* TODO */
5874#if 0
5875 /* From FAQ 3-11 */
5876
5877 CursorDevicePtr myMouse;
5878 Point where;
5879
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005880 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5881 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882 {
5883 /* New way */
5884
5885 /*
5886 * Get first devoice with one button.
5887 * This will probably be the standad mouse
5888 * startat head of cursor dev list
5889 *
5890 */
5891
5892 myMouse = nil;
5893
5894 do
5895 {
5896 /* Get the next cursor device */
5897 CursorDeviceNextDevice(&myMouse);
5898 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005899 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005901 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902 }
5903 else
5904 {
5905 /* Old way */
5906 where.h = x;
5907 where.v = y;
5908
5909 *(Point *)RawMouse = where;
5910 *(Point *)MTemp = where;
5911 *(Ptr) CrsrNew = 0xFFFF;
5912 }
5913#endif
5914}
5915
5916 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005917gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005918{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919/*
5920 * Clone PopUp to use menu
5921 * Create a object descriptor for the current selection
5922 * Call the procedure
5923 */
5924
5925 MenuHandle CntxMenu;
5926 Point where;
5927 OSStatus status;
5928 UInt32 CntxType;
5929 SInt16 CntxMenuID;
5930 UInt16 CntxMenuItem;
5931 Str255 HelpName = "";
5932 GrafPtr savePort;
5933
5934 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005935 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005937 GetMouse(&where);
5938 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005939 CntxMenu = menu->submenu_handle;
5940
5941 /* TODO: Get the text selection from Vim */
5942
5943 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00005944 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005945 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946
5947 if (status == noErr)
5948 {
5949 if (CntxType == kCMMenuItemSelected)
5950 {
5951 /* Handle the menu CntxMenuID, CntxMenuItem */
5952 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00005953 /* But what about the current menu, is the menu changed by
5954 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005955 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005956 }
5957 else if (CntxMenuID == kCMShowHelpSelected)
5958 {
5959 /* Should come up with the help */
5960 }
5961 }
5962
5963 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005964 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965}
5966
5967#if defined(FEAT_CW_EDITOR) || defined(PROTO)
5968/* TODO: Is it need for MACOS_X? (Dany) */
5969 void
5970mch_post_buffer_write(buf_T *buf)
5971{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005972 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
5973 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974}
5975#endif
5976
5977#ifdef FEAT_TITLE
5978/*
5979 * Set the window title and icon.
5980 * (The icon is not taken care of).
5981 */
5982 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005983gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005984{
5985 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
5986 * that 256. Even better get it to fit nicely in the titlebar.
5987 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005988#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005989 CFStringRef windowTitle;
5990 size_t windowTitleLen;
5991#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005993#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994
5995 if (title == NULL) /* nothing to do */
5996 return;
5997
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00005998#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005999 windowTitleLen = STRLEN(title);
6000 windowTitle = mac_enc_to_cfstring(title, windowTitleLen);
6001
6002 if (windowTitle)
6003 {
6004 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6005 CFRelease(windowTitle);
6006 }
6007#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008 pascalTitle = C2Pascal_save(title);
6009 if (pascalTitle != NULL)
6010 {
6011 SetWTitle(gui.VimWindow, pascalTitle);
6012 vim_free(pascalTitle);
6013 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006014#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015}
6016#endif
6017
6018/*
6019 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6020 */
6021
6022 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006023C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024{
6025 char_u *PascalPtr = (char_u *) PascalString;
6026 int len;
6027 int i;
6028
6029 PascalPtr[0] = 0;
6030 if (CString == NULL)
6031 return 0;
6032
6033 len = STRLEN(CString);
6034 if (len > 255)
6035 len = 255;
6036
6037 for (i = 0; i < len; i++)
6038 PascalPtr[i+1] = CString[i];
6039
6040 PascalPtr[0] = len;
6041
6042 return 0;
6043}
6044
6045 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006046GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006047{
6048 /* From FAQ 8-12 */
6049 Str255 filePascal;
6050 CInfoPBRec myCPB;
6051 OSErr err;
6052
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006053 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006054
6055 myCPB.dirInfo.ioNamePtr = filePascal;
6056 myCPB.dirInfo.ioVRefNum = 0;
6057 myCPB.dirInfo.ioFDirIndex = 0;
6058 myCPB.dirInfo.ioDrDirID = 0;
6059
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006060 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061
6062 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006063 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064
6065 /* TODO: Use an error code mechanism */
6066 return 0;
6067}
6068
6069/*
6070 * Convert a FSSpec to a fuill path
6071 */
6072
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006073char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074{
6075 /*
6076 * TODO: Add protection for 256 char max.
6077 */
6078
6079 CInfoPBRec theCPB;
6080 char_u fname[256];
6081 char_u *filenamePtr = fname;
6082 OSErr error;
6083 int folder = 1;
6084#ifdef USE_UNIXFILENAME
6085 SInt16 dfltVol_vRefNum;
6086 SInt32 dfltVol_dirID;
6087 FSRef refFile;
6088 OSStatus status;
6089 UInt32 pathSize = 256;
6090 char_u pathname[256];
6091 char_u *path = pathname;
6092#else
6093 Str255 directoryName;
6094 char_u temporary[255];
6095 char_u *temporaryPtr = temporary;
6096#endif
6097
6098#ifdef USE_UNIXFILENAME
6099 /* Get the default volume */
6100 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006101 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006102
6103 if (error)
6104 return NULL;
6105#endif
6106
6107 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006108 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006109
6110 /* Get the info about the file specified in FSSpec */
6111 theCPB.dirInfo.ioFDirIndex = 0;
6112 theCPB.dirInfo.ioNamePtr = file.name;
6113 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006114 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006115 theCPB.dirInfo.ioDrDirID = file.parID;
6116
6117 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6118 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006119 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006120
6121 /* If we are called for a new file we expect fnfErr */
6122 if ((error) && (error != fnfErr))
6123 return NULL;
6124
6125 /* Check if it's a file or folder */
6126 /* default to file if file don't exist */
6127 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6128 folder = 0; /* It's not a folder */
6129 else
6130 folder = 1;
6131
6132#ifdef USE_UNIXFILENAME
6133 /*
6134 * The function used here are available in Carbon, but
6135 * do nothing une MacOS 8 and 9
6136 */
6137 if (error == fnfErr)
6138 {
6139 /* If the file to be saved does not already exist, it isn't possible
6140 to convert its FSSpec into an FSRef. But we can construct an
6141 FSSpec for the file's parent folder (since we have its volume and
6142 directory IDs), and since that folder does exist, we can convert
6143 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6144 and, finally, append the filename. */
6145 FSSpec dirSpec;
6146 FSRef dirRef;
6147 Str255 emptyFilename = "\p";
6148 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6149 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6150 if (error)
6151 return NULL;
6152
6153 error = FSpMakeFSRef(&dirSpec, &dirRef);
6154 if (error)
6155 return NULL;
6156
6157 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6158 if (status)
6159 return NULL;
6160
6161 STRCAT(path, "/");
6162 STRCAT(path, filenamePtr);
6163 }
6164 else
6165 {
6166 /* If the file to be saved already exists, we can get its full path
6167 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006168 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006169 if (error)
6170 return NULL;
6171
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006172 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173 if (status)
6174 return NULL;
6175 }
6176
6177 /* Add a slash at the end if needed */
6178 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006179 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006181 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006182#else
6183 /* TODO: Get rid of all USE_UNIXFILENAME below */
6184 /* Set ioNamePtr, it's the same area which is always reused. */
6185 theCPB.dirInfo.ioNamePtr = directoryName;
6186
6187 /* Trick for first entry, set ioDrParID to the first value
6188 * we want for ioDrDirID*/
6189 theCPB.dirInfo.ioDrParID = file.parID;
6190 theCPB.dirInfo.ioDrDirID = file.parID;
6191
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006192 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 do
6194 {
6195 theCPB.dirInfo.ioFDirIndex = -1;
6196 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6197 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006198 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006199 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6200
6201 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6202 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006203 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204
6205 if (error)
6206 return NULL;
6207
6208 /* Put the new directoryName in front of the current fname */
6209 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006210 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211 STRCAT(filenamePtr, ":");
6212 STRCAT(filenamePtr, temporaryPtr);
6213 }
6214#if 1 /* def USE_UNIXFILENAME */
6215 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6216 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6217#else
6218 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6219#endif
6220
6221 /* Get the information about the volume on which the file reside */
6222 theCPB.dirInfo.ioFDirIndex = -1;
6223 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6224 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006225 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6227
6228 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6229 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006230 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006231
6232 if (error)
6233 return NULL;
6234
6235 /* For MacOS Classic always add the volume name */
6236 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006237 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238#ifdef USE_UNIXFILENAME
6239 if (file.vRefNum != dfltVol_vRefNum)
6240#endif
6241 {
6242 /* Add the volume name */
6243 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006244 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 STRCAT(filenamePtr, ":");
6246 STRCAT(filenamePtr, temporaryPtr);
6247
6248#ifdef USE_UNIXFILENAME
6249 STRCPY(temporaryPtr, filenamePtr);
6250 filenamePtr[0] = 0; /* NULL terminate the string */
6251 STRCAT(filenamePtr, "Volumes:");
6252 STRCAT(filenamePtr, temporaryPtr);
6253#endif
6254 }
6255
6256 /* Append final path separator if it's a folder */
6257 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006258 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006259
6260 /* As we use Unix File Name for MacOS X convert it */
6261#ifdef USE_UNIXFILENAME
6262 /* Need to insert leading / */
6263 /* TODO: get the above code to use directly the / */
6264 STRCPY(&temporaryPtr[1], filenamePtr);
6265 temporaryPtr[0] = '/';
6266 STRCPY(filenamePtr, temporaryPtr);
6267 {
6268 char *p;
6269 for (p = fname; *p; p++)
6270 if (*p == ':')
6271 *p = '/';
6272 }
6273#endif
6274
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006275 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006276#endif
6277}
6278
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006279#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006280/*
6281 * Input Method Control functions.
6282 */
6283
6284/*
6285 * Notify cursor position to IM.
6286 */
6287 void
6288im_set_position(int row, int col)
6289{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006290#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006292 im_start_row = row;
6293 im_start_col = col;
6294#endif
6295}
6296
6297static ScriptLanguageRecord gTSLWindow;
6298static ScriptLanguageRecord gTSLInsert;
6299static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6300
6301static Component gTSCWindow;
6302static Component gTSCInsert;
6303static Component gTSCDefault;
6304
6305static int im_initialized = 0;
6306
6307 static void
6308im_on_window_switch(int active)
6309{
6310 ScriptLanguageRecord *slptr = NULL;
6311 OSStatus err;
6312
6313 if (! gui.in_use)
6314 return;
6315
6316 if (im_initialized == 0)
6317 {
6318 im_initialized = 1;
6319
6320 /* save default TSM component (should be U.S.) to default */
6321 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6322 kKeyboardInputMethodClass);
6323 }
6324
6325 if (active == TRUE)
6326 {
6327 im_is_active = TRUE;
6328 ActivateTSMDocument(gTSMDocument);
6329 slptr = &gTSLWindow;
6330
6331 if (slptr)
6332 {
6333 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6334 kKeyboardInputMethodClass);
6335 if (err == noErr)
6336 err = SetTextServiceLanguage(slptr);
6337
6338 if (err == noErr)
6339 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6340 }
6341 }
6342 else
6343 {
6344 err = GetTextServiceLanguage(&gTSLWindow);
6345 if (err == noErr)
6346 slptr = &gTSLWindow;
6347
6348 if (slptr)
6349 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6350 kKeyboardInputMethodClass);
6351
6352 im_is_active = FALSE;
6353 DeactivateTSMDocument(gTSMDocument);
6354 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006355}
6356
6357/*
6358 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6359 */
6360 void
6361im_set_active(int active)
6362{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006363 ScriptLanguageRecord *slptr = NULL;
6364 OSStatus err;
6365
6366 if (! gui.in_use)
6367 return;
6368
6369 if (im_initialized == 0)
6370 {
6371 im_initialized = 1;
6372
6373 /* save default TSM component (should be U.S.) to default */
6374 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6375 kKeyboardInputMethodClass);
6376 }
6377
6378 if (active == TRUE)
6379 {
6380 im_is_active = TRUE;
6381 ActivateTSMDocument(gTSMDocument);
6382 slptr = &gTSLInsert;
6383
6384 if (slptr)
6385 {
6386 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6387 kKeyboardInputMethodClass);
6388 if (err == noErr)
6389 err = SetTextServiceLanguage(slptr);
6390
6391 if (err == noErr)
6392 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6393 }
6394 }
6395 else
6396 {
6397 err = GetTextServiceLanguage(&gTSLInsert);
6398 if (err == noErr)
6399 slptr = &gTSLInsert;
6400
6401 if (slptr)
6402 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6403 kKeyboardInputMethodClass);
6404
6405 /* restore to default when switch to normal mode, so than we could
6406 * enter commands easier */
6407 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6408 kKeyboardInputMethodClass);
6409 SetTextServiceLanguage(&gTSLDefault);
6410
6411 im_is_active = FALSE;
6412 DeactivateTSMDocument(gTSMDocument);
6413 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006414}
6415
6416/*
6417 * Get IM status. When IM is on, return not 0. Else return 0.
6418 */
6419 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006420im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006421{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006422 if (! gui.in_use)
6423 return 0;
6424
6425 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006426}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006427
Bram Moolenaar071d4272004-06-13 20:20:40 +00006428#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006429
6430
6431
6432
6433#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6434// drawer implementation
6435static MenuRef contextMenu = NULL;
6436enum
6437{
6438 kTabContextMenuId = 42,
6439};
6440
6441// the caller has to CFRelease() the returned string
6442 static CFStringRef
6443getTabLabel(tabpage_T *page)
6444{
6445 get_tabline_label(page, FALSE);
6446#ifdef MACOS_CONVERT
6447 return mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
6448#else
6449 // TODO: check internal encoding?
6450 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6451 kCFStringEncodingMacRoman);
6452#endif
6453}
6454
6455
6456#define DRAWER_SIZE 150
6457#define DRAWER_INSET 16
6458
6459static ControlRef dataBrowser = NULL;
6460
6461// when the tabline is hidden, vim doesn't call update_tabline(). When
6462// the tabline is shown again, show_tabline() is called before upate_tabline(),
6463// and because of this, the tab labels and vims internal tabs are out of sync
6464// for a very short time. to prevent inconsistent state, we store the labels
6465// of the tabs, not pointers to the tabs (which are invalid for a short time).
6466static CFStringRef *tabLabels = NULL;
6467static int tabLabelsSize = 0;
6468
6469enum
6470{
6471 kTabsColumn = 'Tabs'
6472};
6473
6474 static int
6475getTabCount(void)
6476{
6477 tabpage_T *tp;
6478 int numTabs = 0;
6479
6480 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006481 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006482 return numTabs;
6483}
6484
6485// data browser item display callback
6486 static OSStatus
6487dbItemDataCallback(ControlRef browser,
6488 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006489 DataBrowserPropertyID property /* column id */,
6490 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006491 Boolean changeValue)
6492{
6493 OSStatus status = noErr;
6494
6495 // assert(property == kTabsColumn); // why is this violated??
6496
6497 // changeValue is true if we have a modifieable list and data was changed.
6498 // In our case, it's always false.
6499 // (that is: if (changeValue) updateInternalData(); else return
6500 // internalData();
6501 if (!changeValue)
6502 {
6503 CFStringRef str;
6504
6505 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6506 str = tabLabels[itemID - 1];
6507 status = SetDataBrowserItemDataText(itemData, str);
6508 }
6509 else
6510 status = errDataBrowserPropertyNotSupported;
6511
6512 return status;
6513}
6514
6515// data browser action callback
6516 static void
6517dbItemNotificationCallback(ControlRef browser,
6518 DataBrowserItemID item,
6519 DataBrowserItemNotification message)
6520{
6521 switch (message)
6522 {
6523 case kDataBrowserItemSelected:
6524 send_tabline_event(item);
6525 break;
6526 }
6527}
6528
6529// callbacks needed for contextual menu:
6530 static void
6531dbGetContextualMenuCallback(ControlRef browser,
6532 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006533 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006534 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006535 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006536{
6537 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6538 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6539 *helpItemString = NULL;
6540
6541 *menu = contextMenu;
6542}
6543
6544 static void
6545dbSelectContextualMenuCallback(ControlRef browser,
6546 MenuRef menu,
6547 UInt32 selectionType,
6548 SInt16 menuID,
6549 MenuItemIndex menuItem)
6550{
6551 if (selectionType == kCMMenuItemSelected)
6552 {
6553 MenuCommand command;
6554 GetMenuItemCommandID(menu, menuItem, &command);
6555
6556 // get tab that was selected when the context menu appeared
6557 // (there is always one tab selected). TODO: check if the context menu
6558 // isn't opened on an item but on empty space (has to be possible some
6559 // way, the finder does it too ;-) )
6560 Handle items = NewHandle(0);
6561 if (items != NULL)
6562 {
6563 int numItems;
6564
6565 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6566 kDataBrowserItemIsSelected, items);
6567 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6568 if (numItems > 0)
6569 {
6570 int idx;
6571 DataBrowserItemID *itemsPtr;
6572
6573 HLock(items);
6574 itemsPtr = (DataBrowserItemID *)*items;
6575 idx = itemsPtr[0];
6576 HUnlock(items);
6577 send_tabline_menu_event(idx, command);
6578 }
6579 DisposeHandle(items);
6580 }
6581 }
6582}
6583
6584// focus callback of the data browser to always leave focus in vim
6585 static OSStatus
6586dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6587{
6588 assert(GetEventClass(event) == kEventClassControl
6589 && GetEventKind(event) == kEventControlSetFocusPart);
6590
6591 return paramErr;
6592}
6593
6594
6595// drawer callback to resize data browser to drawer size
6596 static OSStatus
6597drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6598{
6599 switch (GetEventKind(event))
6600 {
6601 case kEventWindowBoundsChanged: // move or resize
6602 {
6603 UInt32 attribs;
6604 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6605 NULL, sizeof(attribs), NULL, &attribs);
6606 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6607 {
6608 Rect r;
6609 GetWindowBounds(drawer, kWindowContentRgn, &r);
6610 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6611 SetControlBounds(dataBrowser, &r);
6612 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6613 kTabsColumn, r.right);
6614 }
6615 }
6616 break;
6617 }
6618
6619 return eventNotHandledErr;
6620}
6621
6622// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6623// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6624// blue highlights in the list view on these systems, though. Oh well.)
6625
6626
6627#import <mach-o/dyld.h>
6628
6629enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6630
6631 static OSStatus
6632myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6633 OptionBits inAttributesToSet,
6634 OptionBits inAttributesToClear)
6635{
6636 long osVersion;
6637 char *symbolName;
6638 NSSymbol symbol = NULL;
6639 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6640 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6641
6642 Gestalt(gestaltSystemVersion, &osVersion);
6643 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6644 return noErr;
6645
6646 // C name mangling...
6647 symbolName = "_DataBrowserChangeAttributes";
6648 if (!NSIsSymbolNameDefined(symbolName)
6649 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6650 return noErr;
6651
6652 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6653 if (dataBrowserChangeAttributes == NULL)
6654 return noErr; // well...
6655 return dataBrowserChangeAttributes(inDataBrowser,
6656 inAttributesToSet, inAttributesToClear);
6657}
6658
6659 static void
6660initialise_tabline(void)
6661{
6662 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6663 DataBrowserCallbacks dbCallbacks;
6664 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6665 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6666 DataBrowserListViewColumnDesc colDesc;
6667
6668 // drawers have to have compositing enabled
6669 CreateNewWindow(kDrawerWindowClass,
6670 kWindowStandardHandlerAttribute
6671 | kWindowCompositingAttribute
6672 | kWindowResizableAttribute
6673 | kWindowLiveResizeAttribute,
6674 &drawerRect, &drawer);
6675
6676 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6677 SetDrawerParent(drawer, gui.VimWindow);
6678 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6679
6680
6681 // create list view embedded in drawer
6682 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6683 &dataBrowser);
6684
6685 dbCallbacks.version = kDataBrowserLatestCallbacks;
6686 InitDataBrowserCallbacks(&dbCallbacks);
6687 dbCallbacks.u.v1.itemDataCallback =
6688 NewDataBrowserItemDataUPP(dbItemDataCallback);
6689 dbCallbacks.u.v1.itemNotificationCallback =
6690 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6691 dbCallbacks.u.v1.getContextualMenuCallback =
6692 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6693 dbCallbacks.u.v1.selectContextualMenuCallback =
6694 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6695
6696 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6697
6698 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6699 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6700 SetDataBrowserSelectionFlags(dataBrowser,
6701 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6702 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6703 kDataBrowserTableViewFillHilite);
6704 Boolean b = false;
6705 SetControlData(dataBrowser, kControlEntireControl,
6706 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6707
6708 // enable blue background in data browser (this is only in 10.4 and vim
6709 // has to support older osx versions as well, so we have to load this
6710 // function dynamically)
6711 myDataBrowserChangeAttributes(dataBrowser,
6712 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6713
6714 // install callback that keeps focus in vim and away from the data browser
6715 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6716 NULL, NULL);
6717
6718 // install callback that keeps data browser at the size of the drawer
6719 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6720 NULL, NULL);
6721
6722 // add "tabs" column to data browser
6723 colDesc.propertyDesc.propertyID = kTabsColumn;
6724 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6725
6726 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6727 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6728
6729 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6730 colDesc.headerBtnDesc.minimumWidth = 100;
6731 colDesc.headerBtnDesc.maximumWidth = 150;
6732 colDesc.headerBtnDesc.titleOffset = 0;
6733 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6734 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6735 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6736 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6737
6738 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6739
6740 // create tabline popup menu required by vim docs (see :he tabline-menu)
6741 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6742 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6743 TABLINE_MENU_CLOSE, NULL);
6744 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6745 TABLINE_MENU_NEW, NULL);
6746 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6747 TABLINE_MENU_OPEN, NULL);
6748}
6749
6750
6751/*
6752 * Show or hide the tabline.
6753 */
6754 void
6755gui_mch_show_tabline(int showit)
6756{
6757 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006758 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006759 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006760 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006761}
6762
6763/*
6764 * Return TRUE when tabline is displayed.
6765 */
6766 int
6767gui_mch_showing_tabline(void)
6768{
6769 WindowDrawerState state = GetDrawerState(drawer);
6770
6771 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6772}
6773
6774/*
6775 * Update the labels of the tabline.
6776 */
6777 void
6778gui_mch_update_tabline(void)
6779{
6780 tabpage_T *tp;
6781 int numTabs = getTabCount();
6782 int nr = 1;
6783 int curtabidx = 1;
6784
6785 // adjust data browser
6786 if (tabLabels != NULL)
6787 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006788 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006789
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006790 for (i = 0; i < tabLabelsSize; ++i)
6791 CFRelease(tabLabels[i]);
6792 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006793 }
6794 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6795 tabLabelsSize = numTabs;
6796
6797 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6798 {
6799 if (tp == curtab)
6800 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006801 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006802 }
6803
6804 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6805 kDataBrowserItemNoProperty);
6806 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6807 // can pass NULL for the id array
6808 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6809 kDataBrowserItemNoProperty);
6810
6811 DataBrowserItemID item = curtabidx;
6812 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6813}
6814
6815/*
6816 * Set the current tab to "nr". First tab is 1.
6817 */
6818 void
6819gui_mch_set_curtab(nr)
6820 int nr;
6821{
6822 DataBrowserItemID item = nr;
6823 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6824
6825 // TODO: call something like this?: (or restore scroll position, or...)
6826 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6827 kDataBrowserRevealOnly);
6828}
6829
6830#endif // FEAT_GUI_TABLINE