Tiny amount of infrastructure for having actual keys in PuTTYgen.
[u/mdw/putty] / mac / macpgen.c
CommitLineData
06e0f715 1/* $Id: macpgen.c,v 1.2 2003/02/15 14:20:43 ben Exp $ */
06c24bc0 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
67static void mac_startup(void);
68static void mac_eventloop(void);
69#pragma noreturn (mac_eventloop)
70static void mac_event(EventRecord *);
71static void mac_contentclick(WindowPtr, EventRecord *);
72static void mac_growwindow(WindowPtr, EventRecord *);
73static void mac_activatewindow(WindowPtr, EventRecord *);
74static void mac_activateabout(WindowPtr, EventRecord *);
75static void mac_updatewindow(WindowPtr);
76static void mac_updatelicence(WindowPtr);
77static void mac_keypress(EventRecord *);
78static int mac_windowtype(WindowPtr);
79static void mac_menucommand(long);
80static void mac_openabout(void);
81static void mac_openlicence(void);
82static void mac_adjustcursor(RgnHandle);
83static void mac_adjustmenus(void);
84static void mac_closewindow(WindowPtr);
85static void mac_zoomwindow(WindowPtr, short);
86#pragma noreturn (cleanup_exit)
87
88struct mac_windows {
89 WindowPtr about;
90 WindowPtr licence;
91};
92
93struct mac_windows windows;
94int borednow;
95struct mac_gestalts mac_gestalts;
96
97int main (int argc, char **argv) {
98
99 mac_startup();
100 mac_eventloop();
101}
102
103#pragma noreturn (main)
104
105static 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)
06e0f715 129 fatalbox("PuTTYgen requires System 7 or newer");
06c24bc0 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
207static 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
225static 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
302static 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
319static void mac_growwindow(WindowPtr window, EventRecord *event) {
320
321 switch (mac_windowtype(window)) {
322 }
323}
324
325static 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
337static 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
352static 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
377static 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 */
407static 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 */
420static 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
433static 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) {
06e0f715 460 case iNew:
461 mac_newkey();
462 goto done;
06c24bc0 463 case iClose:
464 mac_closewindow(window);
465 goto done;
466 case iQuit:
467 cleanup_exit(0);
468 goto done;
469 }
470 break;
471 }
472 /* If we get here, handling is up to window-specific code. */
473 switch (mac_windowtype(window)) {
474 }
475 done:
476 HiliteMenu(0);
477}
478
479static void mac_openabout(void) {
480 DialogItemType itemtype;
481 Handle item;
482 VersRecHndl vers;
483 Rect box;
484 StringPtr longvers;
485 WinInfo *wi;
486
487 if (windows.about)
488 SelectWindow(windows.about);
489 else {
490 windows.about =
491 GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1));
492 wi = smalloc(sizeof(*wi));
493 wi->s = NULL;
494 wi->wtype = wAbout;
495 SetWRefCon(windows.about, (long)wi);
496 vers = (VersRecHndl)Get1Resource('vers', 1);
497 if (vers != NULL && *vers != NULL) {
498 longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
499 GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion,
500 &itemtype, &item, &box);
501 assert(itemtype & kStaticTextDialogItem);
502 SetDialogItemText(item, longvers);
503 }
504 ShowWindow(windows.about);
505 }
506}
507
508static void mac_openlicence(void) {
509 WinInfo *wi;
510
511 if (windows.licence)
512 SelectWindow(windows.licence);
513 else {
514 windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
515 wi = smalloc(sizeof(*wi));
516 wi->s = NULL;
517 wi->wtype = wLicence;
518 SetWRefCon(windows.licence, (long)wi);
519 ShowWindow(windows.licence);
520 }
521}
522
523static void mac_closewindow(WindowPtr window) {
524
525 switch (mac_windowtype(window)) {
526#if !TARGET_API_MAC_CARBON
527 case wDA:
528 CloseDeskAcc(GetWindowKind(window));
529 break;
530#endif
531 case wAbout:
532 windows.about = NULL;
533 DisposeDialog(GetDialogFromWindow(window));
534 break;
535 case wLicence:
536 windows.licence = NULL;
537 DisposeWindow(window);
538 break;
539 }
540}
541
542static void mac_zoomwindow(WindowPtr window, short part) {
543
544 /* FIXME: do something */
545}
546
547/*
548 * Make the menus look right before the user gets to see them.
549 */
550#if TARGET_API_MAC_CARBON
551#define EnableItem EnableMenuItem
552#define DisableItem DisableMenuItem
553#endif
554static void mac_adjustmenus(void) {
555 WindowPtr window;
556 MenuHandle menu;
557
558 window = FrontWindow();
559 menu = GetMenuHandle(mApple);
560 EnableItem(menu, 0);
561 EnableItem(menu, iAbout);
562
563 menu = GetMenuHandle(mFile);
564 EnableItem(menu, 0);
565 EnableItem(menu, iNew);
566 if (window != NULL)
567 EnableItem(menu, iClose);
568 else
569 DisableItem(menu, iClose);
570 EnableItem(menu, iQuit);
571
572 switch (mac_windowtype(window)) {
573 default:
574 DisableItem(menu, iSave);
575 DisableItem(menu, iSaveAs);
576 menu = GetMenuHandle(mEdit);
577 DisableItem(menu, 0);
578 menu = GetMenuHandle(mWindow);
579 DisableItem(menu, 0); /* Until we get more than 1 item on it. */
580 break;
581 }
582 DrawMenuBar();
583}
584
585/*
586 * Make sure the right cursor's being displayed.
587 */
588static void mac_adjustcursor(RgnHandle cursrgn) {
589 Point mouse;
590 WindowPtr window, front;
591 short part;
592#if TARGET_API_MAC_CARBON
593 Cursor arrow;
594 RgnHandle visrgn;
595#endif
596
597 GetMouse(&mouse);
598 LocalToGlobal(&mouse);
599 part = FindWindow(mouse, &window);
600 front = FrontWindow();
601 if (part != inContent || window == NULL || window != front) {
602 /* Cursor isn't in the front window, so switch to arrow */
603#if TARGET_API_MAC_CARBON
604 GetQDGlobalsArrow(&arrow);
605 SetCursor(&arrow);
606#else
607 SetCursor(&qd.arrow);
608#endif
609 SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
610 if (front != NULL) {
611#if TARGET_API_MAC_CARBON
612 visrgn = NewRgn();
613 GetPortVisibleRegion(GetWindowPort(front), visrgn);
614 DiffRgn(cursrgn, visrgn, cursrgn);
615 DisposeRgn(visrgn);
616#else
617 DiffRgn(cursrgn, front->visRgn, cursrgn);
618#endif
619 }
620 } else {
621 switch (mac_windowtype(window)) {
622 default:
623#if TARGET_API_MAC_CARBON
624 GetQDGlobalsArrow(&arrow);
625 SetCursor(&arrow);
626 GetPortVisibleRegion(GetWindowPort(window), cursrgn);
627#else
628 SetCursor(&qd.arrow);
629 CopyRgn(window->visRgn, cursrgn);
630#endif
631 break;
632 }
633 }
634}
635
636pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
637 long refcon)
638{
639 DescType type;
640 Size size;
641
642 if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
643 &type, NULL, 0, &size) == noErr)
644 return errAEParamMissed;
645
646 borednow = 1;
647 return noErr;
648}
649
650void cleanup_exit(int status)
651{
652
653#if !TARGET_RT_MAC_CFM
654 if (mac_gestalts.encvvers != 0)
655 TerminateUnicodeConverter();
656#endif
657 exit(status);
658}
659
660/*
661 * Local Variables:
662 * c-file-style: "simon"
663 * End:
664 */