AmendHub

Download

jcs

/

subtext

/

main.c

 

(View History)

jcs   logger: Add support for resizing window Latest amendment: 288 on 2022-11-18

1 /*
2 * Copyright (c) 2020-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 <stdio.h>
18 #include <string.h>
19
20 #include "subtext.h"
21 #include "console.h"
22 #include "db.h"
23 #include "focusable.h"
24 #include "logger.h"
25 #include "main_menu.h"
26 #include "serial_local.h"
27 #include "session.h"
28 #include "settings.h"
29 #include "telnet.h"
30 #include "user.h"
31 #include "uthread.h"
32 #include "util.h"
33
34 MenuHandle apple_menu, file_menu;
35 short quitting = 0;
36 struct db *db = NULL;
37 bool blanker_on = false;
38 unsigned long blanker_last_blank = 0;
39 WindowPtr blanker_win = NULL;
40
41 bool handle_menu(long menu_id);
42 void handle_exit(void);
43 void blanker_idle(void);
44
45 int
46 main(void)
47 {
48 Handle mbar;
49 EventRecord event;
50 WindowPtr event_win;
51 GrafPtr old_port;
52 AppFile finder_file;
53 struct focusable *found_focusable;
54 unsigned long zone_size, stack_size, heap_size;
55 short event_in, n, finder_action, finder_count;
56 char key, last_daily_job[9] = { 0 }, today[9];
57 struct tm *date_tm;
58
59 uthread_init();
60
61 InitGraf(&thePort);
62 InitFonts();
63 FlushEvents(everyEvent, 0);
64 InitWindows();
65 InitMenus();
66 TEInit();
67 InitDialogs(0);
68 InitCursor();
69 MaxApplZone();
70
71 util_init();
72
73 if (!(mbar = GetNewMBar(MBAR_ID)))
74 panic("no mbar");
75 SetMenuBar(mbar);
76 if (!(apple_menu = GetMHandle(APPLE_MENU_ID)))
77 panic("no apple menu");
78 AddResMenu(apple_menu, 'DRVR');
79 if (!(file_menu = GetMHandle(FILE_MENU_ID)))
80 panic("no file menu");
81 InsertMenu(GetMenu(VIEWS_SUBMENU_ID), -1);
82 DrawMenuBar();
83
84 /* see if we were started by double-clicking a .bbs file */
85 CountAppFiles(&finder_action, &finder_count);
86 if (finder_count) {
87 GetAppFiles(1, &finder_file);
88 ClrAppFiles(1);
89 finder_count = 0;
90 db = db_open(finder_file.fName, finder_file.vRefNum);
91 } else {
92 char none = 0;
93 db = db_open(*((Str255 *)&none), 0);
94 }
95
96 if (!db)
97 panic("Failed to open database");
98
99 _atexit(handle_exit);
100
101 logger_init();
102 logger_update_title();
103
104 main_menu_init();
105
106 zone_size = (unsigned long)CurStackBase - (unsigned long)ApplZone;
107 stack_size = (unsigned long)CurStackBase - (unsigned long)ApplLimit;
108 heap_size = (unsigned long)ApplLimit - (unsigned long)ApplZone;
109 logger_printf("Initialized with %ldKB zone, %ldKB stack for "
110 "%d threads, %ldKB heap", zone_size / 1024L, stack_size / 1024L,
111 NUM_UTHREADS, heap_size / 1024L);
112
113 logger_printf("[db] Updating username cache");
114 user_cache_usernames();
115
116 if (db->config.telnet_port)
117 telnet_init();
118 if (db->config.modem_port)
119 serial_init();
120
121 blanker_last_blank = Time;
122
123 while (!quitting) {
124 if (db->config.telnet_port)
125 telnet_idle();
126 if (db->config.modem_port)
127 serial_idle();
128
129 uthread_coordinate();
130
131 SystemTask();
132 if (!GetNextEvent(everyEvent, &event)) {
133 #ifdef MALLOC_DEBUG
134 xfree_verify();
135 #endif
136 blanker_idle();
137
138 if (nsessions == 0) {
139 date_tm = localtime((time_t *)&Time);
140 strftime(today, sizeof(today), "%Y%m%d", date_tm);
141 if (strcmp(today, last_daily_job) != 0) {
142 session_purge_logs(db->config.session_log_days);
143 strlcpy(last_daily_job, today, sizeof(today));
144 }
145 }
146
147 continue;
148 }
149
150 switch (event.what) {
151 case nullEvent:
152 for (n = 0; n < nfocusables; n++) {
153 if (focusables[n]->idle)
154 focusables[n]->idle(focusables[n], &event);
155 }
156 break;
157 case keyDown:
158 case autoKey:
159 if (blanker_on) {
160 blanker_unblank();
161 break;
162 }
163 key = event.message & charCodeMask;
164 if ((event.modifiers & cmdKey) != 0 &&
165 handle_menu(MenuKey(key)) == true)
166 break;
167 else if (nfocusables && focusables[0]->visible &&
168 focusables[0]->key_down)
169 focusables[0]->key_down(focusables[0], &event);
170 break;
171 case mouseDown:
172 event_in = FindWindow(event.where, &event_win);
173
174 switch (event_in) {
175 case inMenuBar:
176 handle_menu(MenuSelect(event.where));
177 break;
178 case inSysWindow:
179 SystemClick(&event, event_win);
180 break;
181 case inDrag:
182 SelectWindow(event_win);
183 DragWindow(event_win, event.where, &screenBits.bounds);
184 break;
185 case inGrow:
186 found_focusable = find_focusable(event_win);
187 if (event_win != FrontWindow()) {
188 if (found_focusable)
189 show_focusable(found_focusable);
190 }
191 if (found_focusable && found_focusable->resize)
192 found_focusable->resize(found_focusable, &event);
193 break;
194 case inGoAway:
195 if (TrackGoAway(event_win, event.where)) {
196 found_focusable = find_focusable(event_win);
197 if (found_focusable && found_focusable->close)
198 found_focusable->close(found_focusable, &event);
199 }
200 break;
201 case inContent:
202 if (blanker_on) {
203 blanker_unblank();
204 break;
205 }
206 found_focusable = find_focusable(event_win);
207 if (event_win != FrontWindow()) {
208 if (found_focusable)
209 show_focusable(found_focusable);
210 }
211 if (found_focusable && found_focusable->mouse_down)
212 found_focusable->mouse_down(found_focusable, &event);
213 break;
214 }
215 break;
216 case updateEvt:
217 event_win = (WindowPtr)event.message;
218
219 GetPort(&old_port);
220 SetPort(event_win);
221 BeginUpdate(event_win);
222
223 found_focusable = find_focusable(event_win);
224 if (found_focusable && found_focusable->update)
225 found_focusable->update(found_focusable, &event);
226
227 EndUpdate(event_win);
228 SetPort(old_port);
229 break;
230 case activateEvt:
231 break;
232 case app4Evt:
233 if (HiWord(event.message) & (1 << 8)) {
234 /* multifinder suspend/resume */
235 switch (event.message & (1 << 0)) {
236 case 0:
237 /* suspend */
238 for (n = 0; n < nfocusables; n++) {
239 if (focusables[n]->suspend)
240 focusables[n]->suspend(focusables[n], &event);
241 }
242 break;
243 case 1:
244 /* resume */
245 for (n = 0; n < nfocusables; n++) {
246 if (focusables[n]->resume)
247 focusables[n]->resume(focusables[n], &event);
248 }
249 break;
250 }
251 }
252 break;
253 }
254 }
255
256 return 0;
257 }
258
259 void
260 handle_exit(void)
261 {
262 short n;
263
264 blanker_unblank();
265
266 for (n = 0; n < nfocusables; n++) {
267 if (focusables[n]->atexit)
268 focusables[n]->atexit(focusables[n]);
269 }
270
271 if (db->config.telnet_port)
272 telnet_atexit();
273 if (db->config.modem_port)
274 serial_atexit();
275
276 db_close(db);
277 }
278
279 bool
280 handle_menu(long menu_id)
281 {
282 bool ret = false;
283 bool quit = false;
284 size_t n;
285
286 switch (HiWord(menu_id)) {
287 case APPLE_MENU_ID:
288 switch (LoWord(menu_id)) {
289 case APPLE_MENU_ABOUT_ID:
290 about(PROGRAM_NAME);
291 break;
292 default: {
293 Str255 da;
294 GrafPtr save_port;
295
296 GetItem(apple_menu, LoWord(menu_id), &da);
297 GetPort(&save_port);
298 OpenDeskAcc(da);
299 SetPort(save_port);
300 break;
301 }
302 }
303 break;
304 case FILE_MENU_ID:
305 switch (LoWord(menu_id)) {
306 case FILE_MENU_QUIT_ID: {
307 int tnfocusables = nfocusables;
308 struct focusable **tfocusables;
309
310 ret = true;
311 quit = true;
312
313 if (nfocusables) {
314 /*
315 * nfocusables and focusables array will probably be
316 * modified as each focusable quits
317 */
318 tfocusables = xcalloc(sizeof(Ptr), tnfocusables,
319 "focusables quit");
320 memcpy(tfocusables, focusables,
321 sizeof(Ptr) * tnfocusables);
322
323 for (n = 0; n < tnfocusables; n++) {
324 if (tfocusables[n] && tfocusables[n]->quit &&
325 !tfocusables[n]->quit(tfocusables[n])) {
326 quit = false;
327 break;
328 }
329 }
330
331 xfree(&tfocusables);
332 }
333 ExitToShell();
334 break;
335 }
336 }
337 break;
338 case EDIT_MENU_ID:
339 if (nfocusables && focusables[0]->visible && focusables[0]->menu)
340 ret = focusables[0]->menu(focusables[0], HiWord(menu_id),
341 LoWord(menu_id));
342 break;
343 case BBS_MENU_ID:
344 switch (LoWord(menu_id)) {
345 case BBS_MENU_OPEN_CONSOLE_ID:
346 console_init();
347 break;
348 case BBS_MENU_EDIT_MENUS_ID:
349 main_menu_edit();
350 break;
351 }
352 ret = 1;
353 break;
354 case VIEWS_SUBMENU_ID:
355 switch (LoWord(menu_id)) {
356 case VIEWS_SUBMENU_ISSUE_ID:
357 view_editor_show(DB_TEXT_ISSUE_ID, "Edit: Pre-login view");
358 break;
359 case VIEWS_SUBMENU_MAIN_MENU_ID:
360 view_editor_show(DB_TEXT_MENU_ID, "Edit: Main menu");
361 break;
362 case VIEWS_SUBMENU_SHORT_MENU_ID:
363 view_editor_show(DB_TEXT_SHORTMENU_ID, "Edit: Short menu");
364 break;
365 case VIEWS_SUBMENU_SIGNUP_ID:
366 view_editor_show(DB_TEXT_SIGNUP_ID, "Edit: Signup view");
367 break;
368 case VIEWS_SUBMENU_PAGE_SYSOP_ID:
369 view_editor_show(DB_TEXT_PAGE_SYSOP_ID, "Edit: Page Sysop view");
370 break;
371 case VIEWS_SUBMENU_NO_FREE_NODES_ID:
372 view_editor_show(DB_TEXT_NO_FREE_NODES_ID, "Edit: No Free Nodes view");
373 break;
374 case VIEWS_SUBMENU_SIGNOFF_ID:
375 view_editor_show(DB_TEXT_SIGNOFF_ID, "Edit: Session Signoff view");
376 break;
377 }
378 ret = 1;
379 break;
380 }
381
382 HiliteMenu(0);
383 return ret;
384 }
385
386 void
387 blanker_idle(void)
388 {
389 unsigned long t;
390
391 if (!blanker_on && !nsessions &&
392 (Time - blanker_last_blank > db->config.blanker_idle_seconds)) {
393 HideMenuBar();
394
395 blanker_win = NewWindow(0L, &screenBits.bounds, "\p", false,
396 plainDBox, (WindowPtr)-1L, true, 0);
397 if (!blanker_win)
398 panic("NewWindow failed");
399 ShowWindow(blanker_win);
400 SetPort(blanker_win);
401 HideCursor();
402 FillRect(&screenBits.bounds, black);
403 blanker_last_blank = Time;
404 blanker_on = true;
405 return;
406 }
407
408 if (blanker_on && (nsessions ||
409 (Time - blanker_last_blank >= db->config.blanker_runtime_seconds)))
410 blanker_unblank();
411 }
412
413 void
414 blanker_unblank(void)
415 {
416 unsigned long rt;
417
418 if (!blanker_on || !blanker_win)
419 return;
420
421 rt = Time - blanker_last_blank;
422
423 ShowCursor();
424 DisposeWindow(blanker_win);
425 blanker_win = NULL;
426 RestoreHiddenMenuBar();
427 blanker_last_blank = Time;
428 blanker_on = false;
429
430 /*
431 * This will call back to blanker_unblank, so it must be done after
432 * blanker_on = false
433 */
434 logger_printf("[blanker] Blanked screen for %ld second%s",
435 rt, rt == 1 ? "" : "s");
436 }