8c6aa2a8e88ad32cc427172f481b1ddeb6d74cfb
[sgt/putty] / mac / macpgen.c
1 /* $Id: macpgen.c,v 1.1 2003/02/12 23:53:15 ben Exp $ */
2 /*
3 * Copyright (c) 1999, 2003 Ben Harris
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 /*
29 * macpgen.c - PuTTYgen for Mac OS
30 */
31
32 #include <MacTypes.h>
33 #include <AEDataModel.h>
34 #include <AppleEvents.h>
35 #include <Quickdraw.h>
36 #include <Fonts.h>
37 #include <MacWindows.h>
38 #include <Menus.h>
39 #include <TextEdit.h>
40 #include <Appearance.h>
41 #include <CodeFragments.h>
42 #include <Dialogs.h>
43 #include <Devices.h>
44 #include <DiskInit.h>
45 #include <Gestalt.h>
46 #include <LowMem.h>
47 #include <Navigation.h>
48 #include <Resources.h>
49 #include <Script.h>
50 #include <TextCommon.h>
51 #include <ToolUtils.h>
52 #include <UnicodeConverter.h>
53
54 #include <assert.h>
55 #include <limits.h>
56 #include <stdarg.h>
57 #include <stdlib.h> /* putty.h needs size_t */
58 #include <stdio.h> /* for vsprintf */
59
60 #define PUTTY_DO_GLOBALS
61
62 #include "macpgrid.h"
63 #include "putty.h"
64 #include "ssh.h"
65 #include "mac.h"
66
67 static void mac_startup(void);
68 static void mac_eventloop(void);
69 #pragma noreturn (mac_eventloop)
70 static void mac_event(EventRecord *);
71 static void mac_contentclick(WindowPtr, EventRecord *);
72 static void mac_growwindow(WindowPtr, EventRecord *);
73 static void mac_activatewindow(WindowPtr, EventRecord *);
74 static void mac_activateabout(WindowPtr, EventRecord *);
75 static void mac_updatewindow(WindowPtr);
76 static void mac_updatelicence(WindowPtr);
77 static void mac_keypress(EventRecord *);
78 static int mac_windowtype(WindowPtr);
79 static void mac_menucommand(long);
80 static void mac_openabout(void);
81 static void mac_openlicence(void);
82 static void mac_adjustcursor(RgnHandle);
83 static void mac_adjustmenus(void);
84 static void mac_closewindow(WindowPtr);
85 static void mac_zoomwindow(WindowPtr, short);
86 #pragma noreturn (cleanup_exit)
87
88 struct mac_windows {
89 WindowPtr about;
90 WindowPtr licence;
91 };
92
93 struct mac_windows windows;
94 int borednow;
95 struct mac_gestalts mac_gestalts;
96
97 int main (int argc, char **argv) {
98
99 mac_startup();
100 mac_eventloop();
101 }
102
103 #pragma noreturn (main)
104
105 static void mac_startup(void) {
106 Handle menuBar;
107 TECInfoHandle ti;
108
109 #if !TARGET_API_MAC_CARBON
110 /* Init Memory Manager */
111 MaxApplZone();
112 /* Init QuickDraw */
113 InitGraf(&qd.thePort);
114 /* Init Font Manager */
115 InitFonts();
116 /* Init Window Manager */
117 InitWindows();
118 /* Init Menu Manager */
119 InitMenus();
120 /* Init TextEdit */
121 TEInit();
122 /* Init Dialog Manager */
123 InitDialogs(NULL);
124 #endif
125
126 /* Get base system version (only used if there's no better selector) */
127 if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
128 (mac_gestalts.sysvers &= 0xffff) < 0x700)
129 fatalbox("PuTTY requires System 7 or newer");
130 /* Find out if we've got Color Quickdraw */
131 if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
132 mac_gestalts.qdvers = gestaltOriginalQD;
133 /* ... and the Appearance Manager? */
134 if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
135 if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
136 mac_gestalts.apprvers = 0x0100;
137 else
138 mac_gestalts.apprvers = 0;
139 #if TARGET_RT_MAC_CFM
140 /* Paranoia: Did we manage to pull in AppearanceLib? */
141 if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
142 mac_gestalts.apprvers = 0;
143 #endif
144 #if TARGET_CPU_68K
145 mac_gestalts.cntlattr = 0;
146 mac_gestalts.windattr = 0;
147 #else
148 /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
149 if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
150 &SetControlViewSize == kUnresolvedCFragSymbolAddress)
151 mac_gestalts.cntlattr = 0;
152 /* Mac OS 8.5 Window Manager? */
153 if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
154 &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
155 mac_gestalts.windattr = 0;
156 #endif
157 /* Text Encoding Conversion Manager? */
158 if (
159 #if TARGET_RT_MAC_CFM
160 &TECGetInfo == kUnresolvedCFragSymbolAddress ||
161 #else
162 InitializeUnicodeConverter(NULL) != noErr ||
163 #endif
164 TECGetInfo(&ti) != noErr)
165 mac_gestalts.encvvers = 0;
166 else {
167 mac_gestalts.encvvers = (*ti)->tecVersion;
168 mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
169 DisposeHandle((Handle)ti);
170 }
171 /* Navigation Services? */
172 if (NavServicesAvailable())
173 mac_gestalts.navsvers = NavLibraryVersion();
174 else
175 mac_gestalts.navsvers = 0;
176
177 /* We've been tested with the Appearance Manager */
178 if (mac_gestalts.apprvers != 0)
179 RegisterAppearanceClient();
180
181 menuBar = GetNewMBar(128);
182 if (menuBar == NULL)
183 fatalbox("Unable to create menu bar.");
184 SetMenuBar(menuBar);
185 AppendResMenu(GetMenuHandle(mApple), 'DRVR');
186 mac_adjustmenus();
187 DrawMenuBar();
188 InitCursor();
189 windows.about = NULL;
190 windows.licence = NULL;
191
192 flags = FLAG_INTERACTIVE;
193
194 /* Install Apple Event handlers. */
195 #if 0
196 AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
197 NewAEEventHandlerUPP(&mac_aevt_oapp), 0, FALSE);
198 AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
199 NewAEEventHandlerUPP(&mac_aevt_odoc), 0, FALSE);
200 AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
201 NewAEEventHandlerUPP(&mac_aevt_pdoc), 0, FALSE);
202 #endif
203 AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
204 NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE);
205 }
206
207 static void mac_eventloop(void) {
208 Boolean gotevent;
209 EventRecord event;
210 RgnHandle cursrgn;
211
212 cursrgn = NewRgn();
213 for (;;) {
214 mac_adjustcursor(cursrgn);
215 gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
216 mac_adjustcursor(cursrgn);
217 if (gotevent)
218 mac_event(&event);
219 if (borednow)
220 cleanup_exit(0);
221 }
222 DisposeRgn(cursrgn);
223 }
224
225 static void mac_event(EventRecord *event) {
226 short part;
227 WindowPtr window;
228
229 switch (event->what) {
230 case mouseDown:
231 part = FindWindow(event->where, &window);
232 switch (part) {
233 case inMenuBar:
234 mac_adjustmenus();
235 mac_menucommand(MenuSelect(event->where));
236 break;
237 #if !TARGET_API_MAC_CARBON
238 case inSysWindow:
239 SystemClick(event, window);
240 break;
241 #endif
242 case inContent:
243 if (window != FrontWindow())
244 /* XXX: check for movable modal dboxes? */
245 SelectWindow(window);
246 else
247 mac_contentclick(window, event);
248 break;
249 case inGoAway:
250 if (TrackGoAway(window, event->where))
251 mac_closewindow(window);
252 break;
253 case inDrag:
254 /* XXX: moveable modal check? */
255 #if TARGET_API_MAC_CARBON
256 {
257 BitMap screenBits;
258
259 GetQDGlobalsScreenBits(&screenBits);
260 DragWindow(window, event->where, &screenBits.bounds);
261 }
262 #else
263 DragWindow(window, event->where, &qd.screenBits.bounds);
264 #endif
265 break;
266 case inGrow:
267 mac_growwindow(window, event);
268 break;
269 case inZoomIn:
270 case inZoomOut:
271 if (TrackBox(window, event->where, part))
272 mac_zoomwindow(window, part);
273 break;
274 }
275 break;
276 case keyDown:
277 case autoKey:
278 mac_keypress(event);
279 break;
280 case activateEvt:
281 mac_activatewindow((WindowPtr)event->message, event);
282 break;
283 case updateEvt:
284 mac_updatewindow((WindowPtr)event->message);
285 break;
286 #if !TARGET_API_MAC_CARBON
287 case diskEvt:
288 if (HiWord(event->message) != noErr) {
289 Point pt;
290
291 SetPt(&pt, 120, 120);
292 DIBadMount(pt, event->message);
293 }
294 break;
295 #endif
296 case kHighLevelEvent:
297 AEProcessAppleEvent(event); /* errors? */
298 break;
299 }
300 }
301
302 static void mac_contentclick(WindowPtr window, EventRecord *event) {
303 short item;
304 DialogRef dialog;
305
306 switch (mac_windowtype(window)) {
307 case wAbout:
308 dialog = GetDialogFromWindow(window);
309 if (DialogSelect(event, &dialog, &item))
310 switch (item) {
311 case wiAboutLicence:
312 mac_openlicence();
313 break;
314 }
315 break;
316 }
317 }
318
319 static void mac_growwindow(WindowPtr window, EventRecord *event) {
320
321 switch (mac_windowtype(window)) {
322 }
323 }
324
325 static void mac_activatewindow(WindowPtr window, EventRecord *event) {
326 int active;
327
328 active = (event->modifiers & activeFlag) != 0;
329 mac_adjustmenus();
330 switch (mac_windowtype(window)) {
331 case wAbout:
332 mac_activateabout(window, event);
333 break;
334 }
335 }
336
337 static void mac_activateabout(WindowPtr window, EventRecord *event) {
338 DialogRef dialog;
339 DialogItemType itemtype;
340 Handle itemhandle;
341 short item;
342 Rect itemrect;
343 int active;
344
345 dialog = GetDialogFromWindow(window);
346 active = (event->modifiers & activeFlag) != 0;
347 GetDialogItem(dialog, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
348 HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
349 DialogSelect(event, &dialog, &item);
350 }
351
352 static void mac_updatewindow(WindowPtr window)
353 {
354 #if TARGET_API_MAC_CARBON
355 RgnHandle rgn;
356 #endif
357
358 switch (mac_windowtype(window)) {
359 case wAbout:
360 BeginUpdate(window);
361 #if TARGET_API_MAC_CARBON
362 rgn = NewRgn();
363 GetPortVisibleRegion(GetWindowPort(window), rgn);
364 UpdateDialog(GetDialogFromWindow(window), rgn);
365 DisposeRgn(rgn);
366 #else
367 UpdateDialog(window, window->visRgn);
368 #endif
369 EndUpdate(window);
370 break;
371 case wLicence:
372 mac_updatelicence(window);
373 break;
374 }
375 }
376
377 static void mac_updatelicence(WindowPtr window)
378 {
379 Handle h;
380 int len;
381 long fondsize;
382 Rect textrect;
383
384 SetPort((GrafPtr)GetWindowPort(window));
385 BeginUpdate(window);
386 fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
387 TextFont(HiWord(fondsize));
388 TextSize(LoWord(fondsize));
389 h = Get1Resource('TEXT', wLicence);
390 len = GetResourceSizeOnDisk(h);
391 #if TARGET_API_MAC_CARBON
392 GetPortBounds(GetWindowPort(window), &textrect);
393 #else
394 textrect = window->portRect;
395 #endif
396 if (h != NULL) {
397 HLock(h);
398 TETextBox(*h, len, &textrect, teFlushDefault);
399 HUnlock(h);
400 }
401 EndUpdate(window);
402 }
403
404 /*
405 * Work out what kind of window we're dealing with.
406 */
407 static int mac_windowtype(WindowPtr window)
408 {
409
410 #if !TARGET_API_MAC_CARBON
411 if (GetWindowKind(window) < 0)
412 return wDA;
413 #endif
414 return ((WinInfo *)GetWRefCon(window))->wtype;
415 }
416
417 /*
418 * Handle a key press
419 */
420 static void mac_keypress(EventRecord *event) {
421 WindowPtr window;
422
423 window = FrontWindow();
424 if (event->what == keyDown && (event->modifiers & cmdKey)) {
425 mac_adjustmenus();
426 mac_menucommand(MenuKey(event->message & charCodeMask));
427 } else {
428 switch (mac_windowtype(window)) {
429 }
430 }
431 }
432
433 static void mac_menucommand(long result) {
434 short menu, item;
435 WindowPtr window;
436 #if !TARGET_API_MAC_CARBON
437 Str255 da;
438 #endif
439
440 menu = HiWord(result);
441 item = LoWord(result);
442 window = FrontWindow();
443 /* Things which do the same whatever window we're in. */
444 switch (menu) {
445 case mApple:
446 switch (item) {
447 case iAbout:
448 mac_openabout();
449 goto done;
450 #if !TARGET_API_MAC_CARBON
451 default:
452 GetMenuItemText(GetMenuHandle(mApple), item, da);
453 OpenDeskAcc(da);
454 goto done;
455 #endif
456 }
457 break;
458 case mFile:
459 switch (item) {
460 case iClose:
461 mac_closewindow(window);
462 goto done;
463 case iQuit:
464 cleanup_exit(0);
465 goto done;
466 }
467 break;
468 }
469 /* If we get here, handling is up to window-specific code. */
470 switch (mac_windowtype(window)) {
471 }
472 done:
473 HiliteMenu(0);
474 }
475
476 static void mac_openabout(void) {
477 DialogItemType itemtype;
478 Handle item;
479 VersRecHndl vers;
480 Rect box;
481 StringPtr longvers;
482 WinInfo *wi;
483
484 if (windows.about)
485 SelectWindow(windows.about);
486 else {
487 windows.about =
488 GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1));
489 wi = smalloc(sizeof(*wi));
490 wi->s = NULL;
491 wi->wtype = wAbout;
492 SetWRefCon(windows.about, (long)wi);
493 vers = (VersRecHndl)Get1Resource('vers', 1);
494 if (vers != NULL && *vers != NULL) {
495 longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
496 GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion,
497 &itemtype, &item, &box);
498 assert(itemtype & kStaticTextDialogItem);
499 SetDialogItemText(item, longvers);
500 }
501 ShowWindow(windows.about);
502 }
503 }
504
505 static void mac_openlicence(void) {
506 WinInfo *wi;
507
508 if (windows.licence)
509 SelectWindow(windows.licence);
510 else {
511 windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
512 wi = smalloc(sizeof(*wi));
513 wi->s = NULL;
514 wi->wtype = wLicence;
515 SetWRefCon(windows.licence, (long)wi);
516 ShowWindow(windows.licence);
517 }
518 }
519
520 static void mac_closewindow(WindowPtr window) {
521
522 switch (mac_windowtype(window)) {
523 #if !TARGET_API_MAC_CARBON
524 case wDA:
525 CloseDeskAcc(GetWindowKind(window));
526 break;
527 #endif
528 case wAbout:
529 windows.about = NULL;
530 DisposeDialog(GetDialogFromWindow(window));
531 break;
532 case wLicence:
533 windows.licence = NULL;
534 DisposeWindow(window);
535 break;
536 }
537 }
538
539 static void mac_zoomwindow(WindowPtr window, short part) {
540
541 /* FIXME: do something */
542 }
543
544 /*
545 * Make the menus look right before the user gets to see them.
546 */
547 #if TARGET_API_MAC_CARBON
548 #define EnableItem EnableMenuItem
549 #define DisableItem DisableMenuItem
550 #endif
551 static void mac_adjustmenus(void) {
552 WindowPtr window;
553 MenuHandle menu;
554
555 window = FrontWindow();
556 menu = GetMenuHandle(mApple);
557 EnableItem(menu, 0);
558 EnableItem(menu, iAbout);
559
560 menu = GetMenuHandle(mFile);
561 EnableItem(menu, 0);
562 EnableItem(menu, iNew);
563 if (window != NULL)
564 EnableItem(menu, iClose);
565 else
566 DisableItem(menu, iClose);
567 EnableItem(menu, iQuit);
568
569 switch (mac_windowtype(window)) {
570 default:
571 DisableItem(menu, iSave);
572 DisableItem(menu, iSaveAs);
573 menu = GetMenuHandle(mEdit);
574 DisableItem(menu, 0);
575 menu = GetMenuHandle(mWindow);
576 DisableItem(menu, 0); /* Until we get more than 1 item on it. */
577 break;
578 }
579 DrawMenuBar();
580 }
581
582 /*
583 * Make sure the right cursor's being displayed.
584 */
585 static void mac_adjustcursor(RgnHandle cursrgn) {
586 Point mouse;
587 WindowPtr window, front;
588 short part;
589 #if TARGET_API_MAC_CARBON
590 Cursor arrow;
591 RgnHandle visrgn;
592 #endif
593
594 GetMouse(&mouse);
595 LocalToGlobal(&mouse);
596 part = FindWindow(mouse, &window);
597 front = FrontWindow();
598 if (part != inContent || window == NULL || window != front) {
599 /* Cursor isn't in the front window, so switch to arrow */
600 #if TARGET_API_MAC_CARBON
601 GetQDGlobalsArrow(&arrow);
602 SetCursor(&arrow);
603 #else
604 SetCursor(&qd.arrow);
605 #endif
606 SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
607 if (front != NULL) {
608 #if TARGET_API_MAC_CARBON
609 visrgn = NewRgn();
610 GetPortVisibleRegion(GetWindowPort(front), visrgn);
611 DiffRgn(cursrgn, visrgn, cursrgn);
612 DisposeRgn(visrgn);
613 #else
614 DiffRgn(cursrgn, front->visRgn, cursrgn);
615 #endif
616 }
617 } else {
618 switch (mac_windowtype(window)) {
619 default:
620 #if TARGET_API_MAC_CARBON
621 GetQDGlobalsArrow(&arrow);
622 SetCursor(&arrow);
623 GetPortVisibleRegion(GetWindowPort(window), cursrgn);
624 #else
625 SetCursor(&qd.arrow);
626 CopyRgn(window->visRgn, cursrgn);
627 #endif
628 break;
629 }
630 }
631 }
632
633 pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
634 long refcon)
635 {
636 DescType type;
637 Size size;
638
639 if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
640 &type, NULL, 0, &size) == noErr)
641 return errAEParamMissed;
642
643 borednow = 1;
644 return noErr;
645 }
646
647 void cleanup_exit(int status)
648 {
649
650 #if !TARGET_RT_MAC_CFM
651 if (mac_gestalts.encvvers != 0)
652 TerminateUnicodeConverter();
653 #endif
654 exit(status);
655 }
656
657 /*
658 * Local Variables:
659 * c-file-style: "simon"
660 * End:
661 */