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