AmendHub

Download

jcs

/

amend

/

main.c

 

(View History)

jcs   *: Tweak some menu names, add Command+D shortcut for generating a diff Latest amendment: 180 on 2026-09-28

1 /*
2 * Copyright (c) 2020-2021 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 #include <stdarg.h>
20
21 #include "amend.h"
22 #include "browser.h"
23 #include "committer.h"
24 #include "focusable.h"
25 #include "repo.h"
26 #include "settings.h"
27 #include "tests.h"
28 #include "util.h"
29
30 MenuHandle apple_menu, file_menu, edit_menu, repo_menu, amendment_menu;
31 bool quitting = false;
32
33 struct settings settings;
34
35 #ifdef MALLOC_DEBUG
36 MenuHandle debug_menu;
37 #define DEBUG_MENU_DUMP_ID 999
38 static short xalloc_frefnum = 0;
39 size_t xalloc_printf(const char *format, ...);
40 #endif
41
42 bool handle_menu(long menu_id);
43
44 short
45 main(void)
46 {
47 Handle mbar;
48 EventRecord event;
49 WindowPtr event_win;
50 GrafPtr old_port;
51 AppFile finder_file;
52 struct repo *repo;
53 struct focusable *focusable;
54 short event_in, n, finder_action, finder_count;
55 bool did_initial_open = false;
56 char key;
57
58 InitGraf(&thePort);
59 InitFonts();
60 FlushEvents(everyEvent, 0);
61 InitWindows();
62 InitMenus();
63 TEInit();
64 InitDialogs(0);
65 InitCursor();
66 MaxApplZone();
67
68 util_init();
69 settings_load();
70
71 #ifdef TEST_SUITE
72 tests_run();
73 return 0;
74 #endif
75
76 mbar = GetNewMBar(MBAR_ID);
77 SetMenuBar(mbar);
78 apple_menu = GetMHandle(APPLE_MENU_ID);
79 AddResMenu(apple_menu, 'DRVR');
80 file_menu = GetMHandle(FILE_MENU_ID);
81 edit_menu = GetMHandle(EDIT_MENU_ID);
82 repo_menu = GetMHandle(REPO_MENU_ID);
83 amendment_menu = GetMHandle(AMENDMENT_MENU_ID);
84 menu_defaults();
85 #ifdef MALLOC_DEBUG
86 debug_menu = NewMenu(DEBUG_MENU_DUMP_ID, "\pDebug");
87 AppendMenu(debug_menu, "\pDump Allocations");
88 InsertMenu(debug_menu, 0);
89 #endif
90 DrawMenuBar();
91
92 /* see if we were started by double-clicking a .repo file */
93 CountAppFiles(&finder_action, &finder_count);
94
95 while (!quitting) {
96 WaitNextEvent(everyEvent, &event, 5L, 0L);
97
98 switch (event.what) {
99 case nullEvent:
100 for (n = 0; n < nfocusables; n++) {
101 if (focusables[n]->idle)
102 focusables[n]->idle(focusables[n], &event);
103 }
104 if (!did_initial_open) {
105 if (finder_count) {
106 GetAppFiles(1, &finder_file);
107 ClrAppFiles(1);
108 finder_count = 0;
109 repo = repo_open(&finder_file);
110 } else
111 repo = repo_open(NULL);
112
113 if (repo)
114 browser_init(repo);
115
116 did_initial_open = true;
117 }
118 break;
119 case keyDown:
120 case autoKey:
121 key = event.message & charCodeMask;
122 if ((event.modifiers & cmdKey) != 0) {
123 if (handle_menu(MenuKey(key)))
124 break;
125 }
126 if ((focusable = focusable_focused()) &&
127 focusable->key_down)
128 focusable->key_down(focusable, &event);
129 break;
130 case mouseDown:
131 event_in = FindWindow(event.where, &event_win);
132
133 switch (event_in) {
134 case inMenuBar:
135 handle_menu(MenuSelect(event.where));
136 break;
137 case inSysWindow:
138 SystemClick(&event, event_win);
139 break;
140 case inDrag:
141 if ((focusable = focusable_find(event_win)) != NULL) {
142 if (!focusable_show(focusable))
143 break;
144
145 DragWindow(event_win, event.where, &screenBits.bounds);
146 }
147 break;
148 case inGoAway:
149 if (TrackGoAway(event_win, event.where)) {
150 if ((focusable = focusable_find(event_win)) != NULL)
151 focusable_close(focusable);
152 }
153 break;
154 case inContent:
155 if ((focusable = focusable_find(event_win)) != NULL) {
156 if (!focusable_show(focusable))
157 break;
158 if (focusable->mouse_down)
159 focusable->mouse_down(focusable, &event);
160 }
161 break;
162 }
163 break;
164 case updateEvt:
165 event_win = (WindowPtr)event.message;
166 focusable = focusable_find(event_win);
167 if (focusable && focusable->update) {
168 GetPort(&old_port);
169 SetPort(event_win);
170 BeginUpdate(event_win);
171 focusable->update(focusable, &event);
172 EndUpdate(event_win);
173 SetPort(old_port);
174 }
175 break;
176 case activateEvt:
177 break;
178 case app4Evt:
179 if (HiWord(event.message) & (1 << 8)) {
180 /* multifinder suspend/resume */
181 switch (event.message & (1 << 0)) {
182 case 0:
183 /* suspend */
184 for (n = 0; n < nfocusables; n++) {
185 if (focusables[n]->suspend)
186 focusables[n]->suspend(focusables[n], &event);
187 }
188 break;
189 case 1:
190 /* resume */
191 for (n = 0; n < nfocusables; n++) {
192 if (focusables[n]->resume)
193 focusables[n]->resume(focusables[n], &event);
194 }
195 break;
196 }
197 }
198 break;
199 }
200 }
201
202 return 0;
203 }
204
205 bool
206 handle_menu(long menu_id)
207 {
208 struct focusable *focused;
209 short menu, item;
210 bool ret = true;
211
212 menu = HiWord(menu_id);
213 item = LoWord(menu_id);
214
215 if (menu && item && (focused = focusable_focused()) &&
216 focused->menu && focused->menu(focused, menu, item))
217 goto handled;
218
219 switch (menu) {
220 case APPLE_MENU_ID:
221 switch (item) {
222 case APPLE_MENU_ABOUT_ID:
223 about(PROGRAM_NAME);
224 break;
225 default: {
226 Str255 da;
227 GrafPtr save_port;
228
229 GetItem(apple_menu, LoWord(menu_id), &da);
230 GetPort(&save_port);
231 OpenDeskAcc(da);
232 SetPort(save_port);
233 break;
234 }
235 }
236 break;
237 case FILE_MENU_ID:
238 switch (item) {
239 case FILE_MENU_DIFF_ID:
240 case FILE_MENU_CHECKOUT_ID:
241 /* handled by browser */
242 return true;
243 case FILE_MENU_SETTINGS_ID:
244 settings_edit(false);
245 break;
246 case FILE_MENU_QUIT_ID:
247 if (focusables_quit())
248 quitting = true;
249 break;
250 }
251 break;
252 case REPO_MENU_ID:
253 switch (item) {
254 case REPO_MENU_NEW_ID: {
255 struct repo *repo;
256 if ((repo = repo_create()))
257 browser_init(repo);
258 break;
259 }
260 case REPO_MENU_OPEN_ID: {
261 struct repo *repo;
262 if ((repo = repo_open(NULL)))
263 browser_init(repo);
264 break;
265 }
266 case REPO_MENU_ADD_FILE_ID:
267 case REPO_MENU_APPLY_PATCH_ID:
268 /* handled by browser */
269 return false;
270 }
271 break;
272 #ifdef MALLOC_DEBUG
273 case DEBUG_MENU_DUMP_ID:
274 switch (LoWord(menu_id)) {
275 case 1: {
276 Str255 vname;
277 short error, vrefnum;
278
279 error = GetVol(&vname, &vrefnum);
280 if (error)
281 panic("Failed to get volume: %d", error);
282 PtoCstr(vname);
283 strlcat((char *)vname, ":amend_xalloc.txt", sizeof(vname));
284 CtoPstr(vname);
285
286 error = Create(vname, vrefnum, 'TEXT', 'TEXT');
287 if (error && error != dupFNErr)
288 panic("Failed to create file: %d", error);
289 error = FSOpen(vname, vrefnum, &xalloc_frefnum);
290 if (error)
291 panic("Failed to open file: %d", error);
292 error = SetEOF(xalloc_frefnum, 0);
293 if (error)
294 panic("Failed to truncate file: %d", error);
295
296 xalloc_print(xalloc_printf);
297 FSClose(xalloc_frefnum);
298 break;
299 }
300 }
301 ret = true;
302 break;
303 #endif
304 default:
305 ret = false;
306 }
307
308 handled:
309 HiliteMenu(0);
310 return ret;
311 }
312
313 #ifdef MALLOC_DEBUG
314 size_t
315 xalloc_printf(const char *format, ...)
316 {
317 static char buf[256];
318 short error;
319 va_list va;
320 size_t len;
321
322 va_start(va, format);
323 len = vsnprintf(buf, sizeof(buf), format, va);
324 va_end(va);
325
326 error = FSWrite(xalloc_frefnum, &len, buf);
327 if (error)
328 panic("Failed to write: %d", error);
329
330 len = 1;
331 error = FSWrite(xalloc_frefnum, &len, "\r");
332 if (error)
333 panic("Failed to write: %d", error);
334
335 return len;
336 }
337 #endif
338
339 void
340 menu_defaults(void)
341 {
342 DisableItem(file_menu, FILE_MENU_DIFF_ID);
343 DisableItem(file_menu, FILE_MENU_CHECKOUT_ID);
344
345 DisableItem(edit_menu, EDIT_MENU_CUT_ID);
346 DisableItem(edit_menu, EDIT_MENU_COPY_ID);
347 DisableItem(edit_menu, EDIT_MENU_PASTE_ID);
348 DisableItem(edit_menu, EDIT_MENU_SELECT_ALL_ID);
349
350 DisableItem(repo_menu, REPO_MENU_ADD_FILE_ID);
351 DisableItem(repo_menu, REPO_MENU_APPLY_PATCH_ID);
352
353 DisableItem(amendment_menu, AMENDMENT_MENU_EDIT_ID);
354 DisableItem(amendment_menu, AMENDMENT_MENU_EXPORT_ID);
355 }