]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/mac.c
Tentative merge of ben-mac-port (only dead for three years!) into the trunk.
[PuTTY.git] / mac / mac.c
1 /* $Id: mac.c,v 1.1 2002/11/19 02:13:46 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 <Threads.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_keypress(EventRecord *);
74 static int mac_windowtype(WindowPtr);
75 static void mac_menucommand(long);
76 static void mac_openabout(void);
77 static void mac_adjustcursor(RgnHandle);
78 static void mac_adjustmenus(void);
79 static void mac_closewindow(WindowPtr);
80 static void mac_zoomwindow(WindowPtr, short);
81 static void mac_shutdown(void);
82 #pragma noreturn (mac_shutdown)
83
84 struct mac_windows {
85     WindowPtr about;
86     WindowPtr licence;
87 };
88
89 struct mac_windows windows;
90
91 int main (int argc, char **argv) {
92
93     mac_startup();
94     mac_eventloop();
95 }
96
97 #pragma noreturn (main)
98
99 static void mac_startup(void) {
100     Handle menuBar;
101
102     /* Init Memory Manager */
103     MaxApplZone();
104     /* Init QuickDraw */
105     InitGraf(&qd.thePort);
106     /* Init Font Manager */
107     InitFonts();
108     /* Init Window Manager */
109     InitWindows();
110     /* Init Menu Manager */
111     InitMenus();
112     /* Init TextEdit */
113     TEInit();
114     /* Init Dialog Manager */
115     InitDialogs(nil);
116     cold = 0;
117     
118     /* Check for the Thread Manager.  Bail out if it's not there. */
119     if (Gestalt(gestaltThreadMgrAttr, &mac_gestalts.thdsattr) != noErr ||
120         !(mac_gestalts.thdsattr & (1 << gestaltThreadMgrPresent)) ||
121         &NewThread == kUnresolvedCFragSymbolAddress)
122         fatalbox("PuTTY requires the Thread Manager in order to operate.  "
123                  "The Thread Manager can be obtained from Apple Software "
124                  "Updates.");
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         YieldToAnyThread();
177     }
178     DisposeRgn(cursrgn);
179 }
180
181 static void mac_event(EventRecord *event) {
182     short part;
183     WindowPtr window;
184     Point pt;
185
186     switch (event->what) {
187       case mouseDown:
188         part = FindWindow(event->where, &window);
189         switch (part) {
190           case inMenuBar:
191             mac_adjustmenus();
192             mac_menucommand(MenuSelect(event->where));
193             break;
194           case inSysWindow:
195             SystemClick(event, window);
196             break;
197           case inContent:
198             if (window != FrontWindow())
199                 /* XXX: check for movable modal dboxes? */
200                 SelectWindow(window);
201             else
202                 mac_contentclick(window, event);
203             break;
204           case inGoAway:
205             if (TrackGoAway(window, event->where))
206                 mac_closewindow(window);
207             break;
208           case inDrag:
209             /* XXX: moveable modal check? */
210             DragWindow(window, event->where, &qd.screenBits.bounds);
211             break;
212           case inGrow:
213             mac_growwindow(window, event);
214             break;
215           case inZoomIn:
216           case inZoomOut:
217             if (TrackBox(window, event->where, part))
218                 mac_zoomwindow(window, part);
219             break;
220         }
221         break;
222       case keyDown:
223       case autoKey:
224         mac_keypress(event);
225         break;
226       case activateEvt:
227         mac_activatewindow((WindowPtr)event->message, event);
228         break;
229       case updateEvt:
230         mac_updatewindow((WindowPtr)event->message);
231         break;
232       case diskEvt:
233         if (HiWord(event->message) != noErr) {
234             SetPt(&pt, 120, 120);
235             DIBadMount(pt, event->message);
236         }
237         break;
238     }
239 }
240
241 static void mac_contentclick(WindowPtr window, EventRecord *event) {
242     short item;
243
244     switch (mac_windowtype(window)) {
245       case wTerminal:
246         mac_clickterm(window, event);
247         break;
248       case wAbout:
249         if (DialogSelect(event, &(DialogPtr)window, &item))
250             switch (item) {
251               case wiAboutLicence:
252                 /* XXX: Do something */
253                 break;
254             }
255         break;
256     }
257 }
258
259 static void mac_growwindow(WindowPtr window, EventRecord *event) {
260
261     switch (mac_windowtype(window)) {
262       case wTerminal:
263         mac_growterm(window, event);
264     }
265 }
266
267 static void mac_activatewindow(WindowPtr window, EventRecord *event) {
268     int active;
269
270     active = (event->modifiers & activeFlag) != 0;
271     mac_adjustmenus();
272     switch (mac_windowtype(window)) {
273       case wTerminal:
274         mac_activateterm(window, active);
275         break;
276       case wAbout:
277         mac_activateabout(window, event);
278         break;
279     }
280 }
281
282 static void mac_activateabout(WindowPtr window, EventRecord *event) {
283     DialogItemType itemtype;
284     Handle itemhandle;
285     short item;
286     Rect itemrect;
287     int active;
288
289     active = (event->modifiers & activeFlag) != 0;
290     GetDialogItem(window, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
291     HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
292     DialogSelect(event, &window, &item);
293 }
294
295 static void mac_updatewindow(WindowPtr window) {
296
297     switch (mac_windowtype(window)) {
298       case wTerminal:
299         mac_updateterm(window);
300         break;
301       case wAbout:
302         BeginUpdate(window);
303         UpdateDialog(window, window->visRgn);
304         EndUpdate(window);
305         break;
306       case wLicence:
307         /* Do something */
308         break;
309     }
310 }
311
312 /*
313  * Work out what kind of window we're dealing with.
314  * Concept shamelessly nicked from SurfWriter.
315  */
316 static int mac_windowtype(WindowPtr window) {
317     int kind;
318
319     if (window == NULL)
320         return wNone;
321     kind = ((WindowPeek)window)->windowKind;
322     if (kind < 0)
323         return wDA;
324     if (GetWVariant(window) == zoomDocProc)
325         return wTerminal;
326     return GetWRefCon(window);
327 }
328
329 /*
330  * Handle a key press
331  */
332 static void mac_keypress(EventRecord *event) {
333     WindowPtr window;
334
335     window = FrontWindow();
336     /*
337      * Check for a command-key combination, but ignore it if it counts
338      * as a meta-key combination and we're in a terminal window.
339      */
340     if (event->what == keyDown && (event->modifiers & cmdKey) /*&&
341         !((event->modifiers & cfg.meta_modifiers) == cfg.meta_modifiers &&
342             mac_windowtype(window) == wTerminal)*/) {
343         mac_adjustmenus();
344         mac_menucommand(MenuKey(event->message & charCodeMask));
345     } else {
346         switch (mac_windowtype(window)) {
347           case wTerminal:
348             mac_keyterm(window, event);
349             break;
350         }
351     }       
352 }
353
354 static void mac_menucommand(long result) {
355     short menu, item;
356     Str255 da;
357     WindowPtr window;
358
359     menu = HiWord(result);
360     item = LoWord(result);
361     window = FrontWindow();
362     /* Things which do the same whatever window we're in. */
363     switch (menu) {
364       case mApple:
365         switch (item) {
366           case iAbout:
367             mac_openabout();
368             goto done;
369           default:
370             GetMenuItemText(GetMenuHandle(mApple), item, da);
371             OpenDeskAcc(da);
372             goto done;
373         }
374         break;
375       case mFile:
376         switch (item) {
377           case iNew:
378             mac_newsession();
379             goto done;
380           case iClose:
381             mac_closewindow(window);
382             goto done;
383           case iQuit:
384             mac_shutdown();
385             goto done;
386         }
387         break;
388     }
389     /* If we get here, handling is up to window-specific code. */
390     switch (mac_windowtype(window)) {
391       case wTerminal:
392         mac_menuterm(window, menu, item);
393         break;
394     }
395   done:
396     HiliteMenu(0);
397 }
398
399 static void mac_openabout(void) {
400     DialogItemType itemtype;
401     Handle item;
402     VersRecHndl vers;
403     Rect box;
404     StringPtr longvers;
405
406     if (windows.about)
407         SelectWindow(windows.about);
408     else {
409         windows.about = GetNewDialog(wAbout, NULL, (WindowPtr)-1);
410         /* XXX check we're using the right resource file? */
411         vers = (VersRecHndl)GetResource('vers', 1);
412         assert(vers != NULL && *vers != NULL);
413         longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
414         GetDialogItem(windows.about, wiAboutVersion, &itemtype, &item, &box);
415         assert(itemtype & kStaticTextDialogItem);
416         SetDialogItemText(item, longvers);
417         ShowWindow(windows.about);
418     }
419 }
420
421 static void mac_closewindow(WindowPtr window) {
422
423     switch (mac_windowtype(window)) {
424       case wDA:
425         CloseDeskAcc(((WindowPeek)window)->windowKind);
426         break;
427       case wTerminal:
428         /* FIXME: end session and stuff */
429         break;
430       case wAbout:
431         windows.about = NULL;
432         CloseWindow(window);
433         break;
434       default:
435         CloseWindow(window);
436         break;
437     }
438 }
439
440 static void mac_zoomwindow(WindowPtr window, short part) {
441
442     /* FIXME: do something */
443 }
444
445 /*
446  * Make the menus look right before the user gets to see them.
447  */
448 static void mac_adjustmenus(void) {
449     WindowPtr window;
450     MenuHandle menu;
451
452     window = FrontWindow();
453     menu = GetMenuHandle(mApple);
454     EnableItem(menu, 0);
455     EnableItem(menu, iAbout);
456
457     menu = GetMenuHandle(mFile);
458     EnableItem(menu, 0);
459     EnableItem(menu, iNew);
460     if (window != NULL)
461         EnableItem(menu, iClose);
462     else
463         DisableItem(menu, iClose);
464     EnableItem(menu, iQuit);
465
466     switch (mac_windowtype(window)) {
467       case wTerminal:
468         mac_adjusttermmenus(window);
469         break;
470       default:
471         menu = GetMenuHandle(mEdit);
472         DisableItem(menu, 0);
473         break;
474     }
475     DrawMenuBar();
476 }
477
478 /*
479  * Make sure the right cursor's being displayed.
480  */
481 static void mac_adjustcursor(RgnHandle cursrgn) {
482     Point mouse;
483     WindowPtr window, front;
484     short part;
485
486     GetMouse(&mouse);
487     LocalToGlobal(&mouse);
488     part = FindWindow(mouse, &window);
489     front = FrontWindow();
490     if (part != inContent || window == NULL || window != front) {
491         /* Cursor isn't in the front window, so switch to arrow */
492         SetCursor(&qd.arrow);
493         SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
494         if (front != NULL)
495             DiffRgn(cursrgn, front->visRgn, cursrgn);
496     } else {
497         switch (mac_windowtype(window)) {
498           case wTerminal:
499             mac_adjusttermcursor(window, mouse, cursrgn);
500             break;
501           default:
502             SetCursor(&qd.arrow);
503             CopyRgn(window->visRgn, cursrgn);
504             break;
505         }
506     }
507 }
508
509 static void mac_shutdown(void) {
510
511     exit(0);
512 }
513
514 void fatalbox(char *fmt, ...) {
515     va_list ap;
516     Str255 stuff;
517     
518     va_start(ap, fmt);
519     /* We'd like stuff to be a Pascal string */
520     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
521     va_end(ap);
522     ParamText(stuff, NULL, NULL, NULL);
523     StopAlert(128, nil);
524     exit(1);
525 }
526
527 void modalfatalbox(char *fmt, ...) {
528     va_list ap;
529     Str255 stuff;
530     
531     va_start(ap, fmt);
532     /* We'd like stuff to be a Pascal string */
533     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
534     va_end(ap);
535     ParamText(stuff, NULL, NULL, NULL);
536     StopAlert(128, nil);
537     exit(1);
538 }
539
540 /*
541  * Local Variables:
542  * c-file-style: "simon"
543  * End:
544  */