]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/mac.c
b3df4838ea5e4cfcb5b426713a7c46009370d269
[PuTTY.git] / mac / mac.c
1 /* $Id: mac.c,v 1.17 2003/01/04 12:45:11 ben Exp $ */
2 /*
3  * Copyright (c) 1999 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  * mac.c -- miscellaneous Mac-specific routines
29  */
30
31 #include <MacTypes.h>
32 #include <Quickdraw.h>
33 #include <Fonts.h>
34 #include <MacWindows.h>
35 #include <Menus.h>
36 #include <TextEdit.h>
37 #include <Appearance.h>
38 #include <CodeFragments.h>
39 #include <Dialogs.h>
40 #include <Devices.h>
41 #include <DiskInit.h>
42 #include <Gestalt.h>
43 #include <LowMem.h>
44 #include <Resources.h>
45 #include <Script.h>
46 #include <TextCommon.h>
47 #include <ToolUtils.h>
48 #include <UnicodeConverter.h>
49
50 #include <assert.h>
51 #include <limits.h>
52 #include <stdarg.h>
53 #include <stdlib.h>             /* putty.h needs size_t */
54 #include <stdio.h>              /* for vsprintf */
55
56 #define PUTTY_DO_GLOBALS
57
58 #include "macresid.h"
59 #include "putty.h"
60 #include "mac.h"
61
62 QDGlobals qd;
63
64 static int cold = 1;
65 struct mac_gestalts mac_gestalts;
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 static void mac_shutdown(void);
87 #pragma noreturn (mac_shutdown)
88
89 struct mac_windows {
90     WindowPtr about;
91     WindowPtr licence;
92 };
93
94 struct mac_windows windows;
95
96 int main (int argc, char **argv) {
97
98     mac_startup();
99     mac_eventloop();
100 }
101
102 #pragma noreturn (main)
103
104 static void mac_startup(void) {
105     Handle menuBar;
106     TECInfoHandle ti;
107
108     /* Init Memory Manager */
109     MaxApplZone();
110     /* Init QuickDraw */
111     InitGraf(&qd.thePort);
112     /* Init Font Manager */
113     InitFonts();
114     /* Init Window Manager */
115     InitWindows();
116     /* Init Menu Manager */
117     InitMenus();
118     /* Init TextEdit */
119     TEInit();
120     /* Init Dialog Manager */
121     InitDialogs(NULL);
122     cold = 0;
123     
124     /* Get base system version (only used if there's no better selector) */
125     if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
126         (mac_gestalts.sysvers &= 0xffff) < 0x700)
127         fatalbox("PuTTY requires System 7 or newer");
128     /* Find out if we've got Color Quickdraw */
129     if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
130         mac_gestalts.qdvers = gestaltOriginalQD;
131     /* ... and the Appearance Manager? */
132     if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
133         if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
134             mac_gestalts.apprvers = 0x0100;
135         else
136             mac_gestalts.apprvers = 0;
137 #if TARGET_RT_MAC_CFM
138     /* Paranoia: Did we manage to pull in AppearanceLib? */
139     if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
140         mac_gestalts.apprvers = 0;
141 #endif
142 #if TARGET_CPU_68K
143     mac_gestalts.cntlattr = 0;
144     mac_gestalts.windattr = 0;
145 #else
146     /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
147     if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
148         &SetControlViewSize == kUnresolvedCFragSymbolAddress)
149         mac_gestalts.cntlattr = 0;
150     /* Mac OS 8.5 Window Manager? */
151     if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
152         &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
153         mac_gestalts.windattr = 0;
154 #endif
155     /* Text Encoding Conversion Manager? */
156     if (
157 #if TARGET_RT_MAC_CFM
158         &TECGetInfo == kUnresolvedCFragSymbolAddress ||
159 #else
160         InitializeUnicodeConverter(NULL) != noErr ||
161 #endif
162         TECGetInfo(&ti) != noErr)
163         mac_gestalts.encvvers = 0;
164     else {
165         mac_gestalts.encvvers = (*ti)->tecVersion;
166         mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
167         DisposeHandle((Handle)ti);
168     }
169
170     /* We've been tested with the Appearance Manager */
171     if (mac_gestalts.apprvers != 0)
172         RegisterAppearanceClient();
173
174     menuBar = GetNewMBar(128);
175     if (menuBar == NULL)
176         fatalbox("Unable to create menu bar.");
177     SetMenuBar(menuBar);
178     AppendResMenu(GetMenuHandle(mApple), 'DRVR');
179     mac_adjustmenus();
180     DrawMenuBar();
181     InitCursor();
182     windows.about = NULL;
183     windows.licence = NULL;
184
185     {
186         short vol;
187         long dirid;
188
189         /* Set the default directory for loading and saving settings. */
190         /* XXX Should we create it? */
191         if (get_session_dir(FALSE, &vol, &dirid) == noErr) {
192             LMSetSFSaveDisk(-vol);
193             LMSetCurDirStore(dirid);
194         }
195     }
196     init_ucs();
197 }
198
199 static void mac_eventloop(void) {
200     Boolean gotevent;
201     EventRecord event;
202     RgnHandle cursrgn;
203
204     cursrgn = NewRgn();
205     for (;;) {
206         mac_adjustcursor(cursrgn);
207         gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
208         mac_adjustcursor(cursrgn);
209         if (gotevent)
210             mac_event(&event);
211     }
212     DisposeRgn(cursrgn);
213 }
214
215 static void mac_event(EventRecord *event) {
216     short part;
217     WindowPtr window;
218     Point pt;
219
220     switch (event->what) {
221       case mouseDown:
222         part = FindWindow(event->where, &window);
223         switch (part) {
224           case inMenuBar:
225             mac_adjustmenus();
226             mac_menucommand(MenuSelect(event->where));
227             break;
228           case inSysWindow:
229             SystemClick(event, window);
230             break;
231           case inContent:
232             if (window != FrontWindow())
233                 /* XXX: check for movable modal dboxes? */
234                 SelectWindow(window);
235             else
236                 mac_contentclick(window, event);
237             break;
238           case inGoAway:
239             if (TrackGoAway(window, event->where))
240                 mac_closewindow(window);
241             break;
242           case inDrag:
243             /* XXX: moveable modal check? */
244             DragWindow(window, event->where, &qd.screenBits.bounds);
245             break;
246           case inGrow:
247             mac_growwindow(window, event);
248             break;
249           case inZoomIn:
250           case inZoomOut:
251             if (TrackBox(window, event->where, part))
252                 mac_zoomwindow(window, part);
253             break;
254         }
255         break;
256       case keyDown:
257       case autoKey:
258         mac_keypress(event);
259         break;
260       case activateEvt:
261         mac_activatewindow((WindowPtr)event->message, event);
262         break;
263       case updateEvt:
264         mac_updatewindow((WindowPtr)event->message);
265         break;
266       case diskEvt:
267         if (HiWord(event->message) != noErr) {
268             SetPt(&pt, 120, 120);
269             DIBadMount(pt, event->message);
270         }
271         break;
272     }
273 }
274
275 static void mac_contentclick(WindowPtr window, EventRecord *event) {
276     short item;
277
278     switch (mac_windowtype(window)) {
279       case wTerminal:
280         mac_clickterm(window, event);
281         break;
282       case wAbout:
283         if (DialogSelect(event, &window, &item))
284             switch (item) {
285               case wiAboutLicence:
286                 mac_openlicence();
287                 break;
288             }
289         break;
290       case wSettings:
291         mac_clickdlg(window, event);
292         break;
293     }
294 }
295
296 static void mac_growwindow(WindowPtr window, EventRecord *event) {
297
298     switch (mac_windowtype(window)) {
299       case wTerminal:
300         mac_growterm(window, event);
301     }
302 }
303
304 static void mac_activatewindow(WindowPtr window, EventRecord *event) {
305     int active;
306
307     active = (event->modifiers & activeFlag) != 0;
308     mac_adjustmenus();
309     switch (mac_windowtype(window)) {
310       case wTerminal:
311         mac_activateterm(window, active);
312         break;
313       case wSettings:
314         mac_activatedlg(window, event);
315         break;
316       case wAbout:
317         mac_activateabout(window, event);
318         break;
319     }
320 }
321
322 static void mac_activateabout(WindowPtr window, EventRecord *event) {
323     DialogItemType itemtype;
324     Handle itemhandle;
325     short item;
326     Rect itemrect;
327     int active;
328
329     active = (event->modifiers & activeFlag) != 0;
330     GetDialogItem(window, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
331     HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
332     DialogSelect(event, &window, &item);
333 }
334
335 static void mac_updatewindow(WindowPtr window) {
336
337     switch (mac_windowtype(window)) {
338       case wTerminal:
339         mac_updateterm(window);
340         break;
341       case wAbout:
342       case wSettings:
343         BeginUpdate(window);
344         UpdateDialog(window, window->visRgn);
345         EndUpdate(window);
346         break;
347       case wLicence:
348         mac_updatelicence(window);
349         break;
350     }
351 }
352
353 static void mac_updatelicence(WindowPtr window)
354 {
355     Handle h;
356     int len;
357     long fondsize;
358
359     SetPort(window);
360     BeginUpdate(window);
361     fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
362     TextFont(HiWord(fondsize));
363     TextSize(LoWord(fondsize));
364     h = Get1Resource('TEXT', wLicence);
365     len = GetResourceSizeOnDisk(h);
366     if (h != NULL) {
367         HLock(h);
368         TETextBox(*h, len, &window->portRect, teFlushDefault);
369         HUnlock(h);
370     }
371     EndUpdate(window);
372 }
373
374 /*
375  * Work out what kind of window we're dealing with.
376  * Concept shamelessly nicked from SurfWriter.
377  */
378 static int mac_windowtype(WindowPtr window) {
379     int kind;
380     long refcon;
381
382     if (window == NULL)
383         return wNone;
384     kind = ((WindowPeek)window)->windowKind;
385     if (kind < 0)
386         return wDA;
387     if (GetWVariant(window) == zoomDocProc)
388         return wTerminal;
389     refcon = GetWRefCon(window);
390     if (refcon < 1024)
391         return refcon;
392     else
393         return wSettings;
394 }
395
396 /*
397  * Handle a key press
398  */
399 static void mac_keypress(EventRecord *event) {
400     WindowPtr window;
401
402     window = FrontWindow();
403     /*
404      * Check for a command-key combination, but ignore it if it counts
405      * as a meta-key combination and we're in a terminal window.
406      */
407     if (event->what == keyDown && (event->modifiers & cmdKey) /*&&
408         !((event->modifiers & cfg.meta_modifiers) == cfg.meta_modifiers &&
409             mac_windowtype(window) == wTerminal)*/) {
410         mac_adjustmenus();
411         mac_menucommand(MenuKey(event->message & charCodeMask));
412     } else {
413         switch (mac_windowtype(window)) {
414           case wTerminal:
415             mac_keyterm(window, event);
416             break;
417         }
418     }       
419 }
420
421 static void mac_menucommand(long result) {
422     short menu, item;
423     Str255 da;
424     WindowPtr window;
425
426     menu = HiWord(result);
427     item = LoWord(result);
428     window = FrontWindow();
429     /* Things which do the same whatever window we're in. */
430     switch (menu) {
431       case mApple:
432         switch (item) {
433           case iAbout:
434             mac_openabout();
435             goto done;
436           default:
437             GetMenuItemText(GetMenuHandle(mApple), item, da);
438             OpenDeskAcc(da);
439             goto done;
440         }
441         break;
442       case mFile:
443         switch (item) {
444           case iNew:
445             mac_newsession();
446             goto done;
447           case iOpen:
448             mac_opensession();
449             goto done;
450           case iClose:
451             mac_closewindow(window);
452             goto done;
453           case iQuit:
454             mac_shutdown();
455             goto done;
456         }
457         break;
458     }
459     /* If we get here, handling is up to window-specific code. */
460     switch (mac_windowtype(window)) {
461       case wTerminal:
462         mac_menuterm(window, menu, item);
463         break;
464     }
465   done:
466     HiliteMenu(0);
467 }
468
469 static void mac_openabout(void) {
470     DialogItemType itemtype;
471     Handle item;
472     VersRecHndl vers;
473     Rect box;
474     StringPtr longvers;
475
476     if (windows.about)
477         SelectWindow(windows.about);
478     else {
479         windows.about = GetNewDialog(wAbout, NULL, (WindowPtr)-1);
480         vers = (VersRecHndl)Get1Resource('vers', 1);
481         if (vers != NULL && *vers != NULL) {
482             longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
483             GetDialogItem(windows.about, wiAboutVersion,
484                           &itemtype, &item, &box);
485             assert(itemtype & kStaticTextDialogItem);
486             SetDialogItemText(item, longvers);
487         }
488         ShowWindow(windows.about);
489     }
490 }
491
492 static void mac_openlicence(void) {
493
494     if (windows.licence)
495         SelectWindow(windows.licence);
496     else {
497         windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
498         ShowWindow(windows.licence);
499     }
500 }
501
502 static void mac_closewindow(WindowPtr window) {
503
504     switch (mac_windowtype(window)) {
505       case wDA:
506         CloseDeskAcc(((WindowPeek)window)->windowKind);
507         break;
508       case wTerminal:
509         /* FIXME: end session and stuff */
510         break;
511       case wAbout:
512         windows.about = NULL;
513         CloseWindow(window);
514         break;
515       case wLicence:
516         windows.licence = NULL;
517         CloseWindow(window);
518         break;
519       default:
520         CloseWindow(window);
521         break;
522     }
523 }
524
525 static void mac_zoomwindow(WindowPtr window, short part) {
526
527     /* FIXME: do something */
528 }
529
530 /*
531  * Make the menus look right before the user gets to see them.
532  */
533 static void mac_adjustmenus(void) {
534     WindowPtr window;
535     MenuHandle menu;
536
537     window = FrontWindow();
538     menu = GetMenuHandle(mApple);
539     EnableItem(menu, 0);
540     EnableItem(menu, iAbout);
541
542     menu = GetMenuHandle(mFile);
543     EnableItem(menu, 0);
544     EnableItem(menu, iNew);
545     if (window != NULL)
546         EnableItem(menu, iClose);
547     else
548         DisableItem(menu, iClose);
549     EnableItem(menu, iQuit);
550
551     switch (mac_windowtype(window)) {
552       case wTerminal:
553         mac_adjusttermmenus(window);
554         break;
555       default:
556         menu = GetMenuHandle(mEdit);
557         DisableItem(menu, 0);
558         break;
559     }
560     DrawMenuBar();
561 }
562
563 /*
564  * Make sure the right cursor's being displayed.
565  */
566 static void mac_adjustcursor(RgnHandle cursrgn) {
567     Point mouse;
568     WindowPtr window, front;
569     short part;
570
571     GetMouse(&mouse);
572     LocalToGlobal(&mouse);
573     part = FindWindow(mouse, &window);
574     front = FrontWindow();
575     if (part != inContent || window == NULL || window != front) {
576         /* Cursor isn't in the front window, so switch to arrow */
577         SetCursor(&qd.arrow);
578         SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
579         if (front != NULL)
580             DiffRgn(cursrgn, front->visRgn, cursrgn);
581     } else {
582         switch (mac_windowtype(window)) {
583           case wTerminal:
584             mac_adjusttermcursor(window, mouse, cursrgn);
585             break;
586           default:
587             SetCursor(&qd.arrow);
588             CopyRgn(window->visRgn, cursrgn);
589             break;
590         }
591     }
592 }
593
594 static void mac_shutdown(void) {
595
596 #if !TARGET_RT_MAC_CFM
597     if (mac_gestalts.encvvers != 0)
598         TerminateUnicodeConverter();
599 #endif
600     exit(0);
601 }
602
603 void fatalbox(char *fmt, ...) {
604     va_list ap;
605     Str255 stuff;
606     
607     va_start(ap, fmt);
608     /* We'd like stuff to be a Pascal string */
609     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
610     va_end(ap);
611     ParamText(stuff, NULL, NULL, NULL);
612     StopAlert(128, NULL);
613     exit(1);
614 }
615
616 void modalfatalbox(char *fmt, ...) {
617     va_list ap;
618     Str255 stuff;
619     
620     va_start(ap, fmt);
621     /* We'd like stuff to be a Pascal string */
622     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
623     va_end(ap);
624     ParamText(stuff, NULL, NULL, NULL);
625     StopAlert(128, NULL);
626     exit(1);
627 }
628
629 /*
630  * Local Variables:
631  * c-file-style: "simon"
632  * End:
633  */