Add support for displaying the licence window.
[sgt/putty] / 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 */