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