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