blob: 8859857637b96be0e087b5b8f8e7f11ca3f6e9f0 [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
Bram Moolenaared39e1d2008-08-09 17:55:22 +000065 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +000066static int im_start_row = 0;
67static int im_start_col = 0;
68#endif
69
70#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0]))
71
72static TSMDocumentID gTSMDocument;
73
74static void im_on_window_switch(int active);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000075static EventHandlerUPP keyEventHandlerUPP = NULL;
Bram Moolenaar1b60e502008-03-12 13:40:54 +000076static EventHandlerUPP winEventHandlerUPP = NULL;
77
78static pascal OSStatus gui_mac_handle_window_activate(
79 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
80
81static pascal OSStatus gui_mac_handle_text_input(
82 EventHandlerCallRef nextHandler, EventRef theEvent, void *data);
83
84static pascal OSStatus gui_mac_update_input_area(
85 EventHandlerCallRef nextHandler, EventRef theEvent);
86
87static pascal OSStatus gui_mac_unicode_key_event(
88 EventHandlerCallRef nextHandler, EventRef theEvent);
89
Bram Moolenaar26a60b42005-02-22 08:49:11 +000090#endif
91
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
93/* Include some file. TODO: move into os_mac.h */
94#include <Menus.h>
95#include <Resources.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000096#include <Processes.h>
97#ifdef USE_AEVENT
98# include <AppleEvents.h>
99# include <AERegistry.h>
100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101# include <Gestalt.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102#if UNIVERSAL_INTERFACES_VERSION >= 0x0330
103# include <ControlDefinitions.h>
104# include <Navigation.h> /* Navigation only part of ?? */
105#endif
106
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000107/* Help Manager (balloon.h, HM prefixed functions) are not supported
108 * under Carbon (Jussi) */
109# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110/* New Help Interface for Mac, not implemented yet.*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000111# include <MacHelp.h>
112# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113
114/*
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000115 * These seem to be rectangle options. Why are they not found in
116 * headers? (Jussi)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000118#define kNothing 0
119#define kCreateEmpty 2 /*1*/
120#define kCreateRect 2
121#define kDestroy 3
122
123/*
124 * Dany: Don't like those...
125 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126#define topLeft(r) (((Point*)&(r))[0])
127#define botRight(r) (((Point*)&(r))[1])
128
129
130/* Time of last mouse click, to detect double-click */
131static long lastMouseTick = 0;
132
133/* ??? */
134static RgnHandle cursorRgn;
135static RgnHandle dragRgn;
136static Rect dragRect;
137static short dragRectEnbl;
138static short dragRectControl;
139
140/* This variable is set when waiting for an event, which is the only moment
141 * scrollbar dragging can be done directly. It's not allowed while commands
142 * are executed, because it may move the cursor and that may cause unexpected
143 * problems (e.g., while ":s" is working).
144 */
145static int allow_scrollbar = FALSE;
146
147/* Last mouse click caused contextual menu, (to provide proper release) */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148static short clickIsPopup;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149
150/* Feedback Action for Scrollbar */
151ControlActionUPP gScrollAction;
152ControlActionUPP gScrollDrag;
153
154/* Keeping track of which scrollbar is being dragged */
155static ControlHandle dragged_sb = NULL;
156
Bram Moolenaarc52da9d2008-03-20 13:39:37 +0000157/* Vector of char_u --> control index for hotkeys in dialogs */
158static short *gDialogHotKeys;
159
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000160static struct
161{
162 FMFontFamily family;
163 FMFontSize size;
164 FMFontStyle style;
165 Boolean isPanelVisible;
166} gFontPanelInfo = { 0, 0, 0, false };
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000167
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000168#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000169# define USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000170int p_macatsui_last;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000171ATSUStyle gFontStyle;
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000172# ifdef FEAT_MBYTE
173ATSUStyle gWideFontStyle;
174# endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000175Boolean gIsFontFallbackSet;
176#endif
177
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178/* Colors Macros */
179#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
180#define Red(c) ((c & 0x00FF0000) >> 16)
181#define Green(c) ((c & 0x0000FF00) >> 8)
182#define Blue(c) ((c & 0x000000FF) >> 0)
183
184/* Key mapping */
185
186#define vk_Esc 0x35 /* -> 1B */
187
188#define vk_F1 0x7A /* -> 10 */
189#define vk_F2 0x78 /*0x63*/
190#define vk_F3 0x63 /*0x76*/
191#define vk_F4 0x76 /*0x60*/
192#define vk_F5 0x60 /*0x61*/
193#define vk_F6 0x61 /*0x62*/
194#define vk_F7 0x62 /*0x63*/ /*?*/
195#define vk_F8 0x64
196#define vk_F9 0x65
197#define vk_F10 0x6D
198#define vk_F11 0x67
199#define vk_F12 0x6F
200#define vk_F13 0x69
201#define vk_F14 0x6B
202#define vk_F15 0x71
203
204#define vk_Clr 0x47 /* -> 1B (ESC) */
205#define vk_Enter 0x4C /* -> 03 */
206
207#define vk_Space 0x31 /* -> 20 */
208#define vk_Tab 0x30 /* -> 09 */
209#define vk_Return 0x24 /* -> 0D */
210/* This is wrong for OSX, what is it for? */
211#define vk_Delete 0X08 /* -> 08 BackSpace */
212
213#define vk_Help 0x72 /* -> 05 */
214#define vk_Home 0x73 /* -> 01 */
215#define vk_PageUp 0x74 /* -> 0D */
216#define vk_FwdDelete 0x75 /* -> 7F */
217#define vk_End 0x77 /* -> 04 */
218#define vk_PageDown 0x79 /* -> 0C */
219
220#define vk_Up 0x7E /* -> 1E */
221#define vk_Down 0x7D /* -> 1F */
222#define vk_Left 0x7B /* -> 1C */
223#define vk_Right 0x7C /* -> 1D */
224
225#define vk_Undo vk_F1
226#define vk_Cut vk_F2
227#define vk_Copy vk_F3
228#define vk_Paste vk_F4
229#define vk_PrintScreen vk_F13
230#define vk_SCrollLock vk_F14
231#define vk_Pause vk_F15
232#define vk_NumLock vk_Clr
233#define vk_Insert vk_Help
234
235#define KeySym char
236
237static struct
238{
239 KeySym key_sym;
240 char_u vim_code0;
241 char_u vim_code1;
242} special_keys[] =
243{
244 {vk_Up, 'k', 'u'},
245 {vk_Down, 'k', 'd'},
246 {vk_Left, 'k', 'l'},
247 {vk_Right, 'k', 'r'},
248
249 {vk_F1, 'k', '1'},
250 {vk_F2, 'k', '2'},
251 {vk_F3, 'k', '3'},
252 {vk_F4, 'k', '4'},
253 {vk_F5, 'k', '5'},
254 {vk_F6, 'k', '6'},
255 {vk_F7, 'k', '7'},
256 {vk_F8, 'k', '8'},
257 {vk_F9, 'k', '9'},
258 {vk_F10, 'k', ';'},
259
260 {vk_F11, 'F', '1'},
261 {vk_F12, 'F', '2'},
262 {vk_F13, 'F', '3'},
263 {vk_F14, 'F', '4'},
264 {vk_F15, 'F', '5'},
265
266/* {XK_Help, '%', '1'}, */
267/* {XK_Undo, '&', '8'}, */
268/* {XK_BackSpace, 'k', 'b'}, */
269#ifndef MACOS_X
270 {vk_Delete, 'k', 'b'},
271#endif
272 {vk_Insert, 'k', 'I'},
273 {vk_FwdDelete, 'k', 'D'},
274 {vk_Home, 'k', 'h'},
275 {vk_End, '@', '7'},
276/* {XK_Prior, 'k', 'P'}, */
277/* {XK_Next, 'k', 'N'}, */
278/* {XK_Print, '%', '9'}, */
279
280 {vk_PageUp, 'k', 'P'},
281 {vk_PageDown, 'k', 'N'},
282
283 /* End of list marker: */
284 {(KeySym)0, 0, 0}
285};
286
287/*
288 * ------------------------------------------------------------
289 * Forward declaration (for those needed)
290 * ------------------------------------------------------------
291 */
292
293#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000294OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295#endif
296
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000297#ifdef FEAT_GUI_TABLINE
298static void initialise_tabline(void);
299static WindowRef drawer = NULL; // TODO: put into gui.h
300#endif
301
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000302#ifdef USE_ATSUI_DRAWING
303static void gui_mac_set_font_attributes(GuiFont font);
304static void gui_mac_dispose_atsui_style(void);
305#endif
306
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307/*
308 * ------------------------------------------------------------
309 * Conversion Utility
310 * ------------------------------------------------------------
311 */
312
313/*
314 * C2Pascal_save
315 *
316 * Allocate memory and convert the C-String passed in
317 * into a pascal string
318 *
319 */
320
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000321 char_u *
322C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323{
324 char_u *PascalString;
325 int len;
326
327 if (Cstring == NULL)
328 return NULL;
329
330 len = STRLEN(Cstring);
331
332 if (len > 255) /* Truncate if necessary */
333 len = 255;
334
335 PascalString = alloc(len + 1);
336 if (PascalString != NULL)
337 {
338 mch_memmove(PascalString + 1, Cstring, len);
339 PascalString[0] = len;
340 }
341
342 return PascalString;
343}
344
345/*
346 * C2Pascal_save_and_remove_backslash
347 *
348 * Allocate memory and convert the C-String passed in
349 * into a pascal string. Also remove the backslash at the same time
350 *
351 */
352
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000353 char_u *
354C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355{
356 char_u *PascalString;
357 int len;
358 char_u *p, *c;
359
360 len = STRLEN(Cstring);
361
362 if (len > 255) /* Truncate if necessary */
363 len = 255;
364
365 PascalString = alloc(len + 1);
366 if (PascalString != NULL)
367 {
368 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
369 {
370 if ((*c == '\\') && (c[1] != 0))
371 {
372 c++;
373 }
374 *p = *c;
375 p++;
376 len++;
377 }
378 PascalString[0] = len;
379 }
380
381 return PascalString;
382}
383
384/*
385 * Convert the modifiers of an Event into vim's modifiers (mouse)
386 */
387
388 int_u
389EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
390{
391 int_u vimModifiers = 0x00;
392
393 if (macModifiers & (shiftKey | rightShiftKey))
394 vimModifiers |= MOUSE_SHIFT;
395 if (macModifiers & (controlKey | rightControlKey))
396 vimModifiers |= MOUSE_CTRL;
397 if (macModifiers & (optionKey | rightOptionKey))
398 vimModifiers |= MOUSE_ALT;
399#if 0
400 /* Not yet supported */
401 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
402 vimModifiers |= MOUSE_CMD;
403#endif
404 return (vimModifiers);
405}
406
407/*
408 * Convert the modifiers of an Event into vim's modifiers (keys)
409 */
410
411 static int_u
412EventModifiers2VimModifiers(EventModifiers macModifiers)
413{
414 int_u vimModifiers = 0x00;
415
416 if (macModifiers & (shiftKey | rightShiftKey))
417 vimModifiers |= MOD_MASK_SHIFT;
418 if (macModifiers & (controlKey | rightControlKey))
419 vimModifiers |= MOD_MASK_CTRL;
420 if (macModifiers & (optionKey | rightOptionKey))
421 vimModifiers |= MOD_MASK_ALT;
422#ifdef USE_CMD_KEY
423 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
424 vimModifiers |= MOD_MASK_CMD;
425#endif
426 return (vimModifiers);
427}
428
429/* Convert a string representing a point size into pixels. The string should
430 * be a positive decimal number, with an optional decimal point (eg, "12", or
431 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
432 * character is stored in *end. The flag "vertical" says whether this
433 * calculation is for a vertical (height) size or a horizontal (width) one.
434 *
435 * From gui_w48.c
436 */
437 static int
438points_to_pixels(char_u *str, char_u **end, int vertical)
439{
440 int pixels;
441 int points = 0;
442 int divisor = 0;
443
444 while (*str)
445 {
446 if (*str == '.' && divisor == 0)
447 {
448 /* Start keeping a divisor, for later */
449 divisor = 1;
450 continue;
451 }
452
453 if (!isdigit(*str))
454 break;
455
456 points *= 10;
457 points += *str - '0';
458 divisor *= 10;
459
460 ++str;
461 }
462
463 if (divisor == 0)
464 divisor = 1;
465
466 pixels = points/divisor;
467 *end = str;
468 return pixels;
469}
470
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000471#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000472/*
473 * Deletes all traces of any Windows-style mnemonic text (including any
474 * parentheses) from a menu item and returns the cleaned menu item title.
475 * The caller is responsible for releasing the returned string.
476 */
477 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000478menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000479{
480 CFStringRef name;
481 size_t menuTitleLen;
482 CFIndex displayLen;
483 CFRange mnemonicStart;
484 CFRange mnemonicEnd;
485 CFMutableStringRef cleanedName;
486
487 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000488 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000489
490 if (name)
491 {
492 /* Simple mnemonic-removal algorithm, assumes single parenthesized
493 * mnemonic character towards the end of the menu text */
494 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
495 displayLen = CFStringGetLength(name);
496
497 if (mnemonicStart.location != kCFNotFound
498 && (mnemonicStart.location + 2) < displayLen
499 && CFStringGetCharacterAtIndex(name,
500 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
501 {
502 if (CFStringFindWithOptions(name, CFSTR(")"),
503 CFRangeMake(mnemonicStart.location + 1,
504 displayLen - mnemonicStart.location - 1),
505 kCFCompareBackwards, &mnemonicEnd) &&
506 (mnemonicStart.location + 2) == mnemonicEnd.location)
507 {
508 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
509 if (cleanedName)
510 {
511 CFStringDelete(cleanedName,
512 CFRangeMake(mnemonicStart.location,
513 mnemonicEnd.location + 1 -
514 mnemonicStart.location));
515
516 CFRelease(name);
517 name = cleanedName;
518 }
519 }
520 }
521 }
522
523 return name;
524}
525#endif
526
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527/*
528 * Convert a list of FSSpec aliases into a list of fullpathname
529 * character strings.
530 */
531
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000532 char_u **
533new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534{
535 char_u **fnames = NULL;
536 OSErr newError;
537 long fileCount;
538 FSSpec fileToOpen;
539 long actualSize;
540 AEKeyword dummyKeyword;
541 DescType dummyType;
542
543 /* Get number of files in list */
544 *error = AECountItems(theList, numFiles);
545 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000546 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547
548 /* Allocate the pointer list */
549 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
550
551 /* Empty out the list */
552 for (fileCount = 0; fileCount < *numFiles; fileCount++)
553 fnames[fileCount] = NULL;
554
555 /* Scan the list of FSSpec */
556 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
557 {
558 /* Get the alias for the nth file, convert to an FSSpec */
559 newError = AEGetNthPtr(theList, fileCount, typeFSS,
560 &dummyKeyword, &dummyType,
561 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
562 if (newError)
563 {
564 /* Caller is able to clean up */
565 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000566 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 }
568
569 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000570 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 }
572
573 return (fnames);
574}
575
576/*
577 * ------------------------------------------------------------
578 * CodeWarrior External Editor Support
579 * ------------------------------------------------------------
580 */
581#ifdef FEAT_CW_EDITOR
582
583/*
584 * Handle the Window Search event from CodeWarrior
585 *
586 * Description
587 * -----------
588 *
589 * The IDE sends the Window Search AppleEvent to the editor when it
590 * needs to know whether a particular file is open in the editor.
591 *
592 * Event Reply
593 * -----------
594 *
595 * None. Put data in the location specified in the structure received.
596 *
597 * Remarks
598 * -------
599 *
600 * When the editor receives this event, determine whether the specified
601 * file is open. If it is, return the modification date/time for that file
602 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000603 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604 *
605 */
606
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607typedef struct WindowSearch WindowSearch;
608struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
609{
610 FSSpec theFile; // identifies the file
611 long *theDate; // where to put the modification date/time
612};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000614 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000615Handle_KAHL_SRCH_AE(
616 const AppleEvent *theAEvent,
617 AppleEvent *theReply,
618 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619{
620 OSErr error = noErr;
621 buf_T *buf;
622 int foundFile = false;
623 DescType typeCode;
624 WindowSearch SearchData;
625 Size actualSize;
626
627 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
628 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000629 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000631 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000633 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634
635 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
636 if (buf->b_ml.ml_mfp != NULL
637 && SearchData.theFile.parID == buf->b_FSSpec.parID
638 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
639 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
640 {
641 foundFile = true;
642 break;
643 }
644
645 if (foundFile == false)
646 *SearchData.theDate = fnfErr;
647 else
648 *SearchData.theDate = buf->b_mtime;
649
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 return error;
651};
652
653/*
654 * Handle the Modified (from IDE to Editor) event from CodeWarrior
655 *
656 * Description
657 * -----------
658 *
659 * The IDE sends this event to the external editor when it wants to
660 * know which files that are open in the editor have been modified.
661 *
662 * Parameters None.
663 * ----------
664 *
665 * Event Reply
666 * -----------
667 * The reply for this event is:
668 *
669 * keyDirectObject typeAEList required
670 * each element in the list is a structure of typeChar
671 *
672 * Remarks
673 * -------
674 *
675 * When building the reply event, include one element in the list for
676 * each open file that has been modified.
677 *
678 */
679
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680typedef struct ModificationInfo ModificationInfo;
681struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
682{
683 FSSpec theFile; // identifies the file
684 long theDate; // the date/time the file was last modified
685 short saved; // set this to zero when replying, unused
686};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000688 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000689Handle_KAHL_MOD_AE(
690 const AppleEvent *theAEvent,
691 AppleEvent *theReply,
692 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693{
694 OSErr error = noErr;
695 AEDescList replyList;
696 long numFiles;
697 ModificationInfo theFile;
698 buf_T *buf;
699
700 theFile.saved = 0;
701
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000702 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000704 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705
706 /* Send the reply */
707/* replyObject.descriptorType = typeNull;
708 replyObject.dataHandle = nil;*/
709
710/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
711 error = AECreateList(nil, 0, false, &replyList);
712 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000713 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714
715#if 0
716 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000718 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
719 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 * sizeof(DescType))
721 */
722
723 /* AEPutDesc */
724#endif
725
726 numFiles = 0;
727 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
728 if (buf->b_ml.ml_mfp != NULL)
729 {
730 /* Add this file to the list */
731 theFile.theFile = buf->b_FSSpec;
732 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000733/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
734 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 };
736
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737#if 0
738 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739#endif
740
741 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000742 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 if (replyList.dataHandle)
745 AEDisposeDesc(&replyList);
746
747 return error;
748};
749
750/*
751 * Handle the Get Text event from CodeWarrior
752 *
753 * Description
754 * -----------
755 *
756 * The IDE sends the Get Text AppleEvent to the editor when it needs
757 * the source code from a file. For example, when the user issues a
758 * Check Syntax or Compile command, the compiler needs access to
759 * the source code contained in the file.
760 *
761 * Event Reply
762 * -----------
763 *
764 * None. Put data in locations specified in the structure received.
765 *
766 * Remarks
767 * -------
768 *
769 * When the editor receives this event, it must set the size of the handle
770 * in theText to fit the data in the file. It must then copy the entire
771 * contents of the specified file into the memory location specified in
772 * theText.
773 *
774 */
775
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776typedef struct CW_GetText CW_GetText;
777struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
778{
779 FSSpec theFile; /* identifies the file */
780 Handle theText; /* the location where you return the text (must be resized properly) */
781 long *unused; /* 0 (not used) */
782 long *theDate; /* where to put the modification date/time */
783};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000785 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000786Handle_KAHL_GTTX_AE(
787 const AppleEvent *theAEvent,
788 AppleEvent *theReply,
789 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790{
791 OSErr error = noErr;
792 buf_T *buf;
793 int foundFile = false;
794 DescType typeCode;
795 CW_GetText GetTextData;
796 Size actualSize;
797 char_u *line;
798 char_u *fullbuffer = NULL;
799 long linesize;
800 long lineStart;
801 long BufferSize;
802 long lineno;
803
804 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
805
806 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000807 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808
809 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
810 if (buf->b_ml.ml_mfp != NULL)
811 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
812 {
813 foundFile = true;
814 break;
815 }
816
817 if (foundFile)
818 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000819 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
821 {
822 /* Must use the right buffer */
823 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
824 linesize = STRLEN(line) + 1;
825 lineStart = BufferSize;
826 BufferSize += linesize;
827 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000828 SetHandleSize(GetTextData.theText, BufferSize);
829 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 break; /* Simple handling for now */
832 }
833 else
834 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000835 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000837 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000839 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000840 }
841 }
842 if (fullbuffer != NULL)
843 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000844 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000846 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 }
848 if (foundFile == false)
849 *GetTextData.theDate = fnfErr;
850 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000851/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 *GetTextData.theDate = buf->b_mtime;
853 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000855 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000857 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858}
859
860/*
861 *
862 */
863
864/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000865 pascal OSErr
866FindProcessBySignature(
867 const OSType targetType,
868 const OSType targetCreator,
869 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870{
871 OSErr anErr = noErr;
872 Boolean lookingForProcess = true;
873
874 ProcessInfoRec infoRec;
875
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000876 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 infoRec.processName = nil;
878 infoRec.processAppSpec = nil;
879
880 psnPtr->lowLongOfPSN = kNoProcess;
881 psnPtr->highLongOfPSN = kNoProcess;
882
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000883 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000885 anErr = GetNextProcess(psnPtr);
886 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 else
889 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000890 anErr = GetProcessInformation(psnPtr, &infoRec);
891 if ((anErr == noErr)
892 && (infoRec.processType == targetType)
893 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 }
896 }
897
898 return anErr;
899}//end FindProcessBySignature
900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000901 void
902Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000904 OSErr anErr = noErr;
905 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
907 AppleEvent theReply = { typeNull, nil };
908 AESendMode sendMode;
909 AppleEvent theEvent = {typeNull, nil };
910 AEIdleUPP idleProcUPP = nil;
911 ModificationInfo ModData;
912
913
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000914 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000915 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000917 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
918 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000920 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 {
922 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
923 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
924 }
925
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000926 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927
928 /* Add the parms */
929 ModData.theFile = buf->b_FSSpec;
930 ModData.theDate = buf->b_mtime;
931
932 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000933 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000934
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000935 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 sendMode = kAENoReply;
937 else
938 sendMode = kAEWaitReply;
939
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000940 if (anErr == noErr)
941 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
942 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000944/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000945 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000946 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947 }
948}
949#endif /* FEAT_CW_EDITOR */
950
951/*
952 * ------------------------------------------------------------
953 * Apple Event Handling procedure
954 * ------------------------------------------------------------
955 */
956#ifdef USE_AEVENT
957
958/*
959 * Handle the Unused parms of an AppleEvent
960 */
961
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000962 OSErr
963HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964{
965 OSErr error;
966 long actualSize;
967 DescType dummyType;
968 AEKeyword missedKeyword;
969
970 /* Get the "missed keyword" attribute from the AppleEvent. */
971 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
972 typeKeyword, &dummyType,
973 (Ptr)&missedKeyword, sizeof(missedKeyword),
974 &actualSize);
975
976 /* If the descriptor isn't found, then we got the required parameters. */
977 if (error == errAEDescNotFound)
978 {
979 error = noErr;
980 }
981 else
982 {
983#if 0
984 /* Why is this removed? */
985 error = errAEEventNotHandled;
986#endif
987 }
988
989 return error;
990}
991
992
993/*
994 * Handle the ODoc AppleEvent
995 *
996 * Deals with all files dragged to the application icon.
997 *
998 */
999
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000typedef struct SelectionRange SelectionRange;
1001struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1002{
1003 short unused1; // 0 (not used)
1004 short lineNum; // line to select (<0 to specify range)
1005 long startRange; // start of selection range (if line < 0)
1006 long endRange; // end of selection range (if line < 0)
1007 long unused2; // 0 (not used)
1008 long theDate; // modification date/time
1009};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010
1011/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1012 itor the selection range. If lineNum is zero or greater, scroll the text
1013 to the specified line. If lineNum is less than zero, use the values in
1014 startRange and endRange to select the specified characters. Scroll
1015 the text to display the selection. If lineNum, startRange, and
1016 endRange are all negative, there is no selection range specified.
1017 */
1018
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001019 pascal OSErr
1020HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021{
1022 /*
1023 * TODO: Clean up the code with convert the AppleEvent into
1024 * a ":args"
1025 */
1026 OSErr error = noErr;
1027// OSErr firstError = noErr;
1028// short numErrors = 0;
1029 AEDesc theList;
1030 DescType typeCode;
1031 long numFiles;
1032 // long fileCount;
1033 char_u **fnames;
1034// char_u fname[256];
1035 Size actualSize;
1036 SelectionRange thePosition;
1037 short gotPosition = false;
1038 long lnum;
1039
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 /* the direct object parameter is the list of aliases to files (one or more) */
1041 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1042 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001043 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001044
1045
1046 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1047 if (error == noErr)
1048 gotPosition = true;
1049 if (error == errAEDescNotFound)
1050 error = noErr;
1051 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001052 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054/*
1055 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1056
1057 if (^error) then
1058 {
1059 if (thePosition.lineNum >= 0)
1060 {
1061 // Goto this line
1062 }
1063 else
1064 {
1065 // Set the range char wise
1066 }
1067 }
1068 */
1069
1070
1071#ifdef FEAT_VISUAL
1072 reset_VIsual();
1073#endif
1074
1075 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1076
1077 if (error)
1078 {
1079 /* TODO: empty fnames[] first */
1080 vim_free(fnames);
1081 return (error);
1082 }
1083
1084 if (starting > 0)
1085 {
1086 int i;
1087 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001088 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089
1090 /* these are the initial files dropped on the Vim icon */
1091 for (i = 0 ; i < numFiles; i++)
1092 {
1093 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1094 || (p = vim_strsave(fnames[i])) == NULL)
1095 mch_exit(2);
1096 else
1097 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001098 if (fnum == -1)
1099 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1100 }
1101
1102 /* If the file name was already in the buffer list we need to switch
1103 * to it. */
1104 if (curbuf->b_fnum != fnum)
1105 {
1106 char_u cmd[30];
1107
1108 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1109 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001111
1112 /* Change directory to the location of the first file. */
1113 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1114 shorten_fnames(TRUE);
1115
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116 goto finished;
1117 }
1118
1119 /* Handle the drop, :edit to get to the file */
1120 handle_drop(numFiles, fnames, FALSE);
1121
1122 /* TODO: Handle the goto/select line more cleanly */
1123 if ((numFiles == 1) & (gotPosition))
1124 {
1125 if (thePosition.lineNum >= 0)
1126 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001127 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 /* oap->motion_type = MLINE;
1129 setpcmark();*/
1130 if (lnum < 1L)
1131 lnum = 1L;
1132 else if (lnum > curbuf->b_ml.ml_line_count)
1133 lnum = curbuf->b_ml.ml_line_count;
1134 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001135 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136 /* beginline(BL_SOL | BL_FIX);*/
1137 }
1138 else
1139 goto_byte(thePosition.startRange + 1);
1140 }
1141
1142 /* Update the screen display */
1143 update_screen(NOT_VALID);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001144#ifdef FEAT_VISUAL
1145 /* Select the text if possible */
1146 if (gotPosition)
1147 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001148 VIsual_active = TRUE;
1149 VIsual_select = FALSE;
1150 VIsual = curwin->w_cursor;
1151 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001152 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001153 VIsual_mode = 'v';
1154 goto_byte(thePosition.endRange);
1155 }
1156 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001157 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001158 VIsual_mode = 'V';
1159 VIsual.col = 0;
1160 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001161 }
1162#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 setcursor();
1164 out_flush();
1165
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001166 /* Fake mouse event to wake from stall */
1167 PostEvent(mouseUp, 0);
1168
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001169finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170 AEDisposeDesc(&theList); /* dispose what we allocated */
1171
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001172 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001173 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174}
1175
1176/*
1177 *
1178 */
1179
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001180 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001181Handle_aevt_oapp_AE(
1182 const AppleEvent *theAEvent,
1183 AppleEvent *theReply,
1184 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185{
1186 OSErr error = noErr;
1187
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001188 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001189 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190}
1191
1192/*
1193 *
1194 */
1195
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001196 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001197Handle_aevt_quit_AE(
1198 const AppleEvent *theAEvent,
1199 AppleEvent *theReply,
1200 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201{
1202 OSErr error = noErr;
1203
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001204 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001206 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207
1208 /* Need to fake a :confirm qa */
1209 do_cmdline_cmd((char_u *)"confirm qa");
1210
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001211 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212}
1213
1214/*
1215 *
1216 */
1217
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001218 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001219Handle_aevt_pdoc_AE(
1220 const AppleEvent *theAEvent,
1221 AppleEvent *theReply,
1222 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223{
1224 OSErr error = noErr;
1225
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001226 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001228 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229}
1230
1231/*
1232 * Handling of unknown AppleEvent
1233 *
1234 * (Just get rid of all the parms)
1235 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001236 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001237Handle_unknown_AE(
1238 const AppleEvent *theAEvent,
1239 AppleEvent *theReply,
1240 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241{
1242 OSErr error = noErr;
1243
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001244 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001246 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247}
1248
1249
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250/*
1251 * Install the various AppleEvent Handlers
1252 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001253 OSErr
1254InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255{
1256 OSErr error;
1257
1258 /* install open application handler */
1259 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001260 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261 if (error)
1262 {
1263 return error;
1264 }
1265
1266 /* install quit application handler */
1267 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001268 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 if (error)
1270 {
1271 return error;
1272 }
1273
1274 /* install open document handler */
1275 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001276 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 if (error)
1278 {
1279 return error;
1280 }
1281
1282 /* install print document handler */
1283 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001284 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285
1286/* Install Core Suite */
1287/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001288 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289
1290 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001291 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292
1293 error = AEInstallEventHandler(kAECoreSuite, kAECountElements,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001294 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295
1296 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001297 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298
1299 error = AEInstallEventHandler(kAECoreSuite, kAEDelete,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001300 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301
1302 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001303 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304
1305 error = AEInstallEventHandler(kAECoreSuite, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001306 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
1308 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001309 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310
1311 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001312 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313
1314 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001315 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316
1317 error = AEInstallEventHandler(kAECoreSuite, kAEMove,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001318 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319
1320 error = AEInstallEventHandler(kAECoreSuite, kAESave,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001321 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322
1323 error = AEInstallEventHandler(kAECoreSuite, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001324 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325*/
1326
1327#ifdef FEAT_CW_EDITOR
1328 /*
1329 * Bind codewarrior support handlers
1330 */
1331 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001332 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001333 if (error)
1334 {
1335 return error;
1336 }
1337 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001338 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 if (error)
1340 {
1341 return error;
1342 }
1343 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001344 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345 if (error)
1346 {
1347 return error;
1348 }
1349#endif
1350
1351 return error;
1352
1353}
1354#endif /* USE_AEVENT */
1355
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001356
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001357/*
1358 * Callback function, installed by InstallFontPanelHandler(), below,
1359 * to handle Font Panel events.
1360 */
1361 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001362FontPanelHandler(
1363 EventHandlerCallRef inHandlerCallRef,
1364 EventRef inEvent,
1365 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001366{
1367 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1368 {
1369 gFontPanelInfo.isPanelVisible = false;
1370 return noErr;
1371 }
1372
1373 if (GetEventKind(inEvent) == kEventFontSelection)
1374 {
1375 OSStatus status;
1376 FMFontFamily newFamily;
1377 FMFontSize newSize;
1378 FMFontStyle newStyle;
1379
1380 /* Retrieve the font family ID number. */
1381 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1382 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1383 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1384 &newFamily);
1385 if (status == noErr)
1386 gFontPanelInfo.family = newFamily;
1387
1388 /* Retrieve the font size. */
1389 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1390 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1391 if (status == noErr)
1392 gFontPanelInfo.size = newSize;
1393
1394 /* Retrieve the font style (bold, etc.). Currently unused. */
1395 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1396 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1397 if (status == noErr)
1398 gFontPanelInfo.style = newStyle;
1399 }
1400 return noErr;
1401}
1402
1403
1404 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001405InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001406{
1407 EventTypeSpec eventTypes[2];
1408 EventHandlerUPP handlerUPP;
1409 /* EventHandlerRef handlerRef; */
1410
1411 eventTypes[0].eventClass = kEventClassFont;
1412 eventTypes[0].eventKind = kEventFontSelection;
1413 eventTypes[1].eventClass = kEventClassFont;
1414 eventTypes[1].eventKind = kEventFontPanelClosed;
1415
1416 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1417
1418 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1419 /*userData=*/NULL, /*handlerRef=*/NULL);
1420}
1421
1422
1423/*
1424 * Fill the buffer pointed to by outName with the name and size
1425 * of the font currently selected in the Font Panel.
1426 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001427#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001428 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001429GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001430{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001431 Str255 buf;
1432 ByteCount fontNameLen = 0;
1433 ATSUFontID fid;
1434 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001435
1436 if (!outName)
1437 return;
1438
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001439 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1440 {
1441 /* Canonicalize localized font names */
1442 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1443 gFontPanelInfo.style, &fid, NULL) != noErr)
1444 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001445
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001446 /* Request font name with Mac encoding (otherwise we could
1447 * get an unwanted utf-16 name) */
1448 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1449 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001450 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001451 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001452
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001453 /* Only encode font size, because style (bold, italic, etc) is
1454 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001455 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001456 gFontPanelInfo.size/*,
1457 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1458 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1459 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1460
1461 if ((fontNameLen + STRLEN(styleString)) < 255)
1462 STRCPY(outName + fontNameLen, styleString);
1463 }
1464 else
1465 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001466 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001467 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001468}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001469
1470
Bram Moolenaar071d4272004-06-13 20:20:40 +00001471/*
1472 * ------------------------------------------------------------
1473 * Unfiled yet
1474 * ------------------------------------------------------------
1475 */
1476
1477/*
1478 * gui_mac_get_menu_item_index
1479 *
1480 * Returns the index inside the menu wher
1481 */
1482 short /* Shoulde we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001483gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484{
1485 short index;
1486 short itemIndex = -1;
1487 vimmenu_T *pBrother;
1488
1489 /* Only menu without parent are the:
1490 * -menu in the menubar
1491 * -popup menu
1492 * -toolbar (guess)
1493 *
1494 * Which are not items anyway.
1495 */
1496 if (pMenu->parent)
1497 {
1498 /* Start from the Oldest Brother */
1499 pBrother = pMenu->parent->children;
1500 index = 1;
1501 while ((pBrother) && (itemIndex == -1))
1502 {
1503 if (pBrother == pMenu)
1504 itemIndex = index;
1505 index++;
1506 pBrother = pBrother->next;
1507 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508 }
1509 return itemIndex;
1510}
1511
1512 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001513gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001514{
1515 short index;
1516 vimmenu_T *pChildMenu;
1517 vimmenu_T *pElder = pMenu->parent;
1518
1519
1520 /* Only menu without parent are the:
1521 * -menu in the menubar
1522 * -popup menu
1523 * -toolbar (guess)
1524 *
1525 * Which are not items anyway.
1526 */
1527
1528 if ((pElder) && (pElder->submenu_id == menuID))
1529 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1531 pMenu = pMenu->next;
1532 }
1533 else
1534 {
1535 for (; pMenu != NULL; pMenu = pMenu->next)
1536 {
1537 if (pMenu->children != NULL)
1538 {
1539 pChildMenu = gui_mac_get_vim_menu
1540 (menuID, itemIndex, pMenu->children);
1541 if (pChildMenu)
1542 {
1543 pMenu = pChildMenu;
1544 break;
1545 }
1546 }
1547 }
1548 }
1549 return pMenu;
1550}
1551
1552/*
1553 * ------------------------------------------------------------
1554 * MacOS Feedback procedures
1555 * ------------------------------------------------------------
1556 */
1557 pascal
1558 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001559gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560{
1561 scrollbar_T *sb;
1562 int value, dragging;
1563 ControlHandle theControlToUse;
1564 int dont_scroll_save = dont_scroll;
1565
1566 theControlToUse = dragged_sb;
1567
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001568 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569
1570 if (sb == NULL)
1571 return;
1572
1573 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001574 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 dragging = (partCode != 0);
1576
1577 /* When "allow_scrollbar" is FALSE still need to remember the new
1578 * position, but don't actually scroll by setting "dont_scroll". */
1579 dont_scroll = !allow_scrollbar;
1580 gui_drag_scrollbar(sb, value, dragging);
1581 dont_scroll = dont_scroll_save;
1582}
1583
1584 pascal
1585 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001586gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587{
1588 /* TODO: have live support */
1589 scrollbar_T *sb, *sb_info;
1590 long data;
1591 long value;
1592 int page;
1593 int dragging = FALSE;
1594 int dont_scroll_save = dont_scroll;
1595
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001596 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597
1598 if (sb == NULL)
1599 return;
1600
1601 if (sb->wp != NULL) /* Left or right scrollbar */
1602 {
1603 /*
1604 * Careful: need to get scrollbar info out of first (left) scrollbar
1605 * for window, but keep real scrollbar too because we must pass it to
1606 * gui_drag_scrollbar().
1607 */
1608 sb_info = &sb->wp->w_scrollbars[0];
1609
1610 if (sb_info->size > 5)
1611 page = sb_info->size - 2; /* use two lines of context */
1612 else
1613 page = sb_info->size;
1614 }
1615 else /* Bottom scrollbar */
1616 {
1617 sb_info = sb;
1618 page = W_WIDTH(curwin) - 5;
1619 }
1620
1621 switch (partCode)
1622 {
1623 case kControlUpButtonPart: data = -1; break;
1624 case kControlDownButtonPart: data = 1; break;
1625 case kControlPageDownPart: data = page; break;
1626 case kControlPageUpPart: data = -page; break;
1627 default: data = 0; break;
1628 }
1629
1630 value = sb_info->value + data;
1631/* if (value > sb_info->max)
1632 value = sb_info->max;
1633 else if (value < 0)
1634 value = 0;*/
1635
1636 /* When "allow_scrollbar" is FALSE still need to remember the new
1637 * position, but don't actually scroll by setting "dont_scroll". */
1638 dont_scroll = !allow_scrollbar;
1639 gui_drag_scrollbar(sb, value, dragging);
1640 dont_scroll = dont_scroll_save;
1641
1642 out_flush();
1643 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1644
1645/* if (sb_info->wp != NULL)
1646 {
1647 win_T *wp;
1648 int sb_num;
1649
1650 sb_num = 0;
1651 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1652 sb_num++;
1653
1654 if (wp != NULL)
1655 {
1656 current_scrollbar = sb_num;
1657 scrollbar_value = value;
1658 gui_do_scroll();
1659 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1660 }
1661 }*/
1662}
1663
1664/*
1665 * ------------------------------------------------------------
1666 * MacOS Click Handling procedures
1667 * ------------------------------------------------------------
1668 */
1669
1670
1671/*
1672 * Handle a click inside the window, it may happens in the
1673 * scrollbar or the contents.
1674 *
1675 * TODO: Add support for potential TOOLBAR
1676 */
1677 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001678gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679{
1680 Point thePoint;
1681 int_u vimModifiers;
1682 short thePortion;
1683 ControlHandle theControl;
1684 int vimMouseButton;
1685 short dblClick;
1686
1687 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001688 GlobalToLocal(&thePoint);
1689 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001691 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692
1693 if (theControl != NUL)
1694 {
1695 /* We hit a scollbar */
1696
1697 if (thePortion != kControlIndicatorPart)
1698 {
1699 dragged_sb = theControl;
1700 TrackControl(theControl, thePoint, gScrollAction);
1701 dragged_sb = NULL;
1702 }
1703 else
1704 {
1705 dragged_sb = theControl;
1706#if 1
1707 TrackControl(theControl, thePoint, gScrollDrag);
1708#else
1709 TrackControl(theControl, thePoint, NULL);
1710#endif
1711 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1712 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001713 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 dragged_sb = NULL;
1715 }
1716 }
1717 else
1718 {
1719 /* We are inside the contents */
1720
1721 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1722 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1723
1724 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1725 vimMouseButton = MOUSE_LEFT;
1726
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001728 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 clickIsPopup = FALSE;
1730
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001731 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1732 {
1733 vimMouseButton = MOUSE_RIGHT;
1734 vimModifiers &= ~MOUSE_CTRL;
1735 clickIsPopup = TRUE;
1736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737
1738 /* Is it a double click ? */
1739 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1740
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001741 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 gui_send_mouse_event(vimMouseButton, thePoint.h,
1743 thePoint.v, dblClick, vimModifiers);
1744
1745 /* Create the rectangle around the cursor to detect
1746 * the mouse dragging
1747 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748#if 0
1749 /* TODO: Do we need to this even for the contextual menu?
1750 * It may be require for popup_setpos, but for popup?
1751 */
1752 if (vimMouseButton == MOUSE_LEFT)
1753#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001754 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001755 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 FILL_Y(Y_2_ROW(thePoint.v)),
1757 FILL_X(X_2_COL(thePoint.h)+1),
1758 FILL_Y(Y_2_ROW(thePoint.v)+1));
1759
1760 dragRectEnbl = TRUE;
1761 dragRectControl = kCreateRect;
1762 }
1763 }
1764}
1765
1766/*
1767 * Handle the click in the titlebar (to move the window)
1768 */
1769 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001770gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771{
1772 Rect movingLimits;
1773 Rect *movingLimitsPtr = &movingLimits;
1774
1775 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001776 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001777 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778}
1779
1780/*
1781 * Handle the click in the grow box
1782 */
1783 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001784gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001785{
1786
1787 long newSize;
1788 unsigned short newWidth;
1789 unsigned short newHeight;
1790 Rect resizeLimits;
1791 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 Rect NewContentRect;
1793
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001794 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795
Bram Moolenaar720c7102007-05-10 18:07:50 +00001796 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 /* TODO: Should this come from Vim? */
1798 resizeLimits.top = 100;
1799 resizeLimits.left = 100;
1800
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1802 newWidth = NewContentRect.right - NewContentRect.left;
1803 newHeight = NewContentRect.bottom - NewContentRect.top;
1804 gui_resize_shell(newWidth, newHeight);
1805 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001806 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807}
1808
1809/*
1810 * Handle the click in the zoom box
1811 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001813gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814{
1815 Rect r;
1816 Point p;
1817 short thePart;
1818
1819 /* ideal width is current */
1820 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1821 if (gui.which_scrollbars[SBAR_LEFT])
1822 p.h += gui.scrollbar_width;
1823 if (gui.which_scrollbars[SBAR_RIGHT])
1824 p.h += gui.scrollbar_width;
1825 /* ideal height is as heigh as we can get */
1826 p.v = 15 * 1024;
1827
1828 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1829 ? inZoomIn : inZoomOut;
1830
1831 if (!TrackBox(whichWindow, theEvent->where, thePart))
1832 return;
1833
1834 /* use returned width */
1835 p.h = r.right - r.left;
1836 /* adjust returned height */
1837 p.v = r.bottom - r.top - 2 * gui.border_offset;
1838 if (gui.which_scrollbars[SBAR_BOTTOM])
1839 p.v -= gui.scrollbar_height;
1840 p.v -= p.v % gui.char_height;
1841 p.v += 2 * gui.border_width;
1842 if (gui.which_scrollbars[SBAR_BOTTOM]);
1843 p.v += gui.scrollbar_height;
1844
1845 ZoomWindowIdeal(whichWindow, thePart, &p);
1846
1847 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1848 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1849 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001850 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852
1853/*
1854 * ------------------------------------------------------------
1855 * MacOS Event Handling procedure
1856 * ------------------------------------------------------------
1857 */
1858
1859/*
1860 * Handle the Update Event
1861 */
1862
1863 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001864gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001865{
1866 WindowPtr whichWindow;
1867 GrafPtr savePort;
1868 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 Rect *updateRectPtr;
1871 Rect rc;
1872 Rect growRect;
1873 RgnHandle saveRgn;
1874
1875
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 updateRgn = NewRgn();
1877 if (updateRgn == NULL)
1878 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879
1880 /* This could be done by the caller as we
1881 * don't require anything else out of the event
1882 */
1883 whichWindow = (WindowPtr) event->message;
1884
1885 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001886 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887
1888 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890
1891 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001892 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 /* Redraw the biggest rectangle covering the area
1894 * to be updated.
1895 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1897# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001898 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 * seem to work under MacOS X (Dany)
1900 */
1901 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1902# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001903
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001905 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001907 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908# if 0
1909 /* Code from original Carbon Port (using GetWindowRegion.
1910 * I believe the UpdateRgn is already in local (Dany)
1911 */
1912 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1913 GlobalToLocal(&botRight(updateRect));
1914# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 /* Update the content (i.e. the text) */
1916 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1917 updateRectPtr->right - updateRectPtr->left,
1918 updateRectPtr->bottom - updateRectPtr->top);
1919 /* Clear the border areas if needed */
1920 gui_mch_set_bg_color(gui.back_pixel);
1921 if (updateRectPtr->left < FILL_X(0))
1922 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001923 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1924 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 }
1926 if (updateRectPtr->top < FILL_Y(0))
1927 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001928 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1929 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 }
1931 if (updateRectPtr->right > FILL_X(Columns))
1932 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001933 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001935 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 }
1937 if (updateRectPtr->bottom > FILL_Y(Rows))
1938 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001939 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001941 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001943 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001944 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001947 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948
1949 /* Update the GrowBox */
1950 /* Taken from FAQ 33-27 */
1951 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001953 GetClip(saveRgn);
1954 ClipRect(&growRect);
1955 DrawGrowIcon(whichWindow);
1956 SetClip(saveRgn);
1957 DisposeRgn(saveRgn);
1958 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959
1960 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001961 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962}
1963
1964/*
1965 * Handle the activate/deactivate event
1966 * (apply to a window)
1967 */
1968 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001969gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970{
1971 WindowPtr whichWindow;
1972
1973 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001974 /* Dim scrollbars */
1975 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001977 ControlRef rootControl;
1978 GetRootControl(gui.VimWindow, &rootControl);
1979 if ((event->modifiers) & activeFlag)
1980 ActivateControl(rootControl);
1981 else
1982 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001984
1985 /* Activate */
1986 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987}
1988
1989
1990/*
1991 * Handle the suspend/resume event
1992 * (apply to the application)
1993 */
1994 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001995gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001996{
1997 /* The frontmost application just changed */
1998
1999 /* NOTE: the suspend may happen before the deactivate
2000 * seen on MacOS X
2001 */
2002
2003 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002004 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005 */
2006 if (event->message & 1)
2007 /* Resume */
2008 gui_focus_change(TRUE);
2009 else
2010 /* Suspend */
2011 gui_focus_change(FALSE);
2012}
2013
2014/*
2015 * Handle the key
2016 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002017#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002018 static pascal OSStatus
2019gui_mac_handle_window_activate(
2020 EventHandlerCallRef nextHandler,
2021 EventRef theEvent,
2022 void *data)
2023{
2024 UInt32 eventClass = GetEventClass(theEvent);
2025 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002026
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002027 if (eventClass == kEventClassWindow)
2028 {
2029 switch (eventKind)
2030 {
2031 case kEventWindowActivated:
2032#if defined(USE_IM_CONTROL)
2033 im_on_window_switch(TRUE);
2034#endif
2035 return noErr;
2036
2037 case kEventWindowDeactivated:
2038#if defined(USE_IM_CONTROL)
2039 im_on_window_switch(FALSE);
2040#endif
2041 return noErr;
2042 }
2043 }
2044
2045 return eventNotHandledErr;
2046}
2047
2048 static pascal OSStatus
2049gui_mac_handle_text_input(
2050 EventHandlerCallRef nextHandler,
2051 EventRef theEvent,
2052 void *data)
2053{
2054 UInt32 eventClass = GetEventClass(theEvent);
2055 UInt32 eventKind = GetEventKind(theEvent);
2056
2057 if (eventClass != kEventClassTextInput)
2058 return eventNotHandledErr;
2059
2060 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2061 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2062 (kEventTextInputOffsetToPos != eventKind) &&
2063 (kEventTextInputPosToOffset != eventKind) &&
2064 (kEventTextInputGetSelectedText != eventKind))
2065 return eventNotHandledErr;
2066
2067 switch (eventKind)
2068 {
2069 case kEventTextInputUpdateActiveInputArea:
2070 return gui_mac_update_input_area(nextHandler, theEvent);
2071 case kEventTextInputUnicodeForKeyEvent:
2072 return gui_mac_unicode_key_event(nextHandler, theEvent);
2073
2074 case kEventTextInputOffsetToPos:
2075 case kEventTextInputPosToOffset:
2076 case kEventTextInputGetSelectedText:
2077 break;
2078 }
2079
2080 return eventNotHandledErr;
2081}
2082
2083 static pascal
2084OSStatus gui_mac_update_input_area(
2085 EventHandlerCallRef nextHandler,
2086 EventRef theEvent)
2087{
2088 return eventNotHandledErr;
2089}
2090
2091static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2092 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002093
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002094# define INLINE_KEY_BUFFER_SIZE 80
2095 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002096gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002097 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002098 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002099{
2100 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002101 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002102 UInt32 actualSize;
2103 UniChar *text;
2104 char_u result[INLINE_KEY_BUFFER_SIZE];
2105 short len = 0;
2106 UInt32 key_sym;
2107 char charcode;
2108 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002109 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002110 size_t encLen;
2111 char_u *to = NULL;
2112 Boolean isSpecial = FALSE;
2113 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002114 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002116 /* Mask the mouse (as per user setting) */
2117 if (p_mh)
2118 ObscureCursor();
2119
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002120 /* Don't use the keys when the dialog wants them. */
2121 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002122 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002123
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002124 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002125 typeUnicodeText, NULL, 0, &actualSize, NULL))
2126 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002127
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002128 text = (UniChar *)alloc(actualSize);
2129 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002130 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002131
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002132 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002133 typeUnicodeText, NULL, actualSize, NULL, text);
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(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002137 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
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, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002141 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
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, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002145 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002146 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002147
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002148 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002149 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002150 require_noerr(err, done);
2151
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002153 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002154 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002155#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002156
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002157 key_char = charcode;
2158 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002159
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002160 /* Find the special key (eg., for cursor keys) */
2161 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002162 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002163 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002164 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2165 if (special_keys[i].key_sym == key_sym)
2166 {
2167 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2168 special_keys[i].vim_code1);
2169 key_char = simplify_key(key_char,
2170 (int *)&vimModifiers);
2171 isSpecial = TRUE;
2172 break;
2173 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002174 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002175
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002176 /* Intercept CMD-. and CTRL-c */
2177 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002178 ((modifiers & cmdKey) && key_char == '.'))
2179 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002180
2181 if (!isSpecial)
2182 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002183 /* remove SHIFT for keys that are already shifted, e.g.,
2184 * '(' and '*' */
2185 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2186 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002187
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002188 /* remove CTRL from keys that already have it */
2189 if (key_char < 0x20)
2190 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002191
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002192 /* don't process unicode characters here */
2193 if (!IS_SPECIAL(key_char))
2194 {
2195 /* Following code to simplify and consolidate vimModifiers
2196 * taken liberally from gui_w48.c */
2197 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002198
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002199 /* Interpret META, include SHIFT, etc. */
2200 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2201 if (key_char == CSI)
2202 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002203
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002204 if (IS_SPECIAL(key_char))
2205 isSpecial = TRUE;
2206 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002207 }
2208
2209 if (vimModifiers)
2210 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002211 result[len++] = CSI;
2212 result[len++] = KS_MODIFIER;
2213 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002214 }
2215
2216 if (isSpecial && IS_SPECIAL(key_char))
2217 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002218 result[len++] = CSI;
2219 result[len++] = K_SECOND(key_char);
2220 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002221 }
2222 else
2223 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002224 encLen = actualSize;
2225 to = mac_utf16_to_enc(text, actualSize, &encLen);
2226 if (to)
2227 {
2228 /* This is basically add_to_input_buf_csi() */
2229 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2230 {
2231 result[len++] = to[i];
2232 if (to[i] == CSI)
2233 {
2234 result[len++] = KS_EXTRA;
2235 result[len++] = (int)KE_CSI;
2236 }
2237 }
2238 vim_free(to);
2239 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002240 }
2241
2242 add_to_input_buf(result, len);
2243 err = noErr;
2244
2245done:
2246 vim_free(text);
2247 if (err == noErr)
2248 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002249 /* Fake event to wake up WNE (required to get
2250 * key repeat working */
2251 PostEvent(keyUp, 0);
2252 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002253 }
2254
2255 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002256}
2257#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 void
2259gui_mac_doKeyEvent(EventRecord *theEvent)
2260{
2261 /* TODO: add support for COMMAND KEY */
2262 long menu;
2263 unsigned char string[20];
2264 short num, i;
2265 short len = 0;
2266 KeySym key_sym;
2267 int key_char;
2268 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002269 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270
2271 /* Mask the mouse (as per user setting) */
2272 if (p_mh)
2273 ObscureCursor();
2274
2275 /* Get the key code and it's ASCII representation */
2276 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2277 key_char = theEvent->message & charCodeMask;
2278 num = 1;
2279
2280 /* Intercept CTRL-C */
2281 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002282 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 if (key_char == Ctrl_C && ctrl_c_interrupts)
2284 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002285 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2286 && (key_char == '2' || key_char == '6'))
2287 {
2288 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2289 if (key_char == '2')
2290 key_char = Ctrl_AT;
2291 else
2292 key_char = Ctrl_HAT;
2293 theEvent->modifiers = 0;
2294 }
2295 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296
2297 /* Intercept CMD-. */
2298 if (theEvent->modifiers & cmdKey)
2299 if (key_char == '.')
2300 got_int = TRUE;
2301
2302 /* Handle command key as per menu */
2303 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2304 if (theEvent->modifiers & cmdKey)
2305 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2306 * Why the mouse button? */
2307 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2308 {
2309 menu = MenuKey(key_char);
2310 if (HiWord(menu))
2311 {
2312 gui_mac_handle_menu(menu);
2313 return;
2314 }
2315 }
2316
2317 /* Convert the modifiers */
2318 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2319
2320
2321 /* Handle special keys. */
2322#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002323 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2325#endif
2326 {
2327 /* Find the special key (for non-printable keyt_char) */
2328 if ((key_char < 0x20) || (key_char == 0x7f))
2329 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2330 if (special_keys[i].key_sym == key_sym)
2331 {
2332# if 0
2333 /* We currently don't have not so special key */
2334 if (special_keys[i].vim_code1 == NUL)
2335 key_char = special_keys[i].vim_code0;
2336 else
2337# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002338 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2339 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002340 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 break;
2342 }
2343 }
2344
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002345 /* For some keys the modifier is included in the char itself. */
2346 if (simplify || key_char == TAB || key_char == ' ')
2347 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348
2349 /* Add the modifier to the input bu if needed */
2350 /* Do not want SHIFT-A or CTRL-A with modifier */
2351 if (!IS_SPECIAL(key_char)
2352 && key_sym != vk_Space
2353 && key_sym != vk_Tab
2354 && key_sym != vk_Return
2355 && key_sym != vk_Enter
2356 && key_sym != vk_Esc)
2357 {
2358#if 1
2359 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002360 if ((modifiers == MOD_MASK_SHIFT)
2361 || (modifiers == MOD_MASK_CTRL)
2362 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 modifiers = 0;
2364#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002365 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002367 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002369 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 modifiers = modifiers & ~MOD_MASK_SHIFT;
2371#endif
2372 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002373 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002375 string[len++] = CSI;
2376 string[len++] = KS_MODIFIER;
2377 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 }
2379
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002380 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002382 string[len++] = CSI;
2383 string[len++] = K_SECOND(key_char);
2384 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 }
2386 else
2387 {
2388#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002389 /* Convert characters when needed (e.g., from MacRoman to latin1).
2390 * This doesn't work for the NUL byte. */
2391 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 {
2393 char_u from[2], *to;
2394 int l;
2395
2396 from[0] = key_char;
2397 from[1] = NUL;
2398 l = 1;
2399 to = string_convert(&input_conv, from, &l);
2400 if (to != NULL)
2401 {
2402 for (i = 0; i < l && len < 19; i++)
2403 {
2404 if (to[i] == CSI)
2405 {
2406 string[len++] = KS_EXTRA;
2407 string[len++] = KE_CSI;
2408 }
2409 else
2410 string[len++] = to[i];
2411 }
2412 vim_free(to);
2413 }
2414 else
2415 string[len++] = key_char;
2416 }
2417 else
2418#endif
2419 string[len++] = key_char;
2420 }
2421
2422 if (len == 1 && string[0] == CSI)
2423 {
2424 /* Turn CSI into K_CSI. */
2425 string[ len++ ] = KS_EXTRA;
2426 string[ len++ ] = KE_CSI;
2427 }
2428
2429 add_to_input_buf(string, len);
2430}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002431#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432
2433/*
2434 * Handle MouseClick
2435 */
2436 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002437gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438{
2439 short thePart;
2440 WindowPtr whichWindow;
2441
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002442 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002444#ifdef FEAT_GUI_TABLINE
2445 /* prevent that the vim window size changes if it's activated by a
2446 click into the tab pane */
2447 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002448 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002449#endif
2450
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451 switch (thePart)
2452 {
2453 case (inDesk):
2454 /* TODO: what to do? */
2455 break;
2456
2457 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002458 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 break;
2460
2461 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002462 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 break;
2464
2465 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002466 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467 break;
2468
2469 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002470 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 break;
2472
2473 case (inGoAway):
2474 if (TrackGoAway(whichWindow, theEvent->where))
2475 gui_shell_closed();
2476 break;
2477
2478 case (inZoomIn):
2479 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 break;
2482 }
2483}
2484
2485/*
2486 * Handle MouseMoved
2487 * [this event is a moving in and out of a region]
2488 */
2489 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002490gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491{
2492 Point thePoint;
2493 int_u vimModifiers;
2494
2495 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002496 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2498
2499 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002500 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2504 thePoint.v, FALSE, vimModifiers);
2505
2506 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002507 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 FILL_Y(Y_2_ROW(thePoint.v)),
2509 FILL_X(X_2_COL(thePoint.h)+1),
2510 FILL_Y(Y_2_ROW(thePoint.v)+1));
2511
2512 if (dragRectEnbl)
2513 dragRectControl = kCreateRect;
2514
2515}
2516
2517/*
2518 * Handle the mouse release
2519 */
2520 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002521gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522{
2523 Point thePoint;
2524 int_u vimModifiers;
2525
2526 /* TODO: Properly convert the Contextual menu mouse-up */
2527 /* Potential source of the double menu */
2528 lastMouseTick = theEvent->when;
2529 dragRectEnbl = FALSE;
2530 dragRectControl = kCreateEmpty;
2531 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002532 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533
2534 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535 if (clickIsPopup)
2536 {
2537 vimModifiers &= ~MOUSE_CTRL;
2538 clickIsPopup = FALSE;
2539 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002540 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541}
2542
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 static pascal OSStatus
2544gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2545 void *data)
2546{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547 Point point;
2548 Rect bounds;
2549 UInt32 mod;
2550 SInt32 delta;
2551 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002552 EventMouseWheelAxis axis;
2553
2554 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2555 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2556 && axis != kEventMouseWheelAxisY)
2557 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558
2559 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2560 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2561 goto bail;
2562 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2563 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2564 goto bail;
2565 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2566 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2567 goto bail;
2568
2569 vim_mod = 0;
2570 if (mod & shiftKey)
2571 vim_mod |= MOUSE_SHIFT;
2572 if (mod & controlKey)
2573 vim_mod |= MOUSE_CTRL;
2574 if (mod & optionKey)
2575 vim_mod |= MOUSE_ALT;
2576
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2578 {
2579 point.h -= bounds.left;
2580 point.v -= bounds.top;
2581 }
2582
2583 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2584 point.h, point.v, FALSE, vim_mod);
2585
Bram Moolenaarc236c162008-07-13 17:41:49 +00002586 /* post a bogus event to wake up WaitNextEvent */
2587 PostEvent(keyUp, 0);
2588
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 return noErr;
2590
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002591bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 /*
2593 * when we fail give any additional callback handler a chance to perform
2594 * it's actions
2595 */
2596 return CallNextEventHandler(nextHandler, theEvent);
2597}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598
2599#if 0
2600
2601/*
2602 * This would be the normal way of invoking the contextual menu
2603 * but the Vim API doesn't seem to a support a request to get
2604 * the menu that we should display
2605 */
2606 void
2607gui_mac_handle_contextual_menu(event)
2608 EventRecord *event;
2609{
2610/*
2611 * Clone PopUp to use menu
2612 * Create a object descriptor for the current selection
2613 * Call the procedure
2614 */
2615
2616// Call to Handle Popup
2617 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2618
2619 if (status != noErr)
2620 return;
2621
2622 if (CntxType == kCMMenuItemSelected)
2623 {
2624 /* Handle the menu CntxMenuID, CntxMenuItem */
2625 /* The submenu can be handle directly by gui_mac_handle_menu */
2626 /* But what about the current menu, is the meny changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002627 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 }
2629 else if (CntxMenuID == kCMShowHelpSelected)
2630 {
2631 /* Should come up with the help */
2632 }
2633
2634}
2635#endif
2636
2637/*
2638 * Handle menubar selection
2639 */
2640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002641gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642{
2643 short menu = HiWord(menuChoice);
2644 short item = LoWord(menuChoice);
2645 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646
2647 if (menu == 256) /* TODO: use constant or gui.xyz */
2648 {
2649 if (item == 1)
2650 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 }
2652 else if (item != 0)
2653 {
2654 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2655
2656 if (theVimMenu)
2657 gui_menu_cb(theVimMenu);
2658 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002659 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660}
2661
2662/*
2663 * Dispatch the event to proper handler
2664 */
2665
2666 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002667gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668{
2669 OSErr error;
2670
2671 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002672 if (IsShowContextualMenuClick(event))
2673 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002675 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002677 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002679 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002680 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681
2682 /* Handle normal event */
2683 switch (event->what)
2684 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002685#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 case (keyDown):
2687 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002688 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002690#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002692 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 break;
2694
2695 case (mouseDown):
2696 gui_mac_doMouseDownEvent(event);
2697 break;
2698
2699 case (mouseUp):
2700 gui_mac_doMouseUpEvent(event);
2701 break;
2702
2703 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002704 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 break;
2706
2707 case (diskEvt):
2708 /* We don't need special handling for disk insertion */
2709 break;
2710
2711 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002712 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 break;
2714
2715 case (osEvt):
2716 switch ((event->message >> 24) & 0xFF)
2717 {
2718 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002719 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 break;
2721 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002722 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 break;
2724 }
2725 break;
2726
2727#ifdef USE_AEVENT
2728 case (kHighLevelEvent):
2729 /* Someone's talking to us, through AppleEvents */
2730 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2731 break;
2732#endif
2733 }
2734}
2735
2736/*
2737 * ------------------------------------------------------------
2738 * Unknown Stuff
2739 * ------------------------------------------------------------
2740 */
2741
2742
2743 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002744gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745{
2746 char_u c;
2747 char_u *p;
2748 char_u pFontName[256];
2749 Str255 systemFontname;
2750 short font_id;
2751 short size=9;
2752 GuiFont font;
2753#if 0
2754 char_u *fontNamePtr;
2755#endif
2756
2757 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2758 ;
2759
2760 c = *p;
2761 *p = 0;
2762
2763#if 1
2764 STRCPY(&pFontName[1], font_name);
2765 pFontName[0] = STRLEN(font_name);
2766 *p = c;
2767
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002768 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002769 char_u fontName[256];
2770 char_u *styleStart = vim_strchr(font_name, ':');
2771 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2772 vim_strncpy(fontName, font_name, fontNameLen);
2773
2774 ATSUFontID fontRef;
2775 FMFontStyle fontStyle;
2776 font_id = 0;
2777
2778 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2779 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2780 &fontRef) == noErr)
2781 {
2782 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2783 font_id = 0;
2784 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002785
2786 if (font_id == 0)
2787 {
2788 /*
2789 * Try again, this time replacing underscores in the font name
2790 * with spaces (:set guifont allows the two to be used
2791 * interchangeably; the Font Manager doesn't).
2792 */
2793 int i, changed = FALSE;
2794
2795 for (i = pFontName[0]; i > 0; --i)
2796 {
2797 if (pFontName[i] == '_')
2798 {
2799 pFontName[i] = ' ';
2800 changed = TRUE;
2801 }
2802 }
2803 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002804 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2805 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2806 kFontNoLanguageCode, &fontRef) == noErr)
2807 {
2808 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2809 font_id = 0;
2810 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002811 }
2812
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813#else
2814 /* name = C2Pascal_save(menu->dname); */
2815 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2816
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002817 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818#endif
2819
2820
2821 if (font_id == 0)
2822 {
2823 /* Oups, the system font was it the one the user want */
2824
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002825 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2826 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002827 if (!EqualString(pFontName, systemFontname, false, false))
2828 return NOFONT;
2829 }
2830 if (*p == ':')
2831 {
2832 p++;
2833 /* Set the values found after ':' */
2834 while (*p)
2835 {
2836 switch (*p++)
2837 {
2838 case 'h':
2839 size = points_to_pixels(p, &p, TRUE);
2840 break;
2841 /*
2842 * TODO: Maybe accept width and styles
2843 */
2844 }
2845 while (*p == ':')
2846 p++;
2847 }
2848 }
2849
2850 if (size < 1)
2851 size = 1; /* Avoid having a size of 0 with system font */
2852
2853 font = (size << 16) + ((long) font_id & 0xFFFF);
2854
2855 return font;
2856}
2857
2858/*
2859 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002860 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 * ------------------------------------------------------------
2862 */
2863
2864/*
2865 * Parse the GUI related command-line arguments. Any arguments used are
2866 * deleted from argv, and *argc is decremented accordingly. This is called
2867 * when vim is started, whether or not the GUI has been started.
2868 */
2869 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002870gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871{
2872 /* TODO: Move most of this stuff toward gui_mch_init */
2873#ifdef USE_EXE_NAME
2874 FSSpec applDir;
2875# ifndef USE_FIND_BUNDLE_PATH
2876 short applVRefNum;
2877 long applDirID;
2878 Str255 volName;
2879# else
2880 ProcessSerialNumber psn;
2881 FSRef applFSRef;
2882# endif
2883#endif
2884
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885#if 0
2886 InitCursor();
2887
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889
2890#ifdef USE_AEVENT
2891 (void) InstallAEHandlers();
2892#endif
2893
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002894 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002896 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002898 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899
2900 DrawMenuBar();
2901
2902
2903#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002904 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002906 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907#endif
2908
2909
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910 CreateNewWindow(kDocumentWindowClass,
2911 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002912 &windRect, &gui.VimWindow);
2913 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914
2915 gui.char_width = 7;
2916 gui.char_height = 11;
2917 gui.char_ascent = 6;
2918 gui.num_rows = 24;
2919 gui.num_cols = 80;
2920 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2921
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002922 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2923 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924
2925 dragRectEnbl = FALSE;
2926 dragRgn = NULL;
2927 dragRectControl = kCreateEmpty;
2928 cursorRgn = NewRgn();
2929#endif
2930#ifdef USE_EXE_NAME
2931# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002932 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002934 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935# else
2936 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2937 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002939 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 /* if (err != noErr) return err; */
2941
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002942 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 /* if (err != noErr) return err; */
2944
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002945 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946
2947 /* This technic return NIL when we disallow_gui */
2948# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002949 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951}
2952
2953#ifndef ALWAYS_USE_GUI
2954/*
2955 * Check if the GUI can be started. Called before gvimrc is sourced.
2956 * Return OK or FAIL.
2957 */
2958 int
2959gui_mch_init_check(void)
2960{
2961 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2962 * using the >console
2963 */
2964 if (disallow_gui) /* see main.c for reason to disallow */
2965 return FAIL;
2966 return OK;
2967}
2968#endif
2969
2970 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002971receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002972{
2973 int x, y;
2974 int_u modifiers;
2975 char_u **fnames = NULL;
2976 int count;
2977 int i, j;
2978
2979 /* Get drop position, modifiers and count of items */
2980 {
2981 Point point;
2982 SInt16 mouseUpModifiers;
2983 UInt16 countItem;
2984
2985 GetDragMouse(theDrag, &point, NULL);
2986 GlobalToLocal(&point);
2987 x = point.h;
2988 y = point.v;
2989 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2990 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2991 CountDragItems(theDrag, &countItem);
2992 count = countItem;
2993 }
2994
2995 fnames = (char_u **)alloc(count * sizeof(char_u *));
2996 if (fnames == NULL)
2997 return dragNotAcceptedErr;
2998
2999 /* Get file names dropped */
3000 for (i = j = 0; i < count; ++i)
3001 {
3002 DragItemRef item;
3003 OSErr err;
3004 Size size;
3005 FlavorType type = flavorTypeHFS;
3006 HFSFlavor hfsFlavor;
3007
3008 fnames[i] = NULL;
3009 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3010 err = GetFlavorDataSize(theDrag, item, type, &size);
3011 if (err != noErr || size > sizeof(hfsFlavor))
3012 continue;
3013 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3014 if (err != noErr)
3015 continue;
3016 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3017 }
3018 count = j;
3019
3020 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003021
3022 /* Fake mouse event to wake from stall */
3023 PostEvent(mouseUp, 0);
3024
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 return noErr;
3026}
3027
3028/*
3029 * Initialise the GUI. Create all the windows, set up all the call-backs
3030 * etc.
3031 */
3032 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003033gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034{
3035 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003036 Rect windRect;
3037 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003039 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003040 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003041
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003042 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003043 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003044
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045#if 1
3046 InitCursor();
3047
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049
3050#ifdef USE_AEVENT
3051 (void) InstallAEHandlers();
3052#endif
3053
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003054 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003056 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003058 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059
3060 DrawMenuBar();
3061
3062
3063#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003064 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003066 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067#endif
3068
3069 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003072 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3074 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003075 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076
3077 gui.char_width = 7;
3078 gui.char_height = 11;
3079 gui.char_ascent = 6;
3080 gui.num_rows = 24;
3081 gui.num_cols = 80;
3082 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3083
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003084 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3085 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003087 /* Install Carbon event callbacks. */
3088 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089
3090 dragRectEnbl = FALSE;
3091 dragRgn = NULL;
3092 dragRectControl = kCreateEmpty;
3093 cursorRgn = NewRgn();
3094#endif
3095 /* Display any pending error messages */
3096 display_errors();
3097
3098 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003099 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 gui.norm_pixel = 0x00000000;
3101 gui.back_pixel = 0x00FFFFFF;
3102
3103 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3104 * file). */
3105 set_normal_colors();
3106
3107 /*
3108 * Check that none of the colors are the same as the background color.
3109 * Then store the current values as the defaults.
3110 */
3111 gui_check_colors();
3112 gui.def_norm_pixel = gui.norm_pixel;
3113 gui.def_back_pixel = gui.back_pixel;
3114
3115 /* Get the colors for the highlight groups (gui_check_colors() might have
3116 * changed them) */
3117 highlight_gui_started();
3118
3119 /*
3120 * Setting the gui constants
3121 */
3122#ifdef FEAT_MENU
3123 gui.menu_height = 0;
3124#endif
3125 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3126 gui.border_offset = gui.border_width = 2;
3127
Bram Moolenaar720c7102007-05-10 18:07:50 +00003128 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 gui_mch_draw_string() below), enable it for all font sizes. */
3130 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 eventTypeSpec.eventClass = kEventClassMouse;
3133 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3134 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3135 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3136 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3137 {
3138 mouseWheelHandlerRef = NULL;
3139 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3140 mouseWheelHandlerUPP = NULL;
3141 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003143#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003144 InterfaceTypeList supportedServices = { kUnicodeDocument };
3145 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3146
3147 /* We don't support inline input yet, use input window by default */
3148 UseInputWindow(gTSMDocument, TRUE);
3149
3150 /* Should we activate the document by default? */
3151 // ActivateTSMDocument(gTSMDocument);
3152
3153 EventTypeSpec textEventTypes[] = {
3154 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3155 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3156 { kEventClassTextInput, kEventTextInputPosToOffset },
3157 { kEventClassTextInput, kEventTextInputOffsetToPos },
3158 };
3159
3160 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3161 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3162 NR_ELEMS(textEventTypes),
3163 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003164 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003165 DisposeEventHandlerUPP(keyEventHandlerUPP);
3166 keyEventHandlerUPP = NULL;
3167 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003168
3169 EventTypeSpec windowEventTypes[] = {
3170 { kEventClassWindow, kEventWindowActivated },
3171 { kEventClassWindow, kEventWindowDeactivated },
3172 };
3173
3174 /* Install window event handler to support TSMDocument activate and
3175 * deactivate */
3176 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3177 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3178 winEventHandlerUPP,
3179 NR_ELEMS(windowEventTypes),
3180 windowEventTypes, NULL, NULL))
3181 {
3182 DisposeEventHandlerUPP(winEventHandlerUPP);
3183 winEventHandlerUPP = NULL;
3184 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185#endif
3186
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003187/*
3188#ifdef FEAT_MBYTE
3189 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3190#endif
3191*/
3192
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003193#ifdef FEAT_GUI_TABLINE
3194 /*
3195 * Create the tabline
3196 */
3197 initialise_tabline();
3198#endif
3199
Bram Moolenaar071d4272004-06-13 20:20:40 +00003200 /* TODO: Load bitmap if using TOOLBAR */
3201 return OK;
3202}
3203
3204/*
3205 * Called when the foreground or background color has been changed.
3206 */
3207 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003208gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209{
3210 /* TODO:
3211 * This proc is called when Normal is set to a value
3212 * so what msut be done? I don't know
3213 */
3214}
3215
3216/*
3217 * Open the GUI window which was created by a call to gui_mch_init().
3218 */
3219 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003220gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221{
3222 ShowWindow(gui.VimWindow);
3223
3224 if (gui_win_x != -1 && gui_win_y != -1)
3225 gui_mch_set_winpos(gui_win_x, gui_win_y);
3226
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 /*
3228 * Make the GUI the foreground process (in case it was launched
3229 * from the Terminal or via :gui).
3230 */
3231 {
3232 ProcessSerialNumber psn;
3233 if (GetCurrentProcess(&psn) == noErr)
3234 SetFrontProcess(&psn);
3235 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237 return OK;
3238}
3239
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003240#ifdef USE_ATSUI_DRAWING
3241 static void
3242gui_mac_dispose_atsui_style(void)
3243{
3244 if (p_macatsui && gFontStyle)
3245 ATSUDisposeStyle(gFontStyle);
3246#ifdef FEAT_MBYTE
3247 if (p_macatsui && gWideFontStyle)
3248 ATSUDisposeStyle(gWideFontStyle);
3249#endif
3250}
3251#endif
3252
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253 void
3254gui_mch_exit(int rc)
3255{
3256 /* TODO: find out all what is missing here? */
3257 DisposeRgn(cursorRgn);
3258
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003259#ifdef USE_CARBONKEYHANDLER
3260 if (keyEventHandlerUPP)
3261 DisposeEventHandlerUPP(keyEventHandlerUPP);
3262#endif
3263
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 if (mouseWheelHandlerUPP != NULL)
3265 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003267#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003268 gui_mac_dispose_atsui_style();
3269#endif
3270
3271#ifdef USE_CARBONKEYHANDLER
3272 FixTSMDocument(gTSMDocument);
3273 DeactivateTSMDocument(gTSMDocument);
3274 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003275#endif
3276
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 /* Exit to shell? */
3278 exit(rc);
3279}
3280
3281/*
3282 * Get the position of the top left corner of the window.
3283 */
3284 int
3285gui_mch_get_winpos(int *x, int *y)
3286{
3287 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 Rect bounds;
3289 OSStatus status;
3290
3291 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003292 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293
3294 if (status != noErr)
3295 return FAIL;
3296 *x = bounds.left;
3297 *y = bounds.top;
3298 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 return FAIL;
3300}
3301
3302/*
3303 * Set the position of the top left corner of the window to the given
3304 * coordinates.
3305 */
3306 void
3307gui_mch_set_winpos(int x, int y)
3308{
3309 /* TODO: Should make sure the window is move within range
3310 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3311 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003312 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313}
3314
3315 void
3316gui_mch_set_shellsize(
3317 int width,
3318 int height,
3319 int min_width,
3320 int min_height,
3321 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003322 int base_height,
3323 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 CGrafPtr VimPort;
3326 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327
3328 if (gui.which_scrollbars[SBAR_LEFT])
3329 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003330 VimPort = GetWindowPort(gui.VimWindow);
3331 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003333 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 }
3336 else
3337 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003338 VimPort = GetWindowPort(gui.VimWindow);
3339 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003341 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 }
3343
3344 SizeWindow(gui.VimWindow, width, height, TRUE);
3345
3346 gui_resize_shell(width, height);
3347}
3348
3349/*
3350 * Get the screen dimensions.
3351 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3352 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003353 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 */
3355 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003356gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357{
3358 GDHandle dominantDevice = GetMainDevice();
3359 Rect screenRect = (**dominantDevice).gdRect;
3360
3361 *screen_w = screenRect.right - 10;
3362 *screen_h = screenRect.bottom - 40;
3363}
3364
3365
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003366/*
3367 * Open the Font Panel and wait for the user to select a font and
3368 * close the panel. Then fill the buffer pointed to by font_name with
3369 * the name and size of the selected font and return the font's handle,
3370 * or NOFONT in case of an error.
3371 */
3372 static GuiFont
3373gui_mac_select_font(char_u *font_name)
3374{
3375 GuiFont selected_font = NOFONT;
3376 OSStatus status;
3377 FontSelectionQDStyle curr_font;
3378
3379 /* Initialize the Font Panel with the current font. */
3380 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3381 curr_font.size = (gui.norm_font >> 16);
3382 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3383 curr_font.instance.fontStyle = 0;
3384 curr_font.hasColor = false;
3385 curr_font.version = 0; /* version number of the style structure */
3386 status = SetFontInfoForSelection(kFontSelectionQDType,
3387 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3388
3389 gFontPanelInfo.family = curr_font.instance.fontFamily;
3390 gFontPanelInfo.style = curr_font.instance.fontStyle;
3391 gFontPanelInfo.size = curr_font.size;
3392
3393 /* Pop up the Font Panel. */
3394 status = FPShowHideFontPanel();
3395 if (status == noErr)
3396 {
3397 /*
3398 * The Font Panel is modeless. We really need it to be modal,
3399 * so we spin in an event loop until the panel is closed.
3400 */
3401 gFontPanelInfo.isPanelVisible = true;
3402 while (gFontPanelInfo.isPanelVisible)
3403 {
3404 EventRecord e;
3405 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3406 }
3407
3408 GetFontPanelSelection(font_name);
3409 selected_font = gui_mac_find_font(font_name);
3410 }
3411 return selected_font;
3412}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003413
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003414#ifdef USE_ATSUI_DRAWING
3415 static void
3416gui_mac_create_atsui_style(void)
3417{
3418 if (p_macatsui && gFontStyle == NULL)
3419 {
3420 if (ATSUCreateStyle(&gFontStyle) != noErr)
3421 gFontStyle = NULL;
3422 }
3423#ifdef FEAT_MBYTE
3424 if (p_macatsui && gWideFontStyle == NULL)
3425 {
3426 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3427 gWideFontStyle = NULL;
3428 }
3429#endif
3430
3431 p_macatsui_last = p_macatsui;
3432}
3433#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434
3435/*
3436 * Initialise vim to use the font with the given name. Return FAIL if the font
3437 * could not be loaded, OK otherwise.
3438 */
3439 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003440gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441{
3442 /* TODO: Add support for bold italic underline proportional etc... */
3443 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003444 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 FontInfo font_info;
3446 short font_id;
3447 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003448 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003450#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003451 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003452#endif
3453
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454 if (font_name == NULL)
3455 {
3456 /* First try to get the suggested font */
3457 GetFNum(suggestedFont, &font_id);
3458
3459 if (font_id == 0)
3460 {
3461 /* Then pickup the standard application font */
3462 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003463 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003465 else
3466 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3468 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003469 else if (STRCMP(font_name, "*") == 0)
3470 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003471 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003472
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003473 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003474 if (font == NOFONT)
3475 return FAIL;
3476
3477 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003478 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003479 if (new_p_guifont != NULL)
3480 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003481 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003482 vim_free(p_guifont);
3483 p_guifont = new_p_guifont;
3484 /* Replace spaces in the font name with underscores. */
3485 for ( ; *new_p_guifont; ++new_p_guifont)
3486 {
3487 if (*new_p_guifont == ' ')
3488 *new_p_guifont = '_';
3489 }
3490 }
3491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 else
3493 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003494 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003495 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003496
3497 if (font == NOFONT)
3498 return FAIL;
3499 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003500
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501 gui.norm_font = font;
3502
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003503 hl_set_font_name(used_font_name);
3504
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003505 TextSize(font >> 16);
3506 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003508 GetFontInfo(&font_info);
3509
3510 gui.char_ascent = font_info.ascent;
3511 gui.char_width = CharWidth('_');
3512 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3513
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003514#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003515 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003516 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003517#endif
3518
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520}
3521
Bram Moolenaar02743632005-07-25 20:42:36 +00003522/*
3523 * Adjust gui.char_height (after 'linespace' was changed).
3524 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003526gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527{
3528 FontInfo font_info;
3529
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003530 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3532 gui.char_ascent = font_info.ascent + p_linespace / 2;
3533 return OK;
3534}
3535
3536/*
3537 * Get a font structure for highlighting.
3538 */
3539 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003540gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003541{
3542 GuiFont font;
3543
3544 font = gui_mac_find_font(name);
3545
3546 if (font == NOFONT)
3547 {
3548 if (giveErrorIfMissing)
3549 EMSG2(_(e_font), name);
3550 return NOFONT;
3551 }
3552 /*
3553 * TODO : Accept only monospace
3554 */
3555
3556 return font;
3557}
3558
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003559#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003561 * Return the name of font "font" in allocated memory.
3562 * Don't know how to get the actual name, thus use the provided name.
3563 */
3564 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003565gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003566{
3567 if (name == NULL)
3568 return NULL;
3569 return vim_strsave(name);
3570}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003571#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003572
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003573#ifdef USE_ATSUI_DRAWING
3574 static void
3575gui_mac_set_font_attributes(GuiFont font)
3576{
3577 ATSUFontID fontID;
3578 Fixed fontSize;
3579 Fixed fontWidth;
3580
3581 fontID = font & 0xFFFF;
3582 fontSize = Long2Fix(font >> 16);
3583 fontWidth = Long2Fix(gui.char_width);
3584
3585 ATSUAttributeTag attribTags[] =
3586 {
3587 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3588 kATSUMaxATSUITagValue + 1
3589 };
3590
3591 ByteCount attribSizes[] =
3592 {
3593 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3594 sizeof(font)
3595 };
3596
3597 ATSUAttributeValuePtr attribValues[] =
3598 {
3599 &fontID, &fontSize, &fontWidth, &font
3600 };
3601
3602 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3603 {
3604 if (ATSUSetAttributes(gFontStyle,
3605 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3606 attribTags, attribSizes, attribValues) != noErr)
3607 {
3608# ifndef NDEBUG
3609 fprintf(stderr, "couldn't set font style\n");
3610# endif
3611 ATSUDisposeStyle(gFontStyle);
3612 gFontStyle = NULL;
3613 }
3614
3615#ifdef FEAT_MBYTE
3616 if (has_mbyte)
3617 {
3618 /* FIXME: we should use a more mbyte sensitive way to support
3619 * wide font drawing */
3620 fontWidth = Long2Fix(gui.char_width * 2);
3621
3622 if (ATSUSetAttributes(gWideFontStyle,
3623 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3624 attribTags, attribSizes, attribValues) != noErr)
3625 {
3626 ATSUDisposeStyle(gWideFontStyle);
3627 gWideFontStyle = NULL;
3628 }
3629 }
3630#endif
3631 }
3632}
3633#endif
3634
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003635/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636 * Set the current text font.
3637 */
3638 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003639gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003641#ifdef USE_ATSUI_DRAWING
3642 GuiFont currFont;
3643 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003644
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003645 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003646 {
3647 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003648 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3649 sizeof(font), &currFont, &actualFontByteCount) == noErr
3650 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003651 {
3652 if (currFont == font)
3653 return;
3654 }
3655
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003656 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003657 }
3658
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003659 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003660 {
3661 /* Setup automatic font substitution. The user's guifontwide
3662 * is tried first, then the system tries other fonts. */
3663/*
3664 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3665 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3666 ATSUCreateFontFallbacks(&gFontFallbacks);
3667 ATSUSetObjFontFallbacks(gFontFallbacks, );
3668*/
3669 if (gui.wide_font)
3670 {
3671 ATSUFontID fallbackFonts;
3672 gIsFontFallbackSet = TRUE;
3673
3674 if (FMGetFontFromFontFamilyInstance(
3675 (gui.wide_font & 0xFFFF),
3676 0,
3677 &fallbackFonts,
3678 NULL) == noErr)
3679 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003680 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3681 &fallbackFonts,
3682 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003683 }
3684/*
3685 ATSUAttributeValuePtr fallbackValues[] = { };
3686*/
3687 }
3688 }
3689#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 TextSize(font >> 16);
3691 TextFont(font & 0xFFFF);
3692}
3693
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694/*
3695 * If a font is not going to be used, free its structure.
3696 */
3697 void
3698gui_mch_free_font(font)
3699 GuiFont font;
3700{
3701 /*
3702 * Free font when "font" is not 0.
3703 * Nothing to do in the current implementation, since
3704 * nothing is allocated for each font used.
3705 */
3706}
3707
3708 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003709hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710{
3711 if (isdigit(c))
3712 return c - '0';
3713 c = TOLOWER_ASC(c);
3714 if (c >= 'a' && c <= 'f')
3715 return c - 'a' + 10;
3716 return -1000;
3717}
3718
3719/*
3720 * Return the Pixel value (color) for the given color name. This routine was
3721 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3722 * Programmer's Guide.
3723 * Return INVALCOLOR when failed.
3724 */
3725 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003726gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727{
3728 /* TODO: Add support for the new named color of MacOS 8
3729 */
3730 RGBColor MacColor;
3731// guicolor_T color = 0;
3732
3733 typedef struct guicolor_tTable
3734 {
3735 char *name;
3736 guicolor_T color;
3737 } guicolor_tTable;
3738
3739 /*
3740 * The comment at the end of each line is the source
3741 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3742 */
3743 static guicolor_tTable table[] =
3744 {
3745 {"Black", RGB(0x00, 0x00, 0x00)},
3746 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3747 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3748 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3749 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3750 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3751 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003752 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3753 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3754 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3755 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3756 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3757 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3758 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3759 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3760 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3761 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3762 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3763 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3764 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3765 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3766 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3767 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003768 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3769 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770 {"white", RGB(0xFF, 0xFF, 0xFF)},
3771 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3772 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3773 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3774 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3775 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3776 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3777 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3778 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3779 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3780 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3781 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3782 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3783 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3784 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3785 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3786 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3787 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3788 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003789 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3791 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3792 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3793 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3794 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3795 };
3796
3797 int r, g, b;
3798 int i;
3799
3800 if (name[0] == '#' && strlen((char *) name) == 7)
3801 {
3802 /* Name is in "#rrggbb" format */
3803 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3804 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3805 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3806 if (r < 0 || g < 0 || b < 0)
3807 return INVALCOLOR;
3808 return RGB(r, g, b);
3809 }
3810 else
3811 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003812 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003814 LMGetHiliteRGB(&MacColor);
3815 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816 }
3817 /* Check if the name is one of the colors we know */
3818 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3819 if (STRICMP(name, table[i].name) == 0)
3820 return table[i].color;
3821 }
3822
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 /*
3824 * Last attempt. Look in the file "$VIM/rgb.txt".
3825 */
3826 {
3827#define LINE_LEN 100
3828 FILE *fd;
3829 char line[LINE_LEN];
3830 char_u *fname;
3831
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833 if (fname == NULL)
3834 return INVALCOLOR;
3835
3836 fd = fopen((char *)fname, "rt");
3837 vim_free(fname);
3838 if (fd == NULL)
3839 return INVALCOLOR;
3840
3841 while (!feof(fd))
3842 {
3843 int len;
3844 int pos;
3845 char *color;
3846
3847 fgets(line, LINE_LEN, fd);
3848 len = strlen(line);
3849
3850 if (len <= 1 || line[len-1] != '\n')
3851 continue;
3852
3853 line[len-1] = '\0';
3854
3855 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3856 if (i != 3)
3857 continue;
3858
3859 color = line + pos;
3860
3861 if (STRICMP(color, name) == 0)
3862 {
3863 fclose(fd);
3864 return (guicolor_T) RGB(r, g, b);
3865 }
3866 }
3867 fclose(fd);
3868 }
3869
3870 return INVALCOLOR;
3871}
3872
3873/*
3874 * Set the current text foreground color.
3875 */
3876 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003877gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003878{
3879 RGBColor TheColor;
3880
3881 TheColor.red = Red(color) * 0x0101;
3882 TheColor.green = Green(color) * 0x0101;
3883 TheColor.blue = Blue(color) * 0x0101;
3884
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003885 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886}
3887
3888/*
3889 * Set the current text background color.
3890 */
3891 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003892gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893{
3894 RGBColor TheColor;
3895
3896 TheColor.red = Red(color) * 0x0101;
3897 TheColor.green = Green(color) * 0x0101;
3898 TheColor.blue = Blue(color) * 0x0101;
3899
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003900 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901}
3902
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003903RGBColor specialColor;
3904
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003905/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003906 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003907 */
3908 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003909gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003910{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003911 specialColor.red = Red(color) * 0x0101;
3912 specialColor.green = Green(color) * 0x0101;
3913 specialColor.blue = Blue(color) * 0x0101;
3914}
3915
3916/*
3917 * Draw undercurl at the bottom of the character cell.
3918 */
3919 static void
3920draw_undercurl(int flags, int row, int col, int cells)
3921{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003922 int x;
3923 int offset;
3924 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3925 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003926
3927 RGBForeColor(&specialColor);
3928
3929 offset = val[FILL_X(col) % 8];
3930 MoveTo(FILL_X(col), y - offset);
3931
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003932 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003933 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003934 offset = val[x % 8];
3935 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003936 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003937}
3938
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003939
3940 static void
3941draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943#ifdef FEAT_MBYTE
3944 char_u *tofree = NULL;
3945
3946 if (output_conv.vc_type != CONV_NONE)
3947 {
3948 tofree = string_convert(&output_conv, s, &len);
3949 if (tofree != NULL)
3950 s = tofree;
3951 }
3952#endif
3953
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 /*
3955 * On OS X, try using Quartz-style text antialiasing.
3956 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003957 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 {
3959 /* Quartz antialiasing is available only in OS 10.2 and later. */
3960 UInt32 qd_flags = (p_antialias ?
3961 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003962 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 }
3964
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003965 /*
3966 * When antialiasing we're using srcOr mode, we have to clear the block
3967 * before drawing the text.
3968 * Also needed when 'linespace' is non-zero to remove the cursor and
3969 * underlining.
3970 * But not when drawing transparently.
3971 * The following is like calling gui_mch_clear_block(row, col, row, col +
3972 * len - 1), but without setting the bg color to gui.back_pixel.
3973 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003974 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003975 && !(flags & DRAW_TRANSP))
3976 {
3977 Rect rc;
3978
3979 rc.left = FILL_X(col);
3980 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003981#ifdef FEAT_MBYTE
3982 /* Multibyte computation taken from gui_w32.c */
3983 if (has_mbyte)
3984 {
3985 int cell_len = 0;
3986 int n;
3987
3988 /* Compute the length in display cells. */
3989 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
3990 cell_len += (*mb_ptr2cells)(s + n);
3991 rc.right = FILL_X(col + cell_len);
3992 }
3993 else
3994#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003995 rc.right = FILL_X(col + len) + (col + len == Columns);
3996 rc.bottom = FILL_Y(row + 1);
3997 EraseRect(&rc);
3998 }
3999
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004000 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001 {
4002 StyleParameter face;
4003
4004 face = normal;
4005 if (flags & DRAW_BOLD)
4006 face |= bold;
4007 if (flags & DRAW_UNDERL)
4008 face |= underline;
4009 TextFace(face);
4010
4011 /* Quartz antialiasing works only in srcOr transfer mode. */
4012 TextMode(srcOr);
4013
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 MoveTo(TEXT_X(col), TEXT_Y(row));
4015 DrawText((char*)s, 0, len);
4016 }
4017 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018 {
4019 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004020 TextMode(srcCopy);
4021 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022
4023 /* SelectFont(hdc, gui.currFont); */
4024
4025 if (flags & DRAW_TRANSP)
4026 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004027 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 }
4029
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004030 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004031 DrawText((char *)s, 0, len);
4032
4033 if (flags & DRAW_BOLD)
4034 {
4035 TextMode(srcOr);
4036 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4037 DrawText((char *)s, 0, len);
4038 }
4039
4040 if (flags & DRAW_UNDERL)
4041 {
4042 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4043 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4044 }
4045 }
4046
4047 if (flags & DRAW_UNDERC)
4048 draw_undercurl(flags, row, col, len);
4049
4050#ifdef FEAT_MBYTE
4051 vim_free(tofree);
4052#endif
4053}
4054
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004055#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004056
4057 static void
4058draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4059{
4060 /* ATSUI requires utf-16 strings */
4061 UniCharCount utf16_len;
4062 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4063 utf16_len /= sizeof(UniChar);
4064
4065 /* - ATSUI automatically antialiases text (Someone)
4066 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004067#ifdef MAC_ATSUI_DEBUG
4068 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4069 row, col, len, len == 1 ? s[0] : ' ');
4070#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004071 /*
4072 * When antialiasing we're using srcOr mode, we have to clear the block
4073 * before drawing the text.
4074 * Also needed when 'linespace' is non-zero to remove the cursor and
4075 * underlining.
4076 * But not when drawing transparently.
4077 * The following is like calling gui_mch_clear_block(row, col, row, col +
4078 * len - 1), but without setting the bg color to gui.back_pixel.
4079 */
4080 if ((flags & DRAW_TRANSP) == 0)
4081 {
4082 Rect rc;
4083
4084 rc.left = FILL_X(col);
4085 rc.top = FILL_Y(row);
4086 /* Multibyte computation taken from gui_w32.c */
4087 if (has_mbyte)
4088 {
4089 int cell_len = 0;
4090 int n;
4091
4092 /* Compute the length in display cells. */
4093 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4094 cell_len += (*mb_ptr2cells)(s + n);
4095 rc.right = FILL_X(col + cell_len);
4096 }
4097 else
4098 rc.right = FILL_X(col + len) + (col + len == Columns);
4099
4100 rc.bottom = FILL_Y(row + 1);
4101 EraseRect(&rc);
4102 }
4103
4104 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004105 TextMode(srcCopy);
4106 TextFace(normal);
4107
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004108 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004109 if (flags & DRAW_TRANSP)
4110 {
4111 TextMode(srcOr);
4112 }
4113
4114 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004115
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004116 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004117 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004118 Boolean attValue = true;
4119 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4120 ByteCount attribSizes[] = { sizeof(Boolean) };
4121 ATSUAttributeValuePtr attribValues[] = { &attValue };
4122
4123 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4124 }
4125
4126#ifdef FEAT_MBYTE
4127 if (has_mbyte)
4128 {
4129 int n, width_in_cell, last_width_in_cell;
4130 UniCharArrayOffset offset = 0;
4131 UniCharCount yet_to_draw = 0;
4132 ATSUTextLayout textLayout;
4133 ATSUStyle textStyle;
4134
4135 last_width_in_cell = 1;
4136 ATSUCreateTextLayout(&textLayout);
4137 ATSUSetTextPointerLocation(textLayout, tofree,
4138 kATSUFromTextBeginning,
4139 kATSUToTextEnd, utf16_len);
4140 /*
4141 ATSUSetRunStyle(textLayout, gFontStyle,
4142 kATSUFromTextBeginning, kATSUToTextEnd); */
4143
4144 /* Compute the length in display cells. */
4145 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4146 {
4147 width_in_cell = (*mb_ptr2cells)(s + n);
4148
4149 /* probably we are switching from single byte character
4150 * to multibyte characters (which requires more than one
4151 * cell to draw) */
4152 if (width_in_cell != last_width_in_cell)
4153 {
4154#ifdef MAC_ATSUI_DEBUG
4155 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4156 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4157#endif
4158 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4159 : gFontStyle;
4160
4161 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4162 offset += yet_to_draw;
4163 yet_to_draw = 0;
4164 last_width_in_cell = width_in_cell;
4165 }
4166
4167 yet_to_draw++;
4168 }
4169
4170 if (yet_to_draw)
4171 {
4172#ifdef MAC_ATSUI_DEBUG
4173 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4174 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4175#endif
4176 /* finish the rest style */
4177 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4178 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4179 }
4180
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004181 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004182 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004183 kATSUFromTextBeginning, kATSUToTextEnd,
4184 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004185 ATSUDisposeTextLayout(textLayout);
4186 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004187 else
4188#endif
4189 {
4190 ATSUTextLayout textLayout;
4191
4192 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4193 kATSUFromTextBeginning, kATSUToTextEnd,
4194 utf16_len,
4195 (gFontStyle ? 1 : 0), &utf16_len,
4196 (gFontStyle ? &gFontStyle : NULL),
4197 &textLayout) == noErr)
4198 {
4199 ATSUSetTransientFontMatching(textLayout, TRUE);
4200
4201 ATSUDrawText(textLayout,
4202 kATSUFromTextBeginning, kATSUToTextEnd,
4203 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4204
4205 ATSUDisposeTextLayout(textLayout);
4206 }
4207 }
4208
4209 /* drawing is done, now reset bold to normal */
4210 if (gFontStyle && flags & DRAW_BOLD)
4211 {
4212 Boolean attValue = false;
4213
4214 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4215 ByteCount attribSizes[] = { sizeof(Boolean) };
4216 ATSUAttributeValuePtr attribValues[] = { &attValue };
4217
4218 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4219 attribValues);
4220 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 }
4222
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004223 if (flags & DRAW_UNDERC)
4224 draw_undercurl(flags, row, col, len);
4225
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004227}
4228#endif
4229
4230 void
4231gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4232{
4233#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004234 if (p_macatsui == 0 && p_macatsui_last != 0)
4235 /* switch from macatsui to nomacatsui */
4236 gui_mac_dispose_atsui_style();
4237 else if (p_macatsui != 0 && p_macatsui_last == 0)
4238 /* switch from nomacatsui to macatsui */
4239 gui_mac_create_atsui_style();
4240
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004241 if (p_macatsui)
4242 draw_string_ATSUI(row, col, s, len, flags);
4243 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004244#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004245 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246}
4247
4248/*
4249 * Return OK if the key with the termcap name "name" is supported.
4250 */
4251 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004252gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253{
4254 int i;
4255
4256 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4257 if (name[0] == special_keys[i].vim_code0 &&
4258 name[1] == special_keys[i].vim_code1)
4259 return OK;
4260 return FAIL;
4261}
4262
4263 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004264gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004266 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267}
4268
4269 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004270gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271{
4272 /* Do a visual beep by reversing the foreground and background colors */
4273 Rect rc;
4274
4275 /*
4276 * Note: InvertRect() excludes right and bottom of rectangle.
4277 */
4278 rc.left = 0;
4279 rc.top = 0;
4280 rc.right = gui.num_cols * gui.char_width;
4281 rc.bottom = gui.num_rows * gui.char_height;
4282 InvertRect(&rc);
4283
4284 ui_delay((long)msec, TRUE); /* wait for some msec */
4285
4286 InvertRect(&rc);
4287}
4288
4289/*
4290 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4291 */
4292 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004293gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294{
4295 Rect rc;
4296
4297 /*
4298 * Note: InvertRect() excludes right and bottom of rectangle.
4299 */
4300 rc.left = FILL_X(c);
4301 rc.top = FILL_Y(r);
4302 rc.right = rc.left + nc * gui.char_width;
4303 rc.bottom = rc.top + nr * gui.char_height;
4304 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305}
4306
4307/*
4308 * Iconify the GUI window.
4309 */
4310 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004311gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312{
4313 /* TODO: find out what could replace iconify
4314 * -window shade?
4315 * -hide application?
4316 */
4317}
4318
4319#if defined(FEAT_EVAL) || defined(PROTO)
4320/*
4321 * Bring the Vim window to the foreground.
4322 */
4323 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004324gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325{
4326 /* TODO */
4327}
4328#endif
4329
4330/*
4331 * Draw a cursor without focus.
4332 */
4333 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004334gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335{
4336 Rect rc;
4337
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 /*
4339 * Note: FrameRect() excludes right and bottom of rectangle.
4340 */
4341 rc.left = FILL_X(gui.col);
4342 rc.top = FILL_Y(gui.row);
4343 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004344#ifdef FEAT_MBYTE
4345 if (mb_lefthalve(gui.row, gui.col))
4346 rc.right += gui.char_width;
4347#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 rc.bottom = rc.top + gui.char_height;
4349
4350 gui_mch_set_fg_color(color);
4351
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004352 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353}
4354
4355/*
4356 * Draw part of a cursor, only w pixels wide, and h pixels high.
4357 */
4358 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004359gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360{
4361 Rect rc;
4362
4363#ifdef FEAT_RIGHTLEFT
4364 /* vertical line should be on the right of current point */
4365 if (CURSOR_BAR_RIGHT)
4366 rc.left = FILL_X(gui.col + 1) - w;
4367 else
4368#endif
4369 rc.left = FILL_X(gui.col);
4370 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4371 rc.right = rc.left + w;
4372 rc.bottom = rc.top + h;
4373
4374 gui_mch_set_fg_color(color);
4375
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004376 FrameRect(&rc);
4377// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378}
4379
4380
4381
4382/*
4383 * Catch up with any queued X events. This may put keyboard input into the
4384 * input buffer, call resize call-backs, trigger timers etc. If there is
4385 * nothing in the X event queue (& no timers pending), then we return
4386 * immediately.
4387 */
4388 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004389gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390{
4391 /* TODO: find what to do
4392 * maybe call gui_mch_wait_for_chars (0)
4393 * more like look at EventQueue then
4394 * call heart of gui_mch_wait_for_chars;
4395 *
4396 * if (eventther)
4397 * gui_mac_handle_event(&event);
4398 */
4399 EventRecord theEvent;
4400
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004401 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402 if (theEvent.what != nullEvent)
4403 gui_mch_wait_for_chars(0);
4404}
4405
4406/*
4407 * Simple wrapper to neglect more easily the time
4408 * spent inside WaitNextEvent while profiling.
4409 */
4410
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411 pascal
4412 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004413WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414{
4415 if (((long) sleep) < -1)
4416 sleep = 32767;
4417 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4418}
4419
4420/*
4421 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4422 * from the keyboard.
4423 * wtime == -1 Wait forever.
4424 * wtime == 0 This should never happen.
4425 * wtime > 0 Wait wtime milliseconds for a character.
4426 * Returns OK if a character was found to be available within the given time,
4427 * or FAIL otherwise.
4428 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004430gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431{
4432 EventMask mask = (everyEvent);
4433 EventRecord event;
4434 long entryTick;
4435 long currentTick;
4436 long sleeppyTick;
4437
4438 /* If we are providing life feedback with the scrollbar,
4439 * we don't want to try to wait for an event, or else
4440 * there won't be any life feedback.
4441 */
4442 if (dragged_sb != NULL)
4443 return FAIL;
4444 /* TODO: Check if FAIL is the proper return code */
4445
4446 entryTick = TickCount();
4447
4448 allow_scrollbar = TRUE;
4449
4450 do
4451 {
4452/* if (dragRectControl == kCreateEmpty)
4453 {
4454 dragRgn = NULL;
4455 dragRectControl = kNothing;
4456 }
4457 else*/ if (dragRectControl == kCreateRect)
4458 {
4459 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004460 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461 dragRectControl = kNothing;
4462 }
4463 /*
4464 * Don't use gui_mch_update() because then we will spin-lock until a
4465 * char arrives, instead we use WaitNextEventWrp() to hang until an
4466 * event arrives. No need to check for input_buf_full because we are
4467 * returning as soon as it contains a single char.
4468 */
4469 /* TODO: reduce wtime accordinly??? */
4470 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004471 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 else
4473 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004474
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004475 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004477 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 if (input_available())
4479 {
4480 allow_scrollbar = FALSE;
4481 return OK;
4482 }
4483 }
4484 currentTick = TickCount();
4485 }
4486 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4487
4488 allow_scrollbar = FALSE;
4489 return FAIL;
4490}
4491
Bram Moolenaar071d4272004-06-13 20:20:40 +00004492/*
4493 * Output routines.
4494 */
4495
4496/* Flush any output to the screen */
4497 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004498gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499{
4500 /* TODO: Is anything needed here? */
4501}
4502
4503/*
4504 * Clear a rectangular region of the screen from text pos (row1, col1) to
4505 * (row2, col2) inclusive.
4506 */
4507 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004508gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509{
4510 Rect rc;
4511
4512 /*
4513 * Clear one extra pixel at the far right, for when bold characters have
4514 * spilled over to the next column.
4515 */
4516 rc.left = FILL_X(col1);
4517 rc.top = FILL_Y(row1);
4518 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4519 rc.bottom = FILL_Y(row2 + 1);
4520
4521 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004522 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523}
4524
4525/*
4526 * Clear the whole text window.
4527 */
4528 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004529gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530{
4531 Rect rc;
4532
4533 rc.left = 0;
4534 rc.top = 0;
4535 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4536 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4537
4538 gui_mch_set_bg_color(gui.back_pixel);
4539 EraseRect(&rc);
4540/* gui_mch_set_fg_color(gui.norm_pixel);
4541 FrameRect(&rc);
4542*/
4543}
4544
4545/*
4546 * Delete the given number of lines from the given row, scrolling up any
4547 * text further down within the scroll region.
4548 */
4549 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004550gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551{
4552 Rect rc;
4553
4554 /* changed without checking! */
4555 rc.left = FILL_X(gui.scroll_region_left);
4556 rc.right = FILL_X(gui.scroll_region_right + 1);
4557 rc.top = FILL_Y(row);
4558 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4559
4560 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004561 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562
4563 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4564 gui.scroll_region_left,
4565 gui.scroll_region_bot, gui.scroll_region_right);
4566}
4567
4568/*
4569 * Insert the given number of lines before the given row, scrolling down any
4570 * following text within the scroll region.
4571 */
4572 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004573gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574{
4575 Rect rc;
4576
4577 rc.left = FILL_X(gui.scroll_region_left);
4578 rc.right = FILL_X(gui.scroll_region_right + 1);
4579 rc.top = FILL_Y(row);
4580 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4581
4582 gui_mch_set_bg_color(gui.back_pixel);
4583
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004584 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585
4586 /* Update gui.cursor_row if the cursor scrolled or copied over */
4587 if (gui.cursor_row >= gui.row
4588 && gui.cursor_col >= gui.scroll_region_left
4589 && gui.cursor_col <= gui.scroll_region_right)
4590 {
4591 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4592 gui.cursor_row += num_lines;
4593 else if (gui.cursor_row <= gui.scroll_region_bot)
4594 gui.cursor_is_valid = FALSE;
4595 }
4596
4597 gui_clear_block(row, gui.scroll_region_left,
4598 row + num_lines - 1, gui.scroll_region_right);
4599}
4600
4601 /*
4602 * TODO: add a vim format to the clipboard which remember
4603 * LINEWISE, CHARWISE, BLOCKWISE
4604 */
4605
4606 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004607clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608{
4609
4610 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004611 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 Size scrapSize;
4613 ScrapFlavorFlags scrapFlags;
4614 ScrapRef scrap = nil;
4615 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 int type;
4617 char *searchCR;
4618 char_u *tempclip;
4619
4620
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004621 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 if (error != noErr)
4623 return;
4624
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004625 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4626 if (error == noErr)
4627 {
4628 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4629 if (error == noErr && scrapSize > 1)
4630 flavor = 1;
4631 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004633 if (flavor == 0)
4634 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004635 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004636 if (error != noErr)
4637 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004639 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004640 if (error != noErr)
4641 return;
4642 }
4643
4644 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004646 /* In CARBON we don't need a Handle, a pointer is good */
4647 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004649 /* tempclip = lalloc(scrapSize+1, TRUE); */
4650 HLock(textOfClip);
4651 error = GetScrapFlavorData(scrap,
4652 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4653 &scrapSize, *textOfClip);
4654 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004656 if (flavor)
4657 type = **textOfClip;
4658 else
4659 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR;
4660
4661 tempclip = lalloc(scrapSize + 1, TRUE);
4662 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4663 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004665#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004666 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004667 /* Convert from utf-16 (clipboard) */
4668 size_t encLen = 0;
4669 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004670
4671 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004673 scrapSize = encLen;
4674 vim_free(tempclip);
4675 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004679
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004680 searchCR = (char *)tempclip;
4681 while (searchCR != NULL)
4682 {
4683 searchCR = strchr(searchCR, '\r');
4684 if (searchCR != NULL)
4685 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004687
4688 clip_yank_selection(type, tempclip, scrapSize, cbd);
4689
4690 vim_free(tempclip);
4691 HUnlock(textOfClip);
4692
4693 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694}
4695
4696 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004697clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004698{
4699 /*
4700 * TODO: Really nothing to do?
4701 */
4702}
4703
4704 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004705clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706{
4707 return OK;
4708}
4709
4710/*
4711 * Send the current selection to the clipboard.
4712 */
4713 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004714clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715{
4716 Handle textOfClip;
4717 long scrapSize;
4718 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720
4721 char_u *str = NULL;
4722
4723 if (!cbd->owned)
4724 return;
4725
4726 clip_get_selection(cbd);
4727
4728 /*
4729 * Once we set the clipboard, lose ownership. If another application sets
4730 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 cbd->owned = FALSE;
4733
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004734 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004736#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004737 size_t utf16_len = 0;
4738 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4739 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004741 scrapSize = utf16_len;
4742 vim_free(str);
4743 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 }
4745#endif
4746
4747 if (type >= 0)
4748 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004751 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752 HLock(textOfClip);
4753
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004754 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004755 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004756 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004757 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004758 scrapSize, *textOfClip + 1);
4759 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4760 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761 HUnlock(textOfClip);
4762 DisposeHandle(textOfClip);
4763 }
4764
4765 vim_free(str);
4766}
4767
4768 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004769gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770{
4771 Rect VimBound;
4772
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004773/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775
4776 if (gui.which_scrollbars[SBAR_LEFT])
4777 {
4778 VimBound.left = -gui.scrollbar_width + 1;
4779 }
4780 else
4781 {
4782 VimBound.left = 0;
4783 }
4784
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004787 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788}
4789
4790/*
4791 * Menu stuff.
4792 */
4793
4794 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004795gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796{
4797 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004798 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 */
4800}
4801
4802 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004803gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804{
4805 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004806 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807 */
4808}
4809
4810/*
4811 * Add a sub menu to the menu bar.
4812 */
4813 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004814gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815{
4816 /*
4817 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4818 * TODO: use menu->mnemonic and menu->actext
4819 * TODO: Try to reuse menu id
4820 * Carbon Help suggest to use only id between 1 and 235
4821 */
4822 static long next_avail_id = 128;
4823 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004824#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004825 CFStringRef name;
4826#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004828#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829 short index;
4830 vimmenu_T *parent = menu->parent;
4831 vimmenu_T *brother = menu->next;
4832
4833 /* Cannot add a menu if ... */
4834 if ((parent != NULL && parent->submenu_id == 0))
4835 return;
4836
4837 /* menu ID greater than 1024 are reserved for ??? */
4838 if (next_avail_id == 1024)
4839 return;
4840
4841 /* My brother could be the PopUp, find my real brother */
4842 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4843 brother = brother->next;
4844
4845 /* Find where to insert the menu (for MenuBar) */
4846 if ((parent == NULL) && (brother != NULL))
4847 menu_after_me = brother->submenu_id;
4848
4849 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4850 if (!menu_is_menubar(menu->name))
4851 menu_after_me = hierMenu;
4852
4853 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004854#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004855 name = menu_title_removing_mnemonic(menu);
4856#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004857 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004858#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004859 if (name == NULL)
4860 return;
4861
4862 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 {
4864 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004865 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4866 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 */
4868 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004869#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004870 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4871 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4872#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004873 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004874#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875 next_avail_id++;
4876 }
4877
4878 if (parent == NULL)
4879 {
4880 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4881
4882 /* TODO: Verify if we could only Insert Menu if really part of the
4883 * menubar The Inserted menu are scanned or the Command-key combos
4884 */
4885
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004886 /* Insert the menu */
4887 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004888#if 1
4889 /* Vim should normally update it. TODO: verify */
4890 DrawMenuBar();
4891#endif
4892 }
4893 else
4894 {
4895 /* Adding as a submenu */
4896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004897 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898
4899 /* Call InsertMenuItem followed by SetMenuItemText
4900 * to avoid special character recognition by InsertMenuItem
4901 */
4902 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004903#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004904 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4905#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004907#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4909 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4910 InsertMenu(menu->submenu_handle, hierMenu);
4911 }
4912
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004913#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004914 CFRelease(name);
4915#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004916 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004917#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918
4919#if 0
4920 /* Done by Vim later on */
4921 DrawMenuBar();
4922#endif
4923}
4924
4925/*
4926 * Add a menu item to a menu
4927 */
4928 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004929gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004931#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004932 CFStringRef name;
4933#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004935#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936 vimmenu_T *parent = menu->parent;
4937 int menu_inserted;
4938
4939 /* Cannot add item, if the menu have not been created */
4940 if (parent->submenu_id == 0)
4941 return;
4942
4943 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4944 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4945
4946 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004947#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004948 name = menu_title_removing_mnemonic(menu);
4949#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004950 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004951#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952
4953 /* Where are just a menu item, so no handle, no id */
4954 menu->submenu_id = 0;
4955 menu->submenu_handle = NULL;
4956
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 menu_inserted = 0;
4958 if (menu->actext)
4959 {
4960 /* If the accelerator text for the menu item looks like it describes
4961 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4962 * item's command equivalent.
4963 */
4964 int key = 0;
4965 int modifiers = 0;
4966 char_u *p_actext;
4967
4968 p_actext = menu->actext;
Bram Moolenaardc5e2182008-12-24 12:06:26 +00004969 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004970 if (*p_actext != 0)
4971 key = 0; /* error: trailing text */
4972 /* find_special_key() returns a keycode with as many of the
4973 * specified modifiers as appropriate already applied (e.g., for
4974 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4975 * as the only modifier). Since we want to display all of the
4976 * modifiers, we need to convert the keycode back to a printable
4977 * character plus modifiers.
4978 * TODO: Write an alternative find_special_key() that doesn't
4979 * apply modifiers.
4980 */
4981 if (key > 0 && key < 32)
4982 {
4983 /* Convert a control key to an uppercase letter. Note that
4984 * by this point it is no longer possible to distinguish
4985 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4986 */
4987 modifiers |= MOD_MASK_CTRL;
4988 key += '@';
4989 }
4990 /* If the keycode is an uppercase letter, set the Shift modifier.
4991 * If it is a lowercase letter, don't set the modifier, but convert
4992 * the letter to uppercase for display in the menu.
4993 */
4994 else if (key >= 'A' && key <= 'Z')
4995 modifiers |= MOD_MASK_SHIFT;
4996 else if (key >= 'a' && key <= 'z')
4997 key += 'A' - 'a';
4998 /* Note: keycodes below 0x22 are reserved by Apple. */
4999 if (key >= 0x22 && vim_isprintc_strict(key))
5000 {
5001 int valid = 1;
5002 char_u mac_mods = kMenuNoModifiers;
5003 /* Convert Vim modifier codes to Menu Manager equivalents. */
5004 if (modifiers & MOD_MASK_SHIFT)
5005 mac_mods |= kMenuShiftModifier;
5006 if (modifiers & MOD_MASK_CTRL)
5007 mac_mods |= kMenuControlModifier;
5008 if (!(modifiers & MOD_MASK_CMD))
5009 mac_mods |= kMenuNoCommandModifier;
5010 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5011 valid = 0; /* TODO: will Alt someday map to Option? */
5012 if (valid)
5013 {
5014 char_u item_txt[10];
5015 /* Insert the menu item after idx, with its command key. */
5016 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5017 item_txt[3] = key;
5018 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5019 /* Set the modifier keys. */
5020 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5021 menu_inserted = 1;
5022 }
5023 }
5024 }
5025 /* Call InsertMenuItem followed by SetMenuItemText
5026 * to avoid special character recognition by InsertMenuItem
5027 */
5028 if (!menu_inserted)
5029 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5030 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005031#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005032 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5033#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005035#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036
5037#if 0
5038 /* Called by Vim */
5039 DrawMenuBar();
5040#endif
5041
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005042#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005043 CFRelease(name);
5044#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005045 /* TODO: Can name be freed? */
5046 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005047#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048}
5049
5050 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005051gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052{
5053 /* no tearoff menus */
5054}
5055
5056/*
5057 * Destroy the machine specific menu widget.
5058 */
5059 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005060gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005061{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005062 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063
5064 if (index > 0)
5065 {
5066 if (menu->parent)
5067 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068 {
5069 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005070 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071
5072 /* Delete the Menu if it was a hierarchical Menu */
5073 if (menu->submenu_id != 0)
5074 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005075 DeleteMenu(menu->submenu_id);
5076 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005077 }
5078 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005079 }
5080#ifdef DEBUG_MAC_MENU
5081 else
5082 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005083 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 }
5085#endif
5086 }
5087 else
5088 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005090 DeleteMenu(menu->submenu_id);
5091 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092 }
5093 }
5094 /* Shouldn't this be already done by Vim. TODO: Check */
5095 DrawMenuBar();
5096}
5097
5098/*
5099 * Make a menu either grey or not grey.
5100 */
5101 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005102gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005103{
5104 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005105 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106/*
5107 index = menu->index;
5108*/
5109 if (grey)
5110 {
5111 if (menu->children)
5112 DisableMenuItem(menu->submenu_handle, index);
5113 if (menu->parent)
5114 if (menu->parent->submenu_handle)
5115 DisableMenuItem(menu->parent->submenu_handle, index);
5116 }
5117 else
5118 {
5119 if (menu->children)
5120 EnableMenuItem(menu->submenu_handle, index);
5121 if (menu->parent)
5122 if (menu->parent->submenu_handle)
5123 EnableMenuItem(menu->parent->submenu_handle, index);
5124 }
5125}
5126
5127/*
5128 * Make menu item hidden or not hidden
5129 */
5130 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005131gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132{
5133 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005134 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135}
5136
5137
5138/*
5139 * This is called after setting all the menus to grey/hidden or not.
5140 */
5141 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005142gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143{
5144 DrawMenuBar();
5145}
5146
5147
5148/*
5149 * Scrollbar stuff.
5150 */
5151
5152 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005153gui_mch_enable_scrollbar(
5154 scrollbar_T *sb,
5155 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005156{
5157 if (flag)
5158 ShowControl(sb->id);
5159 else
5160 HideControl(sb->id);
5161
5162#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005163 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005164#endif
5165}
5166
5167 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005168gui_mch_set_scrollbar_thumb(
5169 scrollbar_T *sb,
5170 long val,
5171 long size,
5172 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173{
5174 SetControl32BitMaximum (sb->id, max);
5175 SetControl32BitMinimum (sb->id, 0);
5176 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005177 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005178#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005179 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005180#endif
5181}
5182
5183 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005184gui_mch_set_scrollbar_pos(
5185 scrollbar_T *sb,
5186 int x,
5187 int y,
5188 int w,
5189 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005190{
5191 gui_mch_set_bg_color(gui.back_pixel);
5192/* if (gui.which_scrollbars[SBAR_LEFT])
5193 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005194 MoveControl(sb->id, x-16, y);
5195 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005196 }
5197 else
5198 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005199 MoveControl(sb->id, x, y);
5200 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 }*/
5202 if (sb == &gui.bottom_sbar)
5203 h += 1;
5204 else
5205 w += 1;
5206
5207 if (gui.which_scrollbars[SBAR_LEFT])
5208 x -= 15;
5209
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005210 MoveControl(sb->id, x, y);
5211 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005212#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005213 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214#endif
5215}
5216
5217 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005218gui_mch_create_scrollbar(
5219 scrollbar_T *sb,
5220 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221{
5222 Rect bounds;
5223
5224 bounds.top = -16;
5225 bounds.bottom = -10;
5226 bounds.right = -10;
5227 bounds.left = -16;
5228
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005229 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 &bounds,
5231 "\pScrollBar",
5232 TRUE,
5233 0, /* current*/
5234 0, /* top */
5235 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005236 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 (long) sb->ident);
5238#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005239 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240#endif
5241}
5242
5243 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005244gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245{
5246 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005247 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005248#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005249 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250#endif
5251}
5252
5253
5254/*
5255 * Cursor blink functions.
5256 *
5257 * This is a simple state machine:
5258 * BLINK_NONE not blinking at all
5259 * BLINK_OFF blinking, cursor is not shown
5260 * BLINK_ON blinking, cursor is shown
5261 */
5262 void
5263gui_mch_set_blinking(long wait, long on, long off)
5264{
5265 /* TODO: TODO: TODO: TODO: */
5266/* blink_waittime = wait;
5267 blink_ontime = on;
5268 blink_offtime = off;*/
5269}
5270
5271/*
5272 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5273 */
5274 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005275gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005276{
5277 gui_update_cursor(TRUE, FALSE);
5278 /* TODO: TODO: TODO: TODO: */
5279/* gui_w32_rm_blink_timer();
5280 if (blink_state == BLINK_OFF)
5281 gui_update_cursor(TRUE, FALSE);
5282 blink_state = BLINK_NONE;*/
5283}
5284
5285/*
5286 * Start the cursor blinking. If it was already blinking, this restarts the
5287 * waiting time and shows the cursor.
5288 */
5289 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005290gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291{
5292 gui_update_cursor(TRUE, FALSE);
5293 /* TODO: TODO: TODO: TODO: */
5294/* gui_w32_rm_blink_timer(); */
5295
5296 /* Only switch blinking on if none of the times is zero */
5297/* if (blink_waittime && blink_ontime && blink_offtime)
5298 {
5299 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5300 (TIMERPROC)_OnBlinkTimer);
5301 blink_state = BLINK_ON;
5302 gui_update_cursor(TRUE, FALSE);
5303 }*/
5304}
5305
5306/*
5307 * Return the RGB value of a pixel as long.
5308 */
5309 long_u
5310gui_mch_get_rgb(guicolor_T pixel)
5311{
5312 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5313}
5314
5315
5316
5317#ifdef FEAT_BROWSE
5318/*
5319 * Pop open a file browser and return the file selected, in allocated memory,
5320 * or NULL if Cancel is hit.
5321 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5322 * title - Title message for the file browser dialog.
5323 * dflt - Default name of file.
5324 * ext - Default extension to be added to files without extensions.
5325 * initdir - directory in which to open the browser (NULL = current dir)
5326 * filter - Filter for matched files to choose from.
5327 * Has a format like this:
5328 * "C Files (*.c)\0*.c\0"
5329 * "All Files\0*.*\0\0"
5330 * If these two strings were concatenated, then a choice of two file
5331 * filters will be selectable to the user. Then only matching files will
5332 * be shown in the browser. If NULL, the default allows all files.
5333 *
5334 * *NOTE* - the filter string must be terminated with TWO nulls.
5335 */
5336 char_u *
5337gui_mch_browse(
5338 int saving,
5339 char_u *title,
5340 char_u *dflt,
5341 char_u *ext,
5342 char_u *initdir,
5343 char_u *filter)
5344{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345 /* TODO: Add Ammon's safety checl (Dany) */
5346 NavReplyRecord reply;
5347 char_u *fname = NULL;
5348 char_u **fnames = NULL;
5349 long numFiles;
5350 NavDialogOptions navOptions;
5351 OSErr error;
5352
5353 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005354 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005355
5356
5357 /* TODO: If we get a :browse args, set the Multiple bit. */
5358 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5359 | kNavDontAutoTranslate
5360 | kNavDontAddTranslateItems
5361 /* | kNavAllowMultipleFiles */
5362 | kNavAllowStationery;
5363
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005364 (void) C2PascalString(title, &navOptions.message);
5365 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005366 /* Could set clientName?
5367 * windowTitle? (there's no title bar?)
5368 */
5369
5370 if (saving)
5371 {
5372 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005373 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005374 if (!reply.validRecord)
5375 return NULL;
5376 }
5377 else
5378 {
5379 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5380 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5381 if (!reply.validRecord)
5382 return NULL;
5383 }
5384
5385 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5386
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005387 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005388
5389 if (fnames)
5390 {
5391 fname = fnames[0];
5392 vim_free(fnames);
5393 }
5394
5395 /* TODO: Shorten the file name if possible */
5396 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397}
5398#endif /* FEAT_BROWSE */
5399
5400#ifdef FEAT_GUI_DIALOG
5401/*
5402 * Stuff for dialogues
5403 */
5404
5405/*
5406 * Create a dialogue dynamically from the parameter strings.
5407 * type = type of dialogue (question, alert, etc.)
5408 * title = dialogue title. may be NULL for default title.
5409 * message = text to display. Dialogue sizes to accommodate it.
5410 * buttons = '\n' separated list of button captions, default first.
5411 * dfltbutton = number of default button.
5412 *
5413 * This routine returns 1 if the first button is pressed,
5414 * 2 for the second, etc.
5415 *
5416 * 0 indicates Esc was pressed.
5417 * -1 for unexpected error
5418 *
5419 * If stubbing out this fn, return 1.
5420 */
5421
5422typedef struct
5423{
5424 short idx;
5425 short width; /* Size of the text in pixel */
5426 Rect box;
5427} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5428
5429#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5430
5431 static void
5432macMoveDialogItem(
5433 DialogRef theDialog,
5434 short itemNumber,
5435 short X,
5436 short Y,
5437 Rect *inBox)
5438{
5439#if 0 /* USE_CARBONIZED */
5440 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005441 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005442 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005443 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005444#else
5445 short itemType;
5446 Handle itemHandle;
5447 Rect localBox;
5448 Rect *itemBox = &localBox;
5449
5450 if (inBox != nil)
5451 itemBox = inBox;
5452
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005453 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5454 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5455 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456 /* To move a control (like a button) we need to call both
5457 * MoveControl and SetDialogItem. FAQ 6-18 */
5458 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005459 MoveControl((ControlRef) itemHandle, X, Y);
5460 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005461#endif
5462}
5463
5464 static void
5465macSizeDialogItem(
5466 DialogRef theDialog,
5467 short itemNumber,
5468 short width,
5469 short height)
5470{
5471 short itemType;
5472 Handle itemHandle;
5473 Rect itemBox;
5474
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005475 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005476
5477 /* When width or height is zero do not change it */
5478 if (width == 0)
5479 width = itemBox.right - itemBox.left;
5480 if (height == 0)
5481 height = itemBox.bottom - itemBox.top;
5482
5483#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005484 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005485#else
5486 /* Resize the bounding box */
5487 itemBox.right = itemBox.left + width;
5488 itemBox.bottom = itemBox.top + height;
5489
5490 /* To resize a control (like a button) we need to call both
5491 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5492 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005493 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005494
5495 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005496 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005497#endif
5498}
5499
5500 static void
5501macSetDialogItemText(
5502 DialogRef theDialog,
5503 short itemNumber,
5504 Str255 itemName)
5505{
5506 short itemType;
5507 Handle itemHandle;
5508 Rect itemBox;
5509
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005510 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511
5512 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005513 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005514 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005515 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005516}
5517
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005518
5519/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5520 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5521 * setting gDialogHotKeys to NULL disables any hotkey handling.
5522 */
5523 static pascal Boolean
5524DialogHotkeyFilterProc (
5525 DialogRef theDialog,
5526 EventRecord *event,
5527 DialogItemIndex *itemHit)
5528{
5529 char_u keyHit;
5530
5531 if (event->what == keyDown || event->what == autoKey)
5532 {
5533 keyHit = (event->message & charCodeMask);
5534
5535 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5536 {
5537#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5538 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5539#endif
5540 *itemHit = gDialogHotKeys[keyHit];
5541
5542 /* When handing off to StdFilterProc, pretend that the user
5543 * clicked the control manually. Note that this is also supposed
5544 * to cause the button to hilite briefly (to give some user
5545 * feedback), but this seems not to actually work (or it's too
5546 * fast to be seen).
5547 */
5548 event->what = kEventControlSimulateHit;
5549
5550 return true; /* we took care of it */
5551 }
5552
5553 /* Defer to the OS's standard behavior for this event.
5554 * This ensures that Enter will still activate the default button. */
5555 return StdFilterProc(theDialog, event, itemHit);
5556 }
5557 return false; /* Let ModalDialog deal with it */
5558}
5559
5560
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005561/* TODO: There have been some crashes with dialogs, check your inbox
5562 * (Jussi)
5563 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005564 int
5565gui_mch_dialog(
5566 int type,
5567 char_u *title,
5568 char_u *message,
5569 char_u *buttons,
5570 int dfltbutton,
5571 char_u *textfield)
5572{
5573 Handle buttonDITL;
5574 Handle iconDITL;
5575 Handle inputDITL;
5576 Handle messageDITL;
5577 Handle itemHandle;
5578 Handle iconHandle;
5579 DialogPtr theDialog;
5580 char_u len;
5581 char_u PascalTitle[256]; /* place holder for the title */
5582 char_u name[256];
5583 GrafPtr oldPort;
5584 short itemHit;
5585 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005586 short hotKeys[256]; /* map of hotkey -> control ID */
5587 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588 Rect box;
5589 short button;
5590 short lastButton;
5591 short itemType;
5592 short useIcon;
5593 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005594 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005595 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596 short widestButton = 0;
5597 short dfltButtonEdge = 20; /* gut feeling */
5598 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5599 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5600 short maximumWidth = 400; /* gut feeling */
5601 short maxButtonWidth = 175; /* gut feeling */
5602
5603 short vertical;
5604 short dialogHeight;
5605 short messageLines = 3;
5606 FontInfo textFontInfo;
5607
5608 vgmDlgItm iconItm;
5609 vgmDlgItm messageItm;
5610 vgmDlgItm inputItm;
5611 vgmDlgItm buttonItm;
5612
5613 WindowRef theWindow;
5614
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005615 ModalFilterUPP dialogUPP;
5616
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 /* Check 'v' flag in 'guioptions': vertical button placement. */
5618 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5619
5620 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005621 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005622
5623 /* Get the WindowRef */
5624 theWindow = GetDialogWindow(theDialog);
5625
5626 /* Hide the window.
5627 * 1. to avoid seeing slow drawing
5628 * 2. to prevent a problem seen while moving dialog item
5629 * within a visible window. (non-Carbon MacOS 9)
5630 * Could be avoided by changing the resource.
5631 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005632 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633
5634 /* Change the graphical port to the dialog,
5635 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005636 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005637 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638
5639 /* Get the info about the default text,
5640 * used to calculate the height of the message
5641 * and of the text field */
5642 GetFontInfo(&textFontInfo);
5643
5644 /* Set the dialog title */
5645 if (title != NULL)
5646 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005647 (void) C2PascalString(title, &PascalTitle);
5648 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005649 }
5650
5651 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005652 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 buttonChar = buttons;
5654 button = 0;
5655
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005656 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005657 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005658
Bram Moolenaar071d4272004-06-13 20:20:40 +00005659 for (;*buttonChar != 0;)
5660 {
5661 /* Get the name of the button */
5662 button++;
5663 len = 0;
5664 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5665 {
5666 if (*buttonChar != DLG_HOTKEY_CHAR)
5667 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005668 else
5669 {
5670 aHotKey = (char_u)*(buttonChar+1);
5671 if (aHotKey >= 'A' && aHotKey <= 'Z')
5672 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5673 hotKeys[aHotKey] = button;
5674#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5675 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5676#endif
5677 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005678 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005679
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 if (*buttonChar != 0)
5681 buttonChar++;
5682 name[0] = len;
5683
5684 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005685 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005686
5687 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005688 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689
5690 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005691 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 /* Limite the size of any button to an acceptable value. */
5693 /* TODO: Should be based on the message width */
5694 if (width > maxButtonWidth)
5695 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005696 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697
5698 totalButtonWidth += width;
5699
5700 if (width > widestButton)
5701 widestButton = width;
5702 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005703 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704 lastButton = button;
5705
5706 /* Add the icon to the Dialog Box. */
5707 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005708 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709 switch (type)
5710 {
5711 case VIM_GENERIC: useIcon = kNoteIcon;
5712 case VIM_ERROR: useIcon = kStopIcon;
5713 case VIM_WARNING: useIcon = kCautionIcon;
5714 case VIM_INFO: useIcon = kNoteIcon;
5715 case VIM_QUESTION: useIcon = kNoteIcon;
5716 default: useIcon = kStopIcon;
5717 };
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005718 AppendDITL(theDialog, iconDITL, overlayDITL);
5719 ReleaseResource(iconDITL);
5720 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005722 iconHandle = GetIcon(useIcon);
5723 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724
5725 /* Add the message to the Dialog box. */
5726 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005727 messageDITL = GetResource('DITL', 132);
5728 AppendDITL(theDialog, messageDITL, overlayDITL);
5729 ReleaseResource(messageDITL);
5730 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5731 (void) C2PascalString(message, &name);
5732 SetDialogItemText(itemHandle, name);
5733 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005734
5735 /* Add the input box if needed */
5736 if (textfield != NULL)
5737 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005738 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005740 inputDITL = GetResource('DITL', 132);
5741 AppendDITL(theDialog, inputDITL, overlayDITL);
5742 ReleaseResource(inputDITL);
5743 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5744/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5745 (void) C2PascalString(textfield, &name);
5746 SetDialogItemText(itemHandle, name);
5747 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005748
5749 /* Hotkeys don't make sense if there's a text field */
5750 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005752 else
5753 /* Install hotkey table */
5754 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005755
5756 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005757 SetDialogDefaultItem(theDialog, dfltbutton);
5758 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759
5760 /* Reposition element */
5761
5762 /* Check if we need to force vertical */
5763 if (totalButtonWidth > maximumWidth)
5764 vertical = TRUE;
5765
5766 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005767 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 iconItm.box.right = box.right;
5769 iconItm.box.bottom = box.bottom;
5770
5771 /* Place Message */
5772 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005773 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5774 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775
5776 /* Place Input */
5777 if (textfield != NULL)
5778 {
5779 inputItm.box.left = messageItm.box.left;
5780 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005781 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5782 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783 /* Convert the static text into a text edit.
5784 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005785 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5786 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5788 }
5789
5790 /* Place Button */
5791 if (textfield != NULL)
5792 {
5793 buttonItm.box.left = inputItm.box.left;
5794 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5795 }
5796 else
5797 {
5798 buttonItm.box.left = messageItm.box.left;
5799 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5800 }
5801
5802 for (button=1; button <= lastButton; button++)
5803 {
5804
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005805 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005806 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005807 if (vertical)
5808 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005809 macSizeDialogItem(theDialog, button, widestButton, 0);
5810 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005811 }
5812 /* Calculate position of next button */
5813 if (vertical)
5814 buttonItm.box.top = box.bottom + dfltElementSpacing;
5815 else
5816 buttonItm.box.left = box.right + dfltElementSpacing;
5817 }
5818
5819 /* Resize the dialog box */
5820 dialogHeight = box.bottom + dfltElementSpacing;
5821 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5822
Bram Moolenaar071d4272004-06-13 20:20:40 +00005823 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005824 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826
5827 /* Display it */
5828 ShowWindow(theWindow);
5829/* BringToFront(theWindow); */
5830 SelectWindow(theWindow);
5831
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005832/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005834 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005835 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005836#endif
5837
Bram Moolenaard68071d2006-05-02 22:08:30 +00005838#ifdef USE_CARBONKEYHANDLER
5839 /* Avoid that we use key events for the main window. */
5840 dialog_busy = TRUE;
5841#endif
5842
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005843 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5844 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5845
Bram Moolenaar071d4272004-06-13 20:20:40 +00005846 /* Hang until one of the button is hit */
5847 do
5848 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005849 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005850 } while ((itemHit < 1) || (itemHit > lastButton));
5851
Bram Moolenaard68071d2006-05-02 22:08:30 +00005852#ifdef USE_CARBONKEYHANDLER
5853 dialog_busy = FALSE;
5854#endif
5855
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 /* Copy back the text entered by the user into the param */
5857 if (textfield != NULL)
5858 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005859 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5860 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861#if IOSIZE < 256
5862 /* Truncate the name to IOSIZE if needed */
5863 if (name[0] > IOSIZE)
5864 name[0] = IOSIZE - 1;
5865#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005866 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005867 }
5868
5869 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005870 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005871
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005872 /* Free the modal filterProc */
5873 DisposeRoutineDescriptor(dialogUPP);
5874
Bram Moolenaar071d4272004-06-13 20:20:40 +00005875 /* Get ride of th edialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005876 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877
5878 return itemHit;
5879/*
5880 * Usefull thing which could be used
5881 * SetDialogTimeout(): Auto click a button after timeout
5882 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5883 * MoveDialogItem(): Probably better than SetDialogItem
5884 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005885 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886 */
5887}
5888#endif /* FEAT_DIALOG_GUI */
5889
5890/*
5891 * Display the saved error message(s).
5892 */
5893#ifdef USE_MCH_ERRMSG
5894 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005895display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005896{
5897 char *p;
5898 char_u pError[256];
5899
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005900 if (error_ga.ga_data == NULL)
5901 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005903 /* avoid putting up a message box with blanks only */
5904 for (p = (char *)error_ga.ga_data; *p; ++p)
5905 if (!isspace(*p))
5906 {
5907 if (STRLEN(p) > 255)
5908 pError[0] = 255;
5909 else
5910 pError[0] = STRLEN(p);
5911
5912 STRNCPY(&pError[1], p, pError[0]);
5913 ParamText(pError, nil, nil, nil);
5914 Alert(128, nil);
5915 break;
5916 /* TODO: handled message longer than 256 chars
5917 * use auto-sizeable alert
5918 * or dialog with scrollbars (TextEdit zone)
5919 */
5920 }
5921 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922}
5923#endif
5924
5925/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005926 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005927 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005928 void
5929gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930{
5931 Point where;
5932
5933 GetMouse(&where);
5934
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005935 *x = where.h;
5936 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005937}
5938
5939 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005940gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941{
5942 /* TODO */
5943#if 0
5944 /* From FAQ 3-11 */
5945
5946 CursorDevicePtr myMouse;
5947 Point where;
5948
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005949 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5950 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951 {
5952 /* New way */
5953
5954 /*
5955 * Get first devoice with one button.
5956 * This will probably be the standad mouse
5957 * startat head of cursor dev list
5958 *
5959 */
5960
5961 myMouse = nil;
5962
5963 do
5964 {
5965 /* Get the next cursor device */
5966 CursorDeviceNextDevice(&myMouse);
5967 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005968 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005970 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005971 }
5972 else
5973 {
5974 /* Old way */
5975 where.h = x;
5976 where.v = y;
5977
5978 *(Point *)RawMouse = where;
5979 *(Point *)MTemp = where;
5980 *(Ptr) CrsrNew = 0xFFFF;
5981 }
5982#endif
5983}
5984
5985 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005986gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005988/*
5989 * Clone PopUp to use menu
5990 * Create a object descriptor for the current selection
5991 * Call the procedure
5992 */
5993
5994 MenuHandle CntxMenu;
5995 Point where;
5996 OSStatus status;
5997 UInt32 CntxType;
5998 SInt16 CntxMenuID;
5999 UInt16 CntxMenuItem;
6000 Str255 HelpName = "";
6001 GrafPtr savePort;
6002
6003 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006004 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006006 GetMouse(&where);
6007 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008 CntxMenu = menu->submenu_handle;
6009
6010 /* TODO: Get the text selection from Vim */
6011
6012 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006013 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006014 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015
6016 if (status == noErr)
6017 {
6018 if (CntxType == kCMMenuItemSelected)
6019 {
6020 /* Handle the menu CntxMenuID, CntxMenuItem */
6021 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006022 /* But what about the current menu, is the menu changed by
6023 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006024 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025 }
6026 else if (CntxMenuID == kCMShowHelpSelected)
6027 {
6028 /* Should come up with the help */
6029 }
6030 }
6031
6032 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006033 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006034}
6035
6036#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6037/* TODO: Is it need for MACOS_X? (Dany) */
6038 void
6039mch_post_buffer_write(buf_T *buf)
6040{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006041 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6042 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006043}
6044#endif
6045
6046#ifdef FEAT_TITLE
6047/*
6048 * Set the window title and icon.
6049 * (The icon is not taken care of).
6050 */
6051 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006052gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006053{
6054 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6055 * that 256. Even better get it to fit nicely in the titlebar.
6056 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006057#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006058 CFStringRef windowTitle;
6059 size_t windowTitleLen;
6060#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006062#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063
6064 if (title == NULL) /* nothing to do */
6065 return;
6066
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006067#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006068 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00006069 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006070
6071 if (windowTitle)
6072 {
6073 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6074 CFRelease(windowTitle);
6075 }
6076#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077 pascalTitle = C2Pascal_save(title);
6078 if (pascalTitle != NULL)
6079 {
6080 SetWTitle(gui.VimWindow, pascalTitle);
6081 vim_free(pascalTitle);
6082 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006083#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084}
6085#endif
6086
6087/*
6088 * Transfered from os_mac.c for MacOS X using os_unix.c prep work
6089 */
6090
6091 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006092C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006093{
6094 char_u *PascalPtr = (char_u *) PascalString;
6095 int len;
6096 int i;
6097
6098 PascalPtr[0] = 0;
6099 if (CString == NULL)
6100 return 0;
6101
6102 len = STRLEN(CString);
6103 if (len > 255)
6104 len = 255;
6105
6106 for (i = 0; i < len; i++)
6107 PascalPtr[i+1] = CString[i];
6108
6109 PascalPtr[0] = len;
6110
6111 return 0;
6112}
6113
6114 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006115GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006116{
6117 /* From FAQ 8-12 */
6118 Str255 filePascal;
6119 CInfoPBRec myCPB;
6120 OSErr err;
6121
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006122 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123
6124 myCPB.dirInfo.ioNamePtr = filePascal;
6125 myCPB.dirInfo.ioVRefNum = 0;
6126 myCPB.dirInfo.ioFDirIndex = 0;
6127 myCPB.dirInfo.ioDrDirID = 0;
6128
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006129 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130
6131 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006132 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133
6134 /* TODO: Use an error code mechanism */
6135 return 0;
6136}
6137
6138/*
6139 * Convert a FSSpec to a fuill path
6140 */
6141
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006142char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006143{
6144 /*
6145 * TODO: Add protection for 256 char max.
6146 */
6147
6148 CInfoPBRec theCPB;
6149 char_u fname[256];
6150 char_u *filenamePtr = fname;
6151 OSErr error;
6152 int folder = 1;
6153#ifdef USE_UNIXFILENAME
6154 SInt16 dfltVol_vRefNum;
6155 SInt32 dfltVol_dirID;
6156 FSRef refFile;
6157 OSStatus status;
6158 UInt32 pathSize = 256;
6159 char_u pathname[256];
6160 char_u *path = pathname;
6161#else
6162 Str255 directoryName;
6163 char_u temporary[255];
6164 char_u *temporaryPtr = temporary;
6165#endif
6166
6167#ifdef USE_UNIXFILENAME
6168 /* Get the default volume */
6169 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006170 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171
6172 if (error)
6173 return NULL;
6174#endif
6175
6176 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006177 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006178
6179 /* Get the info about the file specified in FSSpec */
6180 theCPB.dirInfo.ioFDirIndex = 0;
6181 theCPB.dirInfo.ioNamePtr = file.name;
6182 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006183 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184 theCPB.dirInfo.ioDrDirID = file.parID;
6185
6186 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6187 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006188 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006189
6190 /* If we are called for a new file we expect fnfErr */
6191 if ((error) && (error != fnfErr))
6192 return NULL;
6193
6194 /* Check if it's a file or folder */
6195 /* default to file if file don't exist */
6196 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6197 folder = 0; /* It's not a folder */
6198 else
6199 folder = 1;
6200
6201#ifdef USE_UNIXFILENAME
6202 /*
6203 * The function used here are available in Carbon, but
6204 * do nothing une MacOS 8 and 9
6205 */
6206 if (error == fnfErr)
6207 {
6208 /* If the file to be saved does not already exist, it isn't possible
6209 to convert its FSSpec into an FSRef. But we can construct an
6210 FSSpec for the file's parent folder (since we have its volume and
6211 directory IDs), and since that folder does exist, we can convert
6212 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6213 and, finally, append the filename. */
6214 FSSpec dirSpec;
6215 FSRef dirRef;
6216 Str255 emptyFilename = "\p";
6217 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6218 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6219 if (error)
6220 return NULL;
6221
6222 error = FSpMakeFSRef(&dirSpec, &dirRef);
6223 if (error)
6224 return NULL;
6225
6226 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6227 if (status)
6228 return NULL;
6229
6230 STRCAT(path, "/");
6231 STRCAT(path, filenamePtr);
6232 }
6233 else
6234 {
6235 /* If the file to be saved already exists, we can get its full path
6236 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006237 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238 if (error)
6239 return NULL;
6240
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006241 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 if (status)
6243 return NULL;
6244 }
6245
6246 /* Add a slash at the end if needed */
6247 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006248 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006250 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251#else
6252 /* TODO: Get rid of all USE_UNIXFILENAME below */
6253 /* Set ioNamePtr, it's the same area which is always reused. */
6254 theCPB.dirInfo.ioNamePtr = directoryName;
6255
6256 /* Trick for first entry, set ioDrParID to the first value
6257 * we want for ioDrDirID*/
6258 theCPB.dirInfo.ioDrParID = file.parID;
6259 theCPB.dirInfo.ioDrDirID = file.parID;
6260
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006261 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006262 do
6263 {
6264 theCPB.dirInfo.ioFDirIndex = -1;
6265 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6266 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006267 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6269
6270 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6271 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006272 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006273
6274 if (error)
6275 return NULL;
6276
6277 /* Put the new directoryName in front of the current fname */
6278 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006279 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006280 STRCAT(filenamePtr, ":");
6281 STRCAT(filenamePtr, temporaryPtr);
6282 }
6283#if 1 /* def USE_UNIXFILENAME */
6284 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6285 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6286#else
6287 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6288#endif
6289
6290 /* Get the information about the volume on which the file reside */
6291 theCPB.dirInfo.ioFDirIndex = -1;
6292 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6293 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006294 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006295 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6296
6297 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6298 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006299 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300
6301 if (error)
6302 return NULL;
6303
6304 /* For MacOS Classic always add the volume name */
6305 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006306 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006307#ifdef USE_UNIXFILENAME
6308 if (file.vRefNum != dfltVol_vRefNum)
6309#endif
6310 {
6311 /* Add the volume name */
6312 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006313 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006314 STRCAT(filenamePtr, ":");
6315 STRCAT(filenamePtr, temporaryPtr);
6316
6317#ifdef USE_UNIXFILENAME
6318 STRCPY(temporaryPtr, filenamePtr);
6319 filenamePtr[0] = 0; /* NULL terminate the string */
6320 STRCAT(filenamePtr, "Volumes:");
6321 STRCAT(filenamePtr, temporaryPtr);
6322#endif
6323 }
6324
6325 /* Append final path separator if it's a folder */
6326 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006327 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328
6329 /* As we use Unix File Name for MacOS X convert it */
6330#ifdef USE_UNIXFILENAME
6331 /* Need to insert leading / */
6332 /* TODO: get the above code to use directly the / */
6333 STRCPY(&temporaryPtr[1], filenamePtr);
6334 temporaryPtr[0] = '/';
6335 STRCPY(filenamePtr, temporaryPtr);
6336 {
6337 char *p;
6338 for (p = fname; *p; p++)
6339 if (*p == ':')
6340 *p = '/';
6341 }
6342#endif
6343
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006344 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006345#endif
6346}
6347
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006348#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006349/*
6350 * Input Method Control functions.
6351 */
6352
6353/*
6354 * Notify cursor position to IM.
6355 */
6356 void
6357im_set_position(int row, int col)
6358{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006359#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006360 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006361 im_start_row = row;
6362 im_start_col = col;
6363#endif
6364}
6365
6366static ScriptLanguageRecord gTSLWindow;
6367static ScriptLanguageRecord gTSLInsert;
6368static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6369
6370static Component gTSCWindow;
6371static Component gTSCInsert;
6372static Component gTSCDefault;
6373
6374static int im_initialized = 0;
6375
6376 static void
6377im_on_window_switch(int active)
6378{
6379 ScriptLanguageRecord *slptr = NULL;
6380 OSStatus err;
6381
6382 if (! gui.in_use)
6383 return;
6384
6385 if (im_initialized == 0)
6386 {
6387 im_initialized = 1;
6388
6389 /* save default TSM component (should be U.S.) to default */
6390 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6391 kKeyboardInputMethodClass);
6392 }
6393
6394 if (active == TRUE)
6395 {
6396 im_is_active = TRUE;
6397 ActivateTSMDocument(gTSMDocument);
6398 slptr = &gTSLWindow;
6399
6400 if (slptr)
6401 {
6402 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6403 kKeyboardInputMethodClass);
6404 if (err == noErr)
6405 err = SetTextServiceLanguage(slptr);
6406
6407 if (err == noErr)
6408 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6409 }
6410 }
6411 else
6412 {
6413 err = GetTextServiceLanguage(&gTSLWindow);
6414 if (err == noErr)
6415 slptr = &gTSLWindow;
6416
6417 if (slptr)
6418 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6419 kKeyboardInputMethodClass);
6420
6421 im_is_active = FALSE;
6422 DeactivateTSMDocument(gTSMDocument);
6423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424}
6425
6426/*
6427 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6428 */
6429 void
6430im_set_active(int active)
6431{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006432 ScriptLanguageRecord *slptr = NULL;
6433 OSStatus err;
6434
6435 if (! gui.in_use)
6436 return;
6437
6438 if (im_initialized == 0)
6439 {
6440 im_initialized = 1;
6441
6442 /* save default TSM component (should be U.S.) to default */
6443 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6444 kKeyboardInputMethodClass);
6445 }
6446
6447 if (active == TRUE)
6448 {
6449 im_is_active = TRUE;
6450 ActivateTSMDocument(gTSMDocument);
6451 slptr = &gTSLInsert;
6452
6453 if (slptr)
6454 {
6455 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6456 kKeyboardInputMethodClass);
6457 if (err == noErr)
6458 err = SetTextServiceLanguage(slptr);
6459
6460 if (err == noErr)
6461 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6462 }
6463 }
6464 else
6465 {
6466 err = GetTextServiceLanguage(&gTSLInsert);
6467 if (err == noErr)
6468 slptr = &gTSLInsert;
6469
6470 if (slptr)
6471 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6472 kKeyboardInputMethodClass);
6473
6474 /* restore to default when switch to normal mode, so than we could
6475 * enter commands easier */
6476 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6477 kKeyboardInputMethodClass);
6478 SetTextServiceLanguage(&gTSLDefault);
6479
6480 im_is_active = FALSE;
6481 DeactivateTSMDocument(gTSMDocument);
6482 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006483}
6484
6485/*
6486 * Get IM status. When IM is on, return not 0. Else return 0.
6487 */
6488 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006489im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006490{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006491 if (! gui.in_use)
6492 return 0;
6493
6494 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006495}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006496
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006498
6499
6500
6501
6502#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6503// drawer implementation
6504static MenuRef contextMenu = NULL;
6505enum
6506{
6507 kTabContextMenuId = 42,
6508};
6509
6510// the caller has to CFRelease() the returned string
6511 static CFStringRef
6512getTabLabel(tabpage_T *page)
6513{
6514 get_tabline_label(page, FALSE);
6515#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006516 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006517#else
6518 // TODO: check internal encoding?
6519 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6520 kCFStringEncodingMacRoman);
6521#endif
6522}
6523
6524
6525#define DRAWER_SIZE 150
6526#define DRAWER_INSET 16
6527
6528static ControlRef dataBrowser = NULL;
6529
6530// when the tabline is hidden, vim doesn't call update_tabline(). When
6531// the tabline is shown again, show_tabline() is called before upate_tabline(),
6532// and because of this, the tab labels and vims internal tabs are out of sync
6533// for a very short time. to prevent inconsistent state, we store the labels
6534// of the tabs, not pointers to the tabs (which are invalid for a short time).
6535static CFStringRef *tabLabels = NULL;
6536static int tabLabelsSize = 0;
6537
6538enum
6539{
6540 kTabsColumn = 'Tabs'
6541};
6542
6543 static int
6544getTabCount(void)
6545{
6546 tabpage_T *tp;
6547 int numTabs = 0;
6548
6549 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006550 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006551 return numTabs;
6552}
6553
6554// data browser item display callback
6555 static OSStatus
6556dbItemDataCallback(ControlRef browser,
6557 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006558 DataBrowserPropertyID property /* column id */,
6559 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006560 Boolean changeValue)
6561{
6562 OSStatus status = noErr;
6563
6564 // assert(property == kTabsColumn); // why is this violated??
6565
6566 // changeValue is true if we have a modifieable list and data was changed.
6567 // In our case, it's always false.
6568 // (that is: if (changeValue) updateInternalData(); else return
6569 // internalData();
6570 if (!changeValue)
6571 {
6572 CFStringRef str;
6573
6574 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6575 str = tabLabels[itemID - 1];
6576 status = SetDataBrowserItemDataText(itemData, str);
6577 }
6578 else
6579 status = errDataBrowserPropertyNotSupported;
6580
6581 return status;
6582}
6583
6584// data browser action callback
6585 static void
6586dbItemNotificationCallback(ControlRef browser,
6587 DataBrowserItemID item,
6588 DataBrowserItemNotification message)
6589{
6590 switch (message)
6591 {
6592 case kDataBrowserItemSelected:
6593 send_tabline_event(item);
6594 break;
6595 }
6596}
6597
6598// callbacks needed for contextual menu:
6599 static void
6600dbGetContextualMenuCallback(ControlRef browser,
6601 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006602 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006603 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006604 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006605{
6606 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6607 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6608 *helpItemString = NULL;
6609
6610 *menu = contextMenu;
6611}
6612
6613 static void
6614dbSelectContextualMenuCallback(ControlRef browser,
6615 MenuRef menu,
6616 UInt32 selectionType,
6617 SInt16 menuID,
6618 MenuItemIndex menuItem)
6619{
6620 if (selectionType == kCMMenuItemSelected)
6621 {
6622 MenuCommand command;
6623 GetMenuItemCommandID(menu, menuItem, &command);
6624
6625 // get tab that was selected when the context menu appeared
6626 // (there is always one tab selected). TODO: check if the context menu
6627 // isn't opened on an item but on empty space (has to be possible some
6628 // way, the finder does it too ;-) )
6629 Handle items = NewHandle(0);
6630 if (items != NULL)
6631 {
6632 int numItems;
6633
6634 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6635 kDataBrowserItemIsSelected, items);
6636 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6637 if (numItems > 0)
6638 {
6639 int idx;
6640 DataBrowserItemID *itemsPtr;
6641
6642 HLock(items);
6643 itemsPtr = (DataBrowserItemID *)*items;
6644 idx = itemsPtr[0];
6645 HUnlock(items);
6646 send_tabline_menu_event(idx, command);
6647 }
6648 DisposeHandle(items);
6649 }
6650 }
6651}
6652
6653// focus callback of the data browser to always leave focus in vim
6654 static OSStatus
6655dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6656{
6657 assert(GetEventClass(event) == kEventClassControl
6658 && GetEventKind(event) == kEventControlSetFocusPart);
6659
6660 return paramErr;
6661}
6662
6663
6664// drawer callback to resize data browser to drawer size
6665 static OSStatus
6666drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6667{
6668 switch (GetEventKind(event))
6669 {
6670 case kEventWindowBoundsChanged: // move or resize
6671 {
6672 UInt32 attribs;
6673 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6674 NULL, sizeof(attribs), NULL, &attribs);
6675 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6676 {
6677 Rect r;
6678 GetWindowBounds(drawer, kWindowContentRgn, &r);
6679 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6680 SetControlBounds(dataBrowser, &r);
6681 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6682 kTabsColumn, r.right);
6683 }
6684 }
6685 break;
6686 }
6687
6688 return eventNotHandledErr;
6689}
6690
6691// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6692// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6693// blue highlights in the list view on these systems, though. Oh well.)
6694
6695
6696#import <mach-o/dyld.h>
6697
6698enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6699
6700 static OSStatus
6701myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6702 OptionBits inAttributesToSet,
6703 OptionBits inAttributesToClear)
6704{
6705 long osVersion;
6706 char *symbolName;
6707 NSSymbol symbol = NULL;
6708 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6709 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6710
6711 Gestalt(gestaltSystemVersion, &osVersion);
6712 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6713 return noErr;
6714
6715 // C name mangling...
6716 symbolName = "_DataBrowserChangeAttributes";
6717 if (!NSIsSymbolNameDefined(symbolName)
6718 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6719 return noErr;
6720
6721 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6722 if (dataBrowserChangeAttributes == NULL)
6723 return noErr; // well...
6724 return dataBrowserChangeAttributes(inDataBrowser,
6725 inAttributesToSet, inAttributesToClear);
6726}
6727
6728 static void
6729initialise_tabline(void)
6730{
6731 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6732 DataBrowserCallbacks dbCallbacks;
6733 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6734 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6735 DataBrowserListViewColumnDesc colDesc;
6736
6737 // drawers have to have compositing enabled
6738 CreateNewWindow(kDrawerWindowClass,
6739 kWindowStandardHandlerAttribute
6740 | kWindowCompositingAttribute
6741 | kWindowResizableAttribute
6742 | kWindowLiveResizeAttribute,
6743 &drawerRect, &drawer);
6744
6745 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6746 SetDrawerParent(drawer, gui.VimWindow);
6747 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6748
6749
6750 // create list view embedded in drawer
6751 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6752 &dataBrowser);
6753
6754 dbCallbacks.version = kDataBrowserLatestCallbacks;
6755 InitDataBrowserCallbacks(&dbCallbacks);
6756 dbCallbacks.u.v1.itemDataCallback =
6757 NewDataBrowserItemDataUPP(dbItemDataCallback);
6758 dbCallbacks.u.v1.itemNotificationCallback =
6759 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6760 dbCallbacks.u.v1.getContextualMenuCallback =
6761 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6762 dbCallbacks.u.v1.selectContextualMenuCallback =
6763 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6764
6765 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6766
6767 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6768 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6769 SetDataBrowserSelectionFlags(dataBrowser,
6770 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6771 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6772 kDataBrowserTableViewFillHilite);
6773 Boolean b = false;
6774 SetControlData(dataBrowser, kControlEntireControl,
6775 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6776
6777 // enable blue background in data browser (this is only in 10.4 and vim
6778 // has to support older osx versions as well, so we have to load this
6779 // function dynamically)
6780 myDataBrowserChangeAttributes(dataBrowser,
6781 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6782
6783 // install callback that keeps focus in vim and away from the data browser
6784 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6785 NULL, NULL);
6786
6787 // install callback that keeps data browser at the size of the drawer
6788 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6789 NULL, NULL);
6790
6791 // add "tabs" column to data browser
6792 colDesc.propertyDesc.propertyID = kTabsColumn;
6793 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6794
6795 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6796 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6797
6798 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6799 colDesc.headerBtnDesc.minimumWidth = 100;
6800 colDesc.headerBtnDesc.maximumWidth = 150;
6801 colDesc.headerBtnDesc.titleOffset = 0;
6802 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6803 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6804 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6805 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6806
6807 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6808
6809 // create tabline popup menu required by vim docs (see :he tabline-menu)
6810 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
6811 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close"), 0,
6812 TABLINE_MENU_CLOSE, NULL);
6813 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6814 TABLINE_MENU_NEW, NULL);
6815 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6816 TABLINE_MENU_OPEN, NULL);
6817}
6818
6819
6820/*
6821 * Show or hide the tabline.
6822 */
6823 void
6824gui_mch_show_tabline(int showit)
6825{
6826 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006827 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006828 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006829 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006830}
6831
6832/*
6833 * Return TRUE when tabline is displayed.
6834 */
6835 int
6836gui_mch_showing_tabline(void)
6837{
6838 WindowDrawerState state = GetDrawerState(drawer);
6839
6840 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6841}
6842
6843/*
6844 * Update the labels of the tabline.
6845 */
6846 void
6847gui_mch_update_tabline(void)
6848{
6849 tabpage_T *tp;
6850 int numTabs = getTabCount();
6851 int nr = 1;
6852 int curtabidx = 1;
6853
6854 // adjust data browser
6855 if (tabLabels != NULL)
6856 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006857 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006858
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006859 for (i = 0; i < tabLabelsSize; ++i)
6860 CFRelease(tabLabels[i]);
6861 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006862 }
6863 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6864 tabLabelsSize = numTabs;
6865
6866 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6867 {
6868 if (tp == curtab)
6869 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006870 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006871 }
6872
6873 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6874 kDataBrowserItemNoProperty);
6875 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6876 // can pass NULL for the id array
6877 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6878 kDataBrowserItemNoProperty);
6879
6880 DataBrowserItemID item = curtabidx;
6881 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6882}
6883
6884/*
6885 * Set the current tab to "nr". First tab is 1.
6886 */
6887 void
6888gui_mch_set_curtab(nr)
6889 int nr;
6890{
6891 DataBrowserItemID item = nr;
6892 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6893
6894 // TODO: call something like this?: (or restore scroll position, or...)
6895 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6896 kDataBrowserRevealOnly);
6897}
6898
6899#endif // FEAT_GUI_TABLINE