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