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