Be careful not to try to get information from windows we don't own, or that
[u/mdw/putty] / mac / macpgen.c
CommitLineData
217b88d1 1/* $Id: macpgen.c,v 1.3 2003/02/16 14:27:37 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 *);
06c24bc0 74static void mac_updatewindow(WindowPtr);
06c24bc0 75static void mac_keypress(EventRecord *);
76static int mac_windowtype(WindowPtr);
77static void mac_menucommand(long);
06c24bc0 78static void mac_adjustcursor(RgnHandle);
79static void mac_adjustmenus(void);
80static void mac_closewindow(WindowPtr);
81static void mac_zoomwindow(WindowPtr, short);
82#pragma noreturn (cleanup_exit)
83
84struct mac_windows {
85 WindowPtr about;
86 WindowPtr licence;
87};
88
89struct mac_windows windows;
90int borednow;
91struct mac_gestalts mac_gestalts;
92
93int main (int argc, char **argv) {
94
95 mac_startup();
96 mac_eventloop();
97}
98
99#pragma noreturn (main)
100
101static 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)
06e0f715 125 fatalbox("PuTTYgen requires System 7 or newer");
06c24bc0 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
203static void mac_eventloop(void) {
204 Boolean gotevent;
205 EventRecord event;
206 RgnHandle cursrgn;
207
208 cursrgn = NewRgn();
209 for (;;) {
210 mac_adjustcursor(cursrgn);
211 gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
212 mac_adjustcursor(cursrgn);
213 if (gotevent)
214 mac_event(&event);
215 if (borednow)
216 cleanup_exit(0);
217 }
218 DisposeRgn(cursrgn);
219}
220
221static void mac_event(EventRecord *event) {
222 short part;
223 WindowPtr window;
224
225 switch (event->what) {
226 case mouseDown:
227 part = FindWindow(event->where, &window);
228 switch (part) {
229 case inMenuBar:
230 mac_adjustmenus();
231 mac_menucommand(MenuSelect(event->where));
232 break;
233#if !TARGET_API_MAC_CARBON
234 case inSysWindow:
235 SystemClick(event, window);
236 break;
237#endif
238 case inContent:
239 if (window != FrontWindow())
240 /* XXX: check for movable modal dboxes? */
241 SelectWindow(window);
242 else
243 mac_contentclick(window, event);
244 break;
245 case inGoAway:
246 if (TrackGoAway(window, event->where))
247 mac_closewindow(window);
248 break;
249 case inDrag:
250 /* XXX: moveable modal check? */
251#if TARGET_API_MAC_CARBON
252 {
253 BitMap screenBits;
254
255 GetQDGlobalsScreenBits(&screenBits);
256 DragWindow(window, event->where, &screenBits.bounds);
257 }
258#else
259 DragWindow(window, event->where, &qd.screenBits.bounds);
260#endif
261 break;
262 case inGrow:
263 mac_growwindow(window, event);
264 break;
265 case inZoomIn:
266 case inZoomOut:
267 if (TrackBox(window, event->where, part))
268 mac_zoomwindow(window, part);
269 break;
270 }
271 break;
272 case keyDown:
273 case autoKey:
274 mac_keypress(event);
275 break;
276 case activateEvt:
277 mac_activatewindow((WindowPtr)event->message, event);
278 break;
279 case updateEvt:
280 mac_updatewindow((WindowPtr)event->message);
281 break;
282#if !TARGET_API_MAC_CARBON
283 case diskEvt:
284 if (HiWord(event->message) != noErr) {
285 Point pt;
286
287 SetPt(&pt, 120, 120);
288 DIBadMount(pt, event->message);
289 }
290 break;
291#endif
292 case kHighLevelEvent:
293 AEProcessAppleEvent(event); /* errors? */
294 break;
295 }
296}
297
217b88d1 298static void mac_contentclick(WindowPtr window, EventRecord *event)
299{
06c24bc0 300
217b88d1 301 if (mac_wininfo(window)->click != NULL)
302 (*mac_wininfo(window)->click)(window, event);
06c24bc0 303}
304
217b88d1 305static void mac_growwindow(WindowPtr window, EventRecord *event)
306{
06c24bc0 307
217b88d1 308 if (mac_wininfo(window)->grow != NULL)
309 (*mac_wininfo(window)->grow)(window, event);
06c24bc0 310}
311
217b88d1 312static void mac_activatewindow(WindowPtr window, EventRecord *event)
313{
06c24bc0 314
06c24bc0 315 mac_adjustmenus();
217b88d1 316 if (mac_wininfo(window)->activate != NULL)
317 (*mac_wininfo(window)->activate)(window, event);
06c24bc0 318}
319
320static void mac_updatewindow(WindowPtr window)
321{
06c24bc0 322
217b88d1 323 if (mac_wininfo(window)->update != NULL)
324 (*mac_wininfo(window)->update)(window);
06c24bc0 325}
326
327/*
328 * Work out what kind of window we're dealing with.
329 */
330static int mac_windowtype(WindowPtr window)
331{
332
333#if !TARGET_API_MAC_CARBON
334 if (GetWindowKind(window) < 0)
335 return wDA;
336#endif
337 return ((WinInfo *)GetWRefCon(window))->wtype;
338}
339
340/*
341 * Handle a key press
342 */
217b88d1 343static void mac_keypress(EventRecord *event)
344{
06c24bc0 345 WindowPtr window;
346
347 window = FrontWindow();
348 if (event->what == keyDown && (event->modifiers & cmdKey)) {
349 mac_adjustmenus();
350 mac_menucommand(MenuKey(event->message & charCodeMask));
351 } else {
217b88d1 352 if (mac_wininfo(window)->key != NULL)
353 (*mac_wininfo(window)->key)(window, event);
06c24bc0 354 }
355}
356
217b88d1 357static void mac_menucommand(long result)
358{
06c24bc0 359 short menu, item;
360 WindowPtr window;
361#if !TARGET_API_MAC_CARBON
362 Str255 da;
363#endif
364
365 menu = HiWord(result);
366 item = LoWord(result);
367 window = FrontWindow();
368 /* Things which do the same whatever window we're in. */
369 switch (menu) {
370 case mApple:
371 switch (item) {
372 case iAbout:
373 mac_openabout();
374 goto done;
375#if !TARGET_API_MAC_CARBON
376 default:
377 GetMenuItemText(GetMenuHandle(mApple), item, da);
378 OpenDeskAcc(da);
379 goto done;
380#endif
381 }
382 break;
383 case mFile:
384 switch (item) {
06e0f715 385 case iNew:
386 mac_newkey();
387 goto done;
06c24bc0 388 case iClose:
389 mac_closewindow(window);
390 goto done;
391 case iQuit:
392 cleanup_exit(0);
393 goto done;
394 }
395 break;
396 }
397 /* If we get here, handling is up to window-specific code. */
217b88d1 398 if (mac_wininfo(window)->menu != NULL)
399 (*mac_wininfo(window)->menu)(window, menu, item);
400
06c24bc0 401 done:
402 HiliteMenu(0);
403}
404
217b88d1 405static void mac_closewindow(WindowPtr window)
406{
06c24bc0 407
408 switch (mac_windowtype(window)) {
409#if !TARGET_API_MAC_CARBON
410 case wDA:
411 CloseDeskAcc(GetWindowKind(window));
412 break;
413#endif
217b88d1 414 default:
415 if (mac_wininfo(window)->close != NULL)
416 (*mac_wininfo(window)->close)(window);
06c24bc0 417 }
418}
419
420static void mac_zoomwindow(WindowPtr window, short part) {
421
422 /* FIXME: do something */
423}
424
425/*
426 * Make the menus look right before the user gets to see them.
427 */
428#if TARGET_API_MAC_CARBON
429#define EnableItem EnableMenuItem
430#define DisableItem DisableMenuItem
431#endif
432static void mac_adjustmenus(void) {
433 WindowPtr window;
434 MenuHandle menu;
435
436 window = FrontWindow();
437 menu = GetMenuHandle(mApple);
438 EnableItem(menu, 0);
439 EnableItem(menu, iAbout);
440
441 menu = GetMenuHandle(mFile);
442 EnableItem(menu, 0);
443 EnableItem(menu, iNew);
444 if (window != NULL)
445 EnableItem(menu, iClose);
446 else
447 DisableItem(menu, iClose);
448 EnableItem(menu, iQuit);
449
217b88d1 450 if (mac_wininfo(window)->adjustmenus != NULL)
451 (*mac_wininfo(window)->adjustmenus)(window);
452 else {
06c24bc0 453 DisableItem(menu, iSave);
454 DisableItem(menu, iSaveAs);
455 menu = GetMenuHandle(mEdit);
456 DisableItem(menu, 0);
457 menu = GetMenuHandle(mWindow);
458 DisableItem(menu, 0); /* Until we get more than 1 item on it. */
06c24bc0 459 }
460 DrawMenuBar();
461}
462
463/*
464 * Make sure the right cursor's being displayed.
465 */
217b88d1 466static void mac_adjustcursor(RgnHandle cursrgn)
467{
06c24bc0 468 Point mouse;
469 WindowPtr window, front;
470 short part;
471#if TARGET_API_MAC_CARBON
472 Cursor arrow;
473 RgnHandle visrgn;
474#endif
475
476 GetMouse(&mouse);
477 LocalToGlobal(&mouse);
478 part = FindWindow(mouse, &window);
479 front = FrontWindow();
480 if (part != inContent || window == NULL || window != front) {
481 /* Cursor isn't in the front window, so switch to arrow */
482#if TARGET_API_MAC_CARBON
483 GetQDGlobalsArrow(&arrow);
484 SetCursor(&arrow);
485#else
486 SetCursor(&qd.arrow);
487#endif
488 SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
489 if (front != NULL) {
490#if TARGET_API_MAC_CARBON
491 visrgn = NewRgn();
492 GetPortVisibleRegion(GetWindowPort(front), visrgn);
493 DiffRgn(cursrgn, visrgn, cursrgn);
494 DisposeRgn(visrgn);
495#else
496 DiffRgn(cursrgn, front->visRgn, cursrgn);
497#endif
498 }
499 } else {
217b88d1 500 if (mac_wininfo(window)->adjustcursor != NULL)
501 (*mac_wininfo(window)->adjustcursor)(window, mouse, cursrgn);
502 else {
06c24bc0 503#if TARGET_API_MAC_CARBON
504 GetQDGlobalsArrow(&arrow);
505 SetCursor(&arrow);
506 GetPortVisibleRegion(GetWindowPort(window), cursrgn);
507#else
508 SetCursor(&qd.arrow);
509 CopyRgn(window->visRgn, cursrgn);
510#endif
06c24bc0 511 }
512 }
513}
514
515pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
516 long refcon)
517{
518 DescType type;
519 Size size;
520
521 if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
522 &type, NULL, 0, &size) == noErr)
523 return errAEParamMissed;
524
525 borednow = 1;
526 return noErr;
527}
528
529void cleanup_exit(int status)
530{
531
532#if !TARGET_RT_MAC_CFM
533 if (mac_gestalts.encvvers != 0)
534 TerminateUnicodeConverter();
535#endif
536 exit(status);
537}
538
539/*
540 * Local Variables:
541 * c-file-style: "simon"
542 * End:
543 */