mac.c 13 KB

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