AmendHub

Download

jcs

/

wallops

/

main.c

 

(View History)

jcs   main: Use ModalDialogFilter for about screen, fix enabling Hide menu Latest amendment: 125 on 2024-09-20

1 /*
2 * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <string.h>
18 #include <stdarg.h>
19 #include "chatter.h"
20 #include "irc.h"
21 #include "settings.h"
22 #include "tcp.h"
23 #include "util.h"
24
25 NMRec notification = { 0 };
26 struct settings settings;
27 MenuHandle apple_menu, file_menu, edit_menu, view_menu, ignore_menu,
28 window_menu;
29
30 #ifdef MALLOC_DEBUG
31 MenuHandle debug_menu;
32 #define DEBUG_MENU_DUMP_ID 999
33 static short xalloc_frefnum = 0;
34 size_t xalloc_printf(const char *format, ...);
35 #endif
36
37 void update_menu(void);
38 void handle_exit(void);
39 bool handle_menu(long menu_id);
40 void show_connect_dialog(void);
41 void wallops_about(void);
42
43 short
44 main(void)
45 {
46 Handle mbar;
47 EventRecord event;
48 WindowPtr event_win;
49 GrafPtr old_port;
50 AppFile finder_file;
51 struct focusable *found_focusable;
52 short event_in, n;
53 char key;
54 long wait_ticks;
55 short wait_type;
56
57 SetApplLimit(GetApplLimit() - (1024 * 8));
58
59 InitGraf(&thePort);
60 InitFonts();
61 FlushEvents(everyEvent, 0);
62 InitWindows();
63 InitMenus();
64 TEInit();
65 InitDialogs(0);
66 InitCursor();
67 MaxApplZone();
68
69 util_init();
70 _atexit(handle_exit);
71
72 if (!(mbar = GetNewMBar(MBAR_ID)))
73 panic("No mbar");
74 SetMenuBar(mbar);
75 if (!(apple_menu = GetMHandle(APPLE_MENU_ID)))
76 panic("No Apple menu");
77 AddResMenu(apple_menu, 'DRVR');
78 if (!(file_menu = GetMHandle(FILE_MENU_ID)))
79 panic("No File menu");
80 if (!(edit_menu = GetMHandle(EDIT_MENU_ID)))
81 panic("No Edit menu");
82 if (!(view_menu = GetMHandle(VIEW_MENU_ID)))
83 panic("No View menu");
84 if (!(ignore_menu = GetMenu(IGNORE_MENU_ID)))
85 panic("No Ignore menu");
86 InsertMenu(ignore_menu, -1);
87 if (!(window_menu = GetMenu(WINDOW_MENU_ID)))
88 panic("No Window menu");
89 update_menu();
90 #ifdef MALLOC_DEBUG
91 debug_menu = NewMenu(DEBUG_MENU_DUMP_ID, "\pDebug");
92 AppendMenu(debug_menu, "\pDump Allocations");
93 InsertMenu(debug_menu, 0);
94 #endif
95 DrawMenuBar();
96
97 show_connect_dialog();
98
99 for (;;) {
100 wait_type = WAIT_TYPE_BACKGROUND;
101 for (n = 0; n < nfocusables; n++) {
102 if (focusables[n]->wait_type)
103 wait_type |= focusables[n]->wait_type(focusables[n]);
104 else if (focusables[n]->visible)
105 wait_type |= WAIT_TYPE_FOREGROUND;
106 }
107
108 if (wait_type & WAIT_TYPE_URGENT)
109 wait_ticks = 0;
110 else if (wait_type & WAIT_TYPE_FOREGROUND)
111 wait_ticks = 5L;
112 else
113 wait_ticks = 60L;
114
115 WaitNextEvent(everyEvent, &event, wait_ticks, 0L);
116
117 switch (event.what) {
118 case nullEvent:
119 for (n = 0; n < nfocusables; n++) {
120 if (focusables[n]->idle)
121 focusables[n]->idle(focusables[n], &event);
122 }
123 break;
124 case keyDown:
125 case autoKey:
126 key = event.message & charCodeMask;
127 if ((event.modifiers & cmdKey) != 0 &&
128 handle_menu(MenuKey(key)) == true)
129 break;
130 if (nfocusables && focusables[0]->visible &&
131 focusables[0]->key_down)
132 focusables[0]->key_down(focusables[0], &event);
133 break;
134 case mouseDown:
135 event_in = FindWindow(event.where, &event_win);
136 found_focusable = focusable_find(event_win);
137
138 if (found_focusable) {
139 cancel_notification();
140 focusable_show(found_focusable);
141 }
142
143 switch (event_in) {
144 case inMenuBar:
145 handle_menu(MenuSelect(event.where));
146 break;
147 case inSysWindow:
148 SystemClick(&event, event_win);
149 break;
150 case inDrag:
151 DragWindow(event_win, event.where, &screenBits.bounds);
152 break;
153 case inGrow:
154 if (found_focusable && found_focusable->resize)
155 found_focusable->resize(found_focusable, &event);
156 break;
157 case inGoAway:
158 if (TrackGoAway(event_win, event.where) && found_focusable)
159 focusable_close(found_focusable);
160 break;
161 case inContent:
162 if (found_focusable && found_focusable->mouse_down)
163 found_focusable->mouse_down(found_focusable, &event);
164 break;
165 }
166
167 update_menu();
168 break;
169 case updateEvt:
170 case activateEvt:
171 event_win = (WindowPtr)event.message;
172 found_focusable = focusable_find(event_win);
173
174 GetPort(&old_port);
175 SetPort(event_win);
176
177 if (event.what == updateEvt)
178 BeginUpdate(event_win);
179
180 if (found_focusable && found_focusable->update)
181 found_focusable->update(found_focusable, &event);
182
183 if (event.what == updateEvt)
184 EndUpdate(event_win);
185
186 SetPort(old_port);
187 break;
188 case app4Evt:
189 if (HiWord(event.message) & (1 << 8)) {
190 /* multifinder suspend/resume */
191 switch (event.message & (1 << 0)) {
192 case 0:
193 /* suspend */
194 for (n = 0; n < nfocusables; n++) {
195 if (focusables[n]->suspend)
196 focusables[n]->suspend(focusables[n], &event);
197 }
198 break;
199 case 1:
200 /* resume */
201 cancel_notification();
202 for (n = 0; n < nfocusables; n++) {
203 if (focusables[n]->resume)
204 focusables[n]->resume(focusables[n], &event);
205 }
206 break;
207 }
208 }
209 break;
210 }
211 }
212
213 return 0;
214 }
215
216 void
217 show_connect_dialog(void)
218 {
219 bool valid;
220
221 valid = settings_edit(!settings_load());
222 update_menu();
223
224 if (!valid)
225 return;
226
227 chatter_init(settings.server, settings.port, settings.password,
228 settings.nick, settings.ident, settings.realname,
229 settings.hide_motd, settings.channel);
230 }
231
232 bool
233 handle_menu(long menu_id)
234 {
235 size_t n;
236 bool ret = false;
237 bool quit = true;
238
239 switch (HiWord(menu_id)) {
240 case APPLE_MENU_ID:
241 switch (LoWord(menu_id)) {
242 case APPLE_MENU_ABOUT_ID:
243 wallops_about();
244 ret = true;
245 break;
246 default: {
247 Str255 da;
248 GrafPtr save_port;
249
250 GetItem(apple_menu, LoWord(menu_id), &da);
251 GetPort(&save_port);
252 OpenDeskAcc(da);
253 SetPort(save_port);
254
255 ret = true;
256 break;
257 }
258 }
259 break;
260 case FILE_MENU_ID:
261 switch (LoWord(menu_id)) {
262 case FILE_MENU_CONNECT_ID:
263 show_connect_dialog();
264 ret = true;
265 break;
266 case FILE_MENU_QUIT_ID:
267 ret = true;
268 if (focusables_quit())
269 ExitToShell();
270 break;
271 }
272 break;
273 case VIEW_MENU_ID:
274 break;
275 case IGNORE_MENU_ID: {
276 short current;
277
278 GetItemMark(ignore_menu, LoWord(menu_id), &current);
279
280 switch (LoWord(menu_id)) {
281 case IGNORE_MENU_JOINS_ID:
282 if (current)
283 settings.ignores &= ~(IGNORE_JOINS);
284 else
285 settings.ignores |= (IGNORE_JOINS);
286 break;
287 case IGNORE_MENU_QUITS_ID:
288 if (current)
289 settings.ignores &= ~(IGNORE_QUITS);
290 else
291 settings.ignores |= (IGNORE_QUITS);
292 break;
293 case IGNORE_MENU_NICKS_ID:
294 if (current)
295 settings.ignores &= ~(IGNORE_NICKS);
296 else
297 settings.ignores |= (IGNORE_NICKS);
298 break;
299 }
300 settings_save(&settings);
301 update_menu();
302 ret = true;
303 break;
304 }
305 case WINDOW_MENU_ID:
306 switch (LoWord(menu_id)) {
307 case WINDOW_MENU_HIDE_ID: {
308 Str255 text;
309 struct focusable **tfocusables = NULL;
310
311 /* hiding and showing adjusts order, so duplicate order */
312 tfocusables = xmalloc(sizeof(struct focusable *) * nfocusables);
313 memcpy(tfocusables, focusables, sizeof(struct focusable *) *
314 nfocusables);
315
316 GetItem(window_menu, WINDOW_MENU_HIDE_ID, &text);
317 if (memcmp((char *)text + 1, "Hide", 4) == 0) {
318 for (n = 0; n < nfocusables; n++) {
319 if (tfocusables[n]->visible)
320 focusable_hide(tfocusables[n]);
321 }
322 } else {
323 for (n = 0; n < nfocusables; n++) {
324 if (!tfocusables[n]->visible)
325 focusable_show(tfocusables[n]);
326 }
327 }
328
329 xfree(&tfocusables);
330 update_menu();
331 ret = true;
332 break;
333 }
334 default:
335 if (LoWord(menu_id) >= WINDOW_MENU_N_ID) {
336 for (n = 0; n < nfocusables; n++) {
337 if (focusables[n]->id == LoWord(menu_id) -
338 WINDOW_MENU_N_ID) {
339 focusable_show(focusables[n]);
340 break;
341 }
342 }
343 ret = true;
344 }
345 }
346 break;
347 #ifdef MALLOC_DEBUG
348 case DEBUG_MENU_DUMP_ID:
349 switch (LoWord(menu_id)) {
350 case 1: {
351 Str255 vname;
352 short error, vrefnum;
353
354 error = GetVol(&vname, &vrefnum);
355 if (error)
356 panic("Failed to get volume: %d", error);
357 PtoCstr(vname);
358 strlcat((char *)vname, ":", sizeof(vname));
359 strlcat((char *)vname, PROGRAM_NAME, sizeof(vname));
360 strlcat((char *)vname, "_xalloc.txt", sizeof(vname));
361 CtoPstr(vname);
362
363 error = Create(vname, vrefnum, 'TEXT', 'TEXT');
364 if (error && error != dupFNErr)
365 panic("Failed to create file: %d", error);
366 error = FSOpen(vname, vrefnum, &xalloc_frefnum);
367 if (error)
368 panic("Failed to open file: %d", error);
369 error = SetEOF(xalloc_frefnum, 0);
370 if (error)
371 panic("Failed to truncate file: %d", error);
372
373 xalloc_print(xalloc_printf);
374 FSClose(xalloc_frefnum);
375 break;
376 }
377 }
378 ret = true;
379 break;
380 #endif
381 }
382
383 if (!ret && nfocusables && focusables[0]->visible &&
384 focusables[0]->menu)
385 ret = focusables[0]->menu(focusables[0], HiWord(menu_id),
386 LoWord(menu_id));
387
388 HiliteMenu(0);
389 return ret;
390 }
391
392 #ifdef MALLOC_DEBUG
393 size_t
394 xalloc_printf(const char *format, ...)
395 {
396 static char buf[256];
397 short error;
398 va_list va;
399 size_t len;
400
401 va_start(va, format);
402 len = vsnprintf(buf, sizeof(buf), format, va);
403 va_end(va);
404
405 error = FSWrite(xalloc_frefnum, &len, buf);
406 if (error)
407 panic("Failed to write: %d", error);
408
409 len = 1;
410 error = FSWrite(xalloc_frefnum, &len, "\r");
411 if (error)
412 panic("Failed to write: %d", error);
413
414 return len;
415 }
416 #endif
417
418 void
419 update_menu(void)
420 {
421 short n;
422 bool hidden = false;
423
424 for (n = 0; n < nfocusables; n++) {
425 if (!focusables[n]->visible) {
426 hidden = true;
427 break;
428 }
429 }
430
431 EnableItem(view_menu, WINDOW_MENU_HIDE_ID);
432
433 if (hidden)
434 DisableItem(view_menu, VIEW_MENU_CLOSE_ID);
435
436 CheckItem(ignore_menu, IGNORE_MENU_JOINS_ID,
437 !!(settings.ignores & IGNORE_JOINS));
438 CheckItem(ignore_menu, IGNORE_MENU_QUITS_ID,
439 !!(settings.ignores & IGNORE_QUITS));
440 CheckItem(ignore_menu, IGNORE_MENU_NICKS_ID,
441 !!(settings.ignores & IGNORE_NICKS));
442
443 if (hidden)
444 SetItem(window_menu, WINDOW_MENU_HIDE_ID, "\pShow Windows");
445 else
446 SetItem(window_menu, WINDOW_MENU_HIDE_ID, "\pHide Windows");
447
448 if (nfocusables && focusables[0]->visible &&
449 focusables[0]->update_menu) {
450 focusables[0]->update_menu(focusables[0]);
451 return;
452 }
453
454 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
455 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
456 DisableItem(edit_menu, EDIT_MENU_PASTE_ID);
457
458 if (hidden)
459 EnableItem(window_menu, WINDOW_MENU_HIDE_ID);
460 else
461 DisableItem(window_menu, WINDOW_MENU_HIDE_ID);
462 }
463
464 void
465 handle_exit(void)
466 {
467 focusables_quit();
468
469 while (!SLIST_EMPTY(&irc_connections_list))
470 irc_dealloc_connection(SLIST_FIRST(&irc_connections_list));
471 }
472
473 void
474 notify(void)
475 {
476 memset(&notification, 0, sizeof(notification));
477 notification.qType = nmType;
478 notification.nmMark = 1;
479 notification.nmSound = (Handle)-1;
480 notification.nmIcon = GetResource('SICN', NOTIFICATION_ICON_ID);
481 NMInstall(&notification);
482 }
483
484 void
485 cancel_notification(void)
486 {
487 if (notification.qType)
488 NMRemove(&notification);
489 memset(&notification, 0, sizeof(notification));
490 }
491
492 void
493 wallops_about(void)
494 {
495 char vers_s[255];
496 char short_vers[255] = { 0 };
497 DialogPtr dp;
498 StringHandle dast;
499 VersRecHndl vers;
500 Rect bounds;
501 short hit, vlen, n;
502 Handle h, ihandle;
503
504 vers = (VersRecHndl)GetResource('vers', 1);
505 if (!vers)
506 panic("No vers");
507
508 /*
509 * vers "long version string" is a pascal string after the
510 * short version pascal string
511 */
512 HLock(vers);
513 vlen = (*vers)->shortVersion[0];
514 memcpy(short_vers, (*vers)->shortVersion + vlen + 1,
515 sizeof((*vers)->shortVersion) - vlen - 1);
516 PtoCstr(short_vers);
517 snprintf(vers_s, sizeof(vers_s), "%s %s", PROGRAM_NAME, short_vers);
518 for (n = 0; n < sizeof(vers_s); n++) {
519 if (vers_s[n] == '©') {
520 vers_s[n - 1] = '\r';
521 break;
522 }
523 }
524 ReleaseResource(vers);
525
526 CtoPstr(vers_s);
527
528 dp = GetNewDialog(ABOUT_DLOG_ID, 0L, (WindowPtr)-1L);
529
530 ParamText(vers_s, "\p" HOMEPAGE, "\pI miss you, Carl", "\p");
531
532 center_in_screen(((DialogPeek)dp)->window.port.portRect.right,
533 ((DialogPeek)dp)->window.port.portRect.bottom, false, &bounds);
534 MoveWindow(dp, bounds.left, bounds.top, false);
535 SetPort(dp);
536 ShowWindow(dp);
537
538 for (;;) {
539 ModalDialog(ModalDialogFilter, &hit);
540 if (hit == ok)
541 break;
542 }
543
544 DisposDialog(dp);
545 }