Add a mechanism for collecting entropy, and displaying how much we've got,
[u/mdw/putty] / mac / macpgen.c
1 /* $Id: macpgen.c,v 1.4 2003/02/20 22:55:09 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_updatewindow(WindowPtr);
75 static void mac_keypress(EventRecord *);
76 static int mac_windowtype(WindowPtr);
77 static void mac_menucommand(long);
78 static void mac_adjustcursor(RgnHandle);
79 static void mac_adjustmenus(void);
80 static void mac_closewindow(WindowPtr);
81 static void mac_zoomwindow(WindowPtr, short);
82 #pragma noreturn (cleanup_exit)
83
84 struct mac_windows {
85 WindowPtr about;
86 WindowPtr licence;
87 };
88
89 struct mac_windows windows;
90 int borednow;
91 struct mac_gestalts mac_gestalts;
92
93 int main (int argc, char **argv) {
94
95 mac_startup();
96 mac_eventloop();
97 }
98
99 #pragma noreturn (main)
100
101 static void mac_startup(void) {
102 Handle menuBar;
103 TECInfoHandle ti;
104
105 #if !TARGET_API_MAC_CARBON
106 /* Init Memory Manager */
107 MaxApplZone();
108 /* Init QuickDraw */
109 InitGraf(&qd.thePort);
110 /* Init Font Manager */
111 InitFonts();
112 /* Init Window Manager */
113 InitWindows();
114 /* Init Menu Manager */
115 InitMenus();
116 /* Init TextEdit */
117 TEInit();
118 /* Init Dialog Manager */
119 InitDialogs(NULL);
120 #endif
121
122 /* Get base system version (only used if there's no better selector) */
123 if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
124 (mac_gestalts.sysvers &= 0xffff) < 0x700)
125 fatalbox("PuTTYgen requires System 7 or newer");
126 /* Find out if we've got Color Quickdraw */
127 if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
128 mac_gestalts.qdvers = gestaltOriginalQD;
129 /* ... and the Appearance Manager? */
130 if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
131 if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
132 mac_gestalts.apprvers = 0x0100;
133 else
134 mac_gestalts.apprvers = 0;
135 #if TARGET_RT_MAC_CFM
136 /* Paranoia: Did we manage to pull in AppearanceLib? */
137 if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
138 mac_gestalts.apprvers = 0;
139 #endif
140 #if TARGET_CPU_68K
141 mac_gestalts.cntlattr = 0;
142 mac_gestalts.windattr = 0;
143 #else
144 /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
145 if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
146 &SetControlViewSize == kUnresolvedCFragSymbolAddress)
147 mac_gestalts.cntlattr = 0;
148 /* Mac OS 8.5 Window Manager? */
149 if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
150 &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
151 mac_gestalts.windattr = 0;
152 #endif
153 /* Text Encoding Conversion Manager? */
154 if (
155 #if TARGET_RT_MAC_CFM
156 &TECGetInfo == kUnresolvedCFragSymbolAddress ||
157 #else
158 InitializeUnicodeConverter(NULL) != noErr ||
159 #endif
160 TECGetInfo(&ti) != noErr)
161 mac_gestalts.encvvers = 0;
162 else {
163 mac_gestalts.encvvers = (*ti)->tecVersion;
164 mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
165 DisposeHandle((Handle)ti);
166 }
167 /* Navigation Services? */
168 if (NavServicesAvailable())
169 mac_gestalts.navsvers = NavLibraryVersion();
170 else
171 mac_gestalts.navsvers = 0;
172
173 /* We've been tested with the Appearance Manager */
174 if (mac_gestalts.apprvers != 0)
175 RegisterAppearanceClient();
176
177 menuBar = GetNewMBar(128);
178 if (menuBar == NULL)
179 fatalbox("Unable to create menu bar.");
180 SetMenuBar(menuBar);
181 AppendResMenu(GetMenuHandle(mApple), 'DRVR');
182 mac_adjustmenus();
183 DrawMenuBar();
184 InitCursor();
185 windows.about = NULL;
186 windows.licence = NULL;
187
188 flags = FLAG_INTERACTIVE;
189
190 /* Install Apple Event handlers. */
191 #if 0
192 AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
193 NewAEEventHandlerUPP(&mac_aevt_oapp), 0, FALSE);
194 AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
195 NewAEEventHandlerUPP(&mac_aevt_odoc), 0, FALSE);
196 AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
197 NewAEEventHandlerUPP(&mac_aevt_pdoc), 0, FALSE);
198 #endif
199 AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
200 NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE);
201 }
202
203 static void mac_eventloop(void) {
204 Boolean gotevent;
205 EventRecord event;
206 RgnHandle cursrgn;
207 Point mousenow, mousethen;
208 KeyState *ks;
209 WindowPtr front;
210
211 cursrgn = NewRgn();
212 GetMouse(&mousethen);
213 for (;;) {
214 mac_adjustcursor(cursrgn);
215 gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
216 mac_adjustcursor(cursrgn);
217 front = mac_frontwindow();
218 if (front != NULL) {
219 ks = mac_windowkey(front);
220 if (ks->collecting_entropy) {
221 GetMouse(&mousenow);
222 if (mousenow.h != mousethen.h || mousenow.v != mousethen.v) {
223 ks->entropy[ks->entropy_got++] = *(unsigned *)&mousenow;
224 ks->entropy[ks->entropy_got++] = TickCount();
225 if (ks->entropy_got >= ks->entropy_required)
226 ks->collecting_entropy = 0;
227 SetControlValue(ks->progress, ks->entropy_got);
228 mousethen = mousenow;
229 }
230 SetEmptyRgn(cursrgn);
231 }
232 }
233
234 if (gotevent)
235 mac_event(&event);
236 if (borednow)
237 cleanup_exit(0);
238 }
239 DisposeRgn(cursrgn);
240 }
241
242 static void mac_event(EventRecord *event) {
243 short part;
244 WindowPtr window;
245
246 switch (event->what) {
247 case mouseDown:
248 part = FindWindow(event->where, &window);
249 switch (part) {
250 case inMenuBar:
251 mac_adjustmenus();
252 mac_menucommand(MenuSelect(event->where));
253 break;
254 #if !TARGET_API_MAC_CARBON
255 case inSysWindow:
256 SystemClick(event, window);
257 break;
258 #endif
259 case inContent:
260 if (window != FrontWindow())
261 /* XXX: check for movable modal dboxes? */
262 SelectWindow(window);
263 else
264 mac_contentclick(window, event);
265 break;
266 case inGoAway:
267 if (TrackGoAway(window, event->where))
268 mac_closewindow(window);
269 break;
270 case inDrag:
271 /* XXX: moveable modal check? */
272 #if TARGET_API_MAC_CARBON
273 {
274 BitMap screenBits;
275
276 GetQDGlobalsScreenBits(&screenBits);
277 DragWindow(window, event->where, &screenBits.bounds);
278 }
279 #else
280 DragWindow(window, event->where, &qd.screenBits.bounds);
281 #endif
282 break;
283 case inGrow:
284 mac_growwindow(window, event);
285 break;
286 case inZoomIn:
287 case inZoomOut:
288 if (TrackBox(window, event->where, part))
289 mac_zoomwindow(window, part);
290 break;
291 }
292 break;
293 case keyDown:
294 case autoKey:
295 mac_keypress(event);
296 break;
297 case activateEvt:
298 mac_activatewindow((WindowPtr)event->message, event);
299 break;
300 case updateEvt:
301 mac_updatewindow((WindowPtr)event->message);
302 break;
303 #if !TARGET_API_MAC_CARBON
304 case diskEvt:
305 if (HiWord(event->message) != noErr) {
306 Point pt;
307
308 SetPt(&pt, 120, 120);
309 DIBadMount(pt, event->message);
310 }
311 break;
312 #endif
313 case kHighLevelEvent:
314 AEProcessAppleEvent(event); /* errors? */
315 break;
316 }
317 }
318
319 static void mac_contentclick(WindowPtr window, EventRecord *event)
320 {
321
322 if (mac_wininfo(window)->click != NULL)
323 (*mac_wininfo(window)->click)(window, event);
324 }
325
326 static void mac_growwindow(WindowPtr window, EventRecord *event)
327 {
328
329 if (mac_wininfo(window)->grow != NULL)
330 (*mac_wininfo(window)->grow)(window, event);
331 }
332
333 static void mac_activatewindow(WindowPtr window, EventRecord *event)
334 {
335
336 mac_adjustmenus();
337 if (mac_wininfo(window)->activate != NULL)
338 (*mac_wininfo(window)->activate)(window, event);
339 }
340
341 static void mac_updatewindow(WindowPtr window)
342 {
343
344 if (mac_wininfo(window)->update != NULL)
345 (*mac_wininfo(window)->update)(window);
346 }
347
348 /*
349 * Work out what kind of window we're dealing with.
350 */
351 static int mac_windowtype(WindowPtr window)
352 {
353
354 #if !TARGET_API_MAC_CARBON
355 if (GetWindowKind(window) < 0)
356 return wDA;
357 #endif
358 return ((WinInfo *)GetWRefCon(window))->wtype;
359 }
360
361 /*
362 * Handle a key press
363 */
364 static void mac_keypress(EventRecord *event)
365 {
366 WindowPtr window;
367
368 window = FrontWindow();
369 if (event->what == keyDown && (event->modifiers & cmdKey)) {
370 mac_adjustmenus();
371 mac_menucommand(MenuKey(event->message & charCodeMask));
372 } else {
373 if (mac_wininfo(window)->key != NULL)
374 (*mac_wininfo(window)->key)(window, event);
375 }
376 }
377
378 static void mac_menucommand(long result)
379 {
380 short menu, item;
381 WindowPtr window;
382 #if !TARGET_API_MAC_CARBON
383 Str255 da;
384 #endif
385
386 menu = HiWord(result);
387 item = LoWord(result);
388 window = FrontWindow();
389 /* Things which do the same whatever window we're in. */
390 switch (menu) {
391 case mApple:
392 switch (item) {
393 case iAbout:
394 mac_openabout();
395 goto done;
396 #if !TARGET_API_MAC_CARBON
397 default:
398 GetMenuItemText(GetMenuHandle(mApple), item, da);
399 OpenDeskAcc(da);
400 goto done;
401 #endif
402 }
403 break;
404 case mFile:
405 switch (item) {
406 case iNew:
407 mac_newkey();
408 goto done;
409 case iClose:
410 mac_closewindow(window);
411 goto done;
412 case iQuit:
413 cleanup_exit(0);
414 goto done;
415 }
416 break;
417 }
418 /* If we get here, handling is up to window-specific code. */
419 if (mac_wininfo(window)->menu != NULL)
420 (*mac_wininfo(window)->menu)(window, menu, item);
421
422 done:
423 HiliteMenu(0);
424 }
425
426 static void mac_closewindow(WindowPtr window)
427 {
428
429 switch (mac_windowtype(window)) {
430 #if !TARGET_API_MAC_CARBON
431 case wDA:
432 CloseDeskAcc(GetWindowKind(window));
433 break;
434 #endif
435 default:
436 if (mac_wininfo(window)->close != NULL)
437 (*mac_wininfo(window)->close)(window);
438 }
439 }
440
441 static void mac_zoomwindow(WindowPtr window, short part) {
442
443 /* FIXME: do something */
444 }
445
446 /*
447 * Make the menus look right before the user gets to see them.
448 */
449 #if TARGET_API_MAC_CARBON
450 #define EnableItem EnableMenuItem
451 #define DisableItem DisableMenuItem
452 #endif
453 static void mac_adjustmenus(void) {
454 WindowPtr window;
455 MenuHandle menu;
456
457 window = FrontWindow();
458 menu = GetMenuHandle(mApple);
459 EnableItem(menu, 0);
460 EnableItem(menu, iAbout);
461
462 menu = GetMenuHandle(mFile);
463 EnableItem(menu, 0);
464 EnableItem(menu, iNew);
465 if (window != NULL)
466 EnableItem(menu, iClose);
467 else
468 DisableItem(menu, iClose);
469 EnableItem(menu, iQuit);
470
471 if (mac_wininfo(window)->adjustmenus != NULL)
472 (*mac_wininfo(window)->adjustmenus)(window);
473 else {
474 DisableItem(menu, iSave);
475 DisableItem(menu, iSaveAs);
476 menu = GetMenuHandle(mEdit);
477 DisableItem(menu, 0);
478 menu = GetMenuHandle(mWindow);
479 DisableItem(menu, 0); /* Until we get more than 1 item on it. */
480 }
481 DrawMenuBar();
482 }
483
484 /*
485 * Make sure the right cursor's being displayed.
486 */
487 static void mac_adjustcursor(RgnHandle cursrgn)
488 {
489 Point mouse;
490 WindowPtr window, front;
491 short part;
492 #if TARGET_API_MAC_CARBON
493 Cursor arrow;
494 RgnHandle visrgn;
495 #endif
496
497 GetMouse(&mouse);
498 LocalToGlobal(&mouse);
499 part = FindWindow(mouse, &window);
500 front = FrontWindow();
501 if (part != inContent || window == NULL || window != front) {
502 /* Cursor isn't in the front window, so switch to arrow */
503 #if TARGET_API_MAC_CARBON
504 GetQDGlobalsArrow(&arrow);
505 SetCursor(&arrow);
506 #else
507 SetCursor(&qd.arrow);
508 #endif
509 SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
510 if (front != NULL) {
511 #if TARGET_API_MAC_CARBON
512 visrgn = NewRgn();
513 GetPortVisibleRegion(GetWindowPort(front), visrgn);
514 DiffRgn(cursrgn, visrgn, cursrgn);
515 DisposeRgn(visrgn);
516 #else
517 DiffRgn(cursrgn, front->visRgn, cursrgn);
518 #endif
519 }
520 } else {
521 if (mac_wininfo(window)->adjustcursor != NULL)
522 (*mac_wininfo(window)->adjustcursor)(window, mouse, cursrgn);
523 else {
524 #if TARGET_API_MAC_CARBON
525 GetQDGlobalsArrow(&arrow);
526 SetCursor(&arrow);
527 GetPortVisibleRegion(GetWindowPort(window), cursrgn);
528 #else
529 SetCursor(&qd.arrow);
530 CopyRgn(window->visRgn, cursrgn);
531 #endif
532 }
533 }
534 }
535
536 pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
537 long refcon)
538 {
539 DescType type;
540 Size size;
541
542 if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
543 &type, NULL, 0, &size) == noErr)
544 return errAEParamMissed;
545
546 borednow = 1;
547 return noErr;
548 }
549
550 void cleanup_exit(int status)
551 {
552
553 #if !TARGET_RT_MAC_CFM
554 if (mac_gestalts.encvvers != 0)
555 TerminateUnicodeConverter();
556 #endif
557 exit(status);
558 }
559
560 /*
561 * Local Variables:
562 * c-file-style: "simon"
563 * End:
564 */