Mercurial > vim
comparison src/gui_mac.c @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | 4102fb4ea781 |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
1 /* 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 | |
7 * Port to MPW by Bernhard PrŸmmer | |
8 * 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 /* | |
16 * NOTE: Comment mentionning FAQ refer to the book: | |
17 * "Macworld Mac Programming FAQs" from "IDG Books" | |
18 */ | |
19 | |
20 /* | |
21 * WARNING: Vim must be able to compile without Carbon | |
22 * As the desired minimum requirement are circa System 7 | |
23 * (I want to run it on my Mac Classic) (Dany) | |
24 */ | |
25 | |
26 /* | |
27 * TODO: Change still to merge from the macvim's iDisk | |
28 * | |
29 * error_ga, mch_errmsg, Navigation's changes in gui_mch_browse | |
30 * uses of MenuItemIndex, changes in gui_mch_set_shellsize, | |
31 * ScrapManager error handling. | |
32 * Comments about function remaining to Carbonize. | |
33 * | |
34 */ | |
35 | |
36 /* TODO: find the best place for this (Dany) */ | |
37 #if 0 | |
38 # if ! TARGET_API_MAC_CARBON | |
39 /* Enable the new API functions even when not compiling for Carbon */ | |
40 /* Apple recomends Universal Interface 3.3.2 or later */ | |
41 # define OPAQUE_TOOLBOX_STRUCTS 1 | |
42 # define ACCESSOR_CALLS_ARE_FUNCTIONS 1 | |
43 /* Help Menu not supported by Carbon */ | |
44 # define USE_HELPMENU | |
45 # endif | |
46 #endif | |
47 | |
48 #include <Devices.h> /* included first to avoid CR problems */ | |
49 #include "vim.h" | |
50 | |
51 /* Enable Contextual Menu Support */ | |
52 #if UNIVERSAL_INTERFACES_VERSION >= 0x0320 | |
53 # define USE_CTRLCLICKMENU | |
54 #endif | |
55 | |
56 /* Put Vim Help in MacOS Help */ | |
57 #define USE_HELPMENU | |
58 | |
59 /* Enable AEVENT */ | |
60 #define USE_AEVENT | |
61 | |
62 /* Compile as CodeWarior External Editor */ | |
63 #if defined(FEAT_CW_EDITOR) && !defined(USE_AEVENT) | |
64 # define USE_AEVENT /* Need Apple Event Support */ | |
65 #endif | |
66 | |
67 /* The VIM creator is CodeWarior specific */ | |
68 #if !(defined(__MRC__) || defined(__SC__) || defined(__APPLE_CC__)) | |
69 # define USE_VIM_CREATOR_ID | |
70 #else | |
71 # if 0 /* Was this usefull for some compiler? (Dany) */ | |
72 static OSType _fcreator = 'VIM!'; | |
73 static OSType _ftype = 'TEXT'; | |
74 # endif | |
75 #endif | |
76 | |
77 /* CARBON version only tested with Project Builder under MacOS X */ | |
78 #undef USE_CARBONIZED | |
79 #if (defined(__APPLE_CC__) || defined(__MRC__)) && defined(TARGET_API_MAC_CARBON) | |
80 # if TARGET_API_MAC_CARBON | |
81 # define USE_CARBONIZED | |
82 # endif | |
83 #endif | |
84 | |
85 #undef USE_MOUSEWHEEL | |
86 #if defined(MACOS_X) && defined(USE_CARBONIZED) | |
87 # define USE_MOUSEWHEEL | |
88 static EventHandlerUPP mouseWheelHandlerUPP = NULL; | |
89 #endif | |
90 | |
91 /* Debugging feature: start Vim window OFFSETed */ | |
92 #undef USE_OFFSETED_WINDOW | |
93 | |
94 /* Debugging feature: use CodeWarior SIOUX */ | |
95 #undef USE_SIOUX | |
96 | |
97 | |
98 /* Include some file. TODO: move into os_mac.h */ | |
99 #include <Menus.h> | |
100 #include <Resources.h> | |
101 #if !TARGET_API_MAC_CARBON | |
102 #include <StandardFile.h> | |
103 #include <Traps.h> | |
104 #endif | |
105 #include <Balloons.h> | |
106 #include <Processes.h> | |
107 #ifdef USE_AEVENT | |
108 # include <AppleEvents.h> | |
109 # include <AERegistry.h> | |
110 #endif | |
111 #ifdef USE_CTRLCLICKMENU | |
112 # include <Gestalt.h> | |
113 #endif | |
114 #ifdef USE_SIOUX | |
115 # include <stdio.h> | |
116 # include <sioux.h> | |
117 # include <console.h> | |
118 #endif | |
119 #if UNIVERSAL_INTERFACES_VERSION >= 0x0330 | |
120 # include <ControlDefinitions.h> | |
121 # include <Navigation.h> /* Navigation only part of ?? */ | |
122 #endif | |
123 | |
124 #if TARGET_API_MAC_CARBON && 0 | |
125 /* New Help Interface for Mac, not implemented yet.*/ | |
126 # include <MacHelp.h> | |
127 #endif | |
128 | |
129 /* | |
130 * Translate new name to old ones | |
131 * New function only available in MacOS 8.5, | |
132 * So use old one to be compatible back to System 7 | |
133 */ | |
134 #ifndef USE_CARBONIZED | |
135 # undef EnableMenuItem | |
136 # define EnableMenuItem EnableItem | |
137 # undef DisableMenuItem | |
138 # define DisableMenuItem DisableItem | |
139 #endif | |
140 | |
141 /* Carbon does not support the Get/SetControll functions, | |
142 * use Get/SetControl32Bit instead and rename for non-carbon | |
143 * systems. | |
144 */ | |
145 | |
146 #ifndef USE_CARBONIZED | |
147 # undef SetControl32BitMaximum | |
148 # define SetControl32BitMaximum SetControlMaximum | |
149 # undef SetControl32BitMinimum | |
150 # define SetControl32BitMinimum SetControlMinimum | |
151 # undef SetControl32BitValue | |
152 # define SetControl32BitValue SetControlValue | |
153 # undef GetControl32BitValue | |
154 # define GetControl32BitValue GetControlValue | |
155 #endif | |
156 | |
157 /* | |
158 * ??? | |
159 */ | |
160 | |
161 #define kNothing 0 | |
162 #define kCreateEmpty 2 /*1*/ | |
163 #define kCreateRect 2 | |
164 #define kDestroy 3 | |
165 | |
166 /* | |
167 * Dany: Don't like those... | |
168 */ | |
169 | |
170 #define topLeft(r) (((Point*)&(r))[0]) | |
171 #define botRight(r) (((Point*)&(r))[1]) | |
172 | |
173 | |
174 /* Time of last mouse click, to detect double-click */ | |
175 static long lastMouseTick = 0; | |
176 | |
177 /* ??? */ | |
178 static RgnHandle cursorRgn; | |
179 static RgnHandle dragRgn; | |
180 static Rect dragRect; | |
181 static short dragRectEnbl; | |
182 static short dragRectControl; | |
183 | |
184 /* This variable is set when waiting for an event, which is the only moment | |
185 * scrollbar dragging can be done directly. It's not allowed while commands | |
186 * are executed, because it may move the cursor and that may cause unexpected | |
187 * problems (e.g., while ":s" is working). | |
188 */ | |
189 static int allow_scrollbar = FALSE; | |
190 | |
191 /* Last mouse click caused contextual menu, (to provide proper release) */ | |
192 #ifdef USE_CTRLCLICKMENU | |
193 static short clickIsPopup; | |
194 #endif | |
195 | |
196 /* Feedback Action for Scrollbar */ | |
197 ControlActionUPP gScrollAction; | |
198 ControlActionUPP gScrollDrag; | |
199 | |
200 /* Keeping track of which scrollbar is being dragged */ | |
201 static ControlHandle dragged_sb = NULL; | |
202 | |
203 /* | |
204 * The Quickdraw global is predefined in CodeWarior | |
205 * but is not in Apple MPW | |
206 */ | |
207 #if (defined(__MRC__) || defined(__SC__)) | |
208 # if !(defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON) | |
209 QDGlobals qd; | |
210 # endif | |
211 #endif | |
212 | |
213 /* Colors Macros */ | |
214 #define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b) | |
215 #define Red(c) ((c & 0x00FF0000) >> 16) | |
216 #define Green(c) ((c & 0x0000FF00) >> 8) | |
217 #define Blue(c) ((c & 0x000000FF) >> 0) | |
218 | |
219 /* Key mapping */ | |
220 | |
221 #define vk_Esc 0x35 /* -> 1B */ | |
222 | |
223 #define vk_F1 0x7A /* -> 10 */ | |
224 #define vk_F2 0x78 /*0x63*/ | |
225 #define vk_F3 0x63 /*0x76*/ | |
226 #define vk_F4 0x76 /*0x60*/ | |
227 #define vk_F5 0x60 /*0x61*/ | |
228 #define vk_F6 0x61 /*0x62*/ | |
229 #define vk_F7 0x62 /*0x63*/ /*?*/ | |
230 #define vk_F8 0x64 | |
231 #define vk_F9 0x65 | |
232 #define vk_F10 0x6D | |
233 #define vk_F11 0x67 | |
234 #define vk_F12 0x6F | |
235 #define vk_F13 0x69 | |
236 #define vk_F14 0x6B | |
237 #define vk_F15 0x71 | |
238 | |
239 #define vk_Clr 0x47 /* -> 1B (ESC) */ | |
240 #define vk_Enter 0x4C /* -> 03 */ | |
241 | |
242 #define vk_Space 0x31 /* -> 20 */ | |
243 #define vk_Tab 0x30 /* -> 09 */ | |
244 #define vk_Return 0x24 /* -> 0D */ | |
245 /* This is wrong for OSX, what is it for? */ | |
246 #define vk_Delete 0X08 /* -> 08 BackSpace */ | |
247 | |
248 #define vk_Help 0x72 /* -> 05 */ | |
249 #define vk_Home 0x73 /* -> 01 */ | |
250 #define vk_PageUp 0x74 /* -> 0D */ | |
251 #define vk_FwdDelete 0x75 /* -> 7F */ | |
252 #define vk_End 0x77 /* -> 04 */ | |
253 #define vk_PageDown 0x79 /* -> 0C */ | |
254 | |
255 #define vk_Up 0x7E /* -> 1E */ | |
256 #define vk_Down 0x7D /* -> 1F */ | |
257 #define vk_Left 0x7B /* -> 1C */ | |
258 #define vk_Right 0x7C /* -> 1D */ | |
259 | |
260 #define vk_Undo vk_F1 | |
261 #define vk_Cut vk_F2 | |
262 #define vk_Copy vk_F3 | |
263 #define vk_Paste vk_F4 | |
264 #define vk_PrintScreen vk_F13 | |
265 #define vk_SCrollLock vk_F14 | |
266 #define vk_Pause vk_F15 | |
267 #define vk_NumLock vk_Clr | |
268 #define vk_Insert vk_Help | |
269 | |
270 #define KeySym char | |
271 | |
272 static struct | |
273 { | |
274 KeySym key_sym; | |
275 char_u vim_code0; | |
276 char_u vim_code1; | |
277 } special_keys[] = | |
278 { | |
279 {vk_Up, 'k', 'u'}, | |
280 {vk_Down, 'k', 'd'}, | |
281 {vk_Left, 'k', 'l'}, | |
282 {vk_Right, 'k', 'r'}, | |
283 | |
284 {vk_F1, 'k', '1'}, | |
285 {vk_F2, 'k', '2'}, | |
286 {vk_F3, 'k', '3'}, | |
287 {vk_F4, 'k', '4'}, | |
288 {vk_F5, 'k', '5'}, | |
289 {vk_F6, 'k', '6'}, | |
290 {vk_F7, 'k', '7'}, | |
291 {vk_F8, 'k', '8'}, | |
292 {vk_F9, 'k', '9'}, | |
293 {vk_F10, 'k', ';'}, | |
294 | |
295 {vk_F11, 'F', '1'}, | |
296 {vk_F12, 'F', '2'}, | |
297 {vk_F13, 'F', '3'}, | |
298 {vk_F14, 'F', '4'}, | |
299 {vk_F15, 'F', '5'}, | |
300 | |
301 /* {XK_Help, '%', '1'}, */ | |
302 /* {XK_Undo, '&', '8'}, */ | |
303 /* {XK_BackSpace, 'k', 'b'}, */ | |
304 #ifndef MACOS_X | |
305 {vk_Delete, 'k', 'b'}, | |
306 #endif | |
307 {vk_Insert, 'k', 'I'}, | |
308 {vk_FwdDelete, 'k', 'D'}, | |
309 {vk_Home, 'k', 'h'}, | |
310 {vk_End, '@', '7'}, | |
311 /* {XK_Prior, 'k', 'P'}, */ | |
312 /* {XK_Next, 'k', 'N'}, */ | |
313 /* {XK_Print, '%', '9'}, */ | |
314 | |
315 {vk_PageUp, 'k', 'P'}, | |
316 {vk_PageDown, 'k', 'N'}, | |
317 | |
318 /* End of list marker: */ | |
319 {(KeySym)0, 0, 0} | |
320 }; | |
321 | |
322 /* | |
323 * ------------------------------------------------------------ | |
324 * Forward declaration (for those needed) | |
325 * ------------------------------------------------------------ | |
326 */ | |
327 | |
328 #ifdef USE_AEVENT | |
329 OSErr HandleUnusedParms (const AppleEvent *theAEvent); | |
330 #endif | |
331 | |
332 /* | |
333 * ------------------------------------------------------------ | |
334 * Conversion Utility | |
335 * ------------------------------------------------------------ | |
336 */ | |
337 | |
338 /* | |
339 * C2Pascal_save | |
340 * | |
341 * Allocate memory and convert the C-String passed in | |
342 * into a pascal string | |
343 * | |
344 */ | |
345 | |
346 char_u *C2Pascal_save(char_u *Cstring) | |
347 { | |
348 char_u *PascalString; | |
349 int len; | |
350 | |
351 if (Cstring == NULL) | |
352 return NULL; | |
353 | |
354 len = STRLEN(Cstring); | |
355 | |
356 if (len > 255) /* Truncate if necessary */ | |
357 len = 255; | |
358 | |
359 PascalString = alloc(len + 1); | |
360 if (PascalString != NULL) | |
361 { | |
362 mch_memmove(PascalString + 1, Cstring, len); | |
363 PascalString[0] = len; | |
364 } | |
365 | |
366 return PascalString; | |
367 } | |
368 | |
369 /* | |
370 * C2Pascal_save_and_remove_backslash | |
371 * | |
372 * Allocate memory and convert the C-String passed in | |
373 * into a pascal string. Also remove the backslash at the same time | |
374 * | |
375 */ | |
376 | |
377 char_u *C2Pascal_save_and_remove_backslash(char_u *Cstring) | |
378 { | |
379 char_u *PascalString; | |
380 int len; | |
381 char_u *p, *c; | |
382 | |
383 len = STRLEN(Cstring); | |
384 | |
385 if (len > 255) /* Truncate if necessary */ | |
386 len = 255; | |
387 | |
388 PascalString = alloc(len + 1); | |
389 if (PascalString != NULL) | |
390 { | |
391 for (c = Cstring, p = PascalString+1, len = 0; (*c != 0) && (len < 255); c++) | |
392 { | |
393 if ((*c == '\\') && (c[1] != 0)) | |
394 { | |
395 c++; | |
396 } | |
397 *p = *c; | |
398 p++; | |
399 len++; | |
400 } | |
401 PascalString[0] = len; | |
402 } | |
403 | |
404 return PascalString; | |
405 } | |
406 | |
407 /* | |
408 * Convert the modifiers of an Event into vim's modifiers (mouse) | |
409 */ | |
410 | |
411 int_u | |
412 EventModifiers2VimMouseModifiers(EventModifiers macModifiers) | |
413 { | |
414 int_u vimModifiers = 0x00; | |
415 | |
416 if (macModifiers & (shiftKey | rightShiftKey)) | |
417 vimModifiers |= MOUSE_SHIFT; | |
418 if (macModifiers & (controlKey | rightControlKey)) | |
419 vimModifiers |= MOUSE_CTRL; | |
420 if (macModifiers & (optionKey | rightOptionKey)) | |
421 vimModifiers |= MOUSE_ALT; | |
422 #if 0 | |
423 /* Not yet supported */ | |
424 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */ | |
425 vimModifiers |= MOUSE_CMD; | |
426 #endif | |
427 return (vimModifiers); | |
428 } | |
429 | |
430 /* | |
431 * Convert the modifiers of an Event into vim's modifiers (keys) | |
432 */ | |
433 | |
434 static int_u | |
435 EventModifiers2VimModifiers(EventModifiers macModifiers) | |
436 { | |
437 int_u vimModifiers = 0x00; | |
438 | |
439 if (macModifiers & (shiftKey | rightShiftKey)) | |
440 vimModifiers |= MOD_MASK_SHIFT; | |
441 if (macModifiers & (controlKey | rightControlKey)) | |
442 vimModifiers |= MOD_MASK_CTRL; | |
443 if (macModifiers & (optionKey | rightOptionKey)) | |
444 vimModifiers |= MOD_MASK_ALT; | |
445 #ifdef USE_CMD_KEY | |
446 if (macModifiers & (cmdKey)) /* There's no rightCmdKey */ | |
447 vimModifiers |= MOD_MASK_CMD; | |
448 #endif | |
449 return (vimModifiers); | |
450 } | |
451 | |
452 /* Convert a string representing a point size into pixels. The string should | |
453 * be a positive decimal number, with an optional decimal point (eg, "12", or | |
454 * "10.5"). The pixel value is returned, and a pointer to the next unconverted | |
455 * character is stored in *end. The flag "vertical" says whether this | |
456 * calculation is for a vertical (height) size or a horizontal (width) one. | |
457 * | |
458 * From gui_w48.c | |
459 */ | |
460 static int | |
461 points_to_pixels(char_u *str, char_u **end, int vertical) | |
462 { | |
463 int pixels; | |
464 int points = 0; | |
465 int divisor = 0; | |
466 | |
467 while (*str) | |
468 { | |
469 if (*str == '.' && divisor == 0) | |
470 { | |
471 /* Start keeping a divisor, for later */ | |
472 divisor = 1; | |
473 continue; | |
474 } | |
475 | |
476 if (!isdigit(*str)) | |
477 break; | |
478 | |
479 points *= 10; | |
480 points += *str - '0'; | |
481 divisor *= 10; | |
482 | |
483 ++str; | |
484 } | |
485 | |
486 if (divisor == 0) | |
487 divisor = 1; | |
488 | |
489 pixels = points/divisor; | |
490 *end = str; | |
491 return pixels; | |
492 } | |
493 | |
494 /* | |
495 * Convert a list of FSSpec aliases into a list of fullpathname | |
496 * character strings. | |
497 */ | |
498 | |
499 char_u **new_fnames_from_AEDesc(AEDesc *theList, long *numFiles, OSErr *error) | |
500 { | |
501 char_u **fnames = NULL; | |
502 OSErr newError; | |
503 long fileCount; | |
504 FSSpec fileToOpen; | |
505 long actualSize; | |
506 AEKeyword dummyKeyword; | |
507 DescType dummyType; | |
508 | |
509 /* Get number of files in list */ | |
510 *error = AECountItems(theList, numFiles); | |
511 if (*error) | |
512 { | |
513 #ifdef USE_SIOUX | |
514 printf ("fname_from_AEDesc: AECountItems error: %d\n", error); | |
515 #endif | |
516 return(fnames); | |
517 } | |
518 | |
519 /* Allocate the pointer list */ | |
520 fnames = (char_u **) alloc(*numFiles * sizeof(char_u *)); | |
521 | |
522 /* Empty out the list */ | |
523 for (fileCount = 0; fileCount < *numFiles; fileCount++) | |
524 fnames[fileCount] = NULL; | |
525 | |
526 /* Scan the list of FSSpec */ | |
527 for (fileCount = 1; fileCount <= *numFiles; fileCount++) | |
528 { | |
529 /* Get the alias for the nth file, convert to an FSSpec */ | |
530 newError = AEGetNthPtr(theList, fileCount, typeFSS, | |
531 &dummyKeyword, &dummyType, | |
532 (Ptr) &fileToOpen, sizeof(FSSpec), &actualSize); | |
533 if (newError) | |
534 { | |
535 /* Caller is able to clean up */ | |
536 /* TODO: Should be clean up or not? For safety. */ | |
537 #ifdef USE_SIOUX | |
538 printf ("aevt_odoc: AEGetNthPtr error: %d\n", newError); | |
539 #endif | |
540 return(fnames); | |
541 } | |
542 | |
543 /* Convert the FSSpec to a pathname */ | |
544 fnames[fileCount - 1] = FullPathFromFSSpec_save (fileToOpen); | |
545 } | |
546 | |
547 return (fnames); | |
548 } | |
549 | |
550 /* | |
551 * ------------------------------------------------------------ | |
552 * CodeWarrior External Editor Support | |
553 * ------------------------------------------------------------ | |
554 */ | |
555 #ifdef FEAT_CW_EDITOR | |
556 | |
557 /* | |
558 * Handle the Window Search event from CodeWarrior | |
559 * | |
560 * Description | |
561 * ----------- | |
562 * | |
563 * The IDE sends the Window Search AppleEvent to the editor when it | |
564 * needs to know whether a particular file is open in the editor. | |
565 * | |
566 * Event Reply | |
567 * ----------- | |
568 * | |
569 * None. Put data in the location specified in the structure received. | |
570 * | |
571 * Remarks | |
572 * ------- | |
573 * | |
574 * When the editor receives this event, determine whether the specified | |
575 * file is open. If it is, return the modification date/time for that file | |
576 * in the appropriate location specified in the structure. If the file is | |
577 * not opened, put the value fnfErr (file not found) in that location. | |
578 * | |
579 */ | |
580 | |
581 #if defined(__MWERKS__) /* only in Codewarrior */ | |
582 # pragma options align=mac68k | |
583 #endif | |
584 typedef struct WindowSearch WindowSearch; | |
585 struct WindowSearch /* for handling class 'KAHL', event 'SRCH', keyDirectObject typeChar*/ | |
586 { | |
587 FSSpec theFile; // identifies the file | |
588 long *theDate; // where to put the modification date/time | |
589 }; | |
590 #if defined(__MWERKS__) /* only in Codewarrior */ | |
591 # pragma options align=reset | |
592 #endif | |
593 | |
594 pascal OSErr Handle_KAHL_SRCH_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
595 { | |
596 OSErr error = noErr; | |
597 buf_T *buf; | |
598 int foundFile = false; | |
599 DescType typeCode; | |
600 WindowSearch SearchData; | |
601 Size actualSize; | |
602 | |
603 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &SearchData, sizeof(WindowSearch), &actualSize); | |
604 if (error) | |
605 { | |
606 #ifdef USE_SIOUX | |
607 printf ("KAHL_SRCH: AEGetParamPtr error: %d\n", error); | |
608 #endif | |
609 return(error); | |
610 } | |
611 | |
612 error = HandleUnusedParms (theAEvent); | |
613 if (error) | |
614 { | |
615 #ifdef USE_SIOUX | |
616 printf ("KAHL_SRCH: HandleUnusedParms error: %d\n", error); | |
617 #endif | |
618 return(error); | |
619 } | |
620 | |
621 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
622 if (buf->b_ml.ml_mfp != NULL | |
623 && SearchData.theFile.parID == buf->b_FSSpec.parID | |
624 && SearchData.theFile.name[0] == buf->b_FSSpec.name[0] | |
625 && STRNCMP(SearchData.theFile.name, buf->b_FSSpec.name, buf->b_FSSpec.name[0] + 1) == 0) | |
626 { | |
627 foundFile = true; | |
628 break; | |
629 } | |
630 | |
631 if (foundFile == false) | |
632 *SearchData.theDate = fnfErr; | |
633 else | |
634 *SearchData.theDate = buf->b_mtime; | |
635 | |
636 #ifdef USE_SIOUX | |
637 printf ("KAHL_SRCH: file \"%#s\" {%d}", SearchData.theFile.name,SearchData.theFile.parID); | |
638 if (foundFile == false) | |
639 printf (" NOT"); | |
640 printf (" found. [date %lx, %lx]\n", *SearchData.theDate, buf->b_mtime_read); | |
641 #endif | |
642 | |
643 return error; | |
644 }; | |
645 | |
646 /* | |
647 * Handle the Modified (from IDE to Editor) event from CodeWarrior | |
648 * | |
649 * Description | |
650 * ----------- | |
651 * | |
652 * The IDE sends this event to the external editor when it wants to | |
653 * know which files that are open in the editor have been modified. | |
654 * | |
655 * Parameters None. | |
656 * ---------- | |
657 * | |
658 * Event Reply | |
659 * ----------- | |
660 * The reply for this event is: | |
661 * | |
662 * keyDirectObject typeAEList required | |
663 * each element in the list is a structure of typeChar | |
664 * | |
665 * Remarks | |
666 * ------- | |
667 * | |
668 * When building the reply event, include one element in the list for | |
669 * each open file that has been modified. | |
670 * | |
671 */ | |
672 | |
673 #if defined(__MWERKS__) /* only in Codewarrior */ | |
674 # pragma options align=mac68k | |
675 #endif | |
676 typedef struct ModificationInfo ModificationInfo; | |
677 struct 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 }; | |
683 #if defined(__MWERKS__) /* only in Codewarrior */ | |
684 # pragma options align=reset | |
685 #endif | |
686 | |
687 pascal OSErr Handle_KAHL_MOD_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
688 { | |
689 OSErr error = noErr; | |
690 AEDescList replyList; | |
691 long numFiles; | |
692 ModificationInfo theFile; | |
693 buf_T *buf; | |
694 | |
695 theFile.saved = 0; | |
696 | |
697 error = HandleUnusedParms (theAEvent); | |
698 if (error) | |
699 { | |
700 #ifdef USE_SIOUX | |
701 printf ("KAHL_MOD: HandleUnusedParms error: %d\n", error); | |
702 #endif | |
703 return(error); | |
704 } | |
705 | |
706 /* Send the reply */ | |
707 /* replyObject.descriptorType = typeNull; | |
708 replyObject.dataHandle = nil;*/ | |
709 | |
710 /* AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data) */ | |
711 error = AECreateList(nil, 0, false, &replyList); | |
712 if (error) | |
713 { | |
714 #ifdef USE_SIOUX | |
715 printf ("KAHL_MOD: AECreateList error: %d\n", error); | |
716 #endif | |
717 return(error); | |
718 } | |
719 | |
720 #if 0 | |
721 error = AECountItems(&replyList, &numFiles); | |
722 #ifdef USE_SIOUX | |
723 printf ("KAHL_MOD ReplyList: %x %x\n", replyList.descriptorType, replyList.dataHandle); | |
724 printf ("KAHL_MOD ItemInList: %d\n", numFiles); | |
725 #endif | |
726 | |
727 /* AEPutKeyDesc (&replyList, keyAEPnject, &aDesc) | |
728 * AEPutKeyPtr (&replyList, keyAEPosition, typeChar, (Ptr)&theType, | |
729 * sizeof(DescType)) | |
730 */ | |
731 | |
732 /* AEPutDesc */ | |
733 #endif | |
734 | |
735 numFiles = 0; | |
736 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
737 if (buf->b_ml.ml_mfp != NULL) | |
738 { | |
739 /* Add this file to the list */ | |
740 theFile.theFile = buf->b_FSSpec; | |
741 theFile.theDate = buf->b_mtime; | |
742 /* theFile.theDate = time (NULL) & (time_t) 0xFFFFFFF0; */ | |
743 error = AEPutPtr (&replyList, numFiles, typeChar, (Ptr) &theFile, sizeof(theFile)); | |
744 #ifdef USE_SIOUX | |
745 if (numFiles == 0) | |
746 printf ("KAHL_MOD: "); | |
747 else | |
748 printf (", "); | |
749 printf ("\"%#s\" {%d} [date %lx, %lx]", theFile.theFile.name, theFile.theFile.parID, theFile.theDate, buf->b_mtime_read); | |
750 if (error) | |
751 printf (" (%d)", error); | |
752 numFiles++; | |
753 #endif | |
754 }; | |
755 | |
756 #ifdef USE_SIOUX | |
757 printf ("\n"); | |
758 #endif | |
759 | |
760 #if 0 | |
761 error = AECountItems(&replyList, &numFiles); | |
762 #ifdef USE_SIOUX | |
763 printf ("KAHL_MOD ItemInList: %d\n", numFiles); | |
764 #endif | |
765 #endif | |
766 | |
767 /* We can add data only if something to reply */ | |
768 error = AEPutParamDesc (theReply, keyDirectObject, &replyList); | |
769 | |
770 #ifdef USE_SIOUX | |
771 if (error) | |
772 printf ("KAHL_MOD: AEPutParamDesc error: %d\n", error); | |
773 #endif | |
774 | |
775 if (replyList.dataHandle) | |
776 AEDisposeDesc(&replyList); | |
777 | |
778 return error; | |
779 }; | |
780 | |
781 /* | |
782 * Handle the Get Text event from CodeWarrior | |
783 * | |
784 * Description | |
785 * ----------- | |
786 * | |
787 * The IDE sends the Get Text AppleEvent to the editor when it needs | |
788 * the source code from a file. For example, when the user issues a | |
789 * Check Syntax or Compile command, the compiler needs access to | |
790 * the source code contained in the file. | |
791 * | |
792 * Event Reply | |
793 * ----------- | |
794 * | |
795 * None. Put data in locations specified in the structure received. | |
796 * | |
797 * Remarks | |
798 * ------- | |
799 * | |
800 * When the editor receives this event, it must set the size of the handle | |
801 * in theText to fit the data in the file. It must then copy the entire | |
802 * contents of the specified file into the memory location specified in | |
803 * theText. | |
804 * | |
805 */ | |
806 | |
807 #if defined(__MWERKS__) /* only in Codewarrior */ | |
808 # pragma options align=mac68k | |
809 #endif | |
810 typedef struct CW_GetText CW_GetText; | |
811 struct CW_GetText /* for handling class 'KAHL', event 'GTTX', keyDirectObject typeChar*/ | |
812 { | |
813 FSSpec theFile; /* identifies the file */ | |
814 Handle theText; /* the location where you return the text (must be resized properly) */ | |
815 long *unused; /* 0 (not used) */ | |
816 long *theDate; /* where to put the modification date/time */ | |
817 }; | |
818 #if defined(__MWERKS__) /* only in Codewarrior */ | |
819 # pragma options align=reset | |
820 #endif | |
821 | |
822 pascal OSErr Handle_KAHL_GTTX_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
823 { | |
824 OSErr error = noErr; | |
825 buf_T *buf; | |
826 int foundFile = false; | |
827 DescType typeCode; | |
828 CW_GetText GetTextData; | |
829 Size actualSize; | |
830 char_u *line; | |
831 char_u *fullbuffer = NULL; | |
832 long linesize; | |
833 long lineStart; | |
834 long BufferSize; | |
835 long lineno; | |
836 | |
837 error = AEGetParamPtr(theAEvent, keyDirectObject, typeChar, &typeCode, (Ptr) &GetTextData, sizeof(GetTextData), &actualSize); | |
838 | |
839 if (error) | |
840 { | |
841 #ifdef USE_SIOUX | |
842 printf ("KAHL_GTTX: AEGetParamPtr error: %d\n", error); | |
843 #endif | |
844 return(error); | |
845 } | |
846 | |
847 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
848 if (buf->b_ml.ml_mfp != NULL) | |
849 if (GetTextData.theFile.parID == buf->b_FSSpec.parID) | |
850 { | |
851 foundFile = true; | |
852 break; | |
853 } | |
854 | |
855 if (foundFile) | |
856 { | |
857 BufferSize = 0; /* GetHandleSize (GetTextData.theText); */ | |
858 for (lineno = 0; lineno <= buf->b_ml.ml_line_count; lineno++) | |
859 { | |
860 /* Must use the right buffer */ | |
861 line = ml_get_buf(buf, (linenr_T) lineno, FALSE); | |
862 linesize = STRLEN(line) + 1; | |
863 lineStart = BufferSize; | |
864 BufferSize += linesize; | |
865 /* Resize handle to linesize+1 to include the linefeed */ | |
866 SetHandleSize (GetTextData.theText, BufferSize); | |
867 if (GetHandleSize (GetTextData.theText) != BufferSize) | |
868 { | |
869 #ifdef USE_SIOUX | |
870 printf ("KAHL_GTTX: SetHandleSize increase: %d, size %d\n", | |
871 linesize, BufferSize); | |
872 #endif | |
873 break; /* Simple handling for now */ | |
874 } | |
875 else | |
876 { | |
877 HLock (GetTextData.theText); | |
878 fullbuffer = (char_u *) *GetTextData.theText; | |
879 STRCPY ((char_u *) (fullbuffer + lineStart), line); | |
880 fullbuffer[BufferSize-1] = '\r'; | |
881 HUnlock (GetTextData.theText); | |
882 } | |
883 } | |
884 if (fullbuffer != NULL) | |
885 { | |
886 HLock (GetTextData.theText); | |
887 fullbuffer[BufferSize-1] = 0; | |
888 HUnlock (GetTextData.theText); | |
889 } | |
890 if (foundFile == false) | |
891 *GetTextData.theDate = fnfErr; | |
892 else | |
893 /* *GetTextData.theDate = time (NULL) & (time_t) 0xFFFFFFF0;*/ | |
894 *GetTextData.theDate = buf->b_mtime; | |
895 } | |
896 #ifdef USE_SIOUX | |
897 printf ("KAHL_GTTX: file \"%#s\" {%d} [date %lx, %lx]", GetTextData.theFile.name, GetTextData.theFile.parID, *GetTextData.theDate, buf->b_mtime_read); | |
898 if (foundFile == false) | |
899 printf (" NOT"); | |
900 printf (" found. (BufferSize = %d)\n", BufferSize); | |
901 #endif | |
902 | |
903 error = HandleUnusedParms (theAEvent); | |
904 if (error) | |
905 { | |
906 #ifdef USE_SIOUX | |
907 printf ("KAHL_GTTX: HandleUnusedParms error: %d\n", error); | |
908 #endif | |
909 return(error); | |
910 } | |
911 | |
912 return(error); | |
913 } | |
914 | |
915 /* | |
916 * | |
917 */ | |
918 | |
919 /* Taken from MoreAppleEvents:ProcessHelpers*/ | |
920 pascal OSErr FindProcessBySignature( const OSType targetType, | |
921 const OSType targetCreator, | |
922 ProcessSerialNumberPtr psnPtr ) | |
923 { | |
924 OSErr anErr = noErr; | |
925 Boolean lookingForProcess = true; | |
926 | |
927 ProcessInfoRec infoRec; | |
928 | |
929 infoRec.processInfoLength = sizeof( ProcessInfoRec ); | |
930 infoRec.processName = nil; | |
931 infoRec.processAppSpec = nil; | |
932 | |
933 psnPtr->lowLongOfPSN = kNoProcess; | |
934 psnPtr->highLongOfPSN = kNoProcess; | |
935 | |
936 while ( lookingForProcess ) | |
937 { | |
938 anErr = GetNextProcess( psnPtr ); | |
939 if ( anErr != noErr ) | |
940 { | |
941 lookingForProcess = false; | |
942 } | |
943 else | |
944 { | |
945 anErr = GetProcessInformation( psnPtr, &infoRec ); | |
946 if ( ( anErr == noErr ) | |
947 && ( infoRec.processType == targetType ) | |
948 && ( infoRec.processSignature == targetCreator ) ) | |
949 { | |
950 lookingForProcess = false; | |
951 } | |
952 } | |
953 } | |
954 | |
955 return anErr; | |
956 }//end FindProcessBySignature | |
957 | |
958 void Send_KAHL_MOD_AE (buf_T *buf) | |
959 { | |
960 OSErr anErr = noErr; | |
961 AEDesc targetAppDesc = { typeNull, nil }; | |
962 ProcessSerialNumber psn = { kNoProcess, kNoProcess }; | |
963 AppleEvent theReply = { typeNull, nil }; | |
964 AESendMode sendMode; | |
965 AppleEvent theEvent = {typeNull, nil }; | |
966 AEIdleUPP idleProcUPP = nil; | |
967 ModificationInfo ModData; | |
968 | |
969 | |
970 anErr = FindProcessBySignature( 'APPL', 'CWIE', &psn ); | |
971 #ifdef USE_SIOUX | |
972 printf ("CodeWarrior is"); | |
973 if (anErr != noErr) | |
974 printf (" NOT"); | |
975 printf (" running\n"); | |
976 #endif | |
977 if ( anErr == noErr ) | |
978 { | |
979 anErr = AECreateDesc (typeProcessSerialNumber, &psn, | |
980 sizeof( ProcessSerialNumber ), &targetAppDesc); | |
981 | |
982 if ( anErr == noErr ) | |
983 { | |
984 anErr = AECreateAppleEvent( 'KAHL', 'MOD ', &targetAppDesc, | |
985 kAutoGenerateReturnID, kAnyTransactionID, &theEvent); | |
986 } | |
987 | |
988 AEDisposeDesc( &targetAppDesc ); | |
989 | |
990 /* Add the parms */ | |
991 ModData.theFile = buf->b_FSSpec; | |
992 ModData.theDate = buf->b_mtime; | |
993 | |
994 if (anErr == noErr) | |
995 anErr =AEPutParamPtr (&theEvent, keyDirectObject, typeChar, &ModData, sizeof(ModData)); | |
996 | |
997 if ( idleProcUPP == nil ) | |
998 sendMode = kAENoReply; | |
999 else | |
1000 sendMode = kAEWaitReply; | |
1001 | |
1002 if ( anErr == noErr ) | |
1003 anErr = AESend( &theEvent, &theReply, sendMode, kAENormalPriority, kNoTimeOut, idleProcUPP, nil ); | |
1004 if ( anErr == noErr && sendMode == kAEWaitReply ) | |
1005 { | |
1006 #ifdef USE_SIOUX | |
1007 printf ("KAHL_MOD: Send error: %d\n", anErr); | |
1008 #endif | |
1009 /* anErr = AEHGetHandlerError( &theReply );*/ | |
1010 } | |
1011 (void) AEDisposeDesc( &theReply ); | |
1012 } | |
1013 } | |
1014 #endif /* FEAT_CW_EDITOR */ | |
1015 | |
1016 /* | |
1017 * ------------------------------------------------------------ | |
1018 * Apple Event Handling procedure | |
1019 * ------------------------------------------------------------ | |
1020 */ | |
1021 #ifdef USE_AEVENT | |
1022 | |
1023 /* | |
1024 * Handle the Unused parms of an AppleEvent | |
1025 */ | |
1026 | |
1027 OSErr HandleUnusedParms (const AppleEvent *theAEvent) | |
1028 { | |
1029 OSErr error; | |
1030 long actualSize; | |
1031 DescType dummyType; | |
1032 AEKeyword missedKeyword; | |
1033 | |
1034 /* Get the "missed keyword" attribute from the AppleEvent. */ | |
1035 error = AEGetAttributePtr(theAEvent, keyMissedKeywordAttr, | |
1036 typeKeyword, &dummyType, | |
1037 (Ptr)&missedKeyword, sizeof(missedKeyword), | |
1038 &actualSize); | |
1039 | |
1040 /* If the descriptor isn't found, then we got the required parameters. */ | |
1041 if (error == errAEDescNotFound) | |
1042 { | |
1043 error = noErr; | |
1044 } | |
1045 else | |
1046 { | |
1047 #if 0 | |
1048 /* Why is this removed? */ | |
1049 error = errAEEventNotHandled; | |
1050 #endif | |
1051 } | |
1052 | |
1053 return error; | |
1054 } | |
1055 | |
1056 | |
1057 /* | |
1058 * Handle the ODoc AppleEvent | |
1059 * | |
1060 * Deals with all files dragged to the application icon. | |
1061 * | |
1062 */ | |
1063 | |
1064 #if defined(__MWERKS__) /* only in Codewarrior */ | |
1065 # pragma options align=mac68k | |
1066 #endif | |
1067 typedef struct SelectionRange SelectionRange; | |
1068 struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPosition typeChar */ | |
1069 { | |
1070 short unused1; // 0 (not used) | |
1071 short lineNum; // line to select (<0 to specify range) | |
1072 long startRange; // start of selection range (if line < 0) | |
1073 long endRange; // end of selection range (if line < 0) | |
1074 long unused2; // 0 (not used) | |
1075 long theDate; // modification date/time | |
1076 }; | |
1077 #if defined(__MWERKS__) /* only in Codewarrior */ | |
1078 # pragma options align=reset | |
1079 #endif | |
1080 | |
1081 /* The IDE uses the optional keyAEPosition parameter to tell the ed- | |
1082 itor the selection range. If lineNum is zero or greater, scroll the text | |
1083 to the specified line. If lineNum is less than zero, use the values in | |
1084 startRange and endRange to select the specified characters. Scroll | |
1085 the text to display the selection. If lineNum, startRange, and | |
1086 endRange are all negative, there is no selection range specified. | |
1087 */ | |
1088 | |
1089 pascal OSErr HandleODocAE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
1090 { | |
1091 /* | |
1092 * TODO: Clean up the code with convert the AppleEvent into | |
1093 * a ":args" | |
1094 */ | |
1095 OSErr error = noErr; | |
1096 // OSErr firstError = noErr; | |
1097 // short numErrors = 0; | |
1098 AEDesc theList; | |
1099 DescType typeCode; | |
1100 long numFiles; | |
1101 // long fileCount; | |
1102 char_u **fnames; | |
1103 // char_u fname[256]; | |
1104 Size actualSize; | |
1105 SelectionRange thePosition; | |
1106 short gotPosition = false; | |
1107 long lnum; | |
1108 | |
1109 #ifdef USE_SIOUX | |
1110 printf ("aevt_odoc:\n"); | |
1111 #endif | |
1112 | |
1113 /* the direct object parameter is the list of aliases to files (one or more) */ | |
1114 error = AEGetParamDesc(theAEvent, keyDirectObject, typeAEList, &theList); | |
1115 if (error) | |
1116 { | |
1117 #ifdef USE_SIOUX | |
1118 printf ("aevt_odoc: AEGetParamDesc error: %d\n", error); | |
1119 #endif | |
1120 return(error); | |
1121 } | |
1122 | |
1123 | |
1124 error = AEGetParamPtr(theAEvent, keyAEPosition, typeChar, &typeCode, (Ptr) &thePosition, sizeof(SelectionRange), &actualSize); | |
1125 if (error == noErr) | |
1126 gotPosition = true; | |
1127 if (error == errAEDescNotFound) | |
1128 error = noErr; | |
1129 if (error) | |
1130 { | |
1131 #ifdef USE_SIOUX | |
1132 printf ("aevt_odoc: AEGetParamPtr error: %d\n", error); | |
1133 #endif | |
1134 return(error); | |
1135 } | |
1136 | |
1137 #ifdef USE_SIOUX | |
1138 printf ("aevt_odoc: lineNum: %d, startRange %d, endRange %d, [date %lx]\n", | |
1139 thePosition.lineNum, thePosition.startRange, thePosition.endRange, | |
1140 thePosition.theDate); | |
1141 #endif | |
1142 /* | |
1143 error = AEGetParamDesc(theAEvent, keyAEPosition, typeChar, &thePosition); | |
1144 | |
1145 if (^error) then | |
1146 { | |
1147 if (thePosition.lineNum >= 0) | |
1148 { | |
1149 // Goto this line | |
1150 } | |
1151 else | |
1152 { | |
1153 // Set the range char wise | |
1154 } | |
1155 } | |
1156 */ | |
1157 | |
1158 | |
1159 #ifdef FEAT_VISUAL | |
1160 reset_VIsual(); | |
1161 #endif | |
1162 | |
1163 fnames = new_fnames_from_AEDesc(&theList, &numFiles, &error); | |
1164 | |
1165 if (error) | |
1166 { | |
1167 /* TODO: empty fnames[] first */ | |
1168 vim_free(fnames); | |
1169 return (error); | |
1170 } | |
1171 | |
1172 if (starting > 0) | |
1173 { | |
1174 int i; | |
1175 char_u *p; | |
1176 | |
1177 /* these are the initial files dropped on the Vim icon */ | |
1178 for (i = 0 ; i < numFiles; i++) | |
1179 { | |
1180 if (ga_grow(&global_alist.al_ga, 1) == FAIL | |
1181 || (p = vim_strsave(fnames[i])) == NULL) | |
1182 mch_exit(2); | |
1183 else | |
1184 alist_add(&global_alist, p, 2); | |
1185 } | |
1186 goto finished; | |
1187 } | |
1188 | |
1189 /* Handle the drop, :edit to get to the file */ | |
1190 handle_drop(numFiles, fnames, FALSE); | |
1191 | |
1192 /* TODO: Handle the goto/select line more cleanly */ | |
1193 if ((numFiles == 1) & (gotPosition)) | |
1194 { | |
1195 if (thePosition.lineNum >= 0) | |
1196 { | |
1197 lnum = thePosition.lineNum; | |
1198 /* oap->motion_type = MLINE; | |
1199 setpcmark();*/ | |
1200 if (lnum < 1L) | |
1201 lnum = 1L; | |
1202 else if (lnum > curbuf->b_ml.ml_line_count) | |
1203 lnum = curbuf->b_ml.ml_line_count; | |
1204 curwin->w_cursor.lnum = lnum; | |
1205 /* beginline(BL_SOL | BL_FIX);*/ | |
1206 } | |
1207 else | |
1208 goto_byte(thePosition.startRange + 1); | |
1209 } | |
1210 | |
1211 /* Update the screen display */ | |
1212 update_screen(NOT_VALID); | |
1213 setcursor(); | |
1214 out_flush(); | |
1215 | |
1216 finished: | |
1217 AEDisposeDesc(&theList); /* dispose what we allocated */ | |
1218 | |
1219 error = HandleUnusedParms (theAEvent); | |
1220 if (error) | |
1221 { | |
1222 #ifdef USE_SIOUX | |
1223 printf ("aevt_odoc: HandleUnusedParms error: %d\n", error); | |
1224 #endif | |
1225 return(error); | |
1226 } | |
1227 return(error); | |
1228 } | |
1229 | |
1230 /* | |
1231 * | |
1232 */ | |
1233 | |
1234 pascal OSErr Handle_aevt_oapp_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
1235 { | |
1236 OSErr error = noErr; | |
1237 | |
1238 #ifdef USE_SIOUX | |
1239 printf ("aevt_oapp:\n"); | |
1240 #endif | |
1241 | |
1242 error = HandleUnusedParms (theAEvent); | |
1243 if (error) | |
1244 { | |
1245 return(error); | |
1246 } | |
1247 | |
1248 return(error); | |
1249 } | |
1250 | |
1251 /* | |
1252 * | |
1253 */ | |
1254 | |
1255 pascal OSErr Handle_aevt_quit_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
1256 { | |
1257 OSErr error = noErr; | |
1258 | |
1259 #ifdef USE_SIOUX | |
1260 printf ("aevt_quit\n"); | |
1261 #endif | |
1262 | |
1263 error = HandleUnusedParms (theAEvent); | |
1264 if (error) | |
1265 { | |
1266 return(error); | |
1267 } | |
1268 | |
1269 /* Need to fake a :confirm qa */ | |
1270 do_cmdline_cmd((char_u *)"confirm qa"); | |
1271 | |
1272 return(error); | |
1273 } | |
1274 | |
1275 /* | |
1276 * | |
1277 */ | |
1278 | |
1279 pascal OSErr Handle_aevt_pdoc_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
1280 { | |
1281 OSErr error = noErr; | |
1282 | |
1283 #ifdef USE_SIOUX | |
1284 printf ("aevt_pdoc:\n"); | |
1285 #endif | |
1286 | |
1287 error = HandleUnusedParms (theAEvent); | |
1288 if (error) | |
1289 { | |
1290 return(error); | |
1291 } | |
1292 | |
1293 return(error); | |
1294 } | |
1295 | |
1296 /* | |
1297 * Handling of unknown AppleEvent | |
1298 * | |
1299 * (Just get rid of all the parms) | |
1300 */ | |
1301 pascal OSErr Handle_unknown_AE (const AppleEvent *theAEvent, AppleEvent *theReply, long refCon) | |
1302 { | |
1303 OSErr error = noErr; | |
1304 | |
1305 #ifdef USE_SIOUX | |
1306 printf ("Unknown Event: %x\n", theAEvent->descriptorType); | |
1307 #endif | |
1308 | |
1309 error = HandleUnusedParms (theAEvent); | |
1310 if (error) | |
1311 { | |
1312 return(error); | |
1313 } | |
1314 | |
1315 return(error); | |
1316 } | |
1317 | |
1318 | |
1319 | |
1320 #if TARGET_API_MAC_CARBON | |
1321 # define NewAEEventHandlerProc(x) NewAEEventHandlerUPP(x) | |
1322 #endif | |
1323 | |
1324 /* | |
1325 * Install the various AppleEvent Handlers | |
1326 */ | |
1327 OSErr InstallAEHandlers (void) | |
1328 { | |
1329 OSErr error; | |
1330 | |
1331 /* install open application handler */ | |
1332 error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, | |
1333 NewAEEventHandlerProc(Handle_aevt_oapp_AE), 0, false); | |
1334 if (error) | |
1335 { | |
1336 return error; | |
1337 } | |
1338 | |
1339 /* install quit application handler */ | |
1340 error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, | |
1341 NewAEEventHandlerProc(Handle_aevt_quit_AE), 0, false); | |
1342 if (error) | |
1343 { | |
1344 return error; | |
1345 } | |
1346 | |
1347 /* install open document handler */ | |
1348 error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, | |
1349 NewAEEventHandlerProc(HandleODocAE), 0, false); | |
1350 if (error) | |
1351 { | |
1352 return error; | |
1353 } | |
1354 | |
1355 /* install print document handler */ | |
1356 error = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, | |
1357 NewAEEventHandlerProc(Handle_aevt_pdoc_AE), 0, false); | |
1358 | |
1359 /* Install Core Suite */ | |
1360 /* error = AEInstallEventHandler(kAECoreSuite, kAEClone, | |
1361 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1362 | |
1363 error = AEInstallEventHandler(kAECoreSuite, kAEClose, | |
1364 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1365 | |
1366 error = AEInstallEventHandler(kAECoreSuite, kAECountElements, | |
1367 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1368 | |
1369 error = AEInstallEventHandler(kAECoreSuite, kAECreateElement, | |
1370 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1371 | |
1372 error = AEInstallEventHandler(kAECoreSuite, kAEDelete, | |
1373 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1374 | |
1375 error = AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist, | |
1376 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1377 | |
1378 error = AEInstallEventHandler(kAECoreSuite, kAEGetData, | |
1379 NewAEEventHandlerProc(Handle_unknown_AE), kAEGetData, false); | |
1380 | |
1381 error = AEInstallEventHandler(kAECoreSuite, kAEGetDataSize, | |
1382 NewAEEventHandlerProc(Handle_unknown_AE), kAEGetDataSize, false); | |
1383 | |
1384 error = AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo, | |
1385 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1386 | |
1387 error = AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo, | |
1388 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1389 | |
1390 error = AEInstallEventHandler(kAECoreSuite, kAEMove, | |
1391 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1392 | |
1393 error = AEInstallEventHandler(kAECoreSuite, kAESave, | |
1394 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1395 | |
1396 error = AEInstallEventHandler(kAECoreSuite, kAESetData, | |
1397 NewAEEventHandlerProc(Handle_unknown_AE), nil, false); | |
1398 */ | |
1399 | |
1400 #ifdef FEAT_CW_EDITOR | |
1401 /* | |
1402 * Bind codewarrior support handlers | |
1403 */ | |
1404 error = AEInstallEventHandler('KAHL', 'GTTX', | |
1405 NewAEEventHandlerProc(Handle_KAHL_GTTX_AE), 0, false); | |
1406 if (error) | |
1407 { | |
1408 return error; | |
1409 } | |
1410 error = AEInstallEventHandler('KAHL', 'SRCH', | |
1411 NewAEEventHandlerProc(Handle_KAHL_SRCH_AE), 0, false); | |
1412 if (error) | |
1413 { | |
1414 return error; | |
1415 } | |
1416 error = AEInstallEventHandler('KAHL', 'MOD ', | |
1417 NewAEEventHandlerProc(Handle_KAHL_MOD_AE), 0, false); | |
1418 if (error) | |
1419 { | |
1420 return error; | |
1421 } | |
1422 #endif | |
1423 | |
1424 return error; | |
1425 | |
1426 } | |
1427 #endif /* USE_AEVENT */ | |
1428 | |
1429 /* | |
1430 * ------------------------------------------------------------ | |
1431 * Unfiled yet | |
1432 * ------------------------------------------------------------ | |
1433 */ | |
1434 | |
1435 /* | |
1436 * gui_mac_get_menu_item_index | |
1437 * | |
1438 * Returns the index inside the menu wher | |
1439 */ | |
1440 short /* Shoulde we return MenuItemIndex? */ | |
1441 gui_mac_get_menu_item_index (pMenu) | |
1442 vimmenu_T *pMenu; | |
1443 { | |
1444 short index; | |
1445 short itemIndex = -1; | |
1446 vimmenu_T *pBrother; | |
1447 | |
1448 /* Only menu without parent are the: | |
1449 * -menu in the menubar | |
1450 * -popup menu | |
1451 * -toolbar (guess) | |
1452 * | |
1453 * Which are not items anyway. | |
1454 */ | |
1455 if (pMenu->parent) | |
1456 { | |
1457 /* Start from the Oldest Brother */ | |
1458 pBrother = pMenu->parent->children; | |
1459 index = 1; | |
1460 while ((pBrother) && (itemIndex == -1)) | |
1461 { | |
1462 if (pBrother == pMenu) | |
1463 itemIndex = index; | |
1464 index++; | |
1465 pBrother = pBrother->next; | |
1466 } | |
1467 #ifdef USE_HELPMENU | |
1468 /* Adjust index in help menu (for predefined ones) */ | |
1469 if (itemIndex != -1) | |
1470 if (pMenu->parent->submenu_id == kHMHelpMenuID) | |
1471 itemIndex += gui.MacOSHelpItems; | |
1472 #endif | |
1473 } | |
1474 return itemIndex; | |
1475 } | |
1476 | |
1477 static vimmenu_T * | |
1478 gui_mac_get_vim_menu (menuID, itemIndex, pMenu) | |
1479 short menuID; | |
1480 short itemIndex; | |
1481 vimmenu_T *pMenu; | |
1482 { | |
1483 short index; | |
1484 vimmenu_T *pChildMenu; | |
1485 vimmenu_T *pElder = pMenu->parent; | |
1486 | |
1487 | |
1488 /* Only menu without parent are the: | |
1489 * -menu in the menubar | |
1490 * -popup menu | |
1491 * -toolbar (guess) | |
1492 * | |
1493 * Which are not items anyway. | |
1494 */ | |
1495 | |
1496 if ((pElder) && (pElder->submenu_id == menuID)) | |
1497 { | |
1498 #ifdef USE_HELPMENU | |
1499 if (menuID == kHMHelpMenuID) | |
1500 itemIndex -= gui.MacOSHelpItems; | |
1501 #endif | |
1502 | |
1503 for (index = 1; (index != itemIndex) && (pMenu != NULL); index++) | |
1504 pMenu = pMenu->next; | |
1505 } | |
1506 else | |
1507 { | |
1508 for (; pMenu != NULL; pMenu = pMenu->next) | |
1509 { | |
1510 if (pMenu->children != NULL) | |
1511 { | |
1512 pChildMenu = gui_mac_get_vim_menu | |
1513 (menuID, itemIndex, pMenu->children); | |
1514 if (pChildMenu) | |
1515 { | |
1516 pMenu = pChildMenu; | |
1517 break; | |
1518 } | |
1519 } | |
1520 } | |
1521 } | |
1522 return pMenu; | |
1523 } | |
1524 | |
1525 /* | |
1526 * ------------------------------------------------------------ | |
1527 * MacOS Feedback procedures | |
1528 * ------------------------------------------------------------ | |
1529 */ | |
1530 pascal | |
1531 void | |
1532 gui_mac_drag_thumb (ControlHandle theControl, short partCode) | |
1533 { | |
1534 scrollbar_T *sb; | |
1535 int value, dragging; | |
1536 ControlHandle theControlToUse; | |
1537 int dont_scroll_save = dont_scroll; | |
1538 | |
1539 theControlToUse = dragged_sb; | |
1540 | |
1541 sb = gui_find_scrollbar((long) GetControlReference (theControlToUse)); | |
1542 | |
1543 if (sb == NULL) | |
1544 return; | |
1545 | |
1546 /* Need to find value by diff between Old Poss New Pos */ | |
1547 value = GetControl32BitValue (theControlToUse); | |
1548 dragging = (partCode != 0); | |
1549 | |
1550 /* When "allow_scrollbar" is FALSE still need to remember the new | |
1551 * position, but don't actually scroll by setting "dont_scroll". */ | |
1552 dont_scroll = !allow_scrollbar; | |
1553 gui_drag_scrollbar(sb, value, dragging); | |
1554 dont_scroll = dont_scroll_save; | |
1555 } | |
1556 | |
1557 pascal | |
1558 void | |
1559 gui_mac_scroll_action (ControlHandle theControl, short partCode) | |
1560 { | |
1561 /* TODO: have live support */ | |
1562 scrollbar_T *sb, *sb_info; | |
1563 long data; | |
1564 long value; | |
1565 int page; | |
1566 int dragging = FALSE; | |
1567 int dont_scroll_save = dont_scroll; | |
1568 | |
1569 sb = gui_find_scrollbar((long) GetControlReference (theControl)); | |
1570 | |
1571 if (sb == NULL) | |
1572 return; | |
1573 | |
1574 if (sb->wp != NULL) /* Left or right scrollbar */ | |
1575 { | |
1576 /* | |
1577 * Careful: need to get scrollbar info out of first (left) scrollbar | |
1578 * for window, but keep real scrollbar too because we must pass it to | |
1579 * gui_drag_scrollbar(). | |
1580 */ | |
1581 sb_info = &sb->wp->w_scrollbars[0]; | |
1582 | |
1583 if (sb_info->size > 5) | |
1584 page = sb_info->size - 2; /* use two lines of context */ | |
1585 else | |
1586 page = sb_info->size; | |
1587 } | |
1588 else /* Bottom scrollbar */ | |
1589 { | |
1590 sb_info = sb; | |
1591 page = W_WIDTH(curwin) - 5; | |
1592 } | |
1593 | |
1594 switch (partCode) | |
1595 { | |
1596 case kControlUpButtonPart: data = -1; break; | |
1597 case kControlDownButtonPart: data = 1; break; | |
1598 case kControlPageDownPart: data = page; break; | |
1599 case kControlPageUpPart: data = -page; break; | |
1600 default: data = 0; break; | |
1601 } | |
1602 | |
1603 value = sb_info->value + data; | |
1604 /* if (value > sb_info->max) | |
1605 value = sb_info->max; | |
1606 else if (value < 0) | |
1607 value = 0;*/ | |
1608 | |
1609 /* When "allow_scrollbar" is FALSE still need to remember the new | |
1610 * position, but don't actually scroll by setting "dont_scroll". */ | |
1611 dont_scroll = !allow_scrollbar; | |
1612 gui_drag_scrollbar(sb, value, dragging); | |
1613 dont_scroll = dont_scroll_save; | |
1614 | |
1615 out_flush(); | |
1616 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max); | |
1617 | |
1618 /* if (sb_info->wp != NULL) | |
1619 { | |
1620 win_T *wp; | |
1621 int sb_num; | |
1622 | |
1623 sb_num = 0; | |
1624 for (wp = firstwin; wp != sb->wp && wp != NULL; wp = W_NEXT(wp)) | |
1625 sb_num++; | |
1626 | |
1627 if (wp != NULL) | |
1628 { | |
1629 current_scrollbar = sb_num; | |
1630 scrollbar_value = value; | |
1631 gui_do_scroll(); | |
1632 gui_mch_set_scrollbar_thumb(sb, value, sb_info->size, sb_info->max); | |
1633 } | |
1634 }*/ | |
1635 } | |
1636 | |
1637 /* | |
1638 * ------------------------------------------------------------ | |
1639 * MacOS Click Handling procedures | |
1640 * ------------------------------------------------------------ | |
1641 */ | |
1642 | |
1643 | |
1644 /* | |
1645 * Handle a click inside the window, it may happens in the | |
1646 * scrollbar or the contents. | |
1647 * | |
1648 * TODO: Add support for potential TOOLBAR | |
1649 */ | |
1650 void | |
1651 gui_mac_doInContentClick (theEvent, whichWindow) | |
1652 EventRecord *theEvent; | |
1653 WindowPtr whichWindow; | |
1654 { | |
1655 Point thePoint; | |
1656 int_u vimModifiers; | |
1657 short thePortion; | |
1658 ControlHandle theControl; | |
1659 int vimMouseButton; | |
1660 short dblClick; | |
1661 | |
1662 thePoint = theEvent->where; | |
1663 GlobalToLocal (&thePoint); | |
1664 SelectWindow (whichWindow); | |
1665 | |
1666 thePortion = FindControl (thePoint, whichWindow, &theControl); | |
1667 | |
1668 if (theControl != NUL) | |
1669 { | |
1670 /* We hit a scollbar */ | |
1671 | |
1672 if (thePortion != kControlIndicatorPart) | |
1673 { | |
1674 dragged_sb = theControl; | |
1675 TrackControl(theControl, thePoint, gScrollAction); | |
1676 dragged_sb = NULL; | |
1677 } | |
1678 else | |
1679 { | |
1680 dragged_sb = theControl; | |
1681 #if 1 | |
1682 TrackControl(theControl, thePoint, gScrollDrag); | |
1683 #else | |
1684 TrackControl(theControl, thePoint, NULL); | |
1685 #endif | |
1686 /* pass 0 as the part to tell gui_mac_drag_thumb, that the mouse | |
1687 * button has been released */ | |
1688 gui_mac_drag_thumb (theControl, 0); /* Should it be thePortion ? (Dany) */ | |
1689 dragged_sb = NULL; | |
1690 } | |
1691 } | |
1692 else | |
1693 { | |
1694 /* We are inside the contents */ | |
1695 | |
1696 /* Convert the CTRL, OPTION, SHIFT and CMD key */ | |
1697 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers); | |
1698 | |
1699 /* Defaults to MOUSE_LEFT as there's only one mouse button */ | |
1700 vimMouseButton = MOUSE_LEFT; | |
1701 | |
1702 #ifdef USE_CTRLCLICKMENU | |
1703 /* Convert the CTRL_MOUSE_LEFT to MOUSE_RIGHT */ | |
1704 clickIsPopup = FALSE; | |
1705 | |
1706 if ((gui.MacOSHaveCntxMenu) && (mouse_model_popup())) | |
1707 if (IsShowContextualMenuClick(theEvent)) | |
1708 { | |
1709 vimMouseButton = MOUSE_RIGHT; | |
1710 vimModifiers &= ~MOUSE_CTRL; | |
1711 clickIsPopup = TRUE; | |
1712 } | |
1713 #endif | |
1714 | |
1715 /* Is it a double click ? */ | |
1716 dblClick = ((theEvent->when - lastMouseTick) < GetDblTime()); | |
1717 | |
1718 /* Send the mouse clicj to Vim */ | |
1719 gui_send_mouse_event(vimMouseButton, thePoint.h, | |
1720 thePoint.v, dblClick, vimModifiers); | |
1721 | |
1722 /* Create the rectangle around the cursor to detect | |
1723 * the mouse dragging | |
1724 */ | |
1725 #ifdef USE_CTRLCLICKMENU | |
1726 #if 0 | |
1727 /* TODO: Do we need to this even for the contextual menu? | |
1728 * It may be require for popup_setpos, but for popup? | |
1729 */ | |
1730 if (vimMouseButton == MOUSE_LEFT) | |
1731 #endif | |
1732 #endif | |
1733 { | |
1734 SetRect (&dragRect, FILL_X(X_2_COL(thePoint.h)), | |
1735 FILL_Y(Y_2_ROW(thePoint.v)), | |
1736 FILL_X(X_2_COL(thePoint.h)+1), | |
1737 FILL_Y(Y_2_ROW(thePoint.v)+1)); | |
1738 | |
1739 dragRectEnbl = TRUE; | |
1740 dragRectControl = kCreateRect; | |
1741 } | |
1742 } | |
1743 } | |
1744 | |
1745 /* | |
1746 * Handle the click in the titlebar (to move the window) | |
1747 */ | |
1748 void | |
1749 gui_mac_doInDragClick (where, whichWindow) | |
1750 Point where; | |
1751 WindowPtr whichWindow; | |
1752 { | |
1753 Rect movingLimits; | |
1754 Rect *movingLimitsPtr = &movingLimits; | |
1755 | |
1756 /* TODO: may try to prevent move outside screen? */ | |
1757 #ifdef USE_CARBONIZED | |
1758 movingLimitsPtr = GetRegionBounds ( GetGrayRgn(), &movingLimits ); | |
1759 #else | |
1760 movingLimitsPtr = &(*GetGrayRgn())->rgnBBox; | |
1761 #endif | |
1762 DragWindow (whichWindow, where, movingLimitsPtr); | |
1763 } | |
1764 | |
1765 /* | |
1766 * Handle the click in the grow box | |
1767 */ | |
1768 void | |
1769 gui_mac_doInGrowClick(where, whichWindow) | |
1770 Point where; | |
1771 WindowPtr whichWindow; | |
1772 { | |
1773 | |
1774 long newSize; | |
1775 unsigned short newWidth; | |
1776 unsigned short newHeight; | |
1777 Rect resizeLimits; | |
1778 Rect *resizeLimitsPtr = &resizeLimits; | |
1779 #ifdef USE_CARBONIZED | |
1780 Rect NewContentRect; | |
1781 | |
1782 resizeLimitsPtr = GetRegionBounds ( GetGrayRgn(), &resizeLimits ); | |
1783 #else | |
1784 resizeLimits = qd.screenBits.bounds; | |
1785 #endif | |
1786 | |
1787 /* Set the minimun size */ | |
1788 /* TODO: Should this come from Vim? */ | |
1789 resizeLimits.top = 100; | |
1790 resizeLimits.left = 100; | |
1791 | |
1792 #ifdef USE_CARBONIZED | |
1793 newSize = ResizeWindow(whichWindow, where, &resizeLimits, &NewContentRect); | |
1794 newWidth = NewContentRect.right - NewContentRect.left; | |
1795 newHeight = NewContentRect.bottom - NewContentRect.top; | |
1796 gui_resize_shell(newWidth, newHeight); | |
1797 gui_mch_set_bg_color(gui.back_pixel); | |
1798 gui_set_shellsize(TRUE, FALSE); | |
1799 #else | |
1800 newSize = GrowWindow(whichWindow, where, &resizeLimits); | |
1801 if (newSize != 0) | |
1802 { | |
1803 newWidth = newSize & 0x0000FFFF; | |
1804 newHeight = (newSize >> 16) & 0x0000FFFF; | |
1805 | |
1806 gui_mch_set_bg_color(gui.back_pixel); | |
1807 | |
1808 gui_resize_shell(newWidth, newHeight); | |
1809 | |
1810 /* | |
1811 * We need to call gui_set_shellsize as the size | |
1812 * used by Vim may be smaller than the size selected | |
1813 * by the user. This cause some overhead | |
1814 * TODO: add a check inside gui_resize_shell? | |
1815 */ | |
1816 gui_set_shellsize(TRUE, FALSE); | |
1817 | |
1818 /* | |
1819 * Origin of the code below is unknown. | |
1820 * Functionality is unknown. | |
1821 * Time of commented out is unknown. | |
1822 */ | |
1823 /* SetPort(wp); | |
1824 InvalRect(&wp->portRect); | |
1825 if (isUserWindow(wp)) { | |
1826 DrawingWindowPeek aWindow = (DrawingWindowPeek)wp; | |
1827 | |
1828 if (aWindow->toolRoutines.toolWindowResizedProc) | |
1829 CallToolWindowResizedProc(aWindow->toolRoutines.toolWindowResizedProc, wp); | |
1830 }*/ | |
1831 }; | |
1832 #endif | |
1833 | |
1834 } | |
1835 | |
1836 /* | |
1837 * Handle the click in the zoom box | |
1838 */ | |
1839 #ifdef USE_CARBONIZED | |
1840 static void | |
1841 gui_mac_doInZoomClick(theEvent, whichWindow) | |
1842 EventRecord *theEvent; | |
1843 WindowPtr whichWindow; | |
1844 { | |
1845 Rect r; | |
1846 Point p; | |
1847 short thePart; | |
1848 | |
1849 /* ideal width is current */ | |
1850 p.h = Columns * gui.char_width + 2 * gui.border_offset; | |
1851 if (gui.which_scrollbars[SBAR_LEFT]) | |
1852 p.h += gui.scrollbar_width; | |
1853 if (gui.which_scrollbars[SBAR_RIGHT]) | |
1854 p.h += gui.scrollbar_width; | |
1855 /* ideal height is as heigh as we can get */ | |
1856 p.v = 15 * 1024; | |
1857 | |
1858 thePart = IsWindowInStandardState(whichWindow, &p, &r) | |
1859 ? inZoomIn : inZoomOut; | |
1860 | |
1861 if (!TrackBox(whichWindow, theEvent->where, thePart)) | |
1862 return; | |
1863 | |
1864 /* use returned width */ | |
1865 p.h = r.right - r.left; | |
1866 /* adjust returned height */ | |
1867 p.v = r.bottom - r.top - 2 * gui.border_offset; | |
1868 if (gui.which_scrollbars[SBAR_BOTTOM]) | |
1869 p.v -= gui.scrollbar_height; | |
1870 p.v -= p.v % gui.char_height; | |
1871 p.v += 2 * gui.border_width; | |
1872 if (gui.which_scrollbars[SBAR_BOTTOM]); | |
1873 p.v += gui.scrollbar_height; | |
1874 | |
1875 ZoomWindowIdeal(whichWindow, thePart, &p); | |
1876 | |
1877 GetWindowBounds(whichWindow, kWindowContentRgn, &r); | |
1878 gui_resize_shell(r.right - r.left, r.bottom - r.top); | |
1879 gui_mch_set_bg_color(gui.back_pixel); | |
1880 gui_set_shellsize(TRUE, FALSE); | |
1881 } | |
1882 #endif /* defined(USE_CARBONIZED) */ | |
1883 | |
1884 /* | |
1885 * ------------------------------------------------------------ | |
1886 * MacOS Event Handling procedure | |
1887 * ------------------------------------------------------------ | |
1888 */ | |
1889 | |
1890 /* | |
1891 * Handle the Update Event | |
1892 */ | |
1893 | |
1894 void | |
1895 gui_mac_doUpdateEvent(event) | |
1896 EventRecord *event; | |
1897 { | |
1898 WindowPtr whichWindow; | |
1899 GrafPtr savePort; | |
1900 RgnHandle updateRgn; | |
1901 #ifdef USE_CARBONIZED | |
1902 Rect updateRect; | |
1903 #endif | |
1904 Rect *updateRectPtr; | |
1905 Rect rc; | |
1906 Rect growRect; | |
1907 RgnHandle saveRgn; | |
1908 | |
1909 | |
1910 #ifdef USE_CARBONIZED | |
1911 updateRgn = NewRgn(); | |
1912 if (updateRgn == NULL) | |
1913 return; | |
1914 #endif | |
1915 | |
1916 /* This could be done by the caller as we | |
1917 * don't require anything else out of the event | |
1918 */ | |
1919 whichWindow = (WindowPtr) event->message; | |
1920 | |
1921 /* Save Current Port */ | |
1922 GetPort (&savePort); | |
1923 | |
1924 /* Select the Window's Port */ | |
1925 #ifdef USE_CARBONIZED | |
1926 SetPortWindowPort (whichWindow); | |
1927 #else | |
1928 SetPort (whichWindow); | |
1929 #endif | |
1930 | |
1931 /* Let's update the window */ | |
1932 BeginUpdate (whichWindow); | |
1933 /* Redraw the biggest rectangle covering the area | |
1934 * to be updated. | |
1935 */ | |
1936 #ifdef USE_CARBONIZED | |
1937 GetPortVisibleRegion(GetWindowPort(whichWindow), updateRgn); | |
1938 # if 0 | |
1939 /* Would be more appropriate to use the follwing but doesn't | |
1940 * seem to work under MacOS X (Dany) | |
1941 */ | |
1942 GetWindowRegion(whichWindow, kWindowUpdateRgn, updateRgn); | |
1943 # endif | |
1944 #else | |
1945 updateRgn = whichWindow->visRgn; | |
1946 #endif | |
1947 /* Use the HLock useless in Carbon? Is it harmful?*/ | |
1948 HLock ((Handle) updateRgn); | |
1949 #ifdef USE_CARBONIZED | |
1950 updateRectPtr = GetRegionBounds ( updateRgn, &updateRect ); | |
1951 # if 0 | |
1952 /* Code from original Carbon Port (using GetWindowRegion. | |
1953 * I believe the UpdateRgn is already in local (Dany) | |
1954 */ | |
1955 GlobalToLocal(&topLeft(updateRect)); /* preCarbon? */ | |
1956 GlobalToLocal(&botRight(updateRect)); | |
1957 # endif | |
1958 #else | |
1959 updateRectPtr = &(*updateRgn)->rgnBBox; | |
1960 #endif | |
1961 /* Update the content (i.e. the text) */ | |
1962 gui_redraw(updateRectPtr->left, updateRectPtr->top, | |
1963 updateRectPtr->right - updateRectPtr->left, | |
1964 updateRectPtr->bottom - updateRectPtr->top); | |
1965 /* Clear the border areas if needed */ | |
1966 gui_mch_set_bg_color(gui.back_pixel); | |
1967 if (updateRectPtr->left < FILL_X(0)) | |
1968 { | |
1969 SetRect (&rc, 0, 0, FILL_X(0), FILL_Y(Rows)); | |
1970 EraseRect (&rc); | |
1971 } | |
1972 if (updateRectPtr->top < FILL_Y(0)) | |
1973 { | |
1974 SetRect (&rc, 0, 0, FILL_X(Columns), FILL_Y(0)); | |
1975 EraseRect (&rc); | |
1976 } | |
1977 if (updateRectPtr->right > FILL_X(Columns)) | |
1978 { | |
1979 SetRect (&rc, FILL_X(Columns), 0, | |
1980 FILL_X(Columns) + gui.border_offset, FILL_Y(Rows)); | |
1981 EraseRect (&rc); | |
1982 } | |
1983 if (updateRectPtr->bottom > FILL_Y(Rows)) | |
1984 { | |
1985 SetRect (&rc, 0, FILL_Y(Rows), FILL_X(Columns) + gui.border_offset, | |
1986 FILL_Y(Rows) + gui.border_offset); | |
1987 EraseRect (&rc); | |
1988 } | |
1989 HUnlock ((Handle) updateRgn); | |
1990 #ifdef USE_CARBONIZED | |
1991 DisposeRgn (updateRgn); | |
1992 #endif | |
1993 | |
1994 /* Update scrollbars */ | |
1995 DrawControls (whichWindow); | |
1996 | |
1997 /* Update the GrowBox */ | |
1998 /* Taken from FAQ 33-27 */ | |
1999 saveRgn = NewRgn(); | |
2000 #ifdef USE_CARBONIZED | |
2001 GetWindowBounds(whichWindow, kWindowGrowRgn, &growRect); | |
2002 #else | |
2003 growRect = whichWindow->portRect; | |
2004 growRect.top = growRect.bottom - 15; | |
2005 growRect.left = growRect.right - 15; | |
2006 #endif | |
2007 GetClip (saveRgn); | |
2008 ClipRect (&growRect); | |
2009 DrawGrowIcon (whichWindow); | |
2010 SetClip (saveRgn); | |
2011 DisposeRgn (saveRgn); | |
2012 EndUpdate (whichWindow); | |
2013 | |
2014 /* Restore original Port */ | |
2015 SetPort (savePort); | |
2016 } | |
2017 | |
2018 /* | |
2019 * Handle the activate/deactivate event | |
2020 * (apply to a window) | |
2021 */ | |
2022 void | |
2023 gui_mac_doActivateEvent(event) | |
2024 EventRecord *event; | |
2025 { | |
2026 WindowPtr whichWindow; | |
2027 | |
2028 whichWindow = (WindowPtr) event->message; | |
2029 if ((event->modifiers) & activeFlag) | |
2030 /* Activate */ | |
2031 gui_focus_change(TRUE); | |
2032 else | |
2033 { | |
2034 /* Deactivate */ | |
2035 gui_focus_change(FALSE); | |
2036 /* DON'T KNOW what the code below was doing | |
2037 found in the deactivate clause, but the | |
2038 clause writting TRUE into in_focus (BUG) | |
2039 */ | |
2040 | |
2041 #if 0 /* Removed by Dany as per above June 2001 */ | |
2042 a_bool = false; | |
2043 SetPreserveGlyph (a_bool); | |
2044 SetOutlinePreferred (a_bool); | |
2045 #endif | |
2046 } | |
2047 } | |
2048 | |
2049 | |
2050 /* | |
2051 * Handle the suspend/resume event | |
2052 * (apply to the application) | |
2053 */ | |
2054 void | |
2055 gui_mac_doSuspendEvent(event) | |
2056 EventRecord *event; | |
2057 { | |
2058 /* The frontmost application just changed */ | |
2059 | |
2060 /* NOTE: the suspend may happen before the deactivate | |
2061 * seen on MacOS X | |
2062 */ | |
2063 | |
2064 /* May not need to change focus as the window will | |
2065 * get an activate/desactivate event | |
2066 */ | |
2067 if (event->message & 1) | |
2068 /* Resume */ | |
2069 gui_focus_change(TRUE); | |
2070 else | |
2071 /* Suspend */ | |
2072 gui_focus_change(FALSE); | |
2073 } | |
2074 | |
2075 /* | |
2076 * Handle the key | |
2077 */ | |
2078 | |
2079 void | |
2080 gui_mac_doKeyEvent(EventRecord *theEvent) | |
2081 { | |
2082 /* TODO: add support for COMMAND KEY */ | |
2083 long menu; | |
2084 unsigned char string[20]; | |
2085 short num, i; | |
2086 short len = 0; | |
2087 KeySym key_sym; | |
2088 int key_char; | |
2089 int modifiers; | |
2090 | |
2091 /* Mask the mouse (as per user setting) */ | |
2092 if (p_mh) | |
2093 ObscureCursor(); | |
2094 | |
2095 /* Get the key code and it's ASCII representation */ | |
2096 key_sym = ((theEvent->message & keyCodeMask) >> 8); | |
2097 key_char = theEvent->message & charCodeMask; | |
2098 num = 1; | |
2099 | |
2100 /* Intercept CTRL-C */ | |
2101 if (theEvent->modifiers & controlKey) | |
2102 if (key_char == Ctrl_C && ctrl_c_interrupts) | |
2103 got_int = TRUE; | |
2104 | |
2105 /* Intercept CMD-. */ | |
2106 if (theEvent->modifiers & cmdKey) | |
2107 if (key_char == '.') | |
2108 got_int = TRUE; | |
2109 | |
2110 /* Handle command key as per menu */ | |
2111 /* TODO: should override be allowed? Require YAO or could use 'winaltkey' */ | |
2112 if (theEvent->modifiers & cmdKey) | |
2113 /* Only accept CMD alone or with CAPLOCKS and the mouse button. | |
2114 * Why the mouse button? */ | |
2115 if ((theEvent->modifiers & (~(cmdKey | btnState | alphaLock))) == 0) | |
2116 { | |
2117 menu = MenuKey(key_char); | |
2118 if (HiWord(menu)) | |
2119 { | |
2120 gui_mac_handle_menu(menu); | |
2121 return; | |
2122 } | |
2123 } | |
2124 | |
2125 /* Convert the modifiers */ | |
2126 modifiers = EventModifiers2VimModifiers(theEvent->modifiers); | |
2127 | |
2128 | |
2129 /* Handle special keys. */ | |
2130 #if 0 | |
2131 /* Why have this been removed? */ | |
2132 if (!(theEvent->modifiers & (cmdKey | controlKey | rightControlKey))) | |
2133 #endif | |
2134 { | |
2135 /* Find the special key (for non-printable keyt_char) */ | |
2136 if ((key_char < 0x20) || (key_char == 0x7f)) | |
2137 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++) | |
2138 if (special_keys[i].key_sym == key_sym) | |
2139 { | |
2140 # if 0 | |
2141 /* We currently don't have not so special key */ | |
2142 if (special_keys[i].vim_code1 == NUL) | |
2143 key_char = special_keys[i].vim_code0; | |
2144 else | |
2145 # endif | |
2146 key_char = TO_SPECIAL( special_keys[i].vim_code0, | |
2147 special_keys[i].vim_code1 ); | |
2148 key_char = simplify_key(key_char,&modifiers); | |
2149 break; | |
2150 } | |
2151 } | |
2152 | |
2153 | |
2154 /* Add the modifier to the input bu if needed */ | |
2155 /* Do not want SHIFT-A or CTRL-A with modifier */ | |
2156 if (!IS_SPECIAL(key_char) | |
2157 && key_sym != vk_Space | |
2158 && key_sym != vk_Tab | |
2159 && key_sym != vk_Return | |
2160 && key_sym != vk_Enter | |
2161 && key_sym != vk_Esc) | |
2162 { | |
2163 #if 1 | |
2164 /* Clear modifiers when only one modifier is set */ | |
2165 if( (modifiers == MOD_MASK_SHIFT) || | |
2166 (modifiers == MOD_MASK_CTRL) || | |
2167 (modifiers == MOD_MASK_ALT)) | |
2168 modifiers = 0; | |
2169 #else | |
2170 if( modifiers & MOD_MASK_CTRL) | |
2171 modifiers = modifiers & ~MOD_MASK_CTRL; | |
2172 if( modifiers & MOD_MASK_ALT) | |
2173 modifiers = modifiers & ~MOD_MASK_ALT; | |
2174 if( modifiers & MOD_MASK_SHIFT) | |
2175 modifiers = modifiers & ~MOD_MASK_SHIFT; | |
2176 #endif | |
2177 } | |
2178 if( modifiers ) | |
2179 { | |
2180 string[ len++ ] = CSI; | |
2181 string[ len++ ] = KS_MODIFIER; | |
2182 string[ len++ ] = modifiers; | |
2183 } | |
2184 | |
2185 if( IS_SPECIAL( key_char ) ) | |
2186 { | |
2187 string[ len++ ] = CSI; | |
2188 string[ len++ ] = K_SECOND( key_char ); | |
2189 string[ len++ ] = K_THIRD( key_char ); | |
2190 } | |
2191 else | |
2192 { | |
2193 #ifdef FEAT_MBYTE | |
2194 if (input_conv.vc_type != CONV_NONE) | |
2195 { | |
2196 char_u from[2], *to; | |
2197 int l; | |
2198 | |
2199 from[0] = key_char; | |
2200 from[1] = NUL; | |
2201 l = 1; | |
2202 to = string_convert(&input_conv, from, &l); | |
2203 if (to != NULL) | |
2204 { | |
2205 for (i = 0; i < l && len < 19; i++) | |
2206 { | |
2207 if (to[i] == CSI) | |
2208 { | |
2209 string[len++] = KS_EXTRA; | |
2210 string[len++] = KE_CSI; | |
2211 } | |
2212 else | |
2213 string[len++] = to[i]; | |
2214 } | |
2215 vim_free(to); | |
2216 } | |
2217 else | |
2218 string[len++] = key_char; | |
2219 } | |
2220 else | |
2221 #endif | |
2222 string[len++] = key_char; | |
2223 } | |
2224 | |
2225 if (len == 1 && string[0] == CSI) | |
2226 { | |
2227 /* Turn CSI into K_CSI. */ | |
2228 string[ len++ ] = KS_EXTRA; | |
2229 string[ len++ ] = KE_CSI; | |
2230 } | |
2231 | |
2232 add_to_input_buf(string, len); | |
2233 } | |
2234 | |
2235 /* | |
2236 * Handle MouseClick | |
2237 */ | |
2238 void | |
2239 gui_mac_doMouseDownEvent (theEvent) | |
2240 EventRecord *theEvent; | |
2241 { | |
2242 short thePart; | |
2243 WindowPtr whichWindow; | |
2244 | |
2245 thePart = FindWindow (theEvent->where, &whichWindow); | |
2246 | |
2247 switch (thePart) | |
2248 { | |
2249 case (inDesk): | |
2250 /* TODO: what to do? */ | |
2251 break; | |
2252 | |
2253 case (inMenuBar): | |
2254 gui_mac_handle_menu(MenuSelect (theEvent->where)); | |
2255 break; | |
2256 | |
2257 case (inContent): | |
2258 gui_mac_doInContentClick (theEvent, whichWindow); | |
2259 break; | |
2260 | |
2261 case (inDrag): | |
2262 gui_mac_doInDragClick (theEvent->where, whichWindow); | |
2263 break; | |
2264 | |
2265 case (inGrow): | |
2266 gui_mac_doInGrowClick (theEvent->where, whichWindow); | |
2267 break; | |
2268 | |
2269 case (inGoAway): | |
2270 if (TrackGoAway(whichWindow, theEvent->where)) | |
2271 gui_shell_closed(); | |
2272 break; | |
2273 | |
2274 case (inZoomIn): | |
2275 case (inZoomOut): | |
2276 #ifdef USE_CARBONIZED | |
2277 gui_mac_doInZoomClick(theEvent, whichWindow); | |
2278 #endif | |
2279 break; | |
2280 } | |
2281 } | |
2282 | |
2283 /* | |
2284 * Handle MouseMoved | |
2285 * [this event is a moving in and out of a region] | |
2286 */ | |
2287 void | |
2288 gui_mac_doMouseMovedEvent (event) | |
2289 EventRecord *event; | |
2290 { | |
2291 Point thePoint; | |
2292 int_u vimModifiers; | |
2293 | |
2294 thePoint = event->where; | |
2295 GlobalToLocal (&thePoint); | |
2296 vimModifiers = EventModifiers2VimMouseModifiers(event->modifiers); | |
2297 | |
2298 if (!Button()) | |
2299 gui_mouse_moved (thePoint.h, thePoint.v); | |
2300 else | |
2301 #ifdef USE_CTRLCLICKMENU | |
2302 if (!clickIsPopup) | |
2303 #endif | |
2304 gui_send_mouse_event(MOUSE_DRAG, thePoint.h, | |
2305 thePoint.v, FALSE, vimModifiers); | |
2306 | |
2307 /* Reset the region from which we move in and out */ | |
2308 SetRect (&dragRect, FILL_X(X_2_COL(thePoint.h)), | |
2309 FILL_Y(Y_2_ROW(thePoint.v)), | |
2310 FILL_X(X_2_COL(thePoint.h)+1), | |
2311 FILL_Y(Y_2_ROW(thePoint.v)+1)); | |
2312 | |
2313 if (dragRectEnbl) | |
2314 dragRectControl = kCreateRect; | |
2315 | |
2316 } | |
2317 | |
2318 /* | |
2319 * Handle the mouse release | |
2320 */ | |
2321 void | |
2322 gui_mac_doMouseUpEvent (theEvent) | |
2323 EventRecord *theEvent; | |
2324 { | |
2325 Point thePoint; | |
2326 int_u vimModifiers; | |
2327 | |
2328 /* TODO: Properly convert the Contextual menu mouse-up */ | |
2329 /* Potential source of the double menu */ | |
2330 lastMouseTick = theEvent->when; | |
2331 dragRectEnbl = FALSE; | |
2332 dragRectControl = kCreateEmpty; | |
2333 thePoint = theEvent->where; | |
2334 GlobalToLocal (&thePoint); | |
2335 | |
2336 vimModifiers = EventModifiers2VimMouseModifiers(theEvent->modifiers); | |
2337 #ifdef USE_CTRLCLICKMENU | |
2338 if (clickIsPopup) | |
2339 { | |
2340 vimModifiers &= ~MOUSE_CTRL; | |
2341 clickIsPopup = FALSE; | |
2342 } | |
2343 #endif | |
2344 gui_send_mouse_event | |
2345 (MOUSE_RELEASE, thePoint.h, thePoint.v, FALSE, vimModifiers); | |
2346 } | |
2347 | |
2348 #ifdef USE_MOUSEWHEEL | |
2349 static pascal OSStatus | |
2350 gui_mac_mouse_wheel(EventHandlerCallRef nextHandler, EventRef theEvent, | |
2351 void *data) | |
2352 { | |
2353 EventRef bogusEvent; | |
2354 Point point; | |
2355 Rect bounds; | |
2356 UInt32 mod; | |
2357 SInt32 delta; | |
2358 int_u vim_mod; | |
2359 | |
2360 if (noErr != GetEventParameter(theEvent, kEventParamMouseWheelDelta, | |
2361 typeSInt32, NULL, sizeof(SInt32), NULL, &delta)) | |
2362 goto bail; | |
2363 if (noErr != GetEventParameter(theEvent, kEventParamMouseLocation, | |
2364 typeQDPoint, NULL, sizeof(Point), NULL, &point)) | |
2365 goto bail; | |
2366 if (noErr != GetEventParameter(theEvent, kEventParamKeyModifiers, | |
2367 typeUInt32, NULL, sizeof(UInt32), NULL, &mod)) | |
2368 goto bail; | |
2369 | |
2370 vim_mod = 0; | |
2371 if (mod & shiftKey) | |
2372 vim_mod |= MOUSE_SHIFT; | |
2373 if (mod & controlKey) | |
2374 vim_mod |= MOUSE_CTRL; | |
2375 if (mod & optionKey) | |
2376 vim_mod |= MOUSE_ALT; | |
2377 | |
2378 /* post a bogus event to wake up WaitNextEvent */ | |
2379 if (noErr != CreateEvent(NULL, kEventClassMouse, kEventMouseMoved, 0, | |
2380 kEventAttributeNone, &bogusEvent)) | |
2381 goto bail; | |
2382 if (noErr != PostEventToQueue(GetMainEventQueue(), bogusEvent, | |
2383 kEventPriorityLow)) | |
2384 goto bail; | |
2385 | |
2386 if (noErr == GetWindowBounds(gui.VimWindow, kWindowContentRgn, &bounds)) | |
2387 { | |
2388 point.h -= bounds.left; | |
2389 point.v -= bounds.top; | |
2390 } | |
2391 | |
2392 gui_send_mouse_event((delta > 0) ? MOUSE_4 : MOUSE_5, | |
2393 point.h, point.v, FALSE, vim_mod); | |
2394 | |
2395 return noErr; | |
2396 | |
2397 bail: | |
2398 /* | |
2399 * when we fail give any additional callback handler a chance to perform | |
2400 * it's actions | |
2401 */ | |
2402 return CallNextEventHandler(nextHandler, theEvent); | |
2403 } | |
2404 #endif /* defined(USE_MOUSEWHEEL) */ | |
2405 | |
2406 #if 0 | |
2407 | |
2408 /* | |
2409 * This would be the normal way of invoking the contextual menu | |
2410 * but the Vim API doesn't seem to a support a request to get | |
2411 * the menu that we should display | |
2412 */ | |
2413 void | |
2414 gui_mac_handle_contextual_menu(event) | |
2415 EventRecord *event; | |
2416 { | |
2417 /* | |
2418 * Clone PopUp to use menu | |
2419 * Create a object descriptor for the current selection | |
2420 * Call the procedure | |
2421 */ | |
2422 | |
2423 // Call to Handle Popup | |
2424 OSStatus status = ContextualMenuSelect(CntxMenu, event->where, false, kCMHelpItemNoHelp, "", NULL, &CntxType, &CntxMenuID, &CntxMenuItem); | |
2425 | |
2426 if (status != noErr) | |
2427 return; | |
2428 | |
2429 if (CntxType == kCMMenuItemSelected) | |
2430 { | |
2431 /* Handle the menu CntxMenuID, CntxMenuItem */ | |
2432 /* The submenu can be handle directly by gui_mac_handle_menu */ | |
2433 /* But what about the current menu, is the meny changed by ContextualMenuSelect */ | |
2434 gui_mac_handle_menu ((CntxMenuID << 16) + CntxMenuItem); | |
2435 } | |
2436 else if (CntxMenuID == kCMShowHelpSelected) | |
2437 { | |
2438 /* Should come up with the help */ | |
2439 } | |
2440 | |
2441 } | |
2442 #endif | |
2443 | |
2444 /* | |
2445 * Handle menubar selection | |
2446 */ | |
2447 void | |
2448 gui_mac_handle_menu(menuChoice) | |
2449 long menuChoice; | |
2450 { | |
2451 short menu = HiWord(menuChoice); | |
2452 short item = LoWord(menuChoice); | |
2453 vimmenu_T *theVimMenu = root_menu; | |
2454 #ifndef USE_CARBONIZED | |
2455 MenuHandle appleMenu; | |
2456 Str255 itemName; | |
2457 #endif | |
2458 | |
2459 if (menu == 256) /* TODO: use constant or gui.xyz */ | |
2460 { | |
2461 if (item == 1) | |
2462 gui_mch_beep(); /* TODO: Popup dialog or do :intro */ | |
2463 else | |
2464 { | |
2465 #ifndef USE_CARBONIZED | |
2466 /* Desk Accessory doesn't exist in Carbon */ | |
2467 appleMenu = GetMenuHandle (menu); | |
2468 GetMenuItemText (appleMenu, item, itemName); | |
2469 (void) OpenDeskAcc (itemName); | |
2470 #endif | |
2471 } | |
2472 } | |
2473 else if (item != 0) | |
2474 { | |
2475 theVimMenu = gui_mac_get_vim_menu(menu, item, root_menu); | |
2476 | |
2477 if (theVimMenu) | |
2478 gui_menu_cb(theVimMenu); | |
2479 } | |
2480 HiliteMenu (0); | |
2481 } | |
2482 | |
2483 /* | |
2484 * Dispatch the event to proper handler | |
2485 */ | |
2486 | |
2487 void | |
2488 gui_mac_handle_event (event) | |
2489 EventRecord *event; | |
2490 { | |
2491 OSErr error; | |
2492 | |
2493 /* Handle contextual menu right now (if needed) */ | |
2494 #ifdef USE_CTRLCLICKMENU | |
2495 if (gui.MacOSHaveCntxMenu) | |
2496 if (IsShowContextualMenuClick(event)) | |
2497 { | |
2498 # if 0 | |
2499 gui_mac_handle_contextual_menu(event); | |
2500 # else | |
2501 gui_mac_doMouseDownEvent(event); | |
2502 # endif | |
2503 return; | |
2504 } | |
2505 #endif | |
2506 | |
2507 /* Handle normal event */ | |
2508 switch (event->what) | |
2509 { | |
2510 case (keyDown): | |
2511 case (autoKey): | |
2512 gui_mac_doKeyEvent (event); | |
2513 break; | |
2514 | |
2515 case (keyUp): | |
2516 /* We don't care about when the key get release */ | |
2517 break; | |
2518 | |
2519 case (mouseDown): | |
2520 gui_mac_doMouseDownEvent(event); | |
2521 break; | |
2522 | |
2523 case (mouseUp): | |
2524 gui_mac_doMouseUpEvent(event); | |
2525 break; | |
2526 | |
2527 case (updateEvt): | |
2528 gui_mac_doUpdateEvent (event); | |
2529 break; | |
2530 | |
2531 case (diskEvt): | |
2532 /* We don't need special handling for disk insertion */ | |
2533 break; | |
2534 | |
2535 case (activateEvt): | |
2536 gui_mac_doActivateEvent (event); | |
2537 break; | |
2538 | |
2539 case (osEvt): | |
2540 switch ((event->message >> 24) & 0xFF) | |
2541 { | |
2542 case (0xFA): /* mouseMovedMessage */ | |
2543 gui_mac_doMouseMovedEvent (event); | |
2544 break; | |
2545 case (0x01): /* suspendResumeMessage */ | |
2546 gui_mac_doSuspendEvent (event); | |
2547 break; | |
2548 } | |
2549 break; | |
2550 | |
2551 #ifdef USE_AEVENT | |
2552 case (kHighLevelEvent): | |
2553 /* Someone's talking to us, through AppleEvents */ | |
2554 error = AEProcessAppleEvent(event); /* TODO: Error Handling */ | |
2555 break; | |
2556 #endif | |
2557 } | |
2558 } | |
2559 | |
2560 /* | |
2561 * ------------------------------------------------------------ | |
2562 * Unknown Stuff | |
2563 * ------------------------------------------------------------ | |
2564 */ | |
2565 | |
2566 | |
2567 GuiFont | |
2568 gui_mac_find_font (font_name) | |
2569 char_u *font_name; | |
2570 { | |
2571 char_u c; | |
2572 char_u *p; | |
2573 char_u pFontName[256]; | |
2574 Str255 systemFontname; | |
2575 short font_id; | |
2576 short size=9; | |
2577 GuiFont font; | |
2578 #if 0 | |
2579 char_u *fontNamePtr; | |
2580 #endif | |
2581 | |
2582 for (p = font_name; ((*p != 0) && (*p != ':')); p++) | |
2583 ; | |
2584 | |
2585 c = *p; | |
2586 *p = 0; | |
2587 | |
2588 #if 1 | |
2589 STRCPY(&pFontName[1], font_name); | |
2590 pFontName[0] = STRLEN(font_name); | |
2591 *p = c; | |
2592 | |
2593 GetFNum (pFontName, &font_id); | |
2594 #else | |
2595 /* name = C2Pascal_save(menu->dname); */ | |
2596 fontNamePtr = C2Pascal_save_and_remove_backslash(font_name); | |
2597 | |
2598 GetFNum (fontNamePtr, &font_id); | |
2599 #endif | |
2600 | |
2601 | |
2602 if (font_id == 0) | |
2603 { | |
2604 /* Oups, the system font was it the one the user want */ | |
2605 | |
2606 GetFontName (0, systemFontname); | |
2607 if (!EqualString(pFontName, systemFontname, false, false)) | |
2608 return NOFONT; | |
2609 } | |
2610 if (*p == ':') | |
2611 { | |
2612 p++; | |
2613 /* Set the values found after ':' */ | |
2614 while (*p) | |
2615 { | |
2616 switch (*p++) | |
2617 { | |
2618 case 'h': | |
2619 size = points_to_pixels(p, &p, TRUE); | |
2620 break; | |
2621 /* | |
2622 * TODO: Maybe accept width and styles | |
2623 */ | |
2624 } | |
2625 while (*p == ':') | |
2626 p++; | |
2627 } | |
2628 } | |
2629 | |
2630 if (size < 1) | |
2631 size = 1; /* Avoid having a size of 0 with system font */ | |
2632 | |
2633 font = (size << 16) + ((long) font_id & 0xFFFF); | |
2634 | |
2635 return font; | |
2636 } | |
2637 | |
2638 /* | |
2639 * ------------------------------------------------------------ | |
2640 * GUI_MCH functionnality | |
2641 * ------------------------------------------------------------ | |
2642 */ | |
2643 | |
2644 /* | |
2645 * Parse the GUI related command-line arguments. Any arguments used are | |
2646 * deleted from argv, and *argc is decremented accordingly. This is called | |
2647 * when vim is started, whether or not the GUI has been started. | |
2648 */ | |
2649 void | |
2650 gui_mch_prepare(argc, argv) | |
2651 int *argc; | |
2652 char **argv; | |
2653 { | |
2654 /* TODO: Move most of this stuff toward gui_mch_init */ | |
2655 #ifdef USE_EXE_NAME | |
2656 FSSpec applDir; | |
2657 # ifndef USE_FIND_BUNDLE_PATH | |
2658 short applVRefNum; | |
2659 long applDirID; | |
2660 Str255 volName; | |
2661 # else | |
2662 ProcessSerialNumber psn; | |
2663 FSRef applFSRef; | |
2664 # endif | |
2665 #endif | |
2666 | |
2667 #ifndef USE_CARBONIZED | |
2668 MaxApplZone(); /* What could replace thos */ | |
2669 /* In Carbon, all shared library are automatically load in | |
2670 * there's no need to init them | |
2671 */ | |
2672 InitGraf(&qd.thePort); | |
2673 InitFonts(); | |
2674 InitWindows(); | |
2675 InitMenus(); | |
2676 TEInit(); | |
2677 InitDialogs(nil); | |
2678 #else | |
2679 /* Why did I put that in? (Dany) */ | |
2680 MoreMasterPointers (0x40 * 3); /* we love handles */ | |
2681 #endif | |
2682 | |
2683 #if 0 | |
2684 InitCursor(); | |
2685 | |
2686 #ifdef USE_CARBONIZED | |
2687 RegisterAppearanceClient(); | |
2688 #endif | |
2689 | |
2690 #ifdef USE_AEVENT | |
2691 (void) InstallAEHandlers(); | |
2692 #endif | |
2693 | |
2694 #ifdef USE_CTRLCLICKMENU | |
2695 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr) | |
2696 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable); | |
2697 else | |
2698 gui.MacOSHaveCntxMenu = false; | |
2699 | |
2700 if (gui.MacOSHaveCntxMenu) | |
2701 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr); | |
2702 #endif | |
2703 | |
2704 #ifdef USE_SIOUX | |
2705 SIOUXSettings.standalone = false; | |
2706 SIOUXSettings.initializeTB = false; | |
2707 SIOUXSettings.setupmenus = false; | |
2708 SIOUXSettings.asktosaveonclose = false; | |
2709 SIOUXSettings.showstatusline = true; | |
2710 SIOUXSettings.toppixel = 300; | |
2711 SIOUXSettings.leftpixel = 10; | |
2712 InstallConsole (1); /* fileno(stdout) = 1, on page 430 of MSL C */ | |
2713 printf ("Debugging console enabled\n"); | |
2714 /* SIOUXSetTitle ((char_u *) "Vim Stdout"); */ | |
2715 #endif | |
2716 | |
2717 pomme = NewMenu (256, "\p\024"); /* 0x14= = Apple Menu */ | |
2718 | |
2719 AppendMenu (pomme, "\pAbout VIM"); | |
2720 #ifndef USE_CARBONIZED | |
2721 AppendMenu (pomme, "\p-"); | |
2722 AppendResMenu (pomme, 'DRVR'); | |
2723 #endif | |
2724 | |
2725 InsertMenu (pomme, 0); | |
2726 | |
2727 DrawMenuBar(); | |
2728 | |
2729 | |
2730 #ifndef USE_OFFSETED_WINDOW | |
2731 SetRect (&windRect, 10, 48, 10+80*7 + 16, 48+24*11); | |
2732 #else | |
2733 SetRect (&windRect, 300, 40, 300+80*7 + 16, 40+24*11); | |
2734 #endif | |
2735 | |
2736 | |
2737 #ifdef USE_CARBONIZED | |
2738 CreateNewWindow(kDocumentWindowClass, | |
2739 kWindowResizableAttribute | kWindowCollapseBoxAttribute, | |
2740 &windRect, &gui.VimWindow ); | |
2741 SetPortWindowPort ( gui.VimWindow ); | |
2742 #else | |
2743 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, documentProc, | |
2744 (WindowPtr) -1L, false, 0); | |
2745 SetPort(gui.VimWindow); | |
2746 #endif | |
2747 | |
2748 gui.char_width = 7; | |
2749 gui.char_height = 11; | |
2750 gui.char_ascent = 6; | |
2751 gui.num_rows = 24; | |
2752 gui.num_cols = 80; | |
2753 gui.in_focus = TRUE; /* For the moment -> syn. of front application */ | |
2754 | |
2755 #if TARGET_API_MAC_CARBON | |
2756 gScrollAction = NewControlActionUPP (gui_mac_scroll_action); | |
2757 gScrollDrag = NewControlActionUPP (gui_mac_drag_thumb); | |
2758 #else | |
2759 gScrollAction = NewControlActionProc (gui_mac_scroll_action); | |
2760 gScrollDrag = NewControlActionProc (gui_mac_drag_thumb); | |
2761 #endif | |
2762 | |
2763 /* Getting a handle to the Help menu */ | |
2764 #ifdef USE_HELPMENU | |
2765 # ifdef USE_CARBONIZED | |
2766 HMGetHelpMenu(&gui.MacOSHelpMenu, NULL); | |
2767 # else | |
2768 (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu); | |
2769 # endif | |
2770 | |
2771 if (gui.MacOSHelpMenu != nil) | |
2772 gui.MacOSHelpItems = CountMenuItems (gui.MacOSHelpMenu); | |
2773 else | |
2774 gui.MacOSHelpItems = 0; | |
2775 #endif | |
2776 | |
2777 dragRectEnbl = FALSE; | |
2778 dragRgn = NULL; | |
2779 dragRectControl = kCreateEmpty; | |
2780 cursorRgn = NewRgn(); | |
2781 #endif | |
2782 #ifdef USE_EXE_NAME | |
2783 # ifndef USE_FIND_BUNDLE_PATH | |
2784 HGetVol (volName, &applVRefNum, &applDirID); | |
2785 /* TN2015: mention a possible bad VRefNum */ | |
2786 FSMakeFSSpec (applVRefNum, applDirID, "\p", &applDir); | |
2787 # else | |
2788 /* OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr) | |
2789 * of TN2015 | |
2790 * This technic remove the ../Contents/MacOS/etc part | |
2791 */ | |
2792 (void) GetCurrentProcess(&psn); | |
2793 /* if (err != noErr) return err; */ | |
2794 | |
2795 (void) GetProcessBundleLocation(&psn, &applFSRef); | |
2796 /* if (err != noErr) return err; */ | |
2797 | |
2798 (void) FSGetCatalogInfo(&applFSRef, kFSCatInfoNone, NULL, NULL, &applDir, NULL); | |
2799 | |
2800 /* This technic return NIL when we disallow_gui */ | |
2801 # endif | |
2802 exe_name = FullPathFromFSSpec_save (applDir); | |
2803 #endif | |
2804 | |
2805 #ifdef USE_VIM_CREATOR_ID | |
2806 _fcreator = 'VIM!'; | |
2807 _ftype = 'TEXT'; | |
2808 #endif | |
2809 } | |
2810 | |
2811 #ifndef ALWAYS_USE_GUI | |
2812 /* | |
2813 * Check if the GUI can be started. Called before gvimrc is sourced. | |
2814 * Return OK or FAIL. | |
2815 */ | |
2816 int | |
2817 gui_mch_init_check(void) | |
2818 { | |
2819 /* TODO: For MacOS X find a way to return FAIL, if the user logged in | |
2820 * using the >console | |
2821 */ | |
2822 if (disallow_gui) /* see main.c for reason to disallow */ | |
2823 return FAIL; | |
2824 return OK; | |
2825 } | |
2826 #endif | |
2827 | |
2828 static OSErr | |
2829 receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag) | |
2830 { | |
2831 int x, y; | |
2832 int_u modifiers; | |
2833 char_u **fnames = NULL; | |
2834 int count; | |
2835 int i, j; | |
2836 | |
2837 /* Get drop position, modifiers and count of items */ | |
2838 { | |
2839 Point point; | |
2840 SInt16 mouseUpModifiers; | |
2841 UInt16 countItem; | |
2842 | |
2843 GetDragMouse(theDrag, &point, NULL); | |
2844 GlobalToLocal(&point); | |
2845 x = point.h; | |
2846 y = point.v; | |
2847 GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers); | |
2848 modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers); | |
2849 CountDragItems(theDrag, &countItem); | |
2850 count = countItem; | |
2851 } | |
2852 | |
2853 fnames = (char_u **)alloc(count * sizeof(char_u *)); | |
2854 if (fnames == NULL) | |
2855 return dragNotAcceptedErr; | |
2856 | |
2857 /* Get file names dropped */ | |
2858 for (i = j = 0; i < count; ++i) | |
2859 { | |
2860 DragItemRef item; | |
2861 OSErr err; | |
2862 Size size; | |
2863 FlavorType type = flavorTypeHFS; | |
2864 HFSFlavor hfsFlavor; | |
2865 | |
2866 fnames[i] = NULL; | |
2867 GetDragItemReferenceNumber(theDrag, i + 1, &item); | |
2868 err = GetFlavorDataSize(theDrag, item, type, &size); | |
2869 if (err != noErr || size > sizeof(hfsFlavor)) | |
2870 continue; | |
2871 err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0); | |
2872 if (err != noErr) | |
2873 continue; | |
2874 fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec); | |
2875 } | |
2876 count = j; | |
2877 | |
2878 gui_handle_drop(x, y, modifiers, fnames, count); | |
2879 return noErr; | |
2880 } | |
2881 | |
2882 /* | |
2883 * Initialise the GUI. Create all the windows, set up all the call-backs | |
2884 * etc. | |
2885 */ | |
2886 int | |
2887 gui_mch_init() | |
2888 { | |
2889 /* TODO: Move most of this stuff toward gui_mch_init */ | |
2890 Rect windRect; | |
2891 MenuHandle pomme; | |
2892 #ifdef USE_CTRLCLICKMENU | |
2893 long gestalt_rc; | |
2894 #endif | |
2895 #ifdef USE_MOUSEWHEEL | |
2896 EventTypeSpec eventTypeSpec; | |
2897 EventHandlerRef mouseWheelHandlerRef; | |
2898 #endif | |
2899 #if 1 | |
2900 InitCursor(); | |
2901 | |
2902 #ifdef USE_CARBONIZED | |
2903 RegisterAppearanceClient(); | |
2904 #endif | |
2905 | |
2906 #ifdef USE_AEVENT | |
2907 (void) InstallAEHandlers(); | |
2908 #endif | |
2909 | |
2910 #ifdef USE_CTRLCLICKMENU | |
2911 if (Gestalt(gestaltContextualMenuAttr, &gestalt_rc) == noErr) | |
2912 gui.MacOSHaveCntxMenu = BitTst(&gestalt_rc, 31-gestaltContextualMenuTrapAvailable); | |
2913 else | |
2914 gui.MacOSHaveCntxMenu = false; | |
2915 | |
2916 if (gui.MacOSHaveCntxMenu) | |
2917 gui.MacOSHaveCntxMenu = (InitContextualMenus()==noErr); | |
2918 #endif | |
2919 | |
2920 #ifdef USE_SIOUX | |
2921 SIOUXSettings.standalone = false; | |
2922 SIOUXSettings.initializeTB = false; | |
2923 SIOUXSettings.setupmenus = false; | |
2924 SIOUXSettings.asktosaveonclose = false; | |
2925 SIOUXSettings.showstatusline = true; | |
2926 SIOUXSettings.toppixel = 300; | |
2927 SIOUXSettings.leftpixel = 10; | |
2928 InstallConsole (1); /* fileno(stdout) = 1, on page 430 of MSL C */ | |
2929 printf ("Debugging console enabled\n"); | |
2930 /* SIOUXSetTitle ((char_u *) "Vim Stdout"); */ | |
2931 #endif | |
2932 | |
2933 pomme = NewMenu (256, "\p\024"); /* 0x14= = Apple Menu */ | |
2934 | |
2935 AppendMenu (pomme, "\pAbout VIM"); | |
2936 #ifndef USE_CARBONIZED | |
2937 AppendMenu (pomme, "\p-"); | |
2938 AppendResMenu (pomme, 'DRVR'); | |
2939 #endif | |
2940 | |
2941 InsertMenu (pomme, 0); | |
2942 | |
2943 DrawMenuBar(); | |
2944 | |
2945 | |
2946 #ifndef USE_OFFSETED_WINDOW | |
2947 SetRect (&windRect, 10, 48, 10+80*7 + 16, 48+24*11); | |
2948 #else | |
2949 SetRect (&windRect, 300, 40, 300+80*7 + 16, 40+24*11); | |
2950 #endif | |
2951 | |
2952 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, | |
2953 #ifdef USE_CARBONIZED | |
2954 zoomDocProc, | |
2955 #else | |
2956 documentProc, | |
2957 #endif | |
2958 (WindowPtr)-1L, true, 0); | |
2959 InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler, | |
2960 gui.VimWindow, NULL); | |
2961 #ifdef USE_CARBONIZED | |
2962 SetPortWindowPort ( gui.VimWindow ); | |
2963 #else | |
2964 SetPort(gui.VimWindow); | |
2965 #endif | |
2966 | |
2967 gui.char_width = 7; | |
2968 gui.char_height = 11; | |
2969 gui.char_ascent = 6; | |
2970 gui.num_rows = 24; | |
2971 gui.num_cols = 80; | |
2972 gui.in_focus = TRUE; /* For the moment -> syn. of front application */ | |
2973 | |
2974 #if TARGET_API_MAC_CARBON | |
2975 gScrollAction = NewControlActionUPP (gui_mac_scroll_action); | |
2976 gScrollDrag = NewControlActionUPP (gui_mac_drag_thumb); | |
2977 #else | |
2978 gScrollAction = NewControlActionProc (gui_mac_scroll_action); | |
2979 gScrollDrag = NewControlActionProc (gui_mac_drag_thumb); | |
2980 #endif | |
2981 | |
2982 /* Getting a handle to the Help menu */ | |
2983 #ifdef USE_HELPMENU | |
2984 # ifdef USE_CARBONIZED | |
2985 HMGetHelpMenu(&gui.MacOSHelpMenu, NULL); | |
2986 # else | |
2987 (void) HMGetHelpMenuHandle(&gui.MacOSHelpMenu); | |
2988 # endif | |
2989 | |
2990 if (gui.MacOSHelpMenu != nil) | |
2991 gui.MacOSHelpItems = CountMenuItems (gui.MacOSHelpMenu); | |
2992 else | |
2993 gui.MacOSHelpItems = 0; | |
2994 #endif | |
2995 | |
2996 dragRectEnbl = FALSE; | |
2997 dragRgn = NULL; | |
2998 dragRectControl = kCreateEmpty; | |
2999 cursorRgn = NewRgn(); | |
3000 #endif | |
3001 /* Display any pending error messages */ | |
3002 display_errors(); | |
3003 | |
3004 /* Get background/foreground colors from system */ | |
3005 /* TODO: do the approriate call to get real defaults */ | |
3006 gui.norm_pixel = 0x00000000; | |
3007 gui.back_pixel = 0x00FFFFFF; | |
3008 | |
3009 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc | |
3010 * file). */ | |
3011 set_normal_colors(); | |
3012 | |
3013 /* | |
3014 * Check that none of the colors are the same as the background color. | |
3015 * Then store the current values as the defaults. | |
3016 */ | |
3017 gui_check_colors(); | |
3018 gui.def_norm_pixel = gui.norm_pixel; | |
3019 gui.def_back_pixel = gui.back_pixel; | |
3020 | |
3021 /* Get the colors for the highlight groups (gui_check_colors() might have | |
3022 * changed them) */ | |
3023 highlight_gui_started(); | |
3024 | |
3025 /* | |
3026 * Setting the gui constants | |
3027 */ | |
3028 #ifdef FEAT_MENU | |
3029 gui.menu_height = 0; | |
3030 #endif | |
3031 gui.scrollbar_height = gui.scrollbar_width = 15; /* cheat 1 overlap */ | |
3032 gui.border_offset = gui.border_width = 2; | |
3033 | |
3034 #if defined(FEAT_GUI) && defined(MACOS_X) | |
3035 /* If Quartz-style text antialiasing is available (see | |
3036 gui_mch_draw_string() below), enable it for all font sizes. */ | |
3037 vim_setenv((char_u *)"QDTEXT_MINSIZE", (char_u *)"1"); | |
3038 #endif | |
3039 | |
3040 #ifdef USE_MOUSEWHEEL | |
3041 eventTypeSpec.eventClass = kEventClassMouse; | |
3042 eventTypeSpec.eventKind = kEventMouseWheelMoved; | |
3043 mouseWheelHandlerUPP = NewEventHandlerUPP(gui_mac_mouse_wheel); | |
3044 if (noErr != InstallApplicationEventHandler(mouseWheelHandlerUPP, 1, | |
3045 &eventTypeSpec, NULL, &mouseWheelHandlerRef)) | |
3046 { | |
3047 mouseWheelHandlerRef = NULL; | |
3048 DisposeEventHandlerUPP(mouseWheelHandlerUPP); | |
3049 mouseWheelHandlerUPP = NULL; | |
3050 } | |
3051 #endif | |
3052 | |
3053 #ifdef FEAT_MBYTE | |
3054 set_option_value((char_u *)"termencoding", 0L, (char_u *)"macroman", 0); | |
3055 #endif | |
3056 | |
3057 /* TODO: Load bitmap if using TOOLBAR */ | |
3058 return OK; | |
3059 } | |
3060 | |
3061 /* | |
3062 * Called when the foreground or background color has been changed. | |
3063 */ | |
3064 void | |
3065 gui_mch_new_colors() | |
3066 { | |
3067 /* TODO: | |
3068 * This proc is called when Normal is set to a value | |
3069 * so what msut be done? I don't know | |
3070 */ | |
3071 } | |
3072 | |
3073 /* | |
3074 * Open the GUI window which was created by a call to gui_mch_init(). | |
3075 */ | |
3076 int | |
3077 gui_mch_open() | |
3078 { | |
3079 ShowWindow(gui.VimWindow); | |
3080 | |
3081 if (gui_win_x != -1 && gui_win_y != -1) | |
3082 gui_mch_set_winpos(gui_win_x, gui_win_y); | |
3083 | |
3084 #ifdef USE_CARBONIZED | |
3085 /* | |
3086 * Make the GUI the foreground process (in case it was launched | |
3087 * from the Terminal or via :gui). | |
3088 */ | |
3089 { | |
3090 ProcessSerialNumber psn; | |
3091 if (GetCurrentProcess(&psn) == noErr) | |
3092 SetFrontProcess(&psn); | |
3093 } | |
3094 #endif | |
3095 | |
3096 return OK; | |
3097 } | |
3098 | |
3099 void | |
3100 gui_mch_exit(int rc) | |
3101 { | |
3102 /* TODO: find out all what is missing here? */ | |
3103 DisposeRgn(cursorRgn); | |
3104 | |
3105 #ifdef USE_MOUSEWHEEL | |
3106 if (mouseWheelHandlerUPP != NULL) | |
3107 DisposeEventHandlerUPP(mouseWheelHandlerUPP); | |
3108 #endif | |
3109 | |
3110 /* Exit to shell? */ | |
3111 exit(rc); | |
3112 } | |
3113 | |
3114 /* | |
3115 * Get the position of the top left corner of the window. | |
3116 */ | |
3117 int | |
3118 gui_mch_get_winpos(int *x, int *y) | |
3119 { | |
3120 /* TODO */ | |
3121 #ifdef USE_CARBONIZED | |
3122 Rect bounds; | |
3123 OSStatus status; | |
3124 | |
3125 /* Carbon >= 1.0.2, MacOS >= 8.5 */ | |
3126 status = GetWindowBounds (gui.VimWindow, kWindowStructureRgn, &bounds); | |
3127 | |
3128 if (status != noErr) | |
3129 return FAIL; | |
3130 *x = bounds.left; | |
3131 *y = bounds.top; | |
3132 return OK; | |
3133 #endif | |
3134 return FAIL; | |
3135 } | |
3136 | |
3137 /* | |
3138 * Set the position of the top left corner of the window to the given | |
3139 * coordinates. | |
3140 */ | |
3141 void | |
3142 gui_mch_set_winpos(int x, int y) | |
3143 { | |
3144 /* TODO: Should make sure the window is move within range | |
3145 * e.g.: y > ~16 [Menu bar], x > 0, x < screen width | |
3146 */ | |
3147 MoveWindow(gui.VimWindow, x, y, TRUE); | |
3148 } | |
3149 | |
3150 void | |
3151 gui_mch_set_shellsize( | |
3152 int width, | |
3153 int height, | |
3154 int min_width, | |
3155 int min_height, | |
3156 int base_width, | |
3157 int base_height) | |
3158 { | |
3159 #ifdef USE_CARBONIZED | |
3160 CGrafPtr VimPort; | |
3161 Rect VimBound; | |
3162 #endif | |
3163 | |
3164 if (gui.which_scrollbars[SBAR_LEFT]) | |
3165 { | |
3166 #ifdef USE_CARBONIZED | |
3167 VimPort = GetWindowPort ( gui.VimWindow ); | |
3168 GetPortBounds (VimPort, &VimBound); | |
3169 VimBound.left = -gui.scrollbar_width; /* + 1;*/ | |
3170 SetPortBounds (VimPort, &VimBound); | |
3171 /* GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/ | |
3172 #else | |
3173 gui.VimWindow->portRect.left = -gui.scrollbar_width; /* + 1;*/ | |
3174 /* SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &winPortRect); ??*/ | |
3175 #endif | |
3176 } | |
3177 else | |
3178 { | |
3179 #ifdef USE_CARBONIZED | |
3180 VimPort = GetWindowPort ( gui.VimWindow ); | |
3181 GetPortBounds (VimPort, &VimBound); | |
3182 VimBound.left = 0; | |
3183 SetPortBounds (VimPort, &VimBound); | |
3184 #else | |
3185 gui.VimWindow->portRect.left = 0; | |
3186 #endif; | |
3187 } | |
3188 | |
3189 SizeWindow(gui.VimWindow, width, height, TRUE); | |
3190 | |
3191 gui_resize_shell(width, height); | |
3192 } | |
3193 | |
3194 /* | |
3195 * Get the screen dimensions. | |
3196 * Allow 10 pixels for horizontal borders, 40 for vertical borders. | |
3197 * Is there no way to find out how wide the borders really are? | |
3198 * TODO: Add live udate of those value on suspend/resume. | |
3199 */ | |
3200 void | |
3201 gui_mch_get_screen_dimensions(screen_w, screen_h) | |
3202 int *screen_w; | |
3203 int *screen_h; | |
3204 { | |
3205 GDHandle dominantDevice = GetMainDevice(); | |
3206 Rect screenRect = (**dominantDevice).gdRect; | |
3207 | |
3208 *screen_w = screenRect.right - 10; | |
3209 *screen_h = screenRect.bottom - 40; | |
3210 } | |
3211 | |
3212 | |
3213 | |
3214 /* | |
3215 * Initialise vim to use the font with the given name. Return FAIL if the font | |
3216 * could not be loaded, OK otherwise. | |
3217 */ | |
3218 int | |
3219 gui_mch_init_font(font_name, fontset) | |
3220 char_u *font_name; | |
3221 int fontset; /* not used */ | |
3222 { | |
3223 /* TODO: Add support for bold italic underline proportional etc... */ | |
3224 Str255 suggestedFont = "\pMonaco"; | |
3225 int suggestedSize = 9; | |
3226 FontInfo font_info; | |
3227 short font_id; | |
3228 GuiFont font; | |
3229 | |
3230 if (font_name == NULL) | |
3231 { | |
3232 /* First try to get the suggested font */ | |
3233 GetFNum(suggestedFont, &font_id); | |
3234 | |
3235 if (font_id == 0) | |
3236 { | |
3237 /* Then pickup the standard application font */ | |
3238 font_id = GetAppFont(); | |
3239 } | |
3240 font = (suggestedSize << 16) + ((long) font_id & 0xFFFF); | |
3241 } | |
3242 else | |
3243 { | |
3244 font = gui_mac_find_font (font_name); | |
3245 | |
3246 if (font == NOFONT) | |
3247 return FAIL; | |
3248 } | |
3249 gui.norm_font = font; | |
3250 | |
3251 TextSize (font >> 16); | |
3252 TextFont (font & 0xFFFF); | |
3253 | |
3254 GetFontInfo (&font_info); | |
3255 | |
3256 gui.char_ascent = font_info.ascent; | |
3257 gui.char_width = CharWidth ('_'); | |
3258 gui.char_height = font_info.ascent + font_info.descent + p_linespace; | |
3259 | |
3260 return OK; | |
3261 | |
3262 } | |
3263 | |
3264 int | |
3265 gui_mch_adjust_charsize() | |
3266 { | |
3267 FontInfo font_info; | |
3268 | |
3269 GetFontInfo (&font_info); | |
3270 gui.char_height = font_info.ascent + font_info.descent + p_linespace; | |
3271 gui.char_ascent = font_info.ascent + p_linespace / 2; | |
3272 return OK; | |
3273 } | |
3274 | |
3275 /* | |
3276 * Get a font structure for highlighting. | |
3277 */ | |
3278 GuiFont | |
3279 gui_mch_get_font(name, giveErrorIfMissing) | |
3280 char_u *name; | |
3281 int giveErrorIfMissing; | |
3282 { | |
3283 GuiFont font; | |
3284 | |
3285 font = gui_mac_find_font(name); | |
3286 | |
3287 if (font == NOFONT) | |
3288 { | |
3289 if (giveErrorIfMissing) | |
3290 EMSG2(_(e_font), name); | |
3291 return NOFONT; | |
3292 } | |
3293 /* | |
3294 * TODO : Accept only monospace | |
3295 */ | |
3296 | |
3297 return font; | |
3298 } | |
3299 | |
3300 /* | |
3301 * Set the current text font. | |
3302 */ | |
3303 void | |
3304 gui_mch_set_font(font) | |
3305 GuiFont font; | |
3306 { | |
3307 /* | |
3308 * TODO: maybe avoid set again the current font. | |
3309 */ | |
3310 TextSize(font >> 16); | |
3311 TextFont(font & 0xFFFF); | |
3312 } | |
3313 | |
3314 #if 0 /* not used */ | |
3315 /* | |
3316 * Return TRUE if the two fonts given are equivalent. | |
3317 */ | |
3318 int | |
3319 gui_mch_same_font(f1, f2) | |
3320 GuiFont f1; | |
3321 GuiFont f2; | |
3322 { | |
3323 return f1 == f2; | |
3324 } | |
3325 #endif | |
3326 | |
3327 /* | |
3328 * If a font is not going to be used, free its structure. | |
3329 */ | |
3330 void | |
3331 gui_mch_free_font(font) | |
3332 GuiFont font; | |
3333 { | |
3334 /* | |
3335 * Free font when "font" is not 0. | |
3336 * Nothing to do in the current implementation, since | |
3337 * nothing is allocated for each font used. | |
3338 */ | |
3339 } | |
3340 | |
3341 static int | |
3342 hex_digit(c) | |
3343 int c; | |
3344 { | |
3345 if (isdigit(c)) | |
3346 return c - '0'; | |
3347 c = TOLOWER_ASC(c); | |
3348 if (c >= 'a' && c <= 'f') | |
3349 return c - 'a' + 10; | |
3350 return -1000; | |
3351 } | |
3352 | |
3353 /* | |
3354 * Return the Pixel value (color) for the given color name. This routine was | |
3355 * pretty much taken from example code in the Silicon Graphics OSF/Motif | |
3356 * Programmer's Guide. | |
3357 * Return INVALCOLOR when failed. | |
3358 */ | |
3359 guicolor_T | |
3360 gui_mch_get_color(name) | |
3361 char_u *name; | |
3362 { | |
3363 /* TODO: Add support for the new named color of MacOS 8 | |
3364 */ | |
3365 RGBColor MacColor; | |
3366 // guicolor_T color = 0; | |
3367 | |
3368 typedef struct guicolor_tTable | |
3369 { | |
3370 char *name; | |
3371 guicolor_T color; | |
3372 } guicolor_tTable; | |
3373 | |
3374 /* | |
3375 * The comment at the end of each line is the source | |
3376 * (Mac, Window, Unix) and the number is the unix rgb.txt value | |
3377 */ | |
3378 static guicolor_tTable table[] = | |
3379 { | |
3380 {"Black", RGB(0x00, 0x00, 0x00)}, | |
3381 {"darkgray", RGB(0x80, 0x80, 0x80)}, /*W*/ | |
3382 {"darkgrey", RGB(0x80, 0x80, 0x80)}, /*W*/ | |
3383 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, /*W*/ | |
3384 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, /*W*/ | |
3385 {"lightgray", RGB(0xE0, 0xE0, 0xE0)}, /*W*/ | |
3386 {"lightgrey", RGB(0xE0, 0xE0, 0xE0)}, /*W*/ | |
3387 {"white", RGB(0xFF, 0xFF, 0xFF)}, | |
3388 {"darkred", RGB(0x80, 0x00, 0x00)}, /*W*/ | |
3389 {"red", RGB(0xDD, 0x08, 0x06)}, /*M*/ | |
3390 {"lightred", RGB(0xFF, 0xA0, 0xA0)}, /*W*/ | |
3391 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, /*W*/ | |
3392 {"Blue", RGB(0x00, 0x00, 0xD4)}, /*M*/ | |
3393 {"lightblue", RGB(0xA0, 0xA0, 0xFF)}, /*W*/ | |
3394 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, /*W*/ | |
3395 {"Green", RGB(0x00, 0x64, 0x11)}, /*M*/ | |
3396 {"lightgreen", RGB(0xA0, 0xFF, 0xA0)}, /*W*/ | |
3397 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, /*W ?0x307D7E */ | |
3398 {"cyan", RGB(0x02, 0xAB, 0xEA)}, /*M*/ | |
3399 {"lightcyan", RGB(0xA0, 0xFF, 0xFF)}, /*W*/ | |
3400 {"darkmagenta", RGB(0x80, 0x00, 0x80)}, /*W*/ | |
3401 {"magenta", RGB(0xF2, 0x08, 0x84)}, /*M*/ | |
3402 {"lightmagenta",RGB(0xF0, 0xA0, 0xF0)}, /*W*/ | |
3403 {"brown", RGB(0x80, 0x40, 0x40)}, /*W*/ | |
3404 {"yellow", RGB(0xFC, 0xF3, 0x05)}, /*M*/ | |
3405 {"lightyellow", RGB(0xFF, 0xFF, 0xA0)}, /*M*/ | |
3406 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, /*W 0x4E8975 */ | |
3407 {"orange", RGB(0xFC, 0x80, 0x00)}, /*W 0xF87A17 */ | |
3408 {"Purple", RGB(0xA0, 0x20, 0xF0)}, /*W 0x8e35e5 */ | |
3409 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, /*W 0x737CA1 */ | |
3410 {"Violet", RGB(0x8D, 0x38, 0xC9)}, /*U*/ | |
3411 }; | |
3412 | |
3413 int r, g, b; | |
3414 int i; | |
3415 | |
3416 if (name[0] == '#' && strlen((char *) name) == 7) | |
3417 { | |
3418 /* Name is in "#rrggbb" format */ | |
3419 r = hex_digit(name[1]) * 16 + hex_digit(name[2]); | |
3420 g = hex_digit(name[3]) * 16 + hex_digit(name[4]); | |
3421 b = hex_digit(name[5]) * 16 + hex_digit(name[6]); | |
3422 if (r < 0 || g < 0 || b < 0) | |
3423 return INVALCOLOR; | |
3424 return RGB(r, g, b); | |
3425 } | |
3426 else | |
3427 { | |
3428 if (STRICMP (name, "hilite") == 0) | |
3429 { | |
3430 LMGetHiliteRGB (&MacColor); | |
3431 return (RGB (MacColor.red >> 8, MacColor.green >> 8, MacColor.blue >> 8)); | |
3432 } | |
3433 /* Check if the name is one of the colors we know */ | |
3434 for (i = 0; i < sizeof(table) / sizeof(table[0]); i++) | |
3435 if (STRICMP(name, table[i].name) == 0) | |
3436 return table[i].color; | |
3437 } | |
3438 | |
3439 | |
3440 /* | |
3441 * Last attempt. Look in the file "$VIM/rgb.txt". | |
3442 */ | |
3443 { | |
3444 #define LINE_LEN 100 | |
3445 FILE *fd; | |
3446 char line[LINE_LEN]; | |
3447 char_u *fname; | |
3448 | |
3449 #ifdef COLON_AS_PATHSEP | |
3450 fname = expand_env_save((char_u *)"$VIMRUNTIME:rgb.txt"); | |
3451 #else | |
3452 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); | |
3453 #endif | |
3454 if (fname == NULL) | |
3455 return INVALCOLOR; | |
3456 | |
3457 fd = fopen((char *)fname, "rt"); | |
3458 vim_free(fname); | |
3459 if (fd == NULL) | |
3460 return INVALCOLOR; | |
3461 | |
3462 while (!feof(fd)) | |
3463 { | |
3464 int len; | |
3465 int pos; | |
3466 char *color; | |
3467 | |
3468 fgets(line, LINE_LEN, fd); | |
3469 len = strlen(line); | |
3470 | |
3471 if (len <= 1 || line[len-1] != '\n') | |
3472 continue; | |
3473 | |
3474 line[len-1] = '\0'; | |
3475 | |
3476 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); | |
3477 if (i != 3) | |
3478 continue; | |
3479 | |
3480 color = line + pos; | |
3481 | |
3482 if (STRICMP(color, name) == 0) | |
3483 { | |
3484 fclose(fd); | |
3485 return (guicolor_T) RGB(r, g, b); | |
3486 } | |
3487 } | |
3488 fclose(fd); | |
3489 } | |
3490 | |
3491 return INVALCOLOR; | |
3492 } | |
3493 | |
3494 /* | |
3495 * Set the current text foreground color. | |
3496 */ | |
3497 void | |
3498 gui_mch_set_fg_color(color) | |
3499 guicolor_T color; | |
3500 { | |
3501 RGBColor TheColor; | |
3502 | |
3503 TheColor.red = Red(color) * 0x0101; | |
3504 TheColor.green = Green(color) * 0x0101; | |
3505 TheColor.blue = Blue(color) * 0x0101; | |
3506 | |
3507 RGBForeColor (&TheColor); | |
3508 } | |
3509 | |
3510 /* | |
3511 * Set the current text background color. | |
3512 */ | |
3513 void | |
3514 gui_mch_set_bg_color(color) | |
3515 guicolor_T color; | |
3516 { | |
3517 RGBColor TheColor; | |
3518 | |
3519 TheColor.red = Red(color) * 0x0101; | |
3520 TheColor.green = Green(color) * 0x0101; | |
3521 TheColor.blue = Blue(color) * 0x0101; | |
3522 | |
3523 RGBBackColor (&TheColor); | |
3524 } | |
3525 | |
3526 void | |
3527 gui_mch_draw_string(row, col, s, len, flags) | |
3528 int row; | |
3529 int col; | |
3530 char_u *s; | |
3531 int len; | |
3532 int flags; | |
3533 { | |
3534 #if defined(FEAT_GUI) && defined(MACOS_X) | |
3535 SInt32 sys_version; | |
3536 #endif | |
3537 #ifdef FEAT_MBYTE | |
3538 char_u *tofree = NULL; | |
3539 | |
3540 if (output_conv.vc_type != CONV_NONE) | |
3541 { | |
3542 tofree = string_convert(&output_conv, s, &len); | |
3543 if (tofree != NULL) | |
3544 s = tofree; | |
3545 } | |
3546 #endif | |
3547 | |
3548 #if defined(FEAT_GUI) && defined(MACOS_X) | |
3549 /* | |
3550 * On OS X, try using Quartz-style text antialiasing. | |
3551 */ | |
3552 sys_version = 0; | |
3553 | |
3554 Gestalt(gestaltSystemVersion, &sys_version); | |
3555 if (sys_version >= 0x1020) | |
3556 { | |
3557 /* Quartz antialiasing is available only in OS 10.2 and later. */ | |
3558 UInt32 qd_flags = (p_antialias ? | |
3559 kQDUseCGTextRendering | kQDUseCGTextMetrics : 0); | |
3560 (void)SwapQDTextFlags(qd_flags); | |
3561 } | |
3562 | |
3563 if (sys_version >= 0x1020 && p_antialias) | |
3564 { | |
3565 StyleParameter face; | |
3566 | |
3567 face = normal; | |
3568 if (flags & DRAW_BOLD) | |
3569 face |= bold; | |
3570 if (flags & DRAW_UNDERL) | |
3571 face |= underline; | |
3572 TextFace(face); | |
3573 | |
3574 /* Quartz antialiasing works only in srcOr transfer mode. */ | |
3575 TextMode(srcOr); | |
3576 | |
3577 if (!(flags & DRAW_TRANSP)) | |
3578 { | |
3579 /* | |
3580 * Since we're using srcOr mode, we have to clear the block | |
3581 * before drawing the text. The following is like calling | |
3582 * gui_mch_clear_block(row, col, row, col + len - 1), | |
3583 * but without setting the bg color to gui.back_pixel. | |
3584 */ | |
3585 Rect rc; | |
3586 rc.left = FILL_X(col); | |
3587 rc.top = FILL_Y(row); | |
3588 rc.right = FILL_X(col + len) + (col + len == Columns); | |
3589 rc.bottom = FILL_Y(row + 1); | |
3590 EraseRect(&rc); | |
3591 } | |
3592 | |
3593 MoveTo(TEXT_X(col), TEXT_Y(row)); | |
3594 DrawText((char*)s, 0, len); | |
3595 } | |
3596 else | |
3597 #endif | |
3598 { | |
3599 /* Use old-style, non-antialiased QuickDraw text rendering. */ | |
3600 TextMode (srcCopy); | |
3601 TextFace (normal); | |
3602 | |
3603 /* SelectFont(hdc, gui.currFont); */ | |
3604 | |
3605 if (flags & DRAW_TRANSP) | |
3606 { | |
3607 TextMode (srcOr); | |
3608 } | |
3609 | |
3610 MoveTo (TEXT_X(col), TEXT_Y(row)); | |
3611 DrawText ((char *)s, 0, len); | |
3612 | |
3613 | |
3614 if (flags & DRAW_BOLD) | |
3615 { | |
3616 TextMode (srcOr); | |
3617 MoveTo (TEXT_X(col) + 1, TEXT_Y(row)); | |
3618 DrawText ((char *)s, 0, len); | |
3619 } | |
3620 | |
3621 if (flags & DRAW_UNDERL) | |
3622 { | |
3623 MoveTo (FILL_X(col), FILL_Y(row + 1) - 1); | |
3624 LineTo (FILL_X(col + len) - 1, FILL_Y(row + 1) - 1); | |
3625 } | |
3626 } | |
3627 | |
3628 #ifdef FEAT_MBYTE | |
3629 vim_free(tofree); | |
3630 #endif | |
3631 } | |
3632 | |
3633 /* | |
3634 * Return OK if the key with the termcap name "name" is supported. | |
3635 */ | |
3636 int | |
3637 gui_mch_haskey(name) | |
3638 char_u *name; | |
3639 { | |
3640 int i; | |
3641 | |
3642 for (i = 0; special_keys[i].key_sym != (KeySym)0; i++) | |
3643 if (name[0] == special_keys[i].vim_code0 && | |
3644 name[1] == special_keys[i].vim_code1) | |
3645 return OK; | |
3646 return FAIL; | |
3647 } | |
3648 | |
3649 void | |
3650 gui_mch_beep() | |
3651 { | |
3652 SysBeep (1); /* Should this be 0? (????) */ | |
3653 } | |
3654 | |
3655 void | |
3656 gui_mch_flash(msec) | |
3657 int msec; | |
3658 { | |
3659 /* Do a visual beep by reversing the foreground and background colors */ | |
3660 Rect rc; | |
3661 | |
3662 /* | |
3663 * Note: InvertRect() excludes right and bottom of rectangle. | |
3664 */ | |
3665 rc.left = 0; | |
3666 rc.top = 0; | |
3667 rc.right = gui.num_cols * gui.char_width; | |
3668 rc.bottom = gui.num_rows * gui.char_height; | |
3669 InvertRect(&rc); | |
3670 | |
3671 ui_delay((long)msec, TRUE); /* wait for some msec */ | |
3672 | |
3673 InvertRect(&rc); | |
3674 } | |
3675 | |
3676 /* | |
3677 * Invert a rectangle from row r, column c, for nr rows and nc columns. | |
3678 */ | |
3679 void | |
3680 gui_mch_invert_rectangle(r, c, nr, nc) | |
3681 int r; | |
3682 int c; | |
3683 int nr; | |
3684 int nc; | |
3685 { | |
3686 Rect rc; | |
3687 | |
3688 /* | |
3689 * Note: InvertRect() excludes right and bottom of rectangle. | |
3690 */ | |
3691 rc.left = FILL_X(c); | |
3692 rc.top = FILL_Y(r); | |
3693 rc.right = rc.left + nc * gui.char_width; | |
3694 rc.bottom = rc.top + nr * gui.char_height; | |
3695 InvertRect(&rc); | |
3696 | |
3697 } | |
3698 | |
3699 /* | |
3700 * Iconify the GUI window. | |
3701 */ | |
3702 void | |
3703 gui_mch_iconify() | |
3704 { | |
3705 /* TODO: find out what could replace iconify | |
3706 * -window shade? | |
3707 * -hide application? | |
3708 */ | |
3709 } | |
3710 | |
3711 #if defined(FEAT_EVAL) || defined(PROTO) | |
3712 /* | |
3713 * Bring the Vim window to the foreground. | |
3714 */ | |
3715 void | |
3716 gui_mch_set_foreground() | |
3717 { | |
3718 /* TODO */ | |
3719 } | |
3720 #endif | |
3721 | |
3722 /* | |
3723 * Draw a cursor without focus. | |
3724 */ | |
3725 void | |
3726 gui_mch_draw_hollow_cursor(color) | |
3727 guicolor_T color; | |
3728 { | |
3729 Rect rc; | |
3730 | |
3731 gui_mch_set_fg_color(color); | |
3732 | |
3733 /* | |
3734 * Note: FrameRect() excludes right and bottom of rectangle. | |
3735 */ | |
3736 rc.left = FILL_X(gui.col); | |
3737 rc.top = FILL_Y(gui.row); | |
3738 rc.right = rc.left + gui.char_width; | |
3739 rc.bottom = rc.top + gui.char_height; | |
3740 | |
3741 gui_mch_set_fg_color(color); | |
3742 | |
3743 FrameRect (&rc); | |
3744 } | |
3745 | |
3746 /* | |
3747 * Draw part of a cursor, only w pixels wide, and h pixels high. | |
3748 */ | |
3749 void | |
3750 gui_mch_draw_part_cursor(w, h, color) | |
3751 int w; | |
3752 int h; | |
3753 guicolor_T color; | |
3754 { | |
3755 Rect rc; | |
3756 | |
3757 #ifdef FEAT_RIGHTLEFT | |
3758 /* vertical line should be on the right of current point */ | |
3759 if (CURSOR_BAR_RIGHT) | |
3760 rc.left = FILL_X(gui.col + 1) - w; | |
3761 else | |
3762 #endif | |
3763 rc.left = FILL_X(gui.col); | |
3764 rc.top = FILL_Y(gui.row) + gui.char_height - h; | |
3765 rc.right = rc.left + w; | |
3766 rc.bottom = rc.top + h; | |
3767 | |
3768 gui_mch_set_fg_color(color); | |
3769 | |
3770 PaintRect (&rc); | |
3771 } | |
3772 | |
3773 | |
3774 | |
3775 /* | |
3776 * Catch up with any queued X events. This may put keyboard input into the | |
3777 * input buffer, call resize call-backs, trigger timers etc. If there is | |
3778 * nothing in the X event queue (& no timers pending), then we return | |
3779 * immediately. | |
3780 */ | |
3781 void | |
3782 gui_mch_update() | |
3783 { | |
3784 /* TODO: find what to do | |
3785 * maybe call gui_mch_wait_for_chars (0) | |
3786 * more like look at EventQueue then | |
3787 * call heart of gui_mch_wait_for_chars; | |
3788 * | |
3789 * if (eventther) | |
3790 * gui_mac_handle_event(&event); | |
3791 */ | |
3792 EventRecord theEvent; | |
3793 | |
3794 if (EventAvail (everyEvent, &theEvent)) | |
3795 if (theEvent.what != nullEvent) | |
3796 gui_mch_wait_for_chars(0); | |
3797 } | |
3798 | |
3799 /* | |
3800 * Simple wrapper to neglect more easily the time | |
3801 * spent inside WaitNextEvent while profiling. | |
3802 */ | |
3803 | |
3804 #if defined(__MWERKS__) /* only in Codewarrior */ | |
3805 # pragma profile reset | |
3806 #endif | |
3807 pascal | |
3808 Boolean | |
3809 WaitNextEventWrp (EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn) | |
3810 { | |
3811 if (((long) sleep) < -1) | |
3812 sleep = 32767; | |
3813 return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn); | |
3814 } | |
3815 | |
3816 /* | |
3817 * GUI input routine called by gui_wait_for_chars(). Waits for a character | |
3818 * from the keyboard. | |
3819 * wtime == -1 Wait forever. | |
3820 * wtime == 0 This should never happen. | |
3821 * wtime > 0 Wait wtime milliseconds for a character. | |
3822 * Returns OK if a character was found to be available within the given time, | |
3823 * or FAIL otherwise. | |
3824 */ | |
3825 #if defined(__MWERKS__) /* only in Codewarrior */ | |
3826 # pragma profile reset | |
3827 #endif | |
3828 int | |
3829 gui_mch_wait_for_chars(wtime) | |
3830 int wtime; | |
3831 { | |
3832 EventMask mask = (everyEvent); | |
3833 EventRecord event; | |
3834 long entryTick; | |
3835 long currentTick; | |
3836 long sleeppyTick; | |
3837 | |
3838 /* If we are providing life feedback with the scrollbar, | |
3839 * we don't want to try to wait for an event, or else | |
3840 * there won't be any life feedback. | |
3841 */ | |
3842 if (dragged_sb != NULL) | |
3843 return FAIL; | |
3844 /* TODO: Check if FAIL is the proper return code */ | |
3845 | |
3846 entryTick = TickCount(); | |
3847 | |
3848 allow_scrollbar = TRUE; | |
3849 | |
3850 do | |
3851 { | |
3852 /* if (dragRectControl == kCreateEmpty) | |
3853 { | |
3854 dragRgn = NULL; | |
3855 dragRectControl = kNothing; | |
3856 } | |
3857 else*/ if (dragRectControl == kCreateRect) | |
3858 { | |
3859 dragRgn = cursorRgn; | |
3860 RectRgn (dragRgn, &dragRect); | |
3861 dragRectControl = kNothing; | |
3862 } | |
3863 /* | |
3864 * Don't use gui_mch_update() because then we will spin-lock until a | |
3865 * char arrives, instead we use WaitNextEventWrp() to hang until an | |
3866 * event arrives. No need to check for input_buf_full because we are | |
3867 * returning as soon as it contains a single char. | |
3868 */ | |
3869 /* TODO: reduce wtime accordinly??? */ | |
3870 if (wtime > -1) | |
3871 sleeppyTick = 60*wtime/1000; | |
3872 else | |
3873 sleeppyTick = 32767; | |
3874 if (WaitNextEventWrp (mask, &event, sleeppyTick, dragRgn)) | |
3875 { | |
3876 #ifdef USE_SIOUX | |
3877 if (!SIOUXHandleOneEvent(&event)) | |
3878 #endif | |
3879 gui_mac_handle_event (&event); | |
3880 if (input_available()) | |
3881 { | |
3882 allow_scrollbar = FALSE; | |
3883 return OK; | |
3884 } | |
3885 } | |
3886 currentTick = TickCount(); | |
3887 } | |
3888 while ((wtime == -1) || ((currentTick - entryTick) < 60*wtime/1000)); | |
3889 | |
3890 allow_scrollbar = FALSE; | |
3891 return FAIL; | |
3892 } | |
3893 | |
3894 #if defined(__MWERKS__) /* only in Codewarrior */ | |
3895 # pragma profile reset | |
3896 #endif | |
3897 | |
3898 /* | |
3899 * Output routines. | |
3900 */ | |
3901 | |
3902 /* Flush any output to the screen */ | |
3903 void | |
3904 gui_mch_flush() | |
3905 { | |
3906 /* TODO: Is anything needed here? */ | |
3907 } | |
3908 | |
3909 /* | |
3910 * Clear a rectangular region of the screen from text pos (row1, col1) to | |
3911 * (row2, col2) inclusive. | |
3912 */ | |
3913 void | |
3914 gui_mch_clear_block(row1, col1, row2, col2) | |
3915 int row1; | |
3916 int col1; | |
3917 int row2; | |
3918 int col2; | |
3919 { | |
3920 Rect rc; | |
3921 | |
3922 /* | |
3923 * Clear one extra pixel at the far right, for when bold characters have | |
3924 * spilled over to the next column. | |
3925 */ | |
3926 rc.left = FILL_X(col1); | |
3927 rc.top = FILL_Y(row1); | |
3928 rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1); | |
3929 rc.bottom = FILL_Y(row2 + 1); | |
3930 | |
3931 gui_mch_set_bg_color(gui.back_pixel); | |
3932 EraseRect (&rc); | |
3933 } | |
3934 | |
3935 /* | |
3936 * Clear the whole text window. | |
3937 */ | |
3938 void | |
3939 gui_mch_clear_all() | |
3940 { | |
3941 Rect rc; | |
3942 | |
3943 rc.left = 0; | |
3944 rc.top = 0; | |
3945 rc.right = Columns * gui.char_width + 2 * gui.border_width; | |
3946 rc.bottom = Rows * gui.char_height + 2 * gui.border_width; | |
3947 | |
3948 gui_mch_set_bg_color(gui.back_pixel); | |
3949 EraseRect(&rc); | |
3950 /* gui_mch_set_fg_color(gui.norm_pixel); | |
3951 FrameRect(&rc); | |
3952 */ | |
3953 } | |
3954 | |
3955 /* | |
3956 * Delete the given number of lines from the given row, scrolling up any | |
3957 * text further down within the scroll region. | |
3958 */ | |
3959 void | |
3960 gui_mch_delete_lines(row, num_lines) | |
3961 int row; | |
3962 int num_lines; | |
3963 { | |
3964 Rect rc; | |
3965 | |
3966 /* changed without checking! */ | |
3967 rc.left = FILL_X(gui.scroll_region_left); | |
3968 rc.right = FILL_X(gui.scroll_region_right + 1); | |
3969 rc.top = FILL_Y(row); | |
3970 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); | |
3971 | |
3972 gui_mch_set_bg_color(gui.back_pixel); | |
3973 ScrollRect (&rc, 0, -num_lines * gui.char_height, (RgnHandle) nil); | |
3974 | |
3975 gui_clear_block(gui.scroll_region_bot - num_lines + 1, | |
3976 gui.scroll_region_left, | |
3977 gui.scroll_region_bot, gui.scroll_region_right); | |
3978 } | |
3979 | |
3980 /* | |
3981 * Insert the given number of lines before the given row, scrolling down any | |
3982 * following text within the scroll region. | |
3983 */ | |
3984 void | |
3985 gui_mch_insert_lines(row, num_lines) | |
3986 int row; | |
3987 int num_lines; | |
3988 { | |
3989 Rect rc; | |
3990 | |
3991 rc.left = FILL_X(gui.scroll_region_left); | |
3992 rc.right = FILL_X(gui.scroll_region_right + 1); | |
3993 rc.top = FILL_Y(row); | |
3994 rc.bottom = FILL_Y(gui.scroll_region_bot + 1); | |
3995 | |
3996 gui_mch_set_bg_color(gui.back_pixel); | |
3997 | |
3998 ScrollRect (&rc, 0, gui.char_height * num_lines, (RgnHandle) nil); | |
3999 | |
4000 /* Update gui.cursor_row if the cursor scrolled or copied over */ | |
4001 if (gui.cursor_row >= gui.row | |
4002 && gui.cursor_col >= gui.scroll_region_left | |
4003 && gui.cursor_col <= gui.scroll_region_right) | |
4004 { | |
4005 if (gui.cursor_row <= gui.scroll_region_bot - num_lines) | |
4006 gui.cursor_row += num_lines; | |
4007 else if (gui.cursor_row <= gui.scroll_region_bot) | |
4008 gui.cursor_is_valid = FALSE; | |
4009 } | |
4010 | |
4011 gui_clear_block(row, gui.scroll_region_left, | |
4012 row + num_lines - 1, gui.scroll_region_right); | |
4013 } | |
4014 | |
4015 /* | |
4016 * TODO: add a vim format to the clipboard which remember | |
4017 * LINEWISE, CHARWISE, BLOCKWISE | |
4018 */ | |
4019 | |
4020 void | |
4021 clip_mch_request_selection(cbd) | |
4022 VimClipboard *cbd; | |
4023 { | |
4024 | |
4025 Handle textOfClip; | |
4026 #ifdef USE_CARBONIZED | |
4027 Size scrapSize; | |
4028 ScrapFlavorFlags scrapFlags; | |
4029 ScrapRef scrap = nil; | |
4030 OSStatus error; | |
4031 #else | |
4032 long scrapOffset; | |
4033 long scrapSize; | |
4034 #endif | |
4035 int type; | |
4036 char *searchCR; | |
4037 char_u *tempclip; | |
4038 | |
4039 | |
4040 #ifdef USE_CARBONIZED | |
4041 error = GetCurrentScrap (&scrap); | |
4042 if (error != noErr) | |
4043 return; | |
4044 | |
4045 error = GetScrapFlavorFlags(scrap, kScrapFlavorTypeText, &scrapFlags); | |
4046 if (error != noErr) | |
4047 return; | |
4048 | |
4049 error = GetScrapFlavorSize (scrap, kScrapFlavorTypeText, &scrapSize); | |
4050 if (error != noErr) | |
4051 return; | |
4052 | |
4053 ReserveMem (scrapSize); | |
4054 #else | |
4055 /* Call to LoadScrap seem to avoid problem with crash on first paste */ | |
4056 scrapSize = LoadScrap(); | |
4057 scrapSize = GetScrap(nil, 'TEXT', &scrapOffset); | |
4058 | |
4059 if (scrapSize > 0) | |
4060 #endif | |
4061 { | |
4062 #ifdef USE_CARBONIZED | |
4063 /* In CARBON we don't need a Handle, a pointer is good */ | |
4064 textOfClip = NewHandle (scrapSize); | |
4065 /* tempclip = lalloc(scrapSize+1, TRUE); */ | |
4066 #else | |
4067 textOfClip = NewHandle(0); | |
4068 #endif | |
4069 HLock (textOfClip); | |
4070 #ifdef USE_CARBONIZED | |
4071 error = GetScrapFlavorData (scrap, kScrapFlavorTypeText, &scrapSize, *textOfClip); | |
4072 #else | |
4073 scrapSize = GetScrap(textOfClip, 'TEXT', &scrapOffset); | |
4074 #endif | |
4075 | |
4076 type = (strchr(*textOfClip, '\r') != NULL) ? MLINE : MCHAR; | |
4077 | |
4078 tempclip = lalloc(scrapSize+1, TRUE); | |
4079 STRNCPY(tempclip, *textOfClip, scrapSize); | |
4080 tempclip[scrapSize] = 0; | |
4081 | |
4082 searchCR = (char *)tempclip; | |
4083 while (searchCR != NULL) | |
4084 { | |
4085 searchCR = strchr(searchCR, '\r'); | |
4086 | |
4087 if (searchCR != NULL) | |
4088 searchCR[0] = '\n'; | |
4089 | |
4090 } | |
4091 | |
4092 #ifdef FEAT_MBYTE | |
4093 if (input_conv.vc_type != CONV_NONE) | |
4094 { | |
4095 char_u *to; | |
4096 int l = scrapSize; | |
4097 | |
4098 to = string_convert(&input_conv, tempclip, &l); | |
4099 if (to != NULL) | |
4100 { | |
4101 vim_free(tempclip); | |
4102 tempclip = to; | |
4103 scrapSize = l; | |
4104 } | |
4105 } | |
4106 #endif | |
4107 clip_yank_selection(type, tempclip, scrapSize, cbd); | |
4108 | |
4109 vim_free(tempclip); | |
4110 HUnlock(textOfClip); | |
4111 | |
4112 DisposeHandle(textOfClip); | |
4113 } | |
4114 } | |
4115 | |
4116 void | |
4117 clip_mch_lose_selection(cbd) | |
4118 VimClipboard *cbd; | |
4119 { | |
4120 /* | |
4121 * TODO: Really nothing to do? | |
4122 */ | |
4123 } | |
4124 | |
4125 int | |
4126 clip_mch_own_selection(cbd) | |
4127 VimClipboard *cbd; | |
4128 { | |
4129 return OK; | |
4130 } | |
4131 | |
4132 /* | |
4133 * Send the current selection to the clipboard. | |
4134 */ | |
4135 void | |
4136 clip_mch_set_selection(cbd) | |
4137 VimClipboard *cbd; | |
4138 { | |
4139 Handle textOfClip; | |
4140 long scrapSize; | |
4141 int type; | |
4142 #ifdef USE_CARBONIZED | |
4143 ScrapRef scrap; | |
4144 #endif | |
4145 | |
4146 char_u *str = NULL; | |
4147 | |
4148 if (!cbd->owned) | |
4149 return; | |
4150 | |
4151 clip_get_selection(cbd); | |
4152 | |
4153 /* | |
4154 * Once we set the clipboard, lose ownership. If another application sets | |
4155 * the clipboard, we don't want to think that we still own it. | |
4156 * | |
4157 */ | |
4158 | |
4159 cbd->owned = FALSE; | |
4160 | |
4161 type = clip_convert_selection(&str, (long_u *) &scrapSize, cbd); | |
4162 | |
4163 #ifdef FEAT_MBYTE | |
4164 if (str != NULL && output_conv.vc_type != CONV_NONE) | |
4165 { | |
4166 char_u *to; | |
4167 int l = scrapSize; | |
4168 | |
4169 to = string_convert(&output_conv, str, &l); | |
4170 if (to != NULL) | |
4171 { | |
4172 vim_free(str); | |
4173 str = to; | |
4174 scrapSize = l; | |
4175 } | |
4176 } | |
4177 #endif | |
4178 | |
4179 if (type >= 0) | |
4180 { | |
4181 #ifdef USE_CARBONIZED | |
4182 ClearCurrentScrap(); | |
4183 #else | |
4184 ZeroScrap(); | |
4185 #endif | |
4186 | |
4187 textOfClip = NewHandle(scrapSize); | |
4188 HLock(textOfClip); | |
4189 | |
4190 STRNCPY(*textOfClip, str, scrapSize); | |
4191 #ifdef USE_CARBONIZED | |
4192 GetCurrentScrap (&scrap); | |
4193 PutScrapFlavor(scrap, kScrapFlavorTypeText, kScrapFlavorMaskNone, | |
4194 scrapSize, *textOfClip); | |
4195 #else | |
4196 PutScrap(scrapSize, 'TEXT', *textOfClip); | |
4197 #endif | |
4198 HUnlock(textOfClip); | |
4199 DisposeHandle(textOfClip); | |
4200 } | |
4201 | |
4202 vim_free(str); | |
4203 } | |
4204 | |
4205 void | |
4206 gui_mch_set_text_area_pos(x, y, w, h) | |
4207 int x; | |
4208 int y; | |
4209 int w; | |
4210 int h; | |
4211 { | |
4212 Rect VimBound; | |
4213 | |
4214 /* HideWindow (gui.VimWindow); */ | |
4215 #ifdef USE_CARBONIZED | |
4216 GetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound); | |
4217 #else | |
4218 VimBound = gui.VimWindow->portRect; | |
4219 #endif | |
4220 | |
4221 if (gui.which_scrollbars[SBAR_LEFT]) | |
4222 { | |
4223 VimBound.left = -gui.scrollbar_width + 1; | |
4224 } | |
4225 else | |
4226 { | |
4227 VimBound.left = 0; | |
4228 } | |
4229 | |
4230 #ifdef USE_CARBONIZED | |
4231 SetWindowBounds(gui.VimWindow, kWindowGlobalPortRgn, &VimBound); | |
4232 #endif | |
4233 | |
4234 ShowWindow (gui.VimWindow); | |
4235 } | |
4236 | |
4237 /* | |
4238 * Menu stuff. | |
4239 */ | |
4240 | |
4241 void | |
4242 gui_mch_enable_menu(flag) | |
4243 int flag; | |
4244 { | |
4245 /* | |
4246 * Menu is always active in itself | |
4247 * (maybe we should only disable a vim menu | |
4248 * and keep standard menu) | |
4249 * | |
4250 */ | |
4251 } | |
4252 | |
4253 void | |
4254 gui_mch_set_menu_pos(x, y, w, h) | |
4255 int x; | |
4256 int y; | |
4257 int w; | |
4258 int h; | |
4259 { | |
4260 /* | |
4261 * The menu is always at the top of the screen | |
4262 * Maybe a futur version will permit a menu in the window | |
4263 * | |
4264 */ | |
4265 } | |
4266 | |
4267 /* | |
4268 * Add a sub menu to the menu bar. | |
4269 */ | |
4270 void | |
4271 gui_mch_add_menu(menu, idx) | |
4272 vimmenu_T *menu; | |
4273 int idx; | |
4274 { | |
4275 /* | |
4276 * TODO: Try to use only menu_id instead of both menu_id and menu_handle. | |
4277 * TODO: use menu->mnemonic and menu->actext | |
4278 * TODO: Try to reuse menu id | |
4279 * Carbon Help suggest to use only id between 1 and 235 | |
4280 */ | |
4281 static long next_avail_id = 128; | |
4282 long menu_after_me = 0; /* Default to the end */ | |
4283 char_u *name; | |
4284 short index; | |
4285 vimmenu_T *parent = menu->parent; | |
4286 vimmenu_T *brother = menu->next; | |
4287 | |
4288 /* Cannot add a menu if ... */ | |
4289 if ((parent != NULL && parent->submenu_id == 0)) | |
4290 return; | |
4291 | |
4292 /* menu ID greater than 1024 are reserved for ??? */ | |
4293 if (next_avail_id == 1024) | |
4294 return; | |
4295 | |
4296 /* My brother could be the PopUp, find my real brother */ | |
4297 while ((brother != NULL) && (!menu_is_menubar(brother->name))) | |
4298 brother = brother->next; | |
4299 | |
4300 /* Find where to insert the menu (for MenuBar) */ | |
4301 if ((parent == NULL) && (brother != NULL)) | |
4302 menu_after_me = brother->submenu_id; | |
4303 | |
4304 /* If the menu is not part of the menubar (and its submenus), add it 'nowhere' */ | |
4305 if (!menu_is_menubar(menu->name)) | |
4306 menu_after_me = hierMenu; | |
4307 | |
4308 /* Convert the name */ | |
4309 name = C2Pascal_save(menu->dname); | |
4310 if (name == NULL) | |
4311 return; | |
4312 | |
4313 /* Create the menu unless it's the help menu */ | |
4314 #ifdef USE_HELPMENU | |
4315 if (STRNCMP(name, "\4Help", 5) == 0) | |
4316 { | |
4317 menu->submenu_id = kHMHelpMenuID; | |
4318 menu->submenu_handle = gui.MacOSHelpMenu; | |
4319 } | |
4320 else | |
4321 #endif | |
4322 { | |
4323 /* Carbon suggest use of | |
4324 * OSStatus CreateNewMenu ( MenuID, MenuAttributes, MenuRef *); | |
4325 * OSStatus SetMenuTitle ( MenuRef, ConstStr255Param title ); | |
4326 */ | |
4327 menu->submenu_id = next_avail_id; | |
4328 menu->submenu_handle = NewMenu (menu->submenu_id, name); | |
4329 next_avail_id++; | |
4330 } | |
4331 | |
4332 if (parent == NULL) | |
4333 { | |
4334 /* Adding a menu to the menubar, or in the no mans land (for PopUp) */ | |
4335 | |
4336 /* TODO: Verify if we could only Insert Menu if really part of the | |
4337 * menubar The Inserted menu are scanned or the Command-key combos | |
4338 */ | |
4339 | |
4340 /* Insert the menu unless it's the Help menu */ | |
4341 #ifdef USE_HELPMENU | |
4342 if (menu->submenu_id != kHMHelpMenuID) | |
4343 #endif | |
4344 InsertMenu (menu->submenu_handle, menu_after_me); /* insert before */ | |
4345 #if 1 | |
4346 /* Vim should normally update it. TODO: verify */ | |
4347 DrawMenuBar(); | |
4348 #endif | |
4349 } | |
4350 else | |
4351 { | |
4352 /* Adding as a submenu */ | |
4353 | |
4354 index = gui_mac_get_menu_item_index (menu); | |
4355 | |
4356 /* Call InsertMenuItem followed by SetMenuItemText | |
4357 * to avoid special character recognition by InsertMenuItem | |
4358 */ | |
4359 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */ | |
4360 SetMenuItemText(parent->submenu_handle, idx+1, name); | |
4361 SetItemCmd(parent->submenu_handle, idx+1, 0x1B); | |
4362 SetItemMark(parent->submenu_handle, idx+1, menu->submenu_id); | |
4363 InsertMenu(menu->submenu_handle, hierMenu); | |
4364 } | |
4365 | |
4366 vim_free (name); | |
4367 | |
4368 #if 0 | |
4369 /* Done by Vim later on */ | |
4370 DrawMenuBar(); | |
4371 #endif | |
4372 } | |
4373 | |
4374 /* | |
4375 * Add a menu item to a menu | |
4376 */ | |
4377 void | |
4378 gui_mch_add_menu_item(menu, idx) | |
4379 vimmenu_T *menu; | |
4380 int idx; | |
4381 { | |
4382 char_u *name; | |
4383 vimmenu_T *parent = menu->parent; | |
4384 int menu_inserted; | |
4385 | |
4386 /* Cannot add item, if the menu have not been created */ | |
4387 if (parent->submenu_id == 0) | |
4388 return; | |
4389 | |
4390 /* Could call SetMenuRefCon [CARBON] to associate with the Menu, | |
4391 for older OS call GetMenuItemData (menu, item, isCommandID?, data) */ | |
4392 | |
4393 /* Convert the name */ | |
4394 name = C2Pascal_save(menu->dname); | |
4395 | |
4396 /* Where are just a menu item, so no handle, no id */ | |
4397 menu->submenu_id = 0; | |
4398 menu->submenu_handle = NULL; | |
4399 | |
4400 #ifdef USE_HELPMENU | |
4401 /* The index in the help menu are offseted */ | |
4402 if (parent->submenu_id == kHMHelpMenuID) | |
4403 idx += gui.MacOSHelpItems; | |
4404 #endif | |
4405 | |
4406 menu_inserted = 0; | |
4407 if (menu->actext) | |
4408 { | |
4409 /* If the accelerator text for the menu item looks like it describes | |
4410 * a command key (e.g., "<D-S-t>" or "<C-7>"), display it as the | |
4411 * item's command equivalent. | |
4412 */ | |
4413 int key = 0; | |
4414 int modifiers = 0; | |
4415 char_u *p_actext; | |
4416 | |
4417 p_actext = menu->actext; | |
4418 key = find_special_key(&p_actext, &modifiers, /*keycode=*/0); | |
4419 if (*p_actext != 0) | |
4420 key = 0; /* error: trailing text */ | |
4421 /* find_special_key() returns a keycode with as many of the | |
4422 * specified modifiers as appropriate already applied (e.g., for | |
4423 * "<D-C-x>" it returns Ctrl-X as the keycode and MOD_MASK_CMD | |
4424 * as the only modifier). Since we want to display all of the | |
4425 * modifiers, we need to convert the keycode back to a printable | |
4426 * character plus modifiers. | |
4427 * TODO: Write an alternative find_special_key() that doesn't | |
4428 * apply modifiers. | |
4429 */ | |
4430 if (key > 0 && key < 32) | |
4431 { | |
4432 /* Convert a control key to an uppercase letter. Note that | |
4433 * by this point it is no longer possible to distinguish | |
4434 * between, e.g., Ctrl-S and Ctrl-Shift-S. | |
4435 */ | |
4436 modifiers |= MOD_MASK_CTRL; | |
4437 key += '@'; | |
4438 } | |
4439 /* If the keycode is an uppercase letter, set the Shift modifier. | |
4440 * If it is a lowercase letter, don't set the modifier, but convert | |
4441 * the letter to uppercase for display in the menu. | |
4442 */ | |
4443 else if (key >= 'A' && key <= 'Z') | |
4444 modifiers |= MOD_MASK_SHIFT; | |
4445 else if (key >= 'a' && key <= 'z') | |
4446 key += 'A' - 'a'; | |
4447 /* Note: keycodes below 0x22 are reserved by Apple. */ | |
4448 if (key >= 0x22 && vim_isprintc_strict(key)) | |
4449 { | |
4450 int valid = 1; | |
4451 char_u mac_mods = kMenuNoModifiers; | |
4452 /* Convert Vim modifier codes to Menu Manager equivalents. */ | |
4453 if (modifiers & MOD_MASK_SHIFT) | |
4454 mac_mods |= kMenuShiftModifier; | |
4455 if (modifiers & MOD_MASK_CTRL) | |
4456 mac_mods |= kMenuControlModifier; | |
4457 if (!(modifiers & MOD_MASK_CMD)) | |
4458 mac_mods |= kMenuNoCommandModifier; | |
4459 if (modifiers & MOD_MASK_ALT || modifiers & MOD_MASK_MULTI_CLICK) | |
4460 valid = 0; /* TODO: will Alt someday map to Option? */ | |
4461 if (valid) | |
4462 { | |
4463 char_u item_txt[10]; | |
4464 /* Insert the menu item after idx, with its command key. */ | |
4465 item_txt[0] = 3; item_txt[1] = ' '; item_txt[2] = '/'; | |
4466 item_txt[3] = key; | |
4467 InsertMenuItem(parent->submenu_handle, item_txt, idx); | |
4468 /* Set the modifier keys. */ | |
4469 SetMenuItemModifiers(parent->submenu_handle, idx+1, mac_mods); | |
4470 menu_inserted = 1; | |
4471 } | |
4472 } | |
4473 } | |
4474 /* Call InsertMenuItem followed by SetMenuItemText | |
4475 * to avoid special character recognition by InsertMenuItem | |
4476 */ | |
4477 if (!menu_inserted) | |
4478 InsertMenuItem(parent->submenu_handle, "\p ", idx); /* afterItem */ | |
4479 /* Set the menu item name. */ | |
4480 SetMenuItemText(parent->submenu_handle, idx+1, name); | |
4481 | |
4482 #if 0 | |
4483 /* Called by Vim */ | |
4484 DrawMenuBar(); | |
4485 #endif | |
4486 | |
4487 /* TODO: Can name be freed? */ | |
4488 vim_free(name); | |
4489 } | |
4490 | |
4491 void | |
4492 gui_mch_toggle_tearoffs(enable) | |
4493 int enable; | |
4494 { | |
4495 /* no tearoff menus */ | |
4496 } | |
4497 | |
4498 /* | |
4499 * Destroy the machine specific menu widget. | |
4500 */ | |
4501 void | |
4502 gui_mch_destroy_menu(menu) | |
4503 vimmenu_T *menu; | |
4504 { | |
4505 short index = gui_mac_get_menu_item_index (menu); | |
4506 | |
4507 if (index > 0) | |
4508 { | |
4509 if (menu->parent) | |
4510 { | |
4511 #ifdef USE_HELPMENU | |
4512 if (menu->parent->submenu_handle != nil) /*gui.MacOSHelpMenu)*/ | |
4513 #endif | |
4514 { | |
4515 /* For now just don't delete help menu items. (Huh? Dany) */ | |
4516 DeleteMenuItem (menu->parent->submenu_handle, index); | |
4517 | |
4518 /* Delete the Menu if it was a hierarchical Menu */ | |
4519 if (menu->submenu_id != 0) | |
4520 { | |
4521 DeleteMenu (menu->submenu_id); | |
4522 DisposeMenu (menu->submenu_handle); | |
4523 } | |
4524 } | |
4525 #ifdef USE_HELPMENU | |
4526 # ifdef DEBUG_MAC_MENU | |
4527 else | |
4528 { | |
4529 printf ("gmdm 1\n"); | |
4530 } | |
4531 # endif | |
4532 #endif | |
4533 } | |
4534 #ifdef DEBUG_MAC_MENU | |
4535 else | |
4536 { | |
4537 printf ("gmdm 2\n"); | |
4538 } | |
4539 #endif | |
4540 } | |
4541 else | |
4542 { | |
4543 /* Do not delete the Help Menu */ | |
4544 #ifdef USE_HELPMENU | |
4545 if (menu->submenu_id != kHMHelpMenuID) | |
4546 #endif | |
4547 { | |
4548 DeleteMenu (menu->submenu_id); | |
4549 DisposeMenu (menu->submenu_handle); | |
4550 } | |
4551 } | |
4552 /* Shouldn't this be already done by Vim. TODO: Check */ | |
4553 DrawMenuBar(); | |
4554 } | |
4555 | |
4556 /* | |
4557 * Make a menu either grey or not grey. | |
4558 */ | |
4559 void | |
4560 gui_mch_menu_grey(menu, grey) | |
4561 vimmenu_T *menu; | |
4562 int grey; | |
4563 { | |
4564 /* TODO: Check if menu really exists */ | |
4565 short index = gui_mac_get_menu_item_index (menu); | |
4566 /* | |
4567 index = menu->index; | |
4568 */ | |
4569 if (grey) | |
4570 { | |
4571 if (menu->children) | |
4572 DisableMenuItem(menu->submenu_handle, index); | |
4573 if (menu->parent) | |
4574 if (menu->parent->submenu_handle) | |
4575 DisableMenuItem(menu->parent->submenu_handle, index); | |
4576 } | |
4577 else | |
4578 { | |
4579 if (menu->children) | |
4580 EnableMenuItem(menu->submenu_handle, index); | |
4581 if (menu->parent) | |
4582 if (menu->parent->submenu_handle) | |
4583 EnableMenuItem(menu->parent->submenu_handle, index); | |
4584 } | |
4585 } | |
4586 | |
4587 /* | |
4588 * Make menu item hidden or not hidden | |
4589 */ | |
4590 void | |
4591 gui_mch_menu_hidden(menu, hidden) | |
4592 vimmenu_T *menu; | |
4593 int hidden; | |
4594 { | |
4595 /* There's no hidden mode on MacOS */ | |
4596 gui_mch_menu_grey (menu, hidden); | |
4597 } | |
4598 | |
4599 | |
4600 /* | |
4601 * This is called after setting all the menus to grey/hidden or not. | |
4602 */ | |
4603 void | |
4604 gui_mch_draw_menubar() | |
4605 { | |
4606 DrawMenuBar(); | |
4607 } | |
4608 | |
4609 | |
4610 /* | |
4611 * Scrollbar stuff. | |
4612 */ | |
4613 | |
4614 void | |
4615 gui_mch_enable_scrollbar(sb, flag) | |
4616 scrollbar_T *sb; | |
4617 int flag; | |
4618 { | |
4619 if (flag) | |
4620 ShowControl(sb->id); | |
4621 else | |
4622 HideControl(sb->id); | |
4623 | |
4624 #ifdef DEBUG_MAC_SB | |
4625 printf ("enb_sb (%x) %x\n",sb->id, flag); | |
4626 #endif | |
4627 } | |
4628 | |
4629 void | |
4630 gui_mch_set_scrollbar_thumb(sb, val, size, max) | |
4631 scrollbar_T *sb; | |
4632 long val; | |
4633 long size; | |
4634 long max; | |
4635 { | |
4636 SetControl32BitMaximum (sb->id, max); | |
4637 SetControl32BitMinimum (sb->id, 0); | |
4638 SetControl32BitValue (sb->id, val); | |
4639 #ifdef DEBUG_MAC_SB | |
4640 printf ("thumb_sb (%x) %x, %x,%x\n",sb->id, val, size, max); | |
4641 #endif | |
4642 } | |
4643 | |
4644 void | |
4645 gui_mch_set_scrollbar_pos(sb, x, y, w, h) | |
4646 scrollbar_T *sb; | |
4647 int x; | |
4648 int y; | |
4649 int w; | |
4650 int h; | |
4651 { | |
4652 gui_mch_set_bg_color(gui.back_pixel); | |
4653 /* if (gui.which_scrollbars[SBAR_LEFT]) | |
4654 { | |
4655 MoveControl (sb->id, x-16, y); | |
4656 SizeControl (sb->id, w + 1, h); | |
4657 } | |
4658 else | |
4659 { | |
4660 MoveControl (sb->id, x, y); | |
4661 SizeControl (sb->id, w + 1, h); | |
4662 }*/ | |
4663 if (sb == &gui.bottom_sbar) | |
4664 h += 1; | |
4665 else | |
4666 w += 1; | |
4667 | |
4668 if (gui.which_scrollbars[SBAR_LEFT]) | |
4669 x -= 15; | |
4670 | |
4671 MoveControl (sb->id, x, y); | |
4672 SizeControl (sb->id, w, h); | |
4673 #ifdef DEBUG_MAC_SB | |
4674 printf ("size_sb (%x) %x, %x, %x, %x\n",sb->id, x, y, w, h); | |
4675 #endif | |
4676 } | |
4677 | |
4678 void | |
4679 gui_mch_create_scrollbar(sb, orient) | |
4680 scrollbar_T *sb; | |
4681 int orient; /* SBAR_VERT or SBAR_HORIZ */ | |
4682 { | |
4683 Rect bounds; | |
4684 | |
4685 bounds.top = -16; | |
4686 bounds.bottom = -10; | |
4687 bounds.right = -10; | |
4688 bounds.left = -16; | |
4689 | |
4690 sb->id = NewControl (gui.VimWindow, | |
4691 &bounds, | |
4692 "\pScrollBar", | |
4693 TRUE, | |
4694 0, /* current*/ | |
4695 0, /* top */ | |
4696 0, /* bottom */ | |
4697 #ifdef USE_CARBONIZED | |
4698 kControlScrollBarLiveProc, | |
4699 #else | |
4700 scrollBarProc, | |
4701 #endif | |
4702 (long) sb->ident); | |
4703 #ifdef DEBUG_MAC_SB | |
4704 printf ("create_sb (%x) %x\n",sb->id, orient); | |
4705 #endif | |
4706 } | |
4707 | |
4708 void | |
4709 gui_mch_destroy_scrollbar(sb) | |
4710 scrollbar_T *sb; | |
4711 { | |
4712 gui_mch_set_bg_color(gui.back_pixel); | |
4713 DisposeControl (sb->id); | |
4714 #ifdef DEBUG_MAC_SB | |
4715 printf ("dest_sb (%x) \n",sb->id); | |
4716 #endif | |
4717 } | |
4718 | |
4719 | |
4720 /* | |
4721 * Cursor blink functions. | |
4722 * | |
4723 * This is a simple state machine: | |
4724 * BLINK_NONE not blinking at all | |
4725 * BLINK_OFF blinking, cursor is not shown | |
4726 * BLINK_ON blinking, cursor is shown | |
4727 */ | |
4728 void | |
4729 gui_mch_set_blinking(long wait, long on, long off) | |
4730 { | |
4731 /* TODO: TODO: TODO: TODO: */ | |
4732 /* blink_waittime = wait; | |
4733 blink_ontime = on; | |
4734 blink_offtime = off;*/ | |
4735 } | |
4736 | |
4737 /* | |
4738 * Stop the cursor blinking. Show the cursor if it wasn't shown. | |
4739 */ | |
4740 void | |
4741 gui_mch_stop_blink() | |
4742 { | |
4743 gui_update_cursor(TRUE, FALSE); | |
4744 /* TODO: TODO: TODO: TODO: */ | |
4745 /* gui_w32_rm_blink_timer(); | |
4746 if (blink_state == BLINK_OFF) | |
4747 gui_update_cursor(TRUE, FALSE); | |
4748 blink_state = BLINK_NONE;*/ | |
4749 } | |
4750 | |
4751 /* | |
4752 * Start the cursor blinking. If it was already blinking, this restarts the | |
4753 * waiting time and shows the cursor. | |
4754 */ | |
4755 void | |
4756 gui_mch_start_blink() | |
4757 { | |
4758 gui_update_cursor(TRUE, FALSE); | |
4759 /* TODO: TODO: TODO: TODO: */ | |
4760 /* gui_w32_rm_blink_timer(); */ | |
4761 | |
4762 /* Only switch blinking on if none of the times is zero */ | |
4763 /* if (blink_waittime && blink_ontime && blink_offtime) | |
4764 { | |
4765 blink_timer = SetTimer(NULL, 0, (UINT)blink_waittime, | |
4766 (TIMERPROC)_OnBlinkTimer); | |
4767 blink_state = BLINK_ON; | |
4768 gui_update_cursor(TRUE, FALSE); | |
4769 }*/ | |
4770 } | |
4771 | |
4772 /* | |
4773 * Return the RGB value of a pixel as long. | |
4774 */ | |
4775 long_u | |
4776 gui_mch_get_rgb(guicolor_T pixel) | |
4777 { | |
4778 return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel); | |
4779 } | |
4780 | |
4781 | |
4782 | |
4783 #ifdef FEAT_BROWSE | |
4784 /* | |
4785 * Pop open a file browser and return the file selected, in allocated memory, | |
4786 * or NULL if Cancel is hit. | |
4787 * saving - TRUE if the file will be saved to, FALSE if it will be opened. | |
4788 * title - Title message for the file browser dialog. | |
4789 * dflt - Default name of file. | |
4790 * ext - Default extension to be added to files without extensions. | |
4791 * initdir - directory in which to open the browser (NULL = current dir) | |
4792 * filter - Filter for matched files to choose from. | |
4793 * Has a format like this: | |
4794 * "C Files (*.c)\0*.c\0" | |
4795 * "All Files\0*.*\0\0" | |
4796 * If these two strings were concatenated, then a choice of two file | |
4797 * filters will be selectable to the user. Then only matching files will | |
4798 * be shown in the browser. If NULL, the default allows all files. | |
4799 * | |
4800 * *NOTE* - the filter string must be terminated with TWO nulls. | |
4801 */ | |
4802 char_u * | |
4803 gui_mch_browse( | |
4804 int saving, | |
4805 char_u *title, | |
4806 char_u *dflt, | |
4807 char_u *ext, | |
4808 char_u *initdir, | |
4809 char_u *filter) | |
4810 { | |
4811 #if defined (USE_NAVIGATION_SERVICE) || defined (USE_CARBONIZED) | |
4812 /* TODO: Add Ammon's safety checl (Dany) */ | |
4813 NavReplyRecord reply; | |
4814 char_u *fname = NULL; | |
4815 char_u **fnames = NULL; | |
4816 long numFiles; | |
4817 NavDialogOptions navOptions; | |
4818 OSErr error; | |
4819 | |
4820 /* Get Navigation Service Defaults value */ | |
4821 NavGetDefaultDialogOptions (&navOptions); | |
4822 | |
4823 | |
4824 /* TODO: If we get a :browse args, set the Multiple bit. */ | |
4825 navOptions.dialogOptionFlags = kNavAllowInvisibleFiles | |
4826 | kNavDontAutoTranslate | |
4827 | kNavDontAddTranslateItems | |
4828 /* | kNavAllowMultipleFiles */ | |
4829 | kNavAllowStationery; | |
4830 | |
4831 (void) C2PascalString (title, &navOptions.message); | |
4832 (void) C2PascalString (dflt, &navOptions.savedFileName); | |
4833 /* Could set clientName? | |
4834 * windowTitle? (there's no title bar?) | |
4835 */ | |
4836 | |
4837 if (saving) | |
4838 { | |
4839 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */ | |
4840 NavPutFile (NULL, &reply, &navOptions, NULL, 'TEXT', 'VIM!', NULL); | |
4841 if (!reply.validRecord) | |
4842 return NULL; | |
4843 } | |
4844 else | |
4845 { | |
4846 /* Change first parm AEDesc (typeFSS) *defaultLocation to match dflt */ | |
4847 NavGetFile(NULL, &reply, &navOptions, NULL, NULL, NULL, NULL, NULL); | |
4848 if (!reply.validRecord) | |
4849 return NULL; | |
4850 } | |
4851 | |
4852 fnames = new_fnames_from_AEDesc(&reply.selection, &numFiles, &error); | |
4853 | |
4854 NavDisposeReply (&reply); | |
4855 | |
4856 if (fnames) | |
4857 { | |
4858 fname = fnames[0]; | |
4859 vim_free(fnames); | |
4860 } | |
4861 | |
4862 /* TODO: Shorten the file name if possible */ | |
4863 return fname; | |
4864 #else | |
4865 SFTypeList fileTypes; | |
4866 StandardFileReply reply; | |
4867 Str255 Prompt; | |
4868 Str255 DefaultName; | |
4869 Str255 Directory; | |
4870 | |
4871 /* TODO: split dflt in path and filename */ | |
4872 | |
4873 (void) C2PascalString (title, &Prompt); | |
4874 (void) C2PascalString (dflt, &DefaultName); | |
4875 (void) C2PascalString (initdir, &Directory); | |
4876 | |
4877 if (saving) | |
4878 { | |
4879 /* Use a custon filter instead of nil FAQ 9-4 */ | |
4880 StandardPutFile (Prompt, DefaultName, &reply); | |
4881 if (!reply.sfGood) | |
4882 return NULL; | |
4883 } | |
4884 else | |
4885 { | |
4886 StandardGetFile (nil, -1, fileTypes, &reply); | |
4887 if (!reply.sfGood) | |
4888 return NULL; | |
4889 } | |
4890 | |
4891 /* Work fine but append a : for new file */ | |
4892 return (FullPathFromFSSpec_save (reply.sfFile)); | |
4893 | |
4894 /* Shorten the file name if possible */ | |
4895 /* mch_dirname(IObuff, IOSIZE); | |
4896 p = shorten_fname(fileBuf, IObuff); | |
4897 if (p == NULL) | |
4898 p = fileBuf; | |
4899 return vim_strsave(p); | |
4900 */ | |
4901 #endif | |
4902 } | |
4903 #endif /* FEAT_BROWSE */ | |
4904 | |
4905 #ifdef FEAT_GUI_DIALOG | |
4906 /* | |
4907 * Stuff for dialogues | |
4908 */ | |
4909 | |
4910 /* | |
4911 * Create a dialogue dynamically from the parameter strings. | |
4912 * type = type of dialogue (question, alert, etc.) | |
4913 * title = dialogue title. may be NULL for default title. | |
4914 * message = text to display. Dialogue sizes to accommodate it. | |
4915 * buttons = '\n' separated list of button captions, default first. | |
4916 * dfltbutton = number of default button. | |
4917 * | |
4918 * This routine returns 1 if the first button is pressed, | |
4919 * 2 for the second, etc. | |
4920 * | |
4921 * 0 indicates Esc was pressed. | |
4922 * -1 for unexpected error | |
4923 * | |
4924 * If stubbing out this fn, return 1. | |
4925 */ | |
4926 | |
4927 typedef struct | |
4928 { | |
4929 short idx; | |
4930 short width; /* Size of the text in pixel */ | |
4931 Rect box; | |
4932 } vgmDlgItm; /* Vim Gui_Mac.c Dialog Item */ | |
4933 | |
4934 #define MoveRectTo(r,x,y) OffsetRect(r,x-r->left,y-r->top) | |
4935 | |
4936 static void | |
4937 macMoveDialogItem( | |
4938 DialogRef theDialog, | |
4939 short itemNumber, | |
4940 short X, | |
4941 short Y, | |
4942 Rect *inBox) | |
4943 { | |
4944 #if 0 /* USE_CARBONIZED */ | |
4945 /* Untested */ | |
4946 MoveDialogItem (theDialog, itemNumber, X, Y); | |
4947 if (inBox != nil) | |
4948 GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, inBox); | |
4949 #else | |
4950 short itemType; | |
4951 Handle itemHandle; | |
4952 Rect localBox; | |
4953 Rect *itemBox = &localBox; | |
4954 | |
4955 if (inBox != nil) | |
4956 itemBox = inBox; | |
4957 | |
4958 GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, itemBox); | |
4959 OffsetRect (itemBox, -itemBox->left, -itemBox->top); | |
4960 OffsetRect (itemBox, X, Y); | |
4961 /* To move a control (like a button) we need to call both | |
4962 * MoveControl and SetDialogItem. FAQ 6-18 */ | |
4963 if (1) /*(itemType & kControlDialogItem) */ | |
4964 MoveControl ((ControlRef) itemHandle, X, Y); | |
4965 SetDialogItem (theDialog, itemNumber, itemType, itemHandle, itemBox); | |
4966 #endif | |
4967 } | |
4968 | |
4969 static void | |
4970 macSizeDialogItem( | |
4971 DialogRef theDialog, | |
4972 short itemNumber, | |
4973 short width, | |
4974 short height) | |
4975 { | |
4976 short itemType; | |
4977 Handle itemHandle; | |
4978 Rect itemBox; | |
4979 | |
4980 GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, &itemBox); | |
4981 | |
4982 /* When width or height is zero do not change it */ | |
4983 if (width == 0) | |
4984 width = itemBox.right - itemBox.left; | |
4985 if (height == 0) | |
4986 height = itemBox.bottom - itemBox.top; | |
4987 | |
4988 #if 0 /* USE_CARBONIZED */ | |
4989 SizeDialogItem (theDialog, itemNumber, width, height); /* Untested */ | |
4990 #else | |
4991 /* Resize the bounding box */ | |
4992 itemBox.right = itemBox.left + width; | |
4993 itemBox.bottom = itemBox.top + height; | |
4994 | |
4995 /* To resize a control (like a button) we need to call both | |
4996 * SizeControl and SetDialogItem. (deducted from FAQ 6-18) */ | |
4997 if (itemType & kControlDialogItem) | |
4998 SizeControl ((ControlRef) itemHandle, width, height); | |
4999 | |
5000 /* Configure back the item */ | |
5001 SetDialogItem (theDialog, itemNumber, itemType, itemHandle, &itemBox); | |
5002 #endif | |
5003 } | |
5004 | |
5005 static void | |
5006 macSetDialogItemText( | |
5007 DialogRef theDialog, | |
5008 short itemNumber, | |
5009 Str255 itemName) | |
5010 { | |
5011 short itemType; | |
5012 Handle itemHandle; | |
5013 Rect itemBox; | |
5014 | |
5015 GetDialogItem (theDialog, itemNumber, &itemType, &itemHandle, &itemBox); | |
5016 | |
5017 if (itemType & kControlDialogItem) | |
5018 SetControlTitle ((ControlRef) itemHandle, itemName); | |
5019 else | |
5020 SetDialogItemText (itemHandle, itemName); | |
5021 } | |
5022 | |
5023 int | |
5024 gui_mch_dialog( | |
5025 int type, | |
5026 char_u *title, | |
5027 char_u *message, | |
5028 char_u *buttons, | |
5029 int dfltbutton, | |
5030 char_u *textfield) | |
5031 { | |
5032 Handle buttonDITL; | |
5033 Handle iconDITL; | |
5034 Handle inputDITL; | |
5035 Handle messageDITL; | |
5036 Handle itemHandle; | |
5037 Handle iconHandle; | |
5038 DialogPtr theDialog; | |
5039 char_u len; | |
5040 char_u PascalTitle[256]; /* place holder for the title */ | |
5041 char_u name[256]; | |
5042 GrafPtr oldPort; | |
5043 short itemHit; | |
5044 char_u *buttonChar; | |
5045 Rect box; | |
5046 short button; | |
5047 short lastButton; | |
5048 short itemType; | |
5049 short useIcon; | |
5050 short width; | |
5051 short totalButtonWidth = 0; /* the width of all button together incuding spacing */ | |
5052 short widestButton = 0; | |
5053 short dfltButtonEdge = 20; /* gut feeling */ | |
5054 short dfltElementSpacing = 13; /* from IM:V.2-29 */ | |
5055 short dfltIconSideSpace = 23; /* from IM:V.2-29 */ | |
5056 short maximumWidth = 400; /* gut feeling */ | |
5057 short maxButtonWidth = 175; /* gut feeling */ | |
5058 | |
5059 short vertical; | |
5060 short dialogHeight; | |
5061 short messageLines = 3; | |
5062 FontInfo textFontInfo; | |
5063 | |
5064 vgmDlgItm iconItm; | |
5065 vgmDlgItm messageItm; | |
5066 vgmDlgItm inputItm; | |
5067 vgmDlgItm buttonItm; | |
5068 | |
5069 WindowRef theWindow; | |
5070 | |
5071 /* Check 'v' flag in 'guioptions': vertical button placement. */ | |
5072 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); | |
5073 | |
5074 /* Create a new Dialog Box from template. */ | |
5075 theDialog = GetNewDialog (129, nil, (WindowRef) -1); | |
5076 | |
5077 /* Get the WindowRef */ | |
5078 theWindow = GetDialogWindow(theDialog); | |
5079 | |
5080 /* Hide the window. | |
5081 * 1. to avoid seeing slow drawing | |
5082 * 2. to prevent a problem seen while moving dialog item | |
5083 * within a visible window. (non-Carbon MacOS 9) | |
5084 * Could be avoided by changing the resource. | |
5085 */ | |
5086 HideWindow (theWindow); | |
5087 | |
5088 /* Change the graphical port to the dialog, | |
5089 * so we can measure the text with the proper font */ | |
5090 GetPort (&oldPort); | |
5091 #ifdef USE_CARBONIZED | |
5092 SetPortDialogPort (theDialog); | |
5093 #else | |
5094 SetPort (theDialog); | |
5095 #endif | |
5096 | |
5097 /* Get the info about the default text, | |
5098 * used to calculate the height of the message | |
5099 * and of the text field */ | |
5100 GetFontInfo(&textFontInfo); | |
5101 | |
5102 /* Set the dialog title */ | |
5103 if (title != NULL) | |
5104 { | |
5105 (void) C2PascalString (title, &PascalTitle); | |
5106 SetWTitle (theWindow, PascalTitle); | |
5107 } | |
5108 | |
5109 /* Creates the buttons and add them to the Dialog Box. */ | |
5110 buttonDITL = GetResource ('DITL', 130); | |
5111 buttonChar = buttons; | |
5112 button = 0; | |
5113 | |
5114 for (;*buttonChar != 0;) | |
5115 { | |
5116 /* Get the name of the button */ | |
5117 button++; | |
5118 len = 0; | |
5119 for (;((*buttonChar != DLG_BUTTON_SEP) && (*buttonChar != 0) && (len < 255)); buttonChar++) | |
5120 { | |
5121 if (*buttonChar != DLG_HOTKEY_CHAR) | |
5122 name[++len] = *buttonChar; | |
5123 } | |
5124 if (*buttonChar != 0) | |
5125 buttonChar++; | |
5126 name[0] = len; | |
5127 | |
5128 /* Add the button */ | |
5129 AppendDITL (theDialog, buttonDITL, overlayDITL); /* appendDITLRight); */ | |
5130 | |
5131 /* Change the button's name */ | |
5132 macSetDialogItemText (theDialog, button, name); | |
5133 | |
5134 /* Resize the button to fit its name */ | |
5135 width = StringWidth (name) + 2 * dfltButtonEdge; | |
5136 /* Limite the size of any button to an acceptable value. */ | |
5137 /* TODO: Should be based on the message width */ | |
5138 if (width > maxButtonWidth) | |
5139 width = maxButtonWidth; | |
5140 macSizeDialogItem (theDialog, button, width, 0); | |
5141 | |
5142 totalButtonWidth += width; | |
5143 | |
5144 if (width > widestButton) | |
5145 widestButton = width; | |
5146 } | |
5147 ReleaseResource (buttonDITL); | |
5148 lastButton = button; | |
5149 | |
5150 /* Add the icon to the Dialog Box. */ | |
5151 iconItm.idx = lastButton + 1; | |
5152 iconDITL = GetResource ('DITL', 131); | |
5153 switch (type) | |
5154 { | |
5155 case VIM_GENERIC: useIcon = kNoteIcon; | |
5156 case VIM_ERROR: useIcon = kStopIcon; | |
5157 case VIM_WARNING: useIcon = kCautionIcon; | |
5158 case VIM_INFO: useIcon = kNoteIcon; | |
5159 case VIM_QUESTION: useIcon = kNoteIcon; | |
5160 default: useIcon = kStopIcon; | |
5161 }; | |
5162 AppendDITL (theDialog, iconDITL, overlayDITL); | |
5163 ReleaseResource (iconDITL); | |
5164 GetDialogItem (theDialog, iconItm.idx, &itemType, &itemHandle, &box); | |
5165 /* TODO: Should the item be freed? */ | |
5166 iconHandle = GetIcon (useIcon); | |
5167 SetDialogItem (theDialog, iconItm.idx, itemType, iconHandle, &box); | |
5168 | |
5169 /* Add the message to the Dialog box. */ | |
5170 messageItm.idx = lastButton + 2; | |
5171 messageDITL = GetResource ('DITL', 132); | |
5172 AppendDITL (theDialog, messageDITL, overlayDITL); | |
5173 ReleaseResource (messageDITL); | |
5174 GetDialogItem (theDialog, messageItm.idx, &itemType, &itemHandle, &box); | |
5175 (void) C2PascalString (message, &name); | |
5176 SetDialogItemText (itemHandle, name); | |
5177 messageItm.width = StringWidth (name); | |
5178 | |
5179 /* Add the input box if needed */ | |
5180 if (textfield != NULL) | |
5181 { | |
5182 /* Cheat for now reuse the message and convet to text edit */ | |
5183 inputItm.idx = lastButton + 3; | |
5184 inputDITL = GetResource ('DITL', 132); | |
5185 AppendDITL (theDialog, inputDITL, overlayDITL); | |
5186 ReleaseResource (inputDITL); | |
5187 GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &box); | |
5188 /* SetDialogItem (theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &box);*/ | |
5189 (void) C2PascalString (textfield, &name); | |
5190 SetDialogItemText (itemHandle, name); | |
5191 inputItm.width = StringWidth (name); | |
5192 } | |
5193 | |
5194 /* Set the <ENTER> and <ESC> button. */ | |
5195 SetDialogDefaultItem (theDialog, dfltbutton); | |
5196 SetDialogCancelItem (theDialog, 0); | |
5197 | |
5198 /* Reposition element */ | |
5199 | |
5200 /* Check if we need to force vertical */ | |
5201 if (totalButtonWidth > maximumWidth) | |
5202 vertical = TRUE; | |
5203 | |
5204 /* Place icon */ | |
5205 macMoveDialogItem (theDialog, iconItm.idx, dfltIconSideSpace, dfltElementSpacing, &box); | |
5206 iconItm.box.right = box.right; | |
5207 iconItm.box.bottom = box.bottom; | |
5208 | |
5209 /* Place Message */ | |
5210 messageItm.box.left = iconItm.box.right + dfltIconSideSpace; | |
5211 macSizeDialogItem (theDialog, messageItm.idx, 0, messageLines * (textFontInfo.ascent + textFontInfo.descent)); | |
5212 macMoveDialogItem (theDialog, messageItm.idx, messageItm.box.left, dfltElementSpacing, &messageItm.box); | |
5213 | |
5214 /* Place Input */ | |
5215 if (textfield != NULL) | |
5216 { | |
5217 inputItm.box.left = messageItm.box.left; | |
5218 inputItm.box.top = messageItm.box.bottom + dfltElementSpacing; | |
5219 macSizeDialogItem (theDialog, inputItm.idx, 0, textFontInfo.ascent + textFontInfo.descent); | |
5220 macMoveDialogItem (theDialog, inputItm.idx, inputItm.box.left, inputItm.box.top, &inputItm.box); | |
5221 /* Convert the static text into a text edit. | |
5222 * For some reason this change need to be done last (Dany) */ | |
5223 GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &inputItm.box); | |
5224 SetDialogItem (theDialog, inputItm.idx, kEditTextDialogItem, itemHandle, &inputItm.box); | |
5225 SelectDialogItemText(theDialog, inputItm.idx, 0, 32767); | |
5226 } | |
5227 | |
5228 /* Place Button */ | |
5229 if (textfield != NULL) | |
5230 { | |
5231 buttonItm.box.left = inputItm.box.left; | |
5232 buttonItm.box.top = inputItm.box.bottom + dfltElementSpacing; | |
5233 } | |
5234 else | |
5235 { | |
5236 buttonItm.box.left = messageItm.box.left; | |
5237 buttonItm.box.top = messageItm.box.bottom + dfltElementSpacing; | |
5238 } | |
5239 | |
5240 for (button=1; button <= lastButton; button++) | |
5241 { | |
5242 | |
5243 macMoveDialogItem (theDialog, button, buttonItm.box.left, buttonItm.box.top, &box); | |
5244 /* With vertical, it's better to have all button the same lenght */ | |
5245 if (vertical) | |
5246 { | |
5247 macSizeDialogItem (theDialog, button, widestButton, 0); | |
5248 GetDialogItem (theDialog, button, &itemType, &itemHandle, &box); | |
5249 } | |
5250 /* Calculate position of next button */ | |
5251 if (vertical) | |
5252 buttonItm.box.top = box.bottom + dfltElementSpacing; | |
5253 else | |
5254 buttonItm.box.left = box.right + dfltElementSpacing; | |
5255 } | |
5256 | |
5257 /* Resize the dialog box */ | |
5258 dialogHeight = box.bottom + dfltElementSpacing; | |
5259 SizeWindow(theWindow, maximumWidth, dialogHeight, TRUE); | |
5260 | |
5261 #ifdef USE_CARBONIZED | |
5262 /* Magic resize */ | |
5263 AutoSizeDialog (theDialog); | |
5264 /* Need a horizontal resize anyway so not that useful */ | |
5265 #endif | |
5266 | |
5267 /* Display it */ | |
5268 ShowWindow(theWindow); | |
5269 /* BringToFront(theWindow); */ | |
5270 SelectWindow(theWindow); | |
5271 | |
5272 /* DrawDialog (theDialog); */ | |
5273 #if 0 | |
5274 GetPort (&oldPort); | |
5275 #ifdef USE_CARBONIZED | |
5276 SetPortDialogPort (theDialog); | |
5277 #else | |
5278 SetPort (theDialog); | |
5279 #endif | |
5280 #endif | |
5281 | |
5282 /* Hang until one of the button is hit */ | |
5283 do | |
5284 { | |
5285 ModalDialog (nil, &itemHit); | |
5286 } while ((itemHit < 1) || (itemHit > lastButton)); | |
5287 | |
5288 /* Copy back the text entered by the user into the param */ | |
5289 if (textfield != NULL) | |
5290 { | |
5291 GetDialogItem (theDialog, inputItm.idx, &itemType, &itemHandle, &box); | |
5292 GetDialogItemText (itemHandle, (char_u *) &name); | |
5293 #if IOSIZE < 256 | |
5294 /* Truncate the name to IOSIZE if needed */ | |
5295 if (name[0] > IOSIZE) | |
5296 name[0] = IOSIZE - 1; | |
5297 #endif | |
5298 STRNCPY(textfield, &name[1], name[0]); | |
5299 textfield[name[0]] = NUL; | |
5300 } | |
5301 | |
5302 /* Restore the original graphical port */ | |
5303 SetPort (oldPort); | |
5304 | |
5305 /* Get ride of th edialog (free memory) */ | |
5306 DisposeDialog (theDialog); | |
5307 | |
5308 return itemHit; | |
5309 /* | |
5310 * Usefull thing which could be used | |
5311 * SetDialogTimeout(): Auto click a button after timeout | |
5312 * SetDialogTracksCursor() : Get the I-beam cursor over input box | |
5313 * MoveDialogItem(): Probably better than SetDialogItem | |
5314 * SizeDialogItem(): (but is it Carbon Only?) | |
5315 * AutoSizeDialog(): Magic resize of dialog based on text lenght | |
5316 */ | |
5317 } | |
5318 #endif /* FEAT_DIALOG_GUI */ | |
5319 | |
5320 /* | |
5321 * Display the saved error message(s). | |
5322 */ | |
5323 #ifdef USE_MCH_ERRMSG | |
5324 void | |
5325 display_errors() | |
5326 { | |
5327 char *p; | |
5328 char_u pError[256]; | |
5329 | |
5330 if (error_ga.ga_data != NULL) | |
5331 { | |
5332 /* avoid putting up a message box with blanks only */ | |
5333 for (p = (char *)error_ga.ga_data; *p; ++p) | |
5334 if (!isspace(*p)) | |
5335 { | |
5336 if (STRLEN(p) > 255) | |
5337 pError[0] = 255; | |
5338 else | |
5339 pError[0] = STRLEN(p); | |
5340 | |
5341 STRNCPY(&pError[1], p, pError[0]); | |
5342 ParamText (pError, nil, nil, nil); | |
5343 Alert (128, nil); | |
5344 break; | |
5345 /* TODO: handled message longer than 256 chars | |
5346 * use auto-sizeable alert | |
5347 * or dialog with scrollbars (TextEdit zone) | |
5348 */ | |
5349 } | |
5350 ga_clear(&error_ga); | |
5351 } | |
5352 } | |
5353 #endif | |
5354 | |
5355 /* | |
5356 * Get current y mouse coordinate in text window. | |
5357 * Return -1 when unknown. | |
5358 */ | |
5359 int | |
5360 gui_mch_get_mouse_x() | |
5361 { | |
5362 Point where; | |
5363 | |
5364 GetMouse(&where); | |
5365 | |
5366 return (where.h); | |
5367 } | |
5368 | |
5369 int | |
5370 gui_mch_get_mouse_y() | |
5371 { | |
5372 Point where; | |
5373 | |
5374 GetMouse(&where); | |
5375 | |
5376 return (where.v); | |
5377 } | |
5378 | |
5379 void | |
5380 gui_mch_setmouse(x, y) | |
5381 int x; | |
5382 int y; | |
5383 { | |
5384 /* TODO */ | |
5385 #if 0 | |
5386 /* From FAQ 3-11 */ | |
5387 | |
5388 CursorDevicePtr myMouse; | |
5389 Point where; | |
5390 | |
5391 if ( NGetTrapAddress (_CursorDeviceDispatch, ToolTrap) | |
5392 != NGetTrapAddress (_Unimplemented, ToolTrap) ) | |
5393 { | |
5394 /* New way */ | |
5395 | |
5396 /* | |
5397 * Get first devoice with one button. | |
5398 * This will probably be the standad mouse | |
5399 * startat head of cursor dev list | |
5400 * | |
5401 */ | |
5402 | |
5403 myMouse = nil; | |
5404 | |
5405 do | |
5406 { | |
5407 /* Get the next cursor device */ | |
5408 CursorDeviceNextDevice(&myMouse); | |
5409 } | |
5410 while ( (myMouse != nil) && (myMouse->cntButtons != 1) ); | |
5411 | |
5412 CursorDeviceMoveTo (myMouse, x, y); | |
5413 } | |
5414 else | |
5415 { | |
5416 /* Old way */ | |
5417 where.h = x; | |
5418 where.v = y; | |
5419 | |
5420 *(Point *)RawMouse = where; | |
5421 *(Point *)MTemp = where; | |
5422 *(Ptr) CrsrNew = 0xFFFF; | |
5423 } | |
5424 #endif | |
5425 } | |
5426 | |
5427 void | |
5428 gui_mch_show_popupmenu(menu) | |
5429 vimmenu_T *menu; | |
5430 { | |
5431 #ifdef USE_CTRLCLICKMENU | |
5432 /* | |
5433 * Clone PopUp to use menu | |
5434 * Create a object descriptor for the current selection | |
5435 * Call the procedure | |
5436 */ | |
5437 | |
5438 MenuHandle CntxMenu; | |
5439 Point where; | |
5440 OSStatus status; | |
5441 UInt32 CntxType; | |
5442 SInt16 CntxMenuID; | |
5443 UInt16 CntxMenuItem; | |
5444 Str255 HelpName = ""; | |
5445 GrafPtr savePort; | |
5446 | |
5447 /* Save Current Port: On MacOS X we seem to lose the port */ | |
5448 GetPort (&savePort); /*OSX*/ | |
5449 | |
5450 GetMouse (&where); | |
5451 LocalToGlobal (&where); /*OSX*/ | |
5452 CntxMenu = menu->submenu_handle; | |
5453 | |
5454 /* TODO: Get the text selection from Vim */ | |
5455 | |
5456 /* Call to Handle Popup */ | |
5457 status = ContextualMenuSelect(CntxMenu, where, false, kCMHelpItemNoHelp, HelpName, NULL, &CntxType, &CntxMenuID, &CntxMenuItem); | |
5458 | |
5459 if (status == noErr) | |
5460 { | |
5461 if (CntxType == kCMMenuItemSelected) | |
5462 { | |
5463 /* Handle the menu CntxMenuID, CntxMenuItem */ | |
5464 /* The submenu can be handle directly by gui_mac_handle_menu */ | |
5465 /* But what about the current menu, is the menu changed by ContextualMenuSelect */ | |
5466 gui_mac_handle_menu ((CntxMenuID << 16) + CntxMenuItem); | |
5467 } | |
5468 else if (CntxMenuID == kCMShowHelpSelected) | |
5469 { | |
5470 /* Should come up with the help */ | |
5471 } | |
5472 } | |
5473 | |
5474 /* Restore original Port */ | |
5475 SetPort (savePort); /*OSX*/ | |
5476 #endif | |
5477 } | |
5478 | |
5479 #if defined(FEAT_CW_EDITOR) || defined(PROTO) | |
5480 /* TODO: Is it need for MACOS_X? (Dany) */ | |
5481 void | |
5482 mch_post_buffer_write(buf_T *buf) | |
5483 { | |
5484 # ifdef USE_SIOUX | |
5485 printf ("Writing Buf...\n"); | |
5486 # endif | |
5487 GetFSSpecFromPath (buf->b_ffname, &buf->b_FSSpec); | |
5488 Send_KAHL_MOD_AE (buf); | |
5489 } | |
5490 #endif | |
5491 | |
5492 #ifdef FEAT_TITLE | |
5493 /* | |
5494 * Set the window title and icon. | |
5495 * (The icon is not taken care of). | |
5496 */ | |
5497 void | |
5498 gui_mch_settitle(title, icon) | |
5499 char_u *title; | |
5500 char_u *icon; | |
5501 { | |
5502 /* TODO: Get vim to make sure maxlen (from p_titlelen) is smaller | |
5503 * that 256. Even better get it to fit nicely in the titlebar. | |
5504 */ | |
5505 char_u *pascalTitle; | |
5506 | |
5507 if (title == NULL) /* nothing to do */ | |
5508 return; | |
5509 | |
5510 pascalTitle = C2Pascal_save(title); | |
5511 if (pascalTitle != NULL) | |
5512 { | |
5513 SetWTitle(gui.VimWindow, pascalTitle); | |
5514 vim_free(pascalTitle); | |
5515 } | |
5516 } | |
5517 #endif | |
5518 | |
5519 /* | |
5520 * Transfered from os_mac.c for MacOS X using os_unix.c prep work | |
5521 */ | |
5522 | |
5523 int | |
5524 C2PascalString (CString, PascalString) | |
5525 char_u *CString; | |
5526 Str255 *PascalString; | |
5527 { | |
5528 char_u *PascalPtr = (char_u *) PascalString; | |
5529 int len; | |
5530 int i; | |
5531 | |
5532 PascalPtr[0] = 0; | |
5533 if (CString == NULL) | |
5534 return 0; | |
5535 | |
5536 len = STRLEN(CString); | |
5537 if (len > 255) | |
5538 len = 255; | |
5539 | |
5540 for (i = 0; i < len; i++) | |
5541 PascalPtr[i+1] = CString[i]; | |
5542 | |
5543 PascalPtr[0] = len; | |
5544 | |
5545 return 0; | |
5546 } | |
5547 | |
5548 int | |
5549 GetFSSpecFromPath (file, fileFSSpec) | |
5550 char_u *file; | |
5551 FSSpec *fileFSSpec; | |
5552 { | |
5553 /* From FAQ 8-12 */ | |
5554 Str255 filePascal; | |
5555 CInfoPBRec myCPB; | |
5556 OSErr err; | |
5557 | |
5558 (void) C2PascalString (file, &filePascal); | |
5559 | |
5560 myCPB.dirInfo.ioNamePtr = filePascal; | |
5561 myCPB.dirInfo.ioVRefNum = 0; | |
5562 myCPB.dirInfo.ioFDirIndex = 0; | |
5563 myCPB.dirInfo.ioDrDirID = 0; | |
5564 | |
5565 err= PBGetCatInfo (&myCPB, false); | |
5566 | |
5567 /* vRefNum, dirID, name */ | |
5568 FSMakeFSSpec (0, 0, filePascal, fileFSSpec); | |
5569 | |
5570 /* TODO: Use an error code mechanism */ | |
5571 return 0; | |
5572 } | |
5573 | |
5574 /* | |
5575 * Convert a FSSpec to a fuill path | |
5576 */ | |
5577 | |
5578 char_u *FullPathFromFSSpec_save (FSSpec file) | |
5579 { | |
5580 /* | |
5581 * TODO: Add protection for 256 char max. | |
5582 */ | |
5583 | |
5584 CInfoPBRec theCPB; | |
5585 char_u fname[256]; | |
5586 char_u *filenamePtr = fname; | |
5587 OSErr error; | |
5588 int folder = 1; | |
5589 #ifdef USE_UNIXFILENAME | |
5590 SInt16 dfltVol_vRefNum; | |
5591 SInt32 dfltVol_dirID; | |
5592 FSRef refFile; | |
5593 OSStatus status; | |
5594 UInt32 pathSize = 256; | |
5595 char_u pathname[256]; | |
5596 char_u *path = pathname; | |
5597 #else | |
5598 Str255 directoryName; | |
5599 char_u temporary[255]; | |
5600 char_u *temporaryPtr = temporary; | |
5601 #endif | |
5602 | |
5603 #ifdef USE_UNIXFILENAME | |
5604 /* Get the default volume */ | |
5605 /* TODO: Remove as this only work if Vim is on the Boot Volume*/ | |
5606 error=HGetVol ( NULL, &dfltVol_vRefNum, &dfltVol_dirID ); | |
5607 | |
5608 if (error) | |
5609 return NULL; | |
5610 #endif | |
5611 | |
5612 /* Start filling fname with file.name */ | |
5613 STRNCPY(filenamePtr, &file.name[1], file.name[0]); | |
5614 filenamePtr[file.name[0]] = 0; /* NULL terminate the string */ | |
5615 | |
5616 /* Get the info about the file specified in FSSpec */ | |
5617 theCPB.dirInfo.ioFDirIndex = 0; | |
5618 theCPB.dirInfo.ioNamePtr = file.name; | |
5619 theCPB.dirInfo.ioVRefNum = file.vRefNum; | |
5620 /*theCPB.hFileInfo.ioDirID = 0;*/ | |
5621 theCPB.dirInfo.ioDrDirID = file.parID; | |
5622 | |
5623 /* As ioFDirIndex = 0, get the info of ioNamePtr, | |
5624 which is relative to ioVrefNum, ioDirID */ | |
5625 error = PBGetCatInfo (&theCPB, false); | |
5626 | |
5627 /* If we are called for a new file we expect fnfErr */ | |
5628 if ((error) && (error != fnfErr)) | |
5629 return NULL; | |
5630 | |
5631 /* Check if it's a file or folder */ | |
5632 /* default to file if file don't exist */ | |
5633 if (((theCPB.hFileInfo.ioFlAttrib & ioDirMask) == 0) || (error)) | |
5634 folder = 0; /* It's not a folder */ | |
5635 else | |
5636 folder = 1; | |
5637 | |
5638 #ifdef USE_UNIXFILENAME | |
5639 /* | |
5640 * The function used here are available in Carbon, but | |
5641 * do nothing une MacOS 8 and 9 | |
5642 */ | |
5643 if (error == fnfErr) | |
5644 { | |
5645 /* If the file to be saved does not already exist, it isn't possible | |
5646 to convert its FSSpec into an FSRef. But we can construct an | |
5647 FSSpec for the file's parent folder (since we have its volume and | |
5648 directory IDs), and since that folder does exist, we can convert | |
5649 that FSSpec into an FSRef, convert the FSRef in turn into a path, | |
5650 and, finally, append the filename. */ | |
5651 FSSpec dirSpec; | |
5652 FSRef dirRef; | |
5653 Str255 emptyFilename = "\p"; | |
5654 error = FSMakeFSSpec(theCPB.dirInfo.ioVRefNum, | |
5655 theCPB.dirInfo.ioDrDirID, emptyFilename, &dirSpec); | |
5656 if (error) | |
5657 return NULL; | |
5658 | |
5659 error = FSpMakeFSRef(&dirSpec, &dirRef); | |
5660 if (error) | |
5661 return NULL; | |
5662 | |
5663 status = FSRefMakePath(&dirRef, (UInt8*)path, pathSize); | |
5664 if (status) | |
5665 return NULL; | |
5666 | |
5667 STRCAT(path, "/"); | |
5668 STRCAT(path, filenamePtr); | |
5669 } | |
5670 else | |
5671 { | |
5672 /* If the file to be saved already exists, we can get its full path | |
5673 by converting its FSSpec into an FSRef. */ | |
5674 error=FSpMakeFSRef (&file, &refFile); | |
5675 if (error) | |
5676 return NULL; | |
5677 | |
5678 status=FSRefMakePath (&refFile, (UInt8 *) path, pathSize); | |
5679 if (status) | |
5680 return NULL; | |
5681 } | |
5682 | |
5683 /* Add a slash at the end if needed */ | |
5684 if (folder) | |
5685 STRCAT (path, "/"); | |
5686 | |
5687 return (vim_strsave (path)); | |
5688 #else | |
5689 /* TODO: Get rid of all USE_UNIXFILENAME below */ | |
5690 /* Set ioNamePtr, it's the same area which is always reused. */ | |
5691 theCPB.dirInfo.ioNamePtr = directoryName; | |
5692 | |
5693 /* Trick for first entry, set ioDrParID to the first value | |
5694 * we want for ioDrDirID*/ | |
5695 theCPB.dirInfo.ioDrParID = file.parID; | |
5696 theCPB.dirInfo.ioDrDirID = file.parID; | |
5697 | |
5698 if ((TRUE) && (file.parID != fsRtDirID /*fsRtParID*/ )) | |
5699 do | |
5700 { | |
5701 theCPB.dirInfo.ioFDirIndex = -1; | |
5702 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */ | |
5703 theCPB.dirInfo.ioVRefNum = file.vRefNum; | |
5704 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */ | |
5705 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID; | |
5706 | |
5707 /* As ioFDirIndex = -1, get the info of ioDrDirID, */ | |
5708 /* *ioNamePtr[0 TO 31] will be updated */ | |
5709 error = PBGetCatInfo (&theCPB,false); | |
5710 | |
5711 if (error) | |
5712 return NULL; | |
5713 | |
5714 /* Put the new directoryName in front of the current fname */ | |
5715 STRCPY(temporaryPtr, filenamePtr); | |
5716 STRNCPY(filenamePtr, &directoryName[1], directoryName[0]); | |
5717 filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */ | |
5718 STRCAT(filenamePtr, ":"); | |
5719 STRCAT(filenamePtr, temporaryPtr); | |
5720 } | |
5721 #if 1 /* def USE_UNIXFILENAME */ | |
5722 while ((theCPB.dirInfo.ioDrParID != fsRtDirID) /* && */ | |
5723 /* (theCPB.dirInfo.ioDrDirID != fsRtDirID)*/); | |
5724 #else | |
5725 while (theCPB.dirInfo.ioDrDirID != fsRtDirID); | |
5726 #endif | |
5727 | |
5728 /* Get the information about the volume on which the file reside */ | |
5729 theCPB.dirInfo.ioFDirIndex = -1; | |
5730 /* theCPB.dirInfo.ioNamePtr = directoryName; Already done above. */ | |
5731 theCPB.dirInfo.ioVRefNum = file.vRefNum; | |
5732 /* theCPB.dirInfo.ioDirID = irrevelant when ioFDirIndex = -1 */ | |
5733 theCPB.dirInfo.ioDrDirID = theCPB.dirInfo.ioDrParID; | |
5734 | |
5735 /* As ioFDirIndex = -1, get the info of ioDrDirID, */ | |
5736 /* *ioNamePtr[0 TO 31] will be updated */ | |
5737 error = PBGetCatInfo (&theCPB,false); | |
5738 | |
5739 if (error) | |
5740 return NULL; | |
5741 | |
5742 /* For MacOS Classic always add the volume name */ | |
5743 /* For MacOS X add the volume name preceded by "Volumes" */ | |
5744 /* when we are not refering to the boot volume */ | |
5745 #ifdef USE_UNIXFILENAME | |
5746 if (file.vRefNum != dfltVol_vRefNum) | |
5747 #endif | |
5748 { | |
5749 /* Add the volume name */ | |
5750 STRCPY(temporaryPtr, filenamePtr); | |
5751 STRNCPY(filenamePtr, &directoryName[1], directoryName[0]); | |
5752 filenamePtr[directoryName[0]] = 0; /* NULL terminate the string */ | |
5753 STRCAT(filenamePtr, ":"); | |
5754 STRCAT(filenamePtr, temporaryPtr); | |
5755 | |
5756 #ifdef USE_UNIXFILENAME | |
5757 STRCPY(temporaryPtr, filenamePtr); | |
5758 filenamePtr[0] = 0; /* NULL terminate the string */ | |
5759 STRCAT(filenamePtr, "Volumes:"); | |
5760 STRCAT(filenamePtr, temporaryPtr); | |
5761 #endif | |
5762 } | |
5763 | |
5764 /* Append final path separator if it's a folder */ | |
5765 if (folder) | |
5766 STRCAT (fname, ":"); | |
5767 | |
5768 /* As we use Unix File Name for MacOS X convert it */ | |
5769 #ifdef USE_UNIXFILENAME | |
5770 /* Need to insert leading / */ | |
5771 /* TODO: get the above code to use directly the / */ | |
5772 STRCPY(&temporaryPtr[1], filenamePtr); | |
5773 temporaryPtr[0] = '/'; | |
5774 STRCPY(filenamePtr, temporaryPtr); | |
5775 { | |
5776 char *p; | |
5777 for (p = fname; *p; p++) | |
5778 if (*p == ':') | |
5779 *p = '/'; | |
5780 } | |
5781 #endif | |
5782 | |
5783 return (vim_strsave (fname)); | |
5784 #endif | |
5785 } | |
5786 | |
5787 #if defined(USE_IM_CONTROL) || defined(PROTO) | |
5788 /* | |
5789 * Input Method Control functions. | |
5790 */ | |
5791 | |
5792 /* | |
5793 * Notify cursor position to IM. | |
5794 */ | |
5795 void | |
5796 im_set_position(int row, int col) | |
5797 { | |
5798 /* TODO: Implement me! */ | |
5799 } | |
5800 | |
5801 /* | |
5802 * Set IM status on ("active" is TRUE) or off ("active" is FALSE). | |
5803 */ | |
5804 void | |
5805 im_set_active(int active) | |
5806 { | |
5807 KeyScript(active ? smKeySysScript : smKeyRoman); | |
5808 } | |
5809 | |
5810 /* | |
5811 * Get IM status. When IM is on, return not 0. Else return 0. | |
5812 */ | |
5813 int | |
5814 im_get_status() | |
5815 { | |
5816 SInt32 script = GetScriptManagerVariable(smKeyScript); | |
5817 return (script != smRoman | |
5818 && script == GetScriptManagerVariable(smSysScript)) ? 1 : 0; | |
5819 } | |
5820 #endif /* defined(USE_IM_CONTROL) || defined(PROTO) */ |