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