blob: 3479dbb55c52de89bcca47e2a0849a0828347f50 [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
Bram Moolenaar84a05ac2013-05-06 04:24:17 +020044/* Compile as CodeWarrior External Editor */
Bram Moolenaar071d4272004-06-13 20:20:40 +000045#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;
Bram Moolenaar76b96fc2010-07-17 16:44:59 +0200176UInt32 useAntialias_cached = 0x0;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000177#endif
178
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179/* Colors Macros */
180#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
181#define Red(c) ((c & 0x00FF0000) >> 16)
182#define Green(c) ((c & 0x0000FF00) >> 8)
183#define Blue(c) ((c & 0x000000FF) >> 0)
184
185/* Key mapping */
186
187#define vk_Esc 0x35 /* -> 1B */
188
189#define vk_F1 0x7A /* -> 10 */
190#define vk_F2 0x78 /*0x63*/
191#define vk_F3 0x63 /*0x76*/
192#define vk_F4 0x76 /*0x60*/
193#define vk_F5 0x60 /*0x61*/
194#define vk_F6 0x61 /*0x62*/
195#define vk_F7 0x62 /*0x63*/ /*?*/
196#define vk_F8 0x64
197#define vk_F9 0x65
198#define vk_F10 0x6D
199#define vk_F11 0x67
200#define vk_F12 0x6F
201#define vk_F13 0x69
202#define vk_F14 0x6B
203#define vk_F15 0x71
204
205#define vk_Clr 0x47 /* -> 1B (ESC) */
206#define vk_Enter 0x4C /* -> 03 */
207
208#define vk_Space 0x31 /* -> 20 */
209#define vk_Tab 0x30 /* -> 09 */
210#define vk_Return 0x24 /* -> 0D */
211/* This is wrong for OSX, what is it for? */
212#define vk_Delete 0X08 /* -> 08 BackSpace */
213
214#define vk_Help 0x72 /* -> 05 */
215#define vk_Home 0x73 /* -> 01 */
216#define vk_PageUp 0x74 /* -> 0D */
217#define vk_FwdDelete 0x75 /* -> 7F */
218#define vk_End 0x77 /* -> 04 */
219#define vk_PageDown 0x79 /* -> 0C */
220
221#define vk_Up 0x7E /* -> 1E */
222#define vk_Down 0x7D /* -> 1F */
223#define vk_Left 0x7B /* -> 1C */
224#define vk_Right 0x7C /* -> 1D */
225
226#define vk_Undo vk_F1
227#define vk_Cut vk_F2
228#define vk_Copy vk_F3
229#define vk_Paste vk_F4
230#define vk_PrintScreen vk_F13
231#define vk_SCrollLock vk_F14
232#define vk_Pause vk_F15
233#define vk_NumLock vk_Clr
234#define vk_Insert vk_Help
235
236#define KeySym char
237
238static struct
239{
240 KeySym key_sym;
241 char_u vim_code0;
242 char_u vim_code1;
243} special_keys[] =
244{
245 {vk_Up, 'k', 'u'},
246 {vk_Down, 'k', 'd'},
247 {vk_Left, 'k', 'l'},
248 {vk_Right, 'k', 'r'},
249
250 {vk_F1, 'k', '1'},
251 {vk_F2, 'k', '2'},
252 {vk_F3, 'k', '3'},
253 {vk_F4, 'k', '4'},
254 {vk_F5, 'k', '5'},
255 {vk_F6, 'k', '6'},
256 {vk_F7, 'k', '7'},
257 {vk_F8, 'k', '8'},
258 {vk_F9, 'k', '9'},
259 {vk_F10, 'k', ';'},
260
261 {vk_F11, 'F', '1'},
262 {vk_F12, 'F', '2'},
263 {vk_F13, 'F', '3'},
264 {vk_F14, 'F', '4'},
265 {vk_F15, 'F', '5'},
266
267/* {XK_Help, '%', '1'}, */
268/* {XK_Undo, '&', '8'}, */
269/* {XK_BackSpace, 'k', 'b'}, */
270#ifndef MACOS_X
271 {vk_Delete, 'k', 'b'},
272#endif
273 {vk_Insert, 'k', 'I'},
274 {vk_FwdDelete, 'k', 'D'},
275 {vk_Home, 'k', 'h'},
276 {vk_End, '@', '7'},
277/* {XK_Prior, 'k', 'P'}, */
278/* {XK_Next, 'k', 'N'}, */
279/* {XK_Print, '%', '9'}, */
280
281 {vk_PageUp, 'k', 'P'},
282 {vk_PageDown, 'k', 'N'},
283
284 /* End of list marker: */
285 {(KeySym)0, 0, 0}
286};
287
288/*
289 * ------------------------------------------------------------
290 * Forward declaration (for those needed)
291 * ------------------------------------------------------------
292 */
293
294#ifdef USE_AEVENT
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000295OSErr HandleUnusedParms(const AppleEvent *theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296#endif
297
Bram Moolenaar79ee3152007-04-26 16:20:50 +0000298#ifdef FEAT_GUI_TABLINE
299static void initialise_tabline(void);
300static WindowRef drawer = NULL; // TODO: put into gui.h
301#endif
302
Bram Moolenaar1b60e502008-03-12 13:40:54 +0000303#ifdef USE_ATSUI_DRAWING
304static void gui_mac_set_font_attributes(GuiFont font);
305static void gui_mac_dispose_atsui_style(void);
306#endif
307
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308/*
309 * ------------------------------------------------------------
310 * Conversion Utility
311 * ------------------------------------------------------------
312 */
313
314/*
315 * C2Pascal_save
316 *
317 * Allocate memory and convert the C-String passed in
318 * into a pascal string
319 *
320 */
321
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000322 char_u *
323C2Pascal_save(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324{
325 char_u *PascalString;
326 int len;
327
328 if (Cstring == NULL)
329 return NULL;
330
331 len = STRLEN(Cstring);
332
333 if (len > 255) /* Truncate if necessary */
334 len = 255;
335
336 PascalString = alloc(len + 1);
337 if (PascalString != NULL)
338 {
339 mch_memmove(PascalString + 1, Cstring, len);
340 PascalString[0] = len;
341 }
342
343 return PascalString;
344}
345
346/*
347 * C2Pascal_save_and_remove_backslash
348 *
349 * Allocate memory and convert the C-String passed in
350 * into a pascal string. Also remove the backslash at the same time
351 *
352 */
353
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000354 char_u *
355C2Pascal_save_and_remove_backslash(char_u *Cstring)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356{
357 char_u *PascalString;
358 int len;
359 char_u *p, *c;
360
361 len = STRLEN(Cstring);
362
363 if (len > 255) /* Truncate if necessary */
364 len = 255;
365
366 PascalString = alloc(len + 1);
367 if (PascalString != NULL)
368 {
369 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++)
370 {
371 if ((*c == '\\') && (c[1] != 0))
372 {
373 c++;
374 }
375 *p = *c;
376 p++;
377 len++;
378 }
379 PascalString[0] = len;
380 }
381
382 return PascalString;
383}
384
385/*
386 * Convert the modifiers of an Event into vim's modifiers (mouse)
387 */
388
389 int_u
390EventModifiers2VimMouseModifiers(EventModifiers macModifiers)
391{
392 int_u vimModifiers = 0x00;
393
394 if (macModifiers & (shiftKey | rightShiftKey))
395 vimModifiers |= MOUSE_SHIFT;
396 if (macModifiers & (controlKey | rightControlKey))
397 vimModifiers |= MOUSE_CTRL;
398 if (macModifiers & (optionKey | rightOptionKey))
399 vimModifiers |= MOUSE_ALT;
400#if 0
401 /* Not yet supported */
402 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
403 vimModifiers |= MOUSE_CMD;
404#endif
405 return (vimModifiers);
406}
407
408/*
409 * Convert the modifiers of an Event into vim's modifiers (keys)
410 */
411
412 static int_u
413EventModifiers2VimModifiers(EventModifiers macModifiers)
414{
415 int_u vimModifiers = 0x00;
416
417 if (macModifiers & (shiftKey | rightShiftKey))
418 vimModifiers |= MOD_MASK_SHIFT;
419 if (macModifiers & (controlKey | rightControlKey))
420 vimModifiers |= MOD_MASK_CTRL;
421 if (macModifiers & (optionKey | rightOptionKey))
422 vimModifiers |= MOD_MASK_ALT;
423#ifdef USE_CMD_KEY
424 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */
425 vimModifiers |= MOD_MASK_CMD;
426#endif
427 return (vimModifiers);
428}
429
430/* Convert a string representing a point size into pixels. The string should
431 * be a positive decimal number, with an optional decimal point (eg, "12", or
432 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
433 * character is stored in *end. The flag "vertical" says whether this
434 * calculation is for a vertical (height) size or a horizontal (width) one.
435 *
436 * From gui_w48.c
437 */
438 static int
439points_to_pixels(char_u *str, char_u **end, int vertical)
440{
441 int pixels;
442 int points = 0;
443 int divisor = 0;
444
445 while (*str)
446 {
447 if (*str == '.' && divisor == 0)
448 {
449 /* Start keeping a divisor, for later */
450 divisor = 1;
451 continue;
452 }
453
454 if (!isdigit(*str))
455 break;
456
457 points *= 10;
458 points += *str - '0';
459 divisor *= 10;
460
461 ++str;
462 }
463
464 if (divisor == 0)
465 divisor = 1;
466
467 pixels = points/divisor;
468 *end = str;
469 return pixels;
470}
471
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000472#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000473/*
474 * Deletes all traces of any Windows-style mnemonic text (including any
475 * parentheses) from a menu item and returns the cleaned menu item title.
476 * The caller is responsible for releasing the returned string.
477 */
478 static CFStringRef
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000479menu_title_removing_mnemonic(vimmenu_T *menu)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000480{
481 CFStringRef name;
482 size_t menuTitleLen;
483 CFIndex displayLen;
484 CFRange mnemonicStart;
485 CFRange mnemonicEnd;
486 CFMutableStringRef cleanedName;
487
488 menuTitleLen = STRLEN(menu->dname);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000489 name = (CFStringRef) mac_enc_to_cfstring(menu->dname, menuTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000490
491 if (name)
492 {
493 /* Simple mnemonic-removal algorithm, assumes single parenthesized
494 * mnemonic character towards the end of the menu text */
495 mnemonicStart = CFStringFind(name, CFSTR("("), kCFCompareBackwards);
496 displayLen = CFStringGetLength(name);
497
498 if (mnemonicStart.location != kCFNotFound
499 && (mnemonicStart.location + 2) < displayLen
500 && CFStringGetCharacterAtIndex(name,
501 mnemonicStart.location + 1) == (UniChar)menu->mnemonic)
502 {
503 if (CFStringFindWithOptions(name, CFSTR(")"),
504 CFRangeMake(mnemonicStart.location + 1,
505 displayLen - mnemonicStart.location - 1),
506 kCFCompareBackwards, &mnemonicEnd) &&
507 (mnemonicStart.location + 2) == mnemonicEnd.location)
508 {
509 cleanedName = CFStringCreateMutableCopy(NULL, 0, name);
510 if (cleanedName)
511 {
512 CFStringDelete(cleanedName,
513 CFRangeMake(mnemonicStart.location,
514 mnemonicEnd.location + 1 -
515 mnemonicStart.location));
516
517 CFRelease(name);
518 name = cleanedName;
519 }
520 }
521 }
522 }
523
524 return name;
525}
526#endif
527
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528/*
529 * Convert a list of FSSpec aliases into a list of fullpathname
530 * character strings.
531 */
532
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000533 char_u **
534new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535{
536 char_u **fnames = NULL;
537 OSErr newError;
538 long fileCount;
539 FSSpec fileToOpen;
540 long actualSize;
541 AEKeyword dummyKeyword;
542 DescType dummyType;
543
544 /* Get number of files in list */
545 *error = AECountItems(theList, numFiles);
546 if (*error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000547 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548
549 /* Allocate the pointer list */
550 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *));
551
552 /* Empty out the list */
553 for (fileCount = 0; fileCount < *numFiles; fileCount++)
554 fnames[fileCount] = NULL;
555
556 /* Scan the list of FSSpec */
557 for (fileCount = 1; fileCount <= *numFiles; fileCount++)
558 {
559 /* Get the alias for the nth file, convert to an FSSpec */
560 newError = AEGetNthPtr(theList, fileCount, typeFSS,
561 &dummyKeyword, &dummyType,
562 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize);
563 if (newError)
564 {
565 /* Caller is able to clean up */
566 /* TODO: Should be clean up or not? For safety. */
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000567 return fnames;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 }
569
570 /* Convert the FSSpec to a pathname */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000571 fnames[fileCount - 1] = FullPathFromFSSpec_save(fileToOpen);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 }
573
574 return (fnames);
575}
576
577/*
578 * ------------------------------------------------------------
579 * CodeWarrior External Editor Support
580 * ------------------------------------------------------------
581 */
582#ifdef FEAT_CW_EDITOR
583
584/*
585 * Handle the Window Search event from CodeWarrior
586 *
587 * Description
588 * -----------
589 *
590 * The IDE sends the Window Search AppleEvent to the editor when it
591 * needs to know whether a particular file is open in the editor.
592 *
593 * Event Reply
594 * -----------
595 *
596 * None. Put data in the location specified in the structure received.
597 *
598 * Remarks
599 * -------
600 *
601 * When the editor receives this event, determine whether the specified
602 * file is open. If it is, return the modification date/time for that file
603 * in the appropriate location specified in the structure. If the file is
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000604 * not opened, put the value fnfErr(file not found) in that location.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 *
606 */
607
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608typedef struct WindowSearch WindowSearch;
609struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/
610{
611 FSSpec theFile; // identifies the file
612 long *theDate; // where to put the modification date/time
613};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000615 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000616Handle_KAHL_SRCH_AE(
617 const AppleEvent *theAEvent,
618 AppleEvent *theReply,
619 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620{
621 OSErr error = noErr;
622 buf_T *buf;
623 int foundFile = false;
624 DescType typeCode;
625 WindowSearch SearchData;
626 Size actualSize;
627
628 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize);
629 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000630 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000632 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000634 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635
636 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
637 if (buf->b_ml.ml_mfp != NULL
638 && SearchData.theFile.parID == buf->b_FSSpec.parID
639 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0]
640 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0)
641 {
642 foundFile = true;
643 break;
644 }
645
646 if (foundFile == false)
647 *SearchData.theDate = fnfErr;
648 else
649 *SearchData.theDate = buf->b_mtime;
650
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 return error;
652};
653
654/*
655 * Handle the Modified (from IDE to Editor) event from CodeWarrior
656 *
657 * Description
658 * -----------
659 *
660 * The IDE sends this event to the external editor when it wants to
661 * know which files that are open in the editor have been modified.
662 *
663 * Parameters None.
664 * ----------
665 *
666 * Event Reply
667 * -----------
668 * The reply for this event is:
669 *
670 * keyDirectObject typeAEList required
671 * each element in the list is a structure of typeChar
672 *
673 * Remarks
674 * -------
675 *
676 * When building the reply event, include one element in the list for
677 * each open file that has been modified.
678 *
679 */
680
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681typedef struct ModificationInfo ModificationInfo;
682struct ModificationInfo /* for replying to class 'KAHL', event 'MOD ', keyDirectObject typeAEList*/
683{
684 FSSpec theFile; // identifies the file
685 long theDate; // the date/time the file was last modified
686 short saved; // set this to zero when replying, unused
687};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000688
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000689 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000690Handle_KAHL_MOD_AE(
691 const AppleEvent *theAEvent,
692 AppleEvent *theReply,
693 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694{
695 OSErr error = noErr;
696 AEDescList replyList;
697 long numFiles;
698 ModificationInfo theFile;
699 buf_T *buf;
700
701 theFile.saved = 0;
702
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000703 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000705 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706
707 /* Send the reply */
708/* replyObject.descriptorType = typeNull;
709 replyObject.dataHandle = nil;*/
710
711/* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */
712 error = AECreateList(nil, 0, false, &replyList);
713 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000714 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715
716#if 0
717 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000719 /* AEPutKeyDesc(&replyList, keyAEPnject, &aDesc)
720 * AEPutKeyPtr(&replyList, keyAEPosition, typeChar, (Ptr)&theType,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 * sizeof(DescType))
722 */
723
724 /* AEPutDesc */
725#endif
726
727 numFiles = 0;
728 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
729 if (buf->b_ml.ml_mfp != NULL)
730 {
731 /* Add this file to the list */
732 theFile.theFile = buf->b_FSSpec;
733 theFile.theDate = buf->b_mtime;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000734/* theFile.theDate = time(NULL) & (time_t) 0xFFFFFFF0; */
735 error = AEPutPtr(&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 };
737
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#if 0
739 error = AECountItems(&replyList, &numFiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740#endif
741
742 /* We can add data only if something to reply */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000743 error = AEPutParamDesc(theReply, keyDirectObject, &replyList);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 if (replyList.dataHandle)
746 AEDisposeDesc(&replyList);
747
748 return error;
749};
750
751/*
752 * Handle the Get Text event from CodeWarrior
753 *
754 * Description
755 * -----------
756 *
757 * The IDE sends the Get Text AppleEvent to the editor when it needs
758 * the source code from a file. For example, when the user issues a
759 * Check Syntax or Compile command, the compiler needs access to
760 * the source code contained in the file.
761 *
762 * Event Reply
763 * -----------
764 *
765 * None. Put data in locations specified in the structure received.
766 *
767 * Remarks
768 * -------
769 *
770 * When the editor receives this event, it must set the size of the handle
771 * in theText to fit the data in the file. It must then copy the entire
772 * contents of the specified file into the memory location specified in
773 * theText.
774 *
775 */
776
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777typedef struct CW_GetText CW_GetText;
778struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/
779{
780 FSSpec theFile; /* identifies the file */
781 Handle theText; /* the location where you return the text (must be resized properly) */
782 long *unused; /* 0 (not used) */
783 long *theDate; /* where to put the modification date/time */
784};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000786 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000787Handle_KAHL_GTTX_AE(
788 const AppleEvent *theAEvent,
789 AppleEvent *theReply,
790 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791{
792 OSErr error = noErr;
793 buf_T *buf;
794 int foundFile = false;
795 DescType typeCode;
796 CW_GetText GetTextData;
797 Size actualSize;
798 char_u *line;
799 char_u *fullbuffer = NULL;
800 long linesize;
801 long lineStart;
802 long BufferSize;
803 long lineno;
804
805 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize);
806
807 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000808 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809
810 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
811 if (buf->b_ml.ml_mfp != NULL)
812 if (GetTextData.theFile.parID == buf->b_FSSpec.parID)
813 {
814 foundFile = true;
815 break;
816 }
817
818 if (foundFile)
819 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000820 BufferSize = 0; /* GetHandleSize(GetTextData.theText); */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++)
822 {
823 /* Must use the right buffer */
824 line = ml_get_buf(buf, (linenr_T) lineno, FALSE);
825 linesize = STRLEN(line) + 1;
826 lineStart = BufferSize;
827 BufferSize += linesize;
828 /* Resize handle to linesize+1 to include the linefeed */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000829 SetHandleSize(GetTextData.theText, BufferSize);
830 if (GetHandleSize(GetTextData.theText) != BufferSize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 break; /* Simple handling for now */
833 }
834 else
835 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000836 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 fullbuffer = (char_u *) *GetTextData.theText;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000838 STRCPY((char_u *)(fullbuffer + lineStart), line);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 fullbuffer[BufferSize-1] = '\r';
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000840 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 }
842 }
843 if (fullbuffer != NULL)
844 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000845 HLock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 fullbuffer[BufferSize-1] = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000847 HUnlock(GetTextData.theText);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 }
849 if (foundFile == false)
850 *GetTextData.theDate = fnfErr;
851 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000852/* *GetTextData.theDate = time(NULL) & (time_t) 0xFFFFFFF0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 *GetTextData.theDate = buf->b_mtime;
854 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000856 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +0000858 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859}
860
861/*
862 *
863 */
864
865/* Taken from MoreAppleEvents:ProcessHelpers*/
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +0000866 pascal OSErr
867FindProcessBySignature(
868 const OSType targetType,
869 const OSType targetCreator,
870 ProcessSerialNumberPtr psnPtr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871{
872 OSErr anErr = noErr;
873 Boolean lookingForProcess = true;
874
875 ProcessInfoRec infoRec;
876
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000877 infoRec.processInfoLength = sizeof(ProcessInfoRec);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 infoRec.processName = nil;
879 infoRec.processAppSpec = nil;
880
881 psnPtr->lowLongOfPSN = kNoProcess;
882 psnPtr->highLongOfPSN = kNoProcess;
883
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000884 while (lookingForProcess)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000886 anErr = GetNextProcess(psnPtr);
887 if (anErr != noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 else
890 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000891 anErr = GetProcessInformation(psnPtr, &infoRec);
892 if ((anErr == noErr)
893 && (infoRec.processType == targetType)
894 && (infoRec.processSignature == targetCreator))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 lookingForProcess = false;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 }
897 }
898
899 return anErr;
900}//end FindProcessBySignature
901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000902 void
903Send_KAHL_MOD_AE(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000905 OSErr anErr = noErr;
906 AEDesc targetAppDesc = { typeNull, nil };
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 ProcessSerialNumber psn = { kNoProcess, kNoProcess };
908 AppleEvent theReply = { typeNull, nil };
909 AESendMode sendMode;
910 AppleEvent theEvent = {typeNull, nil };
911 AEIdleUPP idleProcUPP = nil;
912 ModificationInfo ModData;
913
914
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000915 anErr = FindProcessBySignature('APPL', 'CWIE', &psn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000916 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000918 anErr = AECreateDesc(typeProcessSerialNumber, &psn,
919 sizeof(ProcessSerialNumber), &targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000921 if (anErr == noErr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 {
923 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc,
924 kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
925 }
926
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000927 AEDisposeDesc(&targetAppDesc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928
929 /* Add the parms */
930 ModData.theFile = buf->b_FSSpec;
931 ModData.theDate = buf->b_mtime;
932
933 if (anErr == noErr)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000934 anErr = AEPutParamPtr(&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000936 if (idleProcUPP == nil)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 sendMode = kAENoReply;
938 else
939 sendMode = kAEWaitReply;
940
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000941 if (anErr == noErr)
942 anErr = AESend(&theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil);
943 if (anErr == noErr && sendMode == kAEWaitReply)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000945/* anErr = AEHGetHandlerError(&theReply);*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000947 (void) AEDisposeDesc(&theReply);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948 }
949}
950#endif /* FEAT_CW_EDITOR */
951
952/*
953 * ------------------------------------------------------------
954 * Apple Event Handling procedure
955 * ------------------------------------------------------------
956 */
957#ifdef USE_AEVENT
958
959/*
960 * Handle the Unused parms of an AppleEvent
961 */
962
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000963 OSErr
964HandleUnusedParms(const AppleEvent *theAEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965{
966 OSErr error;
967 long actualSize;
968 DescType dummyType;
969 AEKeyword missedKeyword;
970
971 /* Get the "missed keyword" attribute from the AppleEvent. */
972 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr,
973 typeKeyword, &dummyType,
974 (Ptr)&missedKeyword, sizeof(missedKeyword),
975 &actualSize);
976
977 /* If the descriptor isn't found, then we got the required parameters. */
978 if (error == errAEDescNotFound)
979 {
980 error = noErr;
981 }
982 else
983 {
984#if 0
985 /* Why is this removed? */
986 error = errAEEventNotHandled;
987#endif
988 }
989
990 return error;
991}
992
993
994/*
995 * Handle the ODoc AppleEvent
996 *
997 * Deals with all files dragged to the application icon.
998 *
999 */
1000
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001typedef struct SelectionRange SelectionRange;
1002struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */
1003{
1004 short unused1; // 0 (not used)
1005 short lineNum; // line to select (<0 to specify range)
1006 long startRange; // start of selection range (if line < 0)
1007 long endRange; // end of selection range (if line < 0)
1008 long unused2; // 0 (not used)
1009 long theDate; // modification date/time
1010};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011
1012/* The IDE uses the optional keyAEPosition parameter to tell the ed-
1013 itor the selection range. If lineNum is zero or greater, scroll the text
1014 to the specified line. If lineNum is less than zero, use the values in
1015 startRange and endRange to select the specified characters. Scroll
1016 the text to display the selection. If lineNum, startRange, and
1017 endRange are all negative, there is no selection range specified.
1018 */
1019
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001020 pascal OSErr
1021HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022{
1023 /*
1024 * TODO: Clean up the code with convert the AppleEvent into
1025 * a ":args"
1026 */
1027 OSErr error = noErr;
1028// OSErr firstError = noErr;
1029// short numErrors = 0;
1030 AEDesc theList;
1031 DescType typeCode;
1032 long numFiles;
1033 // long fileCount;
1034 char_u **fnames;
1035// char_u fname[256];
1036 Size actualSize;
1037 SelectionRange thePosition;
1038 short gotPosition = false;
1039 long lnum;
1040
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041 /* the direct object parameter is the list of aliases to files (one or more) */
1042 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList);
1043 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001044 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045
1046
1047 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize);
1048 if (error == noErr)
1049 gotPosition = true;
1050 if (error == errAEDescNotFound)
1051 error = noErr;
1052 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001053 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055/*
1056 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition);
1057
1058 if (^error) then
1059 {
1060 if (thePosition.lineNum >= 0)
1061 {
1062 // Goto this line
1063 }
1064 else
1065 {
1066 // Set the range char wise
1067 }
1068 }
1069 */
1070
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 reset_VIsual();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001072 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error);
1073
1074 if (error)
1075 {
1076 /* TODO: empty fnames[] first */
1077 vim_free(fnames);
1078 return (error);
1079 }
1080
1081 if (starting > 0)
1082 {
1083 int i;
1084 char_u *p;
Bram Moolenaar51b84362007-09-29 11:16:17 +00001085 int fnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086
1087 /* these are the initial files dropped on the Vim icon */
1088 for (i = 0 ; i < numFiles; i++)
1089 {
1090 if (ga_grow(&global_alist.al_ga, 1) == FAIL
1091 || (p = vim_strsave(fnames[i])) == NULL)
1092 mch_exit(2);
1093 else
1094 alist_add(&global_alist, p, 2);
Bram Moolenaar51b84362007-09-29 11:16:17 +00001095 if (fnum == -1)
1096 fnum = GARGLIST[GARGCOUNT - 1].ae_fnum;
1097 }
1098
1099 /* If the file name was already in the buffer list we need to switch
1100 * to it. */
1101 if (curbuf->b_fnum != fnum)
1102 {
1103 char_u cmd[30];
1104
1105 vim_snprintf((char *)cmd, 30, "silent %dbuffer", fnum);
1106 do_cmdline_cmd(cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 }
Bram Moolenaard2cec5b2006-03-28 21:08:56 +00001108
1109 /* Change directory to the location of the first file. */
1110 if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
1111 shorten_fnames(TRUE);
1112
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113 goto finished;
1114 }
1115
1116 /* Handle the drop, :edit to get to the file */
1117 handle_drop(numFiles, fnames, FALSE);
1118
1119 /* TODO: Handle the goto/select line more cleanly */
1120 if ((numFiles == 1) & (gotPosition))
1121 {
1122 if (thePosition.lineNum >= 0)
1123 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001124 lnum = thePosition.lineNum + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 /* oap->motion_type = MLINE;
1126 setpcmark();*/
1127 if (lnum < 1L)
1128 lnum = 1L;
1129 else if (lnum > curbuf->b_ml.ml_line_count)
1130 lnum = curbuf->b_ml.ml_line_count;
1131 curwin->w_cursor.lnum = lnum;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001132 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 /* beginline(BL_SOL | BL_FIX);*/
1134 }
1135 else
1136 goto_byte(thePosition.startRange + 1);
1137 }
1138
1139 /* Update the screen display */
1140 update_screen(NOT_VALID);
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001141
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001142 /* Select the text if possible */
1143 if (gotPosition)
1144 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001145 VIsual_active = TRUE;
1146 VIsual_select = FALSE;
1147 VIsual = curwin->w_cursor;
1148 if (thePosition.lineNum < 0)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001149 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001150 VIsual_mode = 'v';
1151 goto_byte(thePosition.endRange);
1152 }
1153 else
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001154 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001155 VIsual_mode = 'V';
1156 VIsual.col = 0;
1157 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001158 }
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01001159
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 setcursor();
1161 out_flush();
1162
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001163 /* Fake mouse event to wake from stall */
1164 PostEvent(mouseUp, 0);
1165
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001166finished:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 AEDisposeDesc(&theList); /* dispose what we allocated */
1168
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001169 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001170 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171}
1172
1173/*
1174 *
1175 */
1176
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001177 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001178Handle_aevt_oapp_AE(
1179 const AppleEvent *theAEvent,
1180 AppleEvent *theReply,
1181 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182{
1183 OSErr error = noErr;
1184
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001185 error = HandleUnusedParms(theAEvent);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001186 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001187}
1188
1189/*
1190 *
1191 */
1192
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001193 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001194Handle_aevt_quit_AE(
1195 const AppleEvent *theAEvent,
1196 AppleEvent *theReply,
1197 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198{
1199 OSErr error = noErr;
1200
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001201 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 if (error)
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001203 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204
1205 /* Need to fake a :confirm qa */
1206 do_cmdline_cmd((char_u *)"confirm qa");
1207
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001208 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209}
1210
1211/*
1212 *
1213 */
1214
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001215 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001216Handle_aevt_pdoc_AE(
1217 const AppleEvent *theAEvent,
1218 AppleEvent *theReply,
1219 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220{
1221 OSErr error = noErr;
1222
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001223 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001225 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226}
1227
1228/*
1229 * Handling of unknown AppleEvent
1230 *
1231 * (Just get rid of all the parms)
1232 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001233 pascal OSErr
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001234Handle_unknown_AE(
1235 const AppleEvent *theAEvent,
1236 AppleEvent *theReply,
1237 long refCon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238{
1239 OSErr error = noErr;
1240
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001241 error = HandleUnusedParms(theAEvent);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00001243 return error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244}
1245
1246
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247/*
1248 * Install the various AppleEvent Handlers
1249 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001250 OSErr
1251InstallAEHandlers(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252{
1253 OSErr error;
1254
1255 /* install open application handler */
1256 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001257 NewAEEventHandlerUPP(Handle_aevt_oapp_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 if (error)
1259 {
1260 return error;
1261 }
1262
1263 /* install quit application handler */
1264 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001265 NewAEEventHandlerUPP(Handle_aevt_quit_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 if (error)
1267 {
1268 return error;
1269 }
1270
1271 /* install open document handler */
1272 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001273 NewAEEventHandlerUPP(HandleODocAE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274 if (error)
1275 {
1276 return error;
1277 }
1278
1279 /* install print document handler */
1280 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001281 NewAEEventHandlerUPP(Handle_aevt_pdoc_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282
1283/* Install Core Suite */
1284/* error = AEInstallEventHandler(kAECoreSuite, kAEClone,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001285 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286
1287 error = AEInstallEventHandler(kAECoreSuite, kAEClose,
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, kAECountElements,
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, kAECreateElement,
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, kAEDelete,
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, kAEDoObjectsExist,
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, kAEGetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001303 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetData, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304
1305 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001306 NewAEEventHandlerUPP(Handle_unknown_AE), kAEGetDataSize, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307
1308 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001309 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310
1311 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo,
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, kAEMove,
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, kAESave,
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, kAESetData,
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001321 NewAEEventHandlerUPP(Handle_unknown_AE), nil, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322*/
1323
1324#ifdef FEAT_CW_EDITOR
1325 /*
1326 * Bind codewarrior support handlers
1327 */
1328 error = AEInstallEventHandler('KAHL', 'GTTX',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001329 NewAEEventHandlerUPP(Handle_KAHL_GTTX_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330 if (error)
1331 {
1332 return error;
1333 }
1334 error = AEInstallEventHandler('KAHL', 'SRCH',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001335 NewAEEventHandlerUPP(Handle_KAHL_SRCH_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 if (error)
1337 {
1338 return error;
1339 }
1340 error = AEInstallEventHandler('KAHL', 'MOD ',
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001341 NewAEEventHandlerUPP(Handle_KAHL_MOD_AE), 0, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 if (error)
1343 {
1344 return error;
1345 }
1346#endif
1347
1348 return error;
1349
1350}
1351#endif /* USE_AEVENT */
1352
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001353
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001354/*
1355 * Callback function, installed by InstallFontPanelHandler(), below,
1356 * to handle Font Panel events.
1357 */
1358 static OSStatus
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001359FontPanelHandler(
1360 EventHandlerCallRef inHandlerCallRef,
1361 EventRef inEvent,
1362 void *inUserData)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001363{
1364 if (GetEventKind(inEvent) == kEventFontPanelClosed)
1365 {
1366 gFontPanelInfo.isPanelVisible = false;
1367 return noErr;
1368 }
1369
1370 if (GetEventKind(inEvent) == kEventFontSelection)
1371 {
1372 OSStatus status;
1373 FMFontFamily newFamily;
1374 FMFontSize newSize;
1375 FMFontStyle newStyle;
1376
1377 /* Retrieve the font family ID number. */
1378 status = GetEventParameter(inEvent, kEventParamFMFontFamily,
1379 /*inDesiredType=*/typeFMFontFamily, /*outActualType=*/NULL,
1380 /*inBufferSize=*/sizeof(FMFontFamily), /*outActualSize=*/NULL,
1381 &newFamily);
1382 if (status == noErr)
1383 gFontPanelInfo.family = newFamily;
1384
1385 /* Retrieve the font size. */
1386 status = GetEventParameter(inEvent, kEventParamFMFontSize,
1387 typeFMFontSize, NULL, sizeof(FMFontSize), NULL, &newSize);
1388 if (status == noErr)
1389 gFontPanelInfo.size = newSize;
1390
1391 /* Retrieve the font style (bold, etc.). Currently unused. */
1392 status = GetEventParameter(inEvent, kEventParamFMFontStyle,
1393 typeFMFontStyle, NULL, sizeof(FMFontStyle), NULL, &newStyle);
1394 if (status == noErr)
1395 gFontPanelInfo.style = newStyle;
1396 }
1397 return noErr;
1398}
1399
1400
1401 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001402InstallFontPanelHandler(void)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001403{
1404 EventTypeSpec eventTypes[2];
1405 EventHandlerUPP handlerUPP;
1406 /* EventHandlerRef handlerRef; */
1407
1408 eventTypes[0].eventClass = kEventClassFont;
1409 eventTypes[0].eventKind = kEventFontSelection;
1410 eventTypes[1].eventClass = kEventClassFont;
1411 eventTypes[1].eventKind = kEventFontPanelClosed;
1412
1413 handlerUPP = NewEventHandlerUPP(FontPanelHandler);
1414
1415 InstallApplicationEventHandler(handlerUPP, /*numTypes=*/2, eventTypes,
1416 /*userData=*/NULL, /*handlerRef=*/NULL);
1417}
1418
1419
1420/*
1421 * Fill the buffer pointed to by outName with the name and size
1422 * of the font currently selected in the Font Panel.
1423 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001424#define FONT_STYLE_BUFFER_SIZE 32
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001425 static void
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001426GetFontPanelSelection(char_u *outName)
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001427{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001428 Str255 buf;
1429 ByteCount fontNameLen = 0;
1430 ATSUFontID fid;
1431 char_u styleString[FONT_STYLE_BUFFER_SIZE];
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001432
1433 if (!outName)
1434 return;
1435
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001436 if (FMGetFontFamilyName(gFontPanelInfo.family, buf) == noErr)
1437 {
1438 /* Canonicalize localized font names */
1439 if (FMGetFontFromFontFamilyInstance(gFontPanelInfo.family,
1440 gFontPanelInfo.style, &fid, NULL) != noErr)
1441 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001442
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001443 /* Request font name with Mac encoding (otherwise we could
1444 * get an unwanted utf-16 name) */
1445 if (ATSUFindFontName(fid, kFontFullName, kFontMacintoshPlatform,
1446 kFontNoScriptCode, kFontNoLanguageCode,
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001447 255, (char *)outName, &fontNameLen, NULL) != noErr)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001448 return;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001449
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001450 /* Only encode font size, because style (bold, italic, etc) is
1451 * already part of the font full name */
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001452 vim_snprintf((char *)styleString, FONT_STYLE_BUFFER_SIZE, ":h%d",
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001453 gFontPanelInfo.size/*,
1454 ((gFontPanelInfo.style & bold)!=0 ? ":b" : ""),
1455 ((gFontPanelInfo.style & italic)!=0 ? ":i" : ""),
1456 ((gFontPanelInfo.style & underline)!=0 ? ":u" : "")*/);
1457
1458 if ((fontNameLen + STRLEN(styleString)) < 255)
1459 STRCPY(outName + fontNameLen, styleString);
1460 }
1461 else
1462 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +00001463 *outName = NUL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001464 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001465}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00001466
1467
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468/*
1469 * ------------------------------------------------------------
1470 * Unfiled yet
1471 * ------------------------------------------------------------
1472 */
1473
1474/*
1475 * gui_mac_get_menu_item_index
1476 *
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001477 * Returns the index inside the menu where
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001479 short /* Should we return MenuItemIndex? */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001480gui_mac_get_menu_item_index(vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481{
1482 short index;
1483 short itemIndex = -1;
1484 vimmenu_T *pBrother;
1485
1486 /* Only menu without parent are the:
1487 * -menu in the menubar
1488 * -popup menu
1489 * -toolbar (guess)
1490 *
1491 * Which are not items anyway.
1492 */
1493 if (pMenu->parent)
1494 {
1495 /* Start from the Oldest Brother */
1496 pBrother = pMenu->parent->children;
1497 index = 1;
1498 while ((pBrother) && (itemIndex == -1))
1499 {
1500 if (pBrother == pMenu)
1501 itemIndex = index;
1502 index++;
1503 pBrother = pBrother->next;
1504 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 }
1506 return itemIndex;
1507}
1508
1509 static vimmenu_T *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001510gui_mac_get_vim_menu(short menuID, short itemIndex, vimmenu_T *pMenu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511{
1512 short index;
1513 vimmenu_T *pChildMenu;
1514 vimmenu_T *pElder = pMenu->parent;
1515
1516
1517 /* Only menu without parent are the:
1518 * -menu in the menubar
1519 * -popup menu
1520 * -toolbar (guess)
1521 *
1522 * Which are not items anyway.
1523 */
1524
1525 if ((pElder) && (pElder->submenu_id == menuID))
1526 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++)
1528 pMenu = pMenu->next;
1529 }
1530 else
1531 {
1532 for (; pMenu != NULL; pMenu = pMenu->next)
1533 {
1534 if (pMenu->children != NULL)
1535 {
1536 pChildMenu = gui_mac_get_vim_menu
1537 (menuID, itemIndex, pMenu->children);
1538 if (pChildMenu)
1539 {
1540 pMenu = pChildMenu;
1541 break;
1542 }
1543 }
1544 }
1545 }
1546 return pMenu;
1547}
1548
1549/*
1550 * ------------------------------------------------------------
1551 * MacOS Feedback procedures
1552 * ------------------------------------------------------------
1553 */
1554 pascal
1555 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001556gui_mac_drag_thumb(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557{
1558 scrollbar_T *sb;
1559 int value, dragging;
1560 ControlHandle theControlToUse;
1561 int dont_scroll_save = dont_scroll;
1562
1563 theControlToUse = dragged_sb;
1564
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001565 sb = gui_find_scrollbar((long) GetControlReference(theControlToUse));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566
1567 if (sb == NULL)
1568 return;
1569
1570 /* Need to find value by diff between Old Poss New Pos */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001571 value = GetControl32BitValue(theControlToUse);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572 dragging = (partCode != 0);
1573
1574 /* When "allow_scrollbar" is FALSE still need to remember the new
1575 * position, but don't actually scroll by setting "dont_scroll". */
1576 dont_scroll = !allow_scrollbar;
1577 gui_drag_scrollbar(sb, value, dragging);
1578 dont_scroll = dont_scroll_save;
1579}
1580
1581 pascal
1582 void
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001583gui_mac_scroll_action(ControlHandle theControl, short partCode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001584{
1585 /* TODO: have live support */
1586 scrollbar_T *sb, *sb_info;
1587 long data;
1588 long value;
1589 int page;
1590 int dragging = FALSE;
1591 int dont_scroll_save = dont_scroll;
1592
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001593 sb = gui_find_scrollbar((long)GetControlReference(theControl));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594
1595 if (sb == NULL)
1596 return;
1597
1598 if (sb->wp != NULL) /* Left or right scrollbar */
1599 {
1600 /*
1601 * Careful: need to get scrollbar info out of first (left) scrollbar
1602 * for window, but keep real scrollbar too because we must pass it to
1603 * gui_drag_scrollbar().
1604 */
1605 sb_info = &sb->wp->w_scrollbars[0];
1606
1607 if (sb_info->size > 5)
1608 page = sb_info->size - 2; /* use two lines of context */
1609 else
1610 page = sb_info->size;
1611 }
1612 else /* Bottom scrollbar */
1613 {
1614 sb_info = sb;
1615 page = W_WIDTH(curwin) - 5;
1616 }
1617
1618 switch (partCode)
1619 {
1620 case kControlUpButtonPart: data = -1; break;
1621 case kControlDownButtonPart: data = 1; break;
1622 case kControlPageDownPart: data = page; break;
1623 case kControlPageUpPart: data = -page; break;
1624 default: data = 0; break;
1625 }
1626
1627 value = sb_info->value + data;
1628/* if (value > sb_info->max)
1629 value = sb_info->max;
1630 else if (value < 0)
1631 value = 0;*/
1632
1633 /* When "allow_scrollbar" is FALSE still need to remember the new
1634 * position, but don't actually scroll by setting "dont_scroll". */
1635 dont_scroll = !allow_scrollbar;
1636 gui_drag_scrollbar(sb, value, dragging);
1637 dont_scroll = dont_scroll_save;
1638
1639 out_flush();
1640 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1641
1642/* if (sb_info->wp != NULL)
1643 {
1644 win_T *wp;
1645 int sb_num;
1646
1647 sb_num = 0;
1648 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp))
1649 sb_num++;
1650
1651 if (wp != NULL)
1652 {
1653 current_scrollbar = sb_num;
1654 scrollbar_value = value;
1655 gui_do_scroll();
1656 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max);
1657 }
1658 }*/
1659}
1660
1661/*
1662 * ------------------------------------------------------------
1663 * MacOS Click Handling procedures
1664 * ------------------------------------------------------------
1665 */
1666
1667
1668/*
1669 * Handle a click inside the window, it may happens in the
1670 * scrollbar or the contents.
1671 *
1672 * TODO: Add support for potential TOOLBAR
1673 */
1674 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001675gui_mac_doInContentClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676{
1677 Point thePoint;
1678 int_u vimModifiers;
1679 short thePortion;
1680 ControlHandle theControl;
1681 int vimMouseButton;
1682 short dblClick;
1683
1684 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001685 GlobalToLocal(&thePoint);
1686 SelectWindow(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001688 thePortion = FindControl(thePoint, whichWindow, &theControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689
1690 if (theControl != NUL)
1691 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001692 /* We hit a scrollbar */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693
1694 if (thePortion != kControlIndicatorPart)
1695 {
1696 dragged_sb = theControl;
1697 TrackControl(theControl, thePoint, gScrollAction);
1698 dragged_sb = NULL;
1699 }
1700 else
1701 {
1702 dragged_sb = theControl;
1703#if 1
1704 TrackControl(theControl, thePoint, gScrollDrag);
1705#else
1706 TrackControl(theControl, thePoint, NULL);
1707#endif
1708 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse
1709 * button has been released */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001710 gui_mac_drag_thumb(theControl, 0); /* Should it be thePortion ? (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 dragged_sb = NULL;
1712 }
1713 }
1714 else
1715 {
1716 /* We are inside the contents */
1717
1718 /* Convert the CTRL, OPTION, SHIFT and CMD key */
1719 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
1720
1721 /* Defaults to MOUSE_LEFT as there's only one mouse button */
1722 vimMouseButton = MOUSE_LEFT;
1723
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001725 /* TODO: NEEDED? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 clickIsPopup = FALSE;
1727
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001728 if (mouse_model_popup() && IsShowContextualMenuClick(theEvent))
1729 {
1730 vimMouseButton = MOUSE_RIGHT;
1731 vimModifiers &= ~MOUSE_CTRL;
1732 clickIsPopup = TRUE;
1733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734
1735 /* Is it a double click ? */
1736 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime());
1737
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001738 /* Send the mouse click to Vim */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 gui_send_mouse_event(vimMouseButton, thePoint.h,
1740 thePoint.v, dblClick, vimModifiers);
1741
1742 /* Create the rectangle around the cursor to detect
1743 * the mouse dragging
1744 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745#if 0
1746 /* TODO: Do we need to this even for the contextual menu?
1747 * It may be require for popup_setpos, but for popup?
1748 */
1749 if (vimMouseButton == MOUSE_LEFT)
1750#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001752 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001753 FILL_Y(Y_2_ROW(thePoint.v)),
1754 FILL_X(X_2_COL(thePoint.h)+1),
1755 FILL_Y(Y_2_ROW(thePoint.v)+1));
1756
1757 dragRectEnbl = TRUE;
1758 dragRectControl = kCreateRect;
1759 }
1760 }
1761}
1762
1763/*
1764 * Handle the click in the titlebar (to move the window)
1765 */
1766 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001767gui_mac_doInDragClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768{
1769 Rect movingLimits;
1770 Rect *movingLimitsPtr = &movingLimits;
1771
1772 /* TODO: may try to prevent move outside screen? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001773 movingLimitsPtr = GetRegionBounds(GetGrayRgn(), &movingLimits);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001774 DragWindow(whichWindow, where, movingLimitsPtr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775}
1776
1777/*
1778 * Handle the click in the grow box
1779 */
1780 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001781gui_mac_doInGrowClick(Point where, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782{
1783
1784 long newSize;
1785 unsigned short newWidth;
1786 unsigned short newHeight;
1787 Rect resizeLimits;
1788 Rect *resizeLimitsPtr = &resizeLimits;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 Rect NewContentRect;
1790
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001791 resizeLimitsPtr = GetRegionBounds(GetGrayRgn(), &resizeLimits);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792
Bram Moolenaar720c7102007-05-10 18:07:50 +00001793 /* Set the minimum size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 /* TODO: Should this come from Vim? */
1795 resizeLimits.top = 100;
1796 resizeLimits.left = 100;
1797
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect);
1799 newWidth = NewContentRect.right - NewContentRect.left;
1800 newHeight = NewContentRect.bottom - NewContentRect.top;
1801 gui_resize_shell(newWidth, newHeight);
1802 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001803 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804}
1805
1806/*
1807 * Handle the click in the zoom box
1808 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 static void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001810gui_mac_doInZoomClick(EventRecord *theEvent, WindowPtr whichWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811{
1812 Rect r;
1813 Point p;
1814 short thePart;
1815
1816 /* ideal width is current */
1817 p.h = Columns * gui.char_width + 2 * gui.border_offset;
1818 if (gui.which_scrollbars[SBAR_LEFT])
1819 p.h += gui.scrollbar_width;
1820 if (gui.which_scrollbars[SBAR_RIGHT])
1821 p.h += gui.scrollbar_width;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02001822 /* ideal height is as high as we can get */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 p.v = 15 * 1024;
1824
1825 thePart = IsWindowInStandardState(whichWindow, &p, &r)
1826 ? inZoomIn : inZoomOut;
1827
1828 if (!TrackBox(whichWindow, theEvent->where, thePart))
1829 return;
1830
1831 /* use returned width */
1832 p.h = r.right - r.left;
1833 /* adjust returned height */
1834 p.v = r.bottom - r.top - 2 * gui.border_offset;
1835 if (gui.which_scrollbars[SBAR_BOTTOM])
1836 p.v -= gui.scrollbar_height;
1837 p.v -= p.v % gui.char_height;
1838 p.v += 2 * gui.border_width;
Bram Moolenaard8644bd2011-06-12 20:33:38 +02001839 if (gui.which_scrollbars[SBAR_BOTTOM])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840 p.v += gui.scrollbar_height;
1841
1842 ZoomWindowIdeal(whichWindow, thePart, &p);
1843
1844 GetWindowBounds(whichWindow, kWindowContentRgn, &r);
1845 gui_resize_shell(r.right - r.left, r.bottom - r.top);
1846 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaarafa24992006-03-27 20:58:26 +00001847 gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849
1850/*
1851 * ------------------------------------------------------------
1852 * MacOS Event Handling procedure
1853 * ------------------------------------------------------------
1854 */
1855
1856/*
1857 * Handle the Update Event
1858 */
1859
1860 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001861gui_mac_doUpdateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862{
1863 WindowPtr whichWindow;
1864 GrafPtr savePort;
1865 RgnHandle updateRgn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 Rect updateRect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001867 Rect *updateRectPtr;
1868 Rect rc;
1869 Rect growRect;
1870 RgnHandle saveRgn;
1871
1872
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873 updateRgn = NewRgn();
1874 if (updateRgn == NULL)
1875 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 /* This could be done by the caller as we
1878 * don't require anything else out of the event
1879 */
1880 whichWindow = (WindowPtr) event->message;
1881
1882 /* Save Current Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001883 GetPort(&savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884
1885 /* Select the Window's Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001886 SetPortWindowPort(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887
1888 /* Let's update the window */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001889 BeginUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 /* Redraw the biggest rectangle covering the area
1891 * to be updated.
1892 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn);
1894# if 0
Bram Moolenaar720c7102007-05-10 18:07:50 +00001895 /* Would be more appropriate to use the following but doesn't
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 * seem to work under MacOS X (Dany)
1897 */
1898 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn);
1899# endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001900
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901 /* Use the HLock useless in Carbon? Is it harmful?*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001902 HLock((Handle) updateRgn);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001903
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001904 updateRectPtr = GetRegionBounds(updateRgn, &updateRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905# if 0
1906 /* Code from original Carbon Port (using GetWindowRegion.
1907 * I believe the UpdateRgn is already in local (Dany)
1908 */
1909 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */
1910 GlobalToLocal(&botRight(updateRect));
1911# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 /* Update the content (i.e. the text) */
1913 gui_redraw(updateRectPtr->left, updateRectPtr->top,
1914 updateRectPtr->right - updateRectPtr->left,
1915 updateRectPtr->bottom - updateRectPtr->top);
1916 /* Clear the border areas if needed */
1917 gui_mch_set_bg_color(gui.back_pixel);
1918 if (updateRectPtr->left < FILL_X(0))
1919 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001920 SetRect(&rc, 0, 0, FILL_X(0), FILL_Y(Rows));
1921 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 }
1923 if (updateRectPtr->top < FILL_Y(0))
1924 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001925 SetRect(&rc, 0, 0, FILL_X(Columns), FILL_Y(0));
1926 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927 }
1928 if (updateRectPtr->right > FILL_X(Columns))
1929 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001930 SetRect(&rc, FILL_X(Columns), 0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows));
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001932 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 }
1934 if (updateRectPtr->bottom > FILL_Y(Rows))
1935 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001936 SetRect(&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 FILL_Y(Rows) + gui.border_offset);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001938 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001940 HUnlock((Handle) updateRgn);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001941 DisposeRgn(updateRgn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942
1943 /* Update scrollbars */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001944 DrawControls(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945
1946 /* Update the GrowBox */
1947 /* Taken from FAQ 33-27 */
1948 saveRgn = NewRgn();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001950 GetClip(saveRgn);
1951 ClipRect(&growRect);
1952 DrawGrowIcon(whichWindow);
1953 SetClip(saveRgn);
1954 DisposeRgn(saveRgn);
1955 EndUpdate(whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956
1957 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001958 SetPort(savePort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959}
1960
1961/*
1962 * Handle the activate/deactivate event
1963 * (apply to a window)
1964 */
1965 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001966gui_mac_doActivateEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967{
1968 WindowPtr whichWindow;
1969
1970 whichWindow = (WindowPtr) event->message;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001971 /* Dim scrollbars */
1972 if (whichWindow == gui.VimWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00001974 ControlRef rootControl;
1975 GetRootControl(gui.VimWindow, &rootControl);
1976 if ((event->modifiers) & activeFlag)
1977 ActivateControl(rootControl);
1978 else
1979 DeactivateControl(rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 }
Bram Moolenaare02d7b22007-06-19 14:29:43 +00001981
1982 /* Activate */
1983 gui_focus_change((event->modifiers) & activeFlag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984}
1985
1986
1987/*
1988 * Handle the suspend/resume event
1989 * (apply to the application)
1990 */
1991 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00001992gui_mac_doSuspendEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993{
1994 /* The frontmost application just changed */
1995
1996 /* NOTE: the suspend may happen before the deactivate
1997 * seen on MacOS X
1998 */
1999
2000 /* May not need to change focus as the window will
Bram Moolenaar720c7102007-05-10 18:07:50 +00002001 * get an activate/deactivate event
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 */
2003 if (event->message & 1)
2004 /* Resume */
2005 gui_focus_change(TRUE);
2006 else
2007 /* Suspend */
2008 gui_focus_change(FALSE);
2009}
2010
2011/*
2012 * Handle the key
2013 */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002014#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002015 static pascal OSStatus
2016gui_mac_handle_window_activate(
2017 EventHandlerCallRef nextHandler,
2018 EventRef theEvent,
2019 void *data)
2020{
2021 UInt32 eventClass = GetEventClass(theEvent);
2022 UInt32 eventKind = GetEventKind(theEvent);
Bram Moolenaard68071d2006-05-02 22:08:30 +00002023
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002024 if (eventClass == kEventClassWindow)
2025 {
2026 switch (eventKind)
2027 {
2028 case kEventWindowActivated:
2029#if defined(USE_IM_CONTROL)
2030 im_on_window_switch(TRUE);
2031#endif
2032 return noErr;
2033
2034 case kEventWindowDeactivated:
2035#if defined(USE_IM_CONTROL)
2036 im_on_window_switch(FALSE);
2037#endif
2038 return noErr;
2039 }
2040 }
2041
2042 return eventNotHandledErr;
2043}
2044
2045 static pascal OSStatus
2046gui_mac_handle_text_input(
2047 EventHandlerCallRef nextHandler,
2048 EventRef theEvent,
2049 void *data)
2050{
2051 UInt32 eventClass = GetEventClass(theEvent);
2052 UInt32 eventKind = GetEventKind(theEvent);
2053
2054 if (eventClass != kEventClassTextInput)
2055 return eventNotHandledErr;
2056
2057 if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
2058 (kEventTextInputUnicodeForKeyEvent != eventKind) &&
2059 (kEventTextInputOffsetToPos != eventKind) &&
2060 (kEventTextInputPosToOffset != eventKind) &&
2061 (kEventTextInputGetSelectedText != eventKind))
2062 return eventNotHandledErr;
2063
2064 switch (eventKind)
2065 {
2066 case kEventTextInputUpdateActiveInputArea:
2067 return gui_mac_update_input_area(nextHandler, theEvent);
2068 case kEventTextInputUnicodeForKeyEvent:
2069 return gui_mac_unicode_key_event(nextHandler, theEvent);
2070
2071 case kEventTextInputOffsetToPos:
2072 case kEventTextInputPosToOffset:
2073 case kEventTextInputGetSelectedText:
2074 break;
2075 }
2076
2077 return eventNotHandledErr;
2078}
2079
2080 static pascal
2081OSStatus gui_mac_update_input_area(
2082 EventHandlerCallRef nextHandler,
2083 EventRef theEvent)
2084{
2085 return eventNotHandledErr;
2086}
2087
2088static int dialog_busy = FALSE; /* TRUE when gui_mch_dialog() wants the
2089 keys */
Bram Moolenaard68071d2006-05-02 22:08:30 +00002090
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002091# define INLINE_KEY_BUFFER_SIZE 80
2092 static pascal OSStatus
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002093gui_mac_unicode_key_event(
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002094 EventHandlerCallRef nextHandler,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002095 EventRef theEvent)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002096{
2097 /* Multibyte-friendly key event handler */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002098 OSStatus err = -1;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002099 UInt32 actualSize;
2100 UniChar *text;
2101 char_u result[INLINE_KEY_BUFFER_SIZE];
2102 short len = 0;
2103 UInt32 key_sym;
2104 char charcode;
2105 int key_char;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002106 UInt32 modifiers, vimModifiers;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002107 size_t encLen;
2108 char_u *to = NULL;
2109 Boolean isSpecial = FALSE;
2110 int i;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002111 EventRef keyEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002113 /* Mask the mouse (as per user setting) */
2114 if (p_mh)
2115 ObscureCursor();
2116
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002117 /* Don't use the keys when the dialog wants them. */
2118 if (dialog_busy)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002119 return eventNotHandledErr;
Bram Moolenaard68071d2006-05-02 22:08:30 +00002120
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002121 if (noErr != GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002122 typeUnicodeText, NULL, 0, &actualSize, NULL))
2123 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002124
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002125 text = (UniChar *)alloc(actualSize);
2126 if (!text)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002127 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002128
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002129 err = GetEventParameter(theEvent, kEventParamTextInputSendText,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002130 typeUnicodeText, NULL, actualSize, NULL, text);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002131 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002132
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002133 err = GetEventParameter(theEvent, kEventParamTextInputSendKeyboardEvent,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002134 typeEventRef, NULL, sizeof(EventRef), NULL, &keyEvent);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002135 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002136
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002137 err = GetEventParameter(keyEvent, kEventParamKeyModifiers,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002138 typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002139 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002140
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002141 err = GetEventParameter(keyEvent, kEventParamKeyCode,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002142 typeUInt32, NULL, sizeof(UInt32), NULL, &key_sym);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002143 require_noerr(err, done);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002144
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002145 err = GetEventParameter(keyEvent, kEventParamKeyMacCharCodes,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002146 typeChar, NULL, sizeof(char), NULL, &charcode);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002147 require_noerr(err, done);
2148
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002149#ifndef USE_CMD_KEY
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002150 if (modifiers & cmdKey)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002151 goto done; /* Let system handle Cmd+... */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002152#endif
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002153
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002154 key_char = charcode;
2155 vimModifiers = EventModifiers2VimModifiers(modifiers);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002156
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002157 /* Find the special key (eg., for cursor keys) */
2158 if (actualSize <= sizeof(UniChar) &&
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002159 ((text[0] < 0x20) || (text[0] == 0x7f)))
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002160 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002161 for (i = 0; special_keys[i].key_sym != (KeySym)0; ++i)
2162 if (special_keys[i].key_sym == key_sym)
2163 {
2164 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2165 special_keys[i].vim_code1);
2166 key_char = simplify_key(key_char,
2167 (int *)&vimModifiers);
2168 isSpecial = TRUE;
2169 break;
2170 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002171 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002172
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002173 /* Intercept CMD-. and CTRL-c */
2174 if (((modifiers & controlKey) && key_char == 'c') ||
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002175 ((modifiers & cmdKey) && key_char == '.'))
2176 got_int = TRUE;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002177
2178 if (!isSpecial)
2179 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002180 /* remove SHIFT for keys that are already shifted, e.g.,
2181 * '(' and '*' */
2182 if (key_char < 0x100 && !isalpha(key_char) && isprint(key_char))
2183 vimModifiers &= ~MOD_MASK_SHIFT;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002184
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002185 /* remove CTRL from keys that already have it */
2186 if (key_char < 0x20)
2187 vimModifiers &= ~MOD_MASK_CTRL;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002188
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002189 /* don't process unicode characters here */
2190 if (!IS_SPECIAL(key_char))
2191 {
2192 /* Following code to simplify and consolidate vimModifiers
2193 * taken liberally from gui_w48.c */
2194 key_char = simplify_key(key_char, (int *)&vimModifiers);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002195
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002196 /* Interpret META, include SHIFT, etc. */
2197 key_char = extract_modifiers(key_char, (int *)&vimModifiers);
2198 if (key_char == CSI)
2199 key_char = K_CSI;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002200
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002201 if (IS_SPECIAL(key_char))
2202 isSpecial = TRUE;
2203 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002204 }
2205
2206 if (vimModifiers)
2207 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002208 result[len++] = CSI;
2209 result[len++] = KS_MODIFIER;
2210 result[len++] = vimModifiers;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002211 }
2212
2213 if (isSpecial && IS_SPECIAL(key_char))
2214 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002215 result[len++] = CSI;
2216 result[len++] = K_SECOND(key_char);
2217 result[len++] = K_THIRD(key_char);
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002218 }
2219 else
2220 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002221 encLen = actualSize;
2222 to = mac_utf16_to_enc(text, actualSize, &encLen);
2223 if (to)
2224 {
2225 /* This is basically add_to_input_buf_csi() */
2226 for (i = 0; i < encLen && len < (INLINE_KEY_BUFFER_SIZE-1); ++i)
2227 {
2228 result[len++] = to[i];
2229 if (to[i] == CSI)
2230 {
2231 result[len++] = KS_EXTRA;
2232 result[len++] = (int)KE_CSI;
2233 }
2234 }
2235 vim_free(to);
2236 }
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002237 }
2238
2239 add_to_input_buf(result, len);
2240 err = noErr;
2241
2242done:
2243 vim_free(text);
2244 if (err == noErr)
2245 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002246 /* Fake event to wake up WNE (required to get
2247 * key repeat working */
2248 PostEvent(keyUp, 0);
2249 return noErr;
Bram Moolenaaradcb9492006-10-17 10:51:57 +00002250 }
2251
2252 return eventNotHandledErr;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002253}
2254#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 void
2256gui_mac_doKeyEvent(EventRecord *theEvent)
2257{
2258 /* TODO: add support for COMMAND KEY */
2259 long menu;
2260 unsigned char string[20];
2261 short num, i;
2262 short len = 0;
2263 KeySym key_sym;
2264 int key_char;
2265 int modifiers;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002266 int simplify = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267
2268 /* Mask the mouse (as per user setting) */
2269 if (p_mh)
2270 ObscureCursor();
2271
2272 /* Get the key code and it's ASCII representation */
2273 key_sym = ((theEvent->message & keyCodeMask) >> 8);
2274 key_char = theEvent->message & charCodeMask;
2275 num = 1;
2276
2277 /* Intercept CTRL-C */
2278 if (theEvent->modifiers & controlKey)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002279 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280 if (key_char == Ctrl_C && ctrl_c_interrupts)
2281 got_int = TRUE;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002282 else if ((theEvent->modifiers & ~(controlKey|shiftKey)) == 0
2283 && (key_char == '2' || key_char == '6'))
2284 {
2285 /* CTRL-^ and CTRL-@ don't work in the normal way. */
2286 if (key_char == '2')
2287 key_char = Ctrl_AT;
2288 else
2289 key_char = Ctrl_HAT;
2290 theEvent->modifiers = 0;
2291 }
2292 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293
2294 /* Intercept CMD-. */
2295 if (theEvent->modifiers & cmdKey)
2296 if (key_char == '.')
2297 got_int = TRUE;
2298
2299 /* Handle command key as per menu */
2300 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */
2301 if (theEvent->modifiers & cmdKey)
2302 /* Only accept CMD alone or with CAPLOCKS and the mouse button.
2303 * Why the mouse button? */
2304 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0)
2305 {
2306 menu = MenuKey(key_char);
2307 if (HiWord(menu))
2308 {
2309 gui_mac_handle_menu(menu);
2310 return;
2311 }
2312 }
2313
2314 /* Convert the modifiers */
2315 modifiers = EventModifiers2VimModifiers(theEvent->modifiers);
2316
2317
2318 /* Handle special keys. */
2319#if 0
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002320 /* Why has this been removed? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey)))
2322#endif
2323 {
2324 /* Find the special key (for non-printable keyt_char) */
2325 if ((key_char < 0x20) || (key_char == 0x7f))
2326 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2327 if (special_keys[i].key_sym == key_sym)
2328 {
2329# if 0
2330 /* We currently don't have not so special key */
2331 if (special_keys[i].vim_code1 == NUL)
2332 key_char = special_keys[i].vim_code0;
2333 else
2334# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002335 key_char = TO_SPECIAL(special_keys[i].vim_code0,
2336 special_keys[i].vim_code1);
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002337 simplify = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338 break;
2339 }
2340 }
2341
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002342 /* For some keys the modifier is included in the char itself. */
2343 if (simplify || key_char == TAB || key_char == ' ')
2344 key_char = simplify_key(key_char, &modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345
2346 /* Add the modifier to the input bu if needed */
2347 /* Do not want SHIFT-A or CTRL-A with modifier */
2348 if (!IS_SPECIAL(key_char)
2349 && key_sym != vk_Space
2350 && key_sym != vk_Tab
2351 && key_sym != vk_Return
2352 && key_sym != vk_Enter
2353 && key_sym != vk_Esc)
2354 {
2355#if 1
2356 /* Clear modifiers when only one modifier is set */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002357 if ((modifiers == MOD_MASK_SHIFT)
2358 || (modifiers == MOD_MASK_CTRL)
2359 || (modifiers == MOD_MASK_ALT))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 modifiers = 0;
2361#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002362 if (modifiers & MOD_MASK_CTRL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 modifiers = modifiers & ~MOD_MASK_CTRL;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002364 if (modifiers & MOD_MASK_ALT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 modifiers = modifiers & ~MOD_MASK_ALT;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002366 if (modifiers & MOD_MASK_SHIFT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 modifiers = modifiers & ~MOD_MASK_SHIFT;
2368#endif
2369 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002370 if (modifiers)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002372 string[len++] = CSI;
2373 string[len++] = KS_MODIFIER;
2374 string[len++] = modifiers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 }
2376
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002377 if (IS_SPECIAL(key_char))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002379 string[len++] = CSI;
2380 string[len++] = K_SECOND(key_char);
2381 string[len++] = K_THIRD(key_char);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 }
2383 else
2384 {
2385#ifdef FEAT_MBYTE
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002386 /* Convert characters when needed (e.g., from MacRoman to latin1).
2387 * This doesn't work for the NUL byte. */
2388 if (input_conv.vc_type != CONV_NONE && key_char > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 {
2390 char_u from[2], *to;
2391 int l;
2392
2393 from[0] = key_char;
2394 from[1] = NUL;
2395 l = 1;
2396 to = string_convert(&input_conv, from, &l);
2397 if (to != NULL)
2398 {
2399 for (i = 0; i < l && len < 19; i++)
2400 {
2401 if (to[i] == CSI)
2402 {
2403 string[len++] = KS_EXTRA;
2404 string[len++] = KE_CSI;
2405 }
2406 else
2407 string[len++] = to[i];
2408 }
2409 vim_free(to);
2410 }
2411 else
2412 string[len++] = key_char;
2413 }
2414 else
2415#endif
2416 string[len++] = key_char;
2417 }
2418
2419 if (len == 1 && string[0] == CSI)
2420 {
2421 /* Turn CSI into K_CSI. */
2422 string[ len++ ] = KS_EXTRA;
2423 string[ len++ ] = KE_CSI;
2424 }
2425
2426 add_to_input_buf(string, len);
2427}
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002428#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429
2430/*
2431 * Handle MouseClick
2432 */
2433 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002434gui_mac_doMouseDownEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435{
2436 short thePart;
2437 WindowPtr whichWindow;
2438
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002439 thePart = FindWindow(theEvent->where, &whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002441#ifdef FEAT_GUI_TABLINE
2442 /* prevent that the vim window size changes if it's activated by a
2443 click into the tab pane */
2444 if (whichWindow == drawer)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002445 return;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00002446#endif
2447
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448 switch (thePart)
2449 {
2450 case (inDesk):
2451 /* TODO: what to do? */
2452 break;
2453
2454 case (inMenuBar):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002455 gui_mac_handle_menu(MenuSelect(theEvent->where));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 break;
2457
2458 case (inContent):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002459 gui_mac_doInContentClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002460 break;
2461
2462 case (inDrag):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002463 gui_mac_doInDragClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 break;
2465
2466 case (inGrow):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002467 gui_mac_doInGrowClick(theEvent->where, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 break;
2469
2470 case (inGoAway):
2471 if (TrackGoAway(whichWindow, theEvent->where))
2472 gui_shell_closed();
2473 break;
2474
2475 case (inZoomIn):
2476 case (inZoomOut):
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 gui_mac_doInZoomClick(theEvent, whichWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 break;
2479 }
2480}
2481
2482/*
2483 * Handle MouseMoved
2484 * [this event is a moving in and out of a region]
2485 */
2486 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002487gui_mac_doMouseMovedEvent(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488{
2489 Point thePoint;
2490 int_u vimModifiers;
2491
2492 thePoint = event->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002493 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers);
2495
2496 if (!Button())
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002497 gui_mouse_moved(thePoint.h, thePoint.v);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 if (!clickIsPopup)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 gui_send_mouse_event(MOUSE_DRAG, thePoint.h,
2501 thePoint.v, FALSE, vimModifiers);
2502
2503 /* Reset the region from which we move in and out */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002504 SetRect(&dragRect, FILL_X(X_2_COL(thePoint.h)),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505 FILL_Y(Y_2_ROW(thePoint.v)),
2506 FILL_X(X_2_COL(thePoint.h)+1),
2507 FILL_Y(Y_2_ROW(thePoint.v)+1));
2508
2509 if (dragRectEnbl)
2510 dragRectControl = kCreateRect;
2511
2512}
2513
2514/*
2515 * Handle the mouse release
2516 */
2517 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002518gui_mac_doMouseUpEvent(EventRecord *theEvent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519{
2520 Point thePoint;
2521 int_u vimModifiers;
2522
2523 /* TODO: Properly convert the Contextual menu mouse-up */
2524 /* Potential source of the double menu */
2525 lastMouseTick = theEvent->when;
2526 dragRectEnbl = FALSE;
2527 dragRectControl = kCreateEmpty;
2528 thePoint = theEvent->where;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002529 GlobalToLocal(&thePoint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530
2531 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 if (clickIsPopup)
2533 {
2534 vimModifiers &= ~MOUSE_CTRL;
2535 clickIsPopup = FALSE;
2536 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002537 gui_send_mouse_event(MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538}
2539
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 static pascal OSStatus
2541gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent,
2542 void *data)
2543{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 Point point;
2545 Rect bounds;
2546 UInt32 mod;
2547 SInt32 delta;
2548 int_u vim_mod;
Bram Moolenaar621e2fd2006-08-22 19:36:17 +00002549 EventMouseWheelAxis axis;
2550
2551 if (noErr == GetEventParameter(theEvent, kEventParamMouseWheelAxis,
2552 typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis)
2553 && axis != kEventMouseWheelAxisY)
2554 goto bail; /* Vim only does up-down scrolling */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555
2556 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta,
2557 typeSInt32, NULL, sizeof(SInt32), NULL, &delta))
2558 goto bail;
2559 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation,
2560 typeQDPoint, NULL, sizeof(Point), NULL, &point))
2561 goto bail;
2562 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers,
2563 typeUInt32, NULL, sizeof(UInt32), NULL, &mod))
2564 goto bail;
2565
2566 vim_mod = 0;
2567 if (mod & shiftKey)
2568 vim_mod |= MOUSE_SHIFT;
2569 if (mod & controlKey)
2570 vim_mod |= MOUSE_CTRL;
2571 if (mod & optionKey)
2572 vim_mod |= MOUSE_ALT;
2573
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds))
2575 {
2576 point.h -= bounds.left;
2577 point.v -= bounds.top;
2578 }
2579
2580 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5,
2581 point.h, point.v, FALSE, vim_mod);
2582
Bram Moolenaarc236c162008-07-13 17:41:49 +00002583 /* post a bogus event to wake up WaitNextEvent */
2584 PostEvent(keyUp, 0);
2585
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 return noErr;
2587
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002588bail:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 /*
2590 * when we fail give any additional callback handler a chance to perform
2591 * it's actions
2592 */
2593 return CallNextEventHandler(nextHandler, theEvent);
2594}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595
Bram Moolenaare00289d2010-08-14 21:56:42 +02002596 void
2597gui_mch_mousehide(int hide)
2598{
2599 /* TODO */
2600}
2601
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602#if 0
2603
2604/*
2605 * This would be the normal way of invoking the contextual menu
2606 * but the Vim API doesn't seem to a support a request to get
2607 * the menu that we should display
2608 */
2609 void
2610gui_mac_handle_contextual_menu(event)
2611 EventRecord *event;
2612{
2613/*
2614 * Clone PopUp to use menu
2615 * Create a object descriptor for the current selection
2616 * Call the procedure
2617 */
2618
2619// Call to Handle Popup
2620 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
2621
2622 if (status != noErr)
2623 return;
2624
2625 if (CntxType == kCMMenuItemSelected)
2626 {
2627 /* Handle the menu CntxMenuID, CntxMenuItem */
2628 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002629 /* But what about the current menu, is the many changed by ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002630 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631 }
2632 else if (CntxMenuID == kCMShowHelpSelected)
2633 {
2634 /* Should come up with the help */
2635 }
2636
2637}
2638#endif
2639
2640/*
2641 * Handle menubar selection
2642 */
2643 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002644gui_mac_handle_menu(long menuChoice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645{
2646 short menu = HiWord(menuChoice);
2647 short item = LoWord(menuChoice);
2648 vimmenu_T *theVimMenu = root_menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649
2650 if (menu == 256) /* TODO: use constant or gui.xyz */
2651 {
2652 if (item == 1)
2653 gui_mch_beep(); /* TODO: Popup dialog or do :intro */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654 }
2655 else if (item != 0)
2656 {
2657 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu);
2658
2659 if (theVimMenu)
2660 gui_menu_cb(theVimMenu);
2661 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002662 HiliteMenu(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663}
2664
2665/*
2666 * Dispatch the event to proper handler
2667 */
2668
2669 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002670gui_mac_handle_event(EventRecord *event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671{
2672 OSErr error;
2673
2674 /* Handle contextual menu right now (if needed) */
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002675 if (IsShowContextualMenuClick(event))
2676 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677# if 0
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002678 gui_mac_handle_contextual_menu(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679# else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002680 gui_mac_doMouseDownEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681# endif
Bram Moolenaar1b60e502008-03-12 13:40:54 +00002682 return;
Bram Moolenaare02d7b22007-06-19 14:29:43 +00002683 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684
2685 /* Handle normal event */
2686 switch (event->what)
2687 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002688#ifndef USE_CARBONKEYHANDLER
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 case (keyDown):
2690 case (autoKey):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002691 gui_mac_doKeyEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 break;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002693#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002694 case (keyUp):
Bram Moolenaard68071d2006-05-02 22:08:30 +00002695 /* We don't care about when the key is released */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 break;
2697
2698 case (mouseDown):
2699 gui_mac_doMouseDownEvent(event);
2700 break;
2701
2702 case (mouseUp):
2703 gui_mac_doMouseUpEvent(event);
2704 break;
2705
2706 case (updateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002707 gui_mac_doUpdateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 break;
2709
2710 case (diskEvt):
2711 /* We don't need special handling for disk insertion */
2712 break;
2713
2714 case (activateEvt):
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002715 gui_mac_doActivateEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 break;
2717
2718 case (osEvt):
2719 switch ((event->message >> 24) & 0xFF)
2720 {
2721 case (0xFA): /* mouseMovedMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002722 gui_mac_doMouseMovedEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 break;
2724 case (0x01): /* suspendResumeMessage */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002725 gui_mac_doSuspendEvent(event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 break;
2727 }
2728 break;
2729
2730#ifdef USE_AEVENT
2731 case (kHighLevelEvent):
2732 /* Someone's talking to us, through AppleEvents */
2733 error = AEProcessAppleEvent(event); /* TODO: Error Handling */
2734 break;
2735#endif
2736 }
2737}
2738
2739/*
2740 * ------------------------------------------------------------
2741 * Unknown Stuff
2742 * ------------------------------------------------------------
2743 */
2744
2745
2746 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002747gui_mac_find_font(char_u *font_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748{
2749 char_u c;
2750 char_u *p;
2751 char_u pFontName[256];
2752 Str255 systemFontname;
2753 short font_id;
2754 short size=9;
2755 GuiFont font;
2756#if 0
2757 char_u *fontNamePtr;
2758#endif
2759
2760 for (p = font_name; ((*p != 0) && (*p != ':')); p++)
2761 ;
2762
2763 c = *p;
2764 *p = 0;
2765
2766#if 1
2767 STRCPY(&pFontName[1], font_name);
2768 pFontName[0] = STRLEN(font_name);
2769 *p = c;
2770
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002771 /* Get the font name, minus the style suffix (:h, etc) */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002772 char_u fontName[256];
2773 char_u *styleStart = vim_strchr(font_name, ':');
2774 size_t fontNameLen = styleStart ? styleStart - font_name : STRLEN(fontName);
2775 vim_strncpy(fontName, font_name, fontNameLen);
2776
2777 ATSUFontID fontRef;
2778 FMFontStyle fontStyle;
2779 font_id = 0;
2780
2781 if (ATSUFindFontFromName(&pFontName[1], pFontName[0], kFontFullName,
2782 kFontMacintoshPlatform, kFontNoScriptCode, kFontNoLanguageCode,
2783 &fontRef) == noErr)
2784 {
2785 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2786 font_id = 0;
2787 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002788
2789 if (font_id == 0)
2790 {
2791 /*
2792 * Try again, this time replacing underscores in the font name
2793 * with spaces (:set guifont allows the two to be used
2794 * interchangeably; the Font Manager doesn't).
2795 */
2796 int i, changed = FALSE;
2797
2798 for (i = pFontName[0]; i > 0; --i)
2799 {
2800 if (pFontName[i] == '_')
2801 {
2802 pFontName[i] = ' ';
2803 changed = TRUE;
2804 }
2805 }
2806 if (changed)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002807 if (ATSUFindFontFromName(&pFontName[1], pFontName[0],
2808 kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
2809 kFontNoLanguageCode, &fontRef) == noErr)
2810 {
2811 if (FMGetFontFamilyInstanceFromFont(fontRef, &font_id, &fontStyle) != noErr)
2812 font_id = 0;
2813 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00002814 }
2815
Bram Moolenaar071d4272004-06-13 20:20:40 +00002816#else
2817 /* name = C2Pascal_save(menu->dname); */
2818 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name);
2819
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002820 GetFNum(fontNamePtr, &font_id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821#endif
2822
2823
2824 if (font_id == 0)
2825 {
2826 /* Oups, the system font was it the one the user want */
2827
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002828 if (FMGetFontFamilyName(systemFont, systemFontname) != noErr)
2829 return NOFONT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 if (!EqualString(pFontName, systemFontname, false, false))
2831 return NOFONT;
2832 }
2833 if (*p == ':')
2834 {
2835 p++;
2836 /* Set the values found after ':' */
2837 while (*p)
2838 {
2839 switch (*p++)
2840 {
2841 case 'h':
2842 size = points_to_pixels(p, &p, TRUE);
2843 break;
2844 /*
2845 * TODO: Maybe accept width and styles
2846 */
2847 }
2848 while (*p == ':')
2849 p++;
2850 }
2851 }
2852
2853 if (size < 1)
2854 size = 1; /* Avoid having a size of 0 with system font */
2855
2856 font = (size << 16) + ((long) font_id & 0xFFFF);
2857
2858 return font;
2859}
2860
2861/*
2862 * ------------------------------------------------------------
Bram Moolenaar720c7102007-05-10 18:07:50 +00002863 * GUI_MCH functionality
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864 * ------------------------------------------------------------
2865 */
2866
2867/*
2868 * Parse the GUI related command-line arguments. Any arguments used are
2869 * deleted from argv, and *argc is decremented accordingly. This is called
2870 * when vim is started, whether or not the GUI has been started.
2871 */
2872 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00002873gui_mch_prepare(int *argc, char **argv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874{
2875 /* TODO: Move most of this stuff toward gui_mch_init */
2876#ifdef USE_EXE_NAME
2877 FSSpec applDir;
2878# ifndef USE_FIND_BUNDLE_PATH
2879 short applVRefNum;
2880 long applDirID;
2881 Str255 volName;
2882# else
2883 ProcessSerialNumber psn;
2884 FSRef applFSRef;
2885# endif
2886#endif
2887
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888#if 0
2889 InitCursor();
2890
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892
2893#ifdef USE_AEVENT
2894 (void) InstallAEHandlers();
2895#endif
2896
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002897 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002899 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002901 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902
2903 DrawMenuBar();
2904
2905
2906#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002907 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002909 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910#endif
2911
2912
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913 CreateNewWindow(kDocumentWindowClass,
2914 kWindowResizableAttribute | kWindowCollapseBoxAttribute,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002915 &windRect, &gui.VimWindow);
2916 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917
2918 gui.char_width = 7;
2919 gui.char_height = 11;
2920 gui.char_ascent = 6;
2921 gui.num_rows = 24;
2922 gui.num_cols = 80;
2923 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
2924
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002925 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
2926 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927
2928 dragRectEnbl = FALSE;
2929 dragRgn = NULL;
2930 dragRectControl = kCreateEmpty;
2931 cursorRgn = NewRgn();
2932#endif
2933#ifdef USE_EXE_NAME
2934# ifndef USE_FIND_BUNDLE_PATH
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002935 HGetVol(volName, &applVRefNum, &applDirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002936 /* TN2015: mention a possible bad VRefNum */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002937 FSMakeFSSpec(applVRefNum, applDirID, "\p", &applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938# else
2939 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr)
2940 * of TN2015
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002942 (void)GetCurrentProcess(&psn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 /* if (err != noErr) return err; */
2944
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002945 (void)GetProcessBundleLocation(&psn, &applFSRef);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 /* if (err != noErr) return err; */
2947
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002948 (void)FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949
2950 /* This technic return NIL when we disallow_gui */
2951# endif
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002952 exe_name = FullPathFromFSSpec_save(applDir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954}
2955
2956#ifndef ALWAYS_USE_GUI
2957/*
2958 * Check if the GUI can be started. Called before gvimrc is sourced.
2959 * Return OK or FAIL.
2960 */
2961 int
2962gui_mch_init_check(void)
2963{
2964 /* TODO: For MacOS X find a way to return FAIL, if the user logged in
2965 * using the >console
2966 */
2967 if (disallow_gui) /* see main.c for reason to disallow */
2968 return FAIL;
2969 return OK;
2970}
2971#endif
2972
2973 static OSErr
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00002974receiveHandler(WindowRef theWindow, void *handlerRefCon, DragRef theDrag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975{
2976 int x, y;
2977 int_u modifiers;
2978 char_u **fnames = NULL;
2979 int count;
2980 int i, j;
2981
2982 /* Get drop position, modifiers and count of items */
2983 {
2984 Point point;
2985 SInt16 mouseUpModifiers;
2986 UInt16 countItem;
2987
2988 GetDragMouse(theDrag, &point, NULL);
2989 GlobalToLocal(&point);
2990 x = point.h;
2991 y = point.v;
2992 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
2993 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
2994 CountDragItems(theDrag, &countItem);
2995 count = countItem;
2996 }
2997
2998 fnames = (char_u **)alloc(count * sizeof(char_u *));
2999 if (fnames == NULL)
3000 return dragNotAcceptedErr;
3001
3002 /* Get file names dropped */
3003 for (i = j = 0; i < count; ++i)
3004 {
3005 DragItemRef item;
3006 OSErr err;
3007 Size size;
3008 FlavorType type = flavorTypeHFS;
3009 HFSFlavor hfsFlavor;
3010
3011 fnames[i] = NULL;
3012 GetDragItemReferenceNumber(theDrag, i + 1, &item);
3013 err = GetFlavorDataSize(theDrag, item, type, &size);
3014 if (err != noErr || size > sizeof(hfsFlavor))
3015 continue;
3016 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
3017 if (err != noErr)
3018 continue;
3019 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
3020 }
3021 count = j;
3022
3023 gui_handle_drop(x, y, modifiers, fnames, count);
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003024
3025 /* Fake mouse event to wake from stall */
3026 PostEvent(mouseUp, 0);
3027
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 return noErr;
3029}
3030
3031/*
3032 * Initialise the GUI. Create all the windows, set up all the call-backs
3033 * etc.
3034 */
3035 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003036gui_mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037{
3038 /* TODO: Move most of this stuff toward gui_mch_init */
Bram Moolenaar39858af2008-03-12 20:48:13 +00003039 Rect windRect;
3040 MenuHandle pomme;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 EventHandlerRef mouseWheelHandlerRef;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003042 EventTypeSpec eventTypeSpec;
Bram Moolenaar39858af2008-03-12 20:48:13 +00003043 ControlRef rootControl;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003044
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003045 if (Gestalt(gestaltSystemVersion, &gMacSystemVersion) != noErr)
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003046 gMacSystemVersion = 0x1000; /* TODO: Default to minimum sensible value */
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003047
Bram Moolenaar071d4272004-06-13 20:20:40 +00003048#if 1
3049 InitCursor();
3050
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 RegisterAppearanceClient();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052
3053#ifdef USE_AEVENT
3054 (void) InstallAEHandlers();
3055#endif
3056
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003057 pomme = NewMenu(256, "\p\024"); /* 0x14= = Apple Menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003059 AppendMenu(pomme, "\pAbout VIM");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003061 InsertMenu(pomme, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062
3063 DrawMenuBar();
3064
3065
3066#ifndef USE_OFFSETED_WINDOW
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003067 SetRect(&windRect, 10, 48, 10+80*7 + 16, 48+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003069 SetRect(&windRect, 300, 40, 300+80*7 + 16, 40+24*11);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070#endif
3071
3072 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 zoomDocProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 (WindowPtr)-1L, true, 0);
Bram Moolenaare02d7b22007-06-19 14:29:43 +00003075 CreateRootControl(gui.VimWindow, &rootControl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
3077 gui.VimWindow, NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003078 SetPortWindowPort(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079
3080 gui.char_width = 7;
3081 gui.char_height = 11;
3082 gui.char_ascent = 6;
3083 gui.num_rows = 24;
3084 gui.num_cols = 80;
3085 gui.in_focus = TRUE; /* For the moment -> syn. of front application */
3086
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003087 gScrollAction = NewControlActionUPP(gui_mac_scroll_action);
3088 gScrollDrag = NewControlActionUPP(gui_mac_drag_thumb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003090 /* Install Carbon event callbacks. */
3091 (void)InstallFontPanelHandler();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092
3093 dragRectEnbl = FALSE;
3094 dragRgn = NULL;
3095 dragRectControl = kCreateEmpty;
3096 cursorRgn = NewRgn();
3097#endif
3098 /* Display any pending error messages */
3099 display_errors();
3100
3101 /* Get background/foreground colors from system */
Bram Moolenaar720c7102007-05-10 18:07:50 +00003102 /* TODO: do the appropriate call to get real defaults */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103 gui.norm_pixel = 0x00000000;
3104 gui.back_pixel = 0x00FFFFFF;
3105
3106 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3107 * file). */
3108 set_normal_colors();
3109
3110 /*
3111 * Check that none of the colors are the same as the background color.
3112 * Then store the current values as the defaults.
3113 */
3114 gui_check_colors();
3115 gui.def_norm_pixel = gui.norm_pixel;
3116 gui.def_back_pixel = gui.back_pixel;
3117
3118 /* Get the colors for the highlight groups (gui_check_colors() might have
3119 * changed them) */
3120 highlight_gui_started();
3121
3122 /*
3123 * Setting the gui constants
3124 */
3125#ifdef FEAT_MENU
3126 gui.menu_height = 0;
3127#endif
3128 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */
3129 gui.border_offset = gui.border_width = 2;
3130
Bram Moolenaar720c7102007-05-10 18:07:50 +00003131 /* If Quartz-style text anti aliasing is available (see
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 gui_mch_draw_string() below), enable it for all font sizes. */
3133 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 eventTypeSpec.eventClass = kEventClassMouse;
3136 eventTypeSpec.eventKind = kEventMouseWheelMoved;
3137 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel);
3138 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1,
3139 &eventTypeSpec, NULL, &mouseWheelHandlerRef))
3140 {
3141 mouseWheelHandlerRef = NULL;
3142 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
3143 mouseWheelHandlerUPP = NULL;
3144 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003146#ifdef USE_CARBONKEYHANDLER
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003147 InterfaceTypeList supportedServices = { kUnicodeDocument };
3148 NewTSMDocument(1, supportedServices, &gTSMDocument, 0);
3149
3150 /* We don't support inline input yet, use input window by default */
3151 UseInputWindow(gTSMDocument, TRUE);
3152
3153 /* Should we activate the document by default? */
3154 // ActivateTSMDocument(gTSMDocument);
3155
3156 EventTypeSpec textEventTypes[] = {
3157 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
3158 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
3159 { kEventClassTextInput, kEventTextInputPosToOffset },
3160 { kEventClassTextInput, kEventTextInputOffsetToPos },
3161 };
3162
3163 keyEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_text_input);
3164 if (noErr != InstallApplicationEventHandler(keyEventHandlerUPP,
3165 NR_ELEMS(textEventTypes),
3166 textEventTypes, NULL, NULL))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003167 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003168 DisposeEventHandlerUPP(keyEventHandlerUPP);
3169 keyEventHandlerUPP = NULL;
3170 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003171
3172 EventTypeSpec windowEventTypes[] = {
3173 { kEventClassWindow, kEventWindowActivated },
3174 { kEventClassWindow, kEventWindowDeactivated },
3175 };
3176
3177 /* Install window event handler to support TSMDocument activate and
3178 * deactivate */
3179 winEventHandlerUPP = NewEventHandlerUPP(gui_mac_handle_window_activate);
3180 if (noErr != InstallWindowEventHandler(gui.VimWindow,
3181 winEventHandlerUPP,
3182 NR_ELEMS(windowEventTypes),
3183 windowEventTypes, NULL, NULL))
3184 {
3185 DisposeEventHandlerUPP(winEventHandlerUPP);
3186 winEventHandlerUPP = NULL;
3187 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188#endif
3189
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003190/*
3191#ifdef FEAT_MBYTE
3192 set_option_value((char_u *)"encoding", 0L, (char_u *)"utf-8", 0);
3193#endif
3194*/
3195
Bram Moolenaar79ee3152007-04-26 16:20:50 +00003196#ifdef FEAT_GUI_TABLINE
3197 /*
3198 * Create the tabline
3199 */
3200 initialise_tabline();
3201#endif
3202
Bram Moolenaar071d4272004-06-13 20:20:40 +00003203 /* TODO: Load bitmap if using TOOLBAR */
3204 return OK;
3205}
3206
3207/*
3208 * Called when the foreground or background color has been changed.
3209 */
3210 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003211gui_mch_new_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212{
3213 /* TODO:
3214 * This proc is called when Normal is set to a value
Bram Moolenaar68dfcdf2011-12-14 15:07:29 +01003215 * so what must be done? I don't know
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 */
3217}
3218
3219/*
3220 * Open the GUI window which was created by a call to gui_mch_init().
3221 */
3222 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003223gui_mch_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224{
3225 ShowWindow(gui.VimWindow);
3226
3227 if (gui_win_x != -1 && gui_win_y != -1)
3228 gui_mch_set_winpos(gui_win_x, gui_win_y);
3229
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 /*
3231 * Make the GUI the foreground process (in case it was launched
3232 * from the Terminal or via :gui).
3233 */
3234 {
3235 ProcessSerialNumber psn;
3236 if (GetCurrentProcess(&psn) == noErr)
3237 SetFrontProcess(&psn);
3238 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239
3240 return OK;
3241}
3242
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003243#ifdef USE_ATSUI_DRAWING
3244 static void
3245gui_mac_dispose_atsui_style(void)
3246{
3247 if (p_macatsui && gFontStyle)
3248 ATSUDisposeStyle(gFontStyle);
3249#ifdef FEAT_MBYTE
3250 if (p_macatsui && gWideFontStyle)
3251 ATSUDisposeStyle(gWideFontStyle);
3252#endif
3253}
3254#endif
3255
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 void
3257gui_mch_exit(int rc)
3258{
3259 /* TODO: find out all what is missing here? */
3260 DisposeRgn(cursorRgn);
3261
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003262#ifdef USE_CARBONKEYHANDLER
3263 if (keyEventHandlerUPP)
3264 DisposeEventHandlerUPP(keyEventHandlerUPP);
3265#endif
3266
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 if (mouseWheelHandlerUPP != NULL)
3268 DisposeEventHandlerUPP(mouseWheelHandlerUPP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003270#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003271 gui_mac_dispose_atsui_style();
3272#endif
3273
3274#ifdef USE_CARBONKEYHANDLER
3275 FixTSMDocument(gTSMDocument);
3276 DeactivateTSMDocument(gTSMDocument);
3277 DeleteTSMDocument(gTSMDocument);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003278#endif
3279
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280 /* Exit to shell? */
3281 exit(rc);
3282}
3283
3284/*
3285 * Get the position of the top left corner of the window.
3286 */
3287 int
3288gui_mch_get_winpos(int *x, int *y)
3289{
3290 /* TODO */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 Rect bounds;
3292 OSStatus status;
3293
3294 /* Carbon >= 1.0.2, MacOS >= 8.5 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003295 status = GetWindowBounds(gui.VimWindow, kWindowStructureRgn, &bounds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296
3297 if (status != noErr)
3298 return FAIL;
3299 *x = bounds.left;
3300 *y = bounds.top;
3301 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302}
3303
3304/*
3305 * Set the position of the top left corner of the window to the given
3306 * coordinates.
3307 */
3308 void
3309gui_mch_set_winpos(int x, int y)
3310{
3311 /* TODO: Should make sure the window is move within range
3312 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width
3313 */
Bram Moolenaarec831732007-08-30 10:51:14 +00003314 MoveWindowStructure(gui.VimWindow, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315}
3316
3317 void
3318gui_mch_set_shellsize(
3319 int width,
3320 int height,
3321 int min_width,
3322 int min_height,
3323 int base_width,
Bram Moolenaarafa24992006-03-27 20:58:26 +00003324 int base_height,
3325 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 CGrafPtr VimPort;
3328 Rect VimBound;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329
3330 if (gui.which_scrollbars[SBAR_LEFT])
3331 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003332 VimPort = GetWindowPort(gui.VimWindow);
3333 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334 VimBound.left = -gui.scrollbar_width; /* + 1;*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003335 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003336 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 }
3338 else
3339 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003340 VimPort = GetWindowPort(gui.VimWindow);
3341 GetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 VimBound.left = 0;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003343 SetPortBounds(VimPort, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 }
3345
3346 SizeWindow(gui.VimWindow, width, height, TRUE);
3347
3348 gui_resize_shell(width, height);
3349}
3350
3351/*
3352 * Get the screen dimensions.
3353 * Allow 10 pixels for horizontal borders, 40 for vertical borders.
3354 * Is there no way to find out how wide the borders really are?
Bram Moolenaar720c7102007-05-10 18:07:50 +00003355 * TODO: Add live update of those value on suspend/resume.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 */
3357 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003358gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359{
3360 GDHandle dominantDevice = GetMainDevice();
3361 Rect screenRect = (**dominantDevice).gdRect;
3362
3363 *screen_w = screenRect.right - 10;
3364 *screen_h = screenRect.bottom - 40;
3365}
3366
3367
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003368/*
3369 * Open the Font Panel and wait for the user to select a font and
3370 * close the panel. Then fill the buffer pointed to by font_name with
3371 * the name and size of the selected font and return the font's handle,
3372 * or NOFONT in case of an error.
3373 */
3374 static GuiFont
3375gui_mac_select_font(char_u *font_name)
3376{
3377 GuiFont selected_font = NOFONT;
3378 OSStatus status;
3379 FontSelectionQDStyle curr_font;
3380
3381 /* Initialize the Font Panel with the current font. */
3382 curr_font.instance.fontFamily = gui.norm_font & 0xFFFF;
3383 curr_font.size = (gui.norm_font >> 16);
3384 /* TODO: set fontStyle once styles are supported in gui_mac_find_font() */
3385 curr_font.instance.fontStyle = 0;
3386 curr_font.hasColor = false;
3387 curr_font.version = 0; /* version number of the style structure */
3388 status = SetFontInfoForSelection(kFontSelectionQDType,
3389 /*numStyles=*/1, &curr_font, /*eventTarget=*/NULL);
3390
3391 gFontPanelInfo.family = curr_font.instance.fontFamily;
3392 gFontPanelInfo.style = curr_font.instance.fontStyle;
3393 gFontPanelInfo.size = curr_font.size;
3394
3395 /* Pop up the Font Panel. */
3396 status = FPShowHideFontPanel();
3397 if (status == noErr)
3398 {
3399 /*
3400 * The Font Panel is modeless. We really need it to be modal,
3401 * so we spin in an event loop until the panel is closed.
3402 */
3403 gFontPanelInfo.isPanelVisible = true;
3404 while (gFontPanelInfo.isPanelVisible)
3405 {
3406 EventRecord e;
3407 WaitNextEvent(everyEvent, &e, /*sleep=*/20, /*mouseRgn=*/NULL);
3408 }
3409
3410 GetFontPanelSelection(font_name);
3411 selected_font = gui_mac_find_font(font_name);
3412 }
3413 return selected_font;
3414}
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003415
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003416#ifdef USE_ATSUI_DRAWING
3417 static void
3418gui_mac_create_atsui_style(void)
3419{
3420 if (p_macatsui && gFontStyle == NULL)
3421 {
3422 if (ATSUCreateStyle(&gFontStyle) != noErr)
3423 gFontStyle = NULL;
3424 }
3425#ifdef FEAT_MBYTE
3426 if (p_macatsui && gWideFontStyle == NULL)
3427 {
3428 if (ATSUCreateStyle(&gWideFontStyle) != noErr)
3429 gWideFontStyle = NULL;
3430 }
3431#endif
3432
3433 p_macatsui_last = p_macatsui;
3434}
3435#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436
3437/*
3438 * Initialise vim to use the font with the given name. Return FAIL if the font
3439 * could not be loaded, OK otherwise.
3440 */
3441 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003442gui_mch_init_font(char_u *font_name, int fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443{
3444 /* TODO: Add support for bold italic underline proportional etc... */
3445 Str255 suggestedFont = "\pMonaco";
Bram Moolenaar05159a02005-02-26 23:04:13 +00003446 int suggestedSize = 10;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 FontInfo font_info;
3448 short font_id;
3449 GuiFont font;
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003450 char_u used_font_name[512];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003452#ifdef USE_ATSUI_DRAWING
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003453 gui_mac_create_atsui_style();
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003454#endif
3455
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456 if (font_name == NULL)
3457 {
3458 /* First try to get the suggested font */
3459 GetFNum(suggestedFont, &font_id);
3460
3461 if (font_id == 0)
3462 {
3463 /* Then pickup the standard application font */
3464 font_id = GetAppFont();
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003465 STRCPY(used_font_name, "default");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003467 else
3468 STRCPY(used_font_name, "Monaco");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF);
3470 }
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003471 else if (STRCMP(font_name, "*") == 0)
3472 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003473 char_u *new_p_guifont;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003474
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003475 font = gui_mac_select_font(used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003476 if (font == NOFONT)
3477 return FAIL;
3478
3479 /* Set guifont to the name of the selected font. */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003480 new_p_guifont = alloc(STRLEN(used_font_name) + 1);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003481 if (new_p_guifont != NULL)
3482 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003483 STRCPY(new_p_guifont, used_font_name);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00003484 vim_free(p_guifont);
3485 p_guifont = new_p_guifont;
3486 /* Replace spaces in the font name with underscores. */
3487 for ( ; *new_p_guifont; ++new_p_guifont)
3488 {
3489 if (*new_p_guifont == ' ')
3490 *new_p_guifont = '_';
3491 }
3492 }
3493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494 else
3495 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003496 font = gui_mac_find_font(font_name);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003497 vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498
3499 if (font == NOFONT)
3500 return FAIL;
3501 }
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003502
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 gui.norm_font = font;
3504
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003505 hl_set_font_name(used_font_name);
3506
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003507 TextSize(font >> 16);
3508 TextFont(font & 0xFFFF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003510 GetFontInfo(&font_info);
3511
3512 gui.char_ascent = font_info.ascent;
3513 gui.char_width = CharWidth('_');
3514 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3515
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003516#ifdef USE_ATSUI_DRAWING
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003517 if (p_macatsui && gFontStyle)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003518 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003519#endif
3520
Bram Moolenaar071d4272004-06-13 20:20:40 +00003521 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522}
3523
Bram Moolenaar02743632005-07-25 20:42:36 +00003524/*
3525 * Adjust gui.char_height (after 'linespace' was changed).
3526 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003528gui_mch_adjust_charheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529{
3530 FontInfo font_info;
3531
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003532 GetFontInfo(&font_info);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003533 gui.char_height = font_info.ascent + font_info.descent + p_linespace;
3534 gui.char_ascent = font_info.ascent + p_linespace / 2;
3535 return OK;
3536}
3537
3538/*
3539 * Get a font structure for highlighting.
3540 */
3541 GuiFont
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003542gui_mch_get_font(char_u *name, int giveErrorIfMissing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543{
3544 GuiFont font;
3545
3546 font = gui_mac_find_font(name);
3547
3548 if (font == NOFONT)
3549 {
3550 if (giveErrorIfMissing)
3551 EMSG2(_(e_font), name);
3552 return NOFONT;
3553 }
3554 /*
3555 * TODO : Accept only monospace
3556 */
3557
3558 return font;
3559}
3560
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003561#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003563 * Return the name of font "font" in allocated memory.
3564 * Don't know how to get the actual name, thus use the provided name.
3565 */
3566 char_u *
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003567gui_mch_get_fontname(GuiFont font, char_u *name)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003568{
3569 if (name == NULL)
3570 return NULL;
3571 return vim_strsave(name);
3572}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003573#endif
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003574
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003575#ifdef USE_ATSUI_DRAWING
3576 static void
3577gui_mac_set_font_attributes(GuiFont font)
3578{
3579 ATSUFontID fontID;
3580 Fixed fontSize;
3581 Fixed fontWidth;
3582
3583 fontID = font & 0xFFFF;
3584 fontSize = Long2Fix(font >> 16);
3585 fontWidth = Long2Fix(gui.char_width);
3586
3587 ATSUAttributeTag attribTags[] =
3588 {
3589 kATSUFontTag, kATSUSizeTag, kATSUImposeWidthTag,
3590 kATSUMaxATSUITagValue + 1
3591 };
3592
3593 ByteCount attribSizes[] =
3594 {
3595 sizeof(ATSUFontID), sizeof(Fixed), sizeof(fontWidth),
3596 sizeof(font)
3597 };
3598
3599 ATSUAttributeValuePtr attribValues[] =
3600 {
3601 &fontID, &fontSize, &fontWidth, &font
3602 };
3603
3604 if (FMGetFontFromFontFamilyInstance(fontID, 0, &fontID, NULL) == noErr)
3605 {
3606 if (ATSUSetAttributes(gFontStyle,
3607 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3608 attribTags, attribSizes, attribValues) != noErr)
3609 {
3610# ifndef NDEBUG
3611 fprintf(stderr, "couldn't set font style\n");
3612# endif
3613 ATSUDisposeStyle(gFontStyle);
3614 gFontStyle = NULL;
3615 }
3616
3617#ifdef FEAT_MBYTE
3618 if (has_mbyte)
3619 {
3620 /* FIXME: we should use a more mbyte sensitive way to support
3621 * wide font drawing */
3622 fontWidth = Long2Fix(gui.char_width * 2);
3623
3624 if (ATSUSetAttributes(gWideFontStyle,
3625 (sizeof attribTags) / sizeof(ATSUAttributeTag),
3626 attribTags, attribSizes, attribValues) != noErr)
3627 {
3628 ATSUDisposeStyle(gWideFontStyle);
3629 gWideFontStyle = NULL;
3630 }
3631 }
3632#endif
3633 }
3634}
3635#endif
3636
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00003637/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 * Set the current text font.
3639 */
3640 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003641gui_mch_set_font(GuiFont font)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003643#ifdef USE_ATSUI_DRAWING
3644 GuiFont currFont;
3645 ByteCount actualFontByteCount;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003646
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003647 if (p_macatsui && gFontStyle)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003648 {
3649 /* Avoid setting same font again */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003650 if (ATSUGetAttribute(gFontStyle, kATSUMaxATSUITagValue + 1,
3651 sizeof(font), &currFont, &actualFontByteCount) == noErr
3652 && actualFontByteCount == (sizeof font))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003653 {
3654 if (currFont == font)
3655 return;
3656 }
3657
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003658 gui_mac_set_font_attributes(font);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003659 }
3660
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00003661 if (p_macatsui && !gIsFontFallbackSet)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003662 {
3663 /* Setup automatic font substitution. The user's guifontwide
3664 * is tried first, then the system tries other fonts. */
3665/*
3666 ATSUAttributeTag fallbackTags[] = { kATSULineFontFallbacksTag };
3667 ByteCount fallbackSizes[] = { sizeof(ATSUFontFallbacks) };
3668 ATSUCreateFontFallbacks(&gFontFallbacks);
3669 ATSUSetObjFontFallbacks(gFontFallbacks, );
3670*/
3671 if (gui.wide_font)
3672 {
3673 ATSUFontID fallbackFonts;
3674 gIsFontFallbackSet = TRUE;
3675
3676 if (FMGetFontFromFontFamilyInstance(
3677 (gui.wide_font & 0xFFFF),
3678 0,
3679 &fallbackFonts,
3680 NULL) == noErr)
3681 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00003682 ATSUSetFontFallbacks((sizeof fallbackFonts)/sizeof(ATSUFontID),
3683 &fallbackFonts,
3684 kATSUSequentialFallbacksPreferred);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003685 }
3686/*
3687 ATSUAttributeValuePtr fallbackValues[] = { };
3688*/
3689 }
3690 }
3691#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692 TextSize(font >> 16);
3693 TextFont(font & 0xFFFF);
3694}
3695
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696/*
3697 * If a font is not going to be used, free its structure.
3698 */
3699 void
3700gui_mch_free_font(font)
3701 GuiFont font;
3702{
3703 /*
3704 * Free font when "font" is not 0.
3705 * Nothing to do in the current implementation, since
3706 * nothing is allocated for each font used.
3707 */
3708}
3709
3710 static int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003711hex_digit(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712{
3713 if (isdigit(c))
3714 return c - '0';
3715 c = TOLOWER_ASC(c);
3716 if (c >= 'a' && c <= 'f')
3717 return c - 'a' + 10;
3718 return -1000;
3719}
3720
3721/*
3722 * Return the Pixel value (color) for the given color name. This routine was
3723 * pretty much taken from example code in the Silicon Graphics OSF/Motif
3724 * Programmer's Guide.
3725 * Return INVALCOLOR when failed.
3726 */
3727 guicolor_T
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003728gui_mch_get_color(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729{
3730 /* TODO: Add support for the new named color of MacOS 8
3731 */
3732 RGBColor MacColor;
3733// guicolor_T color = 0;
3734
3735 typedef struct guicolor_tTable
3736 {
3737 char *name;
3738 guicolor_T color;
3739 } guicolor_tTable;
3740
3741 /*
3742 * The comment at the end of each line is the source
3743 * (Mac, Window, Unix) and the number is the unix rgb.txt value
3744 */
3745 static guicolor_tTable table[] =
3746 {
3747 {"Black", RGB(0x00, 0x00, 0x00)},
3748 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/
3749 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/
3750 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3751 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/
3752 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
3753 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/
Bram Moolenaarb21e5842006-04-16 18:30:08 +00003754 {"gray10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3755 {"grey10", RGB(0x1A, 0x1A, 0x1A)}, /*W*/
3756 {"gray20", RGB(0x33, 0x33, 0x33)}, /*W*/
3757 {"grey20", RGB(0x33, 0x33, 0x33)}, /*W*/
3758 {"gray30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3759 {"grey30", RGB(0x4D, 0x4D, 0x4D)}, /*W*/
3760 {"gray40", RGB(0x66, 0x66, 0x66)}, /*W*/
3761 {"grey40", RGB(0x66, 0x66, 0x66)}, /*W*/
3762 {"gray50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3763 {"grey50", RGB(0x7F, 0x7F, 0x7F)}, /*W*/
3764 {"gray60", RGB(0x99, 0x99, 0x99)}, /*W*/
3765 {"grey60", RGB(0x99, 0x99, 0x99)}, /*W*/
3766 {"gray70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3767 {"grey70", RGB(0xB3, 0xB3, 0xB3)}, /*W*/
3768 {"gray80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
3769 {"grey80", RGB(0xCC, 0xCC, 0xCC)}, /*W*/
Bram Moolenaare2f98b92006-03-29 21:18:24 +00003770 {"gray90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
3771 {"grey90", RGB(0xE5, 0xE5, 0xE5)}, /*W*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 {"white", RGB(0xFF, 0xFF, 0xFF)},
3773 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/
3774 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/
3775 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/
3776 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/
3777 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/
3778 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/
3779 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/
3780 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/
3781 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/
3782 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */
3783 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/
3784 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/
3785 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/
3786 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/
3787 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/
3788 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/
3789 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/
3790 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/
Bram Moolenaar45eeb132005-06-06 21:59:07 +00003791 {"darkyellow", RGB(0xBB, 0xBB, 0x00)}, /*U*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */
3793 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */
3794 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */
3795 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */
3796 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/
3797 };
3798
3799 int r, g, b;
3800 int i;
3801
3802 if (name[0] == '#' && strlen((char *) name) == 7)
3803 {
3804 /* Name is in "#rrggbb" format */
3805 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
3806 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
3807 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
3808 if (r < 0 || g < 0 || b < 0)
3809 return INVALCOLOR;
3810 return RGB(r, g, b);
3811 }
3812 else
3813 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003814 if (STRICMP(name, "hilite") == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003816 LMGetHiliteRGB(&MacColor);
3817 return (RGB(MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818 }
3819 /* Check if the name is one of the colors we know */
3820 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
3821 if (STRICMP(name, table[i].name) == 0)
3822 return table[i].color;
3823 }
3824
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 /*
3826 * Last attempt. Look in the file "$VIM/rgb.txt".
3827 */
3828 {
3829#define LINE_LEN 100
3830 FILE *fd;
3831 char line[LINE_LEN];
3832 char_u *fname;
3833
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 if (fname == NULL)
3836 return INVALCOLOR;
3837
3838 fd = fopen((char *)fname, "rt");
3839 vim_free(fname);
3840 if (fd == NULL)
3841 return INVALCOLOR;
3842
3843 while (!feof(fd))
3844 {
3845 int len;
3846 int pos;
3847 char *color;
3848
3849 fgets(line, LINE_LEN, fd);
3850 len = strlen(line);
3851
3852 if (len <= 1 || line[len-1] != '\n')
3853 continue;
3854
3855 line[len-1] = '\0';
3856
3857 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
3858 if (i != 3)
3859 continue;
3860
3861 color = line + pos;
3862
3863 if (STRICMP(color, name) == 0)
3864 {
3865 fclose(fd);
3866 return (guicolor_T) RGB(r, g, b);
3867 }
3868 }
3869 fclose(fd);
3870 }
3871
3872 return INVALCOLOR;
3873}
3874
3875/*
3876 * Set the current text foreground color.
3877 */
3878 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003879gui_mch_set_fg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880{
3881 RGBColor TheColor;
3882
3883 TheColor.red = Red(color) * 0x0101;
3884 TheColor.green = Green(color) * 0x0101;
3885 TheColor.blue = Blue(color) * 0x0101;
3886
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003887 RGBForeColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888}
3889
3890/*
3891 * Set the current text background color.
3892 */
3893 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003894gui_mch_set_bg_color(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895{
3896 RGBColor TheColor;
3897
3898 TheColor.red = Red(color) * 0x0101;
3899 TheColor.green = Green(color) * 0x0101;
3900 TheColor.blue = Blue(color) * 0x0101;
3901
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003902 RGBBackColor(&TheColor);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903}
3904
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003905RGBColor specialColor;
3906
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003907/*
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003908 * Set the current text special color.
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003909 */
3910 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003911gui_mch_set_sp_color(guicolor_T color)
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003912{
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003913 specialColor.red = Red(color) * 0x0101;
3914 specialColor.green = Green(color) * 0x0101;
3915 specialColor.blue = Blue(color) * 0x0101;
3916}
3917
3918/*
3919 * Draw undercurl at the bottom of the character cell.
3920 */
3921 static void
3922draw_undercurl(int flags, int row, int col, int cells)
3923{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003924 int x;
3925 int offset;
3926 const static int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
3927 int y = FILL_Y(row + 1) - 1;
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003928
3929 RGBForeColor(&specialColor);
3930
3931 offset = val[FILL_X(col) % 8];
3932 MoveTo(FILL_X(col), y - offset);
3933
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003934 for (x = FILL_X(col); x < FILL_X(col + cells); ++x)
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003935 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003936 offset = val[x % 8];
3937 LineTo(x, y - offset);
Bram Moolenaar5fe38612005-11-26 23:45:02 +00003938 }
Bram Moolenaar916b7af2005-03-16 09:52:38 +00003939}
3940
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00003941
3942 static void
3943draw_string_QD(int row, int col, char_u *s, int len, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945#ifdef FEAT_MBYTE
3946 char_u *tofree = NULL;
3947
3948 if (output_conv.vc_type != CONV_NONE)
3949 {
3950 tofree = string_convert(&output_conv, s, &len);
3951 if (tofree != NULL)
3952 s = tofree;
3953 }
3954#endif
3955
Bram Moolenaar071d4272004-06-13 20:20:40 +00003956 /*
3957 * On OS X, try using Quartz-style text antialiasing.
3958 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003959 if (gMacSystemVersion >= 0x1020)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 {
3961 /* Quartz antialiasing is available only in OS 10.2 and later. */
3962 UInt32 qd_flags = (p_antialias ?
3963 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003964 QDSwapTextFlags(qd_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 }
3966
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003967 /*
3968 * When antialiasing we're using srcOr mode, we have to clear the block
3969 * before drawing the text.
3970 * Also needed when 'linespace' is non-zero to remove the cursor and
3971 * underlining.
3972 * But not when drawing transparently.
3973 * The following is like calling gui_mch_clear_block(row, col, row, col +
3974 * len - 1), but without setting the bg color to gui.back_pixel.
3975 */
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003976 if (((gMacSystemVersion >= 0x1020 && p_antialias) || p_linespace != 0)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003977 && !(flags & DRAW_TRANSP))
3978 {
3979 Rect rc;
3980
3981 rc.left = FILL_X(col);
3982 rc.top = FILL_Y(row);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003983#ifdef FEAT_MBYTE
3984 /* Multibyte computation taken from gui_w32.c */
3985 if (has_mbyte)
3986 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003987 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02003988 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00003989 }
3990 else
3991#endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00003992 rc.right = FILL_X(col + len) + (col + len == Columns);
3993 rc.bottom = FILL_Y(row + 1);
3994 EraseRect(&rc);
3995 }
3996
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00003997 if (gMacSystemVersion >= 0x1020 && p_antialias)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003998 {
3999 StyleParameter face;
4000
4001 face = normal;
4002 if (flags & DRAW_BOLD)
4003 face |= bold;
4004 if (flags & DRAW_UNDERL)
4005 face |= underline;
4006 TextFace(face);
4007
4008 /* Quartz antialiasing works only in srcOr transfer mode. */
4009 TextMode(srcOr);
4010
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011 MoveTo(TEXT_X(col), TEXT_Y(row));
4012 DrawText((char*)s, 0, len);
4013 }
4014 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015 {
4016 /* Use old-style, non-antialiased QuickDraw text rendering. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004017 TextMode(srcCopy);
4018 TextFace(normal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004019
4020 /* SelectFont(hdc, gui.currFont); */
4021
4022 if (flags & DRAW_TRANSP)
4023 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004024 TextMode(srcOr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025 }
4026
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004027 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004028 DrawText((char *)s, 0, len);
4029
4030 if (flags & DRAW_BOLD)
4031 {
4032 TextMode(srcOr);
4033 MoveTo(TEXT_X(col) + 1, TEXT_Y(row));
4034 DrawText((char *)s, 0, len);
4035 }
4036
4037 if (flags & DRAW_UNDERL)
4038 {
4039 MoveTo(FILL_X(col), FILL_Y(row + 1) - 1);
4040 LineTo(FILL_X(col + len) - 1, FILL_Y(row + 1) - 1);
4041 }
4042 }
4043
4044 if (flags & DRAW_UNDERC)
4045 draw_undercurl(flags, row, col, len);
4046
4047#ifdef FEAT_MBYTE
4048 vim_free(tofree);
4049#endif
4050}
4051
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004052#ifdef USE_ATSUI_DRAWING
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004053
4054 static void
4055draw_string_ATSUI(int row, int col, char_u *s, int len, int flags)
4056{
4057 /* ATSUI requires utf-16 strings */
4058 UniCharCount utf16_len;
4059 UniChar *tofree = mac_enc_to_utf16(s, len, (size_t *)&utf16_len);
4060 utf16_len /= sizeof(UniChar);
4061
4062 /* - ATSUI automatically antialiases text (Someone)
4063 * - for some reason it does not work... (Jussi) */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004064#ifdef MAC_ATSUI_DEBUG
4065 fprintf(stderr, "row = %d, col = %d, len = %d: '%c'\n",
4066 row, col, len, len == 1 ? s[0] : ' ');
4067#endif
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004068 /*
4069 * When antialiasing we're using srcOr mode, we have to clear the block
4070 * before drawing the text.
4071 * Also needed when 'linespace' is non-zero to remove the cursor and
4072 * underlining.
4073 * But not when drawing transparently.
4074 * The following is like calling gui_mch_clear_block(row, col, row, col +
4075 * len - 1), but without setting the bg color to gui.back_pixel.
4076 */
4077 if ((flags & DRAW_TRANSP) == 0)
4078 {
4079 Rect rc;
4080
4081 rc.left = FILL_X(col);
4082 rc.top = FILL_Y(row);
4083 /* Multibyte computation taken from gui_w32.c */
4084 if (has_mbyte)
4085 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004086 /* Compute the length in display cells. */
Bram Moolenaar72597a52010-07-18 15:31:08 +02004087 rc.right = FILL_X(col + mb_string2cells(s, len));
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004088 }
4089 else
4090 rc.right = FILL_X(col + len) + (col + len == Columns);
4091
4092 rc.bottom = FILL_Y(row + 1);
4093 EraseRect(&rc);
4094 }
4095
4096 {
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004097 TextMode(srcCopy);
4098 TextFace(normal);
4099
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004100 /* SelectFont(hdc, gui.currFont); */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004101 if (flags & DRAW_TRANSP)
4102 {
4103 TextMode(srcOr);
4104 }
4105
4106 MoveTo(TEXT_X(col), TEXT_Y(row));
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004107
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004108 if (gFontStyle && flags & DRAW_BOLD)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004109 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004110 Boolean attValue = true;
4111 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4112 ByteCount attribSizes[] = { sizeof(Boolean) };
4113 ATSUAttributeValuePtr attribValues[] = { &attValue };
4114
4115 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes, attribValues);
4116 }
4117
Bram Moolenaar76b96fc2010-07-17 16:44:59 +02004118 UInt32 useAntialias = p_antialias ? kATSStyleApplyAntiAliasing
4119 : kATSStyleNoAntiAliasing;
4120 if (useAntialias != useAntialias_cached)
4121 {
4122 ATSUAttributeTag attribTags[] = { kATSUStyleRenderingOptionsTag };
4123 ByteCount attribSizes[] = { sizeof(UInt32) };
4124 ATSUAttributeValuePtr attribValues[] = { &useAntialias };
4125
4126 if (gFontStyle)
4127 ATSUSetAttributes(gFontStyle, 1, attribTags,
4128 attribSizes, attribValues);
4129 if (gWideFontStyle)
4130 ATSUSetAttributes(gWideFontStyle, 1, attribTags,
4131 attribSizes, attribValues);
4132
4133 useAntialias_cached = useAntialias;
4134 }
4135
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004136#ifdef FEAT_MBYTE
4137 if (has_mbyte)
4138 {
4139 int n, width_in_cell, last_width_in_cell;
4140 UniCharArrayOffset offset = 0;
4141 UniCharCount yet_to_draw = 0;
4142 ATSUTextLayout textLayout;
4143 ATSUStyle textStyle;
4144
4145 last_width_in_cell = 1;
4146 ATSUCreateTextLayout(&textLayout);
4147 ATSUSetTextPointerLocation(textLayout, tofree,
4148 kATSUFromTextBeginning,
4149 kATSUToTextEnd, utf16_len);
4150 /*
4151 ATSUSetRunStyle(textLayout, gFontStyle,
4152 kATSUFromTextBeginning, kATSUToTextEnd); */
4153
4154 /* Compute the length in display cells. */
4155 for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
4156 {
4157 width_in_cell = (*mb_ptr2cells)(s + n);
4158
4159 /* probably we are switching from single byte character
4160 * to multibyte characters (which requires more than one
4161 * cell to draw) */
4162 if (width_in_cell != last_width_in_cell)
4163 {
4164#ifdef MAC_ATSUI_DEBUG
4165 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4166 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4167#endif
4168 textStyle = last_width_in_cell > 1 ? gWideFontStyle
4169 : gFontStyle;
4170
4171 ATSUSetRunStyle(textLayout, textStyle, offset, yet_to_draw);
4172 offset += yet_to_draw;
4173 yet_to_draw = 0;
4174 last_width_in_cell = width_in_cell;
4175 }
4176
4177 yet_to_draw++;
4178 }
4179
4180 if (yet_to_draw)
4181 {
4182#ifdef MAC_ATSUI_DEBUG
4183 fprintf(stderr, "\tn = %2d, (%d-%d), offset = %d, yet_to_draw = %d\n",
4184 n, last_width_in_cell, width_in_cell, offset, yet_to_draw);
4185#endif
4186 /* finish the rest style */
4187 textStyle = width_in_cell > 1 ? gWideFontStyle : gFontStyle;
4188 ATSUSetRunStyle(textLayout, textStyle, offset, kATSUToTextEnd);
4189 }
4190
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004191 ATSUSetTransientFontMatching(textLayout, TRUE);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004192 ATSUDrawText(textLayout,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004193 kATSUFromTextBeginning, kATSUToTextEnd,
4194 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004195 ATSUDisposeTextLayout(textLayout);
4196 }
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004197 else
4198#endif
4199 {
4200 ATSUTextLayout textLayout;
4201
4202 if (ATSUCreateTextLayoutWithTextPtr(tofree,
4203 kATSUFromTextBeginning, kATSUToTextEnd,
4204 utf16_len,
4205 (gFontStyle ? 1 : 0), &utf16_len,
4206 (gFontStyle ? &gFontStyle : NULL),
4207 &textLayout) == noErr)
4208 {
4209 ATSUSetTransientFontMatching(textLayout, TRUE);
4210
4211 ATSUDrawText(textLayout,
4212 kATSUFromTextBeginning, kATSUToTextEnd,
4213 kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc);
4214
4215 ATSUDisposeTextLayout(textLayout);
4216 }
4217 }
4218
4219 /* drawing is done, now reset bold to normal */
4220 if (gFontStyle && flags & DRAW_BOLD)
4221 {
4222 Boolean attValue = false;
4223
4224 ATSUAttributeTag attribTags[] = { kATSUQDBoldfaceTag };
4225 ByteCount attribSizes[] = { sizeof(Boolean) };
4226 ATSUAttributeValuePtr attribValues[] = { &attValue };
4227
4228 ATSUSetAttributes(gFontStyle, 1, attribTags, attribSizes,
4229 attribValues);
4230 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231 }
4232
Bram Moolenaar5fe38612005-11-26 23:45:02 +00004233 if (flags & DRAW_UNDERC)
4234 draw_undercurl(flags, row, col, len);
4235
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236 vim_free(tofree);
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004237}
4238#endif
4239
4240 void
4241gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
4242{
4243#if defined(USE_ATSUI_DRAWING)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004244 if (p_macatsui == 0 && p_macatsui_last != 0)
4245 /* switch from macatsui to nomacatsui */
4246 gui_mac_dispose_atsui_style();
4247 else if (p_macatsui != 0 && p_macatsui_last == 0)
4248 /* switch from nomacatsui to macatsui */
4249 gui_mac_create_atsui_style();
4250
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004251 if (p_macatsui)
4252 draw_string_ATSUI(row, col, s, len, flags);
4253 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254#endif
Bram Moolenaarf9393ef2006-04-24 19:47:27 +00004255 draw_string_QD(row, col, s, len, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256}
4257
4258/*
4259 * Return OK if the key with the termcap name "name" is supported.
4260 */
4261 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004262gui_mch_haskey(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263{
4264 int i;
4265
4266 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
4267 if (name[0] == special_keys[i].vim_code0 &&
4268 name[1] == special_keys[i].vim_code1)
4269 return OK;
4270 return FAIL;
4271}
4272
4273 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004274gui_mch_beep(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004276 SysBeep(1); /* Should this be 0? (????) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277}
4278
4279 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004280gui_mch_flash(int msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281{
4282 /* Do a visual beep by reversing the foreground and background colors */
4283 Rect rc;
4284
4285 /*
4286 * Note: InvertRect() excludes right and bottom of rectangle.
4287 */
4288 rc.left = 0;
4289 rc.top = 0;
4290 rc.right = gui.num_cols * gui.char_width;
4291 rc.bottom = gui.num_rows * gui.char_height;
4292 InvertRect(&rc);
4293
4294 ui_delay((long)msec, TRUE); /* wait for some msec */
4295
4296 InvertRect(&rc);
4297}
4298
4299/*
4300 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4301 */
4302 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004303gui_mch_invert_rectangle(int r, int c, int nr, int nc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304{
4305 Rect rc;
4306
4307 /*
4308 * Note: InvertRect() excludes right and bottom of rectangle.
4309 */
4310 rc.left = FILL_X(c);
4311 rc.top = FILL_Y(r);
4312 rc.right = rc.left + nc * gui.char_width;
4313 rc.bottom = rc.top + nr * gui.char_height;
4314 InvertRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315}
4316
4317/*
4318 * Iconify the GUI window.
4319 */
4320 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004321gui_mch_iconify(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322{
4323 /* TODO: find out what could replace iconify
4324 * -window shade?
4325 * -hide application?
4326 */
4327}
4328
4329#if defined(FEAT_EVAL) || defined(PROTO)
4330/*
4331 * Bring the Vim window to the foreground.
4332 */
4333 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004334gui_mch_set_foreground(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335{
4336 /* TODO */
4337}
4338#endif
4339
4340/*
4341 * Draw a cursor without focus.
4342 */
4343 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004344gui_mch_draw_hollow_cursor(guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345{
4346 Rect rc;
4347
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 /*
4349 * Note: FrameRect() excludes right and bottom of rectangle.
4350 */
4351 rc.left = FILL_X(gui.col);
4352 rc.top = FILL_Y(gui.row);
4353 rc.right = rc.left + gui.char_width;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004354#ifdef FEAT_MBYTE
4355 if (mb_lefthalve(gui.row, gui.col))
4356 rc.right += gui.char_width;
4357#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004358 rc.bottom = rc.top + gui.char_height;
4359
4360 gui_mch_set_fg_color(color);
4361
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004362 FrameRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363}
4364
4365/*
4366 * Draw part of a cursor, only w pixels wide, and h pixels high.
4367 */
4368 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004369gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370{
4371 Rect rc;
4372
4373#ifdef FEAT_RIGHTLEFT
4374 /* vertical line should be on the right of current point */
4375 if (CURSOR_BAR_RIGHT)
4376 rc.left = FILL_X(gui.col + 1) - w;
4377 else
4378#endif
4379 rc.left = FILL_X(gui.col);
4380 rc.top = FILL_Y(gui.row) + gui.char_height - h;
4381 rc.right = rc.left + w;
4382 rc.bottom = rc.top + h;
4383
4384 gui_mch_set_fg_color(color);
4385
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004386 FrameRect(&rc);
4387// PaintRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388}
4389
4390
4391
4392/*
4393 * Catch up with any queued X events. This may put keyboard input into the
4394 * input buffer, call resize call-backs, trigger timers etc. If there is
4395 * nothing in the X event queue (& no timers pending), then we return
4396 * immediately.
4397 */
4398 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004399gui_mch_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400{
4401 /* TODO: find what to do
4402 * maybe call gui_mch_wait_for_chars (0)
4403 * more like look at EventQueue then
4404 * call heart of gui_mch_wait_for_chars;
4405 *
4406 * if (eventther)
4407 * gui_mac_handle_event(&event);
4408 */
4409 EventRecord theEvent;
4410
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004411 if (EventAvail(everyEvent, &theEvent))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 if (theEvent.what != nullEvent)
4413 gui_mch_wait_for_chars(0);
4414}
4415
4416/*
4417 * Simple wrapper to neglect more easily the time
4418 * spent inside WaitNextEvent while profiling.
4419 */
4420
Bram Moolenaar071d4272004-06-13 20:20:40 +00004421 pascal
4422 Boolean
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004423WaitNextEventWrp(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424{
4425 if (((long) sleep) < -1)
4426 sleep = 32767;
4427 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn);
4428}
4429
4430/*
4431 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4432 * from the keyboard.
4433 * wtime == -1 Wait forever.
4434 * wtime == 0 This should never happen.
4435 * wtime > 0 Wait wtime milliseconds for a character.
4436 * Returns OK if a character was found to be available within the given time,
4437 * or FAIL otherwise.
4438 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004440gui_mch_wait_for_chars(int wtime)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441{
4442 EventMask mask = (everyEvent);
4443 EventRecord event;
4444 long entryTick;
4445 long currentTick;
4446 long sleeppyTick;
4447
4448 /* If we are providing life feedback with the scrollbar,
4449 * we don't want to try to wait for an event, or else
4450 * there won't be any life feedback.
4451 */
4452 if (dragged_sb != NULL)
4453 return FAIL;
4454 /* TODO: Check if FAIL is the proper return code */
4455
4456 entryTick = TickCount();
4457
4458 allow_scrollbar = TRUE;
4459
4460 do
4461 {
4462/* if (dragRectControl == kCreateEmpty)
4463 {
4464 dragRgn = NULL;
4465 dragRectControl = kNothing;
4466 }
4467 else*/ if (dragRectControl == kCreateRect)
4468 {
4469 dragRgn = cursorRgn;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004470 RectRgn(dragRgn, &dragRect);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 dragRectControl = kNothing;
4472 }
4473 /*
4474 * Don't use gui_mch_update() because then we will spin-lock until a
4475 * char arrives, instead we use WaitNextEventWrp() to hang until an
4476 * event arrives. No need to check for input_buf_full because we are
4477 * returning as soon as it contains a single char.
4478 */
Bram Moolenaarb05034a2010-09-21 17:34:31 +02004479 /* TODO: reduce wtime accordingly??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480 if (wtime > -1)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004481 sleeppyTick = 60 * wtime / 1000;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482 else
4483 sleeppyTick = 32767;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004484
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004485 if (WaitNextEventWrp(mask, &event, sleeppyTick, dragRgn))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00004487 gui_mac_handle_event(&event);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 if (input_available())
4489 {
4490 allow_scrollbar = FALSE;
4491 return OK;
4492 }
4493 }
4494 currentTick = TickCount();
4495 }
4496 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000));
4497
4498 allow_scrollbar = FALSE;
4499 return FAIL;
4500}
4501
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502/*
4503 * Output routines.
4504 */
4505
4506/* Flush any output to the screen */
4507 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004508gui_mch_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509{
4510 /* TODO: Is anything needed here? */
4511}
4512
4513/*
4514 * Clear a rectangular region of the screen from text pos (row1, col1) to
4515 * (row2, col2) inclusive.
4516 */
4517 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004518gui_mch_clear_block(int row1, int col1, int row2, int col2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519{
4520 Rect rc;
4521
4522 /*
4523 * Clear one extra pixel at the far right, for when bold characters have
4524 * spilled over to the next column.
4525 */
4526 rc.left = FILL_X(col1);
4527 rc.top = FILL_Y(row1);
4528 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
4529 rc.bottom = FILL_Y(row2 + 1);
4530
4531 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004532 EraseRect(&rc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533}
4534
4535/*
4536 * Clear the whole text window.
4537 */
4538 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004539gui_mch_clear_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540{
4541 Rect rc;
4542
4543 rc.left = 0;
4544 rc.top = 0;
4545 rc.right = Columns * gui.char_width + 2 * gui.border_width;
4546 rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
4547
4548 gui_mch_set_bg_color(gui.back_pixel);
4549 EraseRect(&rc);
4550/* gui_mch_set_fg_color(gui.norm_pixel);
4551 FrameRect(&rc);
4552*/
4553}
4554
4555/*
4556 * Delete the given number of lines from the given row, scrolling up any
4557 * text further down within the scroll region.
4558 */
4559 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004560gui_mch_delete_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561{
4562 Rect rc;
4563
4564 /* changed without checking! */
4565 rc.left = FILL_X(gui.scroll_region_left);
4566 rc.right = FILL_X(gui.scroll_region_right + 1);
4567 rc.top = FILL_Y(row);
4568 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4569
4570 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004571 ScrollRect(&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572
4573 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
4574 gui.scroll_region_left,
4575 gui.scroll_region_bot, gui.scroll_region_right);
4576}
4577
4578/*
4579 * Insert the given number of lines before the given row, scrolling down any
4580 * following text within the scroll region.
4581 */
4582 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004583gui_mch_insert_lines(int row, int num_lines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584{
4585 Rect rc;
4586
4587 rc.left = FILL_X(gui.scroll_region_left);
4588 rc.right = FILL_X(gui.scroll_region_right + 1);
4589 rc.top = FILL_Y(row);
4590 rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
4591
4592 gui_mch_set_bg_color(gui.back_pixel);
4593
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004594 ScrollRect(&rc, 0, gui.char_height * num_lines, (RgnHandle) nil);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004595
4596 /* Update gui.cursor_row if the cursor scrolled or copied over */
4597 if (gui.cursor_row >= gui.row
4598 && gui.cursor_col >= gui.scroll_region_left
4599 && gui.cursor_col <= gui.scroll_region_right)
4600 {
4601 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
4602 gui.cursor_row += num_lines;
4603 else if (gui.cursor_row <= gui.scroll_region_bot)
4604 gui.cursor_is_valid = FALSE;
4605 }
4606
4607 gui_clear_block(row, gui.scroll_region_left,
4608 row + num_lines - 1, gui.scroll_region_right);
4609}
4610
4611 /*
4612 * TODO: add a vim format to the clipboard which remember
4613 * LINEWISE, CHARWISE, BLOCKWISE
4614 */
4615
4616 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004617clip_mch_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618{
4619
4620 Handle textOfClip;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004621 int flavor = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 Size scrapSize;
4623 ScrapFlavorFlags scrapFlags;
4624 ScrapRef scrap = nil;
4625 OSStatus error;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 int type;
4627 char *searchCR;
4628 char_u *tempclip;
4629
4630
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004631 error = GetCurrentScrap(&scrap);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632 if (error != noErr)
4633 return;
4634
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004635 error = GetScrapFlavorFlags(scrap, VIMSCRAPFLAVOR, &scrapFlags);
4636 if (error == noErr)
4637 {
4638 error = GetScrapFlavorSize(scrap, VIMSCRAPFLAVOR, &scrapSize);
4639 if (error == noErr && scrapSize > 1)
4640 flavor = 1;
4641 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004643 if (flavor == 0)
4644 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004645 error = GetScrapFlavorFlags(scrap, SCRAPTEXTFLAVOR, &scrapFlags);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004646 if (error != noErr)
4647 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004649 error = GetScrapFlavorSize(scrap, SCRAPTEXTFLAVOR, &scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004650 if (error != noErr)
4651 return;
4652 }
4653
4654 ReserveMem(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004655
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004656 /* In CARBON we don't need a Handle, a pointer is good */
4657 textOfClip = NewHandle(scrapSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004659 /* tempclip = lalloc(scrapSize+1, TRUE); */
4660 HLock(textOfClip);
4661 error = GetScrapFlavorData(scrap,
4662 flavor ? VIMSCRAPFLAVOR : SCRAPTEXTFLAVOR,
4663 &scrapSize, *textOfClip);
4664 scrapSize -= flavor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004666 if (flavor)
4667 type = **textOfClip;
4668 else
Bram Moolenaard44347f2011-06-19 01:14:29 +02004669 type = MAUTO;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004670
4671 tempclip = lalloc(scrapSize + 1, TRUE);
4672 mch_memmove(tempclip, *textOfClip + flavor, scrapSize);
4673 tempclip[scrapSize] = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004675#ifdef MACOS_CONVERT
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004676 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004677 /* Convert from utf-16 (clipboard) */
4678 size_t encLen = 0;
4679 char_u *to = mac_utf16_to_enc((UniChar *)tempclip, scrapSize, &encLen);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004680
4681 if (to != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004683 scrapSize = encLen;
4684 vim_free(tempclip);
4685 tempclip = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004687 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688#endif
Bram Moolenaare344bea2005-09-01 20:46:49 +00004689
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004690 searchCR = (char *)tempclip;
4691 while (searchCR != NULL)
4692 {
4693 searchCR = strchr(searchCR, '\r');
4694 if (searchCR != NULL)
4695 *searchCR = '\n';
Bram Moolenaar071d4272004-06-13 20:20:40 +00004696 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004697
4698 clip_yank_selection(type, tempclip, scrapSize, cbd);
4699
4700 vim_free(tempclip);
4701 HUnlock(textOfClip);
4702
4703 DisposeHandle(textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704}
4705
4706 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004707clip_mch_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708{
4709 /*
4710 * TODO: Really nothing to do?
4711 */
4712}
4713
4714 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004715clip_mch_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716{
4717 return OK;
4718}
4719
4720/*
4721 * Send the current selection to the clipboard.
4722 */
4723 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004724clip_mch_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725{
4726 Handle textOfClip;
4727 long scrapSize;
4728 int type;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729 ScrapRef scrap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730
4731 char_u *str = NULL;
4732
4733 if (!cbd->owned)
4734 return;
4735
4736 clip_get_selection(cbd);
4737
4738 /*
4739 * Once we set the clipboard, lose ownership. If another application sets
4740 * the clipboard, we don't want to think that we still own it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 cbd->owned = FALSE;
4743
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004744 type = clip_convert_selection(&str, (long_u *)&scrapSize, cbd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004746#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004747 size_t utf16_len = 0;
4748 UniChar *to = mac_enc_to_utf16(str, scrapSize, &utf16_len);
4749 if (to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004751 scrapSize = utf16_len;
4752 vim_free(str);
4753 str = (char_u *)to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004754 }
4755#endif
4756
4757 if (type >= 0)
4758 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 ClearCurrentScrap();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004761 textOfClip = NewHandle(scrapSize + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762 HLock(textOfClip);
4763
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004764 **textOfClip = type;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004765 mch_memmove(*textOfClip + 1, str, scrapSize);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004766 GetCurrentScrap(&scrap);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00004767 PutScrapFlavor(scrap, SCRAPTEXTFLAVOR, kScrapFlavorMaskNone,
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004768 scrapSize, *textOfClip + 1);
4769 PutScrapFlavor(scrap, VIMSCRAPFLAVOR, kScrapFlavorMaskNone,
4770 scrapSize + 1, *textOfClip);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771 HUnlock(textOfClip);
4772 DisposeHandle(textOfClip);
4773 }
4774
4775 vim_free(str);
4776}
4777
4778 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004779gui_mch_set_text_area_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780{
4781 Rect VimBound;
4782
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004783/* HideWindow(gui.VimWindow); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785
4786 if (gui.which_scrollbars[SBAR_LEFT])
4787 {
4788 VimBound.left = -gui.scrollbar_width + 1;
4789 }
4790 else
4791 {
4792 VimBound.left = 0;
4793 }
4794
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004797 ShowWindow(gui.VimWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798}
4799
4800/*
4801 * Menu stuff.
4802 */
4803
4804 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004805gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806{
4807 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004808 * Menu is always active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809 */
4810}
4811
4812 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004813gui_mch_set_menu_pos(int x, int y, int w, int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814{
4815 /*
Bram Moolenaar02743632005-07-25 20:42:36 +00004816 * The menu is always at the top of the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004817 */
4818}
4819
4820/*
4821 * Add a sub menu to the menu bar.
4822 */
4823 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004824gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825{
4826 /*
4827 * TODO: Try to use only menu_id instead of both menu_id and menu_handle.
4828 * TODO: use menu->mnemonic and menu->actext
4829 * TODO: Try to reuse menu id
4830 * Carbon Help suggest to use only id between 1 and 235
4831 */
4832 static long next_avail_id = 128;
4833 long menu_after_me = 0; /* Default to the end */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004834#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004835 CFStringRef name;
4836#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004838#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 short index;
4840 vimmenu_T *parent = menu->parent;
4841 vimmenu_T *brother = menu->next;
4842
4843 /* Cannot add a menu if ... */
4844 if ((parent != NULL && parent->submenu_id == 0))
4845 return;
4846
4847 /* menu ID greater than 1024 are reserved for ??? */
4848 if (next_avail_id == 1024)
4849 return;
4850
4851 /* My brother could be the PopUp, find my real brother */
4852 while ((brother != NULL) && (!menu_is_menubar(brother->name)))
4853 brother = brother->next;
4854
4855 /* Find where to insert the menu (for MenuBar) */
4856 if ((parent == NULL) && (brother != NULL))
4857 menu_after_me = brother->submenu_id;
4858
4859 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */
4860 if (!menu_is_menubar(menu->name))
4861 menu_after_me = hierMenu;
4862
4863 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004864#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004865 name = menu_title_removing_mnemonic(menu);
4866#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004868#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869 if (name == NULL)
4870 return;
4871
4872 /* Create the menu unless it's the help menu */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 {
4874 /* Carbon suggest use of
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004875 * OSStatus CreateNewMenu(MenuID, MenuAttributes, MenuRef *);
4876 * OSStatus SetMenuTitle(MenuRef, ConstStr255Param title);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 */
4878 menu->submenu_id = next_avail_id;
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004879#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004880 if (CreateNewMenu(menu->submenu_id, 0, (MenuRef *)&menu->submenu_handle) == noErr)
4881 SetMenuTitleWithCFString((MenuRef)menu->submenu_handle, name);
4882#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004883 menu->submenu_handle = NewMenu(menu->submenu_id, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004884#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004885 next_avail_id++;
4886 }
4887
4888 if (parent == NULL)
4889 {
4890 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */
4891
4892 /* TODO: Verify if we could only Insert Menu if really part of the
4893 * menubar The Inserted menu are scanned or the Command-key combos
4894 */
4895
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004896 /* Insert the menu */
4897 InsertMenu(menu->submenu_handle, menu_after_me); /* insert before */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898#if 1
4899 /* Vim should normally update it. TODO: verify */
4900 DrawMenuBar();
4901#endif
4902 }
4903 else
4904 {
4905 /* Adding as a submenu */
4906
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004907 index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908
4909 /* Call InsertMenuItem followed by SetMenuItemText
4910 * to avoid special character recognition by InsertMenuItem
4911 */
4912 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004913#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004914 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
4915#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004916 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004917#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 SetItemCmd(parent->submenu_handle, idx+1, 0x1B);
4919 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id);
4920 InsertMenu(menu->submenu_handle, hierMenu);
4921 }
4922
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004923#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004924 CFRelease(name);
4925#else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004926 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004927#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928
4929#if 0
4930 /* Done by Vim later on */
4931 DrawMenuBar();
4932#endif
4933}
4934
4935/*
4936 * Add a menu item to a menu
4937 */
4938 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004939gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940{
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00004941#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004942 CFStringRef name;
4943#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004944 char_u *name;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004945#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946 vimmenu_T *parent = menu->parent;
4947 int menu_inserted;
4948
4949 /* Cannot add item, if the menu have not been created */
4950 if (parent->submenu_id == 0)
4951 return;
4952
4953 /* Could call SetMenuRefCon [CARBON] to associate with the Menu,
4954 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */
4955
4956 /* Convert the name */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00004957#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004958 name = menu_title_removing_mnemonic(menu);
4959#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004960 name = C2Pascal_save(menu->dname);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00004961#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962
4963 /* Where are just a menu item, so no handle, no id */
4964 menu->submenu_id = 0;
4965 menu->submenu_handle = NULL;
4966
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 menu_inserted = 0;
4968 if (menu->actext)
4969 {
4970 /* If the accelerator text for the menu item looks like it describes
4971 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the
4972 * item's command equivalent.
4973 */
4974 int key = 0;
4975 int modifiers = 0;
4976 char_u *p_actext;
4977
4978 p_actext = menu->actext;
Bram Moolenaardc5e2182008-12-24 12:06:26 +00004979 key = find_special_key(&p_actext, &modifiers, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980 if (*p_actext != 0)
4981 key = 0; /* error: trailing text */
4982 /* find_special_key() returns a keycode with as many of the
4983 * specified modifiers as appropriate already applied (e.g., for
4984 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD
4985 * as the only modifier). Since we want to display all of the
4986 * modifiers, we need to convert the keycode back to a printable
4987 * character plus modifiers.
4988 * TODO: Write an alternative find_special_key() that doesn't
4989 * apply modifiers.
4990 */
4991 if (key > 0 && key < 32)
4992 {
4993 /* Convert a control key to an uppercase letter. Note that
4994 * by this point it is no longer possible to distinguish
4995 * between, e.g., Ctrl-S and Ctrl-Shift-S.
4996 */
4997 modifiers |= MOD_MASK_CTRL;
4998 key += '@';
4999 }
5000 /* If the keycode is an uppercase letter, set the Shift modifier.
5001 * If it is a lowercase letter, don't set the modifier, but convert
5002 * the letter to uppercase for display in the menu.
5003 */
5004 else if (key >= 'A' && key <= 'Z')
5005 modifiers |= MOD_MASK_SHIFT;
5006 else if (key >= 'a' && key <= 'z')
5007 key += 'A' - 'a';
5008 /* Note: keycodes below 0x22 are reserved by Apple. */
5009 if (key >= 0x22 && vim_isprintc_strict(key))
5010 {
5011 int valid = 1;
5012 char_u mac_mods = kMenuNoModifiers;
5013 /* Convert Vim modifier codes to Menu Manager equivalents. */
5014 if (modifiers & MOD_MASK_SHIFT)
5015 mac_mods |= kMenuShiftModifier;
5016 if (modifiers & MOD_MASK_CTRL)
5017 mac_mods |= kMenuControlModifier;
5018 if (!(modifiers & MOD_MASK_CMD))
5019 mac_mods |= kMenuNoCommandModifier;
5020 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK)
5021 valid = 0; /* TODO: will Alt someday map to Option? */
5022 if (valid)
5023 {
5024 char_u item_txt[10];
5025 /* Insert the menu item after idx, with its command key. */
5026 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/';
5027 item_txt[3] = key;
5028 InsertMenuItem(parent->submenu_handle, item_txt, idx);
5029 /* Set the modifier keys. */
5030 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods);
5031 menu_inserted = 1;
5032 }
5033 }
5034 }
5035 /* Call InsertMenuItem followed by SetMenuItemText
5036 * to avoid special character recognition by InsertMenuItem
5037 */
5038 if (!menu_inserted)
5039 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */
5040 /* Set the menu item name. */
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005041#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005042 SetMenuItemTextWithCFString(parent->submenu_handle, idx+1, name);
5043#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044 SetMenuItemText(parent->submenu_handle, idx+1, name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005045#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046
5047#if 0
5048 /* Called by Vim */
5049 DrawMenuBar();
5050#endif
5051
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005052#if defined(FEAT_MBYTE)
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005053 CFRelease(name);
5054#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055 /* TODO: Can name be freed? */
5056 vim_free(name);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005057#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058}
5059
5060 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005061gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062{
5063 /* no tearoff menus */
5064}
5065
5066/*
5067 * Destroy the machine specific menu widget.
5068 */
5069 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005070gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005072 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005073
5074 if (index > 0)
5075 {
5076 if (menu->parent)
5077 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078 {
5079 /* For now just don't delete help menu items. (Huh? Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005080 DeleteMenuItem(menu->parent->submenu_handle, index);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005081
5082 /* Delete the Menu if it was a hierarchical Menu */
5083 if (menu->submenu_id != 0)
5084 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005085 DeleteMenu(menu->submenu_id);
5086 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 }
5088 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 }
5090#ifdef DEBUG_MAC_MENU
5091 else
5092 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005093 printf("gmdm 2\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005094 }
5095#endif
5096 }
5097 else
5098 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005100 DeleteMenu(menu->submenu_id);
5101 DisposeMenu(menu->submenu_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102 }
5103 }
5104 /* Shouldn't this be already done by Vim. TODO: Check */
5105 DrawMenuBar();
5106}
5107
5108/*
5109 * Make a menu either grey or not grey.
5110 */
5111 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005112gui_mch_menu_grey(vimmenu_T *menu, int grey)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113{
5114 /* TODO: Check if menu really exists */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005115 short index = gui_mac_get_menu_item_index(menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116/*
5117 index = menu->index;
5118*/
5119 if (grey)
5120 {
5121 if (menu->children)
5122 DisableMenuItem(menu->submenu_handle, index);
5123 if (menu->parent)
5124 if (menu->parent->submenu_handle)
5125 DisableMenuItem(menu->parent->submenu_handle, index);
5126 }
5127 else
5128 {
5129 if (menu->children)
5130 EnableMenuItem(menu->submenu_handle, index);
5131 if (menu->parent)
5132 if (menu->parent->submenu_handle)
5133 EnableMenuItem(menu->parent->submenu_handle, index);
5134 }
5135}
5136
5137/*
5138 * Make menu item hidden or not hidden
5139 */
5140 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005141gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142{
5143 /* There's no hidden mode on MacOS */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005144 gui_mch_menu_grey(menu, hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145}
5146
5147
5148/*
5149 * This is called after setting all the menus to grey/hidden or not.
5150 */
5151 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005152gui_mch_draw_menubar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153{
5154 DrawMenuBar();
5155}
5156
5157
5158/*
5159 * Scrollbar stuff.
5160 */
5161
5162 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005163gui_mch_enable_scrollbar(
5164 scrollbar_T *sb,
5165 int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166{
5167 if (flag)
5168 ShowControl(sb->id);
5169 else
5170 HideControl(sb->id);
5171
5172#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005173 printf("enb_sb (%x) %x\n",sb->id, flag);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174#endif
5175}
5176
5177 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005178gui_mch_set_scrollbar_thumb(
5179 scrollbar_T *sb,
5180 long val,
5181 long size,
5182 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183{
5184 SetControl32BitMaximum (sb->id, max);
5185 SetControl32BitMinimum (sb->id, 0);
5186 SetControl32BitValue (sb->id, val);
Bram Moolenaarbbe8c3f2007-04-26 16:40:56 +00005187 SetControlViewSize (sb->id, size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005189 printf("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005190#endif
5191}
5192
5193 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005194gui_mch_set_scrollbar_pos(
5195 scrollbar_T *sb,
5196 int x,
5197 int y,
5198 int w,
5199 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200{
5201 gui_mch_set_bg_color(gui.back_pixel);
5202/* if (gui.which_scrollbars[SBAR_LEFT])
5203 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005204 MoveControl(sb->id, x-16, y);
5205 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005206 }
5207 else
5208 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005209 MoveControl(sb->id, x, y);
5210 SizeControl(sb->id, w + 1, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 }*/
5212 if (sb == &gui.bottom_sbar)
5213 h += 1;
5214 else
5215 w += 1;
5216
5217 if (gui.which_scrollbars[SBAR_LEFT])
5218 x -= 15;
5219
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005220 MoveControl(sb->id, x, y);
5221 SizeControl(sb->id, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005222#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005223 printf("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005224#endif
5225}
5226
5227 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005228gui_mch_create_scrollbar(
5229 scrollbar_T *sb,
5230 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005231{
5232 Rect bounds;
5233
5234 bounds.top = -16;
5235 bounds.bottom = -10;
5236 bounds.right = -10;
5237 bounds.left = -16;
5238
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005239 sb->id = NewControl(gui.VimWindow,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 &bounds,
5241 "\pScrollBar",
5242 TRUE,
5243 0, /* current*/
5244 0, /* top */
5245 0, /* bottom */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246 kControlScrollBarLiveProc,
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 (long) sb->ident);
5248#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005249 printf("create_sb (%x) %x\n",sb->id, orient);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250#endif
5251}
5252
5253 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005254gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255{
5256 gui_mch_set_bg_color(gui.back_pixel);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005257 DisposeControl(sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258#ifdef DEBUG_MAC_SB
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005259 printf("dest_sb (%x) \n",sb->id);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260#endif
5261}
5262
5263
5264/*
5265 * Cursor blink functions.
5266 *
5267 * This is a simple state machine:
5268 * BLINK_NONE not blinking at all
5269 * BLINK_OFF blinking, cursor is not shown
5270 * BLINK_ON blinking, cursor is shown
5271 */
5272 void
5273gui_mch_set_blinking(long wait, long on, long off)
5274{
5275 /* TODO: TODO: TODO: TODO: */
5276/* blink_waittime = wait;
5277 blink_ontime = on;
5278 blink_offtime = off;*/
5279}
5280
5281/*
5282 * Stop the cursor blinking. Show the cursor if it wasn't shown.
5283 */
5284 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005285gui_mch_stop_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005286{
5287 gui_update_cursor(TRUE, FALSE);
5288 /* TODO: TODO: TODO: TODO: */
5289/* gui_w32_rm_blink_timer();
5290 if (blink_state == BLINK_OFF)
5291 gui_update_cursor(TRUE, FALSE);
5292 blink_state = BLINK_NONE;*/
5293}
5294
5295/*
5296 * Start the cursor blinking. If it was already blinking, this restarts the
5297 * waiting time and shows the cursor.
5298 */
5299 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005300gui_mch_start_blink(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005301{
5302 gui_update_cursor(TRUE, FALSE);
5303 /* TODO: TODO: TODO: TODO: */
5304/* gui_w32_rm_blink_timer(); */
5305
5306 /* Only switch blinking on if none of the times is zero */
5307/* if (blink_waittime && blink_ontime && blink_offtime)
5308 {
5309 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime,
5310 (TIMERPROC)_OnBlinkTimer);
5311 blink_state = BLINK_ON;
5312 gui_update_cursor(TRUE, FALSE);
5313 }*/
5314}
5315
5316/*
5317 * Return the RGB value of a pixel as long.
5318 */
5319 long_u
5320gui_mch_get_rgb(guicolor_T pixel)
5321{
5322 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
5323}
5324
5325
5326
5327#ifdef FEAT_BROWSE
5328/*
5329 * Pop open a file browser and return the file selected, in allocated memory,
5330 * or NULL if Cancel is hit.
5331 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5332 * title - Title message for the file browser dialog.
5333 * dflt - Default name of file.
5334 * ext - Default extension to be added to files without extensions.
5335 * initdir - directory in which to open the browser (NULL = current dir)
5336 * filter - Filter for matched files to choose from.
5337 * Has a format like this:
5338 * "C Files (*.c)\0*.c\0"
5339 * "All Files\0*.*\0\0"
5340 * If these two strings were concatenated, then a choice of two file
5341 * filters will be selectable to the user. Then only matching files will
5342 * be shown in the browser. If NULL, the default allows all files.
5343 *
5344 * *NOTE* - the filter string must be terminated with TWO nulls.
5345 */
5346 char_u *
5347gui_mch_browse(
5348 int saving,
5349 char_u *title,
5350 char_u *dflt,
5351 char_u *ext,
5352 char_u *initdir,
5353 char_u *filter)
5354{
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005355 /* TODO: Add Ammon's safety check (Dany) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005356 NavReplyRecord reply;
5357 char_u *fname = NULL;
5358 char_u **fnames = NULL;
5359 long numFiles;
5360 NavDialogOptions navOptions;
5361 OSErr error;
5362
5363 /* Get Navigation Service Defaults value */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005364 NavGetDefaultDialogOptions(&navOptions);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365
5366
5367 /* TODO: If we get a :browse args, set the Multiple bit. */
5368 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles
5369 | kNavDontAutoTranslate
5370 | kNavDontAddTranslateItems
5371 /* | kNavAllowMultipleFiles */
5372 | kNavAllowStationery;
5373
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005374 (void) C2PascalString(title, &navOptions.message);
5375 (void) C2PascalString(dflt, &navOptions.savedFileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005376 /* Could set clientName?
5377 * windowTitle? (there's no title bar?)
5378 */
5379
5380 if (saving)
5381 {
5382 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005383 NavPutFile(NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005384 if (!reply.validRecord)
5385 return NULL;
5386 }
5387 else
5388 {
5389 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */
5390 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL);
5391 if (!reply.validRecord)
5392 return NULL;
5393 }
5394
5395 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error);
5396
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005397 NavDisposeReply(&reply);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398
5399 if (fnames)
5400 {
5401 fname = fnames[0];
5402 vim_free(fnames);
5403 }
5404
5405 /* TODO: Shorten the file name if possible */
5406 return fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407}
5408#endif /* FEAT_BROWSE */
5409
5410#ifdef FEAT_GUI_DIALOG
5411/*
5412 * Stuff for dialogues
5413 */
5414
5415/*
5416 * Create a dialogue dynamically from the parameter strings.
5417 * type = type of dialogue (question, alert, etc.)
5418 * title = dialogue title. may be NULL for default title.
5419 * message = text to display. Dialogue sizes to accommodate it.
5420 * buttons = '\n' separated list of button captions, default first.
5421 * dfltbutton = number of default button.
5422 *
5423 * This routine returns 1 if the first button is pressed,
5424 * 2 for the second, etc.
5425 *
5426 * 0 indicates Esc was pressed.
5427 * -1 for unexpected error
5428 *
5429 * If stubbing out this fn, return 1.
5430 */
5431
5432typedef struct
5433{
5434 short idx;
5435 short width; /* Size of the text in pixel */
5436 Rect box;
5437} vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */
5438
5439#define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top)
5440
5441 static void
5442macMoveDialogItem(
5443 DialogRef theDialog,
5444 short itemNumber,
5445 short X,
5446 short Y,
5447 Rect *inBox)
5448{
5449#if 0 /* USE_CARBONIZED */
5450 /* Untested */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005451 MoveDialogItem(theDialog, itemNumber, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452 if (inBox != nil)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005453 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, inBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005454#else
5455 short itemType;
5456 Handle itemHandle;
5457 Rect localBox;
5458 Rect *itemBox = &localBox;
5459
5460 if (inBox != nil)
5461 itemBox = inBox;
5462
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005463 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, itemBox);
5464 OffsetRect(itemBox, -itemBox->left, -itemBox->top);
5465 OffsetRect(itemBox, X, Y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005466 /* To move a control (like a button) we need to call both
5467 * MoveControl and SetDialogItem. FAQ 6-18 */
5468 if (1) /*(itemType & kControlDialogItem) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005469 MoveControl((ControlRef) itemHandle, X, Y);
5470 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471#endif
5472}
5473
5474 static void
5475macSizeDialogItem(
5476 DialogRef theDialog,
5477 short itemNumber,
5478 short width,
5479 short height)
5480{
5481 short itemType;
5482 Handle itemHandle;
5483 Rect itemBox;
5484
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005485 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486
5487 /* When width or height is zero do not change it */
5488 if (width == 0)
5489 width = itemBox.right - itemBox.left;
5490 if (height == 0)
5491 height = itemBox.bottom - itemBox.top;
5492
5493#if 0 /* USE_CARBONIZED */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005494 SizeDialogItem(theDialog, itemNumber, width, height); /* Untested */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005495#else
5496 /* Resize the bounding box */
5497 itemBox.right = itemBox.left + width;
5498 itemBox.bottom = itemBox.top + height;
5499
5500 /* To resize a control (like a button) we need to call both
5501 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */
5502 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005503 SizeControl((ControlRef) itemHandle, width, height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504
5505 /* Configure back the item */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005506 SetDialogItem(theDialog, itemNumber, itemType, itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005507#endif
5508}
5509
5510 static void
5511macSetDialogItemText(
5512 DialogRef theDialog,
5513 short itemNumber,
5514 Str255 itemName)
5515{
5516 short itemType;
5517 Handle itemHandle;
5518 Rect itemBox;
5519
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005520 GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemBox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521
5522 if (itemType & kControlDialogItem)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005523 SetControlTitle((ControlRef) itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005524 else
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005525 SetDialogItemText(itemHandle, itemName);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005526}
5527
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005528
5529/* ModalDialog() handler for message dialogs that have hotkey accelerators.
5530 * Expects a mapping of hotkey char to control index in gDialogHotKeys;
5531 * setting gDialogHotKeys to NULL disables any hotkey handling.
5532 */
5533 static pascal Boolean
5534DialogHotkeyFilterProc (
5535 DialogRef theDialog,
5536 EventRecord *event,
5537 DialogItemIndex *itemHit)
5538{
5539 char_u keyHit;
5540
5541 if (event->what == keyDown || event->what == autoKey)
5542 {
5543 keyHit = (event->message & charCodeMask);
5544
5545 if (gDialogHotKeys && gDialogHotKeys[keyHit])
5546 {
5547#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5548 printf("user pressed hotkey '%c' --> item %d\n", keyHit, gDialogHotKeys[keyHit]);
5549#endif
5550 *itemHit = gDialogHotKeys[keyHit];
5551
5552 /* When handing off to StdFilterProc, pretend that the user
5553 * clicked the control manually. Note that this is also supposed
5554 * to cause the button to hilite briefly (to give some user
5555 * feedback), but this seems not to actually work (or it's too
5556 * fast to be seen).
5557 */
5558 event->what = kEventControlSimulateHit;
5559
5560 return true; /* we took care of it */
5561 }
5562
5563 /* Defer to the OS's standard behavior for this event.
5564 * This ensures that Enter will still activate the default button. */
5565 return StdFilterProc(theDialog, event, itemHit);
5566 }
5567 return false; /* Let ModalDialog deal with it */
5568}
5569
5570
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005571/* TODO: There have been some crashes with dialogs, check your inbox
5572 * (Jussi)
5573 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 int
5575gui_mch_dialog(
5576 int type,
5577 char_u *title,
5578 char_u *message,
5579 char_u *buttons,
5580 int dfltbutton,
Bram Moolenaard2c340a2011-01-17 20:08:11 +01005581 char_u *textfield,
5582 int ex_cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005583{
5584 Handle buttonDITL;
5585 Handle iconDITL;
5586 Handle inputDITL;
5587 Handle messageDITL;
5588 Handle itemHandle;
5589 Handle iconHandle;
5590 DialogPtr theDialog;
5591 char_u len;
5592 char_u PascalTitle[256]; /* place holder for the title */
5593 char_u name[256];
5594 GrafPtr oldPort;
5595 short itemHit;
5596 char_u *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005597 short hotKeys[256]; /* map of hotkey -> control ID */
5598 char_u aHotKey;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 Rect box;
5600 short button;
5601 short lastButton;
5602 short itemType;
5603 short useIcon;
5604 short width;
Bram Moolenaarec831732007-08-30 10:51:14 +00005605 short totalButtonWidth = 0; /* the width of all buttons together
Bram Moolenaar720c7102007-05-10 18:07:50 +00005606 including spacing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 short widestButton = 0;
5608 short dfltButtonEdge = 20; /* gut feeling */
5609 short dfltElementSpacing = 13; /* from IM:V.2-29 */
5610 short dfltIconSideSpace = 23; /* from IM:V.2-29 */
5611 short maximumWidth = 400; /* gut feeling */
5612 short maxButtonWidth = 175; /* gut feeling */
5613
5614 short vertical;
5615 short dialogHeight;
5616 short messageLines = 3;
5617 FontInfo textFontInfo;
5618
5619 vgmDlgItm iconItm;
5620 vgmDlgItm messageItm;
5621 vgmDlgItm inputItm;
5622 vgmDlgItm buttonItm;
5623
5624 WindowRef theWindow;
5625
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005626 ModalFilterUPP dialogUPP;
5627
Bram Moolenaar071d4272004-06-13 20:20:40 +00005628 /* Check 'v' flag in 'guioptions': vertical button placement. */
5629 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
5630
5631 /* Create a new Dialog Box from template. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005632 theDialog = GetNewDialog(129, nil, (WindowRef) -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633
5634 /* Get the WindowRef */
5635 theWindow = GetDialogWindow(theDialog);
5636
5637 /* Hide the window.
5638 * 1. to avoid seeing slow drawing
5639 * 2. to prevent a problem seen while moving dialog item
5640 * within a visible window. (non-Carbon MacOS 9)
5641 * Could be avoided by changing the resource.
5642 */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005643 HideWindow(theWindow);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644
5645 /* Change the graphical port to the dialog,
5646 * so we can measure the text with the proper font */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005647 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005648 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005649
5650 /* Get the info about the default text,
5651 * used to calculate the height of the message
5652 * and of the text field */
5653 GetFontInfo(&textFontInfo);
5654
5655 /* Set the dialog title */
5656 if (title != NULL)
5657 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005658 (void) C2PascalString(title, &PascalTitle);
5659 SetWTitle(theWindow, PascalTitle);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 }
5661
5662 /* Creates the buttons and add them to the Dialog Box. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005663 buttonDITL = GetResource('DITL', 130);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005664 buttonChar = buttons;
5665 button = 0;
5666
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005667 /* initialize the hotkey mapping */
Bram Moolenaar7db5fc82010-05-24 11:59:29 +02005668 vim_memset(hotKeys, 0, sizeof(hotKeys));
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005669
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 for (;*buttonChar != 0;)
5671 {
5672 /* Get the name of the button */
5673 button++;
5674 len = 0;
5675 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++)
5676 {
5677 if (*buttonChar != DLG_HOTKEY_CHAR)
5678 name[++len] = *buttonChar;
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005679 else
5680 {
5681 aHotKey = (char_u)*(buttonChar+1);
5682 if (aHotKey >= 'A' && aHotKey <= 'Z')
5683 aHotKey = (char_u)((int)aHotKey + (int)'a' - (int)'A');
5684 hotKeys[aHotKey] = button;
5685#ifdef DEBUG_MAC_DIALOG_HOTKEYS
5686 printf("### hotKey for button %d is '%c'\n", button, aHotKey);
5687#endif
5688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005690
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 if (*buttonChar != 0)
5692 buttonChar++;
5693 name[0] = len;
5694
5695 /* Add the button */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005696 AppendDITL(theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697
5698 /* Change the button's name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005699 macSetDialogItemText(theDialog, button, name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700
5701 /* Resize the button to fit its name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005702 width = StringWidth(name) + 2 * dfltButtonEdge;
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005703 /* Limit the size of any button to an acceptable value. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005704 /* TODO: Should be based on the message width */
5705 if (width > maxButtonWidth)
5706 width = maxButtonWidth;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005707 macSizeDialogItem(theDialog, button, width, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708
5709 totalButtonWidth += width;
5710
5711 if (width > widestButton)
5712 widestButton = width;
5713 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005714 ReleaseResource(buttonDITL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005715 lastButton = button;
5716
5717 /* Add the icon to the Dialog Box. */
5718 iconItm.idx = lastButton + 1;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005719 iconDITL = GetResource('DITL', 131);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 switch (type)
5721 {
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005722 case VIM_GENERIC:
5723 case VIM_INFO:
5724 case VIM_QUESTION: useIcon = kNoteIcon; break;
5725 case VIM_WARNING: useIcon = kCautionIcon; break;
5726 case VIM_ERROR: useIcon = kStopIcon; break;
Bram Moolenaar8d4eecc2012-11-20 17:19:01 +01005727 default: useIcon = kStopIcon;
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005728 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005729 AppendDITL(theDialog, iconDITL, overlayDITL);
5730 ReleaseResource(iconDITL);
5731 GetDialogItem(theDialog, iconItm.idx, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005732 /* TODO: Should the item be freed? */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005733 iconHandle = GetIcon(useIcon);
5734 SetDialogItem(theDialog, iconItm.idx, itemType, iconHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735
5736 /* Add the message to the Dialog box. */
5737 messageItm.idx = lastButton + 2;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005738 messageDITL = GetResource('DITL', 132);
5739 AppendDITL(theDialog, messageDITL, overlayDITL);
5740 ReleaseResource(messageDITL);
5741 GetDialogItem(theDialog, messageItm.idx, &itemType, &itemHandle, &box);
5742 (void) C2PascalString(message, &name);
5743 SetDialogItemText(itemHandle, name);
5744 messageItm.width = StringWidth(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005745
5746 /* Add the input box if needed */
5747 if (textfield != NULL)
5748 {
Bram Moolenaard68071d2006-05-02 22:08:30 +00005749 /* Cheat for now reuse the message and convert to text edit */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005750 inputItm.idx = lastButton + 3;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005751 inputDITL = GetResource('DITL', 132);
5752 AppendDITL(theDialog, inputDITL, overlayDITL);
5753 ReleaseResource(inputDITL);
5754 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5755/* SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/
5756 (void) C2PascalString(textfield, &name);
5757 SetDialogItemText(itemHandle, name);
5758 inputItm.width = StringWidth(name);
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005759
5760 /* Hotkeys don't make sense if there's a text field */
5761 gDialogHotKeys = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762 }
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005763 else
5764 /* Install hotkey table */
5765 gDialogHotKeys = (short *)&hotKeys;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005766
5767 /* Set the <ENTER> and <ESC> button. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005768 SetDialogDefaultItem(theDialog, dfltbutton);
5769 SetDialogCancelItem(theDialog, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770
5771 /* Reposition element */
5772
5773 /* Check if we need to force vertical */
5774 if (totalButtonWidth > maximumWidth)
5775 vertical = TRUE;
5776
5777 /* Place icon */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005778 macMoveDialogItem(theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779 iconItm.box.right = box.right;
5780 iconItm.box.bottom = box.bottom;
5781
5782 /* Place Message */
5783 messageItm.box.left = iconItm.box.right + dfltIconSideSpace;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005784 macSizeDialogItem(theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent));
5785 macMoveDialogItem(theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786
5787 /* Place Input */
5788 if (textfield != NULL)
5789 {
5790 inputItm.box.left = messageItm.box.left;
5791 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing;
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005792 macSizeDialogItem(theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent);
5793 macMoveDialogItem(theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794 /* Convert the static text into a text edit.
5795 * For some reason this change need to be done last (Dany) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005796 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box);
5797 SetDialogItem(theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005798 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767);
5799 }
5800
5801 /* Place Button */
5802 if (textfield != NULL)
5803 {
5804 buttonItm.box.left = inputItm.box.left;
5805 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing;
5806 }
5807 else
5808 {
5809 buttonItm.box.left = messageItm.box.left;
5810 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing;
5811 }
5812
5813 for (button=1; button <= lastButton; button++)
5814 {
5815
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005816 macMoveDialogItem(theDialog, button, buttonItm.box.left, buttonItm.box.top, &box);
Bram Moolenaarec831732007-08-30 10:51:14 +00005817 /* With vertical, it's better to have all buttons the same length */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005818 if (vertical)
5819 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005820 macSizeDialogItem(theDialog, button, widestButton, 0);
5821 GetDialogItem(theDialog, button, &itemType, &itemHandle, &box);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822 }
5823 /* Calculate position of next button */
5824 if (vertical)
5825 buttonItm.box.top = box.bottom + dfltElementSpacing;
5826 else
5827 buttonItm.box.left = box.right + dfltElementSpacing;
5828 }
5829
5830 /* Resize the dialog box */
5831 dialogHeight = box.bottom + dfltElementSpacing;
5832 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE);
5833
Bram Moolenaar071d4272004-06-13 20:20:40 +00005834 /* Magic resize */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005835 AutoSizeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005836 /* Need a horizontal resize anyway so not that useful */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005837
5838 /* Display it */
5839 ShowWindow(theWindow);
5840/* BringToFront(theWindow); */
5841 SelectWindow(theWindow);
5842
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005843/* DrawDialog(theDialog); */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005844#if 0
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005845 GetPort(&oldPort);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005846 SetPortDialogPort(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847#endif
5848
Bram Moolenaard68071d2006-05-02 22:08:30 +00005849#ifdef USE_CARBONKEYHANDLER
5850 /* Avoid that we use key events for the main window. */
5851 dialog_busy = TRUE;
5852#endif
5853
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005854 /* Prepare the shortcut-handling filterProc for handing to the dialog */
5855 dialogUPP = NewModalFilterUPP(DialogHotkeyFilterProc);
5856
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857 /* Hang until one of the button is hit */
5858 do
5859 {
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005860 ModalDialog(dialogUPP, &itemHit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861 } while ((itemHit < 1) || (itemHit > lastButton));
5862
Bram Moolenaard68071d2006-05-02 22:08:30 +00005863#ifdef USE_CARBONKEYHANDLER
5864 dialog_busy = FALSE;
5865#endif
5866
Bram Moolenaar071d4272004-06-13 20:20:40 +00005867 /* Copy back the text entered by the user into the param */
5868 if (textfield != NULL)
5869 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005870 GetDialogItem(theDialog, inputItm.idx, &itemType, &itemHandle, &box);
5871 GetDialogItemText(itemHandle, (char_u *) &name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872#if IOSIZE < 256
5873 /* Truncate the name to IOSIZE if needed */
5874 if (name[0] > IOSIZE)
5875 name[0] = IOSIZE - 1;
5876#endif
Bram Moolenaarbbebc852005-07-18 21:47:53 +00005877 vim_strncpy(textfield, &name[1], name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878 }
5879
5880 /* Restore the original graphical port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005881 SetPort(oldPort);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882
Bram Moolenaarc52da9d2008-03-20 13:39:37 +00005883 /* Free the modal filterProc */
5884 DisposeRoutineDescriptor(dialogUPP);
5885
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005886 /* Get ride of the dialog (free memory) */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005887 DisposeDialog(theDialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888
5889 return itemHit;
5890/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02005891 * Useful thing which could be used
Bram Moolenaar071d4272004-06-13 20:20:40 +00005892 * SetDialogTimeout(): Auto click a button after timeout
5893 * SetDialogTracksCursor() : Get the I-beam cursor over input box
5894 * MoveDialogItem(): Probably better than SetDialogItem
5895 * SizeDialogItem(): (but is it Carbon Only?)
Bram Moolenaar14d0e792007-08-30 08:35:35 +00005896 * AutoSizeDialog(): Magic resize of dialog based on text length
Bram Moolenaar071d4272004-06-13 20:20:40 +00005897 */
5898}
5899#endif /* FEAT_DIALOG_GUI */
5900
5901/*
5902 * Display the saved error message(s).
5903 */
5904#ifdef USE_MCH_ERRMSG
5905 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005906display_errors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907{
5908 char *p;
5909 char_u pError[256];
5910
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005911 if (error_ga.ga_data == NULL)
5912 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005914 /* avoid putting up a message box with blanks only */
5915 for (p = (char *)error_ga.ga_data; *p; ++p)
5916 if (!isspace(*p))
5917 {
5918 if (STRLEN(p) > 255)
5919 pError[0] = 255;
5920 else
5921 pError[0] = STRLEN(p);
5922
5923 STRNCPY(&pError[1], p, pError[0]);
5924 ParamText(pError, nil, nil, nil);
5925 Alert(128, nil);
5926 break;
5927 /* TODO: handled message longer than 256 chars
5928 * use auto-sizeable alert
5929 * or dialog with scrollbars (TextEdit zone)
5930 */
5931 }
5932 ga_clear(&error_ga);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005933}
5934#endif
5935
5936/*
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005937 * Get current mouse coordinates in text window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938 */
Bram Moolenaar5f2bb9f2005-01-11 21:29:04 +00005939 void
5940gui_mch_getmouse(int *x, int *y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941{
5942 Point where;
5943
5944 GetMouse(&where);
5945
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00005946 *x = where.h;
5947 *y = where.v;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948}
5949
5950 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005951gui_mch_setmouse(int x, int y)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005952{
5953 /* TODO */
5954#if 0
5955 /* From FAQ 3-11 */
5956
5957 CursorDevicePtr myMouse;
5958 Point where;
5959
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005960 if ( NGetTrapAddress(_CursorDeviceDispatch, ToolTrap)
5961 != NGetTrapAddress(_Unimplemented, ToolTrap))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 {
5963 /* New way */
5964
5965 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02005966 * Get first device with one button.
5967 * This will probably be the standard mouse
5968 * start at head of cursor dev list
Bram Moolenaar071d4272004-06-13 20:20:40 +00005969 *
5970 */
5971
5972 myMouse = nil;
5973
5974 do
5975 {
5976 /* Get the next cursor device */
5977 CursorDeviceNextDevice(&myMouse);
5978 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005979 while ((myMouse != nil) && (myMouse->cntButtons != 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00005981 CursorDeviceMoveTo(myMouse, x, y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982 }
5983 else
5984 {
5985 /* Old way */
5986 where.h = x;
5987 where.v = y;
5988
5989 *(Point *)RawMouse = where;
5990 *(Point *)MTemp = where;
5991 *(Ptr) CrsrNew = 0xFFFF;
5992 }
5993#endif
5994}
5995
5996 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00005997gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005998{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005999/*
6000 * Clone PopUp to use menu
6001 * Create a object descriptor for the current selection
6002 * Call the procedure
6003 */
6004
6005 MenuHandle CntxMenu;
6006 Point where;
6007 OSStatus status;
6008 UInt32 CntxType;
6009 SInt16 CntxMenuID;
6010 UInt16 CntxMenuItem;
6011 Str255 HelpName = "";
6012 GrafPtr savePort;
6013
6014 /* Save Current Port: On MacOS X we seem to lose the port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006015 GetPort(&savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006016
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006017 GetMouse(&where);
6018 LocalToGlobal(&where); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006019 CntxMenu = menu->submenu_handle;
6020
6021 /* TODO: Get the text selection from Vim */
6022
6023 /* Call to Handle Popup */
Bram Moolenaar48c2c9a2007-03-08 19:34:12 +00006024 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemRemoveHelp,
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006025 HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006026
6027 if (status == noErr)
6028 {
6029 if (CntxType == kCMMenuItemSelected)
6030 {
6031 /* Handle the menu CntxMenuID, CntxMenuItem */
6032 /* The submenu can be handle directly by gui_mac_handle_menu */
Bram Moolenaaradcb9492006-10-17 10:51:57 +00006033 /* But what about the current menu, is the menu changed by
6034 * ContextualMenuSelect */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006035 gui_mac_handle_menu((CntxMenuID << 16) + CntxMenuItem);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006036 }
6037 else if (CntxMenuID == kCMShowHelpSelected)
6038 {
6039 /* Should come up with the help */
6040 }
6041 }
6042
6043 /* Restore original Port */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006044 SetPort(savePort); /*OSX*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006045}
6046
6047#if defined(FEAT_CW_EDITOR) || defined(PROTO)
6048/* TODO: Is it need for MACOS_X? (Dany) */
6049 void
6050mch_post_buffer_write(buf_T *buf)
6051{
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006052 GetFSSpecFromPath(buf->b_ffname, &buf->b_FSSpec);
6053 Send_KAHL_MOD_AE(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006054}
6055#endif
6056
6057#ifdef FEAT_TITLE
6058/*
6059 * Set the window title and icon.
6060 * (The icon is not taken care of).
6061 */
6062 void
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006063gui_mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064{
6065 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller
6066 * that 256. Even better get it to fit nicely in the titlebar.
6067 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006068#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006069 CFStringRef windowTitle;
6070 size_t windowTitleLen;
6071#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 char_u *pascalTitle;
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006073#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074
6075 if (title == NULL) /* nothing to do */
6076 return;
6077
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +00006078#ifdef MACOS_CONVERT
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006079 windowTitleLen = STRLEN(title);
Bram Moolenaar446cb832008-06-24 21:56:24 +00006080 windowTitle = (CFStringRef)mac_enc_to_cfstring(title, windowTitleLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006081
6082 if (windowTitle)
6083 {
6084 SetWindowTitleWithCFString(gui.VimWindow, windowTitle);
6085 CFRelease(windowTitle);
6086 }
6087#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006088 pascalTitle = C2Pascal_save(title);
6089 if (pascalTitle != NULL)
6090 {
6091 SetWTitle(gui.VimWindow, pascalTitle);
6092 vim_free(pascalTitle);
6093 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00006094#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006095}
6096#endif
6097
6098/*
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006099 * Transferred from os_mac.c for MacOS X using os_unix.c prep work
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100 */
6101
6102 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006103C2PascalString(char_u *CString, Str255 *PascalString)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104{
6105 char_u *PascalPtr = (char_u *) PascalString;
6106 int len;
6107 int i;
6108
6109 PascalPtr[0] = 0;
6110 if (CString == NULL)
6111 return 0;
6112
6113 len = STRLEN(CString);
6114 if (len > 255)
6115 len = 255;
6116
6117 for (i = 0; i < len; i++)
6118 PascalPtr[i+1] = CString[i];
6119
6120 PascalPtr[0] = len;
6121
6122 return 0;
6123}
6124
6125 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006126GetFSSpecFromPath(char_u *file, FSSpec *fileFSSpec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006127{
6128 /* From FAQ 8-12 */
6129 Str255 filePascal;
6130 CInfoPBRec myCPB;
6131 OSErr err;
6132
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006133 (void) C2PascalString(file, &filePascal);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134
6135 myCPB.dirInfo.ioNamePtr = filePascal;
6136 myCPB.dirInfo.ioVRefNum = 0;
6137 myCPB.dirInfo.ioFDirIndex = 0;
6138 myCPB.dirInfo.ioDrDirID = 0;
6139
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006140 err= PBGetCatInfo(&myCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141
6142 /* vRefNum, dirID, name */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006143 FSMakeFSSpec(0, 0, filePascal, fileFSSpec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144
6145 /* TODO: Use an error code mechanism */
6146 return 0;
6147}
6148
6149/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006150 * Convert a FSSpec to a full path
Bram Moolenaar071d4272004-06-13 20:20:40 +00006151 */
6152
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006153char_u *FullPathFromFSSpec_save(FSSpec file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006154{
6155 /*
6156 * TODO: Add protection for 256 char max.
6157 */
6158
6159 CInfoPBRec theCPB;
6160 char_u fname[256];
6161 char_u *filenamePtr = fname;
6162 OSErr error;
6163 int folder = 1;
6164#ifdef USE_UNIXFILENAME
6165 SInt16 dfltVol_vRefNum;
6166 SInt32 dfltVol_dirID;
6167 FSRef refFile;
6168 OSStatus status;
6169 UInt32 pathSize = 256;
6170 char_u pathname[256];
6171 char_u *path = pathname;
6172#else
6173 Str255 directoryName;
6174 char_u temporary[255];
6175 char_u *temporaryPtr = temporary;
6176#endif
6177
6178#ifdef USE_UNIXFILENAME
6179 /* Get the default volume */
6180 /* TODO: Remove as this only work if Vim is on the Boot Volume*/
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006181 error=HGetVol(NULL, &dfltVol_vRefNum, &dfltVol_dirID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006182
6183 if (error)
6184 return NULL;
6185#endif
6186
6187 /* Start filling fname with file.name */
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006188 vim_strncpy(filenamePtr, &file.name[1], file.name[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006189
6190 /* Get the info about the file specified in FSSpec */
6191 theCPB.dirInfo.ioFDirIndex = 0;
6192 theCPB.dirInfo.ioNamePtr = file.name;
6193 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006194 /*theCPB.hFileInfo.ioDirID = 0;*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00006195 theCPB.dirInfo.ioDrDirID = file.parID;
6196
6197 /* As ioFDirIndex = 0, get the info of ioNamePtr,
6198 which is relative to ioVrefNum, ioDirID */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006199 error = PBGetCatInfo(&theCPB, false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006200
6201 /* If we are called for a new file we expect fnfErr */
6202 if ((error) && (error != fnfErr))
6203 return NULL;
6204
6205 /* Check if it's a file or folder */
6206 /* default to file if file don't exist */
6207 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error))
6208 folder = 0; /* It's not a folder */
6209 else
6210 folder = 1;
6211
6212#ifdef USE_UNIXFILENAME
6213 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006214 * The functions used here are available in Carbon, but do nothing on
6215 * MacOS 8 and 9.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006216 */
6217 if (error == fnfErr)
6218 {
6219 /* If the file to be saved does not already exist, it isn't possible
6220 to convert its FSSpec into an FSRef. But we can construct an
6221 FSSpec for the file's parent folder (since we have its volume and
6222 directory IDs), and since that folder does exist, we can convert
6223 that FSSpec into an FSRef, convert the FSRef in turn into a path,
6224 and, finally, append the filename. */
6225 FSSpec dirSpec;
6226 FSRef dirRef;
6227 Str255 emptyFilename = "\p";
6228 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum,
6229 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec);
6230 if (error)
6231 return NULL;
6232
6233 error = FSpMakeFSRef(&dirSpec, &dirRef);
6234 if (error)
6235 return NULL;
6236
6237 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize);
6238 if (status)
6239 return NULL;
6240
6241 STRCAT(path, "/");
6242 STRCAT(path, filenamePtr);
6243 }
6244 else
6245 {
6246 /* If the file to be saved already exists, we can get its full path
6247 by converting its FSSpec into an FSRef. */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006248 error=FSpMakeFSRef(&file, &refFile);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 if (error)
6250 return NULL;
6251
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006252 status=FSRefMakePath(&refFile, (UInt8 *) path, pathSize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253 if (status)
6254 return NULL;
6255 }
6256
6257 /* Add a slash at the end if needed */
6258 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006259 STRCAT(path, "/");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006260
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006261 return (vim_strsave(path));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006262#else
6263 /* TODO: Get rid of all USE_UNIXFILENAME below */
6264 /* Set ioNamePtr, it's the same area which is always reused. */
6265 theCPB.dirInfo.ioNamePtr = directoryName;
6266
6267 /* Trick for first entry, set ioDrParID to the first value
6268 * we want for ioDrDirID*/
6269 theCPB.dirInfo.ioDrParID = file.parID;
6270 theCPB.dirInfo.ioDrDirID = file.parID;
6271
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006272 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006273 do
6274 {
6275 theCPB.dirInfo.ioFDirIndex = -1;
6276 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6277 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006278 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006279 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6280
6281 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6282 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006283 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284
6285 if (error)
6286 return NULL;
6287
6288 /* Put the new directoryName in front of the current fname */
6289 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006290 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 STRCAT(filenamePtr, ":");
6292 STRCAT(filenamePtr, temporaryPtr);
6293 }
6294#if 1 /* def USE_UNIXFILENAME */
6295 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */
6296 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/);
6297#else
6298 while (theCPB.dirInfo.ioDrDirID != fsRtDirID);
6299#endif
6300
6301 /* Get the information about the volume on which the file reside */
6302 theCPB.dirInfo.ioFDirIndex = -1;
6303 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */
6304 theCPB.dirInfo.ioVRefNum = file.vRefNum;
Bram Moolenaar720c7102007-05-10 18:07:50 +00006305 /* theCPB.dirInfo.ioDirID = irrelevant when ioFDirIndex = -1 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID;
6307
6308 /* As ioFDirIndex = -1, get the info of ioDrDirID, */
6309 /* *ioNamePtr[0 TO 31] will be updated */
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006310 error = PBGetCatInfo(&theCPB,false);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311
6312 if (error)
6313 return NULL;
6314
6315 /* For MacOS Classic always add the volume name */
6316 /* For MacOS X add the volume name preceded by "Volumes" */
Bram Moolenaar720c7102007-05-10 18:07:50 +00006317 /* when we are not referring to the boot volume */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318#ifdef USE_UNIXFILENAME
6319 if (file.vRefNum != dfltVol_vRefNum)
6320#endif
6321 {
6322 /* Add the volume name */
6323 STRCPY(temporaryPtr, filenamePtr);
Bram Moolenaarbbebc852005-07-18 21:47:53 +00006324 vim_strncpy(filenamePtr, &directoryName[1], directoryName[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325 STRCAT(filenamePtr, ":");
6326 STRCAT(filenamePtr, temporaryPtr);
6327
6328#ifdef USE_UNIXFILENAME
6329 STRCPY(temporaryPtr, filenamePtr);
6330 filenamePtr[0] = 0; /* NULL terminate the string */
6331 STRCAT(filenamePtr, "Volumes:");
6332 STRCAT(filenamePtr, temporaryPtr);
6333#endif
6334 }
6335
6336 /* Append final path separator if it's a folder */
6337 if (folder)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006338 STRCAT(fname, ":");
Bram Moolenaar071d4272004-06-13 20:20:40 +00006339
6340 /* As we use Unix File Name for MacOS X convert it */
6341#ifdef USE_UNIXFILENAME
6342 /* Need to insert leading / */
6343 /* TODO: get the above code to use directly the / */
6344 STRCPY(&temporaryPtr[1], filenamePtr);
6345 temporaryPtr[0] = '/';
6346 STRCPY(filenamePtr, temporaryPtr);
6347 {
6348 char *p;
6349 for (p = fname; *p; p++)
6350 if (*p == ':')
6351 *p = '/';
6352 }
6353#endif
6354
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00006355 return (vim_strsave(fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356#endif
6357}
6358
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006359#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006360/*
6361 * Input Method Control functions.
6362 */
6363
6364/*
6365 * Notify cursor position to IM.
6366 */
6367 void
6368im_set_position(int row, int col)
6369{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006370#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006371 /* TODO: Implement me! */
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006372 im_start_row = row;
6373 im_start_col = col;
6374#endif
6375}
6376
6377static ScriptLanguageRecord gTSLWindow;
6378static ScriptLanguageRecord gTSLInsert;
6379static ScriptLanguageRecord gTSLDefault = { 0, 0 };
6380
6381static Component gTSCWindow;
6382static Component gTSCInsert;
6383static Component gTSCDefault;
6384
6385static int im_initialized = 0;
6386
6387 static void
6388im_on_window_switch(int active)
6389{
6390 ScriptLanguageRecord *slptr = NULL;
6391 OSStatus err;
6392
6393 if (! gui.in_use)
6394 return;
6395
6396 if (im_initialized == 0)
6397 {
6398 im_initialized = 1;
6399
6400 /* save default TSM component (should be U.S.) to default */
6401 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6402 kKeyboardInputMethodClass);
6403 }
6404
6405 if (active == TRUE)
6406 {
6407 im_is_active = TRUE;
6408 ActivateTSMDocument(gTSMDocument);
6409 slptr = &gTSLWindow;
6410
6411 if (slptr)
6412 {
6413 err = SetDefaultInputMethodOfClass(gTSCWindow, slptr,
6414 kKeyboardInputMethodClass);
6415 if (err == noErr)
6416 err = SetTextServiceLanguage(slptr);
6417
6418 if (err == noErr)
6419 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6420 }
6421 }
6422 else
6423 {
6424 err = GetTextServiceLanguage(&gTSLWindow);
6425 if (err == noErr)
6426 slptr = &gTSLWindow;
6427
6428 if (slptr)
6429 GetDefaultInputMethodOfClass(&gTSCWindow, slptr,
6430 kKeyboardInputMethodClass);
6431
6432 im_is_active = FALSE;
6433 DeactivateTSMDocument(gTSMDocument);
6434 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435}
6436
6437/*
6438 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
6439 */
6440 void
6441im_set_active(int active)
6442{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006443 ScriptLanguageRecord *slptr = NULL;
6444 OSStatus err;
6445
6446 if (! gui.in_use)
6447 return;
6448
6449 if (im_initialized == 0)
6450 {
6451 im_initialized = 1;
6452
6453 /* save default TSM component (should be U.S.) to default */
6454 GetDefaultInputMethodOfClass(&gTSCDefault, &gTSLDefault,
6455 kKeyboardInputMethodClass);
6456 }
6457
6458 if (active == TRUE)
6459 {
6460 im_is_active = TRUE;
6461 ActivateTSMDocument(gTSMDocument);
6462 slptr = &gTSLInsert;
6463
6464 if (slptr)
6465 {
6466 err = SetDefaultInputMethodOfClass(gTSCInsert, slptr,
6467 kKeyboardInputMethodClass);
6468 if (err == noErr)
6469 err = SetTextServiceLanguage(slptr);
6470
6471 if (err == noErr)
6472 KeyScript(slptr->fScript | smKeyForceKeyScriptMask);
6473 }
6474 }
6475 else
6476 {
6477 err = GetTextServiceLanguage(&gTSLInsert);
6478 if (err == noErr)
6479 slptr = &gTSLInsert;
6480
6481 if (slptr)
6482 GetDefaultInputMethodOfClass(&gTSCInsert, slptr,
6483 kKeyboardInputMethodClass);
6484
6485 /* restore to default when switch to normal mode, so than we could
6486 * enter commands easier */
6487 SetDefaultInputMethodOfClass(gTSCDefault, &gTSLDefault,
6488 kKeyboardInputMethodClass);
6489 SetTextServiceLanguage(&gTSLDefault);
6490
6491 im_is_active = FALSE;
6492 DeactivateTSMDocument(gTSMDocument);
6493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006494}
6495
6496/*
6497 * Get IM status. When IM is on, return not 0. Else return 0.
6498 */
6499 int
Bram Moolenaar2c7a29c2005-12-12 22:02:31 +00006500im_get_status(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006501{
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006502 if (! gui.in_use)
6503 return 0;
6504
6505 return im_is_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506}
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006507
Bram Moolenaar071d4272004-06-13 20:20:40 +00006508#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006509
6510
6511
6512
6513#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
6514// drawer implementation
6515static MenuRef contextMenu = NULL;
6516enum
6517{
6518 kTabContextMenuId = 42,
6519};
6520
6521// the caller has to CFRelease() the returned string
6522 static CFStringRef
6523getTabLabel(tabpage_T *page)
6524{
6525 get_tabline_label(page, FALSE);
6526#ifdef MACOS_CONVERT
Bram Moolenaar446cb832008-06-24 21:56:24 +00006527 return (CFStringRef)mac_enc_to_cfstring(NameBuff, STRLEN(NameBuff));
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006528#else
6529 // TODO: check internal encoding?
6530 return CFStringCreateWithCString(kCFAllocatorDefault, (char *)NameBuff,
6531 kCFStringEncodingMacRoman);
6532#endif
6533}
6534
6535
6536#define DRAWER_SIZE 150
6537#define DRAWER_INSET 16
6538
6539static ControlRef dataBrowser = NULL;
6540
6541// when the tabline is hidden, vim doesn't call update_tabline(). When
Bram Moolenaarb05034a2010-09-21 17:34:31 +02006542// the tabline is shown again, show_tabline() is called before update_tabline(),
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006543// and because of this, the tab labels and vim's internal tabs are out of sync
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006544// for a very short time. to prevent inconsistent state, we store the labels
6545// of the tabs, not pointers to the tabs (which are invalid for a short time).
6546static CFStringRef *tabLabels = NULL;
6547static int tabLabelsSize = 0;
6548
6549enum
6550{
6551 kTabsColumn = 'Tabs'
6552};
6553
6554 static int
6555getTabCount(void)
6556{
6557 tabpage_T *tp;
6558 int numTabs = 0;
6559
6560 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006561 ++numTabs;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006562 return numTabs;
6563}
6564
6565// data browser item display callback
6566 static OSStatus
6567dbItemDataCallback(ControlRef browser,
6568 DataBrowserItemID itemID,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006569 DataBrowserPropertyID property /* column id */,
6570 DataBrowserItemDataRef itemData,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006571 Boolean changeValue)
6572{
6573 OSStatus status = noErr;
6574
6575 // assert(property == kTabsColumn); // why is this violated??
6576
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02006577 // changeValue is true if we have a modifiable list and data was changed.
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006578 // In our case, it's always false.
6579 // (that is: if (changeValue) updateInternalData(); else return
6580 // internalData();
6581 if (!changeValue)
6582 {
6583 CFStringRef str;
6584
6585 assert(itemID - 1 >= 0 && itemID - 1 < tabLabelsSize);
6586 str = tabLabels[itemID - 1];
6587 status = SetDataBrowserItemDataText(itemData, str);
6588 }
6589 else
6590 status = errDataBrowserPropertyNotSupported;
6591
6592 return status;
6593}
6594
6595// data browser action callback
6596 static void
6597dbItemNotificationCallback(ControlRef browser,
6598 DataBrowserItemID item,
6599 DataBrowserItemNotification message)
6600{
6601 switch (message)
6602 {
6603 case kDataBrowserItemSelected:
6604 send_tabline_event(item);
6605 break;
6606 }
6607}
6608
6609// callbacks needed for contextual menu:
6610 static void
6611dbGetContextualMenuCallback(ControlRef browser,
6612 MenuRef *menu,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006613 UInt32 *helpType,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006614 CFStringRef *helpItemString,
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006615 AEDesc *selection)
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006616{
6617 // on mac os 9: kCMHelpItemNoHelp, but it's not the same
6618 *helpType = kCMHelpItemRemoveHelp; // OS X only ;-)
6619 *helpItemString = NULL;
6620
6621 *menu = contextMenu;
6622}
6623
6624 static void
6625dbSelectContextualMenuCallback(ControlRef browser,
6626 MenuRef menu,
6627 UInt32 selectionType,
6628 SInt16 menuID,
6629 MenuItemIndex menuItem)
6630{
6631 if (selectionType == kCMMenuItemSelected)
6632 {
6633 MenuCommand command;
6634 GetMenuItemCommandID(menu, menuItem, &command);
6635
6636 // get tab that was selected when the context menu appeared
6637 // (there is always one tab selected). TODO: check if the context menu
6638 // isn't opened on an item but on empty space (has to be possible some
6639 // way, the finder does it too ;-) )
6640 Handle items = NewHandle(0);
6641 if (items != NULL)
6642 {
6643 int numItems;
6644
6645 GetDataBrowserItems(browser, kDataBrowserNoItem, false,
6646 kDataBrowserItemIsSelected, items);
6647 numItems = GetHandleSize(items) / sizeof(DataBrowserItemID);
6648 if (numItems > 0)
6649 {
6650 int idx;
6651 DataBrowserItemID *itemsPtr;
6652
6653 HLock(items);
6654 itemsPtr = (DataBrowserItemID *)*items;
6655 idx = itemsPtr[0];
6656 HUnlock(items);
6657 send_tabline_menu_event(idx, command);
6658 }
6659 DisposeHandle(items);
6660 }
6661 }
6662}
6663
6664// focus callback of the data browser to always leave focus in vim
6665 static OSStatus
6666dbFocusCallback(EventHandlerCallRef handler, EventRef event, void *data)
6667{
6668 assert(GetEventClass(event) == kEventClassControl
6669 && GetEventKind(event) == kEventControlSetFocusPart);
6670
6671 return paramErr;
6672}
6673
6674
6675// drawer callback to resize data browser to drawer size
6676 static OSStatus
6677drawerCallback(EventHandlerCallRef handler, EventRef event, void *data)
6678{
6679 switch (GetEventKind(event))
6680 {
6681 case kEventWindowBoundsChanged: // move or resize
6682 {
6683 UInt32 attribs;
6684 GetEventParameter(event, kEventParamAttributes, typeUInt32,
6685 NULL, sizeof(attribs), NULL, &attribs);
6686 if (attribs & kWindowBoundsChangeSizeChanged) // resize
6687 {
6688 Rect r;
6689 GetWindowBounds(drawer, kWindowContentRgn, &r);
6690 SetRect(&r, 0, 0, r.right - r.left, r.bottom - r.top);
6691 SetControlBounds(dataBrowser, &r);
6692 SetDataBrowserTableViewNamedColumnWidth(dataBrowser,
6693 kTabsColumn, r.right);
6694 }
6695 }
6696 break;
6697 }
6698
6699 return eventNotHandledErr;
6700}
6701
6702// Load DataBrowserChangeAttributes() dynamically on tiger (and better).
6703// This way the code works on 10.2 and 10.3 as well (it doesn't have the
6704// blue highlights in the list view on these systems, though. Oh well.)
6705
6706
6707#import <mach-o/dyld.h>
6708
6709enum { kMyDataBrowserAttributeListViewAlternatingRowColors = (1 << 1) };
6710
6711 static OSStatus
6712myDataBrowserChangeAttributes(ControlRef inDataBrowser,
6713 OptionBits inAttributesToSet,
6714 OptionBits inAttributesToClear)
6715{
6716 long osVersion;
6717 char *symbolName;
6718 NSSymbol symbol = NULL;
6719 OSStatus (*dataBrowserChangeAttributes)(ControlRef inDataBrowser,
6720 OptionBits inAttributesToSet, OptionBits inAttributesToClear);
6721
6722 Gestalt(gestaltSystemVersion, &osVersion);
6723 if (osVersion < 0x1040) // only supported for 10.4 (and up)
6724 return noErr;
6725
6726 // C name mangling...
6727 symbolName = "_DataBrowserChangeAttributes";
6728 if (!NSIsSymbolNameDefined(symbolName)
6729 || (symbol = NSLookupAndBindSymbol(symbolName)) == NULL)
6730 return noErr;
6731
6732 dataBrowserChangeAttributes = NSAddressOfSymbol(symbol);
6733 if (dataBrowserChangeAttributes == NULL)
6734 return noErr; // well...
6735 return dataBrowserChangeAttributes(inDataBrowser,
6736 inAttributesToSet, inAttributesToClear);
6737}
6738
6739 static void
6740initialise_tabline(void)
6741{
6742 Rect drawerRect = { 0, 0, 0, DRAWER_SIZE };
6743 DataBrowserCallbacks dbCallbacks;
6744 EventTypeSpec focusEvent = {kEventClassControl, kEventControlSetFocusPart};
6745 EventTypeSpec resizeEvent = {kEventClassWindow, kEventWindowBoundsChanged};
6746 DataBrowserListViewColumnDesc colDesc;
6747
6748 // drawers have to have compositing enabled
6749 CreateNewWindow(kDrawerWindowClass,
6750 kWindowStandardHandlerAttribute
6751 | kWindowCompositingAttribute
6752 | kWindowResizableAttribute
6753 | kWindowLiveResizeAttribute,
6754 &drawerRect, &drawer);
6755
6756 SetThemeWindowBackground(drawer, kThemeBrushDrawerBackground, true);
6757 SetDrawerParent(drawer, gui.VimWindow);
6758 SetDrawerOffsets(drawer, kWindowOffsetUnchanged, DRAWER_INSET);
6759
6760
6761 // create list view embedded in drawer
6762 CreateDataBrowserControl(drawer, &drawerRect, kDataBrowserListView,
6763 &dataBrowser);
6764
6765 dbCallbacks.version = kDataBrowserLatestCallbacks;
6766 InitDataBrowserCallbacks(&dbCallbacks);
6767 dbCallbacks.u.v1.itemDataCallback =
6768 NewDataBrowserItemDataUPP(dbItemDataCallback);
6769 dbCallbacks.u.v1.itemNotificationCallback =
6770 NewDataBrowserItemNotificationUPP(dbItemNotificationCallback);
6771 dbCallbacks.u.v1.getContextualMenuCallback =
6772 NewDataBrowserGetContextualMenuUPP(dbGetContextualMenuCallback);
6773 dbCallbacks.u.v1.selectContextualMenuCallback =
6774 NewDataBrowserSelectContextualMenuUPP(dbSelectContextualMenuCallback);
6775
6776 SetDataBrowserCallbacks(dataBrowser, &dbCallbacks);
6777
6778 SetDataBrowserListViewHeaderBtnHeight(dataBrowser, 0); // no header
6779 SetDataBrowserHasScrollBars(dataBrowser, false, true); // only vertical
6780 SetDataBrowserSelectionFlags(dataBrowser,
6781 kDataBrowserSelectOnlyOne | kDataBrowserNeverEmptySelectionSet);
6782 SetDataBrowserTableViewHiliteStyle(dataBrowser,
6783 kDataBrowserTableViewFillHilite);
6784 Boolean b = false;
6785 SetControlData(dataBrowser, kControlEntireControl,
6786 kControlDataBrowserIncludesFrameAndFocusTag, sizeof(b), &b);
6787
6788 // enable blue background in data browser (this is only in 10.4 and vim
6789 // has to support older osx versions as well, so we have to load this
6790 // function dynamically)
6791 myDataBrowserChangeAttributes(dataBrowser,
6792 kMyDataBrowserAttributeListViewAlternatingRowColors, 0);
6793
6794 // install callback that keeps focus in vim and away from the data browser
6795 InstallControlEventHandler(dataBrowser, dbFocusCallback, 1, &focusEvent,
6796 NULL, NULL);
6797
6798 // install callback that keeps data browser at the size of the drawer
6799 InstallWindowEventHandler(drawer, drawerCallback, 1, &resizeEvent,
6800 NULL, NULL);
6801
6802 // add "tabs" column to data browser
6803 colDesc.propertyDesc.propertyID = kTabsColumn;
6804 colDesc.propertyDesc.propertyType = kDataBrowserTextType;
6805
6806 // add if items can be selected (?): kDataBrowserListViewSelectionColumn
6807 colDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
6808
6809 colDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
6810 colDesc.headerBtnDesc.minimumWidth = 100;
6811 colDesc.headerBtnDesc.maximumWidth = 150;
6812 colDesc.headerBtnDesc.titleOffset = 0;
6813 colDesc.headerBtnDesc.titleString = CFSTR("Tabs");
6814 colDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
6815 colDesc.headerBtnDesc.btnFontStyle.flags = 0; // use default font
6816 colDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
6817
6818 AddDataBrowserListViewColumn(dataBrowser, &colDesc, 0);
6819
6820 // create tabline popup menu required by vim docs (see :he tabline-menu)
6821 CreateNewMenu(kTabContextMenuId, 0, &contextMenu);
Bram Moolenaar7098ee52015-06-09 19:14:24 +02006822 if (first_tabpage->tp_next != NULL)
6823 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Close Tab"), 0,
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006824 TABLINE_MENU_CLOSE, NULL);
6825 AppendMenuItemTextWithCFString(contextMenu, CFSTR("New Tab"), 0,
6826 TABLINE_MENU_NEW, NULL);
6827 AppendMenuItemTextWithCFString(contextMenu, CFSTR("Open Tab..."), 0,
6828 TABLINE_MENU_OPEN, NULL);
6829}
6830
6831
6832/*
6833 * Show or hide the tabline.
6834 */
6835 void
6836gui_mch_show_tabline(int showit)
6837{
6838 if (showit == 0)
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006839 CloseDrawer(drawer, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006840 else
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006841 OpenDrawer(drawer, kWindowEdgeRight, true);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006842}
6843
6844/*
6845 * Return TRUE when tabline is displayed.
6846 */
6847 int
6848gui_mch_showing_tabline(void)
6849{
6850 WindowDrawerState state = GetDrawerState(drawer);
6851
6852 return state == kWindowDrawerOpen || state == kWindowDrawerOpening;
6853}
6854
6855/*
6856 * Update the labels of the tabline.
6857 */
6858 void
6859gui_mch_update_tabline(void)
6860{
6861 tabpage_T *tp;
6862 int numTabs = getTabCount();
6863 int nr = 1;
6864 int curtabidx = 1;
6865
6866 // adjust data browser
6867 if (tabLabels != NULL)
6868 {
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006869 int i;
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006870
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006871 for (i = 0; i < tabLabelsSize; ++i)
6872 CFRelease(tabLabels[i]);
6873 free(tabLabels);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006874 }
6875 tabLabels = (CFStringRef *)malloc(numTabs * sizeof(CFStringRef));
6876 tabLabelsSize = numTabs;
6877
6878 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
6879 {
6880 if (tp == curtab)
6881 curtabidx = nr;
Bram Moolenaar1b60e502008-03-12 13:40:54 +00006882 tabLabels[nr-1] = getTabLabel(tp);
Bram Moolenaar79ee3152007-04-26 16:20:50 +00006883 }
6884
6885 RemoveDataBrowserItems(dataBrowser, kDataBrowserNoItem, 0, NULL,
6886 kDataBrowserItemNoProperty);
6887 // data browser uses ids 1, 2, 3, ... numTabs per default, so we
6888 // can pass NULL for the id array
6889 AddDataBrowserItems(dataBrowser, kDataBrowserNoItem, numTabs, NULL,
6890 kDataBrowserItemNoProperty);
6891
6892 DataBrowserItemID item = curtabidx;
6893 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6894}
6895
6896/*
6897 * Set the current tab to "nr". First tab is 1.
6898 */
6899 void
6900gui_mch_set_curtab(nr)
6901 int nr;
6902{
6903 DataBrowserItemID item = nr;
6904 SetDataBrowserSelectedItems(dataBrowser, 1, &item, kDataBrowserItemsAssign);
6905
6906 // TODO: call something like this?: (or restore scroll position, or...)
6907 RevealDataBrowserItem(dataBrowser, item, kTabsColumn,
6908 kDataBrowserRevealOnly);
6909}
6910
6911#endif // FEAT_GUI_TABLINE