]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/mac.c
7cbe8c796883e15151fe471f532a0004f0758723
[PuTTY.git] / mac / mac.c
1 /* $Id: mac.c,v 1.8 2002/12/28 22:22:43 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
460     if (windows.licence)
461         SelectWindow(windows.licence);
462     else {
463         windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
464         ShowWindow(windows.licence);
465     }
466 }
467
468 static void mac_closewindow(WindowPtr window) {
469
470     switch (mac_windowtype(window)) {
471       case wDA:
472         CloseDeskAcc(((WindowPeek)window)->windowKind);
473         break;
474       case wTerminal:
475         /* FIXME: end session and stuff */
476         break;
477       case wAbout:
478         windows.about = NULL;
479         CloseWindow(window);
480         break;
481       case wLicence:
482         windows.licence = NULL;
483         CloseWindow(window);
484         break;
485       default:
486         CloseWindow(window);
487         break;
488     }
489 }
490
491 static void mac_zoomwindow(WindowPtr window, short part) {
492
493     /* FIXME: do something */
494 }
495
496 /*
497  * Make the menus look right before the user gets to see them.
498  */
499 static void mac_adjustmenus(void) {
500     WindowPtr window;
501     MenuHandle menu;
502
503     window = FrontWindow();
504     menu = GetMenuHandle(mApple);
505     EnableItem(menu, 0);
506     EnableItem(menu, iAbout);
507
508     menu = GetMenuHandle(mFile);
509     EnableItem(menu, 0);
510     EnableItem(menu, iNew);
511     if (window != NULL)
512         EnableItem(menu, iClose);
513     else
514         DisableItem(menu, iClose);
515     EnableItem(menu, iQuit);
516
517     switch (mac_windowtype(window)) {
518       case wTerminal:
519         mac_adjusttermmenus(window);
520         break;
521       default:
522         menu = GetMenuHandle(mEdit);
523         DisableItem(menu, 0);
524         break;
525     }
526     DrawMenuBar();
527 }
528
529 /*
530  * Make sure the right cursor's being displayed.
531  */
532 static void mac_adjustcursor(RgnHandle cursrgn) {
533     Point mouse;
534     WindowPtr window, front;
535     short part;
536
537     GetMouse(&mouse);
538     LocalToGlobal(&mouse);
539     part = FindWindow(mouse, &window);
540     front = FrontWindow();
541     if (part != inContent || window == NULL || window != front) {
542         /* Cursor isn't in the front window, so switch to arrow */
543         SetCursor(&qd.arrow);
544         SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
545         if (front != NULL)
546             DiffRgn(cursrgn, front->visRgn, cursrgn);
547     } else {
548         switch (mac_windowtype(window)) {
549           case wTerminal:
550             mac_adjusttermcursor(window, mouse, cursrgn);
551             break;
552           default:
553             SetCursor(&qd.arrow);
554             CopyRgn(window->visRgn, cursrgn);
555             break;
556         }
557     }
558 }
559
560 static void mac_shutdown(void) {
561
562     if (mac_gestalts.encvvers != 0)
563         TerminateUnicodeConverter();
564     exit(0);
565 }
566
567 void fatalbox(char *fmt, ...) {
568     va_list ap;
569     Str255 stuff;
570     
571     va_start(ap, fmt);
572     /* We'd like stuff to be a Pascal string */
573     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
574     va_end(ap);
575     ParamText(stuff, NULL, NULL, NULL);
576     StopAlert(128, nil);
577     exit(1);
578 }
579
580 void modalfatalbox(char *fmt, ...) {
581     va_list ap;
582     Str255 stuff;
583     
584     va_start(ap, fmt);
585     /* We'd like stuff to be a Pascal string */
586     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
587     va_end(ap);
588     ParamText(stuff, NULL, NULL, NULL);
589     StopAlert(128, nil);
590     exit(1);
591 }
592
593 /*
594  * Local Variables:
595  * c-file-style: "simon"
596  * End:
597  */