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